Skip to content

Commit 43caf9b

Browse files
authored
Fix: Selecting a badge is delayed after the user taps. (#234)
1 parent ecf8952 commit 43caf9b

File tree

3 files changed

+157
-36
lines changed

3 files changed

+157
-36
lines changed

lib/l10n/app_en.arb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,5 +574,6 @@
574574
"productImageSelected": "Product Image Selected",
575575
"selectProductImage": "Select Product Image",
576576
"tapToChangeImage": "Tap to change image",
577-
"chooseImageFromGallery": "Choose image from gallery"
577+
"chooseImageFromGallery": "Choose image from gallery",
578+
"processingImages": "Processing images..."
578579
}

lib/view/display_selection_screen.dart

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,23 @@ class _DisplaySelectionScreenState extends State<DisplaySelectionScreen> {
8888

8989
Navigator.push(
9090
context,
91-
MaterialPageRoute(
92-
builder: (context) => ImageEditor(
93-
isExportOnly: false,
94-
device: displays[index],
91+
PageRouteBuilder(
92+
pageBuilder:
93+
(context, animation, secondaryAnimation) =>
94+
_LoadingWrapper(
95+
child: ImageEditor(
96+
isExportOnly: false,
97+
device: displays[index],
98+
),
9599
),
100+
transitionsBuilder:
101+
(context, animation, secondaryAnimation, child) {
102+
return FadeTransition(
103+
opacity: animation,
104+
child: child,
105+
);
106+
},
107+
transitionDuration: const Duration(milliseconds: 300),
96108
),
97109
);
98110
},
@@ -106,3 +118,56 @@ class _DisplaySelectionScreenState extends State<DisplaySelectionScreen> {
106118
);
107119
}
108120
}
121+
122+
class _LoadingWrapper extends StatefulWidget {
123+
final Widget child;
124+
125+
const _LoadingWrapper({required this.child});
126+
127+
@override
128+
State<_LoadingWrapper> createState() => _LoadingWrapperState();
129+
}
130+
131+
class _LoadingWrapperState extends State<_LoadingWrapper> {
132+
bool _showLoading = true;
133+
134+
@override
135+
void initState() {
136+
super.initState();
137+
WidgetsBinding.instance.addPostFrameCallback((_) {
138+
Future.delayed(const Duration(milliseconds: 50), () {
139+
if (mounted) {
140+
setState(() {
141+
_showLoading = false;
142+
});
143+
}
144+
});
145+
});
146+
}
147+
148+
@override
149+
Widget build(BuildContext context) {
150+
if (_showLoading) {
151+
return Scaffold(
152+
backgroundColor: Colors.white,
153+
body: const Center(
154+
child: Column(
155+
mainAxisAlignment: MainAxisAlignment.center,
156+
children: [
157+
CircularProgressIndicator(
158+
valueColor: AlwaysStoppedAnimation<Color>(Color(0xFF2196F3)),
159+
),
160+
SizedBox(height: 16),
161+
Text(
162+
'Loading...',
163+
style: TextStyle(color: Colors.black, fontSize: 14),
164+
),
165+
],
166+
),
167+
),
168+
);
169+
}
170+
171+
return widget.child;
172+
}
173+
}

lib/view/image_editor.dart

