From c82794d79e125d59708fd5f651a9d389d925f41b Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Wed, 21 Feb 2024 14:52:00 +0200 Subject: [PATCH 1/8] feat(attachments): add error handlers --- .../lib/attachments/queue.dart | 14 ++++++++++- .../lib/src/attachments_queue.dart | 14 ++++++++++- .../lib/src/attachments_queue_table.dart | 7 ++---- .../lib/src/attachments_service.dart | 5 ++++ .../lib/src/syncing_service.dart | 24 ++++++++++++++++++- 5 files changed, 56 insertions(+), 8 deletions(-) diff --git a/demos/supabase-todolist/lib/attachments/queue.dart b/demos/supabase-todolist/lib/attachments/queue.dart index f18fb2a3..661a2888 100644 --- a/demos/supabase-todolist/lib/attachments/queue.dart +++ b/demos/supabase-todolist/lib/attachments/queue.dart @@ -11,9 +11,21 @@ import 'package:powersync_flutter_demo/models/schema.dart'; late final PhotoAttachmentQueue attachmentQueue; final remoteStorage = SupabaseStorageAdapter(); +/// Function to handle errors when downloading attachments +/// Return true if you want to ignore the error and remove the attachment from the queue +Future onDownloadError(Attachment attachment, Object exception) { + if (exception.toString().contains('Object not found')) { + return Future.value(true); + } + return Future.value(false); +} + class PhotoAttachmentQueue extends AbstractAttachmentQueue { PhotoAttachmentQueue(db, remoteStorage) - : super(db: db, remoteStorage: remoteStorage); + : super( + db: db, + remoteStorage: remoteStorage, + onDownloadError: onDownloadError); @override init() async { diff --git a/packages/powersync_attachments_helper/lib/src/attachments_queue.dart b/packages/powersync_attachments_helper/lib/src/attachments_queue.dart index 8dcaa0a1..e9e525ab 100644 --- a/packages/powersync_attachments_helper/lib/src/attachments_queue.dart +++ b/packages/powersync_attachments_helper/lib/src/attachments_queue.dart @@ -24,16 +24,28 @@ abstract class AbstractAttachmentQueue { final LocalStorageAdapter localStorage = LocalStorageAdapter(); String attachmentsQueueTableName; + /// Function to handle errors when downloading attachments + /// Return true if you want to ignore attachment + Future Function(Attachment attachment, Object exception)? + onDownloadError; + + /// Function to handle errors when uploading attachments + /// Return true if you want to ignore attachment + Future Function(Attachment attachment, Object exception)? onUploadError; + AbstractAttachmentQueue( {required this.db, required this.remoteStorage, this.attachmentDirectoryName = 'attachments', this.attachmentsQueueTableName = defaultAttachmentsQueueTableName, + this.onDownloadError, + this.onUploadError, performInitialSync = true}) { attachmentsService = AttachmentsService( db, localStorage, attachmentDirectoryName, attachmentsQueueTableName); syncingService = SyncingService( - db, remoteStorage, localStorage, attachmentsService, getLocalUri); + db, remoteStorage, localStorage, attachmentsService, getLocalUri, + onDownloadError: onDownloadError, onUploadError: onUploadError); } /// Create watcher to get list of ID's from a table to be used for syncing in the attachment queue. diff --git a/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart b/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart index f1bf5a0d..914ad9d0 100644 --- a/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart +++ b/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart @@ -64,11 +64,8 @@ class Attachment { /// 1. Attachment to be uploaded /// 2. Attachment to be downloaded /// 3. Attachment to be deleted -enum AttachmentState { - queuedUpload, - queuedDownload, - queuedDelete, -} +/// 3. Attachment to be ignored +enum AttachmentState { queuedUpload, queuedDownload, queuedDelete, ignore } class AttachmentsQueueTable extends Table { AttachmentsQueueTable( diff --git a/packages/powersync_attachments_helper/lib/src/attachments_service.dart b/packages/powersync_attachments_helper/lib/src/attachments_service.dart index 3c9a3e34..f0b9a4c2 100644 --- a/packages/powersync_attachments_helper/lib/src/attachments_service.dart +++ b/packages/powersync_attachments_helper/lib/src/attachments_service.dart @@ -23,6 +23,11 @@ class AttachmentsService { Future deleteAttachment(String id) async => db.execute('DELETE FROM $table WHERE id = ?', [id]); + ///Set the state of the attachment to ignore. + Future ignoreAttachment(String id) async => db.execute( + 'UPDATE $table SET state = ${AttachmentState.ignore.index} WHERE id = ?', + [id]); + /// Get the attachment from the attachment queue using an ID. Future getAttachment(String id) async => db.getOptional('SELECT * FROM $table WHERE id = ?', [id]).then((row) { diff --git a/packages/powersync_attachments_helper/lib/src/syncing_service.dart b/packages/powersync_attachments_helper/lib/src/syncing_service.dart index 595b4643..34f4ff70 100644 --- a/packages/powersync_attachments_helper/lib/src/syncing_service.dart +++ b/packages/powersync_attachments_helper/lib/src/syncing_service.dart @@ -15,9 +15,14 @@ class SyncingService { final LocalStorageAdapter localStorage; final AttachmentsService attachmentsService; final Function getLocalUri; + final Future Function(Attachment attachment, Object exception)? + onDownloadError; + final Future Function(Attachment attachment, Object exception)? + onUploadError; SyncingService(this.db, this.remoteStorage, this.localStorage, - this.attachmentsService, this.getLocalUri); + this.attachmentsService, this.getLocalUri, + {this.onDownloadError, this.onUploadError}); /// Upload attachment from local storage and to remote storage /// then remove it from the queue. @@ -44,6 +49,14 @@ class SyncingService { } log.severe('Upload attachment error for attachment $attachment', e); + if (onUploadError != null) { + bool shouldIgnoreAttachment = await onUploadError!(attachment, e); + if (shouldIgnoreAttachment) { + log.info('Attachment with ID ${attachment.id} has been ignored', e); + await attachmentsService.ignoreAttachment(attachment.id); + } + } + return; } } @@ -63,6 +76,15 @@ class SyncingService { await attachmentsService.deleteAttachment(attachment.id); return; } catch (e) { + if (onDownloadError != null) { + bool shouldIgnoreAttachment = await onDownloadError!(attachment, e); + if (shouldIgnoreAttachment) { + log.info('Attachment with ID ${attachment.id} has been ignored', e); + await attachmentsService.ignoreAttachment(attachment.id); + return; + } + } + log.severe('Download attachment error for attachment $attachment', e); return; } From 3c19b25a0f0aca2114af94fc66dbce479926e40b Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Wed, 21 Feb 2024 15:38:32 +0200 Subject: [PATCH 2/8] fix: lint issue --- demos/supabase-edge-function-auth/lib/widgets/login_page.dart | 2 +- demos/supabase-edge-function-auth/lib/widgets/signup_page.dart | 2 +- demos/supabase-simple-chat/lib/pages/login_page.dart | 2 +- demos/supabase-todolist/lib/attachments/photo_widget.dart | 2 +- demos/supabase-todolist/lib/widgets/lists_page.dart | 2 +- demos/supabase-todolist/lib/widgets/login_page.dart | 2 +- demos/supabase-todolist/lib/widgets/query_widget.dart | 2 +- demos/supabase-todolist/lib/widgets/signup_page.dart | 2 +- demos/supabase-todolist/lib/widgets/todo_list_page.dart | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/demos/supabase-edge-function-auth/lib/widgets/login_page.dart b/demos/supabase-edge-function-auth/lib/widgets/login_page.dart index f4926361..ea493fac 100644 --- a/demos/supabase-edge-function-auth/lib/widgets/login_page.dart +++ b/demos/supabase-edge-function-auth/lib/widgets/login_page.dart @@ -34,7 +34,7 @@ class _LoginPageState extends State { await Supabase.instance.client.auth.signInWithPassword( email: _usernameController.text, password: _passwordController.text); - if (mounted) { + if (context.mounted) { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => homePage, )); diff --git a/demos/supabase-edge-function-auth/lib/widgets/signup_page.dart b/demos/supabase-edge-function-auth/lib/widgets/signup_page.dart index d2e4219e..2f9150b4 100644 --- a/demos/supabase-edge-function-auth/lib/widgets/signup_page.dart +++ b/demos/supabase-edge-function-auth/lib/widgets/signup_page.dart @@ -34,7 +34,7 @@ class _SignupPageState extends State { final response = await Supabase.instance.client.auth.signUp( email: _usernameController.text, password: _passwordController.text); - if (mounted) { + if (context.mounted) { if (response.session != null) { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => homePage, diff --git a/demos/supabase-simple-chat/lib/pages/login_page.dart b/demos/supabase-simple-chat/lib/pages/login_page.dart index b973f09f..2d62f6ef 100644 --- a/demos/supabase-simple-chat/lib/pages/login_page.dart +++ b/demos/supabase-simple-chat/lib/pages/login_page.dart @@ -37,7 +37,7 @@ class LoginPageState extends State { } catch (_) { context.showErrorSnackBar(message: unexpectedErrorMessage); } - if (mounted) { + if (context.mounted) { setState(() { _isLoading = true; }); diff --git a/demos/supabase-todolist/lib/attachments/photo_widget.dart b/demos/supabase-todolist/lib/attachments/photo_widget.dart index afa523ef..c6ad8e52 100644 --- a/demos/supabase-todolist/lib/attachments/photo_widget.dart +++ b/demos/supabase-todolist/lib/attachments/photo_widget.dart @@ -54,7 +54,7 @@ class _PhotoWidgetState extends State { Widget takePhotoButton = ElevatedButton( onPressed: () async { final camera = await setupCamera(); - if (!mounted) return; + if (!context.mounted) return; if (camera == null) { const snackBar = SnackBar( diff --git a/demos/supabase-todolist/lib/widgets/lists_page.dart b/demos/supabase-todolist/lib/widgets/lists_page.dart index 933fabc1..e31c2fc8 100644 --- a/demos/supabase-todolist/lib/widgets/lists_page.dart +++ b/demos/supabase-todolist/lib/widgets/lists_page.dart @@ -61,7 +61,7 @@ class _ListsWidgetState extends State { super.initState(); final stream = TodoList.watchListsWithStats(); _subscription = stream.listen((data) { - if (!mounted) { + if (!context.mounted) { return; } setState(() { diff --git a/demos/supabase-todolist/lib/widgets/login_page.dart b/demos/supabase-todolist/lib/widgets/login_page.dart index 9402cbbe..f54f09da 100644 --- a/demos/supabase-todolist/lib/widgets/login_page.dart +++ b/demos/supabase-todolist/lib/widgets/login_page.dart @@ -34,7 +34,7 @@ class _LoginPageState extends State { await Supabase.instance.client.auth.signInWithPassword( email: _usernameController.text, password: _passwordController.text); - if (mounted) { + if (context.mounted) { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => listsPage, )); diff --git a/demos/supabase-todolist/lib/widgets/query_widget.dart b/demos/supabase-todolist/lib/widgets/query_widget.dart index b9a285dd..fed1bd78 100644 --- a/demos/supabase-todolist/lib/widgets/query_widget.dart +++ b/demos/supabase-todolist/lib/widgets/query_widget.dart @@ -46,7 +46,7 @@ class QueryWidgetState extends State { _subscription?.cancel(); final stream = db.watch(_query); _subscription = stream.listen((data) { - if (!mounted) { + if (!context.mounted) { return; } setState(() { diff --git a/demos/supabase-todolist/lib/widgets/signup_page.dart b/demos/supabase-todolist/lib/widgets/signup_page.dart index d2e4219e..2f9150b4 100644 --- a/demos/supabase-todolist/lib/widgets/signup_page.dart +++ b/demos/supabase-todolist/lib/widgets/signup_page.dart @@ -34,7 +34,7 @@ class _SignupPageState extends State { final response = await Supabase.instance.client.auth.signUp( email: _usernameController.text, password: _passwordController.text); - if (mounted) { + if (context.mounted) { if (response.session != null) { Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => homePage, diff --git a/demos/supabase-todolist/lib/widgets/todo_list_page.dart b/demos/supabase-todolist/lib/widgets/todo_list_page.dart index e8cebba5..e36e1867 100644 --- a/demos/supabase-todolist/lib/widgets/todo_list_page.dart +++ b/demos/supabase-todolist/lib/widgets/todo_list_page.dart @@ -62,7 +62,7 @@ class TodoListWidgetState extends State { super.initState(); final stream = widget.list.watchItems(); _subscription = stream.listen((data) { - if (!mounted) { + if (!context.mounted) { return; } setState(() { From c50dc1a2c5e501c982d4c2d7d6faee47fb2bbbd5 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Wed, 21 Feb 2024 15:40:54 +0200 Subject: [PATCH 3/8] chore: version bump --- demos/supabase-anonymous-auth/pubspec.lock | 48 +++++++++++++++--- .../supabase-edge-function-auth/pubspec.lock | 48 +++++++++++++++--- demos/supabase-simple-chat/pubspec.lock | 48 +++++++++++++++--- demos/supabase-todolist/pubspec.lock | 50 +++++++++++++++---- .../powersync_attachments_helper/CHANGELOG.md | 5 ++ .../powersync_attachments_helper/pubspec.yaml | 2 +- 6 files changed, 167 insertions(+), 34 deletions(-) diff --git a/demos/supabase-anonymous-auth/pubspec.lock b/demos/supabase-anonymous-auth/pubspec.lock index dc77f1e4..1ea193c4 100644 --- a/demos/supabase-anonymous-auth/pubspec.lock +++ b/demos/supabase-anonymous-auth/pubspec.lock @@ -176,6 +176,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -196,26 +220,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: transitive description: @@ -228,10 +252,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: "direct main" description: @@ -588,6 +612,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" web: dependency: transitive description: diff --git a/demos/supabase-edge-function-auth/pubspec.lock b/demos/supabase-edge-function-auth/pubspec.lock index dc77f1e4..1ea193c4 100644 --- a/demos/supabase-edge-function-auth/pubspec.lock +++ b/demos/supabase-edge-function-auth/pubspec.lock @@ -176,6 +176,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -196,26 +220,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: transitive description: @@ -228,10 +252,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: "direct main" description: @@ -588,6 +612,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" web: dependency: transitive description: diff --git a/demos/supabase-simple-chat/pubspec.lock b/demos/supabase-simple-chat/pubspec.lock index 0d9a16ca..51c3adb3 100644 --- a/demos/supabase-simple-chat/pubspec.lock +++ b/demos/supabase-simple-chat/pubspec.lock @@ -192,6 +192,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -212,26 +236,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: transitive description: @@ -244,10 +268,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: "direct main" description: @@ -636,6 +660,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" web: dependency: transitive description: diff --git a/demos/supabase-todolist/pubspec.lock b/demos/supabase-todolist/pubspec.lock index 35936ea5..01a91ed4 100644 --- a/demos/supabase-todolist/pubspec.lock +++ b/demos/supabase-todolist/pubspec.lock @@ -264,6 +264,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -284,26 +308,26 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: transitive description: @@ -316,10 +340,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_provider: dependency: "direct main" description: @@ -421,7 +445,7 @@ packages: path: "../../packages/powersync_attachments_helper" relative: true source: path - version: "0.2.0" + version: "0.2.1" realtime_client: dependency: transitive description: @@ -707,6 +731,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.dev" + source: hosted + version: "13.0.0" web: dependency: transitive description: diff --git a/packages/powersync_attachments_helper/CHANGELOG.md b/packages/powersync_attachments_helper/CHANGELOG.md index c59f0d09..4f8ebdf8 100644 --- a/packages/powersync_attachments_helper/CHANGELOG.md +++ b/packages/powersync_attachments_helper/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.2.1 + +- Added `onUploadError` as an optional function that can be set when setting up the queue to handle upload errors +- Added `onDownloadError` as an optional function that can be set when setting up the queue to handle upload errors + ## 0.2.0 - Potentially BREAKING CHANGE for users who rely on multiple attachment queues. diff --git a/packages/powersync_attachments_helper/pubspec.yaml b/packages/powersync_attachments_helper/pubspec.yaml index 9656994d..b216afae 100644 --- a/packages/powersync_attachments_helper/pubspec.yaml +++ b/packages/powersync_attachments_helper/pubspec.yaml @@ -1,6 +1,6 @@ name: powersync_attachments_helper description: A helper library for handling attachments when using PowerSync. -version: 0.2.0 +version: 0.2.1 repository: https://github.com/powersync-ja/powersync.dart homepage: https://www.powersync.com/ environment: From c986c3895cc312df5f4b3c19f2995cec8c4a882e Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Wed, 21 Feb 2024 18:04:47 +0200 Subject: [PATCH 4/8] chore: pr reverts --- demos/supabase-todolist/lib/attachments/queue.dart | 6 +++--- .../lib/src/attachments_queue_table.dart | 4 ++-- .../lib/src/attachments_service.dart | 2 +- .../lib/src/syncing_service.dart | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/demos/supabase-todolist/lib/attachments/queue.dart b/demos/supabase-todolist/lib/attachments/queue.dart index 661a2888..2ea16ca7 100644 --- a/demos/supabase-todolist/lib/attachments/queue.dart +++ b/demos/supabase-todolist/lib/attachments/queue.dart @@ -12,12 +12,12 @@ late final PhotoAttachmentQueue attachmentQueue; final remoteStorage = SupabaseStorageAdapter(); /// Function to handle errors when downloading attachments -/// Return true if you want to ignore the error and remove the attachment from the queue +/// Return false if you want to archive the attachment Future onDownloadError(Attachment attachment, Object exception) { if (exception.toString().contains('Object not found')) { - return Future.value(true); + return Future.value(false); } - return Future.value(false); + return Future.value(true); } class PhotoAttachmentQueue extends AbstractAttachmentQueue { diff --git a/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart b/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart index 914ad9d0..0a9b0904 100644 --- a/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart +++ b/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart @@ -64,8 +64,8 @@ class Attachment { /// 1. Attachment to be uploaded /// 2. Attachment to be downloaded /// 3. Attachment to be deleted -/// 3. Attachment to be ignored -enum AttachmentState { queuedUpload, queuedDownload, queuedDelete, ignore } +/// 3. Attachment to be archived +enum AttachmentState { queuedUpload, queuedDownload, queuedDelete, archived } class AttachmentsQueueTable extends Table { AttachmentsQueueTable( diff --git a/packages/powersync_attachments_helper/lib/src/attachments_service.dart b/packages/powersync_attachments_helper/lib/src/attachments_service.dart index f0b9a4c2..a337ad87 100644 --- a/packages/powersync_attachments_helper/lib/src/attachments_service.dart +++ b/packages/powersync_attachments_helper/lib/src/attachments_service.dart @@ -25,7 +25,7 @@ class AttachmentsService { ///Set the state of the attachment to ignore. Future ignoreAttachment(String id) async => db.execute( - 'UPDATE $table SET state = ${AttachmentState.ignore.index} WHERE id = ?', + 'UPDATE $table SET state = ${AttachmentState.archived.index} WHERE id = ?', [id]); /// Get the attachment from the attachment queue using an ID. diff --git a/packages/powersync_attachments_helper/lib/src/syncing_service.dart b/packages/powersync_attachments_helper/lib/src/syncing_service.dart index 34f4ff70..853a1504 100644 --- a/packages/powersync_attachments_helper/lib/src/syncing_service.dart +++ b/packages/powersync_attachments_helper/lib/src/syncing_service.dart @@ -26,7 +26,7 @@ class SyncingService { /// Upload attachment from local storage and to remote storage /// then remove it from the queue. - /// If duplicate of the file is found uploading is ignored and + /// If duplicate of the file is found uploading is archived and /// the attachment is removed from the queue. Future uploadAttachment(Attachment attachment) async { if (attachment.localUri == null) { @@ -50,9 +50,9 @@ class SyncingService { log.severe('Upload attachment error for attachment $attachment', e); if (onUploadError != null) { - bool shouldIgnoreAttachment = await onUploadError!(attachment, e); - if (shouldIgnoreAttachment) { - log.info('Attachment with ID ${attachment.id} has been ignored', e); + bool shouldRetry = await onUploadError!(attachment, e); + if (!shouldRetry) { + log.info('Attachment with ID ${attachment.id} has been archived', e); await attachmentsService.ignoreAttachment(attachment.id); } } @@ -77,9 +77,9 @@ class SyncingService { return; } catch (e) { if (onDownloadError != null) { - bool shouldIgnoreAttachment = await onDownloadError!(attachment, e); - if (shouldIgnoreAttachment) { - log.info('Attachment with ID ${attachment.id} has been ignored', e); + bool shouldRetry = await onDownloadError!(attachment, e); + if (!shouldRetry) { + log.info('Attachment with ID ${attachment.id} has been archived', e); await attachmentsService.ignoreAttachment(attachment.id); return; } From fb4f32fdc94450974b0007cbb135c479c7c7e77a Mon Sep 17 00:00:00 2001 From: Dominic Gunther Bauer <46312751+DominicGBauer@users.noreply.github.com> Date: Thu, 22 Feb 2024 08:29:52 +0200 Subject: [PATCH 5/8] Update packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart Co-authored-by: stevensJourney <51082125+stevensJourney@users.noreply.github.com> --- .../lib/src/attachments_queue_table.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart b/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart index 0a9b0904..05570d1f 100644 --- a/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart +++ b/packages/powersync_attachments_helper/lib/src/attachments_queue_table.dart @@ -64,7 +64,7 @@ class Attachment { /// 1. Attachment to be uploaded /// 2. Attachment to be downloaded /// 3. Attachment to be deleted -/// 3. Attachment to be archived +/// 4. Attachment to be archived enum AttachmentState { queuedUpload, queuedDownload, queuedDelete, archived } class AttachmentsQueueTable extends Table { From 7d561244f25a3ca298ba8e50445115cf4d4475cb Mon Sep 17 00:00:00 2001 From: Dominic Gunther Bauer <46312751+DominicGBauer@users.noreply.github.com> Date: Thu, 22 Feb 2024 08:29:59 +0200 Subject: [PATCH 6/8] Update demos/supabase-todolist/lib/attachments/queue.dart Co-authored-by: stevensJourney <51082125+stevensJourney@users.noreply.github.com> --- demos/supabase-todolist/lib/attachments/queue.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/supabase-todolist/lib/attachments/queue.dart b/demos/supabase-todolist/lib/attachments/queue.dart index 2ea16ca7..07a4b995 100644 --- a/demos/supabase-todolist/lib/attachments/queue.dart +++ b/demos/supabase-todolist/lib/attachments/queue.dart @@ -13,11 +13,11 @@ final remoteStorage = SupabaseStorageAdapter(); /// Function to handle errors when downloading attachments /// Return false if you want to archive the attachment -Future onDownloadError(Attachment attachment, Object exception) { +Future onDownloadError(Attachment attachment, Object exception) async { if (exception.toString().contains('Object not found')) { - return Future.value(false); + return false; } - return Future.value(true); + return true; } class PhotoAttachmentQueue extends AbstractAttachmentQueue { From d60eb25b63dc6cfbaccc9b9b44d0bd949c28f785 Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Thu, 22 Feb 2024 10:12:30 +0200 Subject: [PATCH 7/8] chore: improve demo --- .../ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../lib/attachments/photo_widget.dart | 25 +++++++++++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/demos/supabase-todolist/ios/Runner.xcodeproj/project.pbxproj b/demos/supabase-todolist/ios/Runner.xcodeproj/project.pbxproj index d274f929..16636b7a 100644 --- a/demos/supabase-todolist/ios/Runner.xcodeproj/project.pbxproj +++ b/demos/supabase-todolist/ios/Runner.xcodeproj/project.pbxproj @@ -155,7 +155,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/demos/supabase-todolist/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/demos/supabase-todolist/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db..5e31d3d3 100644 --- a/demos/supabase-todolist/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/demos/supabase-todolist/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ { @@ -35,10 +38,14 @@ class _PhotoWidgetState extends State { return _ResolvedPhotoState(photoPath: null, fileExists: false); } photoPath = await attachmentQueue.getLocalUri('$photoId.jpg'); + final row = await attachmentQueue.db + .get('SELECT * FROM attachments_queue WHERE id = ?', [photoId]); + Attachment attachment = Attachment.fromRow(row); bool fileExists = await File(photoPath).exists(); - return _ResolvedPhotoState(photoPath: photoPath, fileExists: fileExists); + return _ResolvedPhotoState( + photoPath: photoPath, fileExists: fileExists, attachment: attachment); } @override @@ -84,6 +91,20 @@ class _PhotoWidgetState extends State { String? filePath = data.photoPath; bool fileIsDownloading = !data.fileExists; + bool fileArchived = + data.attachment?.state == AttachmentState.archived.index; + + if (fileArchived) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text("Unavailable"), + const SizedBox(height: 8), + takePhotoButton + ], + ); + } if (fileIsDownloading) { return const Text("Downloading..."); From d258242348c4739fa58f2255654fa5726604169f Mon Sep 17 00:00:00 2001 From: DominicGBauer Date: Thu, 22 Feb 2024 10:26:48 +0200 Subject: [PATCH 8/8] fix: image issue --- .../lib/attachments/photo_widget.dart | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/demos/supabase-todolist/lib/attachments/photo_widget.dart b/demos/supabase-todolist/lib/attachments/photo_widget.dart index f14aa948..f034ef5b 100644 --- a/demos/supabase-todolist/lib/attachments/photo_widget.dart +++ b/demos/supabase-todolist/lib/attachments/photo_widget.dart @@ -38,14 +38,20 @@ class _PhotoWidgetState extends State { return _ResolvedPhotoState(photoPath: null, fileExists: false); } photoPath = await attachmentQueue.getLocalUri('$photoId.jpg'); - final row = await attachmentQueue.db - .get('SELECT * FROM attachments_queue WHERE id = ?', [photoId]); - Attachment attachment = Attachment.fromRow(row); bool fileExists = await File(photoPath).exists(); + final row = await attachmentQueue.db + .getOptional('SELECT * FROM attachments_queue WHERE id = ?', [photoId]); + + if (row != null) { + Attachment attachment = Attachment.fromRow(row); + return _ResolvedPhotoState( + photoPath: photoPath, fileExists: fileExists, attachment: attachment); + } + return _ResolvedPhotoState( - photoPath: photoPath, fileExists: fileExists, attachment: attachment); + photoPath: photoPath, fileExists: fileExists, attachment: null); } @override