11import 'dart:async' ;
22
33import 'package:borneo_app/core/events/app_events.dart' ;
4+ import 'package:cancellation_token/cancellation_token.dart' ;
45import 'package:flutter/foundation.dart' ;
56import 'package:borneo_app/core/services/devices/ota_providers.dart' ;
67import 'package:borneo_kernel_abstractions/models/bound_device.dart' ;
7- import 'package:cancellation_token/cancellation_token.dart' ;
88import 'package:event_bus/event_bus.dart' ;
99
1010import '../../shared/view_models/base_view_model.dart' ;
@@ -15,6 +15,10 @@ class DeviceOtaViewModel extends BaseViewModel with ViewModelEventBusMixin {
1515 final OtaProvider otaProvider;
1616 final BoundDevice boundDevice;
1717
18+ /// Returns whether the device is currently reachable.
19+ /// Provided as a callback so the getter stays live after construction.
20+ final bool Function () _isOnlineProvider;
21+
1822 OtaState _state = OtaState .idle;
1923 OtaState get state => _state;
2024
@@ -35,19 +39,25 @@ class DeviceOtaViewModel extends BaseViewModel with ViewModelEventBusMixin {
3539
3640 bool get canCheck => _state != OtaState .checking && _state != OtaState .upgrading;
3741
38- bool get canUpgrade => _state == OtaState .updateAvailable && (_upgradeInfo? .canUpgrade ?? false );
42+ bool get isOnline => _isOnlineProvider ();
43+
44+ bool get canUpgrade => isOnline && _state == OtaState .updateAvailable && (_upgradeInfo? .canUpgrade ?? false );
3945
4046 /// In debug builds the user can force-push firmware even when already up to date.
4147 bool get canForceUpgrade =>
42- kDebugMode && _upgradeInfo != null && (_state == OtaState .upToDate || _state == OtaState .updateAvailable);
48+ kDebugMode &&
49+ isOnline &&
50+ _upgradeInfo != null &&
51+ (_state == OtaState .upToDate || _state == OtaState .updateAvailable);
4352
4453 DeviceOtaViewModel ({
4554 required this .otaProvider,
4655 required this .boundDevice,
56+ required bool Function () isOnlineProvider,
4757 required EventBus eventBus,
4858 required super .gt,
4959 super .logger,
50- }) {
60+ }) : _isOnlineProvider = isOnlineProvider {
5161 super .globalEventBus = eventBus;
5262 }
5363
@@ -84,13 +94,23 @@ class DeviceOtaViewModel extends BaseViewModel with ViewModelEventBusMixin {
8494 await service.upgrade (boundDevice, cancelToken: _cancelToken, force: force);
8595 if (isDisposed) return ;
8696 _setState (OtaState .success);
97+ } on CancelledException {
98+ if (isDisposed) return ;
99+ // Restore to updateAvailable so the user can retry
100+ _setState (_upgradeInfo? .canUpgrade == true ? OtaState .updateAvailable : OtaState .upToDate);
87101 } catch (e, st) {
88102 _errorMessage = e.toString ();
89103 _setState (OtaState .error);
90104 logger? .e ('OTA upgrade failed' , error: e, stackTrace: st);
91105 }
92106 }
93107
108+ /// Cancels an in-progress upgrade.
109+ void cancelUpgrade () {
110+ if (! isUpgrading) return ;
111+ _cancelToken? .cancel ();
112+ }
113+
94114 void _setState (OtaState newState) {
95115 _state = newState;
96116 if (! isDisposed) notifyListeners ();
0 commit comments