From ff62ed268bcbaa9fa3cb1bc77fb2d7055fe9a016 Mon Sep 17 00:00:00 2001 From: Nomad-Dev Date: Fri, 18 Apr 2025 05:54:32 +0200 Subject: [PATCH 1/4] feat(attachments): allow watchIds without fileExtension --- demos/supabase-todolist-drift/lib/attachments/queue.dart | 2 +- demos/supabase-todolist/lib/attachments/queue.dart | 2 +- packages/powersync_attachments_helper/README.md | 2 +- .../example/getting_started.dart | 2 +- .../lib/src/attachments_queue.dart | 4 ++-- .../lib/src/syncing_service.dart | 7 ++++--- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/demos/supabase-todolist-drift/lib/attachments/queue.dart b/demos/supabase-todolist-drift/lib/attachments/queue.dart index 63d903ac..230cb855 100644 --- a/demos/supabase-todolist-drift/lib/attachments/queue.dart +++ b/demos/supabase-todolist-drift/lib/attachments/queue.dart @@ -68,7 +68,7 @@ class PhotoAttachmentQueue extends AbstractAttachmentQueue { } @override - StreamSubscription watchIds({String fileExtension = 'jpg'}) { + StreamSubscription watchIds({String? fileExtension}) { log.info('Watching photos in $todosTable...'); return db.watch(''' SELECT photo_id FROM $todosTable diff --git a/demos/supabase-todolist/lib/attachments/queue.dart b/demos/supabase-todolist/lib/attachments/queue.dart index 2a8dd9ca..d2fc4f64 100644 --- a/demos/supabase-todolist/lib/attachments/queue.dart +++ b/demos/supabase-todolist/lib/attachments/queue.dart @@ -68,7 +68,7 @@ class PhotoAttachmentQueue extends AbstractAttachmentQueue { } @override - StreamSubscription watchIds({String fileExtension = 'jpg'}) { + StreamSubscription watchIds({String? fileExtension}) { log.info('Watching photos in $todosTable...'); return db.watch(''' SELECT photo_id FROM $todosTable diff --git a/packages/powersync_attachments_helper/README.md b/packages/powersync_attachments_helper/README.md index dbd65bef..5de3a4ef 100644 --- a/packages/powersync_attachments_helper/README.md +++ b/packages/powersync_attachments_helper/README.md @@ -62,7 +62,7 @@ class PhotoAttachmentQueue extends AbstractAttachmentQueue { // This watcher will handle adding items to the queue based on // a users table element receiving a photoId @override - StreamSubscription watchIds({String fileExtension = 'jpg'}) { + StreamSubscription watchIds({String? fileExtension}) { return db.watch(''' SELECT photo_id FROM users WHERE photo_id IS NOT NULL diff --git a/packages/powersync_attachments_helper/example/getting_started.dart b/packages/powersync_attachments_helper/example/getting_started.dart index 037046f0..858be3df 100644 --- a/packages/powersync_attachments_helper/example/getting_started.dart +++ b/packages/powersync_attachments_helper/example/getting_started.dart @@ -46,7 +46,7 @@ class PhotoAttachmentQueue extends AbstractAttachmentQueue { } @override - StreamSubscription watchIds({String fileExtension = 'jpg'}) { + StreamSubscription watchIds({String? fileExtension}) { return db.watch(''' SELECT photo_id FROM users WHERE photo_id IS NOT NULL diff --git a/packages/powersync_attachments_helper/lib/src/attachments_queue.dart b/packages/powersync_attachments_helper/lib/src/attachments_queue.dart index 08dd48ce..ad5fc20a 100644 --- a/packages/powersync_attachments_helper/lib/src/attachments_queue.dart +++ b/packages/powersync_attachments_helper/lib/src/attachments_queue.dart @@ -59,7 +59,7 @@ abstract class AbstractAttachmentQueue { /// Create watcher to get list of ID's from a table to be used for syncing in the attachment queue. /// Set the file extension if you are using a different file type - StreamSubscription watchIds({String fileExtension = 'jpg'}); + StreamSubscription watchIds({String? fileExtension}); /// Create a function to save files using the attachment queue Future saveFile(String fileId, int size); @@ -82,7 +82,7 @@ abstract class AbstractAttachmentQueue { } } - watchIds(); + watchIds(fileExtension: 'jpg'); syncingService.watchAttachments(); syncingService.startPeriodicSync(intervalInMinutes); diff --git a/packages/powersync_attachments_helper/lib/src/syncing_service.dart b/packages/powersync_attachments_helper/lib/src/syncing_service.dart index 04897329..c055839a 100644 --- a/packages/powersync_attachments_helper/lib/src/syncing_service.dart +++ b/packages/powersync_attachments_helper/lib/src/syncing_service.dart @@ -165,11 +165,12 @@ class SyncingService { } /// Process ID's to be included in the attachment queue. - Future processIds(List ids, String fileExtension) async { + Future processIds(List ids, String? fileExtension) async { List attachments = List.empty(growable: true); for (String id in ids) { - String path = await getLocalUri('$id.$fileExtension'); + String filename = fileExtension != null ? '$id.$fileExtension' : id; + String path = await getLocalUri(filename); File file = File(path); bool fileExists = await file.exists(); @@ -180,7 +181,7 @@ class SyncingService { log.info('Adding $id to queue'); attachments.add(Attachment( id: id, - filename: '$id.$fileExtension', + filename: filename, state: AttachmentState.queuedDownload.index)); } From 3773ac8fdef035ae4b7e316a8d73003e720503bb Mon Sep 17 00:00:00 2001 From: Nomad-Dev Date: Fri, 18 Apr 2025 06:11:57 +0200 Subject: [PATCH 2/4] refactor(attachments): make fileExtension part of queue initialization --- .../lib/src/attachments_queue.dart | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/powersync_attachments_helper/lib/src/attachments_queue.dart b/packages/powersync_attachments_helper/lib/src/attachments_queue.dart index ad5fc20a..f8e18ba0 100644 --- a/packages/powersync_attachments_helper/lib/src/attachments_queue.dart +++ b/packages/powersync_attachments_helper/lib/src/attachments_queue.dart @@ -41,6 +41,10 @@ abstract class AbstractAttachmentQueue { /// when the attachment queue is initialized. List? subdirectories; + /// File extension to be used for the attachments queue + /// Can be left null if no extension is used or if extension is part of the filename + String? fileExtension; + AbstractAttachmentQueue( {required this.db, required this.remoteStorage, @@ -49,7 +53,8 @@ abstract class AbstractAttachmentQueue { this.onDownloadError, this.onUploadError, this.intervalInMinutes = 5, - this.subdirectories}) { + this.subdirectories, + this.fileExtension}) { attachmentsService = AttachmentsService( db, localStorage, attachmentDirectoryName, attachmentsQueueTableName); syncingService = SyncingService( @@ -82,7 +87,7 @@ abstract class AbstractAttachmentQueue { } } - watchIds(fileExtension: 'jpg'); + watchIds(fileExtension: fileExtension); syncingService.watchAttachments(); syncingService.startPeriodicSync(intervalInMinutes); From 08713f65de9648eeeb34d8808f5b3b2c073d41d0 Mon Sep 17 00:00:00 2001 From: Nomad-Dev Date: Fri, 18 Apr 2025 06:21:48 +0200 Subject: [PATCH 3/4] fix(attachments): ensure directory existence on local storage before saving file --- .../lib/src/local_storage_adapter.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/powersync_attachments_helper/lib/src/local_storage_adapter.dart b/packages/powersync_attachments_helper/lib/src/local_storage_adapter.dart index f12d3f35..b8a997e4 100644 --- a/packages/powersync_attachments_helper/lib/src/local_storage_adapter.dart +++ b/packages/powersync_attachments_helper/lib/src/local_storage_adapter.dart @@ -5,6 +5,7 @@ import 'package:path_provider/path_provider.dart'; /// Storage adapter for local storage class LocalStorageAdapter { Future saveFile(String fileUri, Uint8List data) async { + await makeDir(fileUri); final file = File(fileUri); return await file.writeAsBytes(data); } @@ -36,6 +37,7 @@ class LocalStorageAdapter { } Future copyFile(String sourceUri, String targetUri) async { + await makeDir(targetUri); File file = File(sourceUri); await file.copy(targetUri); } From 405056c5320d58216fce93c38a243f324264961b Mon Sep 17 00:00:00 2001 From: Nomad-Dev Date: Sat, 19 Apr 2025 14:16:48 +0200 Subject: [PATCH 4/4] fix(attachments): Create only parent folders to avoid FileSystemException (Is a directory) --- .../lib/src/local_storage_adapter.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/powersync_attachments_helper/lib/src/local_storage_adapter.dart b/packages/powersync_attachments_helper/lib/src/local_storage_adapter.dart index b8a997e4..d2bef3cc 100644 --- a/packages/powersync_attachments_helper/lib/src/local_storage_adapter.dart +++ b/packages/powersync_attachments_helper/lib/src/local_storage_adapter.dart @@ -31,8 +31,8 @@ class LocalStorageAdapter { Future makeDir(String fileUri) async { bool exists = await fileExists(fileUri); if (!exists) { - Directory newDirectory = Directory(fileUri); - await newDirectory.create(recursive: true); + Directory parentDirectories = File(fileUri).parent; + await parentDirectories.create(recursive: true); } }