From edf49edfa8515eeb5abbd780b669a135440ac8ba Mon Sep 17 00:00:00 2001 From: Juan Gilsanz Polo Date: Tue, 11 Jun 2024 15:14:21 +0200 Subject: [PATCH] Open links on system browser --- lib/constants/enums.dart | 11 +++ lib/constants/shared_preferences_keys.dart | 1 + lib/i18n/strings.g.dart | 28 +++++- lib/i18n/strings_en.i18n.json | 6 +- lib/i18n/strings_es.i18n.json | 6 +- lib/i18n/strings_tr.i18n.json | 6 +- .../providers_models/app_status.model.dart | 4 +- lib/providers/app_status.provider.dart | 15 ++-- .../provider/bookmarks.provider.dart | 20 +++-- .../provider/search_bookmarks.provider.dart | 20 +++-- .../provider/filtered_bookmarks.provider.dart | 20 +++-- .../onboarding/ui/server_required.dart | 4 +- .../browser_mode_selection_modal.dart | 88 +++++++++++++++++++ .../ui/general_settings/general_settings.dart | 31 +++++-- lib/screens/settings/ui/settings.dart | 6 +- lib/screens/webview/ui/webview.dart | 2 +- lib/utils/open_url.dart | 22 ++++- pubspec.lock | 4 +- pubspec.yaml | 2 +- 19 files changed, 243 insertions(+), 53 deletions(-) create mode 100644 lib/screens/settings/ui/general_settings/browser_mode_selection_modal.dart diff --git a/lib/constants/enums.dart b/lib/constants/enums.dart index 45adff2..de5ad89 100644 --- a/lib/constants/enums.dart +++ b/lib/constants/enums.dart @@ -13,3 +13,14 @@ enum ReadStatus { all, unread, read } enum SortingType { date, title } enum SortingWay { descendant, ascendant } + +enum OpenLinksBrowser { integrated, browserCustomTab, systemBrowser } + +extension OpenLinksBrowserExtension on OpenLinksBrowser { + static OpenLinksBrowser? fromString(String? value) { + if (value == null || !OpenLinksBrowser.values.map((v) => v.toString()).contains(value)) { + return null; + } + return OpenLinksBrowser.values.firstWhere((e) => e.toString() == value); + } +} diff --git a/lib/constants/shared_preferences_keys.dart b/lib/constants/shared_preferences_keys.dart index 9355ea4..f83665c 100644 --- a/lib/constants/shared_preferences_keys.dart +++ b/lib/constants/shared_preferences_keys.dart @@ -5,4 +5,5 @@ class SharedPreferencesKeys { static const selectedColor = "selectedColor"; static const useInAppBrowser = "useInAppBrowser"; static const showFavicon = "showFavicon"; + static const openLinksBrowser = "openLinksBrowser"; } diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index d1899bc..8b4829c 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 3 -/// Strings: 570 (190 per locale) +/// Strings: 582 (194 per locale) /// -/// Built on 2024-04-14 at 18:40 UTC +/// Built on 2024-06-11 at 12:16 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -498,6 +498,10 @@ class _StringsSettingsGeneralSettingsEn { late final _StringsSettingsGeneralSettingsDisconnectModalEn disconnectModal = _StringsSettingsGeneralSettingsDisconnectModalEn._(_root); String get useInAppBrowser => 'Use in app browser'; String get useInAppBrowserDescription => 'Opens the bookmarks with the integrated browser instead of with the system browser. On tablet mode the internal browser will always be used.'; + String get openLinksWith => 'Open links with...'; + String get internalBrowser => 'App internal browser'; + String get browserCustomTab => 'Browser custom tab'; + String get systemBrowser => 'System browser'; } // Path: settings.generalSettings.disconnectModal @@ -884,6 +888,10 @@ class _StringsSettingsGeneralSettingsEs implements _StringsSettingsGeneralSettin @override late final _StringsSettingsGeneralSettingsDisconnectModalEs disconnectModal = _StringsSettingsGeneralSettingsDisconnectModalEs._(_root); @override String get useInAppBrowser => 'Usar navegador de la aplicación'; @override String get useInAppBrowserDescription => 'Abre los marcadores con el navegador integrado en vez de con el navegador del sietema. En modo tablet siempre se usará el navegador integrado.'; + @override String get openLinksWith => 'Abrir enlaces con...'; + @override String get internalBrowser => 'Navegador interno de la app'; + @override String get browserCustomTab => 'Pestaña personalizada del navegador'; + @override String get systemBrowser => 'Navegador del sistema'; } // Path: settings.generalSettings.disconnectModal @@ -1270,6 +1278,10 @@ class _StringsSettingsGeneralSettingsTr implements _StringsSettingsGeneralSettin @override late final _StringsSettingsGeneralSettingsDisconnectModalTr disconnectModal = _StringsSettingsGeneralSettingsDisconnectModalTr._(_root); @override String get useInAppBrowser => 'Uygulama tarayıcısında kullanın'; @override String get useInAppBrowserDescription => 'Yer işaretlerini sistem tarayıcısı yerine entegre tarayıcı ile açar. Tablet modunda dahili tarayıcı her zaman kullanılacaktır.'; + @override String get openLinksWith => 'Open links with...'; + @override String get internalBrowser => 'App internal browser'; + @override String get browserCustomTab => 'Browser custom tab'; + @override String get systemBrowser => 'System browser'; } // Path: settings.generalSettings.disconnectModal @@ -1461,6 +1473,10 @@ extension on Translations { case 'settings.generalSettings.disconnectModal.description': return 'Are you sure you want to disconnect from the server?\nYou will be redirected to the initial setup.'; case 'settings.generalSettings.useInAppBrowser': return 'Use in app browser'; case 'settings.generalSettings.useInAppBrowserDescription': return 'Opens the bookmarks with the integrated browser instead of with the system browser. On tablet mode the internal browser will always be used.'; + case 'settings.generalSettings.openLinksWith': return 'Open links with...'; + case 'settings.generalSettings.internalBrowser': return 'App internal browser'; + case 'settings.generalSettings.browserCustomTab': return 'Browser custom tab'; + case 'settings.generalSettings.systemBrowser': return 'System browser'; case 'webview.goBack': return 'Go back'; case 'webview.goForward': return 'Go forward'; case 'webview.reload': return 'Reload'; @@ -1659,6 +1675,10 @@ extension on _StringsEs { case 'settings.generalSettings.disconnectModal.description': return '¿Estás seguro que deseas desconectarte del servidor?\nSerás redirigido a la configuración inicial.'; case 'settings.generalSettings.useInAppBrowser': return 'Usar navegador de la aplicación'; case 'settings.generalSettings.useInAppBrowserDescription': return 'Abre los marcadores con el navegador integrado en vez de con el navegador del sietema. En modo tablet siempre se usará el navegador integrado.'; + case 'settings.generalSettings.openLinksWith': return 'Abrir enlaces con...'; + case 'settings.generalSettings.internalBrowser': return 'Navegador interno de la app'; + case 'settings.generalSettings.browserCustomTab': return 'Pestaña personalizada del navegador'; + case 'settings.generalSettings.systemBrowser': return 'Navegador del sistema'; case 'webview.goBack': return 'Ir atrás'; case 'webview.goForward': return 'Ir adelante'; case 'webview.reload': return 'Recargar'; @@ -1857,6 +1877,10 @@ extension on _StringsTr { case 'settings.generalSettings.disconnectModal.description': return 'Sunucu bağlantısını kesmek istediğinizden emin misiniz?\nİlk kuruluma yönlendirileceksiniz.'; case 'settings.generalSettings.useInAppBrowser': return 'Uygulama tarayıcısında kullanın'; case 'settings.generalSettings.useInAppBrowserDescription': return 'Yer işaretlerini sistem tarayıcısı yerine entegre tarayıcı ile açar. Tablet modunda dahili tarayıcı her zaman kullanılacaktır.'; + case 'settings.generalSettings.openLinksWith': return 'Open links with...'; + case 'settings.generalSettings.internalBrowser': return 'App internal browser'; + case 'settings.generalSettings.browserCustomTab': return 'Browser custom tab'; + case 'settings.generalSettings.systemBrowser': return 'System browser'; case 'webview.goBack': return 'Geri dön'; case 'webview.goForward': return 'İleri git'; case 'webview.reload': return 'Yenile'; diff --git a/lib/i18n/strings_en.i18n.json b/lib/i18n/strings_en.i18n.json index c70814e..382fac4 100644 --- a/lib/i18n/strings_en.i18n.json +++ b/lib/i18n/strings_en.i18n.json @@ -198,7 +198,11 @@ "description": "Are you sure you want to disconnect from the server?\nYou will be redirected to the initial setup." }, "useInAppBrowser": "Use in app browser", - "useInAppBrowserDescription": "Opens the bookmarks with the integrated browser instead of with the system browser. On tablet mode the internal browser will always be used." + "useInAppBrowserDescription": "Opens the bookmarks with the integrated browser instead of with the system browser. On tablet mode the internal browser will always be used.", + "openLinksWith": "Open links with...", + "internalBrowser": "App internal browser", + "browserCustomTab": "Browser custom tab", + "systemBrowser": "System browser" } }, "webview": { diff --git a/lib/i18n/strings_es.i18n.json b/lib/i18n/strings_es.i18n.json index 278734b..f20411a 100644 --- a/lib/i18n/strings_es.i18n.json +++ b/lib/i18n/strings_es.i18n.json @@ -198,7 +198,11 @@ "description": "¿Estás seguro que deseas desconectarte del servidor?\nSerás redirigido a la configuración inicial." }, "useInAppBrowser": "Usar navegador de la aplicación", - "useInAppBrowserDescription": "Abre los marcadores con el navegador integrado en vez de con el navegador del sietema. En modo tablet siempre se usará el navegador integrado." + "useInAppBrowserDescription": "Abre los marcadores con el navegador integrado en vez de con el navegador del sietema. En modo tablet siempre se usará el navegador integrado.", + "openLinksWith": "Abrir enlaces con...", + "internalBrowser": "Navegador interno de la app", + "browserCustomTab": "Pestaña personalizada del navegador", + "systemBrowser": "Navegador del sistema" } }, "webview": { diff --git a/lib/i18n/strings_tr.i18n.json b/lib/i18n/strings_tr.i18n.json index f5cdb18..42aec64 100644 --- a/lib/i18n/strings_tr.i18n.json +++ b/lib/i18n/strings_tr.i18n.json @@ -198,7 +198,11 @@ "description": "Sunucu bağlantısını kesmek istediğinizden emin misiniz?\nİlk kuruluma yönlendirileceksiniz." }, "useInAppBrowser": "Uygulama tarayıcısında kullanın", - "useInAppBrowserDescription": "Yer işaretlerini sistem tarayıcısı yerine entegre tarayıcı ile açar. Tablet modunda dahili tarayıcı her zaman kullanılacaktır." + "useInAppBrowserDescription": "Yer işaretlerini sistem tarayıcısı yerine entegre tarayıcı ile açar. Tablet modunda dahili tarayıcı her zaman kullanılacaktır.", + "openLinksWith": "Open links with...", + "internalBrowser": "App internal browser", + "browserCustomTab": "Browser custom tab", + "systemBrowser": "System browser" } }, "webview": { diff --git a/lib/models/providers_models/app_status.model.dart b/lib/models/providers_models/app_status.model.dart index 60c3c1a..4a5ba59 100644 --- a/lib/models/providers_models/app_status.model.dart +++ b/lib/models/providers_models/app_status.model.dart @@ -5,7 +5,7 @@ class AppStatusModel { bool supportsDynamicTheme; bool useDynamicTheme; int selectedColor; - bool useInAppBrowser; + OpenLinksBrowser openLinksBrowser; bool showFavicon; AppStatusModel({ @@ -13,7 +13,7 @@ class AppStatusModel { this.supportsDynamicTheme = false, this.useDynamicTheme = true, this.selectedColor = 0, - this.useInAppBrowser = true, + this.openLinksBrowser = OpenLinksBrowser.integrated, this.showFavicon = true, }); } diff --git a/lib/providers/app_status.provider.dart b/lib/providers/app_status.provider.dart index 035de39..756de14 100644 --- a/lib/providers/app_status.provider.dart +++ b/lib/providers/app_status.provider.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; -import 'package:linkdy/constants/shared_preferences_keys.dart'; -import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; +import 'package:linkdy/constants/shared_preferences_keys.dart'; import 'package:linkdy/providers/shared_preferences.provider.dart'; import 'package:linkdy/constants/enums.dart'; import 'package:linkdy/models/providers_models/app_status.model.dart'; @@ -19,7 +19,9 @@ class AppStatus extends _$AppStatus { selectedColor: sharedPreferences.getInt(SharedPreferencesKeys.selectedColor) ?? 0, selectedTheme: SelectedTheme.values[sharedPreferences.getInt(SharedPreferencesKeys.selectedTheme) ?? 0], useDynamicTheme: sharedPreferences.getBool(SharedPreferencesKeys.useDynamicTheme) ?? true, - useInAppBrowser: sharedPreferences.getBool(SharedPreferencesKeys.useInAppBrowser) ?? true, + openLinksBrowser: + OpenLinksBrowserExtension.fromString(sharedPreferences.getString(SharedPreferencesKeys.openLinksBrowser)) ?? + OpenLinksBrowser.integrated, showFavicon: sharedPreferences.getBool(SharedPreferencesKeys.showFavicon) ?? true, ); } @@ -46,9 +48,10 @@ class AppStatus extends _$AppStatus { ref.notifyListeners(); } - void setUseInAppBrowser(bool value) { - state.useInAppBrowser = value; - ref.read(sharedPreferencesProvider).setBool(SharedPreferencesKeys.useInAppBrowser, value); + void updateSelectedBrowser(OpenLinksBrowser? value) { + if (value == null) return; + state.openLinksBrowser = value; + ref.read(sharedPreferencesProvider).setString(SharedPreferencesKeys.openLinksBrowser, value.toString()); ref.notifyListeners(); } diff --git a/lib/screens/bookmarks/provider/bookmarks.provider.dart b/lib/screens/bookmarks/provider/bookmarks.provider.dart index 80a07e7..d771285 100644 --- a/lib/screens/bookmarks/provider/bookmarks.provider.dart +++ b/lib/screens/bookmarks/provider/bookmarks.provider.dart @@ -160,15 +160,19 @@ class Bookmarks extends _$Bookmarks { } void selectBookmark(Bookmark bookmark, double width) { - if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == true) { - ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark); - } else if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == false) { - openUrl(bookmark.url!); - } else if (bookmark != state.selectedBookmark) { - state.webViewRouter.go(_webViewRoutePath, extra: bookmark); + if (ref.watch(appStatusProvider).openLinksBrowser == OpenLinksBrowser.browserCustomTab) { + openUrlCustomTab(bookmark.url!); + } else if (ref.watch(appStatusProvider).openLinksBrowser == OpenLinksBrowser.systemBrowser) { + openUrlSystemBrowser(bookmark.url!); + } else { + if (width <= Sizes.tabletBreakpoint) { + ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark); + } else if (bookmark != state.selectedBookmark) { + state.webViewRouter.go(_webViewRoutePath, extra: bookmark); + } + state.selectedBookmark = bookmark; + ref.notifyListeners(); } - state.selectedBookmark = bookmark; - ref.notifyListeners(); } Future refresh() async { diff --git a/lib/screens/bookmarks/provider/search_bookmarks.provider.dart b/lib/screens/bookmarks/provider/search_bookmarks.provider.dart index 09c48de..b9c2c35 100644 --- a/lib/screens/bookmarks/provider/search_bookmarks.provider.dart +++ b/lib/screens/bookmarks/provider/search_bookmarks.provider.dart @@ -132,15 +132,19 @@ class SearchBookmarks extends _$SearchBookmarks { } void selectBookmark(Bookmark bookmark, double width) { - if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == true) { - ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark); - } else if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == false) { - openUrl(bookmark.url!); - } else if (bookmark != state.selectedBookmark) { - state.webViewRouter.go(_webViewRoutePath, extra: bookmark); + if (ref.watch(appStatusProvider).openLinksBrowser == OpenLinksBrowser.browserCustomTab) { + openUrlCustomTab(bookmark.url!); + } else if (ref.watch(appStatusProvider).openLinksBrowser == OpenLinksBrowser.systemBrowser) { + openUrlSystemBrowser(bookmark.url!); + } else { + if (width <= Sizes.tabletBreakpoint) { + ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark); + } else if (bookmark != state.selectedBookmark) { + state.webViewRouter.go(_webViewRoutePath, extra: bookmark); + } + state.selectedBookmark = bookmark; + ref.notifyListeners(); } - state.selectedBookmark = bookmark; - ref.notifyListeners(); } void deleteBookmark(Bookmark bookmark) async { diff --git a/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart b/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart index 961cc13..f5f0152 100644 --- a/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart +++ b/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart @@ -183,15 +183,19 @@ class FilteredBookmarks extends _$FilteredBookmarks { } void selectBookmark(Bookmark bookmark, double width) { - if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == true) { - ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark); - } else if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == false) { - openUrl(bookmark.url!); - } else if (bookmark != state.selectedBookmark) { - state.webViewRouter.go(_webViewRoutePath, extra: bookmark); + if (ref.watch(appStatusProvider).openLinksBrowser == OpenLinksBrowser.browserCustomTab) { + openUrlCustomTab(bookmark.url!); + } else if (ref.watch(appStatusProvider).openLinksBrowser == OpenLinksBrowser.systemBrowser) { + openUrlSystemBrowser(bookmark.url!); + } else { + if (width <= Sizes.tabletBreakpoint) { + ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark); + } else if (bookmark != state.selectedBookmark) { + state.webViewRouter.go(_webViewRoutePath, extra: bookmark); + } + state.selectedBookmark = bookmark; + ref.notifyListeners(); } - state.selectedBookmark = bookmark; - ref.notifyListeners(); } Future refresh() async { diff --git a/lib/screens/onboarding/ui/server_required.dart b/lib/screens/onboarding/ui/server_required.dart index 36be1ec..4c1919f 100644 --- a/lib/screens/onboarding/ui/server_required.dart +++ b/lib/screens/onboarding/ui/server_required.dart @@ -10,7 +10,7 @@ import 'package:linkdy/i18n/strings.g.dart'; import 'package:linkdy/utils/open_url.dart'; class OnboardingServerRequired extends ConsumerWidget { - const OnboardingServerRequired({Key? key}) : super(key: key); + const OnboardingServerRequired({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -42,7 +42,7 @@ class OnboardingServerRequired extends ConsumerWidget { const SizedBox(height: 16), Card( child: InkWell( - onTap: () => openUrl(Urls.linkdingInstallationInstructions), + onTap: () => openUrlCustomTab(Urls.linkdingInstallationInstructions), borderRadius: BorderRadius.circular(10), child: Padding( padding: const EdgeInsets.all(24), diff --git a/lib/screens/settings/ui/general_settings/browser_mode_selection_modal.dart b/lib/screens/settings/ui/general_settings/browser_mode_selection_modal.dart new file mode 100644 index 0000000..a8e2aba --- /dev/null +++ b/lib/screens/settings/ui/general_settings/browser_mode_selection_modal.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:linkdy/constants/enums.dart'; + +import 'package:linkdy/i18n/strings.g.dart'; +import 'package:linkdy/providers/app_status.provider.dart'; + +class BrowserModeSelectionModal extends ConsumerWidget { + const BrowserModeSelectionModal({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(28), + topRight: Radius.circular(28), + ), + ), + child: SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Flexible( + child: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.only(top: 24, left: 24, right: 24, bottom: 8), + child: Column( + children: [ + Icon( + Icons.public_rounded, + color: Theme.of(context).colorScheme.secondary, + size: 24, + ), + const SizedBox(height: 16), + Text( + t.settings.generalSettings.openLinksWith, + style: const TextStyle( + fontSize: 24, + ), + ), + ], + ), + ), + RadioListTile( + value: OpenLinksBrowser.integrated, + groupValue: ref.watch(appStatusProvider).openLinksBrowser, + onChanged: ref.read(appStatusProvider.notifier).updateSelectedBrowser, + title: Text(t.settings.generalSettings.internalBrowser), + ), + RadioListTile( + value: OpenLinksBrowser.browserCustomTab, + groupValue: ref.watch(appStatusProvider).openLinksBrowser, + onChanged: ref.read(appStatusProvider.notifier).updateSelectedBrowser, + title: Text(t.settings.generalSettings.browserCustomTab), + ), + RadioListTile( + value: OpenLinksBrowser.systemBrowser, + groupValue: ref.watch(appStatusProvider).openLinksBrowser, + onChanged: ref.read(appStatusProvider.notifier).updateSelectedBrowser, + title: Text(t.settings.generalSettings.systemBrowser), + ), + ], + ), + ), + ), + Padding( + padding: const EdgeInsets.all(24), + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(t.generic.close), + ), + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/screens/settings/ui/general_settings/general_settings.dart b/lib/screens/settings/ui/general_settings/general_settings.dart index 45dadb8..468a6af 100644 --- a/lib/screens/settings/ui/general_settings/general_settings.dart +++ b/lib/screens/settings/ui/general_settings/general_settings.dart @@ -1,17 +1,37 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:linkdy/constants/enums.dart'; import 'package:linkdy/i18n/strings.g.dart'; +import 'package:linkdy/screens/settings/ui/general_settings/browser_mode_selection_modal.dart'; import 'package:linkdy/screens/settings/ui/general_settings/disconnect_modal.dart'; import 'package:linkdy/providers/app_status.provider.dart'; import 'package:linkdy/widgets/section_label.dart'; class GeneralSettings extends ConsumerWidget { - const GeneralSettings({Key? key}) : super(key: key); + const GeneralSettings({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { + void openBrowserSelectionSheet() { + showModalBottomSheet( + context: context, + builder: (context) => const BrowserModeSelectionModal(), + ); + } + + String browserLabel() { + switch (ref.watch(appStatusProvider).openLinksBrowser) { + case OpenLinksBrowser.integrated: + return t.settings.generalSettings.internalBrowser; + case OpenLinksBrowser.browserCustomTab: + return t.settings.generalSettings.browserCustomTab; + case OpenLinksBrowser.systemBrowser: + return t.settings.generalSettings.systemBrowser; + } + } + return Scaffold( appBar: AppBar( title: Text(t.settings.generalSettings.generalSettings), @@ -25,11 +45,10 @@ class GeneralSettings extends ConsumerWidget { value: ref.watch(appStatusProvider).showFavicon, onChanged: ref.read(appStatusProvider.notifier).setShowFavicon, ), - SwitchListTile( - title: Text(t.settings.generalSettings.useInAppBrowser), - subtitle: Text(t.settings.generalSettings.useInAppBrowserDescription), - value: ref.watch(appStatusProvider).useInAppBrowser, - onChanged: ref.read(appStatusProvider.notifier).setUseInAppBrowser, + ListTile( + title: Text(t.settings.generalSettings.openLinksWith), + subtitle: Text(browserLabel()), + onTap: openBrowserSelectionSheet, ), const Padding( padding: EdgeInsets.symmetric(vertical: 16), diff --git a/lib/screens/settings/ui/settings.dart b/lib/screens/settings/ui/settings.dart index 275992d..9587a4b 100644 --- a/lib/screens/settings/ui/settings.dart +++ b/lib/screens/settings/ui/settings.dart @@ -82,7 +82,7 @@ class _List extends ConsumerWidget { Icons.open_in_new_rounded, color: Theme.of(context).colorScheme.onSurfaceVariant, ), - onTap: () => openUrl(Urls.linkdingRepo), + onTap: () => openUrlCustomTab(Urls.linkdingRepo), ), CustomListTile( title: t.settings.appVersion, @@ -99,7 +99,7 @@ class _List extends ConsumerWidget { children: [ if (Platform.isAndroid) IconButton( - onPressed: () => openUrl(Urls.playStoreLink), + onPressed: () => openUrlCustomTab(Urls.playStoreLink), icon: SvgPicture.asset( 'assets/resources/google-play.svg', color: Theme.of(context).colorScheme.onSurfaceVariant, @@ -109,7 +109,7 @@ class _List extends ConsumerWidget { tooltip: t.settings.visitGooglePlay, ), IconButton( - onPressed: () => openUrl(Urls.gitHubRepo), + onPressed: () => openUrlCustomTab(Urls.gitHubRepo), icon: SvgPicture.asset( 'assets/resources/github.svg', color: Theme.of(context).colorScheme.onSurfaceVariant, diff --git a/lib/screens/webview/ui/webview.dart b/lib/screens/webview/ui/webview.dart index c36dd22..8cc959f 100644 --- a/lib/screens/webview/ui/webview.dart +++ b/lib/screens/webview/ui/webview.dart @@ -143,7 +143,7 @@ class WebViewScreen extends HookConsumerWidget { ), ), PopupMenuItem( - onTap: () => openUrl(bookmark.url!), + onTap: () => openUrlCustomTab(bookmark.url!), child: Row( children: [ const Icon(Icons.open_in_browser_rounded), diff --git a/lib/utils/open_url.dart b/lib/utils/open_url.dart index 013699b..ecfb098 100644 --- a/lib/utils/open_url.dart +++ b/lib/utils/open_url.dart @@ -4,7 +4,7 @@ import 'package:flutter_custom_tabs/flutter_custom_tabs.dart' as flutter_custom_ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:url_launcher/url_launcher.dart' as url_launcher; -void openUrl(String url) async { +void openUrlCustomTab(String url) async { if (Platform.isAndroid || Platform.isIOS) { try { await flutter_custom_tabs.launchUrl( @@ -30,3 +30,23 @@ void openUrl(String url) async { } } } + +void openUrlSystemBrowser(String url) async { + if (Platform.isAndroid || Platform.isIOS) { + try { + await flutter_custom_tabs.launchUrl( + Uri.parse(url), + customTabsOptions: null, + safariVCOptions: null, + ); + } catch (e, stackTrace) { + Sentry.captureException(e, stackTrace: stackTrace); + } + } else { + try { + url_launcher.launchUrl(Uri.parse(url)); + } catch (e, stackTrace) { + Sentry.captureException(e, stackTrace: stackTrace); + } + } +} diff --git a/pubspec.lock b/pubspec.lock index 09e7bca..a30ff8e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1183,10 +1183,10 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" + sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" url: "https://pub.dev" source: hosted - version: "6.2.6" + version: "6.3.0" url_launcher_android: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 09436ec..e68b740 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,7 +38,7 @@ dependencies: riverpod_annotation: ^2.3.5 dynamic_color: ^1.7.0 shared_preferences: ^2.2.2 - url_launcher: ^6.2.5 + url_launcher: ^6.3.0 animations: ^2.0.11 segmented_button_slide: ^1.0.4 dio: ^5.4.1