Adapted bookmarks list to tablet mode
This commit is contained in:
@@ -10,6 +10,7 @@ class BookmarksModel {
|
||||
bool loadingMore;
|
||||
int maxNumber;
|
||||
ReadStatus readStatus;
|
||||
Bookmark? selectedBookmark;
|
||||
|
||||
BookmarksModel({
|
||||
this.currentPage = 0,
|
||||
@@ -19,5 +20,6 @@ class BookmarksModel {
|
||||
this.loadingMore = false,
|
||||
this.maxNumber = 0,
|
||||
this.readStatus = ReadStatus.all,
|
||||
this.selectedBookmark,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class SearchBookmarksModel {
|
||||
LoadStatus inialLoadStatus;
|
||||
bool loadingMore;
|
||||
int maxNumber;
|
||||
Bookmark? selectedBookmark;
|
||||
|
||||
SearchBookmarksModel({
|
||||
required this.searchController,
|
||||
@@ -23,5 +24,6 @@ class SearchBookmarksModel {
|
||||
this.inialLoadStatus = LoadStatus.loaded,
|
||||
this.loadingMore = false,
|
||||
this.maxNumber = 0,
|
||||
this.selectedBookmark,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import 'package:linkdy/constants/global_keys.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/config/sizes.dart';
|
||||
import 'package:linkdy/constants/global_keys.dart';
|
||||
import 'package:linkdy/providers/app_status.provider.dart';
|
||||
import 'package:linkdy/providers/router.provider.dart';
|
||||
import 'package:linkdy/router/paths.dart';
|
||||
import 'package:linkdy/utils/open_url.dart';
|
||||
import 'package:linkdy/models/data/bookmarks.dart';
|
||||
import 'package:linkdy/providers/api_client.provider.dart';
|
||||
import 'package:linkdy/constants/enums.dart';
|
||||
@@ -93,6 +98,16 @@ class Bookmarks extends _$Bookmarks {
|
||||
ref.notifyListeners();
|
||||
}
|
||||
|
||||
void selectBookmark(Bookmark bookmark, double width) {
|
||||
if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == true) {
|
||||
ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark);
|
||||
} else if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == true) {
|
||||
openUrl(bookmark.url!);
|
||||
}
|
||||
state.selectedBookmark = bookmark;
|
||||
ref.notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
await ref.read(bookmarksRequestProvider(state.readStatus, state.limit).future);
|
||||
}
|
||||
|
||||
@@ -189,7 +189,7 @@ final bookmarksRequestLoadMoreProvider =
|
||||
);
|
||||
|
||||
typedef BookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef<void>;
|
||||
String _$bookmarksHash() => r'6ebfea9e1b2b70e692527de3a3cccd0c85946c12';
|
||||
String _$bookmarksHash() => r'80e94e586950b9072f229958f98c88069086d7ab';
|
||||
|
||||
/// See also [Bookmarks].
|
||||
@ProviderFor(Bookmarks)
|
||||
|
||||
@@ -6,6 +6,11 @@ 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/config/sizes.dart';
|
||||
import 'package:linkdy/providers/app_status.provider.dart';
|
||||
import 'package:linkdy/providers/router.provider.dart';
|
||||
import 'package:linkdy/router/paths.dart';
|
||||
import 'package:linkdy/utils/open_url.dart';
|
||||
import 'package:linkdy/constants/global_keys.dart';
|
||||
import 'package:linkdy/constants/enums.dart';
|
||||
import 'package:linkdy/models/data/bookmarks.dart';
|
||||
@@ -99,6 +104,16 @@ class SearchBookmarks extends _$SearchBookmarks {
|
||||
ref.notifyListeners();
|
||||
}
|
||||
|
||||
void selectBookmark(Bookmark bookmark, double width) {
|
||||
if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == true) {
|
||||
ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark);
|
||||
} else if (width <= Sizes.tabletBreakpoint && ref.watch(appStatusProvider).useInAppBrowser == true) {
|
||||
openUrl(bookmark.url!);
|
||||
}
|
||||
state.selectedBookmark = bookmark;
|
||||
ref.notifyListeners();
|
||||
}
|
||||
|
||||
void deleteBookmark(Bookmark bookmark) async {
|
||||
final result = await BookmarkCommonFunctions.deleteBookmark<SearchBookmarksModel>(
|
||||
ref: ref,
|
||||
|
||||
@@ -174,7 +174,7 @@ final fetchSearchBookmarksLoadMoreProvider =
|
||||
);
|
||||
|
||||
typedef FetchSearchBookmarksLoadMoreRef = AutoDisposeFutureProviderRef<void>;
|
||||
String _$searchBookmarksHash() => r'bdb0eedf3ebdde4b2cb4795efe61ce42e4c85d00';
|
||||
String _$searchBookmarksHash() => r'3daf460b8389e8bcf8498c4bdf3935e88f4ce156';
|
||||
|
||||
/// See also [SearchBookmarks].
|
||||
@ProviderFor(SearchBookmarks)
|
||||
|
||||
@@ -11,27 +11,30 @@ import 'package:linkdy/config/options.dart';
|
||||
import 'package:linkdy/i18n/strings.g.dart';
|
||||
import 'package:linkdy/models/data/bookmarks.dart';
|
||||
import 'package:linkdy/providers/app_status.provider.dart';
|
||||
import 'package:linkdy/providers/router.provider.dart';
|
||||
import 'package:linkdy/router/paths.dart';
|
||||
import 'package:linkdy/utils/date_to_string.dart';
|
||||
import 'package:linkdy/utils/open_url.dart';
|
||||
|
||||
class BookmarkItem extends ConsumerWidget {
|
||||
final Bookmark bookmark;
|
||||
final void Function(Bookmark bookmark) onSelect;
|
||||
final void Function(Bookmark bookmark) onDelete;
|
||||
final void Function(Bookmark bookmark) onReadUnread;
|
||||
final void Function(Bookmark bookmark) onArchiveUnarchive;
|
||||
final void Function(Bookmark bookmark) onEdit;
|
||||
final void Function(Bookmark bookmark) onShareInternally;
|
||||
final bool selected;
|
||||
final bool tabletMode;
|
||||
|
||||
const BookmarkItem({
|
||||
super.key,
|
||||
required this.bookmark,
|
||||
required this.onSelect,
|
||||
required this.onDelete,
|
||||
required this.onReadUnread,
|
||||
required this.onArchiveUnarchive,
|
||||
required this.onEdit,
|
||||
required this.onShareInternally,
|
||||
required this.selected,
|
||||
required this.tabletMode,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -46,274 +49,283 @@ class BookmarkItem extends ConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
return Slidable(
|
||||
key: ValueKey(bookmark.id!),
|
||||
groupTag: ConfigOptions.slidableGroupTag,
|
||||
startActionPane: ActionPane(
|
||||
motion: const DrawerMotion(),
|
||||
extentRatio: 0.75,
|
||||
children: [
|
||||
SlidableAction(
|
||||
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) => onArchiveUnarchive(bookmark),
|
||||
backgroundColor: Colors.grey,
|
||||
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(
|
||||
onPressed: (ctx) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => ShareOptionsModal(bookmark: bookmark, onShareInternally: onShareInternally),
|
||||
),
|
||||
backgroundColor: Colors.orange,
|
||||
label: t.bookmarks.bookmarkOptions.shareOptions,
|
||||
icon: Icons.share_rounded,
|
||||
padding: const EdgeInsets.all(4),
|
||||
),
|
||||
],
|
||||
),
|
||||
endActionPane: ActionPane(
|
||||
motion: const DrawerMotion(),
|
||||
extentRatio: 0.5,
|
||||
children: [
|
||||
SlidableAction(
|
||||
onPressed: (ctx) => onEdit(bookmark),
|
||||
backgroundColor: Colors.green,
|
||||
label: t.bookmarks.bookmarkOptions.edit,
|
||||
icon: Icons.edit_rounded,
|
||||
padding: const EdgeInsets.all(4),
|
||||
),
|
||||
SlidableAction(
|
||||
onPressed: (_) => onDelete(bookmark),
|
||||
backgroundColor: Colors.red,
|
||||
label: t.bookmarks.bookmarkOptions.delete,
|
||||
icon: Icons.delete_rounded,
|
||||
padding: const EdgeInsets.all(4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: InkWell(
|
||||
onTap: ref.watch(appStatusProvider).useInAppBrowser == true
|
||||
? () => ref.watch(routerProvider).push(RoutesPaths.webview, extra: bookmark)
|
||||
: () => openUrl(bookmark.url!),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
return Padding(
|
||||
padding: tabletMode ? const EdgeInsets.symmetric(horizontal: 8) : const EdgeInsets.all(0),
|
||||
child: ClipRRect(
|
||||
borderRadius: tabletMode ? BorderRadius.circular(28) : BorderRadius.circular(0),
|
||||
child: Slidable(
|
||||
key: ValueKey(bookmark.id!),
|
||||
groupTag: ConfigOptions.slidableGroupTag,
|
||||
startActionPane: ActionPane(
|
||||
motion: const DrawerMotion(),
|
||||
extentRatio: 0.75,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
if (ref.watch(appStatusProvider).showFavicon == true)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: ref.watch(faviconStoreProvider).loadingFavicons == true
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Skeletonizer(
|
||||
enabled: true,
|
||||
ignoreContainers: true,
|
||||
child: Container(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Builder(
|
||||
builder: (context) {
|
||||
final faviconItem = ref
|
||||
.watch(faviconStoreProvider)
|
||||
.favicons
|
||||
.where((f) => f.url == bookmark.url!)
|
||||
.toList();
|
||||
if (faviconItem.isEmpty) return const SizedBox();
|
||||
if (faviconItem[0].isSvg == true) {
|
||||
return SvgPicture.network(
|
||||
faviconItem[0].favicon,
|
||||
width: 16,
|
||||
height: 16,
|
||||
placeholderBuilder: (context) => ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Skeletonizer(
|
||||
enabled: true,
|
||||
ignoreContainers: true,
|
||||
child: Container(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
SlidableAction(
|
||||
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) => onArchiveUnarchive(bookmark),
|
||||
backgroundColor: Colors.grey,
|
||||
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(
|
||||
onPressed: (ctx) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => ShareOptionsModal(bookmark: bookmark, onShareInternally: onShareInternally),
|
||||
),
|
||||
backgroundColor: Colors.orange,
|
||||
label: t.bookmarks.bookmarkOptions.shareOptions,
|
||||
icon: Icons.share_rounded,
|
||||
padding: const EdgeInsets.all(4),
|
||||
),
|
||||
],
|
||||
),
|
||||
endActionPane: ActionPane(
|
||||
motion: const DrawerMotion(),
|
||||
extentRatio: 0.5,
|
||||
children: [
|
||||
SlidableAction(
|
||||
onPressed: (ctx) => onEdit(bookmark),
|
||||
backgroundColor: Colors.green,
|
||||
label: t.bookmarks.bookmarkOptions.edit,
|
||||
icon: Icons.edit_rounded,
|
||||
padding: const EdgeInsets.all(4),
|
||||
),
|
||||
SlidableAction(
|
||||
onPressed: (_) => onDelete(bookmark),
|
||||
backgroundColor: Colors.red,
|
||||
label: t.bookmarks.bookmarkOptions.delete,
|
||||
icon: Icons.delete_rounded,
|
||||
padding: const EdgeInsets.all(4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Material(
|
||||
color: selected && tabletMode ? Theme.of(context).colorScheme.primaryContainer : Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => onSelect(bookmark),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
if (ref.watch(appStatusProvider).showFavicon == true)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: ref.watch(faviconStoreProvider).loadingFavicons == true
|
||||
? ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Skeletonizer(
|
||||
enabled: true,
|
||||
ignoreContainers: true,
|
||||
child: Container(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Image.network(
|
||||
faviconItem[0].favicon,
|
||||
width: 16,
|
||||
height: 16,
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress != null) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Skeletonizer(
|
||||
enabled: true,
|
||||
ignoreContainers: true,
|
||||
child: Container(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Colors.black,
|
||||
)
|
||||
: Builder(
|
||||
builder: (context) {
|
||||
final faviconItem = ref
|
||||
.watch(faviconStoreProvider)
|
||||
.favicons
|
||||
.where((f) => f.url == bookmark.url!)
|
||||
.toList();
|
||||
if (faviconItem.isEmpty) return const SizedBox();
|
||||
if (faviconItem[0].isSvg == true) {
|
||||
return SvgPicture.network(
|
||||
faviconItem[0].favicon,
|
||||
width: 16,
|
||||
height: 16,
|
||||
placeholderBuilder: (context) => ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Skeletonizer(
|
||||
enabled: true,
|
||||
ignoreContainers: true,
|
||||
child: Container(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Image.network(
|
||||
faviconItem[0].favicon,
|
||||
width: 16,
|
||||
height: 16,
|
||||
loadingBuilder: (context, child, loadingProgress) {
|
||||
if (loadingProgress != null) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: Skeletonizer(
|
||||
enabled: true,
|
||||
ignoreContainers: true,
|
||||
child: Container(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return child;
|
||||
},
|
||||
);
|
||||
}
|
||||
return child;
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
validateStrings(bookmark.title, bookmark.websiteTitle),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
validateStrings(bookmark.title, bookmark.websiteTitle),
|
||||
maxLines: 1,
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
validateStrings(bookmark.description, bookmark.websiteDescription),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
validateStrings(bookmark.description, bookmark.websiteDescription),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
bookmark.tagNames?.map((tag) => "#$tag").join(" ") ?? '',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (bookmark.shared == true) ...[
|
||||
if (bookmark.tagNames?.isNotEmpty == true)
|
||||
Container(
|
||||
width: 1,
|
||||
height: 12,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||
color: Theme.of(context).colorScheme.tertiary.withOpacity(0.3),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.share_rounded,
|
||||
size: 12,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
t.bookmarks.bookmarkOptions.shared,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (bookmark.unread == true) ...[
|
||||
if (bookmark.tagNames?.isNotEmpty == true || bookmark.shared == true)
|
||||
Container(
|
||||
width: 1,
|
||||
height: 12,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||
color: Theme.of(context).colorScheme.tertiary.withOpacity(0.3),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
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,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (bookmark.dateModified != null) ...[
|
||||
if (bookmark.unread == true || bookmark.shared == true || bookmark.tagNames?.isNotEmpty == true)
|
||||
Container(
|
||||
width: 1,
|
||||
height: 12,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||
color: Theme.of(context).colorScheme.tertiary.withOpacity(0.3),
|
||||
),
|
||||
Text(
|
||||
dateToString(bookmark.dateModified!),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
bookmark.tagNames?.map((tag) => "#$tag").join(" ") ?? '',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (bookmark.shared == true) ...[
|
||||
if (bookmark.tagNames?.isNotEmpty == true)
|
||||
Container(
|
||||
width: 1,
|
||||
height: 12,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||
color: Theme.of(context).colorScheme.tertiary.withOpacity(0.3),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.share_rounded,
|
||||
size: 12,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
t.bookmarks.bookmarkOptions.shared,
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (bookmark.unread == true) ...[
|
||||
if (bookmark.tagNames?.isNotEmpty == true || bookmark.shared == true)
|
||||
Container(
|
||||
width: 1,
|
||||
height: 12,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||
color: Theme.of(context).colorScheme.tertiary.withOpacity(0.3),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 6,
|
||||
vertical: 2,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
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,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
if (bookmark.dateModified != null) ...[
|
||||
if (bookmark.unread == true ||
|
||||
bookmark.shared == true ||
|
||||
bookmark.tagNames?.isNotEmpty == true)
|
||||
Container(
|
||||
width: 1,
|
||||
height: 12,
|
||||
margin: const EdgeInsets.symmetric(horizontal: 8),
|
||||
color: Theme.of(context).colorScheme.tertiary.withOpacity(0.3),
|
||||
),
|
||||
Text(
|
||||
dateToString(bookmark.dateModified!),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:linkdy/screens/bookmarks/ui/visualization_modal.dart';
|
||||
|
||||
import 'package:linkdy/screens/bookmarks/ui/visualization_modal.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/bookmark_form_modal.dart';
|
||||
import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart';
|
||||
import 'package:linkdy/screens/bookmarks/ui/search_bookmarks.dart';
|
||||
import 'package:linkdy/screens/webview/ui/webview.dart';
|
||||
import 'package:linkdy/widgets/circle_page_transition.dart';
|
||||
import 'package:linkdy/widgets/error_screen.dart';
|
||||
import 'package:linkdy/widgets/no_data_screen.dart';
|
||||
|
||||
import 'package:linkdy/config/sizes.dart';
|
||||
import 'package:linkdy/constants/enums.dart';
|
||||
import 'package:linkdy/providers/router.provider.dart';
|
||||
import 'package:linkdy/router/paths.dart';
|
||||
@@ -23,6 +25,46 @@ final GlobalKey _searchButtonKey = GlobalKey();
|
||||
class BookmarksScreen extends ConsumerWidget {
|
||||
const BookmarksScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return ScaffoldMessenger(
|
||||
key: ScaffoldMessengerKeys.bookmarks,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
if (constraints.maxWidth > Sizes.tabletBreakpoint) {
|
||||
return Row(
|
||||
children: [
|
||||
const Expanded(flex: 2, child: _List(tabletMode: true)),
|
||||
if (ref.watch(bookmarksProvider).selectedBookmark != null)
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: WebViewScreen(
|
||||
bookmark: ref.watch(bookmarksProvider).selectedBookmark!,
|
||||
),
|
||||
),
|
||||
if (ref.watch(bookmarksProvider).selectedBookmark == null)
|
||||
const Expanded(
|
||||
flex: 3,
|
||||
child: SizedBox(),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return const _List(tabletMode: false);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _List extends ConsumerWidget {
|
||||
final bool tabletMode;
|
||||
|
||||
const _List({
|
||||
required this.tabletMode,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final bookmarks = ref.watch(bookmarksProvider);
|
||||
@@ -51,184 +93,184 @@ class BookmarksScreen extends ConsumerWidget {
|
||||
return false;
|
||||
}
|
||||
|
||||
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: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(t.bookmarks.bookmarks),
|
||||
if (bookmarks.readStatus == ReadStatus.read || bookmarks.readStatus == ReadStatus.unread)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 8),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
bookmarks.readStatus == ReadStatus.read
|
||||
? Icons.mark_email_read_rounded
|
||||
: Icons.mark_as_unread_rounded,
|
||||
size: 14,
|
||||
return Scaffold(
|
||||
body: NestedScrollView(
|
||||
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||
SliverOverlapAbsorber(
|
||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||
sliver: SliverAppBar.large(
|
||||
pinned: true,
|
||||
floating: true,
|
||||
centerTitle: false,
|
||||
forceElevated: innerBoxIsScrolled,
|
||||
title: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(t.bookmarks.bookmarks),
|
||||
if (bookmarks.readStatus == ReadStatus.read || bookmarks.readStatus == ReadStatus.unread)
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 8),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
bookmarks.readStatus == ReadStatus.read
|
||||
? Icons.mark_email_read_rounded
|
||||
: Icons.mark_as_unread_rounded,
|
||||
size: 14,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
bookmarks.readStatus == ReadStatus.read ? t.bookmarks.read : t.bookmarks.unread,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
bookmarks.readStatus == ReadStatus.read ? t.bookmarks.read : t.bookmarks.unread,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
key: _searchButtonKey,
|
||||
onPressed: openSearchModal,
|
||||
icon: const Icon(Icons.search_rounded),
|
||||
tooltip: t.bookmarks.search.searchBookmarks,
|
||||
),
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) => <PopupMenuEntry>[
|
||||
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 PopupMenuDivider(height: 1),
|
||||
PopupMenuItem(
|
||||
onTap: () => showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
builder: (context) => const VisualizationModal(),
|
||||
isScrollControlled: true,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.sort_rounded),
|
||||
const SizedBox(width: 16),
|
||||
Text(t.bookmarks.filterSort),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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),
|
||||
),
|
||||
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.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],
|
||||
onSelect: (b) => ref.read(bookmarksProvider.notifier).selectBookmark(b, width),
|
||||
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,
|
||||
onShareInternally: ref.read(bookmarksProvider.notifier).shareUnshare,
|
||||
onEdit: (b) => openBookmarkFormModal(context: context, width: width, bookmark: b),
|
||||
selected: bookmarks.bookmarks[index] == bookmarks.selectedBookmark,
|
||||
tabletMode: tabletMode,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
key: _searchButtonKey,
|
||||
onPressed: openSearchModal,
|
||||
icon: const Icon(Icons.search_rounded),
|
||||
tooltip: t.bookmarks.search.searchBookmarks,
|
||||
),
|
||||
PopupMenuButton(
|
||||
itemBuilder: (context) => <PopupMenuEntry>[
|
||||
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 PopupMenuDivider(height: 1),
|
||||
PopupMenuItem(
|
||||
onTap: () => showModalBottomSheet(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
builder: (context) => const VisualizationModal(),
|
||||
isScrollControlled: true,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.sort_rounded),
|
||||
const SizedBox(width: 16),
|
||||
Text(t.bookmarks.filterSort),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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),
|
||||
),
|
||||
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.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,
|
||||
),
|
||||
),
|
||||
onArchiveUnarchive: ref.read(bookmarksProvider.notifier).archiveUnarchive,
|
||||
onShareInternally: ref.read(bookmarksProvider.notifier).shareUnshare,
|
||||
onEdit: (b) => openBookmarkFormModal(context: context, width: width, bookmark: b),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => openBookmarkFormModal(context: context, width: width),
|
||||
child: const Icon(Icons.add_rounded),
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: () => openBookmarkFormModal(context: context, width: width),
|
||||
child: const Icon(Icons.add_rounded),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,15 +6,17 @@ import 'package:linkdy/screens/bookmarks/provider/search_bookmarks.provider.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/webview/ui/webview.dart';
|
||||
import 'package:linkdy/widgets/enter_search_term_screen.dart';
|
||||
import 'package:linkdy/widgets/no_data_screen.dart';
|
||||
import 'package:linkdy/widgets/error_screen.dart';
|
||||
|
||||
import 'package:linkdy/constants/global_keys.dart';
|
||||
import 'package:linkdy/constants/enums.dart';
|
||||
import 'package:linkdy/providers/router.provider.dart';
|
||||
|
||||
import 'package:linkdy/config/sizes.dart';
|
||||
import 'package:linkdy/i18n/strings.g.dart';
|
||||
import 'package:linkdy/widgets/no_data_screen.dart';
|
||||
|
||||
class SearchBookmarksModal extends ConsumerWidget {
|
||||
final bool fullscreen;
|
||||
@@ -24,6 +26,50 @@ class SearchBookmarksModal extends ConsumerWidget {
|
||||
required this.fullscreen,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return ScaffoldMessenger(
|
||||
key: ScaffoldMessengerKeys.search,
|
||||
child: Dialog.fullscreen(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
if (constraints.maxWidth > Sizes.tabletBreakpoint) {
|
||||
return Row(
|
||||
children: [
|
||||
const Expanded(flex: 2, child: _List(tabletMode: true)),
|
||||
if (ref.watch(searchBookmarksProvider).selectedBookmark != null)
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: WebViewScreen(
|
||||
bookmark: ref.watch(searchBookmarksProvider).selectedBookmark!,
|
||||
),
|
||||
),
|
||||
if (ref.watch(searchBookmarksProvider).selectedBookmark == null)
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return const _List(tabletMode: false);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _List extends ConsumerWidget {
|
||||
final bool tabletMode;
|
||||
|
||||
const _List({
|
||||
required this.tabletMode,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final provider = ref.watch(searchBookmarksProvider);
|
||||
@@ -40,116 +86,114 @@ class SearchBookmarksModal extends ConsumerWidget {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ScaffoldMessenger(
|
||||
key: ScaffoldMessengerKeys.search,
|
||||
child: Dialog.fullscreen(
|
||||
child: Scaffold(
|
||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2),
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0),
|
||||
toolbarHeight: 68,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: BackButton(
|
||||
onPressed: () => ref.watch(routerProvider).pop(),
|
||||
),
|
||||
),
|
||||
titleSpacing: 0,
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, right: 16),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: TextFormField(
|
||||
controller: ref.watch(searchBookmarksProvider).searchController,
|
||||
onChanged: (_) => ref.read(searchBookmarksProvider.notifier).notifyListeners(),
|
||||
onEditingComplete: () {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
ref.read(searchBookmarksProvider.notifier).setSearchTerm();
|
||||
ref.read(searchBookmarksProvider.notifier).setInitialLoadStatus(LoadStatus.loading);
|
||||
ref.read(fetchSearchBookmarksProvider(provider.limit));
|
||||
},
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: t.bookmarks.search.searchBookmarks,
|
||||
prefixIcon: const Icon(Icons.search_rounded),
|
||||
border: InputBorder.none,
|
||||
filled: true,
|
||||
fillColor: Colors.grey.withOpacity(0.2),
|
||||
suffixIcon: ref.watch(searchBookmarksProvider).searchController.text != ""
|
||||
? IconButton(
|
||||
onPressed: ref.read(searchBookmarksProvider.notifier).clearSearch,
|
||||
icon: const Icon(
|
||||
Icons.close_rounded,
|
||||
size: 20,
|
||||
),
|
||||
tooltip: t.bookmarks.search.clearSearch,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
textInputAction: TextInputAction.search,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
if (provider.searchTerm == "") {
|
||||
return EnterSearchTermScreen(message: t.bookmarks.search.inputSearchTerm);
|
||||
}
|
||||
|
||||
if (provider.inialLoadStatus == LoadStatus.loading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
if (provider.inialLoadStatus == LoadStatus.error) {
|
||||
return ErrorScreen(
|
||||
error: t.bookmarks.search.cannotSearchError,
|
||||
);
|
||||
}
|
||||
|
||||
if (provider.bookmarks.isEmpty) {
|
||||
return NoDataScreen(
|
||||
message: t.bookmarks.search.inputtedSearchTermNoResults,
|
||||
);
|
||||
}
|
||||
|
||||
return NotificationListener(
|
||||
onNotification: scrollListener,
|
||||
child: SlidableAutoCloseBehavior(
|
||||
child: ListView.builder(
|
||||
itemCount: provider.loadingMore ? 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(searchBookmarksProvider.notifier).markAsReadUnread,
|
||||
onDelete: (bookmark) => showDialog(
|
||||
context: context,
|
||||
builder: (context) => DeleteBookmarkModal(
|
||||
bookmark: bookmark,
|
||||
onDelete: ref.read(searchBookmarksProvider.notifier).deleteBookmark,
|
||||
),
|
||||
),
|
||||
onArchiveUnarchive: ref.read(searchBookmarksProvider.notifier).archiveUnarchive,
|
||||
onShareInternally: ref.read(searchBookmarksProvider.notifier).shareUnshare,
|
||||
onEdit: (b) => openBookmarkFormModal(context: context, width: width, bookmark: b),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2),
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0),
|
||||
toolbarHeight: 68,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: BackButton(
|
||||
onPressed: () => ref.watch(routerProvider).pop(),
|
||||
),
|
||||
),
|
||||
titleSpacing: 0,
|
||||
title: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8, right: 16),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
child: TextFormField(
|
||||
controller: ref.watch(searchBookmarksProvider).searchController,
|
||||
onChanged: (_) => ref.read(searchBookmarksProvider.notifier).notifyListeners(),
|
||||
onEditingComplete: () {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
ref.read(searchBookmarksProvider.notifier).setSearchTerm();
|
||||
ref.read(searchBookmarksProvider.notifier).setInitialLoadStatus(LoadStatus.loading);
|
||||
ref.read(fetchSearchBookmarksProvider(provider.limit));
|
||||
},
|
||||
autofocus: true,
|
||||
decoration: InputDecoration(
|
||||
hintText: t.bookmarks.search.searchBookmarks,
|
||||
prefixIcon: const Icon(Icons.search_rounded),
|
||||
border: InputBorder.none,
|
||||
filled: true,
|
||||
fillColor: Colors.grey.withOpacity(0.2),
|
||||
suffixIcon: ref.watch(searchBookmarksProvider).searchController.text != ""
|
||||
? IconButton(
|
||||
onPressed: ref.read(searchBookmarksProvider.notifier).clearSearch,
|
||||
icon: const Icon(
|
||||
Icons.close_rounded,
|
||||
size: 20,
|
||||
),
|
||||
tooltip: t.bookmarks.search.clearSearch,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
textInputAction: TextInputAction.search,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: Builder(
|
||||
builder: (context) {
|
||||
if (provider.searchTerm == "") {
|
||||
return EnterSearchTermScreen(message: t.bookmarks.search.inputSearchTerm);
|
||||
}
|
||||
|
||||
if (provider.inialLoadStatus == LoadStatus.loading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
if (provider.inialLoadStatus == LoadStatus.error) {
|
||||
return ErrorScreen(
|
||||
error: t.bookmarks.search.cannotSearchError,
|
||||
);
|
||||
}
|
||||
|
||||
if (provider.bookmarks.isEmpty) {
|
||||
return NoDataScreen(
|
||||
message: t.bookmarks.search.inputtedSearchTermNoResults,
|
||||
);
|
||||
}
|
||||
|
||||
return NotificationListener(
|
||||
onNotification: scrollListener,
|
||||
child: SlidableAutoCloseBehavior(
|
||||
child: ListView.builder(
|
||||
itemCount: provider.loadingMore ? 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],
|
||||
onSelect: (b) => ref.read(searchBookmarksProvider.notifier).selectBookmark(b, width),
|
||||
onReadUnread: ref.read(searchBookmarksProvider.notifier).markAsReadUnread,
|
||||
onDelete: (bookmark) => showDialog(
|
||||
context: context,
|
||||
builder: (context) => DeleteBookmarkModal(
|
||||
bookmark: bookmark,
|
||||
onDelete: ref.read(searchBookmarksProvider.notifier).deleteBookmark,
|
||||
),
|
||||
),
|
||||
onArchiveUnarchive: ref.read(searchBookmarksProvider.notifier).archiveUnarchive,
|
||||
onShareInternally: ref.read(searchBookmarksProvider.notifier).shareUnshare,
|
||||
onEdit: (b) => openBookmarkFormModal(context: context, width: width, bookmark: b),
|
||||
selected: provider.bookmarks[index] == provider.selectedBookmark,
|
||||
tabletMode: tabletMode,
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user