diff --git a/lib/constants/global_keys.dart b/lib/constants/global_keys.dart index 96d1a95..b2da224 100644 --- a/lib/constants/global_keys.dart +++ b/lib/constants/global_keys.dart @@ -1,4 +1,12 @@ import 'package:flutter/material.dart'; -final scaffoldMessengerGlobalKey = GlobalKey(); -final searchScaffoldMessengerKey = GlobalKey(); +class ScaffoldMessengerKeys { + static final root = GlobalKey(); + static final onboarding = GlobalKey(); + static final bookmarks = GlobalKey(); + static final search = GlobalKey(); + static final tags = GlobalKey(); + static final addBookmark = GlobalKey(); + static final tagBookmarks = GlobalKey(); + static final webview = GlobalKey(); +} diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index 4da9276..09d3370 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -6,7 +6,7 @@ /// Locales: 2 /// Strings: 290 (145 per locale) /// -/// Built on 2024-02-26 at 21:31 UTC +/// Built on 2024-02-27 at 00:35 UTC // coverage:ignore-file // ignore_for_file: type=lint diff --git a/lib/main.dart b/lib/main.dart index 0dc66ea..df2e828 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,14 +6,14 @@ import 'package:flutter/services.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:linkdy/constants/global_keys.dart'; -import 'package:linkdy/providers/temporary_directory.provider.dart'; import 'package:path_provider/path_provider.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:package_info_plus/package_info_plus.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/temporary_directory.provider.dart'; import 'package:linkdy/providers/app_status.provider.dart'; import 'package:linkdy/providers/app_info.provider.dart'; import 'package:linkdy/config/theme.dart'; @@ -94,7 +94,7 @@ class MyApp extends ConsumerWidget { supportedLocales: AppLocaleUtils.supportedLocales, localizationsDelegates: GlobalMaterialLocalizations.delegates, debugShowCheckedModeBanner: false, - scaffoldMessengerKey: scaffoldMessengerGlobalKey, + scaffoldMessengerKey: ScaffoldMessengerKeys.root, routerConfig: ref.watch(routerProvider), ); }, diff --git a/lib/providers/dio_interceptor.provider.dart b/lib/providers/dio_interceptor.provider.dart index 1101e84..a8964f0 100644 --- a/lib/providers/dio_interceptor.provider.dart +++ b/lib/providers/dio_interceptor.provider.dart @@ -3,8 +3,9 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; -import 'package:linkdy/providers/snackbar.provider.dart'; +import 'package:linkdy/utils/snackbar.dart'; import 'package:linkdy/i18n/strings.g.dart'; +import 'package:linkdy/constants/global_keys.dart'; import 'package:linkdy/providers/server_instances.provider.dart'; import 'package:linkdy/router/routes.dart'; import 'package:linkdy/router/paths.dart'; @@ -23,7 +24,7 @@ InterceptorsWrapper dioInterceptor(DioInterceptorRef ref) { GoRouter.of(rootNavigatorKey.currentContext!).pushReplacement(RoutesPaths.onboarding); ref.read(apiClientProvider.notifier).disconnectApiClient(); ref.read(serverInstancesProvider.notifier).removeServerInstances(); - ref.read(snackbarProvider.notifier).showSnacbkar(label: t.generic.authTokenNotValid, color: Colors.red); + showSnackbar(key: ScaffoldMessengerKeys.root, label: t.generic.authTokenNotValid, color: Colors.red); } handler.next(error); }, diff --git a/lib/providers/dio_interceptor.provider.g.dart b/lib/providers/dio_interceptor.provider.g.dart index 0490fcc..802c82c 100644 --- a/lib/providers/dio_interceptor.provider.g.dart +++ b/lib/providers/dio_interceptor.provider.g.dart @@ -6,7 +6,7 @@ part of 'dio_interceptor.provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$dioInterceptorHash() => r'15186eb74bde12048a96b1d38f1c9308c9f435a8'; +String _$dioInterceptorHash() => r'16ba03ce5f4547c91566a38f348cf85df73fbfca'; /// See also [dioInterceptor]. @ProviderFor(dioInterceptor) diff --git a/lib/providers/snackbar.provider.dart b/lib/providers/snackbar.provider.dart deleted file mode 100644 index fcc6a71..0000000 --- a/lib/providers/snackbar.provider.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -import 'package:linkdy/constants/global_keys.dart'; -import 'package:linkdy/models/providers_models/snackbar_status.model.dart'; - -part 'snackbar.provider.g.dart'; - -@Riverpod(keepAlive: true) -class Snackbar extends _$Snackbar { - @override - SnackbarStatusModel build() { - return SnackbarStatusModel(); - } - - void showSnacbkar({ - required String label, - required Color color, - Color? labelColor, - GlobalKey? key, - }) async { - final GlobalKey scaffoldKey = key ?? scaffoldMessengerGlobalKey; - if (state.visible == true) { - scaffoldKey.currentState?.clearSnackBars(); - await Future.delayed(const Duration(milliseconds: 500)); - } - state.visible = true; - ref.notifyListeners(); - - final snackBar = SnackBar( - content: Text( - label, - style: TextStyle(color: labelColor ?? Colors.white), - ), - backgroundColor: color, - ); - scaffoldKey.currentState?.showSnackBar(snackBar).closed.then((value) { - state.visible = false; - ref.notifyListeners(); - }); - } -} diff --git a/lib/providers/snackbar.provider.g.dart b/lib/providers/snackbar.provider.g.dart deleted file mode 100644 index 88c9ef8..0000000 --- a/lib/providers/snackbar.provider.g.dart +++ /dev/null @@ -1,25 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'snackbar.provider.dart'; - -// ************************************************************************** -// RiverpodGenerator -// ************************************************************************** - -String _$snackbarHash() => r'2522a7ebc0bdd891cea5cb342bd1ff2419473a00'; - -/// See also [Snackbar]. -@ProviderFor(Snackbar) -final snackbarProvider = - NotifierProvider.internal( - Snackbar.new, - name: r'snackbarProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$snackbarHash, - dependencies: null, - allTransitiveDependencies: null, -); - -typedef _$Snackbar = 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/add_bookmark.provider.dart b/lib/screens/bookmarks/provider/add_bookmark.provider.dart index 29289b2..7b71a8b 100644 --- a/lib/screens/bookmarks/provider/add_bookmark.provider.dart +++ b/lib/screens/bookmarks/provider/add_bookmark.provider.dart @@ -1,10 +1,11 @@ import 'package:flutter/material.dart'; +import 'package:linkdy/constants/global_keys.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart'; import 'package:linkdy/screens/bookmarks/model/add_link.model.dart'; -import 'package:linkdy/providers/snackbar.provider.dart'; +import 'package:linkdy/utils/snackbar.dart'; import 'package:linkdy/models/data/tags.dart'; import 'package:linkdy/i18n/strings.g.dart'; import 'package:linkdy/utils/process_modal.dart'; @@ -101,10 +102,11 @@ class AddBookmark extends _$AddBookmark { ref.read(bookmarksProvider.notifier).refresh(); ref.watch(routerProvider).pop(); } else { - ref.read(snackbarProvider.notifier).showSnacbkar( - label: t.bookmarks.addBookmark.errorSavingBookmark, - color: Colors.red, - ); + showSnackbar( + key: ScaffoldMessengerKeys.addBookmark, + label: t.bookmarks.addBookmark.errorSavingBookmark, + color: Colors.red, + ); } } diff --git a/lib/screens/bookmarks/provider/add_bookmark.provider.g.dart b/lib/screens/bookmarks/provider/add_bookmark.provider.g.dart index 7ed1fed..615eeb8 100644 --- a/lib/screens/bookmarks/provider/add_bookmark.provider.g.dart +++ b/lib/screens/bookmarks/provider/add_bookmark.provider.g.dart @@ -175,7 +175,7 @@ final getTagsProvider = ); typedef GetTagsRef = AutoDisposeFutureProviderRef>; -String _$addBookmarkHash() => r'd6425004c3e755ec539ad28da3ef44349680b04b'; +String _$addBookmarkHash() => r'a350eee7aeed2fabae90966afadc609ee5eef895'; /// See also [AddBookmark]. @ProviderFor(AddBookmark) diff --git a/lib/screens/bookmarks/provider/bookmarks.provider.dart b/lib/screens/bookmarks/provider/bookmarks.provider.dart index c4c9065..b9bb1f1 100644 --- a/lib/screens/bookmarks/provider/bookmarks.provider.dart +++ b/lib/screens/bookmarks/provider/bookmarks.provider.dart @@ -1,3 +1,4 @@ +import 'package:linkdy/constants/global_keys.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/screens/bookmarks/provider/common_functions.dart'; @@ -90,6 +91,7 @@ class Bookmarks extends _$Bookmarks { void deleteBookmark(Bookmark bookmark) async { final result = await BookmarkCommonFunctions.deleteBookmark( + scaffoldMessengerKey: ScaffoldMessengerKeys.bookmarks, ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, @@ -102,6 +104,7 @@ class Bookmarks extends _$Bookmarks { void markAsReadUnread(Bookmark bookmark) async { final result = await BookmarkCommonFunctions.markAsReadUnread( + scaffoldMessengerKey: ScaffoldMessengerKeys.bookmarks, ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, @@ -114,6 +117,7 @@ class Bookmarks extends _$Bookmarks { void archiveUnarchive(Bookmark bookmark) async { final result = await BookmarkCommonFunctions.archiveUnarchive( + scaffoldMessengerKey: ScaffoldMessengerKeys.bookmarks, ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, diff --git a/lib/screens/bookmarks/provider/bookmarks.provider.g.dart b/lib/screens/bookmarks/provider/bookmarks.provider.g.dart index c7a4f85..084d95c 100644 --- a/lib/screens/bookmarks/provider/bookmarks.provider.g.dart +++ b/lib/screens/bookmarks/provider/bookmarks.provider.g.dart @@ -172,7 +172,7 @@ final bookmarksRequestLoadMoreProvider = ); typedef BookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef; -String _$bookmarksHash() => r'a2bd6f3226b5a1b9c19b536b31122fb5b449ff6a'; +String _$bookmarksHash() => r'84a236ccce48c0a0069ca2b754da59ff88b17ef2'; /// See also [Bookmarks]. @ProviderFor(Bookmarks) diff --git a/lib/screens/bookmarks/provider/common_functions.dart b/lib/screens/bookmarks/provider/common_functions.dart index 2434b0e..626f025 100644 --- a/lib/screens/bookmarks/provider/common_functions.dart +++ b/lib/screens/bookmarks/provider/common_functions.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; -import 'package:linkdy/providers/snackbar.provider.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/i18n/strings.g.dart'; import 'package:linkdy/models/data/bookmarks.dart'; +import 'package:linkdy/utils/snackbar.dart'; import 'package:linkdy/models/data/set_bookmark_data.dart'; import 'package:linkdy/services/api_client.dart'; import 'package:linkdy/utils/process_modal.dart'; @@ -13,7 +13,7 @@ class BookmarkCommonFunctions { required AutoDisposeNotifierProviderRef ref, required Bookmark bookmark, required ApiClientService apiClient, - GlobalKey? scaffoldMessengerKey, + required GlobalKey scaffoldMessengerKey, }) async { final processModal = ProcessModal(); processModal.open(t.bookmarks.bookmarkOptions.deletingBookmark); @@ -22,17 +22,17 @@ class BookmarkCommonFunctions { processModal.close(); if (result.successful == true) { - ref.read(snackbarProvider.notifier).showSnacbkar( - key: scaffoldMessengerKey, - label: t.bookmarks.bookmarkOptions.bookmarkDeleted, - color: Colors.green, - ); + showSnackbar( + key: scaffoldMessengerKey, + label: t.bookmarks.bookmarkOptions.bookmarkDeleted, + color: Colors.green, + ); } else { - ref.read(snackbarProvider.notifier).showSnacbkar( - key: scaffoldMessengerKey, - label: t.bookmarks.bookmarkOptions.bookmarkNotDeleted, - color: Colors.red, - ); + showSnackbar( + key: scaffoldMessengerKey, + label: t.bookmarks.bookmarkOptions.bookmarkNotDeleted, + color: Colors.red, + ); } return result.successful; } @@ -41,7 +41,7 @@ class BookmarkCommonFunctions { required AutoDisposeNotifierProviderRef ref, required Bookmark bookmark, required ApiClientService apiClient, - GlobalKey? scaffoldMessengerKey, + required GlobalKey scaffoldMessengerKey, }) async { final processModal = ProcessModal(); processModal.open( @@ -63,22 +63,22 @@ class BookmarkCommonFunctions { processModal.close(); if (result.successful == true) { - ref.read(snackbarProvider.notifier).showSnacbkar( - key: scaffoldMessengerKey, - label: bookmark.unread == true - ? t.bookmarks.bookmarkOptions.markedAsReadSuccessfully - : t.bookmarks.bookmarkOptions.markedAsUnreadSuccessfully, - color: Colors.green, - ); + showSnackbar( + key: scaffoldMessengerKey, + label: bookmark.unread == true + ? t.bookmarks.bookmarkOptions.markedAsReadSuccessfully + : t.bookmarks.bookmarkOptions.markedAsUnreadSuccessfully, + color: Colors.green, + ); return result.content; } else { - ref.read(snackbarProvider.notifier).showSnacbkar( - key: scaffoldMessengerKey, - label: bookmark.unread == true - ? t.bookmarks.bookmarkOptions.bookmarkNotMarkedAsRead - : t.bookmarks.bookmarkOptions.bookmarkNotMarkedAsUnread, - color: Colors.red, - ); + showSnackbar( + key: scaffoldMessengerKey, + label: bookmark.unread == true + ? t.bookmarks.bookmarkOptions.bookmarkNotMarkedAsRead + : t.bookmarks.bookmarkOptions.bookmarkNotMarkedAsUnread, + color: Colors.red, + ); return null; } } @@ -87,7 +87,7 @@ class BookmarkCommonFunctions { required AutoDisposeNotifierProviderRef ref, required Bookmark bookmark, required ApiClientService apiClient, - GlobalKey? scaffoldMessengerKey, + required GlobalKey scaffoldMessengerKey, }) async { final processModal = ProcessModal(); processModal.open( @@ -102,21 +102,21 @@ class BookmarkCommonFunctions { processModal.close(); if (result.successful == true) { - ref.read(snackbarProvider.notifier).showSnacbkar( - key: scaffoldMessengerKey, - label: bookmark.isArchived == true - ? t.bookmarks.bookmarkOptions.bookmarkUnrchivedSuccessfully - : t.bookmarks.bookmarkOptions.bookmarkArchivedSuccessfully, - color: Colors.green, - ); + showSnackbar( + key: scaffoldMessengerKey, + label: bookmark.isArchived == true + ? t.bookmarks.bookmarkOptions.bookmarkUnrchivedSuccessfully + : t.bookmarks.bookmarkOptions.bookmarkArchivedSuccessfully, + color: Colors.green, + ); } else { - ref.read(snackbarProvider.notifier).showSnacbkar( - key: scaffoldMessengerKey, - label: bookmark.isArchived == true - ? t.bookmarks.bookmarkOptions.bookmarkNotUnrchived - : t.bookmarks.bookmarkOptions.bookmarkNotArchived, - color: Colors.red, - ); + showSnackbar( + key: scaffoldMessengerKey, + label: bookmark.isArchived == true + ? t.bookmarks.bookmarkOptions.bookmarkNotUnrchived + : t.bookmarks.bookmarkOptions.bookmarkNotArchived, + color: Colors.red, + ); } return result.successful; } diff --git a/lib/screens/bookmarks/provider/search_bookmarks.provider.dart b/lib/screens/bookmarks/provider/search_bookmarks.provider.dart index 675b307..d60d331 100644 --- a/lib/screens/bookmarks/provider/search_bookmarks.provider.dart +++ b/lib/screens/bookmarks/provider/search_bookmarks.provider.dart @@ -104,7 +104,7 @@ class SearchBookmarks extends _$SearchBookmarks { ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, - scaffoldMessengerKey: searchScaffoldMessengerKey, + scaffoldMessengerKey: ScaffoldMessengerKeys.search, ); if (result == true) { state.bookmarks = state.bookmarks.where((b) => b.id != bookmark.id).toList(); @@ -120,7 +120,7 @@ class SearchBookmarks extends _$SearchBookmarks { ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, - scaffoldMessengerKey: searchScaffoldMessengerKey, + scaffoldMessengerKey: ScaffoldMessengerKeys.search, ); if (result != null) { state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList(); @@ -136,7 +136,7 @@ class SearchBookmarks extends _$SearchBookmarks { ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, - scaffoldMessengerKey: searchScaffoldMessengerKey, + scaffoldMessengerKey: ScaffoldMessengerKeys.search, ); if (result == true) { // On this case the bookmark always will pass from unarchived to archived diff --git a/lib/screens/bookmarks/provider/search_bookmarks.provider.g.dart b/lib/screens/bookmarks/provider/search_bookmarks.provider.g.dart index c3fa6eb..fe50972 100644 --- a/lib/screens/bookmarks/provider/search_bookmarks.provider.g.dart +++ b/lib/screens/bookmarks/provider/search_bookmarks.provider.g.dart @@ -174,7 +174,7 @@ final fetchSearchBookmarksLoadMoreProvider = ); typedef FetchSearchBookmarksLoadMoreRef = AutoDisposeFutureProviderRef; -String _$searchBookmarksHash() => r'5a5bc02d87a3eff3976a3bc6991c2208f4232fb4'; +String _$searchBookmarksHash() => r'c7c8394ae9ad71f8106a3b73100b88e09c154e13'; /// See also [SearchBookmarks]. @ProviderFor(SearchBookmarks) diff --git a/lib/screens/bookmarks/ui/add_bookmark_modal.dart b/lib/screens/bookmarks/ui/add_bookmark_modal.dart index 803fdcd..0f9e879 100644 --- a/lib/screens/bookmarks/ui/add_bookmark_modal.dart +++ b/lib/screens/bookmarks/ui/add_bookmark_modal.dart @@ -6,61 +6,65 @@ import 'package:linkdy/screens/bookmarks/provider/add_bookmark.provider.dart'; import 'package:linkdy/widgets/section_label.dart'; import 'package:linkdy/i18n/strings.g.dart'; +import 'package:linkdy/constants/global_keys.dart'; import 'package:linkdy/constants/enums.dart'; class AddBookmarkModal extends ConsumerWidget { final bool fullscreen; const AddBookmarkModal({ - Key? key, + super.key, required this.fullscreen, - }) : super(key: key); + }); @override Widget build(BuildContext context, WidgetRef ref) { - return Dialog.fullscreen( - child: Scaffold( - body: NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) => [ - SliverOverlapAbsorber( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - sliver: SliverAppBar.large( - pinned: true, - floating: true, - centerTitle: false, - forceElevated: innerBoxIsScrolled, - leading: CloseButton( - onPressed: () => Navigator.pop(context), + return ScaffoldMessenger( + key: ScaffoldMessengerKeys.addBookmark, + child: Dialog.fullscreen( + child: Scaffold( + body: NestedScrollView( + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverOverlapAbsorber( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + sliver: SliverAppBar.large( + pinned: true, + floating: true, + centerTitle: false, + forceElevated: innerBoxIsScrolled, + leading: CloseButton( + onPressed: () => Navigator.pop(context), + ), + title: Text(t.bookmarks.addBookmark.addBookmark), + actions: [ + IconButton( + onPressed: ref.watch(addBookmarkProvider).checkBookmark != null + ? () => ref.read(addBookmarkProvider.notifier).addBookmark() + : null, + icon: const Icon(Icons.save_rounded), + tooltip: t.generic.save, + ), + const SizedBox(width: 8), + ], ), - title: Text(t.bookmarks.addBookmark.addBookmark), - actions: [ - IconButton( - onPressed: ref.watch(addBookmarkProvider).checkBookmark != null - ? () => ref.read(addBookmarkProvider.notifier).addBookmark() - : null, - icon: const Icon(Icons.save_rounded), - tooltip: t.generic.save, - ), - const SizedBox(width: 8), - ], ), - ), - ], - body: SafeArea( - top: false, - bottom: true, - child: Builder( - builder: (context) => CustomScrollView( - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - ), - SliverList.list( - children: const [ - _ModalContent(), - ], - ), - ], + ], + body: SafeArea( + top: false, + bottom: true, + child: Builder( + builder: (context) => CustomScrollView( + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + SliverList.list( + children: const [ + _ModalContent(), + ], + ), + ], + ), ), ), ), @@ -71,7 +75,7 @@ class AddBookmarkModal extends ConsumerWidget { } class _ModalContent extends ConsumerWidget { - const _ModalContent({Key? key}) : super(key: key); + const _ModalContent(); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/screens/bookmarks/ui/bookmarks.dart b/lib/screens/bookmarks/ui/bookmarks.dart index e7556bb..f9cd2d2 100644 --- a/lib/screens/bookmarks/ui/bookmarks.dart +++ b/lib/screens/bookmarks/ui/bookmarks.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; -import 'package:linkdy/constants/enums.dart'; import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart'; import 'package:linkdy/screens/bookmarks/ui/bookmark_item.dart'; @@ -12,8 +11,9 @@ import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart'; 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/widgets/snackbar_fab.dart'; +import 'package:linkdy/constants/enums.dart'; +import 'package:linkdy/constants/global_keys.dart'; import 'package:linkdy/i18n/strings.g.dart'; class BookmarksScreen extends ConsumerWidget { @@ -67,105 +67,104 @@ class BookmarksScreen extends ConsumerWidget { return false; } - return Scaffold( - body: Stack( - children: [ - NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) => [ - SliverOverlapAbsorber( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - sliver: SliverAppBar.large( - pinned: true, - floating: true, - centerTitle: false, - forceElevated: innerBoxIsScrolled, - title: Text(t.bookmarks.bookmarks), - actions: [ - IconButton( - onPressed: openSearchModal, - icon: const Icon(Icons.search_rounded), - tooltip: t.bookmarks.search.searchBookmarks, - ), - const SizedBox(width: 8), - ], - ), + return ScaffoldMessenger( + key: ScaffoldMessengerKeys.bookmarks, + child: Scaffold( + body: NestedScrollView( + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverOverlapAbsorber( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + sliver: SliverAppBar.large( + pinned: true, + floating: true, + centerTitle: false, + forceElevated: innerBoxIsScrolled, + title: Text(t.bookmarks.bookmarks), + actions: [ + IconButton( + onPressed: openSearchModal, + icon: const Icon(Icons.search_rounded), + tooltip: t.bookmarks.search.searchBookmarks, + ), + const SizedBox(width: 8), + ], ), - ], - body: SafeArea( - top: false, - bottom: false, - child: Builder( - builder: (context) => RefreshIndicator( - displacement: 120, - onRefresh: () => ref.read(bookmarksProvider.notifier).refresh(), - child: NotificationListener( - onNotification: scrollListener, - child: CustomScrollView( - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + ], + body: SafeArea( + top: false, + bottom: false, + child: Builder( + builder: (context) => RefreshIndicator( + displacement: 120, + onRefresh: () => ref.read(bookmarksProvider.notifier).refresh(), + child: NotificationListener( + onNotification: scrollListener, + child: CustomScrollView( + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + if (bookmarks.inialLoadStatus == LoadStatus.loading) + const SliverFillRemaining( + child: Center(child: CircularProgressIndicator()), ), - if (bookmarks.inialLoadStatus == LoadStatus.loading) - const SliverFillRemaining( - child: Center(child: CircularProgressIndicator()), + if (bookmarks.inialLoadStatus == LoadStatus.error) + SliverFillRemaining( + child: ErrorScreen( + error: t.bookmarks.cannotLoadBookmarks, ), - if (bookmarks.inialLoadStatus == LoadStatus.error) - SliverFillRemaining( - child: ErrorScreen( - error: t.bookmarks.cannotLoadBookmarks, - ), + ), + if (bookmarks.bookmarks.isEmpty) + SliverFillRemaining( + child: NoDataScreen( + message: t.bookmarks.noBookmarksAdded, ), - if (bookmarks.bookmarks.isEmpty) - SliverFillRemaining( - child: NoDataScreen( - message: t.bookmarks.noBookmarksAdded, - ), - ), - if (bookmarks.bookmarks.isNotEmpty) - SlidableAutoCloseBehavior( - child: SliverList.builder( - itemCount: bookmarks.bookmarks.length + 1, - itemBuilder: (context, index) { - // index == bookmarks.value!.content!.results!.length -> itemCount + 1 - if (index == bookmarks.bookmarks.length) { - if (bookmarks.loadingMore) { - return const SizedBox( - height: 80, - child: Center( - child: CircularProgressIndicator(), - ), - ); - } - // Bottom gap for FAB - return const SizedBox(height: 80); - } - return BookmarkItem( - bookmark: bookmarks.bookmarks[index], - onReadUnread: ref.read(bookmarksProvider.notifier).markAsReadUnread, - onDelete: (bookmark) => showDialog( - context: context, - builder: (context) => DeleteBookmarkModal( - bookmark: bookmark, - onDelete: ref.read(bookmarksProvider.notifier).deleteBookmark, + ), + if (bookmarks.bookmarks.isNotEmpty) + SlidableAutoCloseBehavior( + child: SliverList.builder( + itemCount: bookmarks.bookmarks.length + 1, + itemBuilder: (context, index) { + // index == bookmarks.value!.content!.results!.length -> itemCount + 1 + if (index == bookmarks.bookmarks.length) { + if (bookmarks.loadingMore) { + return const SizedBox( + height: 80, + child: Center( + child: CircularProgressIndicator(), ), + ); + } + // Bottom gap for FAB + return const SizedBox(height: 80); + } + return BookmarkItem( + bookmark: bookmarks.bookmarks[index], + onReadUnread: ref.read(bookmarksProvider.notifier).markAsReadUnread, + onDelete: (bookmark) => showDialog( + context: context, + builder: (context) => DeleteBookmarkModal( + bookmark: bookmark, + onDelete: ref.read(bookmarksProvider.notifier).deleteBookmark, ), - onArchiveUnarchive: ref.read(bookmarksProvider.notifier).archiveUnarchive, - ); - }, - ), + ), + onArchiveUnarchive: ref.read(bookmarksProvider.notifier).archiveUnarchive, + ); + }, ), - ], - ), + ), + ], ), ), ), ), ), - SnackbarFloatingActionButton( - onPressed: openAddModal, - child: const Icon(Icons.add_rounded), - ), - ], + ), + floatingActionButton: FloatingActionButton( + onPressed: openAddModal, + child: const Icon(Icons.add_rounded), + ), ), ); } diff --git a/lib/screens/bookmarks/ui/search_bookmarks.dart b/lib/screens/bookmarks/ui/search_bookmarks.dart index 30bf4ed..ad4a662 100644 --- a/lib/screens/bookmarks/ui/search_bookmarks.dart +++ b/lib/screens/bookmarks/ui/search_bookmarks.dart @@ -38,7 +38,7 @@ class SearchBookmarksModal extends ConsumerWidget { } return ScaffoldMessenger( - key: searchScaffoldMessengerKey, + key: ScaffoldMessengerKeys.search, child: Dialog.fullscreen( child: Scaffold( appBar: AppBar( diff --git a/lib/screens/onboarding/provider/connect.provider.dart b/lib/screens/onboarding/provider/connect.provider.dart index 4144582..b4afa02 100644 --- a/lib/screens/onboarding/provider/connect.provider.dart +++ b/lib/screens/onboarding/provider/connect.provider.dart @@ -5,8 +5,9 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/screens/onboarding/model/connect.model.dart'; +import 'package:linkdy/constants/global_keys.dart'; +import 'package:linkdy/utils/snackbar.dart'; import 'package:linkdy/providers/dio_interceptor.provider.dart'; -import 'package:linkdy/providers/snackbar.provider.dart'; import 'package:linkdy/providers/server_instances.provider.dart'; import 'package:linkdy/utils/api_base_url.dart'; import 'package:linkdy/i18n/strings.g.dart'; @@ -155,9 +156,17 @@ FutureOr connectToServer(ConnectToServerRef ref) async { ref.read(apiClientProvider.notifier).setApiClient(apiClient); ref.read(serverInstancesProvider.notifier).saveNewInstance(serverInstance); } else if (result == AuthResult.invalidToken) { - ref.read(snackbarProvider.notifier).showSnacbkar(label: t.onboarding.invalidToken, color: Colors.red); + showSnackbar( + key: ScaffoldMessengerKeys.onboarding, + label: t.onboarding.invalidToken, + color: Colors.red, + ); } else { - ref.read(snackbarProvider.notifier).showSnacbkar(label: t.onboarding.cannotConnectToServer, color: Colors.red); + showSnackbar( + key: ScaffoldMessengerKeys.onboarding, + label: t.onboarding.cannotConnectToServer, + color: Colors.red, + ); } return false; diff --git a/lib/screens/onboarding/provider/connect.provider.g.dart b/lib/screens/onboarding/provider/connect.provider.g.dart index 6a70627..bb28578 100644 --- a/lib/screens/onboarding/provider/connect.provider.g.dart +++ b/lib/screens/onboarding/provider/connect.provider.g.dart @@ -6,7 +6,7 @@ part of 'connect.provider.dart'; // RiverpodGenerator // ************************************************************************** -String _$connectToServerHash() => r'a5225cddee0824ab2e6393da9d5c305e212bbfba'; +String _$connectToServerHash() => r'4c7d8eb1e2ed082e5ce2cde03f8afe343d7126b9'; /// See also [connectToServer]. @ProviderFor(connectToServer) diff --git a/lib/screens/onboarding/ui/onboarding.dart b/lib/screens/onboarding/ui/onboarding.dart index c8341c5..a177aef 100644 --- a/lib/screens/onboarding/ui/onboarding.dart +++ b/lib/screens/onboarding/ui/onboarding.dart @@ -7,22 +7,27 @@ import 'package:linkdy/screens/onboarding/ui/server_required.dart'; import 'package:linkdy/screens/onboarding/ui/welcome.dart'; import 'package:linkdy/widgets/system_overlay_style.dart'; +import 'package:linkdy/constants/global_keys.dart'; + class Onboarding extends ConsumerWidget { - const Onboarding({Key? key}) : super(key: key); + const Onboarding({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return OverlayStyle( - child: Scaffold( - body: SafeArea( - child: PageView( - controller: ref.watch(onboardingProvider).pageController, - physics: const NeverScrollableScrollPhysics(), - children: const [ - OnboardingWelcome(), - OnboardingServerRequired(), - OnboardingConnect(), - ], + child: ScaffoldMessenger( + key: ScaffoldMessengerKeys.onboarding, + child: Scaffold( + body: SafeArea( + child: PageView( + controller: ref.watch(onboardingProvider).pageController, + physics: const NeverScrollableScrollPhysics(), + children: const [ + OnboardingWelcome(), + OnboardingServerRequired(), + OnboardingConnect(), + ], + ), ), ), ), diff --git a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart b/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart index 21cf83f..e3872f8 100644 --- a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart +++ b/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart @@ -1,3 +1,4 @@ +import 'package:linkdy/constants/global_keys.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; @@ -99,6 +100,7 @@ class TagBookmarks extends _$TagBookmarks { void deleteBookmark(Bookmark bookmark) async { final result = await BookmarkCommonFunctions.deleteBookmark( + scaffoldMessengerKey: ScaffoldMessengerKeys.tagBookmarks, ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, @@ -111,6 +113,7 @@ class TagBookmarks extends _$TagBookmarks { void markAsReadUnread(Bookmark bookmark) async { final result = await BookmarkCommonFunctions.markAsReadUnread( + scaffoldMessengerKey: ScaffoldMessengerKeys.tagBookmarks, ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, @@ -123,6 +126,7 @@ class TagBookmarks extends _$TagBookmarks { void archiveUnarchive(Bookmark bookmark) async { final result = await BookmarkCommonFunctions.archiveUnarchive( + scaffoldMessengerKey: ScaffoldMessengerKeys.tagBookmarks, ref: ref, bookmark: bookmark, apiClient: ref.read(apiClientProvider)!, diff --git a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart b/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart index 841795f..e87baf7 100644 --- a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart +++ b/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart @@ -206,7 +206,7 @@ final tagBookmarksRequestLoadMoreProvider = ); typedef TagBookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef; -String _$tagBookmarksHash() => r'5a183019775e04aa10f28c1492993f09445867a7'; +String _$tagBookmarksHash() => r'd5004cac68d86490b49fc6f722ec819267aedf17'; /// See also [TagBookmarks]. @ProviderFor(TagBookmarks) diff --git a/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart b/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart index c93a7c3..a3dc33e 100644 --- a/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart +++ b/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; +import 'package:linkdy/constants/global_keys.dart'; import 'package:linkdy/screens/bookmarks/ui/bookmark_item.dart'; import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart'; @@ -19,10 +20,10 @@ class TagBookmarksScreen extends ConsumerStatefulWidget { final Tag? tag; const TagBookmarksScreen({ - Key? key, + super.key, required this.tagId, this.tag, - }) : super(key: key); + }); @override TagBookmarksScreenState createState() => TagBookmarksScreenState(); @@ -66,85 +67,89 @@ class TagBookmarksScreenState extends ConsumerState { return false; } - return Scaffold( - body: NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) => [ - SliverOverlapAbsorber( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - sliver: SliverAppBar.large( - pinned: true, - floating: true, - centerTitle: false, - forceElevated: innerBoxIsScrolled, - title: Text( - widget.tag != null - ? "#${widget.tag!.name}" - : provider.tag != null - ? "#${provider.tag!.name}" - : '', + return ScaffoldMessenger( + key: ScaffoldMessengerKeys.tagBookmarks, + child: Scaffold( + body: NestedScrollView( + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverOverlapAbsorber( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + sliver: SliverAppBar.large( + pinned: true, + floating: true, + centerTitle: false, + forceElevated: innerBoxIsScrolled, + title: Text( + widget.tag != null + ? "#${widget.tag!.name}" + : provider.tag != null + ? "#${provider.tag!.name}" + : '', + ), ), ), - ), - ], - body: SafeArea( - top: false, - child: Builder( - builder: (context) => RefreshIndicator( - displacement: 120, - onRefresh: () => ref.read(tagBookmarksProvider.notifier).refresh(), - child: NotificationListener( - onNotification: scrollListener, - child: CustomScrollView( - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - ), - if (provider.initialLoadStatus == LoadStatus.loading) - const SliverFillRemaining( - child: Center(child: CircularProgressIndicator()), + ], + body: SafeArea( + top: false, + child: Builder( + builder: (context) => RefreshIndicator( + displacement: 120, + onRefresh: () => ref.read(tagBookmarksProvider.notifier).refresh(), + child: NotificationListener( + onNotification: scrollListener, + child: CustomScrollView( + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), ), - if (provider.initialLoadStatus == LoadStatus.error) - SliverFillRemaining( - child: ErrorScreen( - error: t.bookmarks.cannotLoadBookmarks, + if (provider.initialLoadStatus == LoadStatus.loading) + const SliverFillRemaining( + child: Center(child: CircularProgressIndicator()), ), - ), - if (provider.bookmarks.isEmpty) - SliverFillRemaining( - child: NoDataScreen( - message: t.tags.tagBookmarks.noBookmarksWithThisTag, + if (provider.initialLoadStatus == LoadStatus.error) + SliverFillRemaining( + child: ErrorScreen( + error: t.bookmarks.cannotLoadBookmarks, + ), ), - ), - if (provider.bookmarks.isNotEmpty) - SlidableAutoCloseBehavior( - child: SliverList.builder( - itemCount: - provider.loadingMore == true ? provider.bookmarks.length + 1 : provider.bookmarks.length, - itemBuilder: (context, index) { - if (provider.loadingMore == true && index == provider.bookmarks.length) { - return const Padding( - padding: EdgeInsets.all(16), - child: Center( - child: CircularProgressIndicator(), + if (provider.bookmarks.isEmpty) + SliverFillRemaining( + child: NoDataScreen( + message: t.tags.tagBookmarks.noBookmarksWithThisTag, + ), + ), + if (provider.bookmarks.isNotEmpty) + SlidableAutoCloseBehavior( + child: SliverList.builder( + itemCount: provider.loadingMore == true + ? provider.bookmarks.length + 1 + : provider.bookmarks.length, + itemBuilder: (context, index) { + if (provider.loadingMore == true && index == provider.bookmarks.length) { + return const Padding( + padding: EdgeInsets.all(16), + child: Center( + child: CircularProgressIndicator(), + ), + ); + } + return BookmarkItem( + bookmark: provider.bookmarks[index], + onReadUnread: ref.read(tagBookmarksProvider.notifier).markAsReadUnread, + onDelete: (bookmark) => showDialog( + context: context, + builder: (context) => DeleteBookmarkModal( + bookmark: bookmark, + onDelete: ref.read(tagBookmarksProvider.notifier).deleteBookmark, + ), ), + onArchiveUnarchive: ref.read(tagBookmarksProvider.notifier).archiveUnarchive, ); - } - return BookmarkItem( - bookmark: provider.bookmarks[index], - onReadUnread: ref.read(tagBookmarksProvider.notifier).markAsReadUnread, - onDelete: (bookmark) => showDialog( - context: context, - builder: (context) => DeleteBookmarkModal( - bookmark: bookmark, - onDelete: ref.read(tagBookmarksProvider.notifier).deleteBookmark, - ), - ), - onArchiveUnarchive: ref.read(tagBookmarksProvider.notifier).archiveUnarchive, - ); - }, + }, + ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/screens/tags/ui/tags.dart b/lib/screens/tags/ui/tags.dart index 4534295..e90da28 100644 --- a/lib/screens/tags/ui/tags.dart +++ b/lib/screens/tags/ui/tags.dart @@ -1,19 +1,19 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:linkdy/providers/router.provider.dart'; -import 'package:linkdy/router/names.dart'; import 'package:linkdy/screens/tags/provider/tags.provider.dart'; import 'package:linkdy/screens/tags/ui/add_tag_modal.dart'; import 'package:linkdy/widgets/error_screen.dart'; import 'package:linkdy/widgets/no_data_screen.dart'; -import 'package:linkdy/widgets/snackbar_fab.dart'; import 'package:linkdy/utils/date_to_string.dart'; +import 'package:linkdy/constants/global_keys.dart'; +import 'package:linkdy/providers/router.provider.dart'; +import 'package:linkdy/router/names.dart'; import 'package:linkdy/i18n/strings.g.dart'; class TagsScreen extends ConsumerWidget { - const TagsScreen({Key? key}) : super(key: key); + const TagsScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -28,120 +28,119 @@ class TagsScreen extends ConsumerWidget { ); } - return Scaffold( - body: Stack( - children: [ - NestedScrollView( - headerSliverBuilder: (context, innerBoxIsScrolled) => [ - SliverOverlapAbsorber( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), - sliver: SliverAppBar.large( - pinned: true, - floating: true, - centerTitle: false, - forceElevated: innerBoxIsScrolled, - title: Text(t.tags.tags), - ), + return ScaffoldMessenger( + key: ScaffoldMessengerKeys.tags, + child: Scaffold( + body: NestedScrollView( + headerSliverBuilder: (context, innerBoxIsScrolled) => [ + SliverOverlapAbsorber( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + sliver: SliverAppBar.large( + pinned: true, + floating: true, + centerTitle: false, + forceElevated: innerBoxIsScrolled, + title: Text(t.tags.tags), ), - ], - body: SafeArea( - top: false, - bottom: false, - child: Builder( - builder: (context) => RefreshIndicator( - displacement: 120, - onRefresh: () => ref.refresh(tagsRequestProvider.future), - child: CustomScrollView( - slivers: [ - SliverOverlapInjector( - handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + ], + body: SafeArea( + top: false, + bottom: false, + child: Builder( + builder: (context) => RefreshIndicator( + displacement: 120, + onRefresh: () => ref.refresh(tagsRequestProvider.future), + child: CustomScrollView( + slivers: [ + SliverOverlapInjector( + handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), + ), + if (tags.isLoading && !tags.isRefreshing) + const SliverFillRemaining( + child: Center(child: CircularProgressIndicator()), ), - if (tags.isLoading && !tags.isRefreshing) - const SliverFillRemaining( - child: Center(child: CircularProgressIndicator()), + if (tags.value != null && tags.value!.successful == false) + SliverFillRemaining( + child: ErrorScreen( + error: t.bookmarks.cannotLoadBookmarks, ), - if (tags.value != null && tags.value!.successful == false) - SliverFillRemaining( - child: ErrorScreen( - error: t.bookmarks.cannotLoadBookmarks, - ), + ), + if (tags.value != null && tags.value!.successful == true && tags.value!.content!.results!.isEmpty) + SliverFillRemaining( + child: NoDataScreen( + message: t.bookmarks.noBookmarksAdded, ), - if (tags.value != null && tags.value!.successful == true && tags.value!.content!.results!.isEmpty) - SliverFillRemaining( - child: NoDataScreen( - message: t.bookmarks.noBookmarksAdded, - ), - ), - if (tags.value != null && - tags.value!.successful == true && - tags.value!.content!.results!.isNotEmpty) - SliverList.builder( - itemCount: tags.value!.content!.results!.length + 1, - itemBuilder: (context, index) { - // index == bookmarks.value!.content!.results!.length -> itemCount + 1 - if (index == tags.value!.content!.results!.length) { - // Bottom gap for FAB - return const SizedBox(height: 80); - } - final tag = tags.value?.content?.results?[index]; - return InkWell( - onTap: () => ref.watch(routerProvider).pushNamed( - RoutesNames.tagBookmarks, - extra: tag, - pathParameters: {'id': tag.id!.toString()}, - ), - child: Container( - width: double.maxFinite, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon( - Icons.label_rounded, - size: 16, - color: Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.7), - ), - const SizedBox(width: 8), - Flexible( - child: Text( - tag!.name!, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Theme.of(context).colorScheme.onSurface, - ), + ), + if (tags.value != null && + tags.value!.successful == true && + tags.value!.content!.results!.isNotEmpty) + SliverList.builder( + itemCount: tags.value!.content!.results!.length + 1, + itemBuilder: (context, index) { + // index == bookmarks.value!.content!.results!.length -> itemCount + 1 + if (index == tags.value!.content!.results!.length) { + // Bottom gap for FAB + return const SizedBox(height: 80); + } + final tag = tags.value?.content?.results?[index]; + return InkWell( + onTap: () => ref.watch(routerProvider).pushNamed( + RoutesNames.tagBookmarks, + extra: tag, + pathParameters: {'id': tag.id!.toString()}, + ), + child: Container( + width: double.maxFinite, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon( + Icons.label_rounded, + size: 16, + color: Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.7), + ), + const SizedBox(width: 8), + Flexible( + child: Text( + tag!.name!, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).colorScheme.onSurface, ), ), - ], - ), - const SizedBox(height: 4), - Text( - t.tags.created(created: dateToString(tag.dateAdded!)), - style: TextStyle( - fontSize: 14, - color: Theme.of(context).colorScheme.onSurfaceVariant, ), + ], + ), + const SizedBox(height: 4), + Text( + t.tags.created(created: dateToString(tag.dateAdded!)), + style: TextStyle( + fontSize: 14, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), - ], - ), + ), + ], ), - ); - }, - ), - ], - ), + ), + ); + }, + ), + ], ), ), ), ), - SnackbarFloatingActionButton( - onPressed: openAddModal, - child: const Icon(Icons.add_rounded), - ), - ], + ), + floatingActionButton: FloatingActionButton( + onPressed: openAddModal, + child: const Icon(Icons.add_rounded), + ), ), ); } diff --git a/lib/screens/webview/ui/webview.dart b/lib/screens/webview/ui/webview.dart index 60562ff..90e5092 100644 --- a/lib/screens/webview/ui/webview.dart +++ b/lib/screens/webview/ui/webview.dart @@ -5,6 +5,7 @@ import 'package:share_plus/share_plus.dart'; import 'package:linkdy/screens/webview/provider/webview.provider.dart'; +import 'package:linkdy/constants/global_keys.dart'; import 'package:linkdy/models/data/bookmarks.dart'; import 'package:linkdy/i18n/strings.g.dart'; import 'package:linkdy/utils/copy_clipboard.dart'; @@ -14,144 +15,148 @@ class WebViewScreen extends ConsumerWidget { final Bookmark bookmark; const WebViewScreen({ - Key? key, + super.key, required this.bookmark, - }) : super(key: key); + }); @override Widget build(BuildContext context, WidgetRef ref) { - return Scaffold( - appBar: AppBar( - elevation: 3, - title: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - bookmark.title != "" ? bookmark.title! : bookmark.websiteTitle!, - style: const TextStyle(fontSize: 14), - ), - const SizedBox(height: 4), - Text( - bookmark.url!, - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.onSurfaceVariant, + return ScaffoldMessenger( + key: ScaffoldMessengerKeys.webview, + child: Scaffold( + appBar: AppBar( + elevation: 3, + title: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + bookmark.title != "" ? bookmark.title! : bookmark.websiteTitle!, + style: const TextStyle(fontSize: 14), ), - ), - ], - ), - bottom: PreferredSize( - preferredSize: const Size(double.maxFinite, 0), - child: ref.watch(webViewProvider).loadProgress < 100 - ? const LinearProgressIndicator() - : const SizedBox( - height: 4, + const SizedBox(height: 4), + Text( + bookmark.url!, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.onSurfaceVariant, ), + ), + ], + ), + bottom: PreferredSize( + preferredSize: const Size(double.maxFinite, 0), + child: ref.watch(webViewProvider).loadProgress < 100 + ? const LinearProgressIndicator() + : const SizedBox( + height: 4, + ), + ), ), - ), - body: SafeArea( - child: Column( - children: [ - Expanded( - child: InAppWebView( - initialUrlRequest: URLRequest(url: WebUri.uri(Uri.parse(bookmark.url!))), - onWebViewCreated: (controller) { - ref.read(webViewProvider).inAppWebViewController = controller; - }, - onPermissionRequest: (controller, request) async { - return PermissionResponse( - resources: request.resources, - action: PermissionResponseAction.DENY, - ); - }, - onProgressChanged: (controller, progress) { - ref.read(webViewProvider.notifier).setLoadProgress(progress); - }, - initialSettings: InAppWebViewSettings( - cacheEnabled: false, - isInspectable: false, + body: SafeArea( + child: Column( + children: [ + Expanded( + child: InAppWebView( + initialUrlRequest: URLRequest(url: WebUri.uri(Uri.parse(bookmark.url!))), + onWebViewCreated: (controller) { + ref.read(webViewProvider).inAppWebViewController = controller; + }, + onPermissionRequest: (controller, request) async { + return PermissionResponse( + resources: request.resources, + action: PermissionResponseAction.DENY, + ); + }, + onProgressChanged: (controller, progress) { + ref.read(webViewProvider.notifier).setLoadProgress(progress); + }, + initialSettings: InAppWebViewSettings( + cacheEnabled: false, + isInspectable: false, + ), + onUpdateVisitedHistory: (controller, url, androidIsReload) { + controller.canGoBack().then( + (value) => context.mounted ? ref.read(webViewProvider.notifier).setCanGoBack(value) : null, + ); + controller.canGoForward().then( + (value) => context.mounted ? ref.read(webViewProvider.notifier).setCanGoForward(value) : null, + ); + }, ), - onUpdateVisitedHistory: (controller, url, androidIsReload) { - controller.canGoBack().then( - (value) => context.mounted ? ref.read(webViewProvider.notifier).setCanGoBack(value) : null, - ); - controller.canGoForward().then( - (value) => context.mounted ? ref.read(webViewProvider.notifier).setCanGoForward(value) : null, - ); - }, ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - IconButton( - onPressed: ref.watch(webViewProvider).canGoBack == true - ? () => ref.watch(webViewProvider).inAppWebViewController?.goBack() - : null, - icon: const Icon(Icons.arrow_back_rounded), - tooltip: t.webview.goForward, - ), - const SizedBox(width: 8), - IconButton( - onPressed: ref.watch(webViewProvider).canGoForward == true - ? () => ref.watch(webViewProvider).inAppWebViewController?.goForward() - : null, - icon: const Icon(Icons.arrow_forward_rounded), - tooltip: t.webview.goForward, - ), - const SizedBox(width: 16), - IconButton( - onPressed: () => ref.watch(webViewProvider).inAppWebViewController?.reload(), - icon: const Icon(Icons.refresh_rounded), - tooltip: t.webview.reload, - ), - ], - ), - PopupMenuButton( - itemBuilder: (context) => [ - PopupMenuItem( - onTap: () => Share.shareUri(Uri.parse(bookmark.url!)), - child: Row( - children: [ - const Icon(Icons.share_rounded), - const SizedBox(width: 12), - Flexible(child: Text(t.webview.share)), - ], + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + children: [ + IconButton( + onPressed: ref.watch(webViewProvider).canGoBack == true + ? () => ref.watch(webViewProvider).inAppWebViewController?.goBack() + : null, + icon: const Icon(Icons.arrow_back_rounded), + tooltip: t.webview.goForward, ), - ), - PopupMenuItem( - onTap: () => copyToClipboard( - value: bookmark.url!, - successMessage: t.webview.linkCopiedClipboard, + const SizedBox(width: 8), + IconButton( + onPressed: ref.watch(webViewProvider).canGoForward == true + ? () => ref.watch(webViewProvider).inAppWebViewController?.goForward() + : null, + icon: const Icon(Icons.arrow_forward_rounded), + tooltip: t.webview.goForward, ), - child: Row( - children: [ - const Icon(Icons.copy_rounded), - const SizedBox(width: 12), - Flexible(child: Text(t.webview.copyLinkClipboard)), - ], + const SizedBox(width: 16), + IconButton( + onPressed: () => ref.watch(webViewProvider).inAppWebViewController?.reload(), + icon: const Icon(Icons.refresh_rounded), + tooltip: t.webview.reload, ), - ), - PopupMenuItem( - onTap: () => openUrl(bookmark.url!), - child: Row( - children: [ - const Icon(Icons.open_in_browser_rounded), - const SizedBox(width: 12), - Flexible(child: Text(t.webview.openInSystemBrowser)), - ], + ], + ), + PopupMenuButton( + itemBuilder: (context) => [ + PopupMenuItem( + onTap: () => Share.shareUri(Uri.parse(bookmark.url!)), + child: Row( + children: [ + const Icon(Icons.share_rounded), + const SizedBox(width: 12), + Flexible(child: Text(t.webview.share)), + ], + ), ), - ), - ], - ), - ], + PopupMenuItem( + onTap: () => copyToClipboard( + key: ScaffoldMessengerKeys.webview, + value: bookmark.url!, + successMessage: t.webview.linkCopiedClipboard, + ), + child: Row( + children: [ + const Icon(Icons.copy_rounded), + const SizedBox(width: 12), + Flexible(child: Text(t.webview.copyLinkClipboard)), + ], + ), + ), + PopupMenuItem( + onTap: () => openUrl(bookmark.url!), + child: Row( + children: [ + const Icon(Icons.open_in_browser_rounded), + const SizedBox(width: 12), + Flexible(child: Text(t.webview.openInSystemBrowser)), + ], + ), + ), + ], + ), + ], + ), ), - ), - ], + ], + ), ), ), ); diff --git a/lib/utils/copy_clipboard.dart b/lib/utils/copy_clipboard.dart index 8cb0e8e..dac7aac 100644 --- a/lib/utils/copy_clipboard.dart +++ b/lib/utils/copy_clipboard.dart @@ -1,23 +1,18 @@ -// ignore_for_file: use_build_context_synchronously - import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:linkdy/constants/global_keys.dart'; - void copyToClipboard({ + required GlobalKey key, required String value, required String successMessage, }) async { - if (scaffoldMessengerGlobalKey.currentState != null) { - await Clipboard.setData( - ClipboardData(text: value), - ); - scaffoldMessengerGlobalKey.currentState!.showSnackBar( - SnackBar( - content: Text(successMessage), - backgroundColor: Colors.green, - ), - ); - } + await Clipboard.setData( + ClipboardData(text: value), + ); + key.currentState!.showSnackBar( + SnackBar( + content: Text(successMessage), + backgroundColor: Colors.green, + ), + ); } diff --git a/lib/utils/snackbar.dart b/lib/utils/snackbar.dart new file mode 100644 index 0000000..a0e6a1e --- /dev/null +++ b/lib/utils/snackbar.dart @@ -0,0 +1,17 @@ +import 'package:flutter/material.dart'; + +void showSnackbar({ + required GlobalKey key, + required String label, + required Color color, + Color? labelColor, +}) { + final snackBar = SnackBar( + content: Text( + label, + style: TextStyle(color: labelColor ?? Colors.white), + ), + backgroundColor: color, + ); + key.currentState?.showSnackBar(snackBar); +} diff --git a/lib/widgets/layout.dart b/lib/widgets/layout.dart index d8dfb7a..6ed995e 100644 --- a/lib/widgets/layout.dart +++ b/lib/widgets/layout.dart @@ -12,10 +12,10 @@ class Layout extends ConsumerWidget { final Widget child; const Layout({ - Key? key, + super.key, required this.state, required this.child, - }) : super(key: key); + }); @override Widget build(BuildContext context, WidgetRef ref) { diff --git a/lib/widgets/snackbar_fab.dart b/lib/widgets/snackbar_fab.dart deleted file mode 100644 index e63e2f0..0000000 --- a/lib/widgets/snackbar_fab.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; - -import 'package:linkdy/providers/snackbar.provider.dart'; - -class SnackbarFloatingActionButton extends ConsumerWidget { - final Widget child; - final void Function() onPressed; - - const SnackbarFloatingActionButton({ - Key? key, - required this.onPressed, - required this.child, - }) : super(key: key); - - @override - Widget build(BuildContext context, WidgetRef ref) { - return AnimatedPositioned( - bottom: ref.watch(snackbarProvider).visible == true ? 70 : 20, - right: 20, - duration: const Duration(milliseconds: 200), - curve: Curves.ease, - child: FloatingActionButton( - onPressed: onPressed, - child: child, - ), - ); - } -}