From 601e4fb49b575e3972b1bb320d969f4b5b9d1de7 Mon Sep 17 00:00:00 2001 From: Juan Gilsanz Polo Date: Sat, 23 Mar 2024 02:10:08 +0100 Subject: [PATCH] Handle sharing intents --- lib/i18n/strings.g.dart | 2 +- lib/main.dart | 35 +++++++++++++++++-- lib/models/received_sharing_intent.dart | 5 +++ .../receive_sharing_intent_url.provider.dart | 16 +++++++++ ...receive_sharing_intent_url.provider.g.dart | 27 ++++++++++++++ .../provider/bookmark_form.provider.dart | 9 +++++ .../provider/bookmark_form.provider.g.dart | 2 +- .../provider/bookmarks.provider.g.dart | 4 +-- .../bookmarks/ui/bookmark_form_modal.dart | 8 ++++- lib/screens/bookmarks/ui/bookmarks.dart | 15 ++++++-- 10 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 lib/models/received_sharing_intent.dart create mode 100644 lib/providers/receive_sharing_intent_url.provider.dart create mode 100644 lib/providers/receive_sharing_intent_url.provider.g.dart diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 36c523b..5b04e48 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -6,7 +6,7 @@ /// Locales: 2 /// Strings: 374 (187 per locale) /// -/// Built on 2024-03-03 at 16:11 UTC +/// Built on 2024-03-23 at 00:33 UTC // coverage:ignore-file // ignore_for_file: type=lint diff --git a/lib/main.dart b/lib/main.dart index aa0d4ce..09b0f83 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,16 +4,20 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:dynamic_color/dynamic_color.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:package_info_plus/package_info_plus.dart'; +import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:linkdy/constants/global_keys.dart'; import 'package:linkdy/providers/app_status.provider.dart'; +import 'package:linkdy/router/paths.dart'; import 'package:linkdy/providers/app_info.provider.dart'; +import 'package:linkdy/providers/receive_sharing_intent_url.provider.dart'; import 'package:linkdy/config/theme.dart'; import 'package:linkdy/constants/colors.dart'; import 'package:linkdy/i18n/strings.g.dart'; @@ -61,7 +65,7 @@ void main() async { } } -class MyApp extends ConsumerWidget { +class MyApp extends HookConsumerWidget { const MyApp({super.key}); @override @@ -69,6 +73,33 @@ class MyApp extends ConsumerWidget { final selectedColor = ref.watch(appStatusProvider).selectedColor; final useDynamicColor = ref.watch(appStatusProvider).useDynamicTheme; + useEffect( + () { + // When app is on background + ReceiveSharingIntent.getMediaStream().listen( + (value) { + if (value.isNotEmpty) { + ref.read(receiveSharingIntentUrlProvider.notifier).setValue(value[0].path); + ref.read(routerProvider).go(RoutesPaths.bookmarks); + } + }, + onError: (e, stackTrace) => Sentry.captureException(e, stackTrace: stackTrace), + ); + + // When app is closed + ReceiveSharingIntent.getInitialMedia().then((value) { + if (value.isNotEmpty) { + ref.read(receiveSharingIntentUrlProvider.notifier).setValue(value[0].path); + ref.read(routerProvider).go(RoutesPaths.bookmarks); + } + ReceiveSharingIntent.reset(); + }); + + return null; + }, + [], + ); + return DynamicColorBuilder( builder: (lightDynamic, darkDynamic) { ref.read(appStatusProvider.notifier).setSupportsDynamicTheme(lightDynamic != null && darkDynamic != null); diff --git a/lib/models/received_sharing_intent.dart b/lib/models/received_sharing_intent.dart new file mode 100644 index 0000000..b09e06a --- /dev/null +++ b/lib/models/received_sharing_intent.dart @@ -0,0 +1,5 @@ +class ReceivedSharingIntentModel { + bool processed; + + ReceivedSharingIntentModel({this.processed = false}); +} diff --git a/lib/providers/receive_sharing_intent_url.provider.dart b/lib/providers/receive_sharing_intent_url.provider.dart new file mode 100644 index 0000000..740b613 --- /dev/null +++ b/lib/providers/receive_sharing_intent_url.provider.dart @@ -0,0 +1,16 @@ +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'receive_sharing_intent_url.provider.g.dart'; + +@Riverpod(keepAlive: true) +class ReceiveSharingIntentUrl extends _$ReceiveSharingIntentUrl { + @override + String? build() { + return null; + } + + void setValue(String? value) { + state = value; + ref.notifyListeners(); + } +} diff --git a/lib/providers/receive_sharing_intent_url.provider.g.dart b/lib/providers/receive_sharing_intent_url.provider.g.dart new file mode 100644 index 0000000..bbf1d4d --- /dev/null +++ b/lib/providers/receive_sharing_intent_url.provider.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'receive_sharing_intent_url.provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$receiveSharingIntentUrlHash() => + r'fc62c4867e311b7d8d0573d263af2daaf784fb1f'; + +/// See also [ReceiveSharingIntentUrl]. +@ProviderFor(ReceiveSharingIntentUrl) +final receiveSharingIntentUrlProvider = + NotifierProvider.internal( + ReceiveSharingIntentUrl.new, + name: r'receiveSharingIntentUrlProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$receiveSharingIntentUrlHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$ReceiveSharingIntentUrl = Notifier; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/screens/bookmarks/provider/bookmark_form.provider.dart b/lib/screens/bookmarks/provider/bookmark_form.provider.dart index f83f280..34fccb8 100644 --- a/lib/screens/bookmarks/provider/bookmark_form.provider.dart +++ b/lib/screens/bookmarks/provider/bookmark_form.provider.dart @@ -65,6 +65,15 @@ class BookmarkForm extends _$BookmarkForm { state.markAsUnread = bookmark.unread ?? false; } + void initializeProviderUrl(String url) { + state.urlController.text = url; + if (Regexps.urlWithoutProtocol.hasMatch(url)) { + state.urlError = null; + } else { + state.urlError = t.bookmarks.addBookmark.invalidUrl; + } + } + void validateUrl(String value) { state.checkBookmark = null; state.checkBookmarkLoadStatus = null; diff --git a/lib/screens/bookmarks/provider/bookmark_form.provider.g.dart b/lib/screens/bookmarks/provider/bookmark_form.provider.g.dart index c04583f..2753be9 100644 --- a/lib/screens/bookmarks/provider/bookmark_form.provider.g.dart +++ b/lib/screens/bookmarks/provider/bookmark_form.provider.g.dart @@ -175,7 +175,7 @@ final getTagsProvider = ); typedef GetTagsRef = AutoDisposeFutureProviderRef>; -String _$bookmarkFormHash() => r'52de9be86618f5e736cfe348d91f7f4154c4db64'; +String _$bookmarkFormHash() => r'a89ab1d3b17c37f072e016d033a0adc26ed39748'; /// See also [BookmarkForm]. @ProviderFor(BookmarkForm) diff --git a/lib/screens/bookmarks/provider/bookmarks.provider.g.dart b/lib/screens/bookmarks/provider/bookmarks.provider.g.dart index 0b6895e..99ba59f 100644 --- a/lib/screens/bookmarks/provider/bookmarks.provider.g.dart +++ b/lib/screens/bookmarks/provider/bookmarks.provider.g.dart @@ -6,7 +6,7 @@ part of 'bookmarks.provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$bookmarksRequestHash() => r'c89579d46046980542ed9898867bfb39e85d1d6c'; +String _$bookmarksRequestHash() => r'b1ac82693d1acf93e0c5c51bbfe8674e1cf3f487'; /// Copied from Dart SDK class _SystemHash { @@ -205,7 +205,7 @@ class _BookmarksRequestProviderElement } String _$bookmarksRequestLoadMoreHash() => - r'cea7de930dc5cb77281b68e91dfa66ff3ecf57b5'; + r'3c1a68da25d2dc9d3b6520d3073186520dfe5e5d'; /// See also [bookmarksRequestLoadMore]. @ProviderFor(bookmarksRequestLoadMore) diff --git a/lib/screens/bookmarks/ui/bookmark_form_modal.dart b/lib/screens/bookmarks/ui/bookmark_form_modal.dart index 5f5b02c..6850b1f 100644 --- a/lib/screens/bookmarks/ui/bookmark_form_modal.dart +++ b/lib/screens/bookmarks/ui/bookmark_form_modal.dart @@ -13,10 +13,12 @@ import 'package:linkdy/constants/enums.dart'; class BookmarkFormModal extends ConsumerStatefulWidget { final Bookmark? bookmark; + final String? url; const BookmarkFormModal({ super.key, this.bookmark, + this.url, }); @override @@ -29,6 +31,9 @@ class BookmarkFormModalState extends ConsumerState { if (widget.bookmark != null) { ref.read(bookmarkFormProvider.notifier).initializeProvider(widget.bookmark!); } + if (widget.url != null) { + ref.read(bookmarkFormProvider.notifier).initializeProviderUrl(widget.url!); + } super.initState(); } @@ -421,6 +426,7 @@ class _ModalContent extends ConsumerWidget { void openBookmarkFormModal({ required BuildContext context, required double width, + String? url, Bookmark? bookmark, }) { showGeneralDialog( @@ -434,6 +440,6 @@ void openBookmarkFormModal({ child: child, ); }, - pageBuilder: (context, animation, secondaryAnimation) => BookmarkFormModal(bookmark: bookmark), + pageBuilder: (context, animation, secondaryAnimation) => BookmarkFormModal(bookmark: bookmark, url: url), ); } diff --git a/lib/screens/bookmarks/ui/bookmarks.dart b/lib/screens/bookmarks/ui/bookmarks.dart index f71ac6e..ec5743f 100644 --- a/lib/screens/bookmarks/ui/bookmarks.dart +++ b/lib/screens/bookmarks/ui/bookmarks.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:linkdy/screens/bookmarks/ui/visualization_modal.dart'; import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart'; @@ -10,6 +11,7 @@ import 'package:linkdy/screens/bookmarks/ui/search_bookmarks.dart'; import 'package:linkdy/widgets/error_screen.dart'; import 'package:linkdy/widgets/no_data_screen.dart'; +import 'package:linkdy/providers/receive_sharing_intent_url.provider.dart'; import 'package:linkdy/config/sizes.dart'; import 'package:linkdy/constants/enums.dart'; import 'package:linkdy/router/paths.dart'; @@ -20,11 +22,20 @@ import 'package:linkdy/widgets/system_overlay_style.dart'; final GlobalKey _searchButtonKey = GlobalKey(); final webviewBookmarksKey = GlobalKey(); -class BookmarksScreen extends ConsumerWidget { +class BookmarksScreen extends HookConsumerWidget { const BookmarksScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { + final width = MediaQuery.of(context).size.width; + final sharedUrl = ref.watch(receiveSharingIntentUrlProvider); + + WidgetsBinding.instance.addPostFrameCallback((_) { + if (sharedUrl == null) return; + openBookmarkFormModal(context: context, width: width, url: sharedUrl); + ref.read(receiveSharingIntentUrlProvider.notifier).setValue(null); + }); + return ScaffoldMessenger( key: ScaffoldMessengerKeys.bookmarks, child: LayoutBuilder(