Skip to content

Commit d397d1a

Browse files
committed
Image details modal
1 parent 071ebbe commit d397d1a

6 files changed

Lines changed: 198 additions & 26 deletions

File tree

l10n/app_en.arb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,27 @@
430430
"imageDetailsFetchError_retryMessage": "Fetching the photo data failed. Try again?",
431431
"imageDetailsFetchError_continueMessage": "Fetching the photo data failed. Continue?",
432432

433+
"imageDetails_dateCreated": "Created on {date} at {time}",
434+
"@imageDetails_dateCreated": {
435+
"placeholders": {
436+
"date": {},
437+
"time": {}
438+
}
439+
},
440+
"imageDetails_dateAvailable": "Available on {date} at {time}",
441+
"@imageDetails_dateAvailable": {
442+
"placeholders": {
443+
"date": {},
444+
"time": {}
445+
}
446+
},
447+
"imageDetails_nbAlbums": "{count, plural, =0{Orphan} =1{Belongs to 1 album} other{Belongs to {count} albums}}",
448+
"@imageDetails_nbAlbums" : {
449+
"placeholders": {
450+
"count": {}
451+
}
452+
},
453+
433454

434455
"privacyLevel": "Privacy Level",
435456
"privacyLevel_admin": "Admins",

l10n/app_fr.arb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,26 @@
339339
"imageDetailsFetchError_title": "Échec de la récupération des propriétés",
340340
"imageDetailsFetchError_retryMessage": "La récupération des données de la photo a échoué. Ré-essayer ?",
341341
"imageDetailsFetchError_continueMessage": "La récupération des données de la photo a échoué. Continuer ?",
342+
"imageDetails_dateCreated": "Créée le {date} à {time}",
343+
"@imageDetails_dateCreated": {
344+
"placeholders": {
345+
"date": {},
346+
"time": {}
347+
}
348+
},
349+
"imageDetails_dateAvailable": "Disponible le {date} à {time}",
350+
"@imageDetails_dateAvailable": {
351+
"placeholders": {
352+
"date": {},
353+
"time": {}
354+
}
355+
},
356+
"imageDetails_nbAlbums": "{count, plural, =0{Orpheline} =1{Appartient à 1 album} other{Appartient à {count} albums}}",
357+
"@imageDetails_nbAlbums" : {
358+
"placeholders": {
359+
"count": {}
360+
}
361+
},
342362
"privacyLevel": "Niveau de Confidentialité",
343363
"privacyLevel_admin": "Admins",
344364
"privacyLevel_adminFamily": "Admins, Famille",