Lines changed: 86 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ class _ImageEditorState extends State<ImageEditor> {
4444
List<img.Image> _rawImages = [];
4545
List<Uint8List> _processedPngs = [];
4646
ImageSaveHandler? _imageSaveHandler;
47+
bool _isProcessingImages = false;
48+
bool _isInitializing = true;
4749

4850
@override
4951
void initState() {
@@ -52,33 +54,44 @@ class _ImageEditorState extends State<ImageEditor> {
5254
_selectedWaveform = null;
5355
_selectedWaveformName = null;
5456

55-
Future.microtask(() {
57+
WidgetsBinding.instance.addPostFrameCallback((_) {
58+
setState(() {
59+
_isInitializing = false;
60+
});
5661
loadInitialImage();
5762
});
5863
}
5964

6065
Future<void> loadInitialImage() async {
61-
final imgLoader = context.read<ImageLoader>();
62-
if (imgLoader.image == null) {
63-
await imgLoader.loadFinalizedImage(
64-
width: widget.device.width,
65-
height: widget.device.height,
66-
);
67-
}
68-
if (imgLoader.image == null) {
69-
loadDefaultImage(imgLoader);
66+
try {
67+
final imgLoader = context.read<ImageLoader>();
68+
if (imgLoader.image == null) {
69+
await imgLoader.loadFinalizedImage(
70+
width: widget.device.width,
71+
height: widget.device.height,
72+
);
73+
}
74+
if (imgLoader.image == null) {
75+
await loadDefaultImage(imgLoader);
76+
}
77+
} catch (e) {
78+
debugPrint('Error loading initial image: $e');
7079
}
7180
}
7281

7382
Future<void> loadDefaultImage(ImageLoader imgLoader) async {
74-
const assetPath = 'assets/images/FOSSASIA.png';
75-
final byteData = await rootBundle.load(assetPath);
76-
final pngBytes = byteData.buffer.asUint8List();
77-
await imgLoader.updateImage(
78-
bytes: pngBytes,
79-
width: widget.device.width,
80-
height: widget.device.height,
81-
);
83+
try {
84+
const assetPath = 'assets/images/FOSSASIA.png';
85+
final byteData = await rootBundle.load(assetPath);
86+
final pngBytes = byteData.buffer.asUint8List();
87+
await imgLoader.updateImage(
88+
bytes: pngBytes,
89+
width: widget.device.width,
90+
height: widget.device.height,
91+
);
92+
} catch (e) {
93+
debugPrint('Error loading default image: $e');
94+
}
8295
}
8396

8497
@override
@@ -132,6 +145,7 @@ class _ImageEditorState extends State<ImageEditor> {
132145
_processedSourceImage = null;
133146
_rawImages = [];
134147
_processedPngs = [];
148+
_isProcessingImages = false;
135149
});
136150
}
137151
return;
@@ -141,17 +155,43 @@ class _ImageEditorState extends State<ImageEditor> {
141155
return;
142156
}
143157

144-
_rawImages = processImages(originalImage: sourceImage, epd: widget.device);
145-
146-
_processedPngs =
147-
_rawImages.map((rawImage) => img.encodePng(rawImage)).toList();
158+
_processImagesAsync(sourceImage);
159+
}
148160

161+
Future<void> _processImagesAsync(img.Image sourceImage) async {
162+
if (_isProcessingImages) return;
149163
setState(() {
150-
_processedSourceImage = sourceImage;
151-
_selectedFilterIndex = 0;
152-
flipHorizontal = false;
153-
flipVertical = false;
164+
_isProcessingImages = true;
154165
});
166+
try {
167+
await Future.delayed(const Duration(milliseconds: 50));
168+
final rawImages =
169+
processImages(originalImage: sourceImage, epd: widget.device);
170+
final processedPngs = <Uint8List>[];
171+
for (int i = 0; i < rawImages.length; i++) {
172+
processedPngs.add(img.encodePng(rawImages[i]));
173+
if (i % 2 == 0) {
174+
await Future.delayed(const Duration(milliseconds: 1));
175+
}
176+
}
177+
if (mounted) {
178+
setState(() {
179+
_rawImages = rawImages;
180+
_processedPngs = processedPngs;
181+
_processedSourceImage = sourceImage;
182+
_selectedFilterIndex = 0;
183+
flipHorizontal = false;
184+
flipVertical = false;
185+
_isProcessingImages = false;
186+
});
187+
}
188+
} catch (e) {
189+
if (mounted) {
190+
setState(() {
191+
_isProcessingImages = false;
192+
});
193+
}
194+
}
155195
}
156196

157197
Future<void> _exportXbmFiles() async {
@@ -218,7 +258,11 @@ class _ImageEditorState extends State<ImageEditor> {
218258
@override
219259
Widget build(BuildContext context) {
220260
var imgLoader = context.watch<ImageLoader>();
221-
_updateProcessedImages(imgLoader.image);
261+
if (!_isInitializing && imgLoader.image != null && !_isProcessingImages) {
262+
WidgetsBinding.instance.addPostFrameCallback((_) {
263+
_updateProcessedImages(imgLoader.image);
264+
});
265+
}
222266

223267
return Scaffold(
224268
backgroundColor: Colors.white,
@@ -344,11 +388,22 @@ class _ImageEditorState extends State<ImageEditor> {
344388
body: SafeArea(
345389
top: false,
346390
bottom: true,
347-
child: imgLoader.isLoading
391+
child: _isInitializing || imgLoader.isLoading || _isProcessingImages
348392
? Center(
349-
child: Text(
350-
appLocalizations.loading,
351-
style: const TextStyle(color: colorBlack, fontSize: 14),
393+
child: Column(
394+
mainAxisAlignment: MainAxisAlignment.center,
395+
children: [
396+
const CircularProgressIndicator(
397+
valueColor: AlwaysStoppedAnimation<Color>(colorAccent),
398+
),
399+
const SizedBox(height: 16),
400+
Text(
401+
_isProcessingImages
402+
? appLocalizations.processingImages
403+
: appLocalizations.loading,
404+
style: const TextStyle(color: colorBlack, fontSize: 14),
405+
),
406+
],
352407
),
353408
)
354409
: Padding(

0 commit comments

Comments
 (0)