diff --git a/apps/weblibre/lib/features/geckoview/domain/providers.dart b/apps/weblibre/lib/features/geckoview/domain/providers.dart index 4bf08f0a..761f1bf9 100644 --- a/apps/weblibre/lib/features/geckoview/domain/providers.dart +++ b/apps/weblibre/lib/features/geckoview/domain/providers.dart @@ -192,6 +192,38 @@ GeckoViewportService viewportService(Ref ref) { @Riverpod(keepAlive: true) class EngineReadyState extends _$EngineReadyState { + Future waitUntilReady({ + Duration timeout = const Duration(seconds: 3), + }) async { + final eventService = ref.read(eventServiceProvider); + final currentState = + eventService.engineReadyStateEvents.valueOrNull ?? false; + + if (currentState) { + return true; + } + + try { + final ready = await eventService.engineReadyStateEvents + .firstWhere((value) => value == true) + .timeout(timeout); + + if (ref.mounted) { + state = ready; + } + + return ready; + } on TimeoutException { + logger.w('Waiting for engine ready state timed out'); + + if (ref.mounted) { + state = true; + } + + return true; + } + } + @override bool build() { final eventService = ref.watch(eventServiceProvider); @@ -200,22 +232,7 @@ class EngineReadyState extends _$EngineReadyState { eventService.engineReadyStateEvents.valueOrNull ?? false; if (!currentState) { - unawaited( - eventService.engineReadyStateEvents - .firstWhere((value) => value == true) - .timeout( - const Duration(seconds: 3), - onTimeout: () { - logger.w('Waiting for engine ready state timed out'); - return true; - }, - ) - .whenComplete(() { - if (ref.mounted) { - state = true; - } - }), - ); + unawaited(waitUntilReady()); } final sub = eventService.engineReadyStateEvents.listen((value) { diff --git a/apps/weblibre/lib/features/geckoview/domain/providers.g.dart b/apps/weblibre/lib/features/geckoview/domain/providers.g.dart index 457766fc..8aae2b41 100644 --- a/apps/weblibre/lib/features/geckoview/domain/providers.g.dart +++ b/apps/weblibre/lib/features/geckoview/domain/providers.g.dart @@ -325,7 +325,7 @@ final class EngineReadyStateProvider } } -String _$engineReadyStateHash() => r'ab3fe385fbda4d7d8acaf8f5428b3b48b75f3f46'; +String _$engineReadyStateHash() => r'0483cc1638d6cc23f7a33b8cb7c52667b07f7eea'; abstract class _$EngineReadyState extends $Notifier { bool build(); diff --git a/apps/weblibre/lib/features/geckoview/features/browser/domain/providers/intent.dart b/apps/weblibre/lib/features/geckoview/features/browser/domain/providers/intent.dart index 00e41182..c9a9c4db 100644 --- a/apps/weblibre/lib/features/geckoview/features/browser/domain/providers/intent.dart +++ b/apps/weblibre/lib/features/geckoview/features/browser/domain/providers/intent.dart @@ -26,7 +26,6 @@ import 'package:weblibre/core/logger.dart'; import 'package:weblibre/core/routing/routes.dart'; import 'package:weblibre/data/models/received_intent_parameter.dart'; import 'package:weblibre/features/app_widget/domain/services/home_widget.dart'; -import 'package:weblibre/features/geckoview/domain/providers.dart'; import 'package:weblibre/features/share_intent/domain/entities/shared_content.dart'; import 'package:weblibre/features/share_intent/domain/services/sharing_intent.dart'; @@ -36,10 +35,8 @@ final _contentParserTransformer = StreamTransformer.fromHandlers( handleData: (parameter, sink) { final parsed = parameter.content.mapNotNull( - (content) => SharedContent.parse( - content, - contextId: parameter.contextId, - ), + (content) => + SharedContent.parse(content, contextId: parameter.contextId), ); if (parsed != null) { @@ -54,11 +51,6 @@ final _contentParserTransformer = class EngineBoundIntentStream extends _$EngineBoundIntentStream { @override Stream build() { - final engineReady = ref.watch(engineReadyStateProvider); - if (!engineReady) { - return const Stream.empty(); - } - final sharingItentStream = ref.watch(sharingIntentStreamProvider); final appWidgetLaunchStream = ref.watch(appWidgetLaunchStreamProvider); diff --git a/apps/weblibre/lib/features/geckoview/features/browser/domain/providers/intent.g.dart b/apps/weblibre/lib/features/geckoview/features/browser/domain/providers/intent.g.dart index 63f3d089..d40cc259 100644 --- a/apps/weblibre/lib/features/geckoview/features/browser/domain/providers/intent.g.dart +++ b/apps/weblibre/lib/features/geckoview/features/browser/domain/providers/intent.g.dart @@ -34,7 +34,7 @@ final class EngineBoundIntentStreamProvider } String _$engineBoundIntentStreamHash() => - r'618eb6431da93989de6f1780cba2993458b0014e'; + r'8170f28c2ce69813066780a65205426182a26863'; abstract class _$EngineBoundIntentStream extends $StreamNotifier { diff --git a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart index 6c045e99..376841ee 100644 --- a/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart +++ b/apps/weblibre/lib/features/geckoview/features/browser/presentation/widgets/browser_modules/browser_view.dart @@ -221,6 +221,8 @@ class _BrowserViewState extends ConsumerState await widget.postInitializationStep?.call(); if (!_initializationCompleter.isCompleted) { + _initializationCompleter.complete(); + const quickActions = QuickActions(); //Debounce: https://github.com/flutter/flutter/issues/131121 @@ -284,8 +286,6 @@ class _BrowserViewState extends ConsumerState localizedTitle: 'New Isolated Tab', ), ]); - - _initializationCompleter.complete(); } }, ), @@ -349,24 +349,24 @@ class _BrowserViewState extends ConsumerState ref.listenManual( engineBoundIntentStreamProvider, - (previous, next) async { - await _initializationCompleter.future; - + (previous, next) { next.whenData((sharedContent) async { - final router = await ref.read(routerProvider.future); final settings = ref.read(generalSettingsWithDefaultsProvider); - // Resolve container from shortcut intent context ID - final containerSelection = await _resolveContainerSelection( - ref, - sharedContent.contextId, - ); - switch (settings.tabIntentOpenSetting) { case TabIntentOpenSetting.regular: case TabIntentOpenSetting.private: + await ref + .read(engineReadyStateProvider.notifier) + .waitUntilReady(); + switch (sharedContent) { case SharedUrl(): + final containerSelection = await _resolveContainerSelection( + ref, + sharedContent.contextId, + ); + await ref .read(tabRepositoryProvider.notifier) .addTab( @@ -399,6 +399,8 @@ class _BrowserViewState extends ConsumerState ); } case TabIntentOpenSetting.ask: + final router = await ref.read(routerProvider.future); + switch (sharedContent) { case SharedUrl(): final route = OpenSharedContentRoute( diff --git a/apps/weblibre/lib/main.dart b/apps/weblibre/lib/main.dart index 03c3d436..956e3139 100644 --- a/apps/weblibre/lib/main.dart +++ b/apps/weblibre/lib/main.dart @@ -42,6 +42,7 @@ import 'package:weblibre/core/providers/app_state.dart'; import 'package:weblibre/core/providers/defaults.dart'; import 'package:weblibre/core/providers/router.dart'; import 'package:weblibre/domain/services/app_initialization.dart'; +import 'package:weblibre/features/geckoview/features/open_link_tools/domain/services/url_cleaner_catalog_service.dart'; import 'package:weblibre/features/user/domain/repositories/engine_settings.dart'; import 'package:weblibre/features/user/domain/repositories/general_settings.dart'; import 'package:weblibre/features/web_feed/presentation/controllers/fetch_articles.dart'; @@ -207,6 +208,24 @@ class _MainWidget extends HookConsumerWidget { await ref.read(appInitializationServiceProvider.notifier).initialize(); + Future preloadUrlCleanerCatalog() async { + if (!generalSettings.urlCleanerEnabled) { + return; + } + + try { + await ref.read(urlCleanerCatalogServiceProvider.future); + } catch (e, s) { + logger.w( + 'Failed preloading URL cleaner catalog', + error: e, + stackTrace: s, + ); + } + } + + unawaited(preloadUrlCleanerCatalog()); + if (!kDebugMode) { await BackgroundFetch.configure( BackgroundFetchConfig(