Bug fixes

This commit is contained in:
Juan Gilsanz Polo
2024-03-24 02:46:30 +01:00
parent 75aa31ad11
commit 822c65c4e6
3 changed files with 297 additions and 263 deletions

View File

@@ -57,124 +57,112 @@ class BookmarkItem extends ConsumerWidget {
padding: tabletMode ? const EdgeInsets.symmetric(horizontal: 8) : const EdgeInsets.all(0), padding: tabletMode ? const EdgeInsets.symmetric(horizontal: 8) : const EdgeInsets.all(0),
child: ClipRRect( child: ClipRRect(
borderRadius: tabletMode ? BorderRadius.circular(28) : BorderRadius.circular(0), borderRadius: tabletMode ? BorderRadius.circular(28) : BorderRadius.circular(0),
child: ContextMenuWidget( child: Builder(
menuProvider: (request) => Menu( builder: (context) {
children: [ return ContextMenuWidget(
MenuAction( menuProvider: (request) => Menu(
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),
children: [ children: [
MenuAction( MenuAction(
callback: () => Future.delayed(_durationTime).then((value) => onShareInternally(bookmark)), callback: () => Future.delayed(_durationTime).then((value) => onReadUnread(bookmark)),
title: bookmark.shared == true title: bookmark.unread == true
? t.bookmarks.bookmarkOptions.unshareInternally ? t.bookmarks.bookmarkOptions.markAsRead
: t.bookmarks.bookmarkOptions.shareInternally, : t.bookmarks.bookmarkOptions.markAsUnread,
image: MenuImage.icon(Icons.input_rounded), image: MenuImage.icon(
bookmark.unread == true ? Icons.mark_email_read_rounded : Icons.mark_as_unread_rounded,
),
), ),
MenuAction( MenuAction(
callback: () => Future.delayed(_durationTime).then( callback: () => Future.delayed(_durationTime).then((value) => onArchiveUnarchive(bookmark)),
(value) => Share.shareUri(Uri.parse(bookmark.url!)), 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(), child: Material(
MenuAction( color: selected && tabletMode
callback: () => Future.delayed(_durationTime).then((value) => onEdit(bookmark)), ? Theme.of(context).colorScheme.primaryContainer
title: t.bookmarks.bookmarkOptions.edit, : tileBackgroundColor ?? Theme.of(context).colorScheme.surface,
image: MenuImage.icon(Icons.edit_rounded), child: InkWell(
), onTap: () => onSelect(bookmark),
MenuAction( child: Padding(
callback: () => Future.delayed(_durationTime).then((value) => onDelete(bookmark)), padding: const EdgeInsets.all(16),
title: t.bookmarks.bookmarkOptions.delete, child: Column(
image: MenuImage.icon(Icons.delete_rounded), crossAxisAlignment: CrossAxisAlignment.start,
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(
children: [ children: [
if (ref.watch(appStatusProvider).showFavicon == true) Row(
Padding( children: [
padding: const EdgeInsets.only(right: 8), if (ref.watch(appStatusProvider).showFavicon == true)
child: ref.watch(faviconStoreProvider).loadingFavicons == true Padding(
? ClipRRect( padding: const EdgeInsets.only(right: 8),
borderRadius: BorderRadius.circular(4), child: ref.watch(faviconStoreProvider).loadingFavicons == true
child: Skeletonizer( ? ClipRRect(
enabled: true, borderRadius: BorderRadius.circular(4),
ignoreContainers: true, child: Skeletonizer(
child: Container( enabled: true,
width: 16, ignoreContainers: true,
height: 16, child: Container(
color: Colors.black, width: 16,
), height: 16,
), color: Colors.black,
)
: Builder(
builder: (context) {
final faviconItem = ref
.watch(faviconStoreProvider)
.favicons
.where((f) => f.url == bookmark.url!)
.toList();
if (faviconItem.isEmpty) return const SizedBox();
if (faviconItem[0].isSvg == true) {
return SvgPicture.network(
faviconItem[0].favicon,
width: 16,
height: 16,
placeholderBuilder: (context) => ClipRRect(
borderRadius: BorderRadius.circular(4),
child: Skeletonizer(
enabled: true,
ignoreContainers: true,
child: Container(
width: 16,
height: 16,
color: Colors.black,
),
),
), ),
); ),
} else { )
return Image.network( : Builder(
faviconItem[0].favicon, builder: (context) {
width: 16, final faviconItem = ref
height: 16, .watch(faviconStoreProvider)
loadingBuilder: (context, child, loadingProgress) { .favicons
if (loadingProgress != null) { .where((f) => f.url == bookmark.url!)
return ClipRRect( .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), borderRadius: BorderRadius.circular(4),
child: Skeletonizer( child: Skeletonizer(
enabled: true, enabled: true,
@@ -185,154 +173,176 @@ class BookmarkItem extends ConsumerWidget {
color: Colors.black, color: Colors.black,
), ),
), ),
); ),
} );
return child; } else {
}, return Image.network(
); faviconItem[0].favicon,
} width: 16,
}, height: 16,
), loadingBuilder: (context, child, loadingProgress) {
), if (loadingProgress != null) {
Expanded( return ClipRRect(
child: Text( borderRadius: BorderRadius.circular(4),
validateStrings(bookmark.title, bookmark.websiteTitle), child: Skeletonizer(
maxLines: 1, enabled: true,
overflow: TextOverflow.ellipsis, ignoreContainers: true,
textAlign: TextAlign.left, child: Container(
style: TextStyle( width: 16,
fontSize: 16, height: 16,
fontWeight: FontWeight.w500, color: Colors.black,
color: Theme.of(context).colorScheme.onSurface, ),
),
);
}
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,
),
),
],
],
),
],
), ),
), ),
), );
), },
), ),
), ),
); );

View File

@@ -48,12 +48,12 @@ class WebViewScreen extends HookConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
bookmark.title != "" ? bookmark.title! : bookmark.websiteTitle!, bookmark.title ?? bookmark.websiteTitle ?? "Website",
style: const TextStyle(fontSize: 14), style: const TextStyle(fontSize: 14),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
bookmark.url!, bookmark.url ?? "",
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant, color: Theme.of(context).colorScheme.onSurfaceVariant,

View File

@@ -75,9 +75,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -97,9 +99,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -119,9 +123,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -139,9 +145,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -157,9 +165,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -179,9 +189,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -197,9 +209,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -212,9 +226,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -224,9 +240,11 @@ class ApiClientService {
return const ApiResponse(successful: true); return const ApiResponse(successful: true);
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -242,9 +260,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -266,9 +286,11 @@ class ApiClientService {
return const ApiResponse(successful: true); return const ApiResponse(successful: true);
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
@@ -284,9 +306,11 @@ class ApiClientService {
); );
} on DioException { } on DioException {
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (e, stackTrace) { } on FormatException catch (e, stackTrace) {
Sentry.captureException(e, stackTrace: stackTrace); Sentry.captureException(e, stackTrace: stackTrace);
return const ApiResponse(successful: false); return const ApiResponse(successful: false);
} catch (_) {
return const ApiResponse(successful: false);
} }
} }
} }