Added bookmark options to search and tag bookmarks

This commit is contained in:
Juan Gilsanz Polo
2024-02-25 23:09:10 +01:00
parent 175963883f
commit eddbdc84ef
19 changed files with 360 additions and 107 deletions

View File

@@ -4,9 +4,9 @@
/// To regenerate, run: `dart run slang`
///
/// Locales: 2
/// Strings: 268 (134 per locale)
/// Strings: 280 (140 per locale)
///
/// Built on 2024-02-25 at 20:04 UTC
/// Built on 2024-02-25 at 20:58 UTC
// coverage:ignore-file
// ignore_for_file: type=lint
@@ -373,6 +373,12 @@ class _StringsBookmarksBookmarkOptionsEn {
String get markedAsUnreadSuccessfully => 'Bookmark marked as unread successfully.';
String get bookmarkNotMarkedAsRead => 'The bookmark couldn\'t be marked as read.';
String get bookmarkNotMarkedAsUnread => 'The bookmark couldn\'t be marked as unread.';
String get archivingBookmark => 'Archiving bookmark...';
String get unarchivingBookmark => 'Unarchiving bookmark...';
String get bookmarkArchivedSuccessfully => 'Bookmark archived successfully.';
String get bookmarkUnrchivedSuccessfully => 'Bookmark unarchived successfully.';
String get bookmarkNotArchived => 'The bookmark couldn\'t be archived.';
String get bookmarkNotUnrchived => 'The bookmark couldn\'t be unarchived.';
}
// Path: tags.createTag
@@ -689,10 +695,16 @@ class _StringsBookmarksBookmarkOptionsEs implements _StringsBookmarksBookmarkOpt
@override String get followingBookmarkDeleted => 'El siguiente marcador será eliminado:';
@override String get markingAsRead => 'Marcando como leído...';
@override String get markingAsUnead => 'Marcando como no leído...';
@override String get markedAsReadSuccessfully => 'Marcador marcado como leído correctamente..';
@override String get markedAsReadSuccessfully => 'Marcador marcado como leído correctamente.';
@override String get markedAsUnreadSuccessfully => 'Marcador marcado como no leído correctamente.';
@override String get bookmarkNotMarkedAsRead => 'El marcador no se ha podido marcar como leído.';
@override String get bookmarkNotMarkedAsUnread => 'El marcador no se ha podido marcar como no leído.';
@override String get archivingBookmark => 'Archivando marcador...';
@override String get unarchivingBookmark => 'Desarchivando marcador...';
@override String get bookmarkArchivedSuccessfully => 'Marcador archivado correctamente.';
@override String get bookmarkUnrchivedSuccessfully => 'Marcador desarchivado correctamente.';
@override String get bookmarkNotArchived => 'El marcador no pudo ser archivado.';
@override String get bookmarkNotUnrchived => 'El marcador no pudo ser desarchivado.';
}
// Path: tags.createTag
@@ -854,6 +866,12 @@ extension on Translations {
case 'bookmarks.bookmarkOptions.markedAsUnreadSuccessfully': return 'Bookmark marked as unread successfully.';
case 'bookmarks.bookmarkOptions.bookmarkNotMarkedAsRead': return 'The bookmark couldn\'t be marked as read.';
case 'bookmarks.bookmarkOptions.bookmarkNotMarkedAsUnread': return 'The bookmark couldn\'t be marked as unread.';
case 'bookmarks.bookmarkOptions.archivingBookmark': return 'Archiving bookmark...';
case 'bookmarks.bookmarkOptions.unarchivingBookmark': return 'Unarchiving bookmark...';
case 'bookmarks.bookmarkOptions.bookmarkArchivedSuccessfully': return 'Bookmark archived successfully.';
case 'bookmarks.bookmarkOptions.bookmarkUnrchivedSuccessfully': return 'Bookmark unarchived successfully.';
case 'bookmarks.bookmarkOptions.bookmarkNotArchived': return 'The bookmark couldn\'t be archived.';
case 'bookmarks.bookmarkOptions.bookmarkNotUnrchived': return 'The bookmark couldn\'t be unarchived.';
case 'tags.tags': return 'Tags';
case 'tags.created': return ({required Object created}) => 'Created: ${created}';
case 'tags.createTag.createTag': return 'Create tag';
@@ -992,10 +1010,16 @@ extension on _StringsEs {
case 'bookmarks.bookmarkOptions.followingBookmarkDeleted': return 'El siguiente marcador será eliminado:';
case 'bookmarks.bookmarkOptions.markingAsRead': return 'Marcando como leído...';
case 'bookmarks.bookmarkOptions.markingAsUnead': return 'Marcando como no leído...';
case 'bookmarks.bookmarkOptions.markedAsReadSuccessfully': return 'Marcador marcado como leído correctamente..';
case 'bookmarks.bookmarkOptions.markedAsReadSuccessfully': return 'Marcador marcado como leído correctamente.';
case 'bookmarks.bookmarkOptions.markedAsUnreadSuccessfully': return 'Marcador marcado como no leído correctamente.';
case 'bookmarks.bookmarkOptions.bookmarkNotMarkedAsRead': return 'El marcador no se ha podido marcar como leído.';
case 'bookmarks.bookmarkOptions.bookmarkNotMarkedAsUnread': return 'El marcador no se ha podido marcar como no leído.';
case 'bookmarks.bookmarkOptions.archivingBookmark': return 'Archivando marcador...';
case 'bookmarks.bookmarkOptions.unarchivingBookmark': return 'Desarchivando marcador...';
case 'bookmarks.bookmarkOptions.bookmarkArchivedSuccessfully': return 'Marcador archivado correctamente.';
case 'bookmarks.bookmarkOptions.bookmarkUnrchivedSuccessfully': return 'Marcador desarchivado correctamente.';
case 'bookmarks.bookmarkOptions.bookmarkNotArchived': return 'El marcador no pudo ser archivado.';
case 'bookmarks.bookmarkOptions.bookmarkNotUnrchived': return 'El marcador no pudo ser desarchivado.';
case 'tags.tags': return 'Etiquetas';
case 'tags.created': return ({required Object created}) => 'Creado: ${created}';
case 'tags.createTag.createTag': return 'Crear etiqueta';

View File

@@ -94,7 +94,13 @@
"markedAsReadSuccessfully": "Bookmark marked as read successfully.",
"markedAsUnreadSuccessfully": "Bookmark marked as unread successfully.",
"bookmarkNotMarkedAsRead": "The bookmark couldn't be marked as read.",
"bookmarkNotMarkedAsUnread": "The bookmark couldn't be marked as unread."
"bookmarkNotMarkedAsUnread": "The bookmark couldn't be marked as unread.",
"archivingBookmark": "Archiving bookmark...",
"unarchivingBookmark": "Unarchiving bookmark...",
"bookmarkArchivedSuccessfully": "Bookmark archived successfully.",
"bookmarkUnrchivedSuccessfully": "Bookmark unarchived successfully.",
"bookmarkNotArchived": "The bookmark couldn't be archived.",
"bookmarkNotUnrchived": "The bookmark couldn't be unarchived."
}
},
"tags": {

View File

@@ -91,10 +91,16 @@
"followingBookmarkDeleted": "El siguiente marcador será eliminado:",
"markingAsRead": "Marcando como leído...",
"markingAsUnead": "Marcando como no leído...",
"markedAsReadSuccessfully": "Marcador marcado como leído correctamente..",
"markedAsReadSuccessfully": "Marcador marcado como leído correctamente.",
"markedAsUnreadSuccessfully": "Marcador marcado como no leído correctamente.",
"bookmarkNotMarkedAsRead": "El marcador no se ha podido marcar como leído.",
"bookmarkNotMarkedAsUnread": "El marcador no se ha podido marcar como no leído."
"bookmarkNotMarkedAsUnread": "El marcador no se ha podido marcar como no leído.",
"archivingBookmark": "Archivando marcador...",
"unarchivingBookmark": "Desarchivando marcador...",
"bookmarkArchivedSuccessfully": "Marcador archivado correctamente.",
"bookmarkUnrchivedSuccessfully": "Marcador desarchivado correctamente.",
"bookmarkNotArchived": "El marcador no pudo ser archivado.",
"bookmarkNotUnrchived": "El marcador no pudo ser desarchivado."
}
},
"tags": {

View File

@@ -6,6 +6,6 @@ class FaviconLoaderModel {
FaviconLoaderModel({
required this.favicons,
this.loadingFavicons = true,
this.loadingFavicons = false,
});
}

View File

@@ -175,7 +175,7 @@ final getTagsProvider =
);
typedef GetTagsRef = AutoDisposeFutureProviderRef<ApiResponse<TagsResponse>>;
String _$addBookmarkHash() => r'ace81358d08fd833b2aa06edddcb10f00728c30c';
String _$addBookmarkHash() => r'510fe4dbdc6628a13be9d8c5c2581fd5ac94ca68';
/// See also [AddBookmark].
@ProviderFor(AddBookmark)

