Adapted bookmarks list to tablet mode
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
/// Locales: 2
|
/// Locales: 2
|
||||||
/// Strings: 350 (175 per locale)
|
/// Strings: 350 (175 per locale)
|
||||||
///
|
///
|
||||||
/// Built on 2024-02-28 at 16:44 UTC
|
/// Built on 2024-02-28 at 18:58 UTC
|
||||||
|
|
||||||
// coverage:ignore-file
|
// coverage:ignore-file
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
@@ -481,7 +481,7 @@ class _StringsSettingsGeneralSettingsEn {
|
|||||||
String get disconnectFromServer => 'Disconnect from server';
|
String get disconnectFromServer => 'Disconnect from server';
|
||||||
late final _StringsSettingsGeneralSettingsDisconnectModalEn disconnectModal = _StringsSettingsGeneralSettingsDisconnectModalEn._(_root);
|
late final _StringsSettingsGeneralSettingsDisconnectModalEn disconnectModal = _StringsSettingsGeneralSettingsDisconnectModalEn._(_root);
|
||||||
String get useInAppBrowser => 'Use in app browser';
|
String get useInAppBrowser => 'Use in app browser';
|
||||||
String get useInAppBrowserDescription => 'Opens the bookmarks with the integrated browser instead of with the system browser.';
|
String get useInAppBrowserDescription => 'Opens the bookmarks with the integrated browser instead of with the system browser. On tablet mode the internal browser will always be used.';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: settings.generalSettings.disconnectModal
|
// Path: settings.generalSettings.disconnectModal
|
||||||
@@ -852,7 +852,7 @@ class _StringsSettingsGeneralSettingsEs implements _StringsSettingsGeneralSettin
|
|||||||
@override String get disconnectFromServer => 'Desconectar del servidor';
|
@override String get disconnectFromServer => 'Desconectar del servidor';
|
||||||
@override late final _StringsSettingsGeneralSettingsDisconnectModalEs disconnectModal = _StringsSettingsGeneralSettingsDisconnectModalEs._(_root);
|
@override late final _StringsSettingsGeneralSettingsDisconnectModalEs disconnectModal = _StringsSettingsGeneralSettingsDisconnectModalEs._(_root);
|
||||||
@override String get useInAppBrowser => 'Usar navegador de la aplicación';
|
@override String get useInAppBrowser => 'Usar navegador de la aplicación';
|
||||||
@override String get useInAppBrowserDescription => 'Abre los marcadores con el navegador integrado en vez de con el navegador del sietema.';
|
@override String get useInAppBrowserDescription => 'Abre los marcadores con el navegador integrado en vez de con el navegador del sietema. En modo tablet siempre se usará el navegador integrado.';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path: settings.generalSettings.disconnectModal
|
// Path: settings.generalSettings.disconnectModal
|
||||||
@@ -1028,7 +1028,7 @@ extension on Translations {
|
|||||||
case 'settings.generalSettings.disconnectModal.title': return 'Disconnect';
|
case 'settings.generalSettings.disconnectModal.title': return 'Disconnect';
|
||||||
case 'settings.generalSettings.disconnectModal.description': return 'Are you sure you want to disconnect from the server?\nYou will be redirected to the initial setup.';
|
case 'settings.generalSettings.disconnectModal.description': return 'Are you sure you want to disconnect from the server?\nYou will be redirected to the initial setup.';
|
||||||
case 'settings.generalSettings.useInAppBrowser': return 'Use in app browser';
|
case 'settings.generalSettings.useInAppBrowser': return 'Use in app browser';
|
||||||
case 'settings.generalSettings.useInAppBrowserDescription': return 'Opens the bookmarks with the integrated browser instead of with the system browser.';
|
case 'settings.generalSettings.useInAppBrowserDescription': return 'Opens the bookmarks with the integrated browser instead of with the system browser. On tablet mode the internal browser will always be used.';
|
||||||
case 'webview.goBack': return 'Go back';
|
case 'webview.goBack': return 'Go back';
|
||||||
case 'webview.goForward': return 'Go forward';
|
case 'webview.goForward': return 'Go forward';
|
||||||
case 'webview.reload': return 'Reload';
|
case 'webview.reload': return 'Reload';
|
||||||
@@ -1211,7 +1211,7 @@ extension on _StringsEs {
|
|||||||
case 'settings.generalSettings.disconnectModal.title': return 'Desconectar';
|
case 'settings.generalSettings.disconnectModal.title': return 'Desconectar';
|
||||||
case 'settings.generalSettings.disconnectModal.description': return '¿Estás seguro que deseas desconectarte del servidor?\nSerás redirigido a la configuración inicial.';
|
case 'settings.generalSettings.disconnectModal.description': return '¿Estás seguro que deseas desconectarte del servidor?\nSerás redirigido a la configuración inicial.';
|
||||||
case 'settings.generalSettings.useInAppBrowser': return 'Usar navegador de la aplicación';
|
case 'settings.generalSettings.useInAppBrowser': return 'Usar navegador de la aplicación';
|
||||||
case 'settings.generalSettings.useInAppBrowserDescription': return 'Abre los marcadores con el navegador integrado en vez de con el navegador del sietema.';
|
case 'settings.generalSettings.useInAppBrowserDescription': return 'Abre los marcadores con el navegador integrado en vez de con el navegador del sietema. En modo tablet siempre se usará el navegador integrado.';
|
||||||
case 'webview.goBack': return 'Ir atrás';
|
case 'webview.goBack': return 'Ir atrás';
|
||||||
case 'webview.goForward': return 'Ir adelante';
|
case 'webview.goForward': return 'Ir adelante';
|
||||||
case 'webview.reload': return 'Recargar';
|
case 'webview.reload': return 'Recargar';
|
||||||
|
|||||||
@@ -183,7 +183,7 @@
|
|||||||
"description": "Are you sure you want to disconnect from the server?\nYou will be redirected to the initial setup."
|
"description": "Are you sure you want to disconnect from the server?\nYou will be redirected to the initial setup."
|
||||||
},
|
},
|
||||||
"useInAppBrowser": "Use in app browser",
|
"useInAppBrowser": "Use in app browser",
|
||||||
"useInAppBrowserDescription": "Opens the bookmarks with the integrated browser instead of with the system browser."
|
"useInAppBrowserDescription": "Opens the bookmarks with the integrated browser instead of with the system browser. On tablet mode the internal browser will always be used."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"webview": {
|
"webview": {
|
||||||
|
|||||||
@@ -183,7 +183,7 @@
|
|||||||
"description": "¿Estás seguro que deseas desconectarte del servidor?\nSerás redirigido a la configuración inicial."
|
"description": "¿Estás seguro que deseas desconectarte del servidor?\nSerás redirigido a la configuración inicial."
|
||||||
},
|
},
|
||||||
"useInAppBrowser": "Usar navegador de la aplicación",
|
"useInAppBrowser": "Usar navegador de la aplicación",
|
||||||
"useInAppBrowserDescription": "Abre los marcadores con el navegador integrado en vez de con el navegador del sietema."
|
"useInAppBrowserDescription": "Abre los marcadores con el navegador integrado en vez de con el navegador del sietema. En modo tablet siempre se usará el navegador integrado."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"webview": {
|
"webview": {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ class BookmarksModel {
|
|||||||
bool loadingMore;
|
bool loadingMore;
|
||||||
int maxNumber;
|
int maxNumber;
|
||||||
ReadStatus readStatus;
|
ReadStatus readStatus;
|
||||||
|
Bookmark? selectedBookmark;
|
||||||
|
|
||||||
BookmarksModel({
|
BookmarksModel({
|
||||||
this.currentPage = 0,
|
this.currentPage = 0,
|
||||||
@@ -19,5 +20,6 @@ class BookmarksModel {
|
|||||||
this.loadingMore = false,
|
this.loadingMore = false,
|
||||||
this.maxNumber = 0,
|
this.maxNumber = 0,
|
||||||
this.readStatus = ReadStatus.all,
|
this.readStatus = ReadStatus.all,
|
||||||
|
this.selectedBookmark,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class SearchBookmarksModel {
|
|||||||
LoadStatus inialLoadStatus;
|
LoadStatus inialLoadStatus;
|
||||||
bool loadingMore;
|
bool loadingMore;
|
||||||
int maxNumber;
|
int maxNumber;
|
||||||
|
Bookmark? selectedBookmark;
|
||||||
|
|
||||||
SearchBookmarksModel({
|
SearchBookmarksModel({
|
||||||
required this.searchController,
|
required this.searchController,
|
||||||
@@ -23,5 +24,6 @@ class SearchBookmarksModel {
|
|||||||
this.inialLoadStatus = LoadStatus.loaded,
|
this.inialLoadStatus = LoadStatus.loaded,
|
||||||
this.loadingMore = false,
|
this.loadingMore = false,
|
||||||
this.maxNumber = 0,
|
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:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
import 'package:linkdy/screens/bookmarks/provider/common_functions.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/provider/favicon_loader.provider.dart';
|
||||||
import 'package:linkdy/screens/bookmarks/model/bookmarks.model.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/models/data/bookmarks.dart';
|
||||||
import 'package:linkdy/providers/api_client.provider.dart';
|
import 'package:linkdy/providers/api_client.provider.dart';
|
||||||
import 'package:linkdy/constants/enums.dart';
|
import 'package:linkdy/constants/enums.dart';
|
||||||
@@ -93,6 +98,16 @@ class Bookmarks extends _$Bookmarks {
|
|||||||
ref.notifyListeners();
|
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 {
|
Future<void> refresh() async {
|
||||||
await ref.read(bookmarksRequestProvider(state.readStatus, state.limit).future);
|
await ref.read(bookmarksRequestProvider(state.readStatus, state.limit).future);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ final bookmarksRequestLoadMoreProvider =
|
|||||||
);
|
);
|
||||||
|
|
||||||
typedef BookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef<void>;
|
typedef BookmarksRequestLoadMoreRef = AutoDisposeFutureProviderRef<void>;
|
||||||
String _$bookmarksHash() => r'6ebfea9e1b2b70e692527de3a3cccd0c85946c12';
|
String _$bookmarksHash() => r'80e94e586950b9072f229958f98c88069086d7ab';
|
||||||
|
|
||||||
/// See also [Bookmarks].
|
/// See also [Bookmarks].
|
||||||
@ProviderFor(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/provider/common_functions.dart';
|
||||||
import 'package:linkdy/screens/bookmarks/model/search_bookmarks.model.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/global_keys.dart';
|
||||||
import 'package:linkdy/constants/enums.dart';
|
import 'package:linkdy/constants/enums.dart';
|
||||||
import 'package:linkdy/models/data/bookmarks.dart';
|
import 'package:linkdy/models/data/bookmarks.dart';
|
||||||
@@ -99,6 +104,16 @@ class SearchBookmarks extends _$SearchBookmarks {
|
|||||||
ref.notifyListeners();
|
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 {
|
void deleteBookmark(Bookmark bookmark) async {
|
||||||
final result = await BookmarkCommonFunctions.deleteBookmark<SearchBookmarksModel>(
|
final result = await BookmarkCommonFunctions.deleteBookmark<SearchBookmarksModel>(
|
||||||
ref: ref,
|
ref: ref,
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ final fetchSearchBookmarksLoadMoreProvider =
|
|||||||
);
|
);
|
||||||
|
|
||||||
typedef FetchSearchBookmarksLoadMoreRef = AutoDisposeFutureProviderRef<void>;
|
typedef FetchSearchBookmarksLoadMoreRef = AutoDisposeFutureProviderRef<void>;
|
||||||
String _$searchBookmarksHash() => r'bdb0eedf3ebdde4b2cb4795efe61ce42e4c85d00';
|
String _$searchBookmarksHash() => r'3daf460b8389e8bcf8498c4bdf3935e88f4ce156';
|
||||||
|
|
||||||
/// See also [SearchBookmarks].
|
/// See also [SearchBookmarks].
|
||||||
@ProviderFor(SearchBookmarks)
|
@ProviderFor(SearchBookmarks)
|
||||||
|
|||||||
@@ -11,27 +11,30 @@ import 'package:linkdy/config/options.dart';
|
|||||||
import 'package:linkdy/i18n/strings.g.dart';
|
import 'package:linkdy/i18n/strings.g.dart';
|
||||||
import 'package:linkdy/models/data/bookmarks.dart';
|
import 'package:linkdy/models/data/bookmarks.dart';
|
||||||
import 'package:linkdy/providers/app_status.provider.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/date_to_string.dart';
|
||||||
import 'package:linkdy/utils/open_url.dart';
|
|
||||||
|
|
||||||
class BookmarkItem extends ConsumerWidget {
|
class BookmarkItem extends ConsumerWidget {
|
||||||
final Bookmark bookmark;
|
final Bookmark bookmark;
|
||||||
|
final void Function(Bookmark bookmark) onSelect;
|
||||||
final void Function(Bookmark bookmark) onDelete;
|
final void Function(Bookmark bookmark) onDelete;
|
||||||
final void Function(Bookmark bookmark) onReadUnread;
|
final void Function(Bookmark bookmark) onReadUnread;
|
||||||
final void Function(Bookmark bookmark) onArchiveUnarchive;
|
final void Function(Bookmark bookmark) onArchiveUnarchive;
|
||||||
final void Function(Bookmark bookmark) onEdit;
|
final void Function(Bookmark bookmark) onEdit;
|
||||||
final void Function(Bookmark bookmark) onShareInternally;
|
final void Function(Bookmark bookmark) onShareInternally;
|
||||||
|
final bool selected;
|
||||||
|
final bool tabletMode;
|
||||||
|
|
||||||
const BookmarkItem({
|
const BookmarkItem({
|
||||||
super.key,
|
super.key,
|
||||||
required this.bookmark,
|
required this.bookmark,
|
||||||
|
required this.onSelect,
|
||||||
required this.onDelete,
|
required this.onDelete,
|
||||||
required this.onReadUnread,
|
required this.onReadUnread,
|
||||||
required this.onArchiveUnarchive,
|
required this.onArchiveUnarchive,
|
||||||
required this.onEdit,
|
required this.onEdit,
|
||||||
required this.onShareInternally,
|
required this.onShareInternally,
|
||||||
|
required this.selected,
|
||||||
|
required this.tabletMode,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -46,274 +49,283 @@ class BookmarkItem extends ConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Slidable(
|
return Padding(
|
||||||
key: ValueKey(bookmark.id!),
|
padding: tabletMode ? const EdgeInsets.symmetric(horizontal: 8) : const EdgeInsets.all(0),
|
||||||
groupTag: ConfigOptions.slidableGroupTag,
|
child: ClipRRect(
|
||||||
startActionPane: ActionPane(
|
borderRadius: tabletMode ? BorderRadius.circular(28) : BorderRadius.circular(0),
|
||||||
motion: const DrawerMotion(),
|
child: Slidable(
|
||||||
extentRatio: 0.75,
|
key: ValueKey(bookmark.id!),
|
||||||
children: [
|
groupTag: ConfigOptions.slidableGroupTag,
|
||||||
SlidableAction(
|
startActionPane: ActionPane(
|
||||||
onPressed: (_) => onReadUnread(bookmark),
|
motion: const DrawerMotion(),
|
||||||
backgroundColor: Colors.blue,
|
extentRatio: 0.75,
|
||||||
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,
|
|
||||||
children: [
|
children: [
|
||||||
Row(
|
SlidableAction(
|
||||||
children: [
|
onPressed: (_) => onReadUnread(bookmark),
|
||||||
if (ref.watch(appStatusProvider).showFavicon == true)
|
backgroundColor: Colors.blue,
|
||||||
Padding(
|
label: bookmark.unread == true ? t.bookmarks.bookmarkOptions.read : t.bookmarks.bookmarkOptions.unread,
|
||||||
padding: const EdgeInsets.only(right: 8),
|
icon: bookmark.unread == true ? Icons.mark_email_read_rounded : Icons.mark_as_unread_rounded,
|
||||||
child: ref.watch(faviconStoreProvider).loadingFavicons == true
|
padding: const EdgeInsets.all(4),
|
||||||
? ClipRRect(
|
),
|
||||||
borderRadius: BorderRadius.circular(4),
|
SlidableAction(
|
||||||
child: Skeletonizer(
|
onPressed: (ctx) => onArchiveUnarchive(bookmark),
|
||||||
enabled: true,
|
backgroundColor: Colors.grey,
|
||||||
ignoreContainers: true,
|
label: bookmark.isArchived == true
|
||||||
child: Container(
|
? t.bookmarks.bookmarkOptions.unarchive
|
||||||
width: 16,
|
: t.bookmarks.bookmarkOptions.archive,
|
||||||
height: 16,
|
icon: bookmark.isArchived == true ? Icons.unarchive_rounded : Icons.archive_rounded,
|
||||||
color: Colors.black,
|
padding: const EdgeInsets.all(4),
|
||||||
),
|
),
|
||||||
),
|
SlidableAction(
|
||||||
)
|
onPressed: (ctx) => showDialog(
|
||||||
: Builder(
|
context: context,
|
||||||
builder: (context) {
|
builder: (ctx) => ShareOptionsModal(bookmark: bookmark, onShareInternally: onShareInternally),
|
||||||
final faviconItem = ref
|
),
|
||||||
.watch(faviconStoreProvider)
|
backgroundColor: Colors.orange,
|
||||||
.favicons
|
label: t.bookmarks.bookmarkOptions.shareOptions,
|
||||||
.where((f) => f.url == bookmark.url!)
|
icon: Icons.share_rounded,
|
||||||
.toList();
|
padding: const EdgeInsets.all(4),
|
||||||
if (faviconItem.isEmpty) return const SizedBox();
|
),
|
||||||
if (faviconItem[0].isSvg == true) {
|
],
|
||||||
return SvgPicture.network(
|
),
|
||||||
faviconItem[0].favicon,
|
endActionPane: ActionPane(
|
||||||
width: 16,
|
motion: const DrawerMotion(),
|
||||||
height: 16,
|
extentRatio: 0.5,
|
||||||
placeholderBuilder: (context) => ClipRRect(
|
children: [
|
||||||
borderRadius: BorderRadius.circular(4),
|
SlidableAction(
|
||||||
child: Skeletonizer(
|
onPressed: (ctx) => onEdit(bookmark),
|
||||||
enabled: true,
|
backgroundColor: Colors.green,
|
||||||
ignoreContainers: true,
|
label: t.bookmarks.bookmarkOptions.edit,
|
||||||
child: Container(
|
icon: Icons.edit_rounded,
|
||||||
width: 16,
|
padding: const EdgeInsets.all(4),
|
||||||
height: 16,
|
),
|
||||||
color: Colors.black,
|
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 {
|
: Builder(
|
||||||
return Image.network(
|
builder: (context) {
|
||||||
faviconItem[0].favicon,
|
final faviconItem = ref
|
||||||
width: 16,
|
.watch(faviconStoreProvider)
|
||||||
height: 16,
|
.favicons
|
||||||
loadingBuilder: (context, child, loadingProgress) {
|
.where((f) => f.url == bookmark.url!)
|
||||||
if (loadingProgress != null) {
|
.toList();
|
||||||
return ClipRRect(
|
if (faviconItem.isEmpty) return const SizedBox();
|
||||||
borderRadius: BorderRadius.circular(4),
|
if (faviconItem[0].isSvg == true) {
|
||||||
child: Skeletonizer(
|
return SvgPicture.network(
|
||||||
enabled: true,
|
faviconItem[0].favicon,
|
||||||
ignoreContainers: true,
|
width: 16,
|
||||||
child: Container(
|
height: 16,
|
||||||
width: 16,
|
placeholderBuilder: (context) => ClipRRect(
|
||||||
height: 16,
|
borderRadius: BorderRadius.circular(4),
|
||||||
color: Colors.black,
|
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(
|
const SizedBox(height: 4),
|
||||||
child: Text(
|
Text(
|
||||||
validateStrings(bookmark.title, bookmark.websiteTitle),
|
validateStrings(bookmark.description, bookmark.websiteDescription),
|
||||||
maxLines: 1,
|
maxLines: 3,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
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,
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
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/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_slidable/flutter_slidable.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/provider/bookmarks.provider.dart';
|
||||||
import 'package:linkdy/screens/bookmarks/ui/bookmark_item.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/bookmark_form_modal.dart';
|
||||||
import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_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/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/circle_page_transition.dart';
|
||||||
import 'package:linkdy/widgets/error_screen.dart';
|
import 'package:linkdy/widgets/error_screen.dart';
|
||||||
import 'package:linkdy/widgets/no_data_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/constants/enums.dart';
|
||||||
import 'package:linkdy/providers/router.provider.dart';
|
import 'package:linkdy/providers/router.provider.dart';
|
||||||
import 'package:linkdy/router/paths.dart';
|
import 'package:linkdy/router/paths.dart';
|
||||||
@@ -23,6 +25,46 @@ final GlobalKey _searchButtonKey = GlobalKey();
|
|||||||
class BookmarksScreen extends ConsumerWidget {
|
class BookmarksScreen extends ConsumerWidget {
|
||||||
const BookmarksScreen({super.key});
|
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
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final bookmarks = ref.watch(bookmarksProvider);
|
final bookmarks = ref.watch(bookmarksProvider);
|
||||||
@@ -51,184 +93,184 @@ class BookmarksScreen extends ConsumerWidget {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ScaffoldMessenger(
|
return Scaffold(
|
||||||
key: ScaffoldMessengerKeys.bookmarks,
|
body: NestedScrollView(
|
||||||
child: Scaffold(
|
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||||
body: NestedScrollView(
|
SliverOverlapAbsorber(
|
||||||
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
SliverOverlapAbsorber(
|
sliver: SliverAppBar.large(
|
||||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
pinned: true,
|
||||||
sliver: SliverAppBar.large(
|
floating: true,
|
||||||
pinned: true,
|
centerTitle: false,
|
||||||
floating: true,
|
forceElevated: innerBoxIsScrolled,
|
||||||
centerTitle: false,
|
title: Row(
|
||||||
forceElevated: innerBoxIsScrolled,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
title: Row(
|
children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
Text(t.bookmarks.bookmarks),
|
||||||
children: [
|
if (bookmarks.readStatus == ReadStatus.read || bookmarks.readStatus == ReadStatus.unread)
|
||||||
Text(t.bookmarks.bookmarks),
|
Container(
|
||||||
if (bookmarks.readStatus == ReadStatus.read || bookmarks.readStatus == ReadStatus.unread)
|
margin: const EdgeInsets.only(left: 8),
|
||||||
Container(
|
padding: const EdgeInsets.symmetric(
|
||||||
margin: const EdgeInsets.only(left: 8),
|
horizontal: 8,
|
||||||
padding: const EdgeInsets.symmetric(
|
vertical: 4,
|
||||||
horizontal: 8,
|
),
|
||||||
vertical: 4,
|
decoration: BoxDecoration(
|
||||||
),
|
borderRadius: BorderRadius.circular(20),
|
||||||
decoration: BoxDecoration(
|
color: Theme.of(context).colorScheme.primaryContainer,
|
||||||
borderRadius: BorderRadius.circular(20),
|
),
|
||||||
color: Theme.of(context).colorScheme.primaryContainer,
|
child: Row(
|
||||||
),
|
children: [
|
||||||
child: Row(
|
Icon(
|
||||||
children: [
|
bookmarks.readStatus == ReadStatus.read
|
||||||
Icon(
|
? Icons.mark_email_read_rounded
|
||||||
bookmarks.readStatus == ReadStatus.read
|
: Icons.mark_as_unread_rounded,
|
||||||
? Icons.mark_email_read_rounded
|
size: 14,
|
||||||
: Icons.mark_as_unread_rounded,
|
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||||
size: 14,
|
),
|
||||||
|
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,
|
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),
|
floatingActionButton: FloatingActionButton(
|
||||||
child: const Icon(Icons.add_rounded),
|
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_form_modal.dart';
|
||||||
import 'package:linkdy/screens/bookmarks/ui/bookmark_item.dart';
|
import 'package:linkdy/screens/bookmarks/ui/bookmark_item.dart';
|
||||||
import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.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/enter_search_term_screen.dart';
|
||||||
|
import 'package:linkdy/widgets/no_data_screen.dart';
|
||||||
import 'package:linkdy/widgets/error_screen.dart';
|
import 'package:linkdy/widgets/error_screen.dart';
|
||||||
|
|
||||||
import 'package:linkdy/constants/global_keys.dart';
|
import 'package:linkdy/constants/global_keys.dart';
|
||||||
import 'package:linkdy/constants/enums.dart';
|
import 'package:linkdy/constants/enums.dart';
|
||||||
import 'package:linkdy/providers/router.provider.dart';
|
import 'package:linkdy/providers/router.provider.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/config/sizes.dart';
|
||||||
import 'package:linkdy/i18n/strings.g.dart';
|
import 'package:linkdy/i18n/strings.g.dart';
|
||||||
import 'package:linkdy/widgets/no_data_screen.dart';
|
|
||||||
|
|
||||||
class SearchBookmarksModal extends ConsumerWidget {
|
class SearchBookmarksModal extends ConsumerWidget {
|
||||||
final bool fullscreen;
|
final bool fullscreen;
|
||||||
@@ -24,6 +26,50 @@ class SearchBookmarksModal extends ConsumerWidget {
|
|||||||
required this.fullscreen,
|
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
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final provider = ref.watch(searchBookmarksProvider);
|
final provider = ref.watch(searchBookmarksProvider);
|
||||||
@@ -40,116 +86,114 @@ class SearchBookmarksModal extends ConsumerWidget {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ScaffoldMessenger(
|
return Scaffold(
|
||||||
key: ScaffoldMessengerKeys.search,
|
backgroundColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2),
|
||||||
child: Dialog.fullscreen(
|
appBar: AppBar(
|
||||||
child: Scaffold(
|
backgroundColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0),
|
||||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0.2),
|
toolbarHeight: 68,
|
||||||
appBar: AppBar(
|
leading: Padding(
|
||||||
backgroundColor: Theme.of(context).colorScheme.primaryContainer.withOpacity(0),
|
padding: const EdgeInsets.only(bottom: 8),
|
||||||
toolbarHeight: 68,
|
child: BackButton(
|
||||||
leading: Padding(
|
onPressed: () => ref.watch(routerProvider).pop(),
|
||||||
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),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ class FilteredBookmarksModel {
|
|||||||
List<Bookmark> bookmarks;
|
List<Bookmark> bookmarks;
|
||||||
int maxNumber;
|
int maxNumber;
|
||||||
bool loadingMore;
|
bool loadingMore;
|
||||||
|
Bookmark? selectedBookmark;
|
||||||
|
|
||||||
FilteredBookmarksModel({
|
FilteredBookmarksModel({
|
||||||
this.filteredBookmarksMode = FilteredBookmarksMode.shared,
|
this.filteredBookmarksMode = FilteredBookmarksMode.shared,
|
||||||
@@ -24,5 +25,6 @@ class FilteredBookmarksModel {
|
|||||||
required this.bookmarks,
|
required this.bookmarks,
|
||||||
this.maxNumber = 0,
|
this.maxNumber = 0,
|
||||||
this.loadingMore = false,
|
this.loadingMore = false,
|
||||||
|
this.selectedBookmark,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'package:linkdy/constants/global_keys.dart';
|
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
|
|
||||||
import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart';
|
import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart';
|
||||||
@@ -6,6 +5,12 @@ import 'package:linkdy/screens/bookmarks/provider/common_functions.dart';
|
|||||||
import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart';
|
import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart';
|
||||||
import 'package:linkdy/screens/filtered_bookmarks/model/filtered_bookmarks.model.dart';
|
import 'package:linkdy/screens/filtered_bookmarks/model/filtered_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/models/data/bookmarks.dart';
|
||||||
import 'package:linkdy/constants/enums.dart';
|
import 'package:linkdy/constants/enums.dart';
|
||||||
import 'package:linkdy/models/data/tags.dart';
|
import 'package:linkdy/models/data/tags.dart';
|
||||||
@@ -149,6 +154,16 @@ class FilteredBookmarks extends _$FilteredBookmarks {
|
|||||||
ref.notifyListeners();
|
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 {
|
Future<void> refresh() async {
|
||||||
if (state.filteredBookmarksMode == FilteredBookmarksMode.tag) {
|
if (state.filteredBookmarksMode == FilteredBookmarksMode.tag) {
|
||||||
await ref.read(
|
await ref.read(
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ final filteredBookmarksRequestLoadMoreProvider =
|
|||||||
|
|
||||||
typedef FilteredBookmarksRequestLoadMoreRef
|
typedef FilteredBookmarksRequestLoadMoreRef
|
||||||
= AutoDisposeFutureProviderRef<void>;
|
= AutoDisposeFutureProviderRef<void>;
|
||||||
String _$filteredBookmarksHash() => r'fdd67391d76f2bf8fd879b2f64a30d54922c4938';
|
String _$filteredBookmarksHash() => r'584c9ee245200f653d43b10d807860dcbac68ff5';
|
||||||
|
|
||||||
/// See also [FilteredBookmarks].
|
/// See also [FilteredBookmarks].
|
||||||
@ProviderFor(FilteredBookmarks)
|
@ProviderFor(FilteredBookmarks)
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
|
||||||
import 'package:linkdy/screens/bookmarks/ui/bookmark_form_modal.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/bookmark_item.dart';
|
||||||
import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart';
|
import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart';
|
||||||
import 'package:linkdy/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart';
|
import 'package:linkdy/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart';
|
||||||
|
import 'package:linkdy/screens/webview/ui/webview.dart';
|
||||||
import 'package:linkdy/widgets/error_screen.dart';
|
import 'package:linkdy/widgets/error_screen.dart';
|
||||||
import 'package:linkdy/widgets/no_data_screen.dart';
|
import 'package:linkdy/widgets/no_data_screen.dart';
|
||||||
|
|
||||||
|
import 'package:linkdy/config/sizes.dart';
|
||||||
import 'package:linkdy/constants/global_keys.dart';
|
import 'package:linkdy/constants/global_keys.dart';
|
||||||
import 'package:linkdy/models/data/tags.dart';
|
import 'package:linkdy/models/data/tags.dart';
|
||||||
import 'package:linkdy/constants/enums.dart';
|
import 'package:linkdy/constants/enums.dart';
|
||||||
@@ -16,7 +19,7 @@ import 'package:linkdy/providers/router.provider.dart';
|
|||||||
import 'package:linkdy/router/paths.dart';
|
import 'package:linkdy/router/paths.dart';
|
||||||
import 'package:linkdy/i18n/strings.g.dart';
|
import 'package:linkdy/i18n/strings.g.dart';
|
||||||
|
|
||||||
class FilteredBookmarksScreen extends ConsumerStatefulWidget {
|
class FilteredBookmarksScreen extends HookConsumerWidget {
|
||||||
final FilteredBookmarksMode filteredBookmarksMode;
|
final FilteredBookmarksMode filteredBookmarksMode;
|
||||||
final String? tagId;
|
final String? tagId;
|
||||||
final Tag? tag;
|
final Tag? tag;
|
||||||
@@ -29,44 +32,97 @@ class FilteredBookmarksScreen extends ConsumerStatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FilteredBookmarksScreenState createState() => FilteredBookmarksScreenState();
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
}
|
useEffect(
|
||||||
|
() {
|
||||||
class FilteredBookmarksScreenState extends ConsumerState<FilteredBookmarksScreen> {
|
ref.read(filteredBookmarksProvider.notifier).setMode(filteredBookmarksMode);
|
||||||
@override
|
if (filteredBookmarksMode == FilteredBookmarksMode.tag) {
|
||||||
void initState() {
|
if (tag == null && tagId == null) {
|
||||||
ref.read(filteredBookmarksProvider.notifier).setMode(widget.filteredBookmarksMode);
|
final router = ref.read(routerProvider);
|
||||||
if (widget.filteredBookmarksMode == FilteredBookmarksMode.tag) {
|
while (router.canPop() == true) {
|
||||||
if (widget.tag == null && widget.tagId == null) {
|
router.pop();
|
||||||
final router = ref.read(routerProvider);
|
}
|
||||||
while (router.canPop() == true) {
|
router.pushReplacement(RoutesPaths.bookmarks);
|
||||||
router.pop();
|
return;
|
||||||
|
}
|
||||||
|
if (tag != null) {
|
||||||
|
ref.read(filteredBookmarksProvider).tag = tag;
|
||||||
|
}
|
||||||
|
if (tagId != null) {
|
||||||
|
ref.read(filteredBookmarksProvider).tagId = tagId;
|
||||||
|
}
|
||||||
|
ref.read(tagBookmarksRequestProvider(tag, tagId, ref.read(filteredBookmarksProvider).limit));
|
||||||
|
} else {
|
||||||
|
ref.read(
|
||||||
|
filteredBookmarksRequestProvider(filteredBookmarksMode, ref.read(filteredBookmarksProvider).limit),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
router.pushReplacement(RoutesPaths.bookmarks);
|
return null;
|
||||||
return;
|
},
|
||||||
}
|
[filteredBookmarksMode, tagId, tag],
|
||||||
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),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.initState();
|
if (filteredBookmarksMode == FilteredBookmarksMode.tag && tag == null && tagId == null) {
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (widget.filteredBookmarksMode == FilteredBookmarksMode.tag && widget.tag == null && widget.tagId == null) {
|
|
||||||
return const Material();
|
return const Material();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ScaffoldMessenger(
|
||||||
|
key: ScaffoldMessengerKeys.filteredBookmarks,
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
if (constraints.maxWidth > Sizes.tabletBreakpoint) {
|
||||||
|
return Material(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: 2,
|
||||||
|
child: _List(
|
||||||
|
filteredBookmarksMode: filteredBookmarksMode,
|
||||||
|
tag: tag,
|
||||||
|
tabletMode: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (ref.watch(filteredBookmarksProvider).selectedBookmark != null)
|
||||||
|
Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: WebViewScreen(
|
||||||
|
bookmark: ref.watch(filteredBookmarksProvider).selectedBookmark!,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (ref.watch(filteredBookmarksProvider).selectedBookmark == null)
|
||||||
|
const Expanded(
|
||||||
|
flex: 3,
|
||||||
|
child: SizedBox(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return _List(
|
||||||
|
filteredBookmarksMode: filteredBookmarksMode,
|
||||||
|
tag: tag,
|
||||||
|
tabletMode: false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _List extends ConsumerWidget {
|
||||||
|
final bool tabletMode;
|
||||||
|
final FilteredBookmarksMode filteredBookmarksMode;
|
||||||
|
final Tag? tag;
|
||||||
|
|
||||||
|
const _List({
|
||||||
|
required this.filteredBookmarksMode,
|
||||||
|
this.tag,
|
||||||
|
required this.tabletMode,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final provider = ref.watch(filteredBookmarksProvider);
|
final provider = ref.watch(filteredBookmarksProvider);
|
||||||
|
|
||||||
final width = MediaQuery.of(context).size.width;
|
final width = MediaQuery.of(context).size.width;
|
||||||
@@ -82,10 +138,10 @@ class FilteredBookmarksScreenState extends ConsumerState<FilteredBookmarksScreen
|
|||||||
}
|
}
|
||||||
|
|
||||||
String title() {
|
String title() {
|
||||||
switch (widget.filteredBookmarksMode) {
|
switch (filteredBookmarksMode) {
|
||||||
case FilteredBookmarksMode.tag:
|
case FilteredBookmarksMode.tag:
|
||||||
return widget.tag != null
|
return tag != null
|
||||||
? "#${widget.tag!.name}"
|
? "#${tag!.name}"
|
||||||
: provider.tag != null
|
: provider.tag != null
|
||||||
? "#${provider.tag!.name}"
|
? "#${provider.tag!.name}"
|
||||||
: '';
|
: '';
|
||||||
@@ -102,7 +158,7 @@ class FilteredBookmarksScreenState extends ConsumerState<FilteredBookmarksScreen
|
|||||||
}
|
}
|
||||||
|
|
||||||
String noContent() {
|
String noContent() {
|
||||||
switch (widget.filteredBookmarksMode) {
|
switch (filteredBookmarksMode) {
|
||||||
case FilteredBookmarksMode.tag:
|
case FilteredBookmarksMode.tag:
|
||||||
return t.tags.filteredBookmarks.noBookmarksWithThisTag;
|
return t.tags.filteredBookmarks.noBookmarksWithThisTag;
|
||||||
|
|
||||||
@@ -117,85 +173,84 @@ class FilteredBookmarksScreenState extends ConsumerState<FilteredBookmarksScreen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ScaffoldMessenger(
|
return Scaffold(
|
||||||
key: ScaffoldMessengerKeys.filteredBookmarks,
|
body: NestedScrollView(
|
||||||
child: Scaffold(
|
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
||||||
body: NestedScrollView(
|
SliverOverlapAbsorber(
|
||||||
headerSliverBuilder: (context, innerBoxIsScrolled) => [
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
SliverOverlapAbsorber(
|
sliver: SliverAppBar.large(
|
||||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
pinned: true,
|
||||||
sliver: SliverAppBar.large(
|
floating: true,
|
||||||
pinned: true,
|
centerTitle: false,
|
||||||
floating: true,
|
forceElevated: innerBoxIsScrolled,
|
||||||
centerTitle: false,
|
title: Text(title()),
|
||||||
forceElevated: innerBoxIsScrolled,
|
|
||||||
title: Text(title()),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
body: SafeArea(
|
],
|
||||||
top: false,
|
body: SafeArea(
|
||||||
child: Builder(
|
top: false,
|
||||||
builder: (context) => RefreshIndicator(
|
child: Builder(
|
||||||
displacement: 120,
|
builder: (context) => RefreshIndicator(
|
||||||
onRefresh: () => ref.read(filteredBookmarksProvider.notifier).refresh(),
|
displacement: 120,
|
||||||
child: NotificationListener(
|
onRefresh: () => ref.read(filteredBookmarksProvider.notifier).refresh(),
|
||||||
onNotification: scrollListener,
|
child: NotificationListener(
|
||||||
child: CustomScrollView(
|
onNotification: scrollListener,
|
||||||
slivers: [
|
child: CustomScrollView(
|
||||||
SliverOverlapInjector(
|
slivers: [
|
||||||
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
SliverOverlapInjector(
|
||||||
|
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
|
||||||
|
),
|
||||||
|
if (provider.initialLoadStatus == LoadStatus.loading)
|
||||||
|
const SliverFillRemaining(
|
||||||
|
child: Center(child: CircularProgressIndicator()),
|
||||||
),
|
),
|
||||||
if (provider.initialLoadStatus == LoadStatus.loading)
|
if (provider.initialLoadStatus == LoadStatus.error)
|
||||||
const SliverFillRemaining(
|
SliverFillRemaining(
|
||||||
child: Center(child: CircularProgressIndicator()),
|
child: ErrorScreen(
|
||||||
|
error: t.bookmarks.cannotLoadBookmarks,
|
||||||
),
|
),
|
||||||
if (provider.initialLoadStatus == LoadStatus.error)
|
),
|
||||||
SliverFillRemaining(
|
if (provider.bookmarks.isEmpty)
|
||||||
child: ErrorScreen(
|
SliverFillRemaining(
|
||||||
error: t.bookmarks.cannotLoadBookmarks,
|
child: NoDataScreen(
|
||||||
),
|
message: noContent(),
|
||||||
),
|
),
|
||||||
if (provider.bookmarks.isEmpty)
|
),
|
||||||
SliverFillRemaining(
|
if (provider.bookmarks.isNotEmpty)
|
||||||
child: NoDataScreen(
|
SlidableAutoCloseBehavior(
|
||||||
message: noContent(),
|
child: SliverList.builder(
|
||||||
),
|
itemCount:
|
||||||
),
|
provider.loadingMore == true ? provider.bookmarks.length + 1 : provider.bookmarks.length,
|
||||||
if (provider.bookmarks.isNotEmpty)
|
itemBuilder: (context, index) {
|
||||||
SlidableAutoCloseBehavior(
|
if (provider.loadingMore == true && index == provider.bookmarks.length) {
|
||||||
child: SliverList.builder(
|
return const Padding(
|
||||||
itemCount: provider.loadingMore == true
|
padding: EdgeInsets.all(16),
|
||||||
? provider.bookmarks.length + 1
|
child: Center(
|
||||||
: provider.bookmarks.length,
|
child: CircularProgressIndicator(),
|
||||||
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(filteredBookmarksProvider.notifier).markAsReadUnread,
|
|
||||||
onDelete: (bookmark) => showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => DeleteBookmarkModal(
|
|
||||||
bookmark: bookmark,
|
|
||||||
onDelete: ref.read(filteredBookmarksProvider.notifier).deleteBookmark,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
onArchiveUnarchive: ref.read(filteredBookmarksProvider.notifier).archiveUnarchive,
|
|
||||||
onShareInternally: ref.read(filteredBookmarksProvider.notifier).shareUnshare,
|
|
||||||
onEdit: (b) => openBookmarkFormModal(context: context, width: width, bookmark: b),
|
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
),
|
return BookmarkItem(
|
||||||
|
bookmark: provider.bookmarks[index],
|
||||||
|
onSelect: (b) => ref.read(filteredBookmarksProvider.notifier).selectBookmark(b, width),
|
||||||
|
onReadUnread: ref.read(filteredBookmarksProvider.notifier).markAsReadUnread,
|
||||||
|
onDelete: (bookmark) => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => DeleteBookmarkModal(
|
||||||
|
bookmark: bookmark,
|
||||||
|
onDelete: ref.read(filteredBookmarksProvider.notifier).deleteBookmark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onArchiveUnarchive: ref.read(filteredBookmarksProvider.notifier).archiveUnarchive,
|
||||||
|
onShareInternally: ref.read(filteredBookmarksProvider.notifier).shareUnshare,
|
||||||
|
onEdit: (b) => openBookmarkFormModal(context: context, width: width, bookmark: b),
|
||||||
|
selected: provider.bookmarks[index] == provider.selectedBookmark,
|
||||||
|
tabletMode: tabletMode,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:webview_flutter/webview_flutter.dart';
|
import 'package:webview_flutter/webview_flutter.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
|
|
||||||
import 'package:linkdy/screens/webview/provider/webview.provider.dart';
|
import 'package:linkdy/screens/webview/provider/webview.provider.dart';
|
||||||
@@ -11,7 +12,7 @@ import 'package:linkdy/i18n/strings.g.dart';
|
|||||||
import 'package:linkdy/utils/copy_clipboard.dart';
|
import 'package:linkdy/utils/copy_clipboard.dart';
|
||||||
import 'package:linkdy/utils/open_url.dart';
|
import 'package:linkdy/utils/open_url.dart';
|
||||||
|
|
||||||
class WebViewScreen extends ConsumerStatefulWidget {
|
class WebViewScreen extends HookConsumerWidget {
|
||||||
final Bookmark bookmark;
|
final Bookmark bookmark;
|
||||||
|
|
||||||
const WebViewScreen({
|
const WebViewScreen({
|
||||||
@@ -20,18 +21,15 @@ class WebViewScreen extends ConsumerStatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
WebViewScreenState createState() => WebViewScreenState();
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
}
|
useEffect(
|
||||||
|
() {
|
||||||
|
ref.read(webViewProvider).webViewController.loadRequest(Uri.parse(bookmark.url!));
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
[bookmark],
|
||||||
|
);
|
||||||
|
|
||||||
class WebViewScreenState extends ConsumerState<WebViewScreen> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
ref.read(webViewProvider).webViewController.loadRequest(Uri.parse(widget.bookmark.url!));
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return ScaffoldMessenger(
|
return ScaffoldMessenger(
|
||||||
key: ScaffoldMessengerKeys.webview,
|
key: ScaffoldMessengerKeys.webview,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
@@ -41,12 +39,12 @@ class WebViewScreenState extends ConsumerState<WebViewScreen> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
widget.bookmark.title != "" ? widget.bookmark.title! : widget.bookmark.websiteTitle!,
|
bookmark.title != "" ? bookmark.title! : bookmark.websiteTitle!,
|
||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Text(
|
||||||
widget.bookmark.url!,
|
bookmark.url!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
@@ -104,7 +102,7 @@ class WebViewScreenState extends ConsumerState<WebViewScreen> {
|
|||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
onTap: () => Share.shareUri(Uri.parse(widget.bookmark.url!)),
|
onTap: () => Share.shareUri(Uri.parse(bookmark.url!)),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.share_rounded),
|
const Icon(Icons.share_rounded),
|
||||||
@@ -116,7 +114,7 @@ class WebViewScreenState extends ConsumerState<WebViewScreen> {
|
|||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
onTap: () => copyToClipboard(
|
onTap: () => copyToClipboard(
|
||||||
key: ScaffoldMessengerKeys.webview,
|
key: ScaffoldMessengerKeys.webview,
|
||||||
value: widget.bookmark.url!,
|
value: bookmark.url!,
|
||||||
successMessage: t.webview.linkCopiedClipboard,
|
successMessage: t.webview.linkCopiedClipboard,
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -128,7 +126,7 @@ class WebViewScreenState extends ConsumerState<WebViewScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
onTap: () => openUrl(widget.bookmark.url!),
|
onTap: () => openUrl(bookmark.url!),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.open_in_browser_rounded),
|
const Icon(Icons.open_in_browser_rounded),
|
||||||
|
|||||||
16
pubspec.lock
16
pubspec.lock
@@ -390,6 +390,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.0"
|
version: "5.1.0"
|
||||||
|
flutter_hooks:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_hooks
|
||||||
|
sha256: cde36b12f7188c85286fba9b38cc5a902e7279f36dd676967106c041dc9dde70
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.20.5"
|
||||||
flutter_launcher_icons:
|
flutter_launcher_icons:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@@ -493,6 +501,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.1"
|
version: "2.3.1"
|
||||||
|
hooks_riverpod:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: hooks_riverpod
|
||||||
|
sha256: "758b07eba336e3cbacbd81dba481f2228a14102083fdde07045e8514e8054c49"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.10"
|
||||||
hotreloader:
|
hotreloader:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ dependencies:
|
|||||||
http: ^1.2.0
|
http: ^1.2.0
|
||||||
flutter_slidable: ^3.0.1
|
flutter_slidable: ^3.0.1
|
||||||
webview_flutter: ^4.7.0
|
webview_flutter: ^4.7.0
|
||||||
|
flutter_hooks: ^0.20.5
|
||||||
|
hooks_riverpod: ^2.4.10
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.8
|
build_runner: ^2.4.8
|
||||||
|
|||||||
Reference in New Issue
Block a user