mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-08-15 15:40:32 +02:00
add no offline data status indicator
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import '../app_state.dart';
|
||||||
|
|
||||||
enum NetworkIssueType { osmTiles, overpassApi, both }
|
enum NetworkIssueType { osmTiles, overpassApi, both }
|
||||||
enum NetworkStatusType { waiting, issues, timedOut, ready }
|
enum NetworkStatusType { waiting, issues, timedOut, noData, ready }
|
||||||
|
|
||||||
class NetworkStatus extends ChangeNotifier {
|
class NetworkStatus extends ChangeNotifier {
|
||||||
static final NetworkStatus instance = NetworkStatus._();
|
static final NetworkStatus instance = NetworkStatus._();
|
||||||
@@ -12,9 +14,12 @@ class NetworkStatus extends ChangeNotifier {
|
|||||||
bool _overpassHasIssues = false;
|
bool _overpassHasIssues = false;
|
||||||
bool _isWaitingForData = false;
|
bool _isWaitingForData = false;
|
||||||
bool _isTimedOut = false;
|
bool _isTimedOut = false;
|
||||||
|
bool _hasNoData = false;
|
||||||
|
int _recentOfflineMisses = 0;
|
||||||
Timer? _osmRecoveryTimer;
|
Timer? _osmRecoveryTimer;
|
||||||
Timer? _overpassRecoveryTimer;
|
Timer? _overpassRecoveryTimer;
|
||||||
Timer? _waitingTimer;
|
Timer? _waitingTimer;
|
||||||
|
Timer? _noDataResetTimer;
|
||||||
|
|
||||||
// Getters
|
// Getters
|
||||||
bool get hasAnyIssues => _osmTilesHaveIssues || _overpassHasIssues;
|
bool get hasAnyIssues => _osmTilesHaveIssues || _overpassHasIssues;
|
||||||
@@ -22,11 +27,13 @@ class NetworkStatus extends ChangeNotifier {
|
|||||||
bool get overpassHasIssues => _overpassHasIssues;
|
bool get overpassHasIssues => _overpassHasIssues;
|
||||||
bool get isWaitingForData => _isWaitingForData;
|
bool get isWaitingForData => _isWaitingForData;
|
||||||
bool get isTimedOut => _isTimedOut;
|
bool get isTimedOut => _isTimedOut;
|
||||||
|
bool get hasNoData => _hasNoData;
|
||||||
|
|
||||||
NetworkStatusType get currentStatus {
|
NetworkStatusType get currentStatus {
|
||||||
if (hasAnyIssues) return NetworkStatusType.issues;
|
if (hasAnyIssues) return NetworkStatusType.issues;
|
||||||
if (_isWaitingForData) return NetworkStatusType.waiting;
|
if (_isWaitingForData) return NetworkStatusType.waiting;
|
||||||
if (_isTimedOut) return NetworkStatusType.timedOut;
|
if (_isTimedOut) return NetworkStatusType.timedOut;
|
||||||
|
if (_hasNoData) return NetworkStatusType.noData;
|
||||||
return NetworkStatusType.ready;
|
return NetworkStatusType.ready;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,8 +100,11 @@ class NetworkStatus extends ChangeNotifier {
|
|||||||
|
|
||||||
/// Set waiting status (show when loading tiles/cameras)
|
/// Set waiting status (show when loading tiles/cameras)
|
||||||
void setWaiting() {
|
void setWaiting() {
|
||||||
// Clear any previous timeout state when starting new wait
|
// Clear any previous timeout/no-data state when starting new wait
|
||||||
_isTimedOut = false;
|
_isTimedOut = false;
|
||||||
|
_hasNoData = false;
|
||||||
|
_recentOfflineMisses = 0;
|
||||||
|
_noDataResetTimer?.cancel();
|
||||||
|
|
||||||
if (!_isWaitingForData) {
|
if (!_isWaitingForData) {
|
||||||
_isWaitingForData = true;
|
_isWaitingForData = true;
|
||||||
@@ -102,25 +112,58 @@ class NetworkStatus extends ChangeNotifier {
|
|||||||
debugPrint('[NetworkStatus] Waiting for data...');
|
debugPrint('[NetworkStatus] Waiting for data...');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set timeout to show "timed out" status after reasonable time
|
// Set timeout to show appropriate status after reasonable time
|
||||||
_waitingTimer?.cancel();
|
_waitingTimer?.cancel();
|
||||||
_waitingTimer = Timer(const Duration(seconds: 10), () {
|
_waitingTimer = Timer(const Duration(seconds: 10), () {
|
||||||
_isWaitingForData = false;
|
_isWaitingForData = false;
|
||||||
_isTimedOut = true;
|
|
||||||
|
// If in offline mode, this is "no data" not "timed out"
|
||||||
|
if (AppState.instance.offlineMode) {
|
||||||
|
_hasNoData = true;
|
||||||
|
debugPrint('[NetworkStatus] No offline data available (timeout in offline mode)');
|
||||||
|
} else {
|
||||||
|
_isTimedOut = true;
|
||||||
|
debugPrint('[NetworkStatus] Data request timed out (online mode)');
|
||||||
|
}
|
||||||
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
debugPrint('[NetworkStatus] Data request timed out');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clear waiting/timeout status when data arrives
|
/// Clear waiting/timeout/no-data status when data arrives
|
||||||
void clearWaiting() {
|
void clearWaiting() {
|
||||||
if (_isWaitingForData || _isTimedOut) {
|
if (_isWaitingForData || _isTimedOut || _hasNoData) {
|
||||||
_isWaitingForData = false;
|
_isWaitingForData = false;
|
||||||
_isTimedOut = false;
|
_isTimedOut = false;
|
||||||
|
_hasNoData = false;
|
||||||
|
_recentOfflineMisses = 0;
|
||||||
|
_waitingTimer?.cancel();
|
||||||
|
_noDataResetTimer?.cancel();
|
||||||
|
notifyListeners();
|
||||||
|
debugPrint('[NetworkStatus] Waiting/timeout/no-data status cleared - data arrived');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Report that a tile was not available offline
|
||||||
|
void reportOfflineMiss() {
|
||||||
|
_recentOfflineMisses++;
|
||||||
|
debugPrint('[NetworkStatus] Offline miss #$_recentOfflineMisses');
|
||||||
|
|
||||||
|
// If we get several misses in a short time, show "no data" status
|
||||||
|
if (_recentOfflineMisses >= 3 && !_hasNoData) {
|
||||||
|
_isWaitingForData = false;
|
||||||
|
_isTimedOut = false;
|
||||||
|
_hasNoData = true;
|
||||||
_waitingTimer?.cancel();
|
_waitingTimer?.cancel();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
debugPrint('[NetworkStatus] Waiting/timeout status cleared - data arrived');
|
debugPrint('[NetworkStatus] No offline data available for this area');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset the miss counter after some time
|
||||||
|
_noDataResetTimer?.cancel();
|
||||||
|
_noDataResetTimer = Timer(const Duration(seconds: 5), () {
|
||||||
|
_recentOfflineMisses = 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -128,6 +171,7 @@ class NetworkStatus extends ChangeNotifier {
|
|||||||
_osmRecoveryTimer?.cancel();
|
_osmRecoveryTimer?.cancel();
|
||||||
_overpassRecoveryTimer?.cancel();
|
_overpassRecoveryTimer?.cancel();
|
||||||
_waitingTimer?.cancel();
|
_waitingTimer?.cancel();
|
||||||
|
_noDataResetTimer?.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,6 +70,8 @@ class SimpleTileHttpClient extends http.BaseClient {
|
|||||||
// Check if we're in offline mode
|
// Check if we're in offline mode
|
||||||
if (AppState.instance.offlineMode) {
|
if (AppState.instance.offlineMode) {
|
||||||
debugPrint('[SimpleTileService] Offline mode - not attempting OSM fetch for $z/$x/$y');
|
debugPrint('[SimpleTileService] Offline mode - not attempting OSM fetch for $z/$x/$y');
|
||||||
|
// Report that we couldn't serve this tile offline
|
||||||
|
NetworkStatus.instance.reportOfflineMiss();
|
||||||
return http.StreamedResponse(
|
return http.StreamedResponse(
|
||||||
Stream.value(<int>[]),
|
Stream.value(<int>[]),
|
||||||
404,
|
404,
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ class NetworkStatusIndicator extends StatelessWidget {
|
|||||||
color = Colors.orange;
|
color = Colors.orange;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NetworkStatusType.noData:
|
||||||
|
message = 'No offline data';
|
||||||
|
icon = Icons.cloud_off;
|
||||||
|
color = Colors.grey;
|
||||||
|
break;
|
||||||
|
|
||||||
case NetworkStatusType.issues:
|
case NetworkStatusType.issues:
|
||||||
switch (networkStatus.currentIssueType) {
|
switch (networkStatus.currentIssueType) {
|
||||||
case NetworkIssueType.osmTiles:
|
case NetworkIssueType.osmTiles:
|
||||||
|
|||||||
Reference in New Issue
Block a user