From f330c2f6b57079685a4411085d077e5d9ba47697 Mon Sep 17 00:00:00 2001 From: Juan Gilsanz Polo Date: Thu, 3 Apr 2025 22:05:30 +0200 Subject: [PATCH] Improved favicons load --- lib/constants/urls.dart | 2 + lib/providers/app_status.provider.dart | 5 - .../provider/bookmarks.provider.dart | 4 +- .../provider/favicon_loader.provider.dart | 94 ------------------- .../provider/favicon_loader.provider.g.dart | 25 ----- .../provider/search_bookmarks.provider.dart | 4 +- lib/screens/bookmarks/ui/bookmarks.dart | 2 +- .../bookmarks/ui/search_bookmarks.dart | 2 +- .../provider/filtered_bookmarks.provider.dart | 8 +- .../ui/filtered_bookmarks.dart | 2 +- .../ui => widgets}/bookmark_item.dart | 73 +++----------- 11 files changed, 24 insertions(+), 197 deletions(-) delete mode 100644 lib/screens/bookmarks/provider/favicon_loader.provider.dart delete mode 100644 lib/screens/bookmarks/provider/favicon_loader.provider.g.dart rename lib/{screens/bookmarks/ui => widgets}/bookmark_item.dart (79%) diff --git a/lib/constants/urls.dart b/lib/constants/urls.dart index 9db5980..cd50c89 100644 --- a/lib/constants/urls.dart +++ b/lib/constants/urls.dart @@ -5,4 +5,6 @@ class Urls { static const playStoreLink = "https://play.google.com/store/apps/details?id=com.jgeek00.linkdy&pcampaignid=web_share"; static const linkdingRepo = "https://github.com/sissbruecker/linkding"; static const support = "https://appsupport.jgeek00.com"; + static gstatic(url) => + "https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=${url}&size=16"; } diff --git a/lib/providers/app_status.provider.dart b/lib/providers/app_status.provider.dart index 61ef40b..8021f9d 100644 --- a/lib/providers/app_status.provider.dart +++ b/lib/providers/app_status.provider.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; -import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; import 'package:linkdy/constants/shared_preferences_keys.dart'; import 'package:linkdy/providers/shared_preferences.provider.dart'; import 'package:linkdy/constants/enums.dart'; @@ -59,7 +58,6 @@ class AppStatus extends _$AppStatus { void setShowFavicon(bool value) { state.showFavicon = value; ref.read(sharedPreferencesProvider).setBool(SharedPreferencesKeys.showFavicon, value); - ref.read(faviconStoreProvider.notifier).clearFavicons(); ref.notifyListeners(); } @@ -89,8 +87,5 @@ ThemeMode selectedTheme(SelectedThemeRef ref) { case SelectedTheme.dark: return ThemeMode.dark; - - default: - return ThemeMode.light; } } diff --git a/lib/screens/bookmarks/provider/bookmarks.provider.dart b/lib/screens/bookmarks/provider/bookmarks.provider.dart index d771285..06687aa 100644 --- a/lib/screens/bookmarks/provider/bookmarks.provider.dart +++ b/lib/screens/bookmarks/provider/bookmarks.provider.dart @@ -4,7 +4,6 @@ import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/screens/webview/ui/webview.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'; @@ -35,7 +34,6 @@ FutureOr bookmarksRequest( ); if (result.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); ref.read(bookmarksProvider).bookmarks = result.content!.results!; ref.read(bookmarksProvider).maxNumber = result.content!.count!; ref.read(bookmarksProvider).currentPage = 0; @@ -65,7 +63,7 @@ FutureOr bookmarksRequestLoadMore(BookmarksRequestLoadMoreRef ref) async { ); if (result.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); + // ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); provider.bookmarks = [...provider.bookmarks, ...result.content!.results!]; provider.maxNumber = result.content!.count!; provider.currentPage = provider.currentPage + 1; diff --git a/lib/screens/bookmarks/provider/favicon_loader.provider.dart b/lib/screens/bookmarks/provider/favicon_loader.provider.dart deleted file mode 100644 index 62081d0..0000000 --- a/lib/screens/bookmarks/provider/favicon_loader.provider.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:favicon/favicon.dart'; -import 'package:riverpod_annotation/riverpod_annotation.dart'; - -import 'package:linkdy/screens/bookmarks/model/favicon_loader.model.dart'; - -import 'package:linkdy/models/favicon_item.dart'; -import 'package:linkdy/models/data/bookmarks.dart'; - -part 'favicon_loader.provider.g.dart'; - -// @riverpod -// FutureOr fetchFavicon(FetchFaviconRef ref, String bookmarkUrl) async { -// final exists = ref.watch(faviconStoreProvider).favicons.where((favicon) => favicon.url == bookmarkUrl).toList(); -// if (exists.isNotEmpty) { -// return exists[0]; -// } - -// final faviconResult = await FaviconFinder.getBest(bookmarkUrl); -// if (faviconResult == null) { -// return null; -// } - -// final result = await http.get(Uri.parse(faviconResult.url)); -// if (result.statusCode == 200) { -// final faviconItem = FaviconItem( -// url: bookmarkUrl, -// favicon: faviconResult.url.contains("svg") ? result.body : base64.encode(result.bodyBytes), -// isSvg: faviconResult.url.contains("svg"), -// ); -// ref.read(faviconStoreProvider).favicons.add(faviconItem); -// return faviconItem; -// } else { -// return null; -// } -// } - -@Riverpod(keepAlive: true) -class FaviconStore extends _$FaviconStore { - @override - FaviconLoaderModel build() { - return FaviconLoaderModel( - favicons: [], - ); - } - - void clearFavicons() { - state.favicons = []; - } - - void loadFavicons(List bookmarks) async { - if (state.loadingFavicons == true) return; - - state.loadingFavicons = true; - ref.notifyListeners(); - - final mappedSaved = state.favicons.map((e) => e.url); - final notExist = bookmarks.map((b) => b.url!).where((b) => !mappedSaved.contains(b)).toList(); - - final favicons = await compute( - (message) => Future.wait( - message.map( - (e) { - try { - return FaviconFinder.getBest(e); - } catch (_) { - return Future.delayed(Duration.zero); - } - }, - ), - ), - notExist, - ); - - final faviconUrls = favicons - .asMap() - .entries - .map( - (e) => e.value != null - ? FaviconItem( - url: notExist[e.key], - favicon: e.value!.url, - isSvg: e.value!.url.contains('svg'), - ) - : null, - ) - .toList(); - faviconUrls.removeWhere((v) => v == null); - - state.favicons = [...state.favicons, ...List.from(faviconUrls)]; - state.loadingFavicons = false; - ref.notifyListeners(); - } -} diff --git a/lib/screens/bookmarks/provider/favicon_loader.provider.g.dart b/lib/screens/bookmarks/provider/favicon_loader.provider.g.dart deleted file mode 100644 index 031fe1e..0000000 --- a/lib/screens/bookmarks/provider/favicon_loader.provider.g.dart +++ /dev/null @@ -1,25 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'favicon_loader.provider.dart'; - -// ************************************************************************** -// RiverpodGenerator -// ************************************************************************** - -String _$faviconStoreHash() => r'5575f5daff34748e6cae0143c8633cbbe19b6009'; - -/// See also [FaviconStore]. -@ProviderFor(FaviconStore) -final faviconStoreProvider = - NotifierProvider.internal( - FaviconStore.new, - name: r'faviconStoreProvider', - debugGetCreateSourceHash: - const bool.fromEnvironment('dart.vm.product') ? null : _$faviconStoreHash, - dependencies: null, - allTransitiveDependencies: null, -); - -typedef _$FaviconStore = Notifier; -// ignore_for_file: type=lint -// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member diff --git a/lib/screens/bookmarks/provider/search_bookmarks.provider.dart b/lib/screens/bookmarks/provider/search_bookmarks.provider.dart index b9c2c35..f7358a5 100644 --- a/lib/screens/bookmarks/provider/search_bookmarks.provider.dart +++ b/lib/screens/bookmarks/provider/search_bookmarks.provider.dart @@ -3,7 +3,6 @@ import 'package:go_router/go_router.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/screens/webview/ui/webview.dart'; -import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart'; import 'package:linkdy/screens/bookmarks/provider/common_functions.dart'; import 'package:linkdy/screens/bookmarks/model/search_bookmarks.model.dart'; @@ -31,7 +30,7 @@ FutureOr fetchSearchBookmarks(FetchSearchBookmarksRef ref, int limit) asyn ); if (result.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); + // ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); ref.read(searchBookmarksProvider).bookmarks = result.content!.results!; ref.read(searchBookmarksProvider).maxNumber = result.content!.count!; ref.read(searchBookmarksProvider).currentPage = 0; @@ -56,7 +55,6 @@ FutureOr fetchSearchBookmarksLoadMore(FetchSearchBookmarksLoadMoreRef ref) ); if (result.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); provider.bookmarks = [...provider.bookmarks, ...result.content!.results!]; provider.maxNumber = result.content!.count!; provider.currentPage = provider.currentPage + 1; diff --git a/lib/screens/bookmarks/ui/bookmarks.dart b/lib/screens/bookmarks/ui/bookmarks.dart index 89619ef..20eaf1f 100644 --- a/lib/screens/bookmarks/ui/bookmarks.dart +++ b/lib/screens/bookmarks/ui/bookmarks.dart @@ -3,7 +3,7 @@ import 'package:hooks_riverpod/hooks_riverpod.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/widgets/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'; diff --git a/lib/screens/bookmarks/ui/search_bookmarks.dart b/lib/screens/bookmarks/ui/search_bookmarks.dart index 10fd760..4d7ff4e 100644 --- a/lib/screens/bookmarks/ui/search_bookmarks.dart +++ b/lib/screens/bookmarks/ui/search_bookmarks.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:linkdy/screens/bookmarks/provider/search_bookmarks.provider.dart'; import 'package:linkdy/screens/bookmarks/ui/bookmark_form_modal.dart'; -import 'package:linkdy/screens/bookmarks/ui/bookmark_item.dart'; +import 'package:linkdy/widgets/bookmark_item.dart'; import 'package:linkdy/screens/bookmarks/ui/delete_bookmark_modal.dart'; import 'package:linkdy/widgets/enter_search_term_screen.dart'; import 'package:linkdy/widgets/no_data_screen.dart'; diff --git a/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart b/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart index f5f0152..92b1f4c 100644 --- a/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart +++ b/lib/screens/filtered_bookmarks/provider/filtered_bookmarks.provider.dart @@ -3,7 +3,6 @@ import 'package:go_router/go_router.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:linkdy/screens/webview/ui/webview.dart'; -import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; import 'package:linkdy/screens/bookmarks/provider/common_functions.dart'; import 'package:linkdy/screens/bookmarks/provider/bookmarks.provider.dart'; import 'package:linkdy/screens/filtered_bookmarks/model/filtered_bookmarks.model.dart'; @@ -36,7 +35,7 @@ FutureOr tagBookmarksRequest(TagBookmarksRequestRef ref, Tag? tag, String? ); if (bookmarksResult.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(bookmarksResult.content!.results!); + // ref.read(faviconStoreProvider.notifier).loadFavicons(bookmarksResult.content!.results!); ref.read(filteredBookmarksProvider).bookmarks = bookmarksResult.content!.results!; ref.read(filteredBookmarksProvider).maxNumber = bookmarksResult.content!.count!; if (tag == null) ref.read(filteredBookmarksProvider).tag = tagResult!.content!; @@ -63,7 +62,6 @@ FutureOr tagBookmarksRequestLoadMore(FilteredBookmarksRequestLoadMoreRef r ); if (result.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); provider.bookmarks = [...provider.bookmarks, ...result.content!.results!]; provider.maxNumber = result.content!.count!; provider.currentPage = provider.currentPage + 1; @@ -85,7 +83,7 @@ FutureOr filteredBookmarksRequest(FilteredBookmarksRequestRef ref, Filtere ); if (bookmarksResult.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(bookmarksResult.content!.results!); + // ref.read(faviconStoreProvider.notifier).loadFavicons(bookmarksResult.content!.results!); ref.read(filteredBookmarksProvider).bookmarks = bookmarksResult.content!.results!; ref.read(filteredBookmarksProvider).maxNumber = bookmarksResult.content!.count!; ref.read(filteredBookmarksProvider).currentPage = 0; @@ -117,7 +115,7 @@ FutureOr filteredBookmarksRequestLoadMore(TagBookmarksRequestLoadMoreRef r ); if (result.successful == true) { - ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); + // ref.read(faviconStoreProvider.notifier).loadFavicons(result.content!.results!); provider.bookmarks = [...provider.bookmarks, ...result.content!.results!]; provider.maxNumber = result.content!.count!; provider.currentPage = provider.currentPage + 1; diff --git a/lib/screens/filtered_bookmarks/ui/filtered_bookmarks.dart b/lib/screens/filtered_bookmarks/ui/filtered_bookmarks.dart index 9156ad5..8d07644 100644 --- a/lib/screens/filtered_bookmarks/ui/filtered_bookmarks.dart +++ b/lib/screens/filtered_bookmarks/ui/filtered_bookmarks.dart @@ -3,7 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.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_item.dart'; +import 'package:linkdy/widgets/bookmark_item.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/widgets/error_screen.dart'; diff --git a/lib/screens/bookmarks/ui/bookmark_item.dart b/lib/widgets/bookmark_item.dart similarity index 79% rename from lib/screens/bookmarks/ui/bookmark_item.dart rename to lib/widgets/bookmark_item.dart index e766641..1a5da0e 100644 --- a/lib/screens/bookmarks/ui/bookmark_item.dart +++ b/lib/widgets/bookmark_item.dart @@ -1,16 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:linkdy/constants/urls.dart'; import 'package:share_plus/share_plus.dart'; import 'package:skeletonizer/skeletonizer.dart'; -import 'package:flutter_svg/flutter_svg.dart'; - -import 'package:linkdy/screens/bookmarks/provider/favicon_loader.provider.dart'; +import 'package:super_context_menu/super_context_menu.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/utils/date_to_string.dart'; -import 'package:super_context_menu/super_context_menu.dart'; // Wait until the context menu close animation animation finishes Duration _durationTime = const Duration(milliseconds: 150); @@ -136,8 +134,13 @@ class BookmarkItem extends ConsumerWidget { if (ref.watch(appStatusProvider).showFavicon == true) Padding( padding: const EdgeInsets.only(right: 8), - child: ref.watch(faviconStoreProvider).loadingFavicons == true - ? ClipRRect( + child: Image.network( + Urls.gstatic(bookmark.url), + width: 16, + height: 16, + loadingBuilder: (context, child, loadingProgress) { + if (loadingProgress != null) { + return ClipRRect( borderRadius: BorderRadius.circular(4), child: Skeletonizer( enabled: true, @@ -148,59 +151,11 @@ class BookmarkItem extends ConsumerWidget { 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(