mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-07-20 11:01:03 +02:00
breakup app_state
This commit is contained in:
@@ -8,9 +8,8 @@ import 'package:http/http.dart' as http;
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
/// Handles PKCE OAuth login with OpenStreetMap.
|
||||
import '../app_state.dart';
|
||||
|
||||
import '../keys.dart';
|
||||
import '../app_state.dart' show UploadMode;
|
||||
|
||||
class AuthService {
|
||||
// Both client IDs from keys.dart
|
||||
|
||||
@@ -6,25 +6,47 @@ import '../offline_areas/offline_tile_utils.dart';
|
||||
|
||||
/// Fetch a tile from the newest offline area that plausibly contains it, or throw if not found.
|
||||
Future<List<int>> fetchLocalTile({required int z, required int x, required int y}) async {
|
||||
final areas = OfflineAreaService().offlineAreas;
|
||||
final offlineService = OfflineAreaService();
|
||||
await offlineService.ensureInitialized();
|
||||
final areas = offlineService.offlineAreas;
|
||||
final List<_AreaTileMatch> candidates = [];
|
||||
|
||||
print('[fetchLocalTile] Looking for tile $z/$x/$y in ${areas.length} offline areas');
|
||||
|
||||
for (final area in areas) {
|
||||
if (area.status != OfflineAreaStatus.complete) continue;
|
||||
if (z < area.minZoom || z > area.maxZoom) continue;
|
||||
print('[fetchLocalTile] Checking area: ${area.id}, status: ${area.status}, zoom: ${area.minZoom}-${area.maxZoom}');
|
||||
|
||||
if (area.status != OfflineAreaStatus.complete) {
|
||||
print('[fetchLocalTile] Skipping area ${area.id} - status not complete: ${area.status}');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (z < area.minZoom || z > area.maxZoom) {
|
||||
print('[fetchLocalTile] Skipping area ${area.id} - zoom $z outside range ${area.minZoom}-${area.maxZoom}');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get tile coverage for area at this zoom only
|
||||
final coveredTiles = computeTileList(area.bounds, z, z);
|
||||
final hasTile = coveredTiles.any((tile) => tile[0] == z && tile[1] == x && tile[2] == y);
|
||||
print('[fetchLocalTile] Area ${area.id} covers ${coveredTiles.length} tiles at zoom $z, contains target tile: $hasTile');
|
||||
|
||||
if (hasTile) {
|
||||
final tilePath = _tilePath(area.directory, z, x, y);
|
||||
final file = File(tilePath);
|
||||
if (await file.exists()) {
|
||||
final exists = await file.exists();
|
||||
print('[fetchLocalTile] Tile file path: $tilePath, exists: $exists');
|
||||
|
||||
if (exists) {
|
||||
final stat = await file.stat();
|
||||
candidates.add(_AreaTileMatch(area: area, file: file, modified: stat.modified));
|
||||
print('[fetchLocalTile] Added candidate from area ${area.id}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
print('[fetchLocalTile] Found ${candidates.length} candidates for tile $z/$x/$y');
|
||||
|
||||
if (candidates.isEmpty) {
|
||||
throw Exception('Tile $z/$x/$y not found in any offline area');
|
||||
}
|
||||
|
||||
@@ -17,12 +17,31 @@ import 'package:flock_map_app/dev_config.dart';
|
||||
class OfflineAreaService {
|
||||
static final OfflineAreaService _instance = OfflineAreaService._();
|
||||
factory OfflineAreaService() => _instance;
|
||||
OfflineAreaService._() {
|
||||
_loadAreasFromDisk().then((_) => _ensureAndAutoDownloadWorldArea());
|
||||
}
|
||||
|
||||
bool _initialized = false;
|
||||
Future<void>? _initializationFuture;
|
||||
|
||||
OfflineAreaService._();
|
||||
|
||||
final List<OfflineArea> _areas = [];
|
||||
List<OfflineArea> get offlineAreas => List.unmodifiable(_areas);
|
||||
|
||||
/// Ensure the service is initialized (areas loaded from disk)
|
||||
Future<void> ensureInitialized() async {
|
||||
if (_initialized) return;
|
||||
|
||||
_initializationFuture ??= _initialize();
|
||||
await _initializationFuture;
|
||||
}
|
||||
|
||||
Future<void> _initialize() async {
|
||||
if (_initialized) return;
|
||||
|
||||
await _loadAreasFromDisk();
|
||||
await _ensureAndAutoDownloadWorldArea();
|
||||
_initialized = true;
|
||||
print('OfflineAreaService: Initialization complete. Found ${_areas.length} offline areas.');
|
||||
}
|
||||
|
||||
Future<Directory> getOfflineAreaDir() async {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
@@ -39,6 +58,7 @@ class OfflineAreaService {
|
||||
}
|
||||
|
||||
Future<int> getAreaSizeBytes(OfflineArea area) async {
|
||||
print('[getAreaSizeBytes] Starting for area ${area.id}, status: ${area.status}');
|
||||
int total = 0;
|
||||
final dir = Directory(area.directory);
|
||||
if (await dir.exists()) {
|
||||
@@ -49,14 +69,30 @@ class OfflineAreaService {
|
||||
}
|
||||
}
|
||||
area.sizeBytes = total;
|
||||
print('[getAreaSizeBytes] Before saveAreasToDisk, area ${area.id} status: ${area.status}');
|
||||
await saveAreasToDisk();
|
||||
print('[getAreaSizeBytes] After saveAreasToDisk, area ${area.id} status: ${area.status}');
|
||||
return total;
|
||||
}
|
||||
|
||||
Future<void> saveAreasToDisk() async {
|
||||
try {
|
||||
final file = await _getMetadataPath();
|
||||
final content = jsonEncode(_areas.map((a) => a.toJson()).toList());
|
||||
final offlineDir = await getOfflineAreaDir();
|
||||
|
||||
// Convert areas to JSON with relative paths for portability
|
||||
final areaJsonList = _areas.map((area) {
|
||||
final json = area.toJson();
|
||||
// Convert absolute path to relative path for storage
|
||||
if (json['directory'].toString().startsWith(offlineDir.path)) {
|
||||
final relativePath = json['directory'].toString().replaceFirst('${offlineDir.path}/', '');
|
||||
json['directory'] = relativePath;
|
||||
print('[OfflineAreaService] Saving area ${area.id} with relative path: $relativePath');
|
||||
}
|
||||
return json;
|
||||
}).toList();
|
||||
|
||||
final content = jsonEncode(areaJsonList);
|
||||
await file.writeAsString(content);
|
||||
} catch (e) {
|
||||
debugPrint('Failed to save offline areas: $e');
|
||||
@@ -77,12 +113,49 @@ class OfflineAreaService {
|
||||
return;
|
||||
}
|
||||
_areas.clear();
|
||||
|
||||
for (final areaJson in data) {
|
||||
// Migrate stored directory paths to be relative for portability
|
||||
String storedDir = areaJson['directory'];
|
||||
String relativePath = storedDir;
|
||||
|
||||
// If it's an absolute path, extract just the folder name
|
||||
if (storedDir.startsWith('/')) {
|
||||
if (storedDir.contains('/offline_areas/')) {
|
||||
final parts = storedDir.split('/offline_areas/');
|
||||
if (parts.length == 2) {
|
||||
relativePath = parts[1]; // Just the folder name (e.g., "world" or "2025-08-19...")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Always construct absolute path at runtime
|
||||
final offlineDir = await getOfflineAreaDir();
|
||||
final fullPath = '${offlineDir.path}/$relativePath';
|
||||
|
||||
print('[OfflineAreaService] Area ${areaJson['id']}: stored="$storedDir", relative="$relativePath", full="$fullPath"');
|
||||
|
||||
// Update the JSON to use the full path for this session
|
||||
areaJson['directory'] = fullPath;
|
||||
|
||||
final area = OfflineArea.fromJson(areaJson);
|
||||
|
||||
if (!Directory(area.directory).existsSync()) {
|
||||
print('[OfflineAreaService] Directory does not exist: ${area.directory}');
|
||||
area.status = OfflineAreaStatus.error;
|
||||
} else {
|
||||
print('[OfflineAreaService] Directory exists, getting size...');
|
||||
|
||||
// Reset error status if directory now exists (fixes areas that were previously broken due to path issues)
|
||||
if (area.status == OfflineAreaStatus.error) {
|
||||
print('[OfflineAreaService] Resetting error status to complete for area ${area.id} since directory now exists');
|
||||
area.status = OfflineAreaStatus.complete;
|
||||
}
|
||||
|
||||
print('[OfflineAreaService] Status before getAreaSizeBytes: ${area.status}');
|
||||
getAreaSizeBytes(area);
|
||||
print('[OfflineAreaService] Status after getAreaSizeBytes: ${area.status}');
|
||||
print('[OfflineAreaService] Area ${area.id} loaded successfully');
|
||||
}
|
||||
_areas.add(area);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user