1+ import 'dart:io' ;
12import 'dart:typed_data' ;
23
4+ import 'package:flutter/foundation.dart' ;
35import 'package:flutter/material.dart' ;
46import 'package:powersync_core/attachments/attachments.dart' ;
7+ import 'package:powersync_core/attachments/io.dart' ;
58import 'package:powersync_flutter_demo/attachments/camera_helpers.dart' ;
69import 'package:powersync_flutter_demo/attachments/photo_capture_widget.dart' ;
710
@@ -44,19 +47,38 @@ class PhotoWidget extends StatelessWidget {
4447 );
4548 }
4649
47- return AttachmentImage (attachment: attachment);
50+ if (! data.fileExists) {
51+ return const Text ('Downloading...' );
52+ }
53+
54+ if (kIsWeb) {
55+ // We can't use Image.file on the web, so fall back to loading the
56+ // image from OPFS.
57+ return _WebAttachmentImage (attachment: attachment);
58+ } else {
59+ final path =
60+ (localStorage as IOLocalStorage ).pathFor (attachment.filename);
61+ return Image .file (
62+ key: ValueKey (attachment),
63+ File (path),
64+ width: 50 ,
65+ height: 50 ,
66+ );
67+ }
4868 },
4969 );
5070 }
5171
5272 static Stream <_AttachmentState > _attachmentState (String ? id) {
5373 return db.watch ('SELECT * FROM attachments_queue WHERE id = ?' ,
54- parameters: [id]).map ((rows) {
74+ parameters: [id]).asyncMap ((rows) async {
5575 if (rows.isEmpty) {
56- return const _AttachmentState (null );
76+ return const _AttachmentState (null , false );
5777 }
5878
59- return _AttachmentState (Attachment .fromRow (rows.single));
79+ final attachment = Attachment .fromRow (rows.single);
80+ final exists = await localStorage.fileExists (attachment.filename);
81+ return _AttachmentState (attachment, exists);
6082 });
6183 }
6284}
@@ -98,25 +120,24 @@ class TakePhotoButton extends StatelessWidget {
98120
99121final class _AttachmentState {
100122 final Attachment ? attachment;
123+ final bool fileExists;
101124
102- const _AttachmentState (this .attachment);
125+ const _AttachmentState (this .attachment, this .fileExists );
103126}
104127
105- /// A widget showing an [Attachment] as an image.
128+ /// A widget showing an [Attachment] as an image by loading it into memory .
106129///
107- /// For better web support, always loads the attachment into memory first. If
108- /// you're only targeting native platforms, a more efficient mechanism would be
109- /// to use `IOLocalStorage.pathFor` with an [Image.file] image.
110- class AttachmentImage extends StatefulWidget {
130+ /// On native platforms, using a file path is more efficient.
131+ class _WebAttachmentImage extends StatefulWidget {
111132 final Attachment attachment;
112133
113- const AttachmentImage ({ super .key, required this .attachment});
134+ const _WebAttachmentImage ({ required this .attachment});
114135
115136 @override
116- State <AttachmentImage > createState () => _AttachmentImageState ();
137+ State <_WebAttachmentImage > createState () => _AttachmentImageState ();
117138}
118139
119- class _AttachmentImageState extends State <AttachmentImage > {
140+ class _AttachmentImageState extends State <_WebAttachmentImage > {
120141 Future <Uint8List ?>? _imageBytes;
121142
122143 void _loadBytes () {
@@ -142,7 +163,7 @@ class _AttachmentImageState extends State<AttachmentImage> {
142163 }
143164
144165 @override
145- void didUpdateWidget (covariant AttachmentImage oldWidget) {
166+ void didUpdateWidget (covariant _WebAttachmentImage oldWidget) {
146167 super .didUpdateWidget (oldWidget);
147168 if (oldWidget.attachment != widget.attachment) {
148169 _loadBytes ();
@@ -154,16 +175,12 @@ class _AttachmentImageState extends State<AttachmentImage> {
154175 return FutureBuilder (
155176 future: _imageBytes,
156177 builder: (context, snapshot) {
157- if (snapshot.connectionState == ConnectionState .done) {
158- if (snapshot.data case final bytes? ) {
159- return Image .memory (
160- bytes,
161- width: 50 ,
162- height: 50 ,
163- );
164- } else {
165- return const Text ('Downloading...' );
166- }
178+ if (snapshot.data case final bytes? ) {
179+ return Image .memory (
180+ bytes,
181+ width: 50 ,
182+ height: 50 ,
183+ );
167184 } else {
168185 return Container ();
169186 }
0 commit comments