feat: implement watchPositions() tag position stream

This commit is contained in:
2026-05-19 21:07:11 +02:00
parent dffe8d4f5e
commit e0a3d5e481
2 changed files with 40 additions and 13 deletions
@@ -38,19 +38,42 @@ class PhoenixTagRepository implements TagRepository {
Future<void> deleteTag(int id) => tagClient.deleteTag(id);
@override
Stream<List<TagPosition>> watchPositions() =>
realtime.channel('tags').map((payload) {
final list = payload['positions'] as List<dynamic>? ?? [];
return list.map((j) {
final m = j as Map<String, dynamic>;
return TagPosition(
tagId: m['tag_id'] as String,
name: m['name'] as String,
color: m['color'] as String,
roomId: m['room_id'] as int?,
);
}).toList();
});
Stream<List<TagPosition>> watchPositions() async* {
var tagMap = await _fetchTagMap();
await for (final occupancy in watchRoomOccupancy()) {
// Re-fetch on every occupancy change so name/color edits and new tags
// are reflected without restarting the stream.
tagMap = await _fetchTagMap();
final positions = <TagPosition>[];
for (final entry in occupancy.entries) {
for (final tagId in entry.value) {
final tag = tagMap[tagId];
positions.add(TagPosition(
tagId: tagId,
name: tag?.name ?? tagId,
color: tag?.color ?? _colorForTagId(tagId),
roomId: entry.key,
));
}
}
yield positions;
}
}
Future<Map<String, Tag>> _fetchTagMap() async {
final raw = await tagClient.getTags();
return {
for (final j in raw.cast<Map<String, dynamic>>())
j['tag_id'] as String: Tag.fromJson(j),
};
}
static String _colorForTagId(String tagId) {
final hash = tagId.codeUnits.fold(0, (h, c) => (h * 31 + c) & 0xFFFFFF);
return '#${hash.toRadixString(16).padLeft(6, '0')}';
}
@override
Stream<ParticleSnapshot> watchParticleCloud(String tagId) =>
+4
View File
@@ -8,11 +8,13 @@ class Tag {
this.currentRoomId,
this.lastPosition,
this.lastSeen,
this.color,
});
final int id;
final String tagId; // BLE beacon advertised identifier
final String name;
final String? color;
final String? currentRoomId;
final Position? lastPosition;
final DateTime? lastSeen;
@@ -34,6 +36,7 @@ class Tag {
'current_room_id': currentRoomId,
'last_position': lastPosition?.toJson(),
'last_seen': lastSeen?.toIso8601String(),
'color': color,
};
factory Tag.fromJson(Map<String, dynamic> json) => Tag(
@@ -41,6 +44,7 @@ class Tag {
tagId: json['tag_id'] as String,
name: json['name'] as String,
currentRoomId: json['current_room_id'] as String?,
color: json['color'] as String?,
lastPosition: json['last_position'] == null
? null
: Position.fromJson(json['last_position'] as Map<String, dynamic>),