Skip to content

Commit eb00a49

Browse files
open_wearable/lib/widgets/fota/stepper_view/update_view.dart: show timer for firmware verification
1 parent 2dfe42f commit eb00a49

File tree

1 file changed

+82
-9
lines changed

1 file changed

+82
-9
lines changed

open_wearable/lib/widgets/fota/stepper_view/update_view.dart

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:async';
2+
13
import 'package:flutter/material.dart';
24
import 'package:flutter_bloc/flutter_bloc.dart';
35
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
@@ -29,15 +31,17 @@ class UpdateStepView extends StatelessWidget {
2931
);
3032
case UpdateFirmwareStateHistory():
3133
return Column(
34+
crossAxisAlignment: CrossAxisAlignment.start,
3235
children: [
33-
for (var state in state.history)
36+
for (var s in state.history)
3437
Row(
3538
children: [
3639
_stateIcon(
37-
state,
40+
s,
3841
Colors.green,
3942
),
40-
PlatformText(state.stage),
43+
const SizedBox(width: 8),
44+
PlatformText(s.stage),
4145
],
4246
),
4347
if (state.currentState != null)
@@ -54,6 +58,7 @@ class UpdateStepView extends StatelessWidget {
5458
_currentState(state),
5559
],
5660
),
61+
const SizedBox(height: 12),
5762
if (state.isComplete && state.updateManager?.logger != null)
5863
ElevatedButton(
5964
onPressed: () {
@@ -76,14 +81,23 @@ class UpdateStepView extends StatelessWidget {
7681
},
7782
child: PlatformText('Update Again'),
7883
),
84+
85+
// Verification info + countdown
7986
if (state.isComplete &&
8087
state.history.last is UpdateCompleteSuccess)
81-
PlatformText(
82-
'Firmware upload complete.\n\n'
83-
'The image has been successfully uploaded and is now being verified by the device. '
84-
'The device will automatically restart once verification is complete.\n\n'
85-
'This may take up to 3 minutes. Please keep the device powered on and nearby.',
86-
textAlign: TextAlign.start,
88+
Column(
89+
crossAxisAlignment: CrossAxisAlignment.start,
90+
children: [
91+
PlatformText(
92+
'Firmware upload complete.\n\n'
93+
'The image has been successfully uploaded and is now being verified by the device. '
94+
'The device will automatically restart once verification is complete.\n\n'
95+
'This may take up to 3 minutes. Please keep the device powered on and nearby.',
96+
textAlign: TextAlign.start,
97+
),
98+
const SizedBox(height: 8),
99+
const _VerificationCountdown(),
100+
],
87101
),
88102
],
89103
);
@@ -139,3 +153,62 @@ class UpdateStepView extends StatelessWidget {
139153
);
140154
}
141155
}
156+
157+
/// Small stateful widget that starts a 3-minute countdown when built.
158+
/// It appears only once the firmware upload completed successfully.
159+
class _VerificationCountdown extends StatefulWidget {
160+
const _VerificationCountdown();
161+
162+
@override
163+
State<_VerificationCountdown> createState() => _VerificationCountdownState();
164+
}
165+
166+
class _VerificationCountdownState extends State<_VerificationCountdown> {
167+
static const Duration _total = Duration(minutes: 3);
168+
late Duration _remaining;
169+
Timer? _timer;
170+
171+
@override
172+
void initState() {
173+
super.initState();
174+
_remaining = _total;
175+
176+
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
177+
if (!mounted) {
178+
timer.cancel();
179+
return;
180+
}
181+
if (_remaining.inSeconds <= 1) {
182+
setState(() {
183+
_remaining = Duration.zero;
184+
});
185+
timer.cancel();
186+
} else {
187+
setState(() {
188+
_remaining -= const Duration(seconds: 1);
189+
});
190+
}
191+
});
192+
}
193+
194+
@override
195+
void dispose() {
196+
_timer?.cancel();
197+
super.dispose();
198+
}
199+
200+
String _format(Duration d) {
201+
final m = d.inMinutes.remainder(60).toString().padLeft(2, '0');
202+
final s = d.inSeconds.remainder(60).toString().padLeft(2, '0');
203+
return '$m:$s';
204+
}
205+
206+
@override
207+
Widget build(BuildContext context) {
208+
return PlatformText(
209+
'Estimated remaining: ${_format(_remaining)}',
210+
textAlign: TextAlign.start,
211+
style: Theme.of(context).textTheme.bodyLarge?.copyWith(fontSize: 16),
212+
);
213+
}
214+
}

0 commit comments

Comments
 (0)