mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-08-23 11:22:33 +02:00
Move settings around part 3
This commit is contained in:
+1
-1
@@ -39,7 +39,7 @@ const String kClientName = 'DeFlock';
|
|||||||
const String kClientVersion = '0.9.13';
|
const String kClientVersion = '0.9.13';
|
||||||
|
|
||||||
// Development/testing features - set to false for production builds
|
// Development/testing features - set to false for production builds
|
||||||
const bool kEnableDevelopmentModes = true; // Set to false to hide sandbox/simulate modes and force production mode
|
const bool kEnableDevelopmentModes = false; // Set to false to hide sandbox/simulate modes and force production mode
|
||||||
|
|
||||||
// Marker/node interaction
|
// Marker/node interaction
|
||||||
const int kCameraMinZoomLevel = 10; // Minimum zoom to show nodes (Overpass)
|
const int kCameraMinZoomLevel = 10; // Minimum zoom to show nodes (Overpass)
|
||||||
|
|||||||
@@ -223,6 +223,7 @@
|
|||||||
"operatorProfileDeleted": "Operator profile deleted"
|
"operatorProfileDeleted": "Operator profile deleted"
|
||||||
},
|
},
|
||||||
"offlineAreas": {
|
"offlineAreas": {
|
||||||
|
"title": "Offline Areas",
|
||||||
"noAreasTitle": "No offline areas",
|
"noAreasTitle": "No offline areas",
|
||||||
"noAreasSubtitle": "Download a map area for offline use.",
|
"noAreasSubtitle": "Download a map area for offline use.",
|
||||||
"provider": "Provider",
|
"provider": "Provider",
|
||||||
|
|||||||
@@ -223,6 +223,7 @@
|
|||||||
"operatorProfileDeleted": "Perfil de operador eliminado"
|
"operatorProfileDeleted": "Perfil de operador eliminado"
|
||||||
},
|
},
|
||||||
"offlineAreas": {
|
"offlineAreas": {
|
||||||
|
"title": "Áreas Sin Conexión",
|
||||||
"noAreasTitle": "Sin áreas sin conexión",
|
"noAreasTitle": "Sin áreas sin conexión",
|
||||||
"noAreasSubtitle": "Descarga un área del mapa para uso sin conexión.",
|
"noAreasSubtitle": "Descarga un área del mapa para uso sin conexión.",
|
||||||
"provider": "Proveedor",
|
"provider": "Proveedor",
|
||||||
|
|||||||
@@ -223,6 +223,7 @@
|
|||||||
"operatorProfileDeleted": "Profil d'opérateur supprimé"
|
"operatorProfileDeleted": "Profil d'opérateur supprimé"
|
||||||
},
|
},
|
||||||
"offlineAreas": {
|
"offlineAreas": {
|
||||||
|
"title": "Zones Hors Ligne",
|
||||||
"noAreasTitle": "Aucune zone hors ligne",
|
"noAreasTitle": "Aucune zone hors ligne",
|
||||||
"noAreasSubtitle": "Téléchargez une zone de carte pour utilisation hors ligne.",
|
"noAreasSubtitle": "Téléchargez une zone de carte pour utilisation hors ligne.",
|
||||||
"provider": "Fournisseur",
|
"provider": "Fournisseur",
|
||||||
|
|||||||
@@ -39,13 +39,17 @@ class _MaxNodesSectionState extends State<MaxNodesSection> {
|
|||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
Text(
|
||||||
|
locService.t('settings.maxNodes'),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.filter_alt),
|
leading: const Icon(Icons.filter_alt),
|
||||||
title: Text(locService.t('settings.maxNodes')),
|
title: Text(locService.t('settings.maxNodesSubtitle')),
|
||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(locService.t('settings.maxNodesSubtitle')),
|
|
||||||
if (showWarning)
|
if (showWarning)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||||
|
|||||||
@@ -65,16 +65,22 @@ class _OfflineAreasSectionState extends State<OfflineAreasSection> {
|
|||||||
final locService = LocalizationService.instance;
|
final locService = LocalizationService.instance;
|
||||||
final areas = service.offlineAreas;
|
final areas = service.offlineAreas;
|
||||||
|
|
||||||
if (areas.isEmpty) {
|
|
||||||
return ListTile(
|
|
||||||
leading: const Icon(Icons.download_for_offline),
|
|
||||||
title: Text(locService.t('offlineAreas.noAreasTitle')),
|
|
||||||
subtitle: Text(locService.t('offlineAreas.noAreasSubtitle')),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: areas.map((area) {
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
locService.t('offlineAreas.title'),
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
if (areas.isEmpty)
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.download_for_offline),
|
||||||
|
title: Text(locService.t('offlineAreas.noAreasTitle')),
|
||||||
|
subtitle: Text(locService.t('offlineAreas.noAreasSubtitle')),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
...areas.map((area) {
|
||||||
String diskStr = area.sizeBytes > 0
|
String diskStr = area.sizeBytes > 0
|
||||||
? area.sizeBytes > 1024 * 1024
|
? area.sizeBytes > 1024 * 1024
|
||||||
? "${(area.sizeBytes / (1024 * 1024)).toStringAsFixed(2)} ${locService.t('offlineAreas.megabytes')}"
|
? "${(area.sizeBytes / (1024 * 1024)).toStringAsFixed(2)} ${locService.t('offlineAreas.megabytes')}"
|
||||||
@@ -202,7 +208,8 @@ class _OfflineAreasSectionState extends State<OfflineAreasSection> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
);
|
],
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,14 +61,23 @@ class OfflineModeSection extends StatelessWidget {
|
|||||||
final locService = LocalizationService.instance;
|
final locService = LocalizationService.instance;
|
||||||
final appState = context.watch<AppState>();
|
final appState = context.watch<AppState>();
|
||||||
|
|
||||||
return ListTile(
|
return Column(
|
||||||
leading: const Icon(Icons.wifi_off),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
title: Text(locService.t('settings.offlineMode')),
|
children: [
|
||||||
subtitle: Text(locService.t('settings.offlineModeSubtitle')),
|
Text(
|
||||||
trailing: Switch(
|
locService.t('settings.offlineMode'),
|
||||||
value: appState.offlineMode,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
onChanged: (value) => _handleOfflineModeChange(context, appState, value),
|
),
|
||||||
),
|
const SizedBox(height: 8),
|
||||||
|
ListTile(
|
||||||
|
leading: const Icon(Icons.wifi_off),
|
||||||
|
title: Text(locService.t('settings.offlineModeSubtitle')),
|
||||||
|
trailing: Switch(
|
||||||
|
value: appState.offlineMode,
|
||||||
|
onChanged: (value) => _handleOfflineModeChange(context, appState, value),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -95,9 +95,8 @@ class _ProximityAlertsSectionState extends State<ProximityAlertsSection> {
|
|||||||
|
|
||||||
// Enable/disable toggle
|
// Enable/disable toggle
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: const Text('Enable proximity alerts'),
|
title: const Text('Get notified when approaching surveillance devices'),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'Get notified when approaching surveillance devices\n'
|
|
||||||
'Uses extra battery for continuous location monitoring\n'
|
'Uses extra battery for continuous location monitoring\n'
|
||||||
'${_notificationsEnabled ? "✓ Notifications enabled" : "⚠ Notifications disabled"}',
|
'${_notificationsEnabled ? "✓ Notifications enabled" : "⚠ Notifications disabled"}',
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
|
|||||||
@@ -1,168 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import '../app_state.dart';
|
|
||||||
import '../models/tile_provider.dart';
|
|
||||||
import '../services/localization_service.dart';
|
|
||||||
import 'tile_provider_editor_screen.dart';
|
|
||||||
|
|
||||||
class TileProviderManagementScreen extends StatelessWidget {
|
|
||||||
const TileProviderManagementScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return AnimatedBuilder(
|
|
||||||
animation: LocalizationService.instance,
|
|
||||||
builder: (context, child) {
|
|
||||||
final locService = LocalizationService.instance;
|
|
||||||
final appState = context.watch<AppState>();
|
|
||||||
final providers = appState.tileProviders;
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(locService.t('tileProviders.title')),
|
|
||||||
actions: [
|
|
||||||
IconButton(
|
|
||||||
icon: const Icon(Icons.add),
|
|
||||||
onPressed: () => _addProvider(context),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: providers.isEmpty
|
|
||||||
? Center(
|
|
||||||
child: Text(locService.t('tileProviders.noProvidersConfigured')),
|
|
||||||
)
|
|
||||||
: ListView.builder(
|
|
||||||
itemCount: providers.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final provider = providers[index];
|
|
||||||
final isSelected = appState.selectedTileProvider?.id == provider.id;
|
|
||||||
|
|
||||||
return Card(
|
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(
|
|
||||||
provider.name,
|
|
||||||
style: TextStyle(
|
|
||||||
fontWeight: isSelected ? FontWeight.bold : null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
subtitle: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(locService.t('tileProviders.tileTypesCount', params: [provider.tileTypes.length.toString()])),
|
|
||||||
if (provider.apiKey?.isNotEmpty == true)
|
|
||||||
Text(
|
|
||||||
locService.t('tileProviders.apiKeyConfigured'),
|
|
||||||
style: const TextStyle(
|
|
||||||
fontStyle: FontStyle.italic,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!provider.isUsable)
|
|
||||||
Text(
|
|
||||||
locService.t('tileProviders.needsApiKey'),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.error,
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
leading: CircleAvatar(
|
|
||||||
backgroundColor: isSelected
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Theme.of(context).colorScheme.surfaceVariant,
|
|
||||||
child: Icon(
|
|
||||||
Icons.map,
|
|
||||||
color: isSelected
|
|
||||||
? Theme.of(context).colorScheme.onPrimary
|
|
||||||
: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
trailing: providers.length > 1
|
|
||||||
? PopupMenuButton<String>(
|
|
||||||
onSelected: (action) {
|
|
||||||
switch (action) {
|
|
||||||
case 'edit':
|
|
||||||
_editProvider(context, provider);
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
_deleteProvider(context, provider);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
itemBuilder: (context) => [
|
|
||||||
PopupMenuItem(
|
|
||||||
value: 'edit',
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.edit),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(locService.t('actions.edit')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
|
||||||
value: 'delete',
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Icons.delete),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(locService.t('tileProviders.deleteProvider')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
: const Icon(Icons.lock, size: 16), // Can't delete last provider
|
|
||||||
onTap: () => _editProvider(context, provider),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _addProvider(BuildContext context) {
|
|
||||||
Navigator.of(context).push(
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => const TileProviderEditorScreen(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _editProvider(BuildContext context, TileProvider provider) {
|
|
||||||
Navigator.of(context).push(
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => TileProviderEditorScreen(provider: provider),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _deleteProvider(BuildContext context, TileProvider provider) {
|
|
||||||
final locService = LocalizationService.instance;
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => AlertDialog(
|
|
||||||
title: Text(locService.t('tileProviders.deleteProvider')),
|
|
||||||
content: Text(locService.t('tileProviders.deleteProviderConfirm', params: [provider.name])),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(),
|
|
||||||
child: Text(locService.t('actions.cancel')),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
context.read<AppState>().deleteTileProvider(provider.id);
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Text(locService.t('tileProviders.deleteProvider')),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user