diff --git a/packages/zweidenker_heinzelmen/CHANGELOG.md b/packages/zweidenker_heinzelmen/CHANGELOG.md index 60d725a..9234000 100644 --- a/packages/zweidenker_heinzelmen/CHANGELOG.md +++ b/packages/zweidenker_heinzelmen/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.0.2 - Added LinkLauncher +* Added LinkLauncher helper + + ## 0.0.1 - Initial Release * Added the following helpers * AppVersion diff --git a/packages/zweidenker_heinzelmen/lib/src/link_laucher.dart b/packages/zweidenker_heinzelmen/lib/src/link_laucher.dart new file mode 100644 index 0000000..16b3885 --- /dev/null +++ b/packages/zweidenker_heinzelmen/lib/src/link_laucher.dart @@ -0,0 +1,51 @@ +import 'package:flutter_web_browser/flutter_web_browser.dart'; +import 'package:universal_platform/universal_platform.dart'; +import 'package:url_launcher/url_launcher.dart'; + +export 'package:flutter_web_browser/flutter_web_browser.dart' + show CustomTabsOptions, SafariViewControllerOptions; + +/// Wrapper class for opening url's inside apps +class LinkLauncher { + /// Creates a LinkLauncher + const LinkLauncher(); + + /// Opens an url in a modal style on a mobile device or in a new tap on a web client + /// if [openExternally] is `true` this will also be launched externally + /// Use [tabsOptions] to customize the Chrome tabs on Android + /// Use [safariViewControllerOptions] to customize the SafariController on iOS + Future openWebPage({ + required Uri url, + bool openExternally = false, + CustomTabsOptions? tabsOptions, + SafariViewControllerOptions? safariViewControllerOptions, + }) async { + if (openExternally || UniversalPlatform.isDesktopOrWeb) { + /// Opens the url in a new tab in the browser + await launchUrl(url, mode: LaunchMode.externalApplication); + } else { + // coverage:ignore-start + // Ignore for Coverage as UniversalPlatform is not testable with a mock + // Check https://github.com/gskinnerTeam/flutter-universal-platform/issues/15 for reference + // This means that this branch of the if/else can not be properly testable + + /// Opens an url in a modal style on a mobile device + await FlutterWebBrowser.openWebPage( + url: url.toString(), + customTabsOptions: tabsOptions ?? + const CustomTabsOptions( + instantAppsEnabled: true, + urlBarHidingEnabled: true, + ), + safariVCOptions: safariViewControllerOptions ?? + const SafariViewControllerOptions( + barCollapsingEnabled: true, + modalPresentationCapturesStatusBarAppearance: true, + dismissButtonStyle: SafariViewControllerDismissButtonStyle.done, + modalPresentationStyle: UIModalPresentationStyle.fullScreen, + ), + ); + // coverage:ignore-end + } + } +} diff --git a/packages/zweidenker_heinzelmen/lib/zweidenker_heinzelmen.dart b/packages/zweidenker_heinzelmen/lib/zweidenker_heinzelmen.dart index 637bcd4..4bbee3d 100644 --- a/packages/zweidenker_heinzelmen/lib/zweidenker_heinzelmen.dart +++ b/packages/zweidenker_heinzelmen/lib/zweidenker_heinzelmen.dart @@ -3,3 +3,4 @@ library zweidenker_heinzelmen; export 'package:zweidenker_heinzelmen/src/app_version.dart'; export 'package:zweidenker_heinzelmen/src/feature_toggle.dart'; export 'package:zweidenker_heinzelmen/src/simple_loader_mixin.dart'; +export 'package:zweidenker_heinzelmen/src/link_laucher.dart'; diff --git a/packages/zweidenker_heinzelmen/pubspec.yaml b/packages/zweidenker_heinzelmen/pubspec.yaml index 7e2cc9d..905cbcd 100644 --- a/packages/zweidenker_heinzelmen/pubspec.yaml +++ b/packages/zweidenker_heinzelmen/pubspec.yaml @@ -1,6 +1,6 @@ name: zweidenker_heinzelmen description: A Flutter Package with useful helpers that are used across Flutter Apps by ZWEIDENKER -version: 0.0.1 +version: 0.0.2 repository: https://github.com/zweidenker/flutter-heinzelmen/packages/zweidenker_heinzelmen environment: @@ -10,13 +10,18 @@ environment: dependencies: flutter: sdk: flutter + flutter_web_browser: ^0.17.1 package_info_plus: ^1.4.2 universal_platform: ^1.0.0+1 + url_launcher: ^6.1.0 dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^1.0.0 + mocktail: ^0.3.0 + plugin_platform_interface: ^2.1.2 + url_launcher_platform_interface: ^2.0.5 flutter: diff --git a/packages/zweidenker_heinzelmen/test/infra/mocks.dart b/packages/zweidenker_heinzelmen/test/infra/mocks.dart index 8b13789..e1aadaa 100644 --- a/packages/zweidenker_heinzelmen/test/infra/mocks.dart +++ b/packages/zweidenker_heinzelmen/test/infra/mocks.dart @@ -1 +1,7 @@ +import 'package:mocktail/mocktail.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; +class MockUrlLauncherPlatform extends Mock + with MockPlatformInterfaceMixin + implements UrlLauncherPlatform {} diff --git a/packages/zweidenker_heinzelmen/test/src/link_launcher_test.dart b/packages/zweidenker_heinzelmen/test/src/link_launcher_test.dart new file mode 100644 index 0000000..ae07af0 --- /dev/null +++ b/packages/zweidenker_heinzelmen/test/src/link_launcher_test.dart @@ -0,0 +1,75 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:url_launcher_platform_interface/url_launcher_platform_interface.dart'; +import 'package:zweidenker_heinzelmen/zweidenker_heinzelmen.dart'; + +import '../infra/mocks.dart'; + +void main() { + const LinkLauncher linkLauncher = LinkLauncher(); + final testUri = Uri.parse('https://en.apptivegrid.de/'); + final mockUrlLauncher = MockUrlLauncherPlatform(); + + setUpAll(() { + UrlLauncherPlatform.instance = mockUrlLauncher; + }); + + group('Url Launcher', () { + test('Calls Url Launcher on Desktop', () async { + // TODO: Set Universal Explicitly to desktop (https://github.com/gskinnerTeam/flutter-universal-platform/issues/15) + when( + () => mockUrlLauncher.launch( + testUri.toString(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ).thenAnswer((invocation) async => true); + await linkLauncher.openWebPage(url: testUri); + + verify( + () => mockUrlLauncher.launch( + testUri.toString(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ).called(1); + }); + + test('Open Externally. Calls Url Launcher', () async { + when( + () => mockUrlLauncher.launch( + testUri.toString(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ).thenAnswer((invocation) async => true); + await linkLauncher.openWebPage(url: testUri, openExternally: true); + + verify( + () => mockUrlLauncher.launch( + testUri.toString(), + useSafariVC: any(named: 'useSafariVC'), + useWebView: any(named: 'useWebView'), + enableJavaScript: any(named: 'enableJavaScript'), + enableDomStorage: any(named: 'enableDomStorage'), + universalLinksOnly: any(named: 'universalLinksOnly'), + headers: any(named: 'headers'), + ), + ).called(1); + }); + }); + + // TODO: Add Test for non Desktop/Web (Waiting for https://github.com/gskinnerTeam/flutter-universal-platform/issues/15) +}