1
+ import 'dart:io' ;
1
2
import 'dart:typed_data' ;
2
3
4
+ import 'package:flutter/foundation.dart' ;
3
5
import 'package:flutter/material.dart' ;
4
6
import 'package:powersync_core/attachments/attachments.dart' ;
7
+ import 'package:powersync_core/attachments/io.dart' ;
5
8
import 'package:powersync_flutter_demo/attachments/camera_helpers.dart' ;
6
9
import 'package:powersync_flutter_demo/attachments/photo_capture_widget.dart' ;
7
10
@@ -44,19 +47,38 @@ class PhotoWidget extends StatelessWidget {
44
47
);
45
48
}
46
49
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
+ }
48
68
},
49
69
);
50
70
}
51
71
52
72
static Stream <_AttachmentState > _attachmentState (String ? id) {
53
73
return db.watch ('SELECT * FROM attachments_queue WHERE id = ?' ,
54
- parameters: [id]).map ((rows) {
74
+ parameters: [id]).asyncMap ((rows) async {
55
75
if (rows.isEmpty) {
56
- return const _AttachmentState (null );
76
+ return const _AttachmentState (null , false );
57
77
}
58
78
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);
60
82
});
61
83
}
62
84
}
@@ -98,25 +120,24 @@ class TakePhotoButton extends StatelessWidget {
98
120
99
121
final class _AttachmentState {
100
122
final Attachment ? attachment;
123
+ final bool fileExists;
101
124
102
- const _AttachmentState (this .attachment);
125
+ const _AttachmentState (this .attachment, this .fileExists );
103
126
}
104
127
105
- /// A widget showing an [Attachment] as an image.
128
+ /// A widget showing an [Attachment] as an image by loading it into memory .
106
129
///
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 {
111
132
final Attachment attachment;
112
133
113
- const AttachmentImage ({ super .key, required this .attachment});
134
+ const _WebAttachmentImage ({ required this .attachment});
114
135
115
136
@override
116
- State <AttachmentImage > createState () => _AttachmentImageState ();
137
+ State <_WebAttachmentImage > createState () => _AttachmentImageState ();
117
138
}
118
139
119
- class _AttachmentImageState extends State <AttachmentImage > {
140
+ class _AttachmentImageState extends State <_WebAttachmentImage > {
120
141
Future <Uint8List ?>? _imageBytes;
121
142
122
143
void _loadBytes () {
@@ -142,7 +163,7 @@ class _AttachmentImageState extends State<AttachmentImage> {
142
163
}
143
164
144
165
@override
145
- void didUpdateWidget (covariant AttachmentImage oldWidget) {
166
+ void didUpdateWidget (covariant _WebAttachmentImage oldWidget) {
146
167
super .didUpdateWidget (oldWidget);
147
168
if (oldWidget.attachment != widget.attachment) {
148
169
_loadBytes ();
@@ -154,16 +175,12 @@ class _AttachmentImageState extends State<AttachmentImage> {
154
175
return FutureBuilder (
155
176
future: _imageBytes,
156
177
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
+ );
167
184
} else {
168
185
return Container ();
169
186
}
0 commit comments