2019-10-26 02:42:50 +00:00
import ' dart:async ' ;
2020-05-11 00:48:41 +00:00
import ' dart:collection ' ;
2019-10-26 02:42:50 +00:00
2019-11-10 13:11:30 +00:00
import ' package:flutter/foundation.dart ' ;
2019-10-26 02:42:50 +00:00
import ' package:flutter/services.dart ' ;
import ' types.dart ' ;
import ' in_app_browser.dart ' ;
///This class uses native [Chrome Custom Tabs](https://developer.android.com/reference/android/support/customtabs/package-summary) on Android
///and [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) on iOS.
///
2019-11-10 13:11:30 +00:00
///[browserFallback] represents the [InAppBrowser] instance fallback in case `Chrome Custom Tabs`/`SFSafariViewController` is not available.
2019-10-26 02:42:50 +00:00
class ChromeSafariBrowser {
String uuid ;
InAppBrowser browserFallback ;
2020-05-11 00:48:41 +00:00
Map < int , ChromeSafariBrowserMenuItem > _menuItems = new HashMap ( ) ;
2019-10-26 02:42:50 +00:00
bool _isOpened = false ;
2019-12-18 20:34:40 +00:00
MethodChannel _channel ;
static const MethodChannel _sharedChannel = const MethodChannel ( ' com.pichillilorenzo/flutter_chromesafaribrowser ' ) ;
2019-10-26 02:42:50 +00:00
///Initialize the [ChromeSafariBrowser] instance with an [InAppBrowser] fallback instance or `null`.
2019-12-01 11:55:06 +00:00
ChromeSafariBrowser ( { bFallback } ) {
2019-10-26 02:42:50 +00:00
uuid = uuidGenerator . v4 ( ) ;
2019-11-10 13:11:30 +00:00
browserFallback = bFallback ;
2019-12-18 20:34:40 +00:00
this . _channel =
MethodChannel ( ' com.pichillilorenzo/flutter_chromesafaribrowser_ $ uuid ' ) ;
this . _channel . setMethodCallHandler ( handleMethod ) ;
2019-10-26 02:42:50 +00:00
_isOpened = false ;
}
Future < dynamic > handleMethod ( MethodCall call ) async {
2019-12-01 11:55:06 +00:00
switch ( call . method ) {
2019-10-26 02:42:50 +00:00
case " onChromeSafariBrowserOpened " :
onOpened ( ) ;
break ;
2019-12-18 00:56:21 +00:00
case " onChromeSafariBrowserCompletedInitialLoad " :
onCompletedInitialLoad ( ) ;
2019-10-26 02:42:50 +00:00
break ;
case " onChromeSafariBrowserClosed " :
onClosed ( ) ;
this . _isOpened = false ;
break ;
2020-05-11 00:48:41 +00:00
case " onChromeSafariBrowserMenuItemActionPerform " :
String url = call . arguments [ " url " ] ;
String title = call . arguments [ " title " ] ;
int id = call . arguments [ " id " ] . toInt ( ) ;
this . _menuItems [ id ] . action ( url , title ) ;
break ;
2019-10-26 02:42:50 +00:00
default :
throw UnimplementedError ( " Unimplemented ${ call . method } method " ) ;
}
}
///Opens an [url] in a new [ChromeSafariBrowser] instance.
///
2019-11-10 13:11:30 +00:00
///[url]: The [url] to load. Call [encodeUriComponent()] on this if the [url] contains Unicode characters.
2019-10-26 02:42:50 +00:00
///
2019-11-10 13:11:30 +00:00
///[options]: Options for the [ChromeSafariBrowser].
2019-10-26 02:42:50 +00:00
///
2019-11-10 13:11:30 +00:00
///[headersFallback]: The additional header of the [InAppBrowser] instance fallback to be used in the HTTP request for this URL, specified as a map from name to value.
2019-10-26 02:42:50 +00:00
///
2019-11-10 13:11:30 +00:00
///[optionsFallback]: Options used by the [InAppBrowser] instance fallback.
2020-05-21 01:34:39 +00:00
///
///[contextMenuFallback]: Context Menu used by the [InAppBrowser] instance fallback.
2019-12-01 11:55:06 +00:00
Future < void > open (
{ @ required String url ,
ChromeSafariBrowserClassOptions options ,
Map < String , String > headersFallback = const { } ,
InAppBrowserClassOptions optionsFallback } ) async {
2019-10-26 02:42:50 +00:00
assert ( url ! = null & & url . isNotEmpty ) ;
this . throwIsAlreadyOpened ( message: ' Cannot open $ url ! ' ) ;
2019-10-27 03:35:05 +00:00
2020-05-11 00:48:41 +00:00
List < Map < String , dynamic > > menuItemList = new List ( ) ;
_menuItems . forEach ( ( key , value ) {
menuItemList . add ( {
" id " : value . id ,
" label " : value . label
} ) ;
} ) ;
2019-10-27 03:35:05 +00:00
2019-10-26 02:42:50 +00:00
Map < String , dynamic > args = < String , dynamic > { } ;
args . putIfAbsent ( ' uuid ' , ( ) = > uuid ) ;
args . putIfAbsent ( ' url ' , ( ) = > url ) ;
2020-05-11 00:48:41 +00:00
args . putIfAbsent ( ' options ' , ( ) = > options ? . toMap ( ) ? ? { } ) ;
2020-05-21 01:34:39 +00:00
args . putIfAbsent ( ' menuItemList ' , ( ) = > menuItemList ) ;
2019-12-18 20:34:40 +00:00
args . putIfAbsent ( ' uuidFallback ' ,
( ) = > ( browserFallback ! = null ) ? browserFallback . uuid : ' ' ) ;
args . putIfAbsent ( ' headersFallback ' , ( ) = > headersFallback ) ;
2020-05-11 00:48:41 +00:00
args . putIfAbsent ( ' optionsFallback ' , ( ) = > optionsFallback ? . toMap ( ) ? ? { } ) ;
2020-05-21 01:34:39 +00:00
args . putIfAbsent ( ' contextMenuFallback ' , ( ) = > browserFallback ? . contextMenu ? . toMap ( ) ? ? { } ) ;
2019-12-18 20:34:40 +00:00
await _sharedChannel . invokeMethod ( ' open ' , args ) ;
2019-10-26 02:42:50 +00:00
this . _isOpened = true ;
}
2020-05-11 00:48:41 +00:00
///Closes the [ChromeSafariBrowser] instance.
Future < void > close ( ) async {
Map < String , dynamic > args = < String , dynamic > { } ;
await _channel . invokeMethod ( " close " , args ) ;
}
///Adds a [ChromeSafariBrowserMenuItem] to the menu.
void addMenuItem ( ChromeSafariBrowserMenuItem menuItem ) {
this . _menuItems [ menuItem . id ] = menuItem ;
}
///Adds a list of [ChromeSafariBrowserMenuItem] to the menu.
void addMenuItems ( List < ChromeSafariBrowserMenuItem > menuItems ) {
menuItems . forEach ( ( menuItem ) {
this . _menuItems [ menuItem . id ] = menuItem ;
} ) ;
}
2019-10-26 02:42:50 +00:00
///Event fires when the [ChromeSafariBrowser] is opened.
2019-12-01 11:55:06 +00:00
void onOpened ( ) { }
2019-10-26 02:42:50 +00:00
2019-12-18 00:56:21 +00:00
///Event fires when the initial URL load is complete.
void onCompletedInitialLoad ( ) { }
2019-10-26 02:42:50 +00:00
///Event fires when the [ChromeSafariBrowser] is closed.
2019-12-01 11:55:06 +00:00
void onClosed ( ) { }
2019-10-26 02:42:50 +00:00
2019-11-25 22:04:17 +00:00
///Returns `true` if the [ChromeSafariBrowser] instance is opened, otherwise `false`.
2019-10-26 02:42:50 +00:00
bool isOpened ( ) {
return this . _isOpened ;
}
void throwIsAlreadyOpened ( { String message = ' ' } ) {
if ( this . isOpened ( ) ) {
2019-12-01 11:55:06 +00:00
throw Exception ( [
' Error: ${ ( message . isEmpty ) ? ' ' : message + ' ' } The browser is already opened. '
] ) ;
2019-10-26 02:42:50 +00:00
}
}
void throwIsNotOpened ( { String message = ' ' } ) {
if ( ! this . isOpened ( ) ) {
2019-12-01 11:55:06 +00:00
throw Exception ( [
' Error: ${ ( message . isEmpty ) ? ' ' : message + ' ' } The browser is not opened. '
] ) ;
2019-10-26 02:42:50 +00:00
}
}
2019-12-01 11:55:06 +00:00
}
2020-05-11 00:48:41 +00:00
class ChromeSafariBrowserMenuItem {
int id ;
String label ;
final void Function ( String url , String title ) action ;
ChromeSafariBrowserMenuItem ( { @ required this . id , @ required this . label , @ required this . action } ) ;
}