From e0a3d5e4811a43a8b634c7a38b24b10b40586749 Mon Sep 17 00:00:00 2001 From: dvdrw Date: Tue, 19 May 2026 21:07:11 +0200 Subject: [PATCH] feat: implement watchPositions() tag position stream --- .../repositories/phoenix_tag_repository.dart | 49 ++++++++++++++----- lib/domain/models/tag.dart | 4 ++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/lib/data/repositories/phoenix_tag_repository.dart b/lib/data/repositories/phoenix_tag_repository.dart index 31546ee..d4c0607 100644 --- a/lib/data/repositories/phoenix_tag_repository.dart +++ b/lib/data/repositories/phoenix_tag_repository.dart @@ -38,19 +38,42 @@ class PhoenixTagRepository implements TagRepository { Future deleteTag(int id) => tagClient.deleteTag(id); @override - Stream> watchPositions() => - realtime.channel('tags').map((payload) { - final list = payload['positions'] as List? ?? []; - return list.map((j) { - final m = j as Map; - 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> 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 = []; + 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> _fetchTagMap() async { + final raw = await tagClient.getTags(); + return { + for (final j in raw.cast>()) + 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 watchParticleCloud(String tagId) => diff --git a/lib/domain/models/tag.dart b/lib/domain/models/tag.dart index c01dc31..f298458 100644 --- a/lib/domain/models/tag.dart +++ b/lib/domain/models/tag.dart @@ -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 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),