From 3e19d6917ff245863be43a39a76daa7010ecda6f Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Wed, 01 Apr 2026 18:35:25 +0200
Subject: [PATCH] feat: auto-reconnect on network change (WiFi/cellular/VPN switch)
---
lib/services/mqtt_service.dart | 35 +++++++++++++++++++++++++++++++++++
1 files changed, 35 insertions(+), 0 deletions(-)
diff --git a/lib/services/mqtt_service.dart b/lib/services/mqtt_service.dart
index e50adcf..841182d 100644
--- a/lib/services/mqtt_service.dart
+++ b/lib/services/mqtt_service.dart
@@ -5,6 +5,7 @@
import 'package:crypto/crypto.dart';
import 'package:bonsoir/bonsoir.dart';
+import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:path_provider/path_provider.dart' as pp;
@@ -50,6 +51,8 @@
bool _intentionalClose = false;
String? _clientId;
String? _lastDiscoveredHost;
+ StreamSubscription? _connectivitySub;
+ List<ConnectivityResult>? _lastConnectivity;
StreamSubscription? _updatesSub;
// Message deduplication
@@ -103,6 +106,36 @@
_intentionalClose = false;
_setStatus(ConnectionStatus.connecting);
+
+ // Start listening for network changes (WiFi↔cellular, VPN connect/disconnect)
+ _connectivitySub ??= Connectivity().onConnectivityChanged.listen((results) {
+ if (_lastConnectivity != null && !_intentionalClose) {
+ final changed = results.length != _lastConnectivity!.length ||
+ !results.every((r) => _lastConnectivity!.contains(r));
+ if (changed) {
+ _mqttLog('MQTT: network changed: ${results.map((r) => r.name).join(",")} — forcing reconnect');
+ // Force disconnect and reconnect on new network
+ final client = _client;
+ if (client != null) {
+ _intentionalClose = true;
+ client.autoReconnect = false;
+ try { client.disconnect(); } catch (_) {}
+ _client = null;
+ _updatesSub?.cancel();
+ _updatesSub = null;
+ _intentionalClose = false;
+ }
+ _lastDiscoveredHost = null; // Clear cached discovery — subnet may have changed
+ connectedHost = null;
+ connectedVia = null;
+ _setStatus(ConnectionStatus.reconnecting);
+ Future.delayed(const Duration(milliseconds: 500), () {
+ if (!_intentionalClose) connect();
+ });
+ }
+ }
+ _lastConnectivity = results;
+ });
// Load trusted cert fingerprint for TOFU verification
if (_trustedFingerprint == null) await _loadTrustedFingerprint();
@@ -724,6 +757,8 @@
_intentionalClose = true;
_updatesSub?.cancel();
_updatesSub = null;
+ _connectivitySub?.cancel();
+ _connectivitySub = null;
try {
_client?.disconnect();
--
Gitblit v1.3.1