+2
lib/models/gallery_photo.dart
+2
lib/models/gallery_photo.dart
···
2
2
3
3
import 'aspect_ratio.dart';
4
4
import 'gallery_state.dart';
5
+
import 'photo_exif.dart';
5
6
6
7
part 'gallery_photo.freezed.dart';
7
8
part 'gallery_photo.g.dart';
···
16
17
String? alt,
17
18
AspectRatio? aspectRatio,
18
19
GalleryState? gallery,
20
+
PhotoExif? exif,
19
21
}) = _GalleryPhoto;
20
22
21
23
factory GalleryPhoto.fromJson(Map<String, dynamic> json) => _$GalleryPhotoFromJson(json);
+40
-2
lib/models/gallery_photo.freezed.dart
+40
-2
lib/models/gallery_photo.freezed.dart
···
28
28
String? get alt => throw _privateConstructorUsedError;
29
29
AspectRatio? get aspectRatio => throw _privateConstructorUsedError;
30
30
GalleryState? get gallery => throw _privateConstructorUsedError;
31
+
PhotoExif? get exif => throw _privateConstructorUsedError;
31
32
32
33
/// Serializes this GalleryPhoto to a JSON map.
33
34
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
···
54
55
String? alt,
55
56
AspectRatio? aspectRatio,
56
57
GalleryState? gallery,
58
+
PhotoExif? exif,
57
59
});
58
60
59
61
$AspectRatioCopyWith<$Res>? get aspectRatio;
60
62
$GalleryStateCopyWith<$Res>? get gallery;
63
+
$PhotoExifCopyWith<$Res>? get exif;
61
64
}
62
65
63
66
/// @nodoc
···
82
85
Object? alt = freezed,
83
86
Object? aspectRatio = freezed,
84
87
Object? gallery = freezed,
88
+
Object? exif = freezed,
85
89
}) {
86
90
return _then(
87
91
_value.copyWith(
···
113
117
? _value.gallery
114
118
: gallery // ignore: cast_nullable_to_non_nullable
115
119
as GalleryState?,
120
+
exif: freezed == exif
121
+
? _value.exif
122
+
: exif // ignore: cast_nullable_to_non_nullable
123
+
as PhotoExif?,
116
124
)
117
125
as $Val,
118
126
);
···
145
153
return _then(_value.copyWith(gallery: value) as $Val);
146
154
});
147
155
}
156
+
157
+
/// Create a copy of GalleryPhoto
158
+
/// with the given fields replaced by the non-null parameter values.
159
+
@override
160
+
@pragma('vm:prefer-inline')
161
+
$PhotoExifCopyWith<$Res>? get exif {
162
+
if (_value.exif == null) {
163
+
return null;
164
+
}
165
+
166
+
return $PhotoExifCopyWith<$Res>(_value.exif!, (value) {
167
+
return _then(_value.copyWith(exif: value) as $Val);
168
+
});
169
+
}
148
170
}
149
171
150
172
/// @nodoc
···
164
186
String? alt,
165
187
AspectRatio? aspectRatio,
166
188
GalleryState? gallery,
189
+
PhotoExif? exif,
167
190
});
168
191
169
192
@override
170
193
$AspectRatioCopyWith<$Res>? get aspectRatio;
171
194
@override
172
195
$GalleryStateCopyWith<$Res>? get gallery;
196
+
@override
197
+
$PhotoExifCopyWith<$Res>? get exif;
173
198
}
174
199
175
200
/// @nodoc
···
193
218
Object? alt = freezed,
194
219
Object? aspectRatio = freezed,
195
220
Object? gallery = freezed,
221
+
Object? exif = freezed,
196
222
}) {
197
223
return _then(
198
224
_$GalleryPhotoImpl(
···
224
250
? _value.gallery
225
251
: gallery // ignore: cast_nullable_to_non_nullable
226
252
as GalleryState?,
253
+
exif: freezed == exif
254
+
? _value.exif
255
+
: exif // ignore: cast_nullable_to_non_nullable
256
+
as PhotoExif?,
227
257
),
228
258
);
229
259
}
···
240
270
this.alt,
241
271
this.aspectRatio,
242
272
this.gallery,
273
+
this.exif,
243
274
});
244
275
245
276
factory _$GalleryPhotoImpl.fromJson(Map<String, dynamic> json) =>
···
259
290
final AspectRatio? aspectRatio;
260
291
@override
261
292
final GalleryState? gallery;
293
+
@override
294
+
final PhotoExif? exif;
262
295
263
296
@override
264
297
String toString() {
265
-
return 'GalleryPhoto(uri: $uri, cid: $cid, thumb: $thumb, fullsize: $fullsize, alt: $alt, aspectRatio: $aspectRatio, gallery: $gallery)';
298
+
return 'GalleryPhoto(uri: $uri, cid: $cid, thumb: $thumb, fullsize: $fullsize, alt: $alt, aspectRatio: $aspectRatio, gallery: $gallery, exif: $exif)';
266
299
}
267
300
268
301
@override
···
278
311
(identical(other.alt, alt) || other.alt == alt) &&
279
312
(identical(other.aspectRatio, aspectRatio) ||
280
313
other.aspectRatio == aspectRatio) &&
281
-
(identical(other.gallery, gallery) || other.gallery == gallery));
314
+
(identical(other.gallery, gallery) || other.gallery == gallery) &&
315
+
(identical(other.exif, exif) || other.exif == exif));
282
316
}
283
317
284
318
@JsonKey(includeFromJson: false, includeToJson: false)
···
292
326
alt,
293
327
aspectRatio,
294
328
gallery,
329
+
exif,
295
330
);
296
331
297
332
/// Create a copy of GalleryPhoto
···
317
352
final String? alt,
318
353
final AspectRatio? aspectRatio,
319
354
final GalleryState? gallery,
355
+
final PhotoExif? exif,
320
356
}) = _$GalleryPhotoImpl;
321
357
322
358
factory _GalleryPhoto.fromJson(Map<String, dynamic> json) =
···
336
372
AspectRatio? get aspectRatio;
337
373
@override
338
374
GalleryState? get gallery;
375
+
@override
376
+
PhotoExif? get exif;
339
377
340
378
/// Create a copy of GalleryPhoto
341
379
/// with the given fields replaced by the non-null parameter values.
+4
lib/models/gallery_photo.g.dart
+4
lib/models/gallery_photo.g.dart
···
19
19
gallery: json['gallery'] == null
20
20
? null
21
21
: GalleryState.fromJson(json['gallery'] as Map<String, dynamic>),
22
+
exif: json['exif'] == null
23
+
? null
24
+
: PhotoExif.fromJson(json['exif'] as Map<String, dynamic>),
22
25
);
23
26
24
27
Map<String, dynamic> _$$GalleryPhotoImplToJson(_$GalleryPhotoImpl instance) =>
···
30
33
'alt': instance.alt,
31
34
'aspectRatio': instance.aspectRatio,
32
35
'gallery': instance.gallery,
36
+
'exif': instance.exif,
33
37
};
+5
-3
lib/models/photo_exif.dart
+5
-3
lib/models/photo_exif.dart
···
8
8
const factory PhotoExif({
9
9
required String photo, // at-uri
10
10
required String createdAt, // datetime
11
+
String? uri, // at-uri
12
+
String? cid, // cid
11
13
String? dateTimeOriginal, // datetime
12
-
int? exposureTime,
13
-
int? fNumber,
14
+
String? exposureTime,
15
+
String? fNumber,
14
16
String? flash,
15
-
int? focalLengthIn35mmFormat,
17
+
String? focalLengthIn35mmFormat,
16
18
int? iSO,
17
19
String? lensMake,
18
20
String? lensModel,
+69
-25
lib/models/photo_exif.freezed.dart
+69
-25
lib/models/photo_exif.freezed.dart
···
23
23
mixin _$PhotoExif {
24
24
String get photo => throw _privateConstructorUsedError; // at-uri
25
25
String get createdAt => throw _privateConstructorUsedError; // datetime
26
+
String? get uri => throw _privateConstructorUsedError; // at-uri
27
+
String? get cid => throw _privateConstructorUsedError; // cid
26
28
String? get dateTimeOriginal =>
27
29
throw _privateConstructorUsedError; // datetime
28
-
int? get exposureTime => throw _privateConstructorUsedError;
29
-
int? get fNumber => throw _privateConstructorUsedError;
30
+
String? get exposureTime => throw _privateConstructorUsedError;
31
+
String? get fNumber => throw _privateConstructorUsedError;
30
32
String? get flash => throw _privateConstructorUsedError;
31
-
int? get focalLengthIn35mmFormat => throw _privateConstructorUsedError;
33
+
String? get focalLengthIn35mmFormat => throw _privateConstructorUsedError;
32
34
int? get iSO => throw _privateConstructorUsedError;
33
35
String? get lensMake => throw _privateConstructorUsedError;
34
36
String? get lensModel => throw _privateConstructorUsedError;
···
53
55
$Res call({
54
56
String photo,
55
57
String createdAt,
58
+
String? uri,
59
+
String? cid,
56
60
String? dateTimeOriginal,
57
-
int? exposureTime,
58
-
int? fNumber,
61
+
String? exposureTime,
62
+
String? fNumber,
59
63
String? flash,
60
-
int? focalLengthIn35mmFormat,
64
+
String? focalLengthIn35mmFormat,
61
65
int? iSO,
62
66
String? lensMake,
63
67
String? lensModel,
···
83
87
$Res call({
84
88
Object? photo = null,
85
89
Object? createdAt = null,
90
+
Object? uri = freezed,
91
+
Object? cid = freezed,
86
92
Object? dateTimeOriginal = freezed,
87
93
Object? exposureTime = freezed,
88
94
Object? fNumber = freezed,
···
104
110
? _value.createdAt
105
111
: createdAt // ignore: cast_nullable_to_non_nullable
106
112
as String,
113
+
uri: freezed == uri
114
+
? _value.uri
115
+
: uri // ignore: cast_nullable_to_non_nullable
116
+
as String?,
117
+
cid: freezed == cid
118
+
? _value.cid
119
+
: cid // ignore: cast_nullable_to_non_nullable
120
+
as String?,
107
121
dateTimeOriginal: freezed == dateTimeOriginal
108
122
? _value.dateTimeOriginal
109
123
: dateTimeOriginal // ignore: cast_nullable_to_non_nullable
···
111
125
exposureTime: freezed == exposureTime
112
126
? _value.exposureTime
113
127
: exposureTime // ignore: cast_nullable_to_non_nullable
114
-
as int?,
128
+
as String?,
115
129
fNumber: freezed == fNumber
116
130
? _value.fNumber
117
131
: fNumber // ignore: cast_nullable_to_non_nullable
118
-
as int?,
132
+
as String?,
119
133
flash: freezed == flash
120
134
? _value.flash
121
135
: flash // ignore: cast_nullable_to_non_nullable
···
123
137
focalLengthIn35mmFormat: freezed == focalLengthIn35mmFormat
124
138
? _value.focalLengthIn35mmFormat
125
139
: focalLengthIn35mmFormat // ignore: cast_nullable_to_non_nullable
126
-
as int?,
140
+
as String?,
127
141
iSO: freezed == iSO
128
142
? _value.iSO
129
143
: iSO // ignore: cast_nullable_to_non_nullable
···
162
176
$Res call({
163
177
String photo,
164
178
String createdAt,
179
+
String? uri,
180
+
String? cid,
165
181
String? dateTimeOriginal,
166
-
int? exposureTime,
167
-
int? fNumber,
182
+
String? exposureTime,
183
+
String? fNumber,
168
184
String? flash,
169
-
int? focalLengthIn35mmFormat,
185
+
String? focalLengthIn35mmFormat,
170
186
int? iSO,
171
187
String? lensMake,
172
188
String? lensModel,
···
191
207
$Res call({
192
208
Object? photo = null,
193
209
Object? createdAt = null,
210
+
Object? uri = freezed,
211
+
Object? cid = freezed,
194
212
Object? dateTimeOriginal = freezed,
195
213
Object? exposureTime = freezed,
196
214
Object? fNumber = freezed,
···
212
230
? _value.createdAt
213
231
: createdAt // ignore: cast_nullable_to_non_nullable
214
232
as String,
233
+
uri: freezed == uri
234
+
? _value.uri
235
+
: uri // ignore: cast_nullable_to_non_nullable
236
+
as String?,
237
+
cid: freezed == cid
238
+
? _value.cid
239
+
: cid // ignore: cast_nullable_to_non_nullable
240
+
as String?,
215
241
dateTimeOriginal: freezed == dateTimeOriginal
216
242
? _value.dateTimeOriginal
217
243
: dateTimeOriginal // ignore: cast_nullable_to_non_nullable
···
219
245
exposureTime: freezed == exposureTime
220
246
? _value.exposureTime
221
247
: exposureTime // ignore: cast_nullable_to_non_nullable
222
-
as int?,
248
+
as String?,
223
249
fNumber: freezed == fNumber
224
250
? _value.fNumber
225
251
: fNumber // ignore: cast_nullable_to_non_nullable
226
-
as int?,
252
+
as String?,
227
253
flash: freezed == flash
228
254
? _value.flash
229
255
: flash // ignore: cast_nullable_to_non_nullable
···
231
257
focalLengthIn35mmFormat: freezed == focalLengthIn35mmFormat
232
258
? _value.focalLengthIn35mmFormat
233
259
: focalLengthIn35mmFormat // ignore: cast_nullable_to_non_nullable
234
-
as int?,
260
+
as String?,
235
261
iSO: freezed == iSO
236
262
? _value.iSO
237
263
: iSO // ignore: cast_nullable_to_non_nullable
···
263
289
const _$PhotoExifImpl({
264
290
required this.photo,
265
291
required this.createdAt,
292
+
this.uri,
293
+
this.cid,
266
294
this.dateTimeOriginal,
267
295
this.exposureTime,
268
296
this.fNumber,
···
285
313
final String createdAt;
286
314
// datetime
287
315
@override
316
+
final String? uri;
317
+
// at-uri
318
+
@override
319
+
final String? cid;
320
+
// cid
321
+
@override
288
322
final String? dateTimeOriginal;
289
323
// datetime
290
324
@override
291
-
final int? exposureTime;
325
+
final String? exposureTime;
292
326
@override
293
-
final int? fNumber;
327
+
final String? fNumber;
294
328
@override
295
329
final String? flash;
296
330
@override
297
-
final int? focalLengthIn35mmFormat;
331
+
final String? focalLengthIn35mmFormat;
298
332
@override
299
333
final int? iSO;
300
334
@override
···
308
342
309
343
@override
310
344
String toString() {
311
-
return 'PhotoExif(photo: $photo, createdAt: $createdAt, dateTimeOriginal: $dateTimeOriginal, exposureTime: $exposureTime, fNumber: $fNumber, flash: $flash, focalLengthIn35mmFormat: $focalLengthIn35mmFormat, iSO: $iSO, lensMake: $lensMake, lensModel: $lensModel, make: $make, model: $model)';
345
+
return 'PhotoExif(photo: $photo, createdAt: $createdAt, uri: $uri, cid: $cid, dateTimeOriginal: $dateTimeOriginal, exposureTime: $exposureTime, fNumber: $fNumber, flash: $flash, focalLengthIn35mmFormat: $focalLengthIn35mmFormat, iSO: $iSO, lensMake: $lensMake, lensModel: $lensModel, make: $make, model: $model)';
312
346
}
313
347
314
348
@override
···
319
353
(identical(other.photo, photo) || other.photo == photo) &&
320
354
(identical(other.createdAt, createdAt) ||
321
355
other.createdAt == createdAt) &&
356
+
(identical(other.uri, uri) || other.uri == uri) &&
357
+
(identical(other.cid, cid) || other.cid == cid) &&
322
358
(identical(other.dateTimeOriginal, dateTimeOriginal) ||
323
359
other.dateTimeOriginal == dateTimeOriginal) &&
324
360
(identical(other.exposureTime, exposureTime) ||
···
345
381
runtimeType,
346
382
photo,
347
383
createdAt,
384
+
uri,
385
+
cid,
348
386
dateTimeOriginal,
349
387
exposureTime,
350
388
fNumber,
···
375
413
const factory _PhotoExif({
376
414
required final String photo,
377
415
required final String createdAt,
416
+
final String? uri,
417
+
final String? cid,
378
418
final String? dateTimeOriginal,
379
-
final int? exposureTime,
380
-
final int? fNumber,
419
+
final String? exposureTime,
420
+
final String? fNumber,
381
421
final String? flash,
382
-
final int? focalLengthIn35mmFormat,
422
+
final String? focalLengthIn35mmFormat,
383
423
final int? iSO,
384
424
final String? lensMake,
385
425
final String? lensModel,
···
395
435
@override
396
436
String get createdAt; // datetime
397
437
@override
438
+
String? get uri; // at-uri
439
+
@override
440
+
String? get cid; // cid
441
+
@override
398
442
String? get dateTimeOriginal; // datetime
399
443
@override
400
-
int? get exposureTime;
444
+
String? get exposureTime;
401
445
@override
402
-
int? get fNumber;
446
+
String? get fNumber;
403
447
@override
404
448
String? get flash;
405
449
@override
406
-
int? get focalLengthIn35mmFormat;
450
+
String? get focalLengthIn35mmFormat;
407
451
@override
408
452
int? get iSO;
409
453
@override
+7
-4
lib/models/photo_exif.g.dart
+7
-4
lib/models/photo_exif.g.dart
···
10
10
_$PhotoExifImpl(
11
11
photo: json['photo'] as String,
12
12
createdAt: json['createdAt'] as String,
13
+
uri: json['uri'] as String?,
14
+
cid: json['cid'] as String?,
13
15
dateTimeOriginal: json['dateTimeOriginal'] as String?,
14
-
exposureTime: (json['exposureTime'] as num?)?.toInt(),
15
-
fNumber: (json['fNumber'] as num?)?.toInt(),
16
+
exposureTime: json['exposureTime'] as String?,
17
+
fNumber: json['fNumber'] as String?,
16
18
flash: json['flash'] as String?,
17
-
focalLengthIn35mmFormat: (json['focalLengthIn35mmFormat'] as num?)
18
-
?.toInt(),
19
+
focalLengthIn35mmFormat: json['focalLengthIn35mmFormat'] as String?,
19
20
iSO: (json['iSO'] as num?)?.toInt(),
20
21
lensMake: json['lensMake'] as String?,
21
22
lensModel: json['lensModel'] as String?,
···
27
28
<String, dynamic>{
28
29
'photo': instance.photo,
29
30
'createdAt': instance.createdAt,
31
+
'uri': instance.uri,
32
+
'cid': instance.cid,
30
33
'dateTimeOriginal': instance.dateTimeOriginal,
31
34
'exposureTime': instance.exposureTime,
32
35
'fNumber': instance.fNumber,
+1
-1
lib/providers/gallery_cache_provider.g.dart
+1
-1
lib/providers/gallery_cache_provider.g.dart
···
6
6
// RiverpodGenerator
7
7
// **************************************************************************
8
8
9
-
String _$galleryCacheHash() => r'00313970bd3f1f3b181afc2bc69dd77f0d9fdf8b';
9
+
String _$galleryCacheHash() => r'cd0665a1f246bd700195cf5ce50893ba73b878f9';
10
10
11
11
/// Holds a cache of galleries by URI.
12
12
///
+67
-44
lib/widgets/gallery_photo_view.dart
+67
-44
lib/widgets/gallery_photo_view.dart
···
6
6
import 'package:grain/widgets/add_comment_button.dart';
7
7
import 'package:grain/widgets/add_comment_sheet.dart';
8
8
import 'package:grain/widgets/app_image.dart';
9
+
import 'package:grain/widgets/photo_exif_dialog.dart';
9
10
10
11
class GalleryPhotoView extends ConsumerStatefulWidget {
11
12
final List<GalleryPhoto> photos;
···
98
99
top: false,
99
100
child: Padding(
100
101
padding: const EdgeInsets.only(top: 8, left: 16, right: 16, bottom: 8),
101
-
child: AddCommentButton(
102
-
onPressed: () async {
103
-
final photo = widget.photos[_currentIndex];
104
-
final creator = widget.gallery?.creator;
105
-
final replyTo = {
106
-
'author': creator != null
107
-
? {
108
-
'avatar': creator.avatar,
109
-
'displayName': creator.displayName,
110
-
'handle': creator.handle,
111
-
}
112
-
: {'avatar': null, 'displayName': '', 'handle': ''},
113
-
'focus': photo,
114
-
'text': '',
115
-
};
116
-
bool commentPosted = false;
117
-
await showAddCommentSheet(
118
-
context,
119
-
gallery: null,
120
-
replyTo: replyTo,
121
-
initialText: '',
122
-
onSubmit: (text) async {
123
-
final photo = widget.photos[_currentIndex];
124
-
final gallery = widget.gallery;
125
-
final subject = gallery?.uri;
126
-
final focus = photo.uri;
127
-
if (subject == null || focus == null) {
128
-
return;
129
-
}
130
-
// Use the provider's createComment method
131
-
final notifier = ref.read(galleryThreadProvider(subject).notifier);
132
-
final success = await notifier.createComment(text: text, focus: focus);
133
-
if (success) commentPosted = true;
134
-
// Sheet will pop itself
135
-
},
136
-
);
137
-
// After sheet closes, notify parent if a comment was posted
138
-
if (commentPosted && widget.gallery?.uri != null) {
139
-
widget.onClose?.call(); // Remove GalleryPhotoView overlay
140
-
widget.onCommentPosted?.call(widget.gallery!.uri);
141
-
}
142
-
},
143
-
backgroundColor: Colors.grey[900],
144
-
foregroundColor: Colors.white,
102
+
child: Row(
103
+
children: [
104
+
Expanded(
105
+
child: AddCommentButton(
106
+
onPressed: () async {
107
+
final photo = widget.photos[_currentIndex];
108
+
final creator = widget.gallery?.creator;
109
+
final replyTo = {
110
+
'author': creator != null
111
+
? {
112
+
'avatar': creator.avatar,
113
+
'displayName': creator.displayName,
114
+
'handle': creator.handle,
115
+
}
116
+
: {'avatar': null, 'displayName': '', 'handle': ''},
117
+
'focus': photo,
118
+
'text': '',
119
+
};
120
+
bool commentPosted = false;
121
+
await showAddCommentSheet(
122
+
context,
123
+
gallery: null,
124
+
replyTo: replyTo,
125
+
initialText: '',
126
+
onSubmit: (text) async {
127
+
final photo = widget.photos[_currentIndex];
128
+
final gallery = widget.gallery;
129
+
final subject = gallery?.uri;
130
+
final focus = photo.uri;
131
+
if (subject == null || focus == null) {
132
+
return;
133
+
}
134
+
// Use the provider's createComment method
135
+
final notifier = ref.read(
136
+
galleryThreadProvider(subject).notifier,
137
+
);
138
+
final success = await notifier.createComment(
139
+
text: text,
140
+
focus: focus,
141
+
);
142
+
if (success) commentPosted = true;
143
+
// Sheet will pop itself
144
+
},
145
+
);
146
+
// After sheet closes, notify parent if a comment was posted
147
+
if (commentPosted && widget.gallery?.uri != null) {
148
+
widget.onClose?.call(); // Remove GalleryPhotoView overlay
149
+
widget.onCommentPosted?.call(widget.gallery!.uri);
150
+
}
151
+
},
152
+
backgroundColor: Colors.grey[900],
153
+
foregroundColor: Colors.white,
154
+
),
155
+
),
156
+
const SizedBox(width: 12),
157
+
if (photo.exif != null)
158
+
IconButton(
159
+
icon: Icon(Icons.camera_alt, color: Colors.white),
160
+
onPressed: () {
161
+
showDialog(
162
+
context: context,
163
+
builder: (context) => PhotoExifDialog(exif: photo.exif!),
164
+
);
165
+
},
166
+
),
167
+
],
145
168
),
146
169
),
147
170
),
+187
lib/widgets/photo_exif_dialog.dart
+187
lib/widgets/photo_exif_dialog.dart
···
1
+
import 'package:flutter/material.dart';
2
+
import 'package:grain/models/photo_exif.dart';
3
+
4
+
class PhotoExifDialog extends StatelessWidget {
5
+
final PhotoExif exif;
6
+
const PhotoExifDialog({super.key, required this.exif});
7
+
8
+
@override
9
+
Widget build(BuildContext context) {
10
+
return Dialog(
11
+
backgroundColor: Colors.black45,
12
+
child: Padding(
13
+
padding: const EdgeInsets.all(20),
14
+
child: SingleChildScrollView(
15
+
child: Column(
16
+
crossAxisAlignment: CrossAxisAlignment.start,
17
+
children: [
18
+
Text(
19
+
'Camera Settings',
20
+
style: TextStyle(color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold),
21
+
),
22
+
const SizedBox(height: 16),
23
+
if (exif.make != null)
24
+
RichText(
25
+
text: TextSpan(
26
+
children: [
27
+
TextSpan(
28
+
text: 'Make: ',
29
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
30
+
),
31
+
TextSpan(
32
+
text: exif.make!,
33
+
style: TextStyle(color: Colors.white),
34
+
),
35
+
],
36
+
),
37
+
),
38
+
if (exif.model != null)
39
+
RichText(
40
+
text: TextSpan(
41
+
children: [
42
+
TextSpan(
43
+
text: 'Model: ',
44
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
45
+
),
46
+
TextSpan(
47
+
text: exif.model!,
48
+
style: TextStyle(color: Colors.white),
49
+
),
50
+
],
51
+
),
52
+
),
53
+
if (exif.lensMake != null)
54
+
RichText(
55
+
text: TextSpan(
56
+
children: [
57
+
TextSpan(
58
+
text: 'Lens Make: ',
59
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
60
+
),
61
+
TextSpan(
62
+
text: exif.lensMake!,
63
+
style: TextStyle(color: Colors.white),
64
+
),
65
+
],
66
+
),
67
+
),
68
+
if (exif.lensModel != null)
69
+
RichText(
70
+
text: TextSpan(
71
+
children: [
72
+
TextSpan(
73
+
text: 'Lens Model: ',
74
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
75
+
),
76
+
TextSpan(
77
+
text: exif.lensModel!,
78
+
style: TextStyle(color: Colors.white),
79
+
),
80
+
],
81
+
),
82
+
),
83
+
if (exif.fNumber != null)
84
+
RichText(
85
+
text: TextSpan(
86
+
children: [
87
+
TextSpan(
88
+
text: 'F Number: ',
89
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
90
+
),
91
+
TextSpan(
92
+
text: exif.fNumber!,
93
+
style: TextStyle(color: Colors.white),
94
+
),
95
+
],
96
+
),
97
+
),
98
+
if (exif.focalLengthIn35mmFormat != null)
99
+
RichText(
100
+
text: TextSpan(
101
+
children: [
102
+
TextSpan(
103
+
text: 'Focal Length (35mm): ',
104
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
105
+
),
106
+
TextSpan(
107
+
text: exif.focalLengthIn35mmFormat!,
108
+
style: TextStyle(color: Colors.white),
109
+
),
110
+
],
111
+
),
112
+
),
113
+
if (exif.exposureTime != null)
114
+
RichText(
115
+
text: TextSpan(
116
+
children: [
117
+
TextSpan(
118
+
text: 'Exposure Time: ',
119
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
120
+
),
121
+
TextSpan(
122
+
text: exif.exposureTime!,
123
+
style: TextStyle(color: Colors.white),
124
+
),
125
+
],
126
+
),
127
+
),
128
+
if (exif.iSO != null)
129
+
RichText(
130
+
text: TextSpan(
131
+
children: [
132
+
TextSpan(
133
+
text: 'ISO: ',
134
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
135
+
),
136
+
TextSpan(
137
+
text: exif.iSO.toString(),
138
+
style: TextStyle(color: Colors.white),
139
+
),
140
+
],
141
+
),
142
+
),
143
+
if (exif.flash != null)
144
+
RichText(
145
+
text: TextSpan(
146
+
children: [
147
+
TextSpan(
148
+
text: 'Flash: ',
149
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
150
+
),
151
+
TextSpan(
152
+
text: exif.flash!,
153
+
style: TextStyle(color: Colors.white),
154
+
),
155
+
],
156
+
),
157
+
),
158
+
if (exif.dateTimeOriginal != null)
159
+
RichText(
160
+
text: TextSpan(
161
+
children: [
162
+
TextSpan(
163
+
text: 'DateTime Original: ',
164
+
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
165
+
),
166
+
TextSpan(
167
+
text: exif.dateTimeOriginal!,
168
+
style: TextStyle(color: Colors.white),
169
+
),
170
+
],
171
+
),
172
+
),
173
+
const SizedBox(height: 20),
174
+
Align(
175
+
alignment: Alignment.centerRight,
176
+
child: TextButton(
177
+
onPressed: () => Navigator.of(context).pop(),
178
+
child: Text('Close', style: TextStyle(color: Colors.white)),
179
+
),
180
+
),
181
+
],
182
+
),
183
+
),
184
+
),
185
+
);
186
+
}
187
+
}