View File

@@ -1,13 +1,9 @@
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:linkdy/screens/bookmarks/provider/common_functions.dart';
import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart';
import 'package:linkdy/screens/bookmarks/model/bookmarks.model.dart';
import 'package:linkdy/models/data/set_bookmark_data.dart';
import 'package:linkdy/utils/process_modal.dart';
import 'package:linkdy/utils/snackbar.dart';
import 'package:linkdy/i18n/strings.g.dart';
import 'package:linkdy/models/data/bookmarks.dart';
import 'package:linkdy/providers/api_client.provider.dart';
import 'package:linkdy/constants/enums.dart';
@@ -83,62 +79,45 @@ class Bookmarks extends _$Bookmarks {
ref.notifyListeners();
}
void setBookmarks(List<Bookmark> bookmarks) {
state.bookmarks = bookmarks;
ref.notifyListeners();
}
Future<void> refresh() async {
await ref.read(bookmarksRequestProvider(state.limit).future);
}
void deleteBookmark(Bookmark bookmark) async {
final processModal = ProcessModal();
processModal.open(t.bookmarks.bookmarkOptions.deletingBookmark);
final result = await ref.read(apiClientProvider)!.postDeleteBookmark(bookmark.id!);
processModal.close();
if (result.successful == true) {
final result = await BookmarkCommonFunctions.deleteBookmark(
bookmark: bookmark,
apiClient: ref.read(apiClientProvider)!,
);
if (result == true) {
state.bookmarks = state.bookmarks.where((b) => b.id != bookmark.id).toList();
ref.notifyListeners();
showSnacbkar(label: t.bookmarks.bookmarkOptions.bookmarkDeleted, color: Colors.green);
} else {
showSnacbkar(label: t.bookmarks.bookmarkOptions.bookmarkNotDeleted, color: Colors.red);
}
}
void markAsReadUnread(Bookmark bookmark) async {
final processModal = ProcessModal();
processModal.open(
bookmark.unread == true ? t.bookmarks.bookmarkOptions.markingAsRead : t.bookmarks.bookmarkOptions.markingAsUnead,
final result = await BookmarkCommonFunctions.markAsReadUnread(
bookmark: bookmark,
apiClient: ref.read(apiClientProvider)!,
);
final result = await ref.read(apiClientProvider)!.putUpdateBookmark(
bookmark.id!,
SetBookmarkData(
url: bookmark.url!,
description: bookmark.description ?? '',
isArchived: bookmark.isArchived ?? false,
shared: bookmark.shared ?? false,
unread: bookmark.unread == true ? false : true,
tagNames: bookmark.tagNames?.join(",") ?? '',
title: bookmark.title ?? '',
),
);
processModal.close();
if (result.successful == true) {
state.bookmarks = state.bookmarks.map((b) => b.id == result.content!.id ? result.content! : b).toList();
if (result != null) {
state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList();
ref.notifyListeners();
showSnacbkar(
label: bookmark.unread == true
? t.bookmarks.bookmarkOptions.markedAsReadSuccessfully
: t.bookmarks.bookmarkOptions.markedAsUnreadSuccessfully,
color: Colors.green,
);
} else {
showSnacbkar(
label: bookmark.unread == true
? t.bookmarks.bookmarkOptions.bookmarkNotMarkedAsRead
: t.bookmarks.bookmarkOptions.bookmarkNotMarkedAsUnread,
color: Colors.red,
}
}
void archiveUnarchive(Bookmark bookmark) async {
final result = await BookmarkCommonFunctions.markAsReadUnread(
bookmark: bookmark,
apiClient: ref.read(apiClientProvider)!,
);
if (result != null) {
state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList();
ref.notifyListeners();
}
}
}

View File

@@ -172,7 +172,7 @@ final bookmarksRequestLoadMoreProvider =
);
typedef BookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef<void>;
String _$bookmarksHash() => r'63863329236a127fce0f7b75e2461a841c0cae55';
String _$bookmarksHash() => r'82c31fa1cbab1ba1e5c77486e7dc7ce5a86e20a5';
/// See also [Bookmarks].
@ProviderFor(Bookmarks)

View File

@@ -0,0 +1,114 @@
import 'package:flutter/material.dart';
import 'package:linkdy/i18n/strings.g.dart';
import 'package:linkdy/models/data/bookmarks.dart';
import 'package:linkdy/models/data/set_bookmark_data.dart';
import 'package:linkdy/services/api_client.dart';
import 'package:linkdy/utils/process_modal.dart';
import 'package:linkdy/utils/snackbar.dart';
class BookmarkCommonFunctions {
static Future<bool> deleteBookmark({
required Bookmark bookmark,
required ApiClientService apiClient,
}) async {
final processModal = ProcessModal();
processModal.open(t.bookmarks.bookmarkOptions.deletingBookmark);
final result = await apiClient.postDeleteBookmark(bookmark.id!);
processModal.close();
if (result.successful == true) {
showSnacbkar(label: t.bookmarks.bookmarkOptions.bookmarkDeleted, color: Colors.green);
} else {
showSnacbkar(label: t.bookmarks.bookmarkOptions.bookmarkNotDeleted, color: Colors.red);
}
return result.successful;
}
static Future<Bookmark?> markAsReadUnread({
required Bookmark bookmark,
required ApiClientService apiClient,
}) async {
final processModal = ProcessModal();
processModal.open(
bookmark.unread == true ? t.bookmarks.bookmarkOptions.markingAsRead : t.bookmarks.bookmarkOptions.markingAsUnead,
);
final result = await apiClient.putUpdateBookmark(
bookmark.id!,
SetBookmarkData(
url: bookmark.url!,
description: bookmark.description ?? '',
isArchived: bookmark.isArchived ?? false,
shared: bookmark.shared ?? false,
unread: bookmark.unread == true ? false : true,
tagNames: bookmark.tagNames?.join(",") ?? '',
title: bookmark.title ?? '',
),
);
processModal.close();
if (result.successful == true) {
showSnacbkar(
label: bookmark.unread == true
? t.bookmarks.bookmarkOptions.markedAsReadSuccessfully
: t.bookmarks.bookmarkOptions.markedAsUnreadSuccessfully,
color: Colors.green,
);
return result.content;
} else {
showSnacbkar(
label: bookmark.unread == true
? t.bookmarks.bookmarkOptions.bookmarkNotMarkedAsRead
: t.bookmarks.bookmarkOptions.bookmarkNotMarkedAsUnread,
color: Colors.red,
);
return null;
}
}
static Future<Bookmark?> archiveUnarchive({
required Bookmark bookmark,
required ApiClientService apiClient,
}) async {
final processModal = ProcessModal();
processModal.open(
bookmark.unread == true
? t.bookmarks.bookmarkOptions.archivingBookmark
: t.bookmarks.bookmarkOptions.unarchivingBookmark,
);
final result = await apiClient.putUpdateBookmark(
bookmark.id!,
SetBookmarkData(
url: bookmark.url!,
description: bookmark.description ?? '',
unread: bookmark.unread ?? false,
shared: bookmark.shared ?? false,
isArchived: bookmark.isArchived == true ? false : true,
tagNames: bookmark.tagNames?.join(",") ?? '',
title: bookmark.title ?? '',
),
);
processModal.close();
if (result.successful == true) {
showSnacbkar(
label: bookmark.isArchived == true
? t.bookmarks.bookmarkOptions.bookmarkUnrchivedSuccessfully
: t.bookmarks.bookmarkOptions.bookmarkArchivedSuccessfully,
color: Colors.green,
);
return result.content;
} else {
showSnacbkar(
label: bookmark.isArchived == true
? t.bookmarks.bookmarkOptions.bookmarkNotUnrchived
: t.bookmarks.bookmarkOptions.bookmarkNotArchived,
color: Colors.red,
);
return null;
}
}
}

View File

@@ -49,6 +49,8 @@ class FaviconStore extends _$FaviconStore {
}
void loadFavicons(List<Bookmark> bookmarks) async {
if (state.loadingFavicons == true) return;
state.loadingFavicons = true;
ref.notifyListeners();

View File

@@ -6,7 +6,7 @@ part of 'favicon_loader.provider.dart';
// RiverpodGenerator
// **************************************************************************
String _$faviconStoreHash() => r'87cd0d0c0df889ca3238b6c05389b8dd351d189c';
String _$faviconStoreHash() => r'aeda388d2c7d220a43a29825a9850d8d7433d84f';
/// See also [FaviconStore].
@ProviderFor(FaviconStore)

View File

@@ -1,9 +1,13 @@
import 'package:flutter/material.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart';
import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart';
import 'package:linkdy/screens/bookmarks/provider/common_functions.dart';
import 'package:linkdy/screens/bookmarks/model/search_bookmarks.model.dart';
import 'package:linkdy/constants/enums.dart';
import 'package:linkdy/models/data/bookmarks.dart';
import 'package:linkdy/providers/api_client.provider.dart';
part 'search_bookmarks.provider.g.dart';
@@ -19,6 +23,7 @@ FutureOr<void> fetchSearchBookmarks(FetchSearchBookmarksRef ref, int limit) asyn
);
if (result.successful == true) {
ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!);
ref.read(searchBookmarksProvider).bookmarks = result.content!.results!;
ref.read(searchBookmarksProvider).maxNumber = result.content!.count!;
ref.read(searchBookmarksProvider).currentPage = 0;
@@ -41,9 +46,9 @@ FutureOr<void> fetchSearchBookmarksLoadMore(FetchSearchBookmarksLoadMoreRef ref)
limit: provider.limit,
offset: newOffset,
);
await Future.delayed(Duration(seconds: 3));
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;
@@ -92,4 +97,46 @@ class SearchBookmarks extends _$SearchBookmarks {
void notifyListeners() {
ref.notifyListeners();
}
void deleteBookmark(Bookmark bookmark) async {
final result = await BookmarkCommonFunctions.deleteBookmark(
bookmark: bookmark,
apiClient: ref.read(apiClientProvider)!,
);
if (result == true) {
state.bookmarks = state.bookmarks.where((b) => b.id != bookmark.id).toList();
ref.notifyListeners();
ref
.read(bookmarksProvider.notifier)
.setBookmarks(ref.read(bookmarksProvider).bookmarks.where((b) => b.id != bookmark.id).toList());
}
}
void markAsReadUnread(Bookmark bookmark) async {
final result = await BookmarkCommonFunctions.markAsReadUnread(
bookmark: bookmark,
apiClient: ref.read(apiClientProvider)!,
);
if (result != null) {
state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList();
ref.notifyListeners();
ref
.read(bookmarksProvider.notifier)
.setBookmarks(ref.read(bookmarksProvider).bookmarks.map((b) => b.id == result.id ? result : b).toList());
}
}
void archiveUnarchive(Bookmark bookmark) async {
final result = await BookmarkCommonFunctions.markAsReadUnread(
bookmark: bookmark,
apiClient: ref.read(apiClientProvider)!,
);
if (result != null) {
state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList();
ref.notifyListeners();
ref
.read(bookmarksProvider.notifier)
.setBookmarks(ref.read(bookmarksProvider).bookmarks.map((b) => b.id == result.id ? result : b).toList());
}
}
}

View File

@@ -7,7 +7,7 @@ part of 'search_bookmarks.provider.dart';
// **************************************************************************
String _$fetchSearchBookmarksHash() =>
r'dea1740df4ad970bc1ffd90d85aa0d1d2cf94bf2';
r'a854d28b2c2b6761cfd716bcbe081b54fbbf29ef';
/// Copied from Dart SDK
class _SystemHash {
@@ -158,7 +158,7 @@ class _FetchSearchBookmarksProviderElement
}
String _$fetchSearchBookmarksLoadMoreHash() =>
r'4c085e4dc487554a209fa73170294b5b8e279c24';
r'f07a6a89f5a87a0f26d3a8d2d49f1d98ce36a287';
/// See also [fetchSearchBookmarksLoadMore].
@ProviderFor(fetchSearchBookmarksLoadMore)
@@ -174,7 +174,7 @@ final fetchSearchBookmarksLoadMoreProvider =
);
typedef FetchSearchBookmarksLoadMoreRef = AutoDisposeFutureProviderRef<void>;
String _$searchBookmarksHash() => r'db9f8d8cc488e820791e22c594ad9046da73ec25';
String _$searchBookmarksHash() => r'843fe597bceab3e3f512b5b4a40ddd1dbeb09f9d';
/// See also [SearchBookmarks].
@ProviderFor(SearchBookmarks)

