From 822c65c4e66fbf8cd5391dd79e8f21d6f39ca9f2 Mon Sep 17 00:00:00 2001 From: Juan Gilsanz Polo Date: Sun, 24 Mar 2024 02:46:30 +0100 Subject: [PATCH] Bug fixes --- lib/screens/bookmarks/ui/bookmark_item.dart | 508 ++++++++++---------- lib/screens/webview/ui/webview.dart | 4 +- lib/services/api_client.dart | 48 +- 3 files changed, 297 insertions(+), 263 deletions(-) diff --git a/lib/screens/bookmarks/ui/bookmark_item.dart b/lib/screens/bookmarks/ui/bookmark_item.dart index 80018e5..0f3c9e9 100644 --- a/lib/screens/bookmarks/ui/bookmark_item.dart +++ b/lib/screens/bookmarks/ui/bookmark_item.dart @@ -57,124 +57,112 @@ class BookmarkItem extends ConsumerWidget { padding: tabletMode ? const EdgeInsets.symmetric(horizontal: 8) : const EdgeInsets.all(0), child: ClipRRect( borderRadius: tabletMode ? BorderRadius.circular(28) : BorderRadius.circular(0), - child: ContextMenuWidget( - menuProvider: (request) => Menu( - children: [ - MenuAction( - callback: () => Future.delayed(_durationTime).then((value) => onReadUnread(bookmark)), - title: bookmark.unread == true - ? t.bookmarks.bookmarkOptions.markAsRead - : t.bookmarks.bookmarkOptions.markAsUnread, - image: MenuImage.icon( - bookmark.unread == true ? Icons.mark_email_read_rounded : Icons.mark_as_unread_rounded, - ), - ), - MenuAction( - callback: () => Future.delayed(_durationTime).then((value) => onArchiveUnarchive(bookmark)), - title: bookmark.isArchived == true - ? t.bookmarks.bookmarkOptions.unarchive - : t.bookmarks.bookmarkOptions.archive, - image: MenuImage.icon( - bookmark.isArchived == true ? Icons.unarchive_rounded : Icons.archive_rounded, - ), - ), - Menu( - title: t.bookmarks.bookmarkOptions.shareOptions, - image: MenuImage.icon(Icons.share_rounded), + child: Builder( + builder: (context) { + return ContextMenuWidget( + menuProvider: (request) => Menu( children: [ MenuAction( - callback: () => Future.delayed(_durationTime).then((value) => onShareInternally(bookmark)), - title: bookmark.shared == true - ? t.bookmarks.bookmarkOptions.unshareInternally - : t.bookmarks.bookmarkOptions.shareInternally, - image: MenuImage.icon(Icons.input_rounded), + callback: () => Future.delayed(_durationTime).then((value) => onReadUnread(bookmark)), + title: bookmark.unread == true + ? t.bookmarks.bookmarkOptions.markAsRead + : t.bookmarks.bookmarkOptions.markAsUnread, + image: MenuImage.icon( + bookmark.unread == true ? Icons.mark_email_read_rounded : Icons.mark_as_unread_rounded, + ), ), MenuAction( - callback: () => Future.delayed(_durationTime).then( - (value) => Share.shareUri(Uri.parse(bookmark.url!)), + callback: () => Future.delayed(_durationTime).then((value) => onArchiveUnarchive(bookmark)), + title: bookmark.isArchived == true + ? t.bookmarks.bookmarkOptions.unarchive + : t.bookmarks.bookmarkOptions.archive, + image: MenuImage.icon( + bookmark.isArchived == true ? Icons.unarchive_rounded : Icons.archive_rounded, ), - title: t.bookmarks.bookmarkOptions.shareThirdPartyApp, - image: MenuImage.icon(Icons.output_rounded), + ), + Menu( + title: t.bookmarks.bookmarkOptions.shareOptions, + image: MenuImage.icon(Icons.share_rounded), + children: [ + MenuAction( + callback: () => Future.delayed(_durationTime).then((value) => onShareInternally(bookmark)), + title: bookmark.shared == true + ? t.bookmarks.bookmarkOptions.unshareInternally + : t.bookmarks.bookmarkOptions.shareInternally, + image: MenuImage.icon(Icons.input_rounded), + ), + MenuAction( + callback: () { + final box = context.findRenderObject() as RenderBox?; + Future.delayed(_durationTime).then( + (value) => Share.share( + bookmark.url!, + sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size, + ), + ); + }, + title: t.bookmarks.bookmarkOptions.shareThirdPartyApp, + image: MenuImage.icon(Icons.output_rounded), + ), + ], + ), + MenuSeparator(), + MenuAction( + callback: () => Future.delayed(_durationTime).then((value) => onEdit(bookmark)), + title: t.bookmarks.bookmarkOptions.edit, + image: MenuImage.icon(Icons.edit_rounded), + ), + MenuAction( + callback: () => Future.delayed(_durationTime).then((value) => onDelete(bookmark)), + title: t.bookmarks.bookmarkOptions.delete, + image: MenuImage.icon(Icons.delete_rounded), + attributes: const MenuActionAttributes(destructive: true), ), ], ), - MenuSeparator(), - MenuAction( - callback: () => Future.delayed(_durationTime).then((value) => onEdit(bookmark)), - title: t.bookmarks.bookmarkOptions.edit, - image: MenuImage.icon(Icons.edit_rounded), - ), - MenuAction( - callback: () => Future.delayed(_durationTime).then((value) => onDelete(bookmark)), - title: t.bookmarks.bookmarkOptions.delete, - image: MenuImage.icon(Icons.delete_rounded), - attributes: const MenuActionAttributes(destructive: true), - ), - ], - ), - child: Material( - color: selected && tabletMode - ? Theme.of(context).colorScheme.primaryContainer - : tileBackgroundColor ?? Theme.of(context).colorScheme.surface, - child: InkWell( - onTap: () => onSelect(bookmark), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( + child: Material( + color: selected && tabletMode + ? Theme.of(context).colorScheme.primaryContainer + : tileBackgroundColor ?? Theme.of(context).colorScheme.surface, + child: InkWell( + onTap: () => onSelect(bookmark), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (ref.watch(appStatusProvider).showFavicon == true) - Padding( - padding: const EdgeInsets.only(right: 8), - child: ref.watch(faviconStoreProvider).loadingFavicons == true - ? ClipRRect( - borderRadius: BorderRadius.circular(4), - child: Skeletonizer( - enabled: true, - ignoreContainers: true, - child: Container( - width: 16, - height: 16, - color: Colors.black, - ), - ), - ) - : Builder( - builder: (context) { - final faviconItem = ref - .watch(faviconStoreProvider) - .favicons - .where((f) => f.url == bookmark.url!) - .toList(); - if (faviconItem.isEmpty) return const SizedBox(); - if (faviconItem[0].isSvg == true) { - return SvgPicture.network( - faviconItem[0].favicon, - width: 16, - height: 16, - placeholderBuilder: (context) => ClipRRect( - borderRadius: BorderRadius.circular(4), - child: Skeletonizer( - enabled: true, - ignoreContainers: true, - child: Container( - width: 16, - height: 16, - color: Colors.black, - ), - ), + Row( + children: [ + if (ref.watch(appStatusProvider).showFavicon == true) + Padding( + padding: const EdgeInsets.only(right: 8), + child: ref.watch(faviconStoreProvider).loadingFavicons == true + ? ClipRRect( + borderRadius: BorderRadius.circular(4), + child: Skeletonizer( + enabled: true, + ignoreContainers: true, + child: Container( + width: 16, + height: 16, + color: Colors.black, ), - ); - } else { - return Image.network( - faviconItem[0].favicon, - width: 16, - height: 16, - loadingBuilder: (context, child, loadingProgress) { - if (loadingProgress != null) { - return ClipRRect( + ), + ) + : 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, @@ -185,154 +173,176 @@ class BookmarkItem extends ConsumerWidget { color: Colors.black, ), ), - ); - } - 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, + ), + ); + } 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; + }, + ); + } + }, + ), + ), + 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, + ), + ), ), + ], + ), + 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, + ), + ), + ], + ], + ), ], ), - 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, - ), - ), - ], - ], - ), - ], + ), ), ), - ), - ), + ); + }, ), ), ); diff --git a/lib/screens/webview/ui/webview.dart b/lib/screens/webview/ui/webview.dart index 4a8f1fe..2c8d770 100644 --- a/lib/screens/webview/ui/webview.dart +++ b/lib/screens/webview/ui/webview.dart @@ -48,12 +48,12 @@ class WebViewScreen extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - bookmark.title != "" ? bookmark.title! : bookmark.websiteTitle!, + bookmark.title ?? bookmark.websiteTitle ?? "Website", style: const TextStyle(fontSize: 14), ), const SizedBox(height: 4), Text( - bookmark.url!, + bookmark.url ?? "", style: TextStyle( fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant, diff --git a/lib/services/api_client.dart b/lib/services/api_client.dart index 68f255a..521e8c9 100644 --- a/lib/services/api_client.dart +++ b/lib/services/api_client.dart @@ -75,9 +75,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -97,9 +99,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -119,9 +123,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -139,9 +145,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -157,9 +165,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -179,9 +189,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -197,9 +209,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -212,9 +226,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -224,9 +240,11 @@ class ApiClientService { return const ApiResponse(successful: true); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -242,9 +260,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -266,9 +286,11 @@ class ApiClientService { return const ApiResponse(successful: true); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } @@ -284,9 +306,11 @@ class ApiClientService { ); } on DioException { return const ApiResponse(successful: false); - } catch (e, stackTrace) { + } on FormatException catch (e, stackTrace) { Sentry.captureException(e, stackTrace: stackTrace); return const ApiResponse(successful: false); + } catch (_) { + return const ApiResponse(successful: false); } } }