fix(mobile): preserve channel list across background/resume reconnection (#588)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Wes
2026-05-14 21:24:54 +00:00
committed by GitHub
co-authored by Claude Opus 4.6
parent 8a2d24e4fd
commit 586b3678d9
2 changed files with 27 additions and 10 deletions
@@ -48,6 +48,14 @@ class ChannelsNotifier extends AsyncNotifier<List<Channel>> {
if (sessionState.status != SessionStatus.connected) {
_clearLiveSubscriptions();
// Preserve the last successfully loaded channels while reconnecting
// instead of re-entering a loading/error state. The UI will show cached
// channels with a "Reconnecting…" banner overlay, which is far better
// than a blank screen.
final previous = state.value;
if (previous != null && previous.isNotEmpty) {
return Future.value(previous);
}
}
return _fetch(
@@ -318,10 +326,13 @@ class ChannelsNotifier extends AsyncNotifier<List<Channel>> {
Future<void> refresh() async {
final sessionState = ref.read(relaySessionProvider);
state = await AsyncValue.guard(
() =>
_fetch(subscribeLive: sessionState.status == SessionStatus.connected),
);
// Don't attempt to fetch when the session isn't connected — fetchHistory
// would send REQs over an unauthenticated socket that either time out
// (returning empty results) or get cancelled on disconnect, replacing the
// cached channel list with [] or an error. Wait for `build()` to re-run
// when the session transitions to connected.
if (sessionState.status != SessionStatus.connected) return;
state = await AsyncValue.guard(() => _fetch(subscribeLive: true));
}
void _clearLiveSubscriptions() {
+12 -6
View File
@@ -231,7 +231,7 @@ class RelaySessionNotifier extends Notifier<SessionState> {
/// Called by the app lifecycle provider when the app goes to background.
void onAppPaused() {
_backgroundGraceTimer?.cancel();
_backgroundGraceTimer = Timer(const Duration(seconds: 30), () {
_backgroundGraceTimer = Timer(const Duration(seconds: 5), () {
_socket?.disconnect();
state = const SessionState(status: SessionStatus.disconnected);
});
@@ -241,11 +241,17 @@ class RelaySessionNotifier extends Notifier<SessionState> {
void onAppResumed() {
_backgroundGraceTimer?.cancel();
_backgroundGraceTimer = null;
if (state.status == SessionStatus.disconnected) {
_reconnectDelayMs = _baseReconnectDelayMs;
final config = ref.read(relayConfigProvider);
_connect(config);
}
// If still connected, nothing to do — the socket survived the background
// grace window.
if (state.status == SessionStatus.connected) return;
// Cancel any in-flight reconnect backoff timer so we reconnect immediately
// instead of waiting for the (possibly large) exponential delay.
_reconnectTimer?.cancel();
_reconnectDelayMs = _baseReconnectDelayMs;
final config = ref.read(relayConfigProvider);
_connect(config);
}
// -------------------------------------------------------------------------