Skip to content

Commit 197fcc2

Browse files
committed
feat: Introduce ChoresChangedEvent and update chore manager to handle scene changes
1 parent 0879440 commit 197fcc2

11 files changed

Lines changed: 45 additions & 44 deletions

File tree

client/lib/core/models/events.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,8 @@ class DeviceGroupDeletedEvent {
4949
}
5050

5151
final class DeviceManagerReadyEvent {}
52+
53+
final class ChoresChangedEvent {
54+
final SceneEntity scene;
55+
const ChoresChangedEvent(this.scene);
56+
}

client/lib/core/services/chore_manager_impl.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'package:borneo_app/core/models/events.dart';
12
import 'package:borneo_app/core/services/chore_manager.dart';
23
import 'package:borneo_app/core/services/clock.dart';
34
import 'package:borneo_app/core/services/scene_manager.dart';
@@ -38,6 +39,11 @@ final class ChoreManagerImpl implements IChoreManager {
3839
this.logger,
3940
}) : _historyStore = ChoreHistoryStore(_db) {
4041
allChores.addAll([PowerOffAllChore(), FeedModeChore(), WaterChangeModeChore(), DryScapeModeChore()]);
42+
43+
// Subscribe to device reload events and publish a ChoresChangedEvent so UI can refresh
44+
_globalBus.on<CurrentSceneDevicesReloadedEvent>().listen((event) {
45+
_globalBus.fire(ChoresChangedEvent(event.scene));
46+
});
4147
}
4248

4349
@override

client/lib/core/services/devices/device_manager_impl.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,7 @@ final class DeviceManagerImpl extends IDeviceManager {
9393

9494
final currentScene = _sceneManager.current;
9595
_globalBus.fire(CurrentSceneDevicesReloadedEvent(currentScene));
96-
logger?.d('Fired CurrentSceneDevicesReloadedEvent for initial scene: ${currentScene.name}');
9796
}());
98-
9997
logger?.i('DeviceManagerImpl has been initialized successfully.');
10098
} finally {
10199
_isInitialized = true;
@@ -277,7 +275,6 @@ final class DeviceManagerImpl extends IDeviceManager {
277275
// Fire event to notify that devices in current scene have been reloaded
278276
final currentScene = _sceneManager.current;
279277
_globalBus.fire(CurrentSceneDevicesReloadedEvent(currentScene));
280-
logger?.d('Fired CurrentSceneDevicesReloadedEvent after adding device: ${device.name}');
281278
return device;
282279
}
283280

@@ -413,7 +410,6 @@ final class DeviceManagerImpl extends IDeviceManager {
413410
// Fire event to notify that devices for current scene have been reloaded
414411
final currentScene = _sceneManager.current;
415412
_globalBus.fire(CurrentSceneDevicesReloadedEvent(currentScene));
416-
logger?.d('Fired CurrentSceneDevicesReloadedEvent for scene: ${currentScene.name}');
417413
}
418414

419415
/// Dispose all existing WotThings

client/lib/features/chores/models/abstract_chore.dart

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import 'package:borneo_app/features/chores/models/actions/power_action.dart';
33
import 'package:borneo_app/features/chores/models/actions/chore_action.dart';
44
import 'package:borneo_app/core/services/devices/device_manager.dart';
55
import 'package:borneo_app/core/models/scene_entity.dart';
6-
import 'package:borneo_kernel_abstractions/models/bound_device.dart';
6+
import 'package:lw_wot/thing.dart';
77

88
import '../../../shared/models/base_entity.dart';
99

@@ -22,9 +22,8 @@ abstract class AbstractChore with BaseEntity {
2222
});
2323

2424
bool checkAvailable(SceneEntity scene, IDeviceManager deviceManager) {
25-
final devices = deviceManager.getBoundDevicesInCurrentScene();
26-
final isAvailable = devices.any((d) => matchAllCapabilities(d, deviceManager));
27-
25+
final things = deviceManager.wotThingsInCurrentScene;
26+
final isAvailable = things.any(matchAllCapabilities);
2827
return isAvailable;
2928
}
3029

