From 06df3c2e0a9107601036b685eee3d97f2eba62b7 Mon Sep 17 00:00:00 2001 From: Juan Gilsanz Polo Date: Wed, 28 Feb 2024 01:13:55 +0100 Subject: [PATCH] Added shared bookmarks screen and archived bookmarks screen --- lib/constants/enums.dart | 2 + lib/constants/global_keys.dart | 2 +- lib/i18n/strings.g.dart | 52 +++-- lib/i18n/strings_en.i18n.json | 11 +- lib/i18n/strings_es.i18n.json | 11 +- lib/models/data/bookmarks.dart | 31 +++ lib/router/paths.dart | 2 + lib/router/routes.dart | 19 +- .../bookmarks/provider/common_functions.dart | 4 +- lib/screens/bookmarks/ui/bookmark_item.dart | 8 +- lib/screens/bookmarks/ui/bookmarks.dart | 26 +++ .../model/filtered_bookmarks.model.dart} | 6 +- .../provider/filtered_bookmarks.provider.dart | 220 ++++++++++++++++++ .../filtered_bookmarks.provider.g.dart} | 193 +++++++++++++-- .../ui/filtered_bookmarks.dart} | 113 ++++++--- .../provider/tag_bookmarks.provider.dart | 153 ------------ lib/services/api_client.dart | 44 ++++ lib/widgets/no_data_screen.dart | 2 +- 18 files changed, 663 insertions(+), 236 deletions(-) rename lib/screens/{tag_bookmarks/model/tag_bookmarks.model.dart => filtered_bookmarks/model/filtered_bookmarks.model.dart} (77%) create mode 100644 lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart rename lib/screens/{tag_bookmarks/provider/tag_bookmarks.provider.g.dart => filtered_bookmarks/provider/filtered_bookmarks.provider.g.dart} (51%) rename lib/screens/{tag_bookmarks/ui/tag_bookmarks.dart => filtered_bookmarks/ui/filtered_bookmarks.dart} (59%) delete mode 100644 lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart diff --git a/lib/constants/enums.dart b/lib/constants/enums.dart index b3fd409..4308001 100644 --- a/lib/constants/enums.dart +++ b/lib/constants/enums.dart @@ -5,3 +5,5 @@ enum ConnectionMethod { http, https } enum SelectedTheme { system, light, dark } enum AuthResult { success, invalidToken, other } + +enum FilteredBookmarksMode { tag, shared, archived } diff --git a/lib/constants/global_keys.dart b/lib/constants/global_keys.dart index b2da224..89d2c72 100644 --- a/lib/constants/global_keys.dart +++ b/lib/constants/global_keys.dart @@ -7,6 +7,6 @@ class ScaffoldMessengerKeys { static final search = GlobalKey(); static final tags = GlobalKey(); static final addBookmark = GlobalKey(); - static final tagBookmarks = GlobalKey(); + static final filteredBookmarks = GlobalKey(); static final webview = GlobalKey(); } diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart index e27c0d6..c7a0fdd 100644 --- a/lib/i18n/strings.g.dart +++ b/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 322 (161 per locale) +/// Strings: 332 (166 per locale) /// -/// Built on 2024-02-27 at 17:13 UTC +/// Built on 2024-02-28 at 00:11 UTC // coverage:ignore-file // ignore_for_file: type=lint @@ -224,6 +224,8 @@ class _StringsBookmarksEn { String get noBookmarksAdded => 'No bookmarks added'; String get cannotLoadBookmarks => 'Cannot load the bookmarks'; late final _StringsBookmarksDatesEn dates = _StringsBookmarksDatesEn._(_root); + String get shared => 'Shared'; + String get archived => 'Archived'; late final _StringsBookmarksAddBookmarkEn addBookmark = _StringsBookmarksAddBookmarkEn._(_root); late final _StringsBookmarksSearchEn search = _StringsBookmarksSearchEn._(_root); late final _StringsBookmarksBookmarkOptionsEn bookmarkOptions = _StringsBookmarksBookmarkOptionsEn._(_root); @@ -240,7 +242,7 @@ class _StringsTagsEn { String get tags => 'Tags'; String created({required Object created}) => 'Created: ${created}'; late final _StringsTagsCreateTagEn createTag = _StringsTagsCreateTagEn._(_root); - late final _StringsTagsTagBookmarksEn tagBookmarks = _StringsTagsTagBookmarksEn._(_root); + late final _StringsTagsFilteredBookmarksEn filteredBookmarks = _StringsTagsFilteredBookmarksEn._(_root); } // Path: settings @@ -368,9 +370,10 @@ class _StringsBookmarksBookmarkOptionsEn { String get delete => 'Delete'; String get unread => 'Unread'; String get read => 'Read'; - String get share => 'Share'; + String get shareOptions => 'Share options'; String get shared => 'Shared'; String get archive => 'Archive'; + String get unarchive => 'Unarchive'; String get deletingBookmark => 'Deleting bookmark...'; String get bookmarkDeleted => 'Bookmark deleted successfully'; String get bookmarkNotDeleted => 'The bookmark couldn\'t be deleted due to an error.'; @@ -425,14 +428,16 @@ class _StringsTagsCreateTagEn { String get errorCreatingTag => 'An error occured when creating the tag.'; } -// Path: tags.tagBookmarks -class _StringsTagsTagBookmarksEn { - _StringsTagsTagBookmarksEn._(this._root); +// Path: tags.filteredBookmarks +class _StringsTagsFilteredBookmarksEn { + _StringsTagsFilteredBookmarksEn._(this._root); final Translations _root; // ignore: unused_field // Translations String get noBookmarksWithThisTag => 'There are no bookmarks with this tag'; + String get noArchivedBookmarks => 'There are no archived bookmarks'; + String get noSharedBookmarks => 'There are no shared bookmarks'; } // Path: settings.customization @@ -581,6 +586,8 @@ class _StringsBookmarksEs implements _StringsBookmarksEn { @override String get noBookmarksAdded => 'No hay marcadores añadidos'; @override String get cannotLoadBookmarks => 'No se pueden cargar los marcadores'; @override late final _StringsBookmarksDatesEs dates = _StringsBookmarksDatesEs._(_root); + @override String get shared => 'Compartidos'; + @override String get archived => 'Archivados'; @override late final _StringsBookmarksAddBookmarkEs addBookmark = _StringsBookmarksAddBookmarkEs._(_root); @override late final _StringsBookmarksSearchEs search = _StringsBookmarksSearchEs._(_root); @override late final _StringsBookmarksBookmarkOptionsEs bookmarkOptions = _StringsBookmarksBookmarkOptionsEs._(_root); @@ -597,7 +604,7 @@ class _StringsTagsEs implements _StringsTagsEn { @override String get tags => 'Etiquetas'; @override String created({required Object created}) => 'Creado: ${created}'; @override late final _StringsTagsCreateTagEs createTag = _StringsTagsCreateTagEs._(_root); - @override late final _StringsTagsTagBookmarksEs tagBookmarks = _StringsTagsTagBookmarksEs._(_root); + @override late final _StringsTagsFilteredBookmarksEs filteredBookmarks = _StringsTagsFilteredBookmarksEs._(_root); } // Path: settings @@ -725,9 +732,10 @@ class _StringsBookmarksBookmarkOptionsEs implements _StringsBookmarksBookmarkOpt @override String get delete => 'Eliminar'; @override String get unread => 'No leído'; @override String get read => 'Leído'; - @override String get share => 'Compartir'; + @override String get shareOptions => 'Opciones de compartir'; @override String get shared => 'Compartido'; @override String get archive => 'Archivar'; + @override String get unarchive => 'Desarchivar'; @override String get deletingBookmark => 'Eliminando marcador...'; @override String get bookmarkDeleted => 'Marcador eliminado correctamente'; @override String get bookmarkNotDeleted => 'El marcador no se ha podido eliminar debido a un error.'; @@ -782,14 +790,16 @@ class _StringsTagsCreateTagEs implements _StringsTagsCreateTagEn { @override String get errorCreatingTag => 'Ocurrió un error al crear la etiqueta.'; } -// Path: tags.tagBookmarks -class _StringsTagsTagBookmarksEs implements _StringsTagsTagBookmarksEn { - _StringsTagsTagBookmarksEs._(this._root); +// Path: tags.filteredBookmarks +class _StringsTagsFilteredBookmarksEs implements _StringsTagsFilteredBookmarksEn { + _StringsTagsFilteredBookmarksEs._(this._root); @override final _StringsEs _root; // ignore: unused_field // Translations @override String get noBookmarksWithThisTag => 'No hay marcadores con esta etiqueta'; + @override String get noArchivedBookmarks => 'No hay marcadores archivados'; + @override String get noSharedBookmarks => 'No hay marcadores compartidos'; } // Path: settings.customization @@ -887,6 +897,8 @@ extension on Translations { case 'bookmarks.cannotLoadBookmarks': return 'Cannot load the bookmarks'; case 'bookmarks.dates.todayAt': return ({required Object time}) => 'Today, ${time}'; case 'bookmarks.dates.yesterdayAt': return ({required Object time}) => 'Yesterday, ${time}'; + case 'bookmarks.shared': return 'Shared'; + case 'bookmarks.archived': return 'Archived'; case 'bookmarks.addBookmark.addBookmark': return 'Add new bookmark'; case 'bookmarks.addBookmark.editBookmark': return 'Edit bookmark'; case 'bookmarks.addBookmark.bookmarkUrl': return 'Bookmark URL'; @@ -922,9 +934,10 @@ extension on Translations { case 'bookmarks.bookmarkOptions.delete': return 'Delete'; case 'bookmarks.bookmarkOptions.unread': return 'Unread'; case 'bookmarks.bookmarkOptions.read': return 'Read'; - case 'bookmarks.bookmarkOptions.share': return 'Share'; + case 'bookmarks.bookmarkOptions.shareOptions': return 'Share options'; case 'bookmarks.bookmarkOptions.shared': return 'Shared'; case 'bookmarks.bookmarkOptions.archive': return 'Archive'; + case 'bookmarks.bookmarkOptions.unarchive': return 'Unarchive'; case 'bookmarks.bookmarkOptions.deletingBookmark': return 'Deleting bookmark...'; case 'bookmarks.bookmarkOptions.bookmarkDeleted': return 'Bookmark deleted successfully'; case 'bookmarks.bookmarkOptions.bookmarkNotDeleted': return 'The bookmark couldn\'t be deleted due to an error.'; @@ -961,7 +974,9 @@ extension on Translations { case 'tags.createTag.name': return 'Name'; case 'tags.createTag.creatingTag': return 'Creating tag...'; case 'tags.createTag.errorCreatingTag': return 'An error occured when creating the tag.'; - case 'tags.tagBookmarks.noBookmarksWithThisTag': return 'There are no bookmarks with this tag'; + case 'tags.filteredBookmarks.noBookmarksWithThisTag': return 'There are no bookmarks with this tag'; + case 'tags.filteredBookmarks.noArchivedBookmarks': return 'There are no archived bookmarks'; + case 'tags.filteredBookmarks.noSharedBookmarks': return 'There are no shared bookmarks'; case 'settings.settings': return 'Settings'; case 'settings.appSettings': return 'App settings'; case 'settings.aboutApp': return 'About the app'; @@ -1056,6 +1071,8 @@ extension on _StringsEs { case 'bookmarks.cannotLoadBookmarks': return 'No se pueden cargar los marcadores'; case 'bookmarks.dates.todayAt': return ({required Object time}) => 'Hoy, ${time}'; case 'bookmarks.dates.yesterdayAt': return ({required Object time}) => 'Ayer, ${time}'; + case 'bookmarks.shared': return 'Compartidos'; + case 'bookmarks.archived': return 'Archivados'; case 'bookmarks.addBookmark.addBookmark': return 'Añadir nuevo marcador'; case 'bookmarks.addBookmark.editBookmark': return 'Editar marcador'; case 'bookmarks.addBookmark.url': return 'URL'; @@ -1091,9 +1108,10 @@ extension on _StringsEs { case 'bookmarks.bookmarkOptions.delete': return 'Eliminar'; case 'bookmarks.bookmarkOptions.unread': return 'No leído'; case 'bookmarks.bookmarkOptions.read': return 'Leído'; - case 'bookmarks.bookmarkOptions.share': return 'Compartir'; + case 'bookmarks.bookmarkOptions.shareOptions': return 'Opciones de compartir'; case 'bookmarks.bookmarkOptions.shared': return 'Compartido'; case 'bookmarks.bookmarkOptions.archive': return 'Archivar'; + case 'bookmarks.bookmarkOptions.unarchive': return 'Desarchivar'; case 'bookmarks.bookmarkOptions.deletingBookmark': return 'Eliminando marcador...'; case 'bookmarks.bookmarkOptions.bookmarkDeleted': return 'Marcador eliminado correctamente'; case 'bookmarks.bookmarkOptions.bookmarkNotDeleted': return 'El marcador no se ha podido eliminar debido a un error.'; @@ -1130,7 +1148,9 @@ extension on _StringsEs { case 'tags.createTag.name': return 'Nombre'; case 'tags.createTag.creatingTag': return 'Creando etiqueta...'; case 'tags.createTag.errorCreatingTag': return 'Ocurrió un error al crear la etiqueta.'; - case 'tags.tagBookmarks.noBookmarksWithThisTag': return 'No hay marcadores con esta etiqueta'; + case 'tags.filteredBookmarks.noBookmarksWithThisTag': return 'No hay marcadores con esta etiqueta'; + case 'tags.filteredBookmarks.noArchivedBookmarks': return 'No hay marcadores archivados'; + case 'tags.filteredBookmarks.noSharedBookmarks': return 'No hay marcadores compartidos'; case 'settings.settings': return 'Ajustes'; case 'settings.appSettings': return 'Ajustes de la aplicación'; case 'settings.aboutApp': return 'Sobre la aplicación'; diff --git a/lib/i18n/strings_en.i18n.json b/lib/i18n/strings_en.i18n.json index 85ff93a..8531d1b 100644 --- a/lib/i18n/strings_en.i18n.json +++ b/lib/i18n/strings_en.i18n.json @@ -49,6 +49,8 @@ "todayAt": "Today, $time", "yesterdayAt": "Yesterday, $time" }, + "shared": "Shared", + "archived": "Archived", "addBookmark": { "addBookmark": "Add new bookmark", "editBookmark": "Edit bookmark", @@ -89,9 +91,10 @@ "delete": "Delete", "unread": "Unread", "read": "Read", - "share": "Share", + "shareOptions": "Share options", "shared": "Shared", "archive": "Archive", + "unarchive": "Unarchive", "deletingBookmark": "Deleting bookmark...", "bookmarkDeleted": "Bookmark deleted successfully", "bookmarkNotDeleted": "The bookmark couldn't be deleted due to an error.", @@ -135,8 +138,10 @@ "creatingTag": "Creating tag...", "errorCreatingTag": "An error occured when creating the tag." }, - "tagBookmarks": { - "noBookmarksWithThisTag": "There are no bookmarks with this tag" + "filteredBookmarks": { + "noBookmarksWithThisTag": "There are no bookmarks with this tag", + "noArchivedBookmarks": "There are no archived bookmarks", + "noSharedBookmarks": "There are no shared bookmarks" } }, "settings": { diff --git a/lib/i18n/strings_es.i18n.json b/lib/i18n/strings_es.i18n.json index f7eba12..37548a4 100644 --- a/lib/i18n/strings_es.i18n.json +++ b/lib/i18n/strings_es.i18n.json @@ -49,6 +49,8 @@ "todayAt": "Hoy, $time", "yesterdayAt": "Ayer, $time" }, + "shared": "Compartidos", + "archived": "Archivados", "addBookmark": { "addBookmark": "Añadir nuevo marcador", "editBookmark": "Editar marcador", @@ -89,9 +91,10 @@ "delete": "Eliminar", "unread": "No leído", "read": "Leído", - "share": "Compartir", + "shareOptions": "Opciones de compartir", "shared": "Compartido", "archive": "Archivar", + "unarchive": "Desarchivar", "deletingBookmark": "Eliminando marcador...", "bookmarkDeleted": "Marcador eliminado correctamente", "bookmarkNotDeleted": "El marcador no se ha podido eliminar debido a un error.", @@ -135,8 +138,10 @@ "creatingTag": "Creando etiqueta...", "errorCreatingTag": "Ocurrió un error al crear la etiqueta." }, - "tagBookmarks": { - "noBookmarksWithThisTag": "No hay marcadores con esta etiqueta" + "filteredBookmarks": { + "noBookmarksWithThisTag": "No hay marcadores con esta etiqueta", + "noArchivedBookmarks": "No hay marcadores archivados", + "noSharedBookmarks": "No hay marcadores compartidos" } }, "settings": { diff --git a/lib/models/data/bookmarks.dart b/lib/models/data/bookmarks.dart index 54d84fd..9d8cba2 100644 --- a/lib/models/data/bookmarks.dart +++ b/lib/models/data/bookmarks.dart @@ -88,4 +88,35 @@ class Bookmark { "date_added": dateAdded?.toIso8601String(), "date_modified": dateModified?.toIso8601String(), }; + + Bookmark copyWith({ + int? id, + String? url, + String? title, + String? description, + String? notes, + String? websiteTitle, + String? websiteDescription, + bool? isArchived, + bool? unread, + bool? shared, + List? tagNames, + DateTime? dateAdded, + DateTime? dateModified, + }) => + Bookmark( + id: id ?? this.id, + url: url ?? this.url, + title: title ?? this.title, + description: description ?? this.description, + notes: notes ?? this.notes, + websiteTitle: websiteTitle ?? this.websiteTitle, + websiteDescription: websiteDescription ?? this.websiteDescription, + isArchived: isArchived ?? this.isArchived, + unread: unread ?? this.unread, + shared: shared ?? this.shared, + tagNames: tagNames ?? this.tagNames, + dateAdded: dateAdded ?? this.dateAdded, + dateModified: dateModified ?? this.dateModified, + ); } diff --git a/lib/router/paths.dart b/lib/router/paths.dart index 81bd540..25922b6 100644 --- a/lib/router/paths.dart +++ b/lib/router/paths.dart @@ -5,6 +5,8 @@ class RoutesPaths { static const webview = "/webview"; static const tags = "/tags"; static const tagBookmarks = "/tags/:id"; + static const sharedBookmarks = "/bookmarks/shared"; + static const archivedBookmarks = "/bookmarks/archived"; static const settings = "/settings"; static const customization = "/settings/customization"; static const generalSettings = "/settings/general"; diff --git a/lib/router/routes.dart b/lib/router/routes.dart index 67faf42..4ca5fe8 100644 --- a/lib/router/routes.dart +++ b/lib/router/routes.dart @@ -1,6 +1,5 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; -import 'package:linkdy/models/data/tags.dart'; import 'package:linkdy/router/names.dart'; import 'package:linkdy/screens/bookmarks/ui/bookmarks.dart'; @@ -8,12 +7,14 @@ import 'package:linkdy/screens/onboarding/ui/onboarding.dart'; import 'package:linkdy/screens/settings/ui/customization/customization.dart'; import 'package:linkdy/screens/settings/ui/general_settings/general_settings.dart'; import 'package:linkdy/screens/settings/ui/settings.dart'; -import 'package:linkdy/screens/tag_bookmarks/ui/tag_bookmarks.dart'; +import 'package:linkdy/screens/filtered_bookmarks/ui/filtered_bookmarks.dart'; import 'package:linkdy/screens/tags/ui/tags.dart'; import 'package:linkdy/screens/webview/ui/webview.dart'; import 'package:linkdy/widgets/layout.dart'; import 'package:linkdy/widgets/page_transition.dart'; +import 'package:linkdy/constants/enums.dart'; +import 'package:linkdy/models/data/tags.dart'; import 'package:linkdy/models/data/bookmarks.dart'; import 'package:linkdy/router/paths.dart'; @@ -50,7 +51,19 @@ final List appRoutes = [ GoRoute( path: RoutesPaths.tagBookmarks, name: RoutesNames.tagBookmarks, - builder: (context, state) => TagBookmarksScreen(tagId: state.pathParameters['id'], tag: state.extra as Tag?), + builder: (context, state) => FilteredBookmarksScreen( + filteredBookmarksMode: FilteredBookmarksMode.tag, + tagId: state.pathParameters['id'], + tag: state.extra as Tag?, + ), + ), + GoRoute( + path: RoutesPaths.sharedBookmarks, + builder: (context, state) => const FilteredBookmarksScreen(filteredBookmarksMode: FilteredBookmarksMode.shared), + ), + GoRoute( + path: RoutesPaths.archivedBookmarks, + builder: (context, state) => const FilteredBookmarksScreen(filteredBookmarksMode: FilteredBookmarksMode.archived), ), GoRoute( path: RoutesPaths.customization, diff --git a/lib/screens/bookmarks/provider/common_functions.dart b/lib/screens/bookmarks/provider/common_functions.dart index 64c84d5..5e24be0 100644 --- a/lib/screens/bookmarks/provider/common_functions.dart +++ b/lib/screens/bookmarks/provider/common_functions.dart @@ -145,7 +145,7 @@ class BookmarkCommonFunctions { if (result.successful == true) { showSnackbar( key: scaffoldMessengerKey, - label: bookmark.isArchived == true + label: bookmark.shared == true ? t.bookmarks.shareOptions.bookmarkUnsharedSuccessfully : t.bookmarks.shareOptions.bookmarkSharedSuccessfully, color: Colors.green, @@ -154,7 +154,7 @@ class BookmarkCommonFunctions { } else { showSnackbar( key: scaffoldMessengerKey, - label: bookmark.isArchived == true + label: bookmark.shared == true ? t.bookmarks.shareOptions.bookmarkNotUnshared : t.bookmarks.shareOptions.bookmarkNotShared, color: Colors.red, diff --git a/lib/screens/bookmarks/ui/bookmark_item.dart b/lib/screens/bookmarks/ui/bookmark_item.dart index 82330a1..47175e9 100644 --- a/lib/screens/bookmarks/ui/bookmark_item.dart +++ b/lib/screens/bookmarks/ui/bookmark_item.dart @@ -63,8 +63,10 @@ class BookmarkItem extends ConsumerWidget { SlidableAction( onPressed: (ctx) => onArchiveUnarchive(bookmark), backgroundColor: Colors.grey, - label: t.bookmarks.bookmarkOptions.archive, - icon: Icons.archive_rounded, + label: bookmark.isArchived == true + ? t.bookmarks.bookmarkOptions.unarchive + : t.bookmarks.bookmarkOptions.archive, + icon: bookmark.isArchived == true ? Icons.unarchive_rounded : Icons.archive_rounded, padding: const EdgeInsets.all(4), ), SlidableAction( @@ -73,7 +75,7 @@ class BookmarkItem extends ConsumerWidget { builder: (ctx) => ShareOptionsModal(bookmark: bookmark, onShareInternally: onShareInternally), ), backgroundColor: Colors.orange, - label: t.bookmarks.bookmarkOptions.share, + label: t.bookmarks.bookmarkOptions.shareOptions, icon: Icons.share_rounded, padding: const EdgeInsets.all(4), ), diff --git a/lib/screens/bookmarks/ui/bookmarks.dart b/lib/screens/bookmarks/ui/bookmarks.dart index 199c317..76ab93b 100644 --- a/lib/screens/bookmarks/ui/bookmarks.dart +++ b/lib/screens/bookmarks/ui/bookmarks.dart @@ -12,6 +12,8 @@ import 'package:linkdy/widgets/error_screen.dart'; import 'package:linkdy/widgets/no_data_screen.dart'; import 'package:linkdy/constants/enums.dart'; +import 'package:linkdy/providers/router.provider.dart'; +import 'package:linkdy/router/paths.dart'; import 'package:linkdy/constants/global_keys.dart'; import 'package:linkdy/i18n/strings.g.dart'; @@ -68,6 +70,30 @@ class BookmarksScreen extends ConsumerWidget { icon: const Icon(Icons.search_rounded), tooltip: t.bookmarks.search.searchBookmarks, ), + PopupMenuButton( + itemBuilder: (context) => [ + PopupMenuItem( + onTap: () => ref.read(routerProvider).push(RoutesPaths.archivedBookmarks), + child: Row( + children: [ + const Icon(Icons.archive_rounded), + const SizedBox(width: 16), + Text(t.bookmarks.archived), + ], + ), + ), + PopupMenuItem( + onTap: () => ref.read(routerProvider).push(RoutesPaths.sharedBookmarks), + child: Row( + children: [ + const Icon(Icons.share_rounded), + const SizedBox(width: 16), + Text(t.bookmarks.shared), + ], + ), + ), + ], + ), const SizedBox(width: 8), ], ), diff --git a/lib/screens/tag_bookmarks/model/tag_bookmarks.model.dart b/lib/screens/filtered_bookmarks/model/filtered_bookmarks.model.dart similarity index 77% rename from lib/screens/tag_bookmarks/model/tag_bookmarks.model.dart rename to lib/screens/filtered_bookmarks/model/filtered_bookmarks.model.dart index e51ca47..19618be 100644 --- a/lib/screens/tag_bookmarks/model/tag_bookmarks.model.dart +++ b/lib/screens/filtered_bookmarks/model/filtered_bookmarks.model.dart @@ -3,7 +3,8 @@ import 'package:linkdy/constants/enums.dart'; import 'package:linkdy/models/data/bookmarks.dart'; import 'package:linkdy/models/data/tags.dart'; -class TagBookmarksModel { +class FilteredBookmarksModel { + FilteredBookmarksMode filteredBookmarksMode; String? tagId; Tag? tag; int currentPage; @@ -13,7 +14,8 @@ class TagBookmarksModel { int maxNumber; bool loadingMore; - TagBookmarksModel({ + FilteredBookmarksModel({ + this.filteredBookmarksMode = FilteredBookmarksMode.shared, this.tagId, this.tag, this.currentPage = 0, diff --git a/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart b/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart new file mode 100644 index 0000000..d3acc89 --- /dev/null +++ b/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart @@ -0,0 +1,220 @@ +import 'package:linkdy/constants/global_keys.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; +import 'package:linkdy/screens/bookmarks/provider/common_functions.dart'; +import 'package:linkdy/screens/filtered_bookmarks/model/filtered_bookmarks.model.dart'; + +import 'package:linkdy/models/data/bookmarks.dart'; +import 'package:linkdy/constants/enums.dart'; +import 'package:linkdy/models/data/tags.dart'; +import 'package:linkdy/providers/api_client.provider.dart'; + +part 'filtered_bookmarks.provider.g.dart'; + +@riverpod +FutureOr tagBookmarksRequest(TagBookmarksRequestRef ref, Tag? tag, String? tagId, int limit) async { + final tagResult = tag == null ? await ref.read(apiClientProvider)!.fetchTagById(tagId!) : null; + if (tagResult != null && tagResult.successful == false) { + ref.read(filteredBookmarksProvider.notifier).setInitialLoadStatus(LoadStatus.error); + return; + } + + final bookmarksResult = await ref.read(apiClientProvider)!.fetchBookmarks( + q: tag != null ? tag.name : tagResult!.content!.name, + limit: limit, + offset: 0, + ); + + if (bookmarksResult.successful == true) { + ref.read(faviconStoreProvider.notifier).loadFavicons(bookmarksResult.content!.results!); + ref.read(filteredBookmarksProvider).bookmarks = bookmarksResult.content!.results!; + ref.read(filteredBookmarksProvider).maxNumber = bookmarksResult.content!.count!; + if (tag == null) ref.read(filteredBookmarksProvider).tag = tagResult!.content!; + ref.read(filteredBookmarksProvider).currentPage = 0; + ref.read(filteredBookmarksProvider).loadingMore = false; + ref.read(filteredBookmarksProvider).initialLoadStatus = LoadStatus.loaded; + } else { + ref.read(filteredBookmarksProvider).initialLoadStatus = LoadStatus.error; + } + + ref.read(filteredBookmarksProvider.notifier).notifyListeners(); +} + +@riverpod +FutureOr tagBookmarksRequestLoadMore(FilteredBookmarksRequestLoadMoreRef ref) async { + final provider = ref.read(filteredBookmarksProvider); + + final newOffset = provider.limit * (provider.currentPage + 1); + + final result = await ref.read(apiClientProvider)!.fetchBookmarks( + q: provider.tag!.name, + limit: provider.limit, + offset: newOffset, + ); + + if (result.successful == true) { + ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); + provider.bookmarks = [...provider.bookmarks, ...result.content!.results!]; + provider.maxNumber = result.content!.count!; + provider.currentPage = provider.currentPage + 1; + } + + ref.read(filteredBookmarksProvider.notifier).setLoadingMore(false); +} + +@riverpod +FutureOr filteredBookmarksRequest(FilteredBookmarksRequestRef ref, FilteredBookmarksMode mode, int limit) async { + final bookmarksResult = mode == FilteredBookmarksMode.shared + ? await ref.read(apiClientProvider)!.fetchSharedBookmarks( + limit: limit, + offset: 0, + ) + : await ref.read(apiClientProvider)!.fetchArchivedBookmarks( + limit: limit, + offset: 0, + ); + + if (bookmarksResult.successful == true) { + ref.read(faviconStoreProvider.notifier).loadFavicons(bookmarksResult.content!.results!); + ref.read(filteredBookmarksProvider).bookmarks = bookmarksResult.content!.results!; + ref.read(filteredBookmarksProvider).maxNumber = bookmarksResult.content!.count!; + ref.read(filteredBookmarksProvider).currentPage = 0; + ref.read(filteredBookmarksProvider).loadingMore = false; + ref.read(filteredBookmarksProvider).initialLoadStatus = LoadStatus.loaded; + } else { + ref.read(filteredBookmarksProvider).initialLoadStatus = LoadStatus.error; + } + + ref.read(filteredBookmarksProvider.notifier).notifyListeners(); +} + +@riverpod +FutureOr filteredBookmarksRequestLoadMore(TagBookmarksRequestLoadMoreRef ref) async { + final provider = ref.read(filteredBookmarksProvider); + + final newOffset = provider.limit * (provider.currentPage + 1); + + final result = ref.read(filteredBookmarksProvider).filteredBookmarksMode == FilteredBookmarksMode.shared + ? await ref.read(apiClientProvider)!.fetchSharedBookmarks( + q: provider.tag!.name, + limit: provider.limit, + offset: newOffset, + ) + : await ref.read(apiClientProvider)!.fetchArchivedBookmarks( + q: provider.tag!.name, + limit: provider.limit, + offset: newOffset, + ); + + if (result.successful == true) { + ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); + provider.bookmarks = [...provider.bookmarks, ...result.content!.results!]; + provider.maxNumber = result.content!.count!; + provider.currentPage = provider.currentPage + 1; + } + + ref.read(filteredBookmarksProvider.notifier).setLoadingMore(false); +} + +@riverpod +class FilteredBookmarks extends _$FilteredBookmarks { + @override + FilteredBookmarksModel build() { + return FilteredBookmarksModel( + bookmarks: [], + ); + } + + void setMode(FilteredBookmarksMode mode) { + state.filteredBookmarksMode = mode; + } + + void setCurrentPage(int page) { + state.currentPage = page; + } + + void setLimit(int limit) { + state.limit = limit; + } + + void setInitialLoadStatus(LoadStatus status) { + state.initialLoadStatus = status; + ref.notifyListeners(); + } + + void setLoadingMore(bool status) { + state.loadingMore = status; + ref.notifyListeners(); + } + + Future refresh() async { + if (state.filteredBookmarksMode == FilteredBookmarksMode.tag) { + await ref.read( + tagBookmarksRequestProvider(state.tag, state.tagId, state.limit).future, + ); + } else { + await ref.read( + filteredBookmarksRequestProvider(state.filteredBookmarksMode, state.limit).future, + ); + } + } + + void notifyListeners() { + ref.notifyListeners(); + } + + void deleteBookmark(Bookmark bookmark) async { + final result = await BookmarkCommonFunctions.deleteBookmark( + scaffoldMessengerKey: ScaffoldMessengerKeys.filteredBookmarks, + ref: ref, + bookmark: bookmark, + apiClient: ref.read(apiClientProvider)!, + ); + if (result == true) { + state.bookmarks = state.bookmarks.where((b) => b.id != bookmark.id).toList(); + ref.notifyListeners(); + } + } + + void markAsReadUnread(Bookmark bookmark) async { + final result = await BookmarkCommonFunctions.markAsReadUnread( + scaffoldMessengerKey: ScaffoldMessengerKeys.filteredBookmarks, + ref: ref, + bookmark: bookmark, + apiClient: ref.read(apiClientProvider)!, + ); + if (result != null) { + state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList(); + ref.notifyListeners(); + } + } + + void archiveUnarchive(Bookmark bookmark) async { + final result = await BookmarkCommonFunctions.archiveUnarchive( + scaffoldMessengerKey: ScaffoldMessengerKeys.filteredBookmarks, + ref: ref, + bookmark: bookmark, + apiClient: ref.read(apiClientProvider)!, + ); + if (result == true) { + state.bookmarks = state.bookmarks.where((b) => b.id != bookmark.id).toList(); + } + ref.notifyListeners(); + } + + void shareUnshare(Bookmark bookmark) async { + final result = await BookmarkCommonFunctions.shareUnshare( + scaffoldMessengerKey: ScaffoldMessengerKeys.filteredBookmarks, + ref: ref, + bookmark: bookmark, + apiClient: ref.read(apiClientProvider)!, + ); + if (result != null && state.filteredBookmarksMode == FilteredBookmarksMode.shared) { + state.bookmarks = state.bookmarks.where((b) => b.id != result.id).toList(); + } else if (result != null && state.filteredBookmarksMode != FilteredBookmarksMode.shared) { + state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList(); + } + ref.notifyListeners(); + } +} diff --git a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart b/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.g.dart similarity index 51% rename from lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart rename to lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.g.dart index 710f8dd..ee3df62 100644 --- a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.g.dart +++ b/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.g.dart @@ -1,13 +1,13 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'tag_bookmarks.provider.dart'; +part of 'filtered_bookmarks.provider.dart'; // ************************************************************************** // RiverpodGenerator // ************************************************************************** String _$tagBookmarksRequestHash() => - r'9a4d4582b680da41069054429315f85976378524'; + r'abcde0e4ef3aecf21708a24573ddd4279211e288'; /// Copied from Dart SDK class _SystemHash { @@ -190,7 +190,7 @@ class _TagBookmarksRequestProviderElement } String _$tagBookmarksRequestLoadMoreHash() => - r'ce7c52c446c2d4b8593fd06e818b3499bdc36a39'; + r'36205474b3c1d3f18f31af56cc97c700f328a4bc'; /// See also [tagBookmarksRequestLoadMore]. @ProviderFor(tagBookmarksRequestLoadMore) @@ -206,20 +206,187 @@ final tagBookmarksRequestLoadMoreProvider = ); typedef TagBookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef; -String _$tagBookmarksHash() => r'35a9ed7751c2d7e9644907f969fb03950b7b9a04'; +String _$filteredBookmarksRequestHash() => + r'f5352c5076d8bf2ed0cf738bdc0c0cffc9d18a25'; -/// See also [TagBookmarks]. -@ProviderFor(TagBookmarks) -final tagBookmarksProvider = - AutoDisposeNotifierProvider.internal( - TagBookmarks.new, - name: r'tagBookmarksProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$tagBookmarksHash, +/// See also [filteredBookmarksRequest]. +@ProviderFor(filteredBookmarksRequest) +const filteredBookmarksRequestProvider = FilteredBookmarksRequestFamily(); + +/// See also [filteredBookmarksRequest]. +class FilteredBookmarksRequestFamily extends Family> { + /// See also [filteredBookmarksRequest]. + const FilteredBookmarksRequestFamily(); + + /// See also [filteredBookmarksRequest]. + FilteredBookmarksRequestProvider call( + FilteredBookmarksMode mode, + int limit, + ) { + return FilteredBookmarksRequestProvider( + mode, + limit, + ); + } + + @override + FilteredBookmarksRequestProvider getProviderOverride( + covariant FilteredBookmarksRequestProvider provider, + ) { + return call( + provider.mode, + provider.limit, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'filteredBookmarksRequestProvider'; +} + +/// See also [filteredBookmarksRequest]. +class FilteredBookmarksRequestProvider extends AutoDisposeFutureProvider { + /// See also [filteredBookmarksRequest]. + FilteredBookmarksRequestProvider( + FilteredBookmarksMode mode, + int limit, + ) : this._internal( + (ref) => filteredBookmarksRequest( + ref as FilteredBookmarksRequestRef, + mode, + limit, + ), + from: filteredBookmarksRequestProvider, + name: r'filteredBookmarksRequestProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$filteredBookmarksRequestHash, + dependencies: FilteredBookmarksRequestFamily._dependencies, + allTransitiveDependencies: + FilteredBookmarksRequestFamily._allTransitiveDependencies, + mode: mode, + limit: limit, + ); + + FilteredBookmarksRequestProvider._internal( + super._createNotifier, { + required super.name, + required super.dependencies, + required super.allTransitiveDependencies, + required super.debugGetCreateSourceHash, + required super.from, + required this.mode, + required this.limit, + }) : super.internal(); + + final FilteredBookmarksMode mode; + final int limit; + + @override + Override overrideWith( + FutureOr Function(FilteredBookmarksRequestRef provider) create, + ) { + return ProviderOverride( + origin: this, + override: FilteredBookmarksRequestProvider._internal( + (ref) => create(ref as FilteredBookmarksRequestRef), + from: from, + name: null, + dependencies: null, + allTransitiveDependencies: null, + debugGetCreateSourceHash: null, + mode: mode, + limit: limit, + ), + ); + } + + @override + AutoDisposeFutureProviderElement createElement() { + return _FilteredBookmarksRequestProviderElement(this); + } + + @override + bool operator ==(Object other) { + return other is FilteredBookmarksRequestProvider && + other.mode == mode && + other.limit == limit; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, mode.hashCode); + hash = _SystemHash.combine(hash, limit.hashCode); + + return _SystemHash.finish(hash); + } +} + +mixin FilteredBookmarksRequestRef on AutoDisposeFutureProviderRef { + /// The parameter `mode` of this provider. + FilteredBookmarksMode get mode; + + /// The parameter `limit` of this provider. + int get limit; +} + +class _FilteredBookmarksRequestProviderElement + extends AutoDisposeFutureProviderElement + with FilteredBookmarksRequestRef { + _FilteredBookmarksRequestProviderElement(super.provider); + + @override + FilteredBookmarksMode get mode => + (origin as FilteredBookmarksRequestProvider).mode; + @override + int get limit => (origin as FilteredBookmarksRequestProvider).limit; +} + +String _$filteredBookmarksRequestLoadMoreHash() => + r'a40280a01fcfa3892c76287a5e67e5ab9cc00cd5'; + +/// See also [filteredBookmarksRequestLoadMore]. +@ProviderFor(filteredBookmarksRequestLoadMore) +final filteredBookmarksRequestLoadMoreProvider = + AutoDisposeFutureProvider.internal( + filteredBookmarksRequestLoadMore, + name: r'filteredBookmarksRequestLoadMoreProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$filteredBookmarksRequestLoadMoreHash, dependencies: null, allTransitiveDependencies: null, ); -typedef _$TagBookmarks = AutoDisposeNotifier; +typedef FilteredBookmarksRequestLoadMoreRef + = AutoDisposeFutureProviderRef; +String _$filteredBookmarksHash() => r'acb051c3b3e53c084c8c33d6ec1e80a1aa2a10f7'; + +/// See also [FilteredBookmarks]. +@ProviderFor(FilteredBookmarks) +final filteredBookmarksProvider = AutoDisposeNotifierProvider.internal( + FilteredBookmarks.new, + name: r'filteredBookmarksProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$filteredBookmarksHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef _$FilteredBookmarks = AutoDisposeNotifier; // 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/tag_bookmarks/ui/tag_bookmarks.dart b/lib/screens/filtered_bookmarks/ui/filtered_bookmarks.dart similarity index 59% rename from lib/screens/tag_bookmarks/ui/tag_bookmarks.dart rename to lib/screens/filtered_bookmarks/ui/filtered_bookmarks.dart index 93d4ba4..6475cf9 100644 --- a/lib/screens/tag_bookmarks/ui/tag_bookmarks.dart +++ b/lib/screens/filtered_bookmarks/ui/filtered_bookmarks.dart @@ -5,7 +5,7 @@ import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:linkdy/screens/bookmarks/ui/bookmark_form_modal.dart'; import 'package:linkdy/screens/bookmarks/ui/bookmark_item.dart'; import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart'; -import 'package:linkdy/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart'; +import 'package:linkdy/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart'; import 'package:linkdy/widgets/error_screen.dart'; import 'package:linkdy/widgets/no_data_screen.dart'; @@ -16,47 +16,58 @@ import 'package:linkdy/providers/router.provider.dart'; import 'package:linkdy/router/paths.dart'; import 'package:linkdy/i18n/strings.g.dart'; -class TagBookmarksScreen extends ConsumerStatefulWidget { +class FilteredBookmarksScreen extends ConsumerStatefulWidget { + final FilteredBookmarksMode filteredBookmarksMode; final String? tagId; final Tag? tag; - const TagBookmarksScreen({ + const FilteredBookmarksScreen({ super.key, - required this.tagId, + required this.filteredBookmarksMode, + this.tagId, this.tag, }); @override - TagBookmarksScreenState createState() => TagBookmarksScreenState(); + FilteredBookmarksScreenState createState() => FilteredBookmarksScreenState(); } -class TagBookmarksScreenState extends ConsumerState { +class FilteredBookmarksScreenState extends ConsumerState { @override void initState() { - if (widget.tag == null && widget.tagId == null) { - final router = ref.read(routerProvider); - while (router.canPop() == true) { - router.pop(); + ref.read(filteredBookmarksProvider.notifier).setMode(widget.filteredBookmarksMode); + if (widget.filteredBookmarksMode == FilteredBookmarksMode.tag) { + if (widget.tag == null && widget.tagId == null) { + final router = ref.read(routerProvider); + while (router.canPop() == true) { + router.pop(); + } + router.pushReplacement(RoutesPaths.bookmarks); + return; } - router.pushReplacement(RoutesPaths.bookmarks); - return; + if (widget.tag != null) { + ref.read(filteredBookmarksProvider).tag = widget.tag; + } + if (widget.tagId != null) { + ref.read(filteredBookmarksProvider).tagId = widget.tagId; + } + ref.read(tagBookmarksRequestProvider(widget.tag, widget.tagId, ref.read(filteredBookmarksProvider).limit)); + } else { + ref.read( + filteredBookmarksRequestProvider(widget.filteredBookmarksMode, ref.read(filteredBookmarksProvider).limit), + ); } - if (widget.tag != null) { - ref.read(tagBookmarksProvider).tag = widget.tag; - } - if (widget.tagId != null) { - ref.read(tagBookmarksProvider).tagId = widget.tagId; - } - ref.read(tagBookmarksRequestProvider(widget.tag, widget.tagId, ref.read(tagBookmarksProvider).limit)); super.initState(); } @override Widget build(BuildContext context) { - if (widget.tag == null && widget.tagId == null) return const Material(); + if (widget.filteredBookmarksMode == FilteredBookmarksMode.tag && widget.tag == null && widget.tagId == null) { + return const Material(); + } - final provider = ref.watch(tagBookmarksProvider); + final provider = ref.watch(filteredBookmarksProvider); final width = MediaQuery.of(context).size.width; @@ -64,14 +75,50 @@ class TagBookmarksScreenState extends ConsumerState { if (scrollNotification.metrics.extentAfter < 100 && provider.loadingMore == false && provider.bookmarks.length < provider.maxNumber) { - ref.read(tagBookmarksProvider.notifier).setLoadingMore(true); + ref.read(filteredBookmarksProvider.notifier).setLoadingMore(true); ref.read(tagBookmarksRequestLoadMoreProvider); } return false; } + String title() { + switch (widget.filteredBookmarksMode) { + case FilteredBookmarksMode.tag: + return widget.tag != null + ? "#${widget.tag!.name}" + : provider.tag != null + ? "#${provider.tag!.name}" + : ''; + + case FilteredBookmarksMode.archived: + return t.bookmarks.archived; + + case FilteredBookmarksMode.shared: + return t.bookmarks.shared; + + default: + return ""; + } + } + + String noContent() { + switch (widget.filteredBookmarksMode) { + case FilteredBookmarksMode.tag: + return t.tags.filteredBookmarks.noBookmarksWithThisTag; + + case FilteredBookmarksMode.archived: + return t.tags.filteredBookmarks.noArchivedBookmarks; + + case FilteredBookmarksMode.shared: + return t.tags.filteredBookmarks.noSharedBookmarks; + + default: + return ""; + } + } + return ScaffoldMessenger( - key: ScaffoldMessengerKeys.tagBookmarks, + key: ScaffoldMessengerKeys.filteredBookmarks, child: Scaffold( body: NestedScrollView( headerSliverBuilder: (context, innerBoxIsScrolled) => [ @@ -82,13 +129,7 @@ class TagBookmarksScreenState extends ConsumerState { floating: true, centerTitle: false, forceElevated: innerBoxIsScrolled, - title: Text( - widget.tag != null - ? "#${widget.tag!.name}" - : provider.tag != null - ? "#${provider.tag!.name}" - : '', - ), + title: Text(title()), ), ), ], @@ -97,7 +138,7 @@ class TagBookmarksScreenState extends ConsumerState { child: Builder( builder: (context) => RefreshIndicator( displacement: 120, - onRefresh: () => ref.read(tagBookmarksProvider.notifier).refresh(), + onRefresh: () => ref.read(filteredBookmarksProvider.notifier).refresh(), child: NotificationListener( onNotification: scrollListener, child: CustomScrollView( @@ -118,7 +159,7 @@ class TagBookmarksScreenState extends ConsumerState { if (provider.bookmarks.isEmpty) SliverFillRemaining( child: NoDataScreen( - message: t.tags.tagBookmarks.noBookmarksWithThisTag, + message: noContent(), ), ), if (provider.bookmarks.isNotEmpty) @@ -138,16 +179,16 @@ class TagBookmarksScreenState extends ConsumerState { } return BookmarkItem( bookmark: provider.bookmarks[index], - onReadUnread: ref.read(tagBookmarksProvider.notifier).markAsReadUnread, + onReadUnread: ref.read(filteredBookmarksProvider.notifier).markAsReadUnread, onDelete: (bookmark) => showDialog( context: context, builder: (context) => DeleteBookmarkModal( bookmark: bookmark, - onDelete: ref.read(tagBookmarksProvider.notifier).deleteBookmark, + onDelete: ref.read(filteredBookmarksProvider.notifier).deleteBookmark, ), ), - onArchiveUnarchive: ref.read(tagBookmarksProvider.notifier).archiveUnarchive, - onShareInternally: ref.read(tagBookmarksProvider.notifier).shareUnshare, + onArchiveUnarchive: ref.read(filteredBookmarksProvider.notifier).archiveUnarchive, + onShareInternally: ref.read(filteredBookmarksProvider.notifier).shareUnshare, onEdit: (b) => openBookmarkFormModal(context: context, width: width, bookmark: b), ); }, diff --git a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart b/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart deleted file mode 100644 index 75248eb..0000000 --- a/lib/screens/tag_bookmarks/provider/tag_bookmarks.provider.dart +++ /dev/null @@ -1,153 +0,0 @@ -import 'package:linkdy/constants/global_keys.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; -import 'package:linkdy/screens/bookmarks/provider/common_functions.dart'; -import 'package:linkdy/screens/tag_bookmarks/model/tag_bookmarks.model.dart'; - -import 'package:linkdy/models/data/bookmarks.dart'; -import 'package:linkdy/constants/enums.dart'; -import 'package:linkdy/models/data/tags.dart'; -import 'package:linkdy/providers/api_client.provider.dart'; - -part 'tag_bookmarks.provider.g.dart'; - -@riverpod -FutureOr tagBookmarksRequest(TagBookmarksRequestRef ref, Tag? tag, String? tagId, int limit) async { - final tagResult = tag == null ? await ref.read(apiClientProvider)!.fetchTagById(tagId!) : null; - if (tagResult != null && tagResult.successful == false) { - ref.read(tagBookmarksProvider.notifier).setInitialLoadStatus(LoadStatus.error); - return; - } - - final bookmarksResult = await ref.read(apiClientProvider)!.fetchBookmarks( - q: tag != null ? tag.name : tagResult!.content!.name, - limit: limit, - offset: 0, - ); - - if (bookmarksResult.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(bookmarksResult.content!.results!); - ref.read(tagBookmarksProvider).bookmarks = bookmarksResult.content!.results!; - ref.read(tagBookmarksProvider).maxNumber = bookmarksResult.content!.count!; - if (tag == null) ref.read(tagBookmarksProvider).tag = tagResult!.content!; - ref.read(tagBookmarksProvider).currentPage = 0; - ref.read(tagBookmarksProvider).loadingMore = false; - ref.read(tagBookmarksProvider).initialLoadStatus = LoadStatus.loaded; - } else { - ref.read(tagBookmarksProvider).initialLoadStatus = LoadStatus.error; - } - - ref.read(tagBookmarksProvider.notifier).notifyListeners(); -} - -@riverpod -FutureOr tagBookmarksRequestLoadMore(TagBookmarksRequestLoadMoreRef ref) async { - final provider = ref.read(tagBookmarksProvider); - - final newOffset = provider.limit * (provider.currentPage + 1); - - final result = await ref.read(apiClientProvider)!.fetchBookmarks( - q: provider.tag!.name, - limit: provider.limit, - offset: newOffset, - ); - - if (result.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); - provider.bookmarks = [...provider.bookmarks, ...result.content!.results!]; - provider.maxNumber = result.content!.count!; - provider.currentPage = provider.currentPage + 1; - } - - ref.read(tagBookmarksProvider.notifier).setLoadingMore(false); -} - -@riverpod -class TagBookmarks extends _$TagBookmarks { - @override - TagBookmarksModel build() { - return TagBookmarksModel( - bookmarks: [], - ); - } - - void setCurrentPage(int page) { - state.currentPage = page; - } - - void setLimit(int limit) { - state.limit = limit; - } - - void setInitialLoadStatus(LoadStatus status) { - state.initialLoadStatus = status; - ref.notifyListeners(); - } - - void setLoadingMore(bool status) { - state.loadingMore = status; - ref.notifyListeners(); - } - - Future refresh() async { - await ref.read(tagBookmarksRequestProvider(state.tag, state.tagId, state.limit).future); - } - - void notifyListeners() { - ref.notifyListeners(); - } - - void deleteBookmark(Bookmark bookmark) async { - final result = await BookmarkCommonFunctions.deleteBookmark( - scaffoldMessengerKey: ScaffoldMessengerKeys.tagBookmarks, - ref: ref, - bookmark: bookmark, - apiClient: ref.read(apiClientProvider)!, - ); - if (result == true) { - state.bookmarks = state.bookmarks.where((b) => b.id != bookmark.id).toList(); - ref.notifyListeners(); - } - } - - void markAsReadUnread(Bookmark bookmark) async { - final result = await BookmarkCommonFunctions.markAsReadUnread( - scaffoldMessengerKey: ScaffoldMessengerKeys.tagBookmarks, - ref: ref, - bookmark: bookmark, - apiClient: ref.read(apiClientProvider)!, - ); - if (result != null) { - state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList(); - ref.notifyListeners(); - } - } - - void archiveUnarchive(Bookmark bookmark) async { - final result = await BookmarkCommonFunctions.archiveUnarchive( - scaffoldMessengerKey: ScaffoldMessengerKeys.tagBookmarks, - ref: ref, - bookmark: bookmark, - apiClient: ref.read(apiClientProvider)!, - ); - if (result == true) { - // On this case the bookmark always will pass from unarchived to archived - state.bookmarks = state.bookmarks.where((b) => b.id != bookmark.id).toList(); - ref.notifyListeners(); - } - } - - void shareUnshare(Bookmark bookmark) async { - final result = await BookmarkCommonFunctions.shareUnshare( - scaffoldMessengerKey: ScaffoldMessengerKeys.tagBookmarks, - ref: ref, - bookmark: bookmark, - apiClient: ref.read(apiClientProvider)!, - ); - if (result != null) { - state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList(); - ref.notifyListeners(); - } - } -} diff --git a/lib/services/api_client.dart b/lib/services/api_client.dart index d39b570..188aa79 100644 --- a/lib/services/api_client.dart +++ b/lib/services/api_client.dart @@ -69,6 +69,50 @@ class ApiClientService { } } + Future> fetchArchivedBookmarks({String? q, int? limit, int? offset}) async { + try { + final response = await dioInstance.get( + "/bookmarks/archived/", + queryParameters: { + "q": q, + "limit": limit, + "offset": offset, + }, + ); + return ApiResponse( + successful: true, + content: BookmarksResponse.fromJson(response.data), + ); + } on DioException { + return const ApiResponse(successful: false); + } catch (e, stackTrace) { + Sentry.captureException(e, stackTrace: stackTrace); + return const ApiResponse(successful: false); + } + } + + Future> fetchSharedBookmarks({String? q, int? limit, int? offset}) async { + try { + final response = await dioInstance.get( + "/bookmarks/shared/", + queryParameters: { + "q": q, + "limit": limit, + "offset": offset, + }, + ); + return ApiResponse( + successful: true, + content: BookmarksResponse.fromJson(response.data), + ); + } on DioException { + return const ApiResponse(successful: false); + } catch (e, stackTrace) { + Sentry.captureException(e, stackTrace: stackTrace); + return const ApiResponse(successful: false); + } + } + Future> fetchCheckAddBookmark({required String url}) async { try { final response = await dioInstance.get( diff --git a/lib/widgets/no_data_screen.dart b/lib/widgets/no_data_screen.dart index ab1c371..f8c0cea 100644 --- a/lib/widgets/no_data_screen.dart +++ b/lib/widgets/no_data_screen.dart @@ -20,7 +20,7 @@ class NoDataScreen extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( - Icons.clear_rounded, + Icons.clear_all_rounded, size: 50, color: Theme.of(context).colorScheme.onSurfaceVariant, ),