diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2c3f27b25..31147a5a6 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -96,8 +96,13 @@ PODS: - PromisesSwift (~> 2.1) - FirebaseSharedSwift (11.5.0) - Flutter (1.0.0) - - flutter_custom_tabs_ios (2.0.0): + - flutter_inappwebview_ios (0.0.1): - Flutter + - flutter_inappwebview_ios/Core (= 0.0.1) + - OrderedSet (~> 6.0.3) + - flutter_inappwebview_ios/Core (0.0.1): + - Flutter + - OrderedSet (~> 6.0.3) - flutter_secure_storage (6.0.0): - Flutter - fluttertoast (0.0.2): @@ -171,6 +176,7 @@ PODS: - nanopb/encode (= 3.30910.0) - nanopb/decode (3.30910.0) - nanopb/encode (3.30910.0) + - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter - path_provider_foundation (0.0.1): @@ -191,9 +197,6 @@ PODS: - Toast (4.1.1) - url_launcher_ios (0.0.1): - Flutter - - webview_flutter_wkwebview (0.0.1): - - Flutter - - FlutterMacOS DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`) @@ -204,7 +207,7 @@ DEPENDENCIES: - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) - firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`) - Flutter (from `Flutter`) - - flutter_custom_tabs_ios (from `.symlinks/plugins/flutter_custom_tabs_ios/ios`) + - flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`) - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) - google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`) @@ -216,7 +219,6 @@ DEPENDENCIES: - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - SwiftyXMLParser (from `https://github.com/yahoojapan/SwiftyXMLParser.git`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/darwin`) SPEC REPOS: trunk: @@ -238,6 +240,7 @@ SPEC REPOS: - GoogleMaps - GoogleUtilities - nanopb + - OrderedSet - PromisesObjC - PromisesSwift - Toast @@ -259,8 +262,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/firebase_remote_config/ios" Flutter: :path: Flutter - flutter_custom_tabs_ios: - :path: ".symlinks/plugins/flutter_custom_tabs_ios/ios" + flutter_inappwebview_ios: + :path: ".symlinks/plugins/flutter_inappwebview_ios/ios" flutter_secure_storage: :path: ".symlinks/plugins/flutter_secure_storage/ios" fluttertoast: @@ -283,8 +286,6 @@ EXTERNAL SOURCES: :git: https://github.com/yahoojapan/SwiftyXMLParser.git url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" - webview_flutter_wkwebview: - :path: ".symlinks/plugins/webview_flutter_wkwebview/darwin" CHECKOUT OPTIONS: SwiftyXMLParser: @@ -312,7 +313,7 @@ SPEC CHECKSUMS: FirebaseSessions: 3f56f177d9e53a85021d16b31f9a111849d1dd8b FirebaseSharedSwift: 302ac5967857ad7e7388b15382d705b8c8d892aa Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_custom_tabs_ios: a651b18786388923b62de8c0537607de87c2eccf + flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c Google-Maps-iOS-Utils: 66d6de12be1ce6d3742a54661e7a79cb317a9321 @@ -323,6 +324,7 @@ SPEC CHECKSUMS: GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 @@ -333,7 +335,6 @@ SPEC CHECKSUMS: SwiftyXMLParser: 027d9e6fb54a38d95dccec025bcea9693f699c47 Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - webview_flutter_wkwebview: 0982481e3d9c78fd5c6f62a002fcd24fc791f1e4 PODFILE CHECKSUM: 18f1615a0bcd417392c9107b3e8dc59c76a68dac diff --git a/lib/features/app/error/outage/widgets/outage_social_section.dart b/lib/features/app/error/outage/widgets/outage_social_section.dart index b0668b823..c23f3cff5 100644 --- a/lib/features/app/error/outage/widgets/outage_social_section.dart +++ b/lib/features/app/error/outage/widgets/outage_social_section.dart @@ -2,15 +2,16 @@ import 'package:flutter/material.dart'; // Package imports: -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; // Project imports: import 'package:notredame/constants/urls.dart'; -import 'package:notredame/utils/utils.dart'; +import 'package:notredame/utils/locator.dart'; +import 'package:notredame/features/app/integration/launch_url_service.dart'; class OutageSocialSection extends StatelessWidget { - const OutageSocialSection({super.key}); + OutageSocialSection({super.key}); + final LaunchUrlService _launchUrlService = locator(); @override Widget build(BuildContext context) { @@ -27,28 +28,28 @@ class OutageSocialSection extends StatelessWidget { color: Colors.white, ), onPressed: () => - Utils.launchURL(Urls.clubWebsite, AppIntl.of(context)!)), - IconButton( + _launchUrlService.launchInBrowser(Urls.clubWebsite)), + IconButton( icon: const FaIcon( FontAwesomeIcons.github, color: Colors.white, ), onPressed: () => - Utils.launchURL(Urls.clubGithub, AppIntl.of(context)!)), + _launchUrlService.launchInBrowser(Urls.clubGithub)), IconButton( icon: const FaIcon( Icons.mail_outline, color: Colors.white, ), onPressed: () => - Utils.launchURL(Urls.clubEmail, AppIntl.of(context)!)), + _launchUrlService.writeEmail(Urls.clubEmail, "")), IconButton( icon: const FaIcon( FontAwesomeIcons.discord, color: Colors.white, ), onPressed: () => - Utils.launchURL(Urls.clubDiscord, AppIntl.of(context)!)), + _launchUrlService.launchInBrowser(Urls.clubDiscord)) ], ), ], diff --git a/lib/features/app/integration/launch_url_service.dart b/lib/features/app/integration/launch_url_service.dart index 14c634825..5269e968a 100644 --- a/lib/features/app/integration/launch_url_service.dart +++ b/lib/features/app/integration/launch_url_service.dart @@ -1,8 +1,7 @@ // Flutter imports: -import 'package:flutter/material.dart'; +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; // Package imports: -import 'package:flutter_custom_tabs/flutter_custom_tabs.dart' as custom_tabs; import 'package:url_launcher/url_launcher.dart' as url_launch; // Project imports: @@ -12,58 +11,41 @@ import 'package:notredame/utils/locator.dart'; class LaunchUrlService { final SettingsManager settingsManager = locator(); + final browser = ChromeSafariBrowser(); - Future canLaunch(String url) async { - final uri = Uri.parse(url); - return url_launch.canLaunchUrl(uri); + Future writeEmail(String emailAddress, String subject) async { + final uri = Uri.parse('mailto:$emailAddress?subject=$subject'); + if (await url_launch.canLaunchUrl(uri)) { + url_launch.launchUrl(uri); + } else { + throw 'Could not send email to $emailAddress'; + } } - Future launch(String url) async { - final uri = Uri.parse(url); - return url_launch.launchUrl(uri); + Future call(String phoneNumber) async { + final uri = Uri.parse('tel:$phoneNumber'); + if (await url_launch.canLaunchUrl(uri)) { + url_launch.launchUrl(uri); + } else { + throw 'Could not call $phoneNumber'; + } } - Future launchInBrowser(String url, Brightness brightness) async { - await custom_tabs.launchUrl( - Uri.parse(url), - customTabsOptions: custom_tabs.CustomTabsOptions( - colorSchemes: custom_tabs.CustomTabsColorSchemes.defaults( - toolbarColor: brightness == Brightness.light - ? AppTheme.etsLightRed - : AppTheme.etsDarkRed), - shareState: custom_tabs.CustomTabsShareState.off, - urlBarHidingEnabled: true, - showTitle: true, - animations: custom_tabs.CustomTabsSystemAnimations.slideIn(), - browser: const custom_tabs.CustomTabsBrowserConfiguration( - fallbackCustomTabs: [ - // ref. https://play.google.com/store/apps/details?id=org.mozilla.firefox - 'org.mozilla.firefox', - // https://play.google.com/store/apps/details?id=com.brave.browser - 'com.brave.browser', - // https://play.google.com/store/apps/details?id=com.opera.browser - 'com.opera.browser', - 'com.opera.mini.native', - 'com.opera.gx', - // https://play.google.com/store/apps/details?id=com.sec.android.app.sbrowser - 'com.sec.android.app.sbrowser', - // ref. https://play.google.com/store/apps/details?id=com.microsoft.emmx - 'com.microsoft.emmx', - // https://play.google.com/store/apps/details?id=com.UCMobile.intl - 'com.UCMobile.intl', - ])), - safariVCOptions: custom_tabs.SafariViewControllerOptions( - preferredBarTintColor: brightness == Brightness.light - ? AppTheme.etsLightRed - : AppTheme.etsDarkRed, - preferredControlTintColor: brightness == Brightness.light - ? AppTheme.lightThemeBackground - : AppTheme.darkThemeBackground, - barCollapsingEnabled: true, - entersReaderIfAvailable: false, - dismissButtonStyle: - custom_tabs.SafariViewControllerDismissButtonStyle.close, - ), + void launchInBrowser(String url) { + browser.open( + url: WebUri(url), + settings: ChromeSafariBrowserSettings( + // Android + dismissButtonStyle: DismissButtonStyle.CLOSE, + enableUrlBarHiding: true, + toolbarBackgroundColor: AppTheme.accent, + navigationBarColor: AppTheme.primaryDark, + + // iOS + barCollapsingEnabled: true, + preferredControlTintColor: AppTheme.lightThemeBackground, + preferredBarTintColor: AppTheme.accent, + ) ); } } diff --git a/lib/features/app/navigation/router.dart b/lib/features/app/navigation/router.dart index 185848893..b7a8ddcdb 100644 --- a/lib/features/app/navigation/router.dart +++ b/lib/features/app/navigation/router.dart @@ -7,14 +7,12 @@ import 'package:notredame/features/app/error/outage/outage_view.dart'; import 'package:notredame/features/app/navigation/router_paths.dart'; import 'package:notredame/features/app/signets-api/models/course.dart'; import 'package:notredame/features/app/startup/startup_view.dart'; -import 'package:notredame/features/app/widgets/link_web_view.dart'; import 'package:notredame/features/dashboard/dashboard_view.dart'; import 'package:notredame/features/ets/ets_view.dart'; import 'package:notredame/features/ets/events/api-client/models/news.dart'; import 'package:notredame/features/ets/events/author/author_view.dart'; import 'package:notredame/features/ets/events/news/news-details/news_details_view.dart'; import 'package:notredame/features/ets/events/news/news_view.dart'; -import 'package:notredame/features/ets/quick-link/models/quick_link.dart'; import 'package:notredame/features/ets/quick-link/quick_links_view.dart'; import 'package:notredame/features/ets/quick-link/widgets/security-info/security_view.dart'; import 'package:notredame/features/more/about/about_view.dart'; @@ -106,10 +104,6 @@ Route generateRoute(RouteSettings routeSettings) { pageBuilder: (_, __, ___) => AuthorView( authorId: routeSettings.arguments! as String, )); - case RouterPaths.webView: - return MaterialPageRoute( - settings: RouteSettings(name: routeSettings.name), - builder: (_) => LinkWebView(routeSettings.arguments! as QuickLink)); case RouterPaths.security: return MaterialPageRoute( settings: RouteSettings(name: routeSettings.name), diff --git a/lib/features/app/navigation/router_paths.dart b/lib/features/app/navigation/router_paths.dart index fc03f0b9c..db01843fa 100644 --- a/lib/features/app/navigation/router_paths.dart +++ b/lib/features/app/navigation/router_paths.dart @@ -9,7 +9,6 @@ class RouterPaths { static const String student = "/student"; static const String gradeDetails = "/student/grade/details"; static const String ets = "/ets"; - static const String webView = "/ets/web-view"; static const String security = "/ets/security"; static const String usefulLinks = "/ets/useful-links"; static const String news = "/ets/news"; diff --git a/lib/features/app/widgets/link_web_view.dart b/lib/features/app/widgets/link_web_view.dart deleted file mode 100644 index c865b0497..000000000 --- a/lib/features/app/widgets/link_web_view.dart +++ /dev/null @@ -1,46 +0,0 @@ -// Flutter imports: -import 'package:flutter/material.dart'; - -// Package imports: -import 'package:webview_flutter/webview_flutter.dart'; - -// Project imports: -import 'package:notredame/features/app/widgets/base_scaffold.dart'; -import 'package:notredame/features/ets/quick-link/models/quick_link.dart'; - -class LinkWebView extends StatefulWidget { - final QuickLink _links; - - const LinkWebView(this._links, {super.key}); - - @override - State createState() => _LinkWebViewState(); -} - -class _LinkWebViewState extends State { - bool isLoading = true; - - @override - Widget build(BuildContext context) { - return BaseScaffold( - isLoading: isLoading, - showBottomBar: false, - appBar: AppBar( - title: Text(widget._links.name), - ), - body: Stack( - children: [ - WebViewWidget( - controller: WebViewController() - ..setJavaScriptMode(JavaScriptMode.unrestricted) - ..setNavigationDelegate( - NavigationDelegate(onPageFinished: (String url) { - setState(() { - isLoading = false; - }); - }))), - ], - ), - ); - } -} diff --git a/lib/features/dashboard/dashboard_view.dart b/lib/features/dashboard/dashboard_view.dart index 6a2fb258e..8f635cfd4 100644 --- a/lib/features/dashboard/dashboard_view.dart +++ b/lib/features/dashboard/dashboard_view.dart @@ -26,7 +26,7 @@ import 'package:notredame/features/student/grades/widgets/grade_button.dart'; import 'package:notredame/utils/app_theme.dart'; import 'package:notredame/utils/loading.dart'; import 'package:notredame/utils/locator.dart'; -import 'package:notredame/utils/utils.dart'; +import 'package:notredame/features/app/integration/launch_url_service.dart'; class DashboardView extends StatefulWidget { const DashboardView({super.key}); @@ -38,6 +38,7 @@ class DashboardView extends StatefulWidget { class _DashboardViewState extends State with TickerProviderStateMixin { Text? progressBarText; + final LaunchUrlService _launchUrlService = locator(); final NavigationService _navigationService = locator(); final AnalyticsService _analyticsService = locator(); static const String tag = "DashboardView"; @@ -145,8 +146,7 @@ class _DashboardViewState extends State IconButton( onPressed: () { _analyticsService.logEvent(tag, "Facebook clicked"); - Utils.launchURL( - Urls.clubFacebook, AppIntl.of(context)!); + _launchUrlService.launchInBrowser(Urls.clubFacebook); }, icon: const FaIcon( FontAwesomeIcons.facebook, @@ -156,8 +156,7 @@ class _DashboardViewState extends State IconButton( onPressed: () { _analyticsService.logEvent(tag, "Instagram clicked"); - Utils.launchURL( - Urls.clubInstagram, AppIntl.of(context)!); + _launchUrlService.launchInBrowser(Urls.clubInstagram); }, icon: const FaIcon( FontAwesomeIcons.instagram, @@ -167,8 +166,8 @@ class _DashboardViewState extends State IconButton( onPressed: () { _analyticsService.logEvent(tag, "Github clicked"); - Utils.launchURL(Urls.clubGithub, AppIntl.of(context)!); - }, + _launchUrlService.launchInBrowser(Urls.clubGithub); + }, icon: const FaIcon( FontAwesomeIcons.github, color: Colors.white, @@ -177,7 +176,7 @@ class _DashboardViewState extends State IconButton( onPressed: () { _analyticsService.logEvent(tag, "Email clicked"); - Utils.launchURL(Urls.clubEmail, AppIntl.of(context)!); + _launchUrlService.writeEmail(Urls.clubEmail, ""); }, icon: const FaIcon( FontAwesomeIcons.envelope, @@ -187,8 +186,8 @@ class _DashboardViewState extends State IconButton( onPressed: () { _analyticsService.logEvent(tag, "Discord clicked"); - Utils.launchURL(Urls.clubDiscord, AppIntl.of(context)!); - }, + _launchUrlService.launchInBrowser(Urls.clubDiscord); + }, icon: const FaIcon( FontAwesomeIcons.discord, color: Colors.white, diff --git a/lib/features/dashboard/dashboard_viewmodel.dart b/lib/features/dashboard/dashboard_viewmodel.dart index c7d3ba874..8e4283aeb 100644 --- a/lib/features/dashboard/dashboard_viewmodel.dart +++ b/lib/features/dashboard/dashboard_viewmodel.dart @@ -1,9 +1,6 @@ // Dart imports: import 'dart:collection'; -// Flutter imports: -import 'package:flutter/material.dart'; - // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -15,8 +12,6 @@ import 'package:notredame/constants/preferences_flags.dart'; import 'package:notredame/features/app/analytics/analytics_service.dart'; import 'package:notredame/features/app/analytics/remote_config_service.dart'; import 'package:notredame/features/app/integration/launch_url_service.dart'; -import 'package:notredame/features/app/navigation/navigation_service.dart'; -import 'package:notredame/features/app/navigation/router_paths.dart'; import 'package:notredame/features/app/repository/course_repository.dart'; import 'package:notredame/features/app/signets-api/models/course.dart'; import 'package:notredame/features/app/signets-api/models/course_activity.dart'; @@ -136,13 +131,7 @@ class DashboardViewModel extends FutureViewModel> { static Future launchBroadcastUrl(String url) async { final LaunchUrlService launchUrlService = locator(); - final NavigationService navigationService = locator(); - try { - await launchUrlService.launchInBrowser(url, Brightness.light); - } catch (error) { - // An exception is thrown if browser app is not installed on Android device. - await navigationService.pushNamed(RouterPaths.webView, arguments: url); - } + launchUrlService.launchInBrowser(url); } void changeProgressBarText() { diff --git a/lib/features/ets/events/social/social_links_card.dart b/lib/features/ets/events/social/social_links_card.dart index 502a1b5f0..4f60eb56d 100644 --- a/lib/features/ets/events/social/social_links_card.dart +++ b/lib/features/ets/events/social/social_links_card.dart @@ -152,7 +152,7 @@ class _SocialLinksState extends State { Widget _buildSocialButton(SocialLink link, WebLinkCardViewModel model) { return IconButton( icon: link.image, - onPressed: () => model.onLinkClicked(link, Theme.of(context).brightness), + onPressed: () => model.onLinkClicked(link), ); } } diff --git a/lib/features/ets/quick-link/widgets/security-info/emergency_view.dart b/lib/features/ets/quick-link/widgets/security-info/emergency_view.dart index c66cb75e1..6666b4c2d 100644 --- a/lib/features/ets/quick-link/widgets/security-info/emergency_view.dart +++ b/lib/features/ets/quick-link/widgets/security-info/emergency_view.dart @@ -9,7 +9,8 @@ import 'package:flutter_markdown/flutter_markdown.dart'; // Project imports: import 'package:notredame/features/app/widgets/base_scaffold.dart'; import 'package:notredame/utils/app_theme.dart'; -import 'package:notredame/utils/utils.dart'; +import 'package:notredame/utils/locator.dart'; +import 'package:notredame/features/app/integration/launch_url_service.dart'; class EmergencyView extends StatefulWidget { final String title; @@ -22,6 +23,8 @@ class EmergencyView extends StatefulWidget { } class _EmergencyViewState extends State { + final LaunchUrlService _launchUrlService = locator(); + @override Widget build(BuildContext context) => BaseScaffold( appBar: AppBar(title: Text(widget.title)), @@ -31,9 +34,7 @@ class _EmergencyViewState extends State { fab: FloatingActionButton.extended( onPressed: () { try { - Utils.launchURL( - 'tel:${AppIntl.of(context)!.security_emergency_number}', - AppIntl.of(context)!); + _launchUrlService.call(AppIntl.of(context)!.security_emergency_number); } catch (e) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text(e.toString()))); diff --git a/lib/features/ets/quick-link/widgets/security-info/security_view.dart b/lib/features/ets/quick-link/widgets/security-info/security_view.dart index fd86f7dcd..26f47ca58 100644 --- a/lib/features/ets/quick-link/widgets/security-info/security_view.dart +++ b/lib/features/ets/quick-link/widgets/security-info/security_view.dart @@ -13,7 +13,8 @@ import 'package:notredame/features/app/widgets/base_scaffold.dart'; import 'package:notredame/features/ets/quick-link/widgets/security-info/emergency_view.dart'; import 'package:notredame/features/ets/quick-link/widgets/security-info/security_viewmodel.dart'; import 'package:notredame/utils/app_theme.dart'; -import 'package:notredame/utils/utils.dart'; +import 'package:notredame/utils/locator.dart'; +import 'package:notredame/features/app/integration/launch_url_service.dart'; class SecurityView extends StatefulWidget { const SecurityView({super.key}); @@ -23,6 +24,7 @@ class SecurityView extends StatefulWidget { } class _SecurityViewState extends State { + final LaunchUrlService _launchUrlService = locator(); static const CameraPosition _etsLocation = CameraPosition( target: LatLng(45.49449875, -73.56246144109338), zoom: 17.0); @@ -84,9 +86,7 @@ class _SecurityViewState extends State { splashColor: Colors.red.withAlpha(50), onTap: () { try { - Utils.launchURL( - 'tel:${AppIntl.of(context)!.security_emergency_number}', - AppIntl.of(context)!); + _launchUrlService.call(AppIntl.of(context)!.security_emergency_number); } catch (e) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text(e.toString()))); diff --git a/lib/features/ets/quick-link/widgets/web_link_card.dart b/lib/features/ets/quick-link/widgets/web_link_card.dart index 890afe02c..121e12af0 100644 --- a/lib/features/ets/quick-link/widgets/web_link_card.dart +++ b/lib/features/ets/quick-link/widgets/web_link_card.dart @@ -26,7 +26,7 @@ class WebLinkCard extends StatelessWidget { child: InkWell( borderRadius: const BorderRadius.all(Radius.circular(10)), onTap: () => - model.onLinkClicked(_links, Theme.of(context).brightness), + model.onLinkClicked(_links), splashColor: AppTheme.etsLightRed.withAlpha(50), child: Padding( padding: const EdgeInsets.all(8.0), diff --git a/lib/features/ets/quick-link/widgets/web_link_card_viewmodel.dart b/lib/features/ets/quick-link/widgets/web_link_card_viewmodel.dart index c7fa0a96a..97f089fde 100644 --- a/lib/features/ets/quick-link/widgets/web_link_card_viewmodel.dart +++ b/lib/features/ets/quick-link/widgets/web_link_card_viewmodel.dart @@ -1,7 +1,3 @@ -// Flutter imports: -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - // Package imports: import 'package:stacked/stacked.dart'; @@ -22,22 +18,13 @@ class WebLinkCardViewModel extends BaseViewModel { final LaunchUrlService _launchUrlService = locator(); /// used to open a website or the security view - Future onLinkClicked(QuickLink link, Brightness brightness) async { + Future onLinkClicked(QuickLink link) async { _analyticsService.logEvent("QuickLink", "QuickLink clicked: ${link.name}"); if (link.link == 'security') { _navigationService.pushNamed(RouterPaths.security); } else { - try { - await _launchUrlService.launchInBrowser(link.link, brightness); - } catch (error) { - // An exception is thrown if browser app is not installed on Android device. - await launchWebView(link); - } + _launchUrlService.launchInBrowser(link.link); } } - - Future launchWebView(QuickLink link) async { - _navigationService.pushNamed(RouterPaths.webView, arguments: link); - } } diff --git a/lib/features/more/about/about_view.dart b/lib/features/more/about/about_view.dart index 28ab61352..b41834b43 100644 --- a/lib/features/more/about/about_view.dart +++ b/lib/features/more/about/about_view.dart @@ -8,7 +8,8 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; // Project imports: import 'package:notredame/constants/urls.dart'; -import 'package:notredame/utils/utils.dart'; +import 'package:notredame/utils/locator.dart'; +import 'package:notredame/features/app/integration/launch_url_service.dart'; class AboutView extends StatefulWidget { const AboutView({super.key}); @@ -18,6 +19,7 @@ class AboutView extends StatefulWidget { } class _AboutViewState extends State with TickerProviderStateMixin { + final LaunchUrlService _launchUrlService = locator(); late AnimationController _controller; bool _completed = false; bool _easterEggTrigger = false; @@ -128,43 +130,43 @@ class _AboutViewState extends State with TickerProviderStateMixin { FontAwesomeIcons.earthAmericas, color: Colors.white, ), - onPressed: () => Utils.launchURL( - Urls.clubWebsite, AppIntl.of(context)!)), + onPressed: () => + _launchUrlService.launchInBrowser(Urls.clubWebsite)), IconButton( icon: const FaIcon( FontAwesomeIcons.github, color: Colors.white, ), - onPressed: () => Utils.launchURL( - Urls.clubGithub, AppIntl.of(context)!)), + onPressed: () => + _launchUrlService.launchInBrowser(Urls.clubGithub)), IconButton( icon: const FaIcon( FontAwesomeIcons.facebook, color: Colors.white, ), - onPressed: () => Utils.launchURL( - Urls.clubFacebook, AppIntl.of(context)!)), + onPressed: () => + _launchUrlService.launchInBrowser(Urls.clubFacebook)), IconButton( icon: const FaIcon( FontAwesomeIcons.twitter, color: Colors.white, ), - onPressed: () => Utils.launchURL( - Urls.clubTwitter, AppIntl.of(context)!)), + onPressed: () => + _launchUrlService.launchInBrowser(Urls.clubTwitter)), IconButton( icon: const FaIcon( FontAwesomeIcons.youtube, color: Colors.white, ), - onPressed: () => Utils.launchURL( - Urls.clubYoutube, AppIntl.of(context)!)), + onPressed: () => + _launchUrlService.launchInBrowser(Urls.clubYoutube)), IconButton( icon: const FaIcon( FontAwesomeIcons.discord, color: Colors.white, ), - onPressed: () => Utils.launchURL( - Urls.clubDiscord, AppIntl.of(context)!)), + onPressed: () => + _launchUrlService.launchInBrowser(Urls.clubDiscord)), ], ), ), diff --git a/lib/features/more/contributors/contributors_view.dart b/lib/features/more/contributors/contributors_view.dart index 33c3ceec4..2409c9443 100644 --- a/lib/features/more/contributors/contributors_view.dart +++ b/lib/features/more/contributors/contributors_view.dart @@ -10,10 +10,12 @@ import 'package:stacked/stacked.dart'; // Project imports: import 'package:notredame/features/app/widgets/base_scaffold.dart'; import 'package:notredame/features/more/contributors/contributors_viewmodel.dart'; -import 'package:notredame/utils/utils.dart'; +import 'package:notredame/utils/locator.dart'; +import 'package:notredame/features/app/integration/launch_url_service.dart'; class ContributorsView extends StatelessWidget { - const ContributorsView({super.key}); + ContributorsView({super.key}); + final LaunchUrlService _launchUrlService = locator(); @override Widget build(BuildContext context) => @@ -54,8 +56,8 @@ class ContributorsView extends StatelessWidget { leading: CircleAvatar( backgroundColor: Colors.grey, backgroundImage: NetworkImage(contributors[index].avatarUrl ?? '')), - onTap: () => Utils.launchURL( - contributors[index].htmlUrl ?? '', AppIntl.of(context)!), + onTap: () => + _launchUrlService.launchInBrowser(contributors[index].htmlUrl ?? ''), ), ); } diff --git a/lib/features/more/faq/faq_view.dart b/lib/features/more/faq/faq_view.dart index c2f893eaa..c7c1e0b94 100644 --- a/lib/features/more/faq/faq_view.dart +++ b/lib/features/more/faq/faq_view.dart @@ -184,9 +184,9 @@ class _FaqViewState extends State { child: ElevatedButton( onPressed: () { if (type.name == ActionType.webview.name) { - openWebview(model, link); + model.launchWebsite(link); } else if (type.name == ActionType.email.name) { - openMail(model, context, link); + model.openMail(link, context); } }, style: ButtonStyle( @@ -253,13 +253,4 @@ class _FaqViewState extends State { ), ); } - - Future openWebview(FaqViewModel model, String link) async { - model.launchWebsite(link, Theme.of(context).brightness); - } - - Future openMail( - FaqViewModel model, BuildContext context, String addressEmail) async { - model.openMail(addressEmail, context); - } } diff --git a/lib/features/more/faq/faq_viewmodel.dart b/lib/features/more/faq/faq_viewmodel.dart index 424870280..e836e2ed0 100644 --- a/lib/features/more/faq/faq_viewmodel.dart +++ b/lib/features/more/faq/faq_viewmodel.dart @@ -19,27 +19,20 @@ class FaqViewModel extends BaseViewModel { Locale? get locale => _settingsManager.locale; - String mailtoStr(String email, String subject) { - return 'mailto:$email?subject=$subject'; - } - - Future launchWebsite(String link, Brightness brightness) async { - await _launchUrlService.launchInBrowser(link, brightness); + void launchWebsite(String link) { + _launchUrlService.launchInBrowser(link); } Future openMail(String addressEmail, BuildContext context) async { - var email = ""; + String subject = ""; + if (addressEmail == AppInfo.email) { - email = mailtoStr(addressEmail, AppIntl.of(context)!.email_subject); - } else { - email = mailtoStr(addressEmail, ""); + subject = AppIntl.of(context)!.email_subject; } - final urlLaunchable = await _launchUrlService.canLaunch(email); - - if (urlLaunchable) { - await _launchUrlService.launch(email); - } else { + try { + _launchUrlService.writeEmail(addressEmail, subject); + } catch (e) { locator().logError("login_view", "Cannot send email."); } } diff --git a/lib/features/more/feedback/feedback_view.dart b/lib/features/more/feedback/feedback_view.dart index 5fe59db1f..9bdda1c6a 100644 --- a/lib/features/more/feedback/feedback_view.dart +++ b/lib/features/more/feedback/feedback_view.dart @@ -11,7 +11,8 @@ import 'package:notredame/features/more/feedback/feedback_type.dart'; import 'package:notredame/features/more/feedback/feedback_viewmodel.dart'; import 'package:notredame/utils/app_theme.dart'; import 'package:notredame/utils/loading.dart'; -import 'package:notredame/utils/utils.dart'; +import 'package:notredame/utils/locator.dart'; +import 'package:notredame/features/app/integration/launch_url_service.dart'; class FeedbackView extends StatefulWidget { const FeedbackView({super.key}); @@ -21,6 +22,8 @@ class FeedbackView extends StatefulWidget { } class _FeedbackViewState extends State { + final LaunchUrlService _launchUrlService = locator(); + @override Widget build(BuildContext context) => ViewModelBuilder.reactive( @@ -116,8 +119,7 @@ class _FeedbackViewState extends State { Theme.of(context).brightness == Brightness.light; return GestureDetector( onTap: () => { - Utils.launchURL(model.myIssues[index].htmlUrl, - AppIntl.of(context)!) + _launchUrlService.launchInBrowser(model.myIssues[index].htmlUrl) }, child: Container( margin: const EdgeInsets.only( diff --git a/lib/features/more/more_view.dart b/lib/features/more/more_view.dart index 5d61b73de..e561c2ee4 100644 --- a/lib/features/more/more_view.dart +++ b/lib/features/more/more_view.dart @@ -14,6 +14,7 @@ import 'package:notredame/features/more/more_viewmodel.dart'; import 'package:notredame/utils/app_theme.dart'; import 'package:notredame/utils/locator.dart'; import 'package:notredame/utils/utils.dart'; +import 'package:notredame/features/app/integration/launch_url_service.dart'; class MoreView extends StatefulWidget { const MoreView({super.key}); @@ -23,6 +24,7 @@ class MoreView extends StatefulWidget { } class _MoreViewState extends State { + final LaunchUrlService _launchUrlService = locator(); final AnalyticsService _analyticsService = locator(); static const String tag = "MoreView"; @@ -47,9 +49,8 @@ class _MoreViewState extends State { style: textStyle.copyWith(color: Colors.blue), text: AppIntl.of(context)!.flutter_website, recognizer: TapGestureRecognizer() - ..onTap = () => Utils.launchURL( - AppIntl.of(context)!.flutter_website, - AppIntl.of(context)!)), + ..onTap = () => + _launchUrlService.launchInBrowser(AppIntl.of(context)!.flutter_website)), TextSpan(style: textStyle, text: '.'), ], ), diff --git a/lib/features/more/more_viewmodel.dart b/lib/features/more/more_viewmodel.dart index e2d3a391c..0b4f9fe9e 100644 --- a/lib/features/more/more_viewmodel.dart +++ b/lib/features/more/more_viewmodel.dart @@ -1,6 +1,3 @@ -// Flutter imports: -import 'package:flutter/material.dart'; - // Package imports: import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:fluttertoast/fluttertoast.dart'; @@ -115,17 +112,8 @@ class MoreViewModel extends FutureViewModel { static Future launchPrivacyPolicy() async { final LaunchUrlService launchUrlService = locator(); - final RemoteConfigService remoteConfigService = - locator(); - final NavigationService navigationService = locator(); - try { - await launchUrlService.launchInBrowser( - remoteConfigService.privacyPolicyUrl, Brightness.light); - } catch (error) { - // An exception is thrown if browser app is not installed on Android device. - await navigationService.pushNamed(RouterPaths.webView, - arguments: remoteConfigService.privacyPolicyUrl); - } + final RemoteConfigService remoteConfigService = locator(); + launchUrlService.launchInBrowser(remoteConfigService.privacyPolicyUrl); } /// Get the privacy policy toggle diff --git a/lib/features/schedule/schedule_view.dart b/lib/features/schedule/schedule_view.dart index b8b42f3b1..673f2d6f3 100644 --- a/lib/features/schedule/schedule_view.dart +++ b/lib/features/schedule/schedule_view.dart @@ -142,7 +142,7 @@ class _ScheduleViewState extends State const SizedBox(height: 8.0), const Divider(indent: 8.0, endIndent: 8.0, thickness: 1), const SizedBox(height: 6.0), - _buildTitleForDate(model.daySelected, model), + _buildTitleForDate(model.daySelected, model), const SizedBox(height: 2.0), if (model.selectedDateEvents(model.daySelected).isEmpty && !model.isBusy) Padding( @@ -327,12 +327,12 @@ class _ScheduleViewState extends State Icons.chevron_left, size: 30, color: chevronColor, - ), + ), rightIcon: Icon( Icons.chevron_right, size: 30, color: chevronColor, - )), + )), weekDayStringBuilder: (p0) { return weekTitles[p0]; }, diff --git a/lib/features/welcome/widgets/forgot_password.dart b/lib/features/welcome/widgets/forgot_password.dart index 2b7199c97..50c349f86 100644 --- a/lib/features/welcome/widgets/forgot_password.dart +++ b/lib/features/welcome/widgets/forgot_password.dart @@ -44,9 +44,7 @@ class _ForgotPasswordState extends State{ .signetsPasswordResetUrl; if (signetsPasswordResetUrl != "") { _launchUrlService.launchInBrowser( - _remoteConfigService - .signetsPasswordResetUrl, - Theme.of(context).brightness); + _remoteConfigService.signetsPasswordResetUrl); } else { Fluttertoast.showToast( msg: AppIntl.of(context)! diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 4c8bded4d..75d3083b2 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -1,23 +1,7 @@ // Flutter imports: import 'package:flutter/material.dart'; -// Package imports: -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:fluttertoast/fluttertoast.dart'; -import 'package:url_launcher/url_launcher.dart'; - mixin Utils { - /// Used to open a url - static Future launchURL(String url, AppIntl intl) async { - final uri = Uri.parse(url); - if (await canLaunchUrl(uri)) { - await launchUrl(uri); - } else { - Fluttertoast.showToast(msg: intl.error); - throw 'Could not launch $url'; - } - } - static double getGradeInPercentage(double? grade, double? maxGrade) { if (grade == null || maxGrade == null || grade == 0.0 || maxGrade == 0.0) { return 0.0; diff --git a/pubspec.lock b/pubspec.lock index 37cc59a09..3b6da9fb1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -435,46 +435,70 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" - flutter_custom_tabs: + flutter_inappwebview: dependency: "direct main" description: - name: flutter_custom_tabs - sha256: "34167bd15fa3479855c011f868e0789c9569c12b64358ca7250accc5a24c3312" + name: flutter_inappwebview + sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" url: "https://pub.dev" source: hosted - version: "2.1.0" - flutter_custom_tabs_android: + version: "6.1.5" + flutter_inappwebview_android: dependency: transitive description: - name: flutter_custom_tabs_android - sha256: cf06fde8c002f326dc6cbf69ee3f97c3feead4436229da02d2e2aa39d5a5dbf4 + name: flutter_inappwebview_android + sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" url: "https://pub.dev" source: hosted - version: "2.1.0" - flutter_custom_tabs_ios: + version: "1.1.3" + flutter_inappwebview_internal_annotations: dependency: transitive description: - name: flutter_custom_tabs_ios - sha256: ef2de533bc45fb84fefc3854bc8b1e43001671c6bc6bc55faa57942eecd3f70a + name: flutter_inappwebview_internal_annotations + sha256: "5f80fd30e208ddded7dbbcd0d569e7995f9f63d45ea3f548d8dd4c0b473fb4c8" url: "https://pub.dev" source: hosted - version: "2.1.0" - flutter_custom_tabs_platform_interface: + version: "1.1.1" + flutter_inappwebview_ios: dependency: transitive description: - name: flutter_custom_tabs_platform_interface - sha256: e18e9b08f92582123bdb84fb6e4c91804b0579700fed6f887d32fd9a1e96a5d5 + name: flutter_inappwebview_ios + sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" url: "https://pub.dev" source: hosted - version: "2.1.0" - flutter_custom_tabs_web: + version: "1.1.2" + flutter_inappwebview_macos: dependency: transitive description: - name: flutter_custom_tabs_web - sha256: "08ae322b11e1972a233d057542279873d0f9d1d5f8159c2c741457239d9d562c" + name: flutter_inappwebview_macos + sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "1.1.2" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 + url: "https://pub.dev" + source: hosted + version: "1.3.0+1" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_windows: + dependency: transitive + description: + name: flutter_inappwebview_windows + sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" + url: "https://pub.dev" + source: hosted + version: "0.6.0" flutter_launcher_icons: dependency: "direct dev" description: @@ -1559,14 +1583,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" - webview_flutter: - dependency: "direct main" - description: - name: webview_flutter - sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" - url: "https://pub.dev" - source: hosted - version: "4.10.0" webview_flutter_android: dependency: "direct dev" description: @@ -1583,14 +1599,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.10.0" - webview_flutter_wkwebview: - dependency: transitive - description: - name: webview_flutter_wkwebview - sha256: "3be297aa4ca78205abdd284cf55f168c35246c75b3079990ad8ba9d257681a30" - url: "https://pub.dev" - source: hosted - version: "3.16.2" win32: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0c6c962f8..dfbdce0f8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ description: The 4th generation of ÉTSMobile, the main gateway between the Éco # pub.dev using `pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 4.55.0 +version: 4.55.1 environment: sdk: '>=3.3.0 <4.0.0' @@ -28,9 +28,8 @@ dependencies: firebase_remote_config: ^5.1.3 # Web + flutter_inappwebview: ^6.1.5 url_launcher: ^6.3.1 - webview_flutter: ^4.10.0 - flutter_custom_tabs: ^2.1.0 # Utils logger: ^2.4.0 diff --git a/test/features/app/integration/mocks/launch_url_service_mock.dart b/test/features/app/integration/mocks/launch_url_service_mock.dart index f323a6d29..65c79eb4a 100644 --- a/test/features/app/integration/mocks/launch_url_service_mock.dart +++ b/test/features/app/integration/mocks/launch_url_service_mock.dart @@ -1,6 +1,5 @@ // Package imports: import 'package:mockito/annotations.dart'; -import 'package:mockito/mockito.dart'; // Project imports: import 'package:notredame/features/app/integration/launch_url_service.dart'; @@ -8,14 +7,4 @@ import 'launch_url_service_mock.mocks.dart'; /// Mock for the [LaunchUrlService] @GenerateNiceMocks([MockSpec()]) -class LaunchUrlServiceMock extends MockLaunchUrlService { - static void stubCanLaunchUrl(LaunchUrlServiceMock client, String url, - {bool toReturn = true}) { - when(client.canLaunch(url)).thenAnswer((_) async => toReturn); - } - - static void stubLaunchUrl(LaunchUrlServiceMock client, String url, - {bool toReturn = true}) { - when(client.launch(url)).thenAnswer((_) async => toReturn); - } -} +class LaunchUrlServiceMock extends MockLaunchUrlService {} diff --git a/test/features/app/widgets/link_web_view_test.dart b/test/features/app/widgets/link_web_view_test.dart deleted file mode 100644 index a2447d963..000000000 --- a/test/features/app/widgets/link_web_view_test.dart +++ /dev/null @@ -1,38 +0,0 @@ -// Flutter imports: -import 'package:flutter/material.dart'; - -// Package imports: -import 'package:flutter_test/flutter_test.dart'; -import 'package:webview_flutter/webview_flutter.dart'; -import 'package:webview_flutter_android/webview_flutter_android.dart'; - -// Project imports: -import 'package:notredame/features/app/widgets/link_web_view.dart'; -import 'package:notredame/features/ets/quick-link/models/quick_link.dart'; -import '../../../common/helpers.dart'; - -final _quickLink = QuickLink( - id: 1, - image: const Icon(Icons.ac_unit), - name: 'test', - link: 'https://clubapplets.ca/'); - -void main() { - group('LinkWebView - ', () { - setUp(() { - WebViewPlatform.instance = AndroidWebViewPlatform(); - setupNetworkingServiceMock(); - }); - - testWidgets('has an AppBar and a WebView', (WidgetTester tester) async { - await tester.pumpWidget(localizedWidget(child: LinkWebView(_quickLink))); - - final appBar = find.byType(AppBar); - final webview = find.byType(WebViewWidget); - - expect(appBar, findsNWidgets(1)); - expect(_quickLink.name, 'test'); - expect(webview, findsNWidgets(1)); - }); - }); -} diff --git a/test/features/dashboard/dashboard_view_test.dart b/test/features/dashboard/dashboard_view_test.dart index e0ef8e71f..87975af32 100644 --- a/test/features/dashboard/dashboard_view_test.dart +++ b/test/features/dashboard/dashboard_view_test.dart @@ -173,6 +173,7 @@ void main() { courseRepositoryMock = setupCourseRepositoryMock(); setupNetworkingServiceMock(); setupAnalyticsServiceMock(); + setupLaunchUrlServiceMock(); setupPreferencesServiceMock(); // TODO: Remove when 4.50.1 is released SharedPreferences.setMockInitialValues({}); diff --git a/test/features/ets/quick-link/widgets/security-info/emergency_view_test.dart b/test/features/ets/quick-link/widgets/security-info/emergency_view_test.dart index b104cb83b..3843feb31 100644 --- a/test/features/ets/quick-link/widgets/security-info/emergency_view_test.dart +++ b/test/features/ets/quick-link/widgets/security-info/emergency_view_test.dart @@ -4,8 +4,6 @@ import 'package:flutter/material.dart'; // Package imports: import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:flutter_test/flutter_test.dart'; -import 'package:webview_flutter/webview_flutter.dart'; -import 'package:webview_flutter_android/webview_flutter_android.dart'; // Project imports: import 'package:notredame/features/ets/quick-link/widgets/security-info/emergency_view.dart'; @@ -14,8 +12,8 @@ import '../../../../../common/helpers.dart'; void main() { group('EmergencyView - ', () { setUp(() async { - WebViewPlatform.instance = AndroidWebViewPlatform(); setupNetworkingServiceMock(); + setupLaunchUrlServiceMock(); }); tearDown(() {}); diff --git a/test/features/ets/quick-link/widgets/security-info/security_view_test.dart b/test/features/ets/quick-link/widgets/security-info/security_view_test.dart index 6ff3db4eb..00f3e9786 100644 --- a/test/features/ets/quick-link/widgets/security-info/security_view_test.dart +++ b/test/features/ets/quick-link/widgets/security-info/security_view_test.dart @@ -18,6 +18,7 @@ void main() { setUp(() async { intl = await setupAppIntl(); setupNetworkingServiceMock(); + setupLaunchUrlServiceMock(); }); tearDown(() {}); diff --git a/test/features/ets/quick-link/widgets/web_link_card_viewmodel_test.dart b/test/features/ets/quick-link/widgets/web_link_card_viewmodel_test.dart index bbd4f8335..d2f592219 100644 --- a/test/features/ets/quick-link/widgets/web_link_card_viewmodel_test.dart +++ b/test/features/ets/quick-link/widgets/web_link_card_viewmodel_test.dart @@ -58,7 +58,7 @@ void main() { group('onLinkClicked -', () { test('navigate to security', () async { - await viewModel.onLinkClicked(securityQuickLink, Brightness.light); + await viewModel.onLinkClicked(securityQuickLink); verify(analyticsServiceMock.logEvent( "QuickLink", "QuickLink clicked: test")); @@ -70,10 +70,9 @@ void main() { InternalInfoServiceMock.stubGetDeviceInfoForErrorReporting( internalInfoServiceMock); - await viewModel.onLinkClicked(quickLink, Brightness.light); + await viewModel.onLinkClicked(quickLink); - verify(launchUrlServiceMock.launchInBrowser( - quickLink.link, Brightness.light)); + verify(launchUrlServiceMock.launchInBrowser(quickLink.link)); verifyNoMoreInteractions(navigationServiceMock); }); }); diff --git a/test/features/more/about/about_view_test.dart b/test/features/more/about/about_view_test.dart index 23d376d1a..fb5222c3e 100644 --- a/test/features/more/about/about_view_test.dart +++ b/test/features/more/about/about_view_test.dart @@ -11,7 +11,9 @@ import '../../../common/helpers.dart'; void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('AboutView - ', () { - setUp(() async {}); + setUp(() async { + setupLaunchUrlServiceMock(); + }); tearDown(() {}); diff --git a/test/features/more/faq/faq_viewmodel_test.dart b/test/features/more/faq/faq_viewmodel_test.dart index 80284e733..b2add4ca2 100644 --- a/test/features/more/faq/faq_viewmodel_test.dart +++ b/test/features/more/faq/faq_viewmodel_test.dart @@ -1,6 +1,3 @@ -// Flutter imports: -import 'package:flutter/material.dart'; - // Package imports: import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/mockito.dart'; @@ -30,20 +27,11 @@ void main() { unregister(); }); - group('Emails - ', () { - test('Has the right mailto', () { - final str = viewModel.mailtoStr("email", "subject"); - - expect(str, "mailto:email?subject=subject"); - }); - }); - group('Webview - ', () { test('Calls launchInBrowser', () { - viewModel.launchWebsite("https://clubapplets.ca/", Brightness.light); + viewModel.launchWebsite("https://clubapplets.ca/"); - verify(launchUrlServiceMock.launchInBrowser( - "https://clubapplets.ca/", Brightness.light)) + verify(launchUrlServiceMock.launchInBrowser("https://clubapplets.ca/")) .called(1); }); }); diff --git a/test/features/more/feedback/models/feedback_view_test.dart b/test/features/more/feedback/models/feedback_view_test.dart index fa7b4821d..376f05010 100644 --- a/test/features/more/feedback/models/feedback_view_test.dart +++ b/test/features/more/feedback/models/feedback_view_test.dart @@ -13,6 +13,7 @@ void main() { setUp(() async { await setupAppIntl(); setupNavigationServiceMock(); + setupLaunchUrlServiceMock(); setupPreferencesServiceMock(); setupGithubApiMock(); }); diff --git a/test/features/more/more_view_test.dart b/test/features/more/more_view_test.dart index 5b82751ef..55e28031f 100644 --- a/test/features/more/more_view_test.dart +++ b/test/features/more/more_view_test.dart @@ -33,6 +33,7 @@ void main() { setupUserRepositoryMock(); setupCacheManagerMock(); setupGithubApiMock(); + setupLaunchUrlServiceMock(); setupNetworkingServiceMock(); setupAnalyticsServiceMock(); setupFlutterToastMock();