@@ -36,22 +35,20 @@ abstract class AbstractChore with BaseEntity {
3635

3736
Future<List<Map<String, dynamic>>> execute(SceneEntity currentScene, IDeviceManager deviceManager);
3837

39-
bool matchAllCapabilities(BoundDevice bound, IDeviceManager deviceManager) {
40-
return requiredCapabilities.every((capability) => _hasCapability(bound, capability, deviceManager));
38+
bool matchAllCapabilities(WotThing thing) {
39+
return requiredCapabilities.every((capability) => _hasCapability(thing, capability));
4140
}
4241

43-
bool _hasCapability(BoundDevice bound, String capability, IDeviceManager deviceManager) {
44-
final wotThing = deviceManager.getWotThing(bound.device.id);
45-
46-
final types = wotThing.type;
42+
bool _hasCapability(WotThing thing, String capability) {
43+
final types = thing.type;
4744
if (types.contains(capability)) return true;
4845

4946
// Check for capability-specific properties that indicate the capability
5047
switch (capability) {
5148
case "OnOffSwitch":
52-
return wotThing.hasProperty("on");
53-
case "LyfiDevice":
54-
return wotThing.hasProperty("state") && wotThing.hasProperty("mode");
49+
return thing.hasProperty("on");
50+
case "LyfiThing":
51+
return thing.hasProperty("state") && thing.hasProperty("mode");
5552
default:
5653
return false;
5754
}

client/lib/features/chores/models/builtin_chores.dart

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,13 @@ final class PowerOffAllChore extends AbstractBuiltinChore {
1515
@override
1616
Future<List<Map<String, dynamic>>> execute(SceneEntity currentScene, IDeviceManager deviceManager) async {
1717
final steps = <PowerAction>[];
18-
for (final bound in deviceManager.boundDevices) {
19-
final wotThing = deviceManager.getWotThing(bound.device.id);
18+
for (final wotThing in deviceManager.wotThingsInCurrentScene) {
2019
final onValue = wotThing.getProperty("on");
2120
if (onValue != null) {
2221
final prevState = onValue as bool;
2322
if (prevState) {
2423
wotThing.setProperty("on", false);
25-
steps.add(PowerAction(deviceId: bound.device.id, prevState: prevState));
24+
steps.add(PowerAction(deviceId: wotThing.id, prevState: prevState));
2625
}
2726
}
2827
}

client/lib/features/chores/view_models/chores_view_model.dart

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,18 @@ class ChoresViewModel extends ChangeNotifier {
3434
bool get isLoading => _isLoading;
3535
String? get error => _error;
3636

37-
late final StreamSubscription<CurrentSceneChangedEvent> _currentSceneChangedSub;
38-
late final StreamSubscription<CurrentSceneDevicesReloadedEvent> _devicesReloadedSub;
37+
late final StreamSubscription<ChoresChangedEvent> _choresChangedSub;
3938

4039
void _setupEventListeners() {
41-
_currentSceneChangedSub = _eventBus.on<CurrentSceneChangedEvent>().listen(_onCurrentSceneChanged);
42-
_devicesReloadedSub = _eventBus.on<CurrentSceneDevicesReloadedEvent>().listen(_onDevicesReloaded);
40+
_choresChangedSub = _eventBus.on<ChoresChangedEvent>().listen(_onChoresChanged);
4341
}
4442

4543
Future<void> initialize() async {
4644
assert(_isLoading);
4745
_error = null;
4846
try {
4947
await _reloadChores();
48+
notifyListeners();
5049
} catch (e) {
5150
_error = e.toString();
5251
} finally {
@@ -56,6 +55,7 @@ class ChoresViewModel extends ChangeNotifier {
5655

5756
Future<void> refresh() async {
5857
await _reloadChores();
58+
notifyListeners();
5959
}
6060

6161
Future<void> _reloadChores() async {
@@ -64,26 +64,15 @@ class ChoresViewModel extends ChangeNotifier {
6464
} catch (e, stackTrace) {
6565
_logger?.e('Failed to reload chores: $e', error: e, stackTrace: stackTrace);
6666
_error = e.toString();
67-
} finally {
68-
notifyListeners();
6967
}
7068
}
7169

72-
void _onCurrentSceneChanged(CurrentSceneChangedEvent event) {
73-
_logger?.d('Scene changed from ${event.from.name} to ${event.to.name}, waiting for devices to reload...');
74-
// Enter loading state immediately when the current scene changes so the UI
75-
// can show a loading indicator while devices and chores are reloaded.
76-
_isLoading = true;
77-
_error = null;
78-
_chores = [];
79-
notifyListeners();
80-
}
81-
82-
void _onDevicesReloaded(CurrentSceneDevicesReloadedEvent event) {
83-
// Devices for the new scene have finished reloading. Refresh chores and
84-
// exit loading state after refresh completes so the UI updates smoothly.
70+
void _onChoresChanged(ChoresChangedEvent event) {
71+
_logger?.d('Chores changed for scene: ${event.scene.name}, reloading chores...');
8572
unawaited(() async {
8673
try {
74+
_isLoading = true;
75+
_error = null;
8776
await _reloadChores();
8877
} finally {
8978
_isLoading = false;
@@ -94,8 +83,7 @@ class ChoresViewModel extends ChangeNotifier {
9483

9584
@override
9685
void dispose() {
97-
_currentSceneChangedSub.cancel();
98-
_devicesReloadedSub.cancel();
86+
_choresChangedSub.cancel();
9987
super.dispose();
10088
}
10189
}

client/packages/borneo_kernel/lib/drivers/borneo/lyfi/wot/wot_thing.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class LyfiThing extends BorneoThing implements WotWriteGuard, WotActionGuard {
4242

4343
LyfiThing({required this.kernel, required this.deviceId, required super.title, this.logger})
4444
: deviceEvents = DeviceEventBus(),
45-
super(id: deviceId, type: ["OnOffSwitch", "Light"], description: "Lyfi LED lighting device") {
45+
super(id: deviceId, type: ["OnOffSwitch", "LyfiThing", "Light"], description: "Lyfi LED lighting device") {
4646
_createPropertiesWithDefaults();
4747
_createActions();
4848
_setupKernelEventSubscriptions();

client/packages/borneo_kernel/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies:
1919
pub_semver: ^2.2.0
2020
synchronized: ^3.4.0
2121
retry: ^3.1.2
22+
polly_dart: ^0.0.7
2223

2324
# in this project
2425
borneo_common:

client/packages/lw_wot/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dependencies:
1111
cancellation_token: ^2.0.1
1212
event_bus: ^2.0.1
1313
pub_semver: ^2.2.0
14+
polly_dart: ^0.0.7
1415

1516
dev_dependencies:
1617
lints: ^6.1.0

client/pubspec.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,14 @@ packages:
13711371
url: "https://pub.dev"
13721372
source: hosted
13731373
version: "0.10.3"
1374+
polly_dart:
1375+
dependency: "direct main"
1376+
description:
1377+
name: polly_dart
1378+
sha256: "440dac3bbf4f5d62746dcf8ff02cd1c2be72bda323ec6b916ab05d7dac75e59b"
1379+
url: "https://pub.dev"
1380+
source: hosted
1381+
version: "0.0.7"
13741382
pool:
13751383
dependency: transitive
13761384
description:

0 commit comments

Comments
 (0)