Skip to content

Commit e72d2e6

Browse files
authored
Move save button to app bar in collage creator (#8631)
## Description Collage creator wasn't responsive and wasn't consistent in design, this makes it look similar to video/image editor. <img width="400" alt="collage" src="https://github.com/user-attachments/assets/333a6324-22cd-433b-8a11-2c73b18fec8c" /> ## Tests - [x] Tested on iOS
2 parents f165afe + 5541a15 commit e72d2e6

File tree

9 files changed

+362
-173
lines changed

9 files changed

+362
-173
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import 'package:flutter/material.dart';
2+
import "package:photos/generated/l10n.dart";
3+
import "package:photos/theme/ente_theme.dart";
4+
5+
class CollageAppBar extends StatelessWidget implements PreferredSizeWidget {
6+
const CollageAppBar({
7+
super.key,
8+
required this.onSave,
9+
this.isSaveEnabled = true,
10+
});
11+
12+
final VoidCallback onSave;
13+
final bool isSaveEnabled;
14+
15+
@override
16+
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
final colorScheme = getEnteColorScheme(context);
21+
final textTheme = getEnteTextTheme(context);
22+
return AppBar(
23+
elevation: 0,
24+
automaticallyImplyLeading: false,
25+
titleSpacing: 0,
26+
title: Row(
27+
mainAxisAlignment: MainAxisAlignment.spaceBetween,
28+
children: [
29+
TextButton(
30+
onPressed: () => Navigator.of(context).pop(),
31+
child: Text(
32+
AppLocalizations.of(context).cancel,
33+
style: textTheme.body,
34+
),
35+
),
36+
TextButton(
37+
onPressed: isSaveEnabled ? onSave : null,
38+
child: Text(
39+
AppLocalizations.of(context).saveCollage,
40+
style: textTheme.body.copyWith(
41+
color: isSaveEnabled
42+
? colorScheme.primary500
43+
: colorScheme.textMuted,
44+
),
45+
),
46+
),
47+
],
48+
),
49+
);
50+
}
51+
}

mobile/apps/photos/lib/ui/tools/collage/collage_creator_page.dart

Lines changed: 110 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
import "package:flutter/material.dart";
2+
import "package:flutter_image_compress/flutter_image_compress.dart";
3+
import "package:logging/logging.dart";
4+
import "package:photo_manager/photo_manager.dart";
25
import "package:photos/generated/l10n.dart";
36
import 'package:photos/models/file/file.dart';
7+
import "package:photos/services/sync/sync_service.dart";
8+
import "package:photos/ui/notification/toast.dart";
9+
import "package:photos/ui/tools/collage/collage_app_bar.dart";
410
import "package:photos/ui/tools/collage/collage_test_grid.dart";
511
import "package:photos/ui/tools/collage/collage_with_five_items.dart";
612
import "package:photos/ui/tools/collage/collage_with_four_items.dart";
713
import "package:photos/ui/tools/collage/collage_with_six_items.dart";
814
import "package:photos/ui/tools/collage/collage_with_three_items.dart";
915
import "package:photos/ui/tools/collage/collage_with_two_items.dart";
16+
import "package:photos/ui/viewer/file/detail_page.dart";
17+
import "package:photos/utils/navigation_util.dart";
18+
import "package:widgets_to_image/widgets_to_image.dart";
1019