lib/components/cards/image_details_card.dart

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,22 @@ class ImageDetailsCard extends StatelessWidget {
2626
@override
2727
Widget build(BuildContext context) {
2828
return Stack(
29+
fit: StackFit.loose,
2930
children: [
30-
Padding(
31-
padding: const EdgeInsets.all(8.0),
32-
child: Row(
33-
children: [
34-
_imageThumbnail(context),
35-
Expanded(
36-
child: _imageDetails(context),
37-
),
38-
],
31+
Positioned.fill(
32+
child: Padding(
33+
padding: const EdgeInsets.all(8.0),
34+
child: Row(
35+
children: [
36+
_imageThumbnail(context),
37+
Expanded(
38+
child: _imageDetails(context),
39+
),
40+
],
41+
),
3942
),
4043
),
41-
_removeButton(context),
44+
if (onRemove != null) _removeButton(context),
4245
],
4346
);
4447
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:intl/intl.dart';
3+
import 'package:piwigo_ng/components/cards/piwigo_chip.dart';
4+
import 'package:piwigo_ng/components/modals/piwigo_modal.dart';
5+
import 'package:piwigo_ng/components/sections/form_section.dart';
6+
import 'package:piwigo_ng/components/sections/settings_section.dart';
7+
import 'package:piwigo_ng/models/image_model.dart';
8+
import 'package:piwigo_ng/services/locale_provider.dart';
9+
import 'package:piwigo_ng/utils/localizations.dart';
10+
import 'package:provider/provider.dart';
11+
12+
class ImageInfoModal extends StatelessWidget {
13+
const ImageInfoModal({Key? key, required this.image}) : super(key: key);
14+
15+
final ImageModel image;
16+
17+
String _getDate(BuildContext context, String date) {
18+
LocaleNotifier localeNotifier =
19+
Provider.of<LocaleNotifier>(context, listen: false);
20+
21+
return DateFormat.yMMMMd(localeNotifier.locale.languageCode)
22+
.format(DateTime.parse(image.dateAvailable!));
23+
}
24+
25+
String _getTime(BuildContext context, String date) {
26+
LocaleNotifier localeNotifier =
27+
Provider.of<LocaleNotifier>(context, listen: false);
28+
29+
return DateFormat.Hms(localeNotifier.locale.languageCode)
30+
.format(DateTime.parse(image.dateAvailable!));
31+
}
32+
33+
@override
34+
Widget build(BuildContext context) {
35+
return PiwigoModal(
36+
title: appStrings.imageDetailsView_title,
37+
content: Padding(
38+
padding: const EdgeInsets.symmetric(
39+
horizontal: 16.0,
40+
vertical: 8.0,
41+
),
42+
child: Column(
43+
crossAxisAlignment: CrossAxisAlignment.start,
44+
children: [
45+
Padding(
46+
padding: const EdgeInsets.all(8.0),
47+
child: Text(
48+
image.name,
49+
style: Theme.of(context).textTheme.titleMedium,
50+
),
51+
),
52+
if (image.comment != null) Text(image.comment!),
53+
const SizedBox(height: 8.0),
54+
SettingsSection(
55+
margin: EdgeInsets.zero,
56+
title: appStrings.settingsHeader_about,
57+
children: [
58+
Padding(
59+
padding: const EdgeInsets.all(8.0),
60+
child: Text(image.file),
61+
),
62+
Padding(
63+
padding: const EdgeInsets.all(8.0),
64+
child: Text("${image.width}x${image.height} px"),
65+
),
66+
if (image.dateCreation != null) ...[
67+
Padding(
68+
padding: const EdgeInsets.all(8.0),
69+
child: Text(appStrings.imageDetails_dateCreated(
70+
_getDate(context, image.dateCreation!),
71+
_getTime(context, image.dateCreation!),
72+
)),
73+
),
74+
],
75+
if (image.dateAvailable != null) ...[
76+
Padding(
77+
padding: const EdgeInsets.all(8.0),
78+
child: Text(appStrings.imageDetails_dateAvailable(
79+
_getDate(context, image.dateAvailable!),
80+
_getTime(context, image.dateAvailable!),
81+
)),
82+
),
83+
],
84+
Padding(
85+
padding: const EdgeInsets.all(8.0),
86+
child: Text(appStrings
87+
.imageDetails_nbAlbums(image.categories.length)),
88+
),
89+
],
90+
),
91+
const SizedBox(height: 8.0),
92+
FormSection(
93+
title: appStrings.tags,
94+
titlePadding: const EdgeInsets.symmetric(horizontal: 8.0),
95+
child: Wrap(
96+
spacing: 8.0,
97+
children: List.generate(
98+
image.tags.length,
99+
(index) => PiwigoChip(
100+
label: image.tags[index].name,
101+
backgroundColor:
102+
Theme.of(context).chipTheme.backgroundColor,
103+
foregroundColor:
104+
Theme.of(context).textTheme.bodyMedium?.color,
105+
),
106+
),
107+
),
108+
),
109+
],
110+
),
111+
),
112+
);
113+
}
114+
}
115+
116+
Future<void> showImageDetailsModal(
117+
BuildContext context,
118+
ImageModel image,
119+
) async {
120+
await showModalBottomSheet(
121+
context: context,
122+
isScrollControlled: true,
123+
useSafeArea: true,
124+
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
125+
builder: (_) => ImageInfoModal(image: image),
126+
);
127+
}

lib/views/image/edit_image_page.dart

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,6 @@ class _EditImagePageState extends State<EditImagePage> {
9595
});
9696
}
9797

98-
void _onDeselectTag(TagModel tag) {
99-
setState(() {
100-
_tags.remove(tag);
101-
});
102-
}
103-
10498
Future<void> _onEdit() async {
10599
_btnController.start();
106100
Iterable<int> tagIds = _tags.map<int>((tag) => tag.id);

lib/views/image/image_page.dart

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import 'package:photo_view/photo_view.dart';
99
import 'package:photo_view/photo_view_gallery.dart';
1010
import 'package:piwigo_ng/app.dart';
1111
import 'package:piwigo_ng/components/app_image_display.dart';
12-
import 'package:piwigo_ng/components/dialogs/image_comment_dialog.dart';
12+
import 'package:piwigo_ng/components/modals/image_info_modal.dart';
1313
import 'package:piwigo_ng/components/popup_list_item.dart';
1414
import 'package:piwigo_ng/models/album_model.dart';
1515
import 'package:piwigo_ng/models/image_model.dart';
@@ -283,6 +283,10 @@ class _ImagePageState extends State<ImagePage> {
283283
);
284284
}
285285

286+
Future<void> _showImageDetails() async {
287+
return showImageDetailsModal(context, _currentImage);
288+
}
289+
286290
@override
287291
Widget build(BuildContext context) {
288292
return WillPopScope(
@@ -357,6 +361,13 @@ class _ImagePageState extends State<ImagePage> {
357361
PopupMenuButton(
358362
position: PopupMenuPosition.under,
359363
itemBuilder: (context) => [
364+
PopupMenuItem(
365+
onTap: _showImageDetails,
366+
child: PopupListItem(
367+
icon: Icons.text_snippet,
368+
text: appStrings.imageDetailsView_title,
369+
),
370+
),
360371
PopupMenuItem(
361372
onTap: () => Future.delayed(
362373
const Duration(seconds: 0),
@@ -660,15 +671,7 @@ class _ImagePageState extends State<ImagePage> {
660671
return const SizedBox();
661672
return GestureDetector(
662673
behavior: HitTestBehavior.opaque,
663-
onTap: () {
664-
showDialog(
665-
barrierColor: Colors.black.withOpacity(0.6),
666-
context: context,
667-
builder: (context) {
668-
return ImageCommentDialog(image: _currentImage);
669-
},
670-
);
671-
},
674+
onTap: _showImageDetails,
672675
child: Padding(
673676
padding: const EdgeInsets.symmetric(
674677
vertical: 8.0,
@@ -704,6 +707,10 @@ class _ImagePageState extends State<ImagePage> {
704707
),
705708
];
706709
List<Widget> userActions = [
710+
IconButton(
711+
onPressed: _showImageDetails,
712+
icon: Icon(Icons.text_snippet),
713+
),
707714
IconButton(
708715
onPressed: () => share([_currentImage]),
709716
icon: Icon(Icons.share),

0 commit comments

Comments
 (0)