View File

@@ -1,11 +1,10 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:share_plus/share_plus.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart';
import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart';
import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart';
import 'package:linkdy/i18n/strings.g.dart';
@@ -18,10 +17,14 @@ import 'package:linkdy/utils/open_url.dart';
class BookmarkItem extends ConsumerWidget {
final Bookmark bookmark;
final void Function(Bookmark bookmark) onDelete;
final void Function(Bookmark bookmark) onReadUnread;
const BookmarkItem({
Key? key,
required this.bookmark,
required this.onDelete,
required this.onReadUnread,
}) : super(key: key);
@override
@@ -36,34 +39,27 @@ class BookmarkItem extends ConsumerWidget {
}
}
void openDeleteBookmarkModal(BuildContext ctx) {
showDialog(
context: context,
builder: (context) => DeleteBookmarkModal(bookmark: bookmark),
);
}
return Slidable(
startActionPane: ActionPane(
motion: const DrawerMotion(),
extentRatio: 0.75,
extentRatio: 0.5,
children: [
SlidableAction(
onPressed: (ctx) => ref.read(bookmarksProvider.notifier).markAsReadUnread(bookmark),
onPressed: (_) => onReadUnread(bookmark),
backgroundColor: Colors.blue,
label: bookmark.unread == true ? t.bookmarks.bookmarkOptions.read : t.bookmarks.bookmarkOptions.unread,
icon: bookmark.unread == true ? Icons.mark_email_read_rounded : Icons.mark_as_unread_rounded,
padding: const EdgeInsets.all(4),
),
// SlidableAction(
// onPressed: (ctx) => {},
// backgroundColor: Colors.grey,
// label: t.bookmarks.bookmarkOptions.archive,
// icon: Icons.archive_rounded,
// padding: const EdgeInsets.all(4),
// ),
SlidableAction(
onPressed: (ctx) => {},
backgroundColor: Colors.grey,
label: t.bookmarks.bookmarkOptions.archive,
icon: Icons.archive_rounded,
padding: const EdgeInsets.all(4),
),
SlidableAction(
onPressed: (ctx) => {},
onPressed: (ctx) => Share.shareUri(Uri.parse(bookmark.url!)),
backgroundColor: Colors.orange,
label: t.bookmarks.bookmarkOptions.share,
icon: Icons.share_rounded,
@@ -83,7 +79,7 @@ class BookmarkItem extends ConsumerWidget {
padding: const EdgeInsets.all(4),
),
SlidableAction(
onPressed: openDeleteBookmarkModal,
onPressed: (_) => onDelete(bookmark),
backgroundColor: Colors.red,
label: t.bookmarks.bookmarkOptions.delete,
icon: Icons.delete_rounded,
@@ -228,7 +224,15 @@ class BookmarkItem extends ConsumerWidget {
borderRadius: BorderRadius.circular(10),
color: Theme.of(context).colorScheme.primaryContainer,
),
child: Text(
child: Row(
children: [
Icon(
Icons.mark_as_unread_rounded,
size: 12,
color: Theme.of(context).colorScheme.onPrimaryContainer,
),
const SizedBox(width: 4),
Text(
t.bookmarks.bookmarkOptions.unread,
style: TextStyle(
fontSize: 10,
@@ -236,6 +240,8 @@ class BookmarkItem extends ConsumerWidget {
fontWeight: FontWeight.w700,
),
),
],
),
),
],
if (bookmark.dateModified != null) ...[

View File

@@ -7,11 +7,13 @@ import 'package:linkdy/constants/enums.dart';
import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart';
import 'package:linkdy/screens/bookmarks/ui/bookmark_item.dart';
import 'package:linkdy/screens/bookmarks/ui/add_bookmark_modal.dart';
import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart';
import 'package:linkdy/widgets/error_screen.dart';
import 'package:linkdy/widgets/no_data_screen.dart';
import 'package:linkdy/i18n/strings.g.dart';
import 'package:linkdy/providers/router.provider.dart';
import 'package:linkdy/models/data/bookmarks.dart';
import 'package:linkdy/router/paths.dart';
class BookmarksScreen extends ConsumerWidget {
@@ -39,6 +41,8 @@ class BookmarksScreen extends ConsumerWidget {
);
}
void openDeleteBookmarkModal(Bookmark bookmark) {}
bool scrollListener(ScrollUpdateNotification scrollNotification) {
if (scrollNotification.metrics.extentAfter < 100 &&
bookmarks.loadingMore == false &&
@@ -118,7 +122,17 @@ class BookmarksScreen extends ConsumerWidget {
// Bottom gap for FAB
return const SizedBox(height: 80);
}
return BookmarkItem(bookmark: bookmarks.bookmarks[index]);
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,
),
),
);
},
),
],

View File

@@ -1,21 +1,20 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart';
import 'package:linkdy/i18n/strings.g.dart';
import 'package:linkdy/models/data/bookmarks.dart';
class DeleteBookmarkModal extends ConsumerWidget {
class DeleteBookmarkModal extends StatelessWidget {
final Bookmark bookmark;
final void Function(Bookmark) onDelete;
const DeleteBookmarkModal({
Key? key,
required this.bookmark,
required this.onDelete,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
Widget build(BuildContext context) {
return AlertDialog(
title: Column(
children: [
@@ -57,7 +56,7 @@ class DeleteBookmarkModal extends ConsumerWidget {
TextButton(
onPressed: () {
Navigator.pop(context);
ref.read(bookmarksProvider.notifier).deleteBookmark(bookmark);
onDelete(bookmark);
},
child: Text(t.generic.confirm),
),

View File

@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:linkdy/screens/bookmarks/provider/search_bookmarks.provider.dart';
import 'package:linkdy/screens/bookmarks/ui/bookmark_item.dart';
import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart';
import 'package:linkdy/widgets/enter_search_term_screen.dart';
import 'package:linkdy/widgets/error_screen.dart';
@@ -113,6 +114,14 @@ class SearchBookmarksScreen extends ConsumerWidget {
}
return BookmarkItem(
bookmark: provider.bookmarks[index],
onReadUnread: ref.read(searchBookmarksProvider.notifier).markAsReadUnread,
onDelete: (bookmark) => showDialog(
context: context,
builder: (context) => DeleteBookmarkModal(
bookmark: bookmark,
onDelete: ref.read(searchBookmarksProvider.notifier).deleteBookmark,
),
),
);
},
),

View File

@@ -1,7 +1,10 @@
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';
@@ -10,19 +13,20 @@ part 'tag_bookmarks.provider.g.dart';
@riverpod
FutureOr<void> tagBookmarksRequest(TagBookmarksRequestRef ref, Tag? tag, String? tagId, int limit) async {
final tagResult = tag == null ? await ref.watch(apiClientProvider)!.fetchTagById(tagId!) : null;
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.watch(apiClientProvider)!.fetchBookmarks(
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!;
@@ -38,17 +42,18 @@ FutureOr<void> tagBookmarksRequest(TagBookmarksRequestRef ref, Tag? tag, String?
@riverpod
FutureOr<void> tagBookmarksRequestLoadMore(TagBookmarksRequestLoadMoreRef ref) async {
final provider = ref.watch(tagBookmarksProvider);
final provider = ref.read(tagBookmarksProvider);
final newOffset = provider.limit * (provider.currentPage + 1);
final result = await ref.watch(apiClientProvider)!.fetchBookmarks(
final result = await ref.read(apiClientProvider)!.fetchBookmarks(
q: provider.tag!.name,
limit: provider.limit,
offset: newOffset,
);
await Future.delayed(Duration(seconds: 4));
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;
@@ -91,4 +96,37 @@ class TagBookmarks extends _$TagBookmarks {
void notifyListeners() {
ref.notifyListeners();
}
void deleteBookmark(Bookmark bookmark) async {
final result = await BookmarkCommonFunctions.deleteBookmark(
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(
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.markAsReadUnread(
bookmark: bookmark,
apiClient: ref.read(apiClientProvider)!,
);
if (result != null) {
state.bookmarks = state.bookmarks.map((b) => b.id == result.id ? result : b).toList();
ref.notifyListeners();
}
}
}

View File

@@ -7,7 +7,7 @@ part of 'tag_bookmarks.provider.dart';
// **************************************************************************
String _$tagBookmarksRequestHash() =>
r'92613aa119dadb65b7b399b9c779197673689908';
r'9a4d4582b680da41069054429315f85976378524';
/// Copied from Dart SDK
class _SystemHash {
@@ -190,7 +190,7 @@ class _TagBookmarksRequestProviderElement
}
String _$tagBookmarksRequestLoadMoreHash() =>
r'3235c66b13a41c52611b86c2b26ecf9376ca1524';
r'ce7c52c446c2d4b8593fd06e818b3499bdc36a39';
/// See also [tagBookmarksRequestLoadMore].
@ProviderFor(tagBookmarksRequestLoadMore)
@@ -206,7 +206,7 @@ final tagBookmarksRequestLoadMoreProvider =
);
typedef TagBookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef<void>;
String _$tagBookmarksHash() => r'74e6463830052de2f05c628455d5ccca9faef765';
String _$tagBookmarksHash() => r'452c0ac002a2c1a5b841d4233fc177a8281f9ea1';
/// See also [TagBookmarks].
@ProviderFor(TagBookmarks)

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.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/widgets/error_screen.dart';
import 'package:linkdy/widgets/no_data_screen.dart';
@@ -30,7 +31,7 @@ class TagBookmarksScreenState extends ConsumerState<TagBookmarksScreen> {
@override
void initState() {
if (widget.tag == null && widget.tagId == null) {
final router = ref.watch(routerProvider);
final router = ref.read(routerProvider);
while (router.canPop() == true) {
router.pop();
}
@@ -59,7 +60,7 @@ class TagBookmarksScreenState extends ConsumerState<TagBookmarksScreen> {
provider.loadingMore == false &&
provider.bookmarks.length < provider.maxNumber) {
ref.read(tagBookmarksProvider.notifier).setLoadingMore(true);
ref.watch(tagBookmarksRequestLoadMoreProvider);
ref.read(tagBookmarksRequestLoadMoreProvider);
}
return false;
}
@@ -128,6 +129,14 @@ class TagBookmarksScreenState extends ConsumerState<TagBookmarksScreen> {
}
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,
),
),
);
},
),