Only show own activity in last activity

This commit is contained in:
2026-01-21 14:32:25 +01:00
parent 7416f7c29b
commit a32fa17b43
4 changed files with 41 additions and 24 deletions

View File

@@ -15,8 +15,14 @@ class LastHeardWebSocketClient {
static const int _maxReconnectAttempts = 5; static const int _maxReconnectAttempts = 5;
static const Duration _reconnectDelay = Duration(seconds: 5); static const Duration _reconnectDelay = Duration(seconds: 5);
final List<int>? _radioIds;
int _receivedCount = 0;
static const int _maxItems = 200;
final Completer<void> _readyCompleter = Completer<void>(); final Completer<void> _readyCompleter = Completer<void>();
LastHeardWebSocketClient({List<int>? radioIds}) : _radioIds = radioIds;
// Socket.IO Engine.IO v4 WebSocket URL for Last Heard // Socket.IO Engine.IO v4 WebSocket URL for Last Heard
static const String _wsUrl = static const String _wsUrl =
'wss://api.brandmeister.network/lh/?EIO=4&transport=websocket'; 'wss://api.brandmeister.network/lh/?EIO=4&transport=websocket';
@@ -37,7 +43,8 @@ class LastHeardWebSocketClient {
} }
_isConnecting = true; _isConnecting = true;
_shouldReconnect = true; // Don't reconnect if radio IDs are supplied (one-time search query)
_shouldReconnect = _radioIds == null || _radioIds.isEmpty;
try { try {
debugPrint('LastHeard WS: Connecting to $_wsUrl'); debugPrint('LastHeard WS: Connecting to $_wsUrl');
@@ -71,7 +78,7 @@ class LastHeardWebSocketClient {
_handleOpenPacket(messageStr); _handleOpenPacket(messageStr);
} else if (messageStr.startsWith('2')) { } else if (messageStr.startsWith('2')) {
_sendPong(); _sendPong();
} else if (messageStr == '40') { } else if (messageStr.startsWith('40')) {
_handleNamespaceConnect(); _handleNamespaceConnect();
} else if (messageStr.startsWith('42')) { } else if (messageStr.startsWith('42')) {
_handleDataPacket(messageStr); _handleDataPacket(messageStr);
@@ -133,11 +140,20 @@ class LastHeardWebSocketClient {
return; return;
} }
if (_radioIds == null || _radioIds.isEmpty) {
debugPrint('LastHeard WS: No radio IDs provided, skipping search query');
return;
}
try { try {
// Build SQL query for multiple radio IDs: SourceID = 123 OR SourceID = 456
final sqlParts = _radioIds.map((id) => 'SourceID = $id').toList();
final sql = sqlParts.join(' OR ');
final message = '42${jsonEncode([ final message = '42${jsonEncode([
'searchMongo', 'searchMongo',
{ {
'query': {'sql': ''}, 'query': {'sql': sql},
'amount': 200 'amount': 200
} }
])}'; ])}';
@@ -180,6 +196,15 @@ class LastHeardWebSocketClient {
_messageController != null && _messageController != null &&
!_messageController!.isClosed) { !_messageController!.isClosed) {
_messageController!.add(eventData); _messageController!.add(eventData);
// Track received items and disconnect after receiving max items (for search queries)
if (_radioIds != null && _radioIds.isNotEmpty) {
_receivedCount++;
if (_receivedCount >= _maxItems) {
debugPrint('LastHeard WS: Received $_maxItems items, disconnecting');
disconnect();
}
}
} }
} catch (e) { } catch (e) {
debugPrint('LastHeard WS: Error parsing data packet: $e'); debugPrint('LastHeard WS: Error parsing data packet: $e');

View File

@@ -500,7 +500,7 @@ class _DeviceDetailViewState extends State<DeviceDetailView> {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
'Last Heard on Talkgroup', 'Last Activity on Talkgroup',
style: Theme.of(context).textTheme.titleLarge?.copyWith( style: Theme.of(context).textTheme.titleLarge?.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),

View File

@@ -1,7 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/last_heard_item.dart'; import '../models/last_heard_item.dart';
import '../services/authentication_manager.dart';
import '../services/lastheard_websocket_client.dart'; import '../services/lastheard_websocket_client.dart';
class LastHeardView extends StatefulWidget { class LastHeardView extends StatefulWidget {
@@ -36,7 +38,11 @@ class _LastHeardViewState extends State<LastHeardView> {
_isConnecting = true; _isConnecting = true;
}); });
_wsClient = LastHeardWebSocketClient(); final authManager = context.read<AuthenticationManager>();
final devices = await authManager.getDevices();
final radioIds = devices.map((d) => d.id).toList();
_wsClient = LastHeardWebSocketClient(radioIds: radioIds);
await _wsClient!.connect(); await _wsClient!.connect();
_wsSubscription = _wsClient!.messageStream.listen((message) { _wsSubscription = _wsClient!.messageStream.listen((message) {
@@ -53,7 +59,7 @@ class _LastHeardViewState extends State<LastHeardView> {
void _handleMqttMessage(Map<String, dynamic> data) { void _handleMqttMessage(Map<String, dynamic> data) {
try { try {
final topic = data['topic'] as String?; final topic = data['topic'] as String?;
if (topic == 'LH') { if (topic == 'LH-Startup') {
final payloadStr = data['payload'] as String?; final payloadStr = data['payload'] as String?;
if (payloadStr != null) { if (payloadStr != null) {
final payload = jsonDecode(payloadStr) as Map<String, dynamic>; final payload = jsonDecode(payloadStr) as Map<String, dynamic>;
@@ -84,21 +90,7 @@ class _LastHeardViewState extends State<LastHeardView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Last Heard'), title: const Text('Last Activity'),
actions: [
if (_items.isNotEmpty)
Padding(
padding: const EdgeInsets.only(right: 16),
child: Center(
child: Text(
'${_items.length} ${_items.length == 1 ? "entry" : "entries"}',
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onPrimaryContainer,
),
),
),
),
],
), ),
body: _buildBody(), body: _buildBody(),
); );
@@ -112,7 +104,7 @@ class _LastHeardViewState extends State<LastHeardView> {
children: [ children: [
CircularProgressIndicator(), CircularProgressIndicator(),
SizedBox(height: 16), SizedBox(height: 16),
Text('Connecting to Last Heard...'), Text('Connecting to Last Activity...'),
], ],
), ),
); );
@@ -135,7 +127,7 @@ class _LastHeardViewState extends State<LastHeardView> {
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
'Waiting for Last Heard data...', 'Waiting for Last Activity data...',
style: TextStyle(color: Colors.grey[600]), style: TextStyle(color: Colors.grey[600]),
), ),
], ],

View File

@@ -40,7 +40,7 @@ class _MainViewState extends State<MainView> {
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Icons.history), icon: Icon(Icons.history),
label: 'Last Heard', label: 'Last Activity',
), ),
BottomNavigationBarItem( BottomNavigationBarItem(
icon: Icon(Icons.more_horiz), icon: Icon(Icons.more_horiz),