11-
class CollageCreatorPage extends StatelessWidget {
20+
class CollageCreatorPage extends StatefulWidget {
1221
static const int _collageItemsMin = 2;
1322
static const int _collageItemsMax = 6;
1423
static bool isValidCount(int count) {
@@ -19,66 +28,141 @@ class CollageCreatorPage extends StatelessWidget {
1928

2029
const CollageCreatorPage(this.files, {super.key});
2130

31+
@override
32+
State<CollageCreatorPage> createState() => _CollageCreatorPageState();
33+
}
34+
35+
class _CollageCreatorPageState extends State<CollageCreatorPage> {
36+
final _logger = Logger("CollageCreatorPage");
37+
WidgetsToImageController? _controller;
38+
bool _isSaving = false;
39+
40+
void _onControllerReady(WidgetsToImageController controller) {
41+
setState(() {
42+
_controller = controller;
43+
});
44+
}
45+
46+
Future<void> _saveCollage() async {
47+
if (_controller == null || _isSaving) return;
48+
49+
setState(() {
50+
_isSaving = true;
51+
});
52+
53+
try {
54+
final bytes = await _controller!.capture();
55+
_logger.info('Size before compression = ${bytes!.length}');
56+
final compressedBytes = await FlutterImageCompress.compressWithList(
57+
bytes,
58+
quality: 80,
59+
);
60+
_logger.info('Size after compression = ${compressedBytes.length}');
61+
final fileName = "ente_collage_" +
62+
DateTime.now().microsecondsSinceEpoch.toString() +
63+
".jpeg";
64+
final newAsset = await (PhotoManager.editor
65+
.saveImage(
66+
compressedBytes,
67+
filename: fileName,
68+
relativePath: "ente Collages",
69+
)
70+
.onError((err, st) async {
71+
return await (PhotoManager.editor.saveImage(
72+
compressedBytes,
73+
filename: fileName,
74+
));
75+
}));
76+
final newFile = await EnteFile.fromAsset("ente Collages", newAsset);
77+
SyncService.instance.sync().ignore();
78+
showShortToast(context, AppLocalizations.of(context).collageSaved);
79+
replacePage(
80+
context,
81+
DetailPage(
82+
DetailPageConfiguration([newFile], 0, "collage"),
83+
),
84+
result: true,
85+
);
86+
} catch (e, s) {
87+
_logger.severe(e, s);
88+
showShortToast(
89+
context,
90+
AppLocalizations.of(context).somethingWentWrong,
91+
);
92+
} finally {
93+
if (mounted) {
94+
setState(() {
95+
_isSaving = false;
96+
});
97+
}
98+
}
99+
}
100+
22101
@override
23102
Widget build(BuildContext context) {
24103
return Scaffold(
25-
appBar: AppBar(
26-
elevation: 0,
27-
title: Text(AppLocalizations.of(context).createCollage),
104+
appBar: CollageAppBar(
105+
onSave: _saveCollage,
106+
isSaveEnabled: _controller != null && !_isSaving,
28107
),
29108
body: _getBody(context),
30109
);
31110
}
32111

33112
Widget _getBody(BuildContext context) {
34-
final count = files.length;
113+
final count = widget.files.length;
35114
Widget collage;
36115
switch (count) {
37116
case 2:
38117
collage = CollageWithTwoItems(
39-
files[0],
40-
files[1],
118+
widget.files[0],
119+
widget.files[1],
120+
onControllerReady: _onControllerReady,
41121
);
42122
break;
43123
case 3:
44124
collage = CollageWithThreeItems(
45-
files[0],
46-
files[1],
47-
files[2],
125+
widget.files[0],
126+
widget.files[1],
127+
widget.files[2],
128+
onControllerReady: _onControllerReady,
48129
);
49130
break;
50131
case 4:
51132
collage = CollageWithFourItems(
52-
files[0],
53-
files[1],
54-
files[2],
55-
files[3],
133+
widget.files[0],
134+
widget.files[1],
135+
widget.files[2],
136+
widget.files[3],
137+
onControllerReady: _onControllerReady,
56138
);
57139
break;
58140
case 5:
59141
collage = CollageWithFiveItems(
60-
files[0],
61-
files[1],
62-
files[2],
63-
files[3],
64-
files[4],
142+
widget.files[0],
143+
widget.files[1],
144+
widget.files[2],
145+
widget.files[3],
146+
widget.files[4],
147+
onControllerReady: _onControllerReady,
65148
);
66149
break;
67150
case 6:
68151
collage = CollageWithSixItems(
69-
files[0],
70-
files[1],
71-
files[2],
72-
files[3],
73-
files[4],
74-
files[5],
152+
widget.files[0],
153+
widget.files[1],
154+
widget.files[2],
155+
widget.files[3],
156+
widget.files[4],
157+
widget.files[5],
158+
onControllerReady: _onControllerReady,
75159
);
76160
break;
77161
default:
78162
collage = const TestGrid();
79163
}
80164
return Padding(
81-
padding: const EdgeInsets.all(12),
165+
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
82166
child: collage,
83167
);
84168
}

mobile/apps/photos/lib/ui/tools/collage/collage_save_button.dart

Lines changed: 0 additions & 77 deletions
This file was deleted.

0 commit comments

Comments
 (0)