Matthias Nott
2026-04-01 1f5e5967edb4146b10f077dd7d38e73385b2ebfd
feat: show connection method (Local/VPN/Remote/Discovered) in app bar and settings
4 files modified
changed files
lib/providers/providers.dart patch | view | blame | history
lib/screens/chat_screen.dart patch | view | blame | history
lib/screens/settings_screen.dart patch | view | blame | history
lib/services/mqtt_service.dart patch | view | blame | history
lib/providers/providers.dart
....@@ -62,6 +62,7 @@
6262 StateProvider<ConnectionStatus>((ref) => ConnectionStatus.disconnected);
6363
6464 final connectionDetailProvider = StateProvider<String>((ref) => '');
65
+final connectedViaProvider = StateProvider<String>((ref) => '');
6566
6667 // --- Sessions ---
6768
lib/screens/chat_screen.dart
....@@ -196,6 +196,9 @@
196196 ref.read(wsStatusProvider.notifier).state = status;
197197 if (status == ConnectionStatus.connected) {
198198 ref.read(connectionDetailProvider.notifier).state = '';
199
+ ref.read(connectedViaProvider.notifier).state = _ws?.connectedVia ?? '';
200
+ } else {
201
+ ref.read(connectedViaProvider.notifier).state = '';
199202 }
200203 }
201204 };
....@@ -1417,6 +1420,11 @@
14171420 connectionDetail,
14181421 style: TextStyle(fontSize: 11, color: Colors.grey.shade400),
14191422 ),
1423
+ if (wsStatus == ConnectionStatus.connected && ref.watch(connectedViaProvider).isNotEmpty)
1424
+ Text(
1425
+ 'via ${ref.watch(connectedViaProvider)}',
1426
+ style: TextStyle(fontSize: 11, color: Colors.grey.shade500),
1427
+ ),
14201428 ],
14211429 ),
14221430 actions: [
lib/screens/settings_screen.dart
....@@ -138,9 +138,24 @@
138138 children: [
139139 StatusDot(status: wsStatus),
140140 const SizedBox(width: 12),
141
- Text(
142
- _statusText(wsStatus),
143
- style: Theme.of(context).textTheme.bodyLarge,
141
+ Expanded(
142
+ child: Column(
143
+ crossAxisAlignment: CrossAxisAlignment.start,
144
+ children: [
145
+ Text(
146
+ _statusText(wsStatus),
147
+ style: Theme.of(context).textTheme.bodyLarge,
148
+ ),
149
+ if (ref.watch(connectedViaProvider).isNotEmpty)
150
+ Text(
151
+ 'via ${ref.watch(connectedViaProvider)}',
152
+ style: TextStyle(
153
+ fontSize: 12,
154
+ color: Colors.grey.shade500,
155
+ ),
156
+ ),
157
+ ],
158
+ ),
144159 ),
145160 ],
146161 ),
lib/services/mqtt_service.dart
....@@ -60,6 +60,8 @@
6060 // Callbacks
6161 void Function(ConnectionStatus status)? onStatusChanged;
6262 void Function(String detail)? onStatusDetail; // "Probing local...", "Scanning network..."
63
+ String? connectedHost; // The host we're currently connected to
64
+ String? connectedVia; // "Local", "VPN", "Remote", "Bonjour", "Scan"
6365 void Function(Map<String, dynamic> message)? onMessage;
6466 void Function()? onOpen;
6567 void Function()? onClose;
....@@ -158,12 +160,27 @@
158160 }
159161
160162 if (winner != null && !_intentionalClose) {
161
- _mqttLog('MQTT: winner: $winner, connecting...');
162
- onStatusDetail?.call('Connecting to $winner...');
163
+ // Determine connection method label
164
+ if (winner == config.localHost) {
165
+ connectedVia = 'Local';
166
+ } else if (winner == config.vpnHost) {
167
+ connectedVia = 'VPN';
168
+ } else if (winner == config.host) {
169
+ connectedVia = 'Remote';
170
+ } else if (winner == _lastDiscoveredHost) {
171
+ connectedVia = 'Discovered';
172
+ } else {
173
+ connectedVia = winner;
174
+ }
175
+ connectedHost = winner;
176
+ _mqttLog('MQTT: winner: $winner ($connectedVia), connecting...');
177
+ onStatusDetail?.call('Connecting via $connectedVia...');
163178 try {
164179 if (await _tryConnect(winner, clientId, timeout: 5000)) return;
165180 } catch (e) {
166181 _mqttLog('MQTT: connect to $winner failed: $e');
182
+ connectedHost = null;
183
+ connectedVia = null;
167184 }
168185 }
169186