Move settings around part 2

This commit is contained in:
stopflock
2025-09-29 23:56:28 -05:00
parent 82501a3131
commit b3a87fc56a
11 changed files with 178 additions and 39 deletions
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'settings_screen_sections/max_nodes_section.dart';
import 'settings_screen_sections/proximity_alerts_section.dart';
import 'settings_screen_sections/tile_provider_section.dart';
import '../services/localization_service.dart';
@@ -21,6 +22,8 @@ class AdvancedSettingsScreen extends StatelessWidget {
children: const [
MaxNodesSection(),
Divider(),
ProximityAlertsSection(),
Divider(),
TileProviderSection(),
],
),
-3
View File
@@ -3,7 +3,6 @@ import 'settings_screen_sections/auth_section.dart';
import 'settings_screen_sections/upload_mode_section.dart';
import 'settings_screen_sections/queue_section.dart';
import 'settings_screen_sections/about_section.dart';
import 'settings_screen_sections/proximity_alerts_section.dart';
import 'settings_screen_sections/language_section.dart';
import '../services/localization_service.dart';
import '../dev_config.dart';
@@ -31,8 +30,6 @@ class SettingsScreen extends StatelessWidget {
const Divider(),
const QueueSection(),
const Divider(),
const ProximityAlertsSection(),
const Divider(),
// Navigation to sub-pages
_buildNavigationTile(
@@ -57,15 +57,11 @@ class _LanguageSectionState extends State<LanguageSection> {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Text(
locService.t('settings.language'),
style: Theme.of(context).textTheme.titleMedium?.copyWith(
color: Theme.of(context).colorScheme.primary,
),
),
Text(
locService.t('settings.language'),
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
// System Default option
RadioListTile<String?>(
title: Text(locService.t('settings.systemDefault')),
@@ -22,7 +22,10 @@ class OperatorProfileListSection extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(locService.t('operatorProfiles.title'), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
Text(
locService.t('operatorProfiles.title'),
style: Theme.of(context).textTheme.titleMedium,
),
TextButton.icon(
onPressed: () => Navigator.push(
context,
@@ -22,7 +22,10 @@ class ProfileListSection extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(locService.t('profiles.nodeProfiles'), style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
Text(
locService.t('profiles.nodeProfiles'),
style: Theme.of(context).textTheme.titleMedium,
),
TextButton.icon(
onPressed: () => Navigator.push(
context,
@@ -82,14 +82,14 @@ class _ProximityAlertsSectionState extends State<ProximityAlertsSection> {
Widget build(BuildContext context) {
return Consumer<AppState>(
builder: (context, appState, child) {
final locService = LocalizationService.instance;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Proximity Alerts',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
locService.t('settings.proximityAlerts'),
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 8),
@@ -4,7 +4,7 @@ import 'package:provider/provider.dart';
import '../../app_state.dart';
import '../../models/tile_provider.dart';
import '../../services/localization_service.dart';
import '../tile_provider_management_screen.dart';
import '../tile_provider_editor_screen.dart';
class TileProviderSection extends StatelessWidget {
const TileProviderSection({super.key});
@@ -15,32 +15,166 @@ class TileProviderSection extends StatelessWidget {
animation: LocalizationService.instance,
builder: (context, child) {
final locService = LocalizationService.instance;
final appState = context.watch<AppState>();
final providers = appState.tileProviders;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
locService.t('mapTiles.title'),
style: Theme.of(context).textTheme.titleMedium,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
locService.t('mapTiles.title'),
style: Theme.of(context).textTheme.titleMedium,
),
TextButton.icon(
onPressed: () => _addProvider(context),
icon: const Icon(Icons.add),
label: Text(locService.t('tileProviders.addProvider')),
),
],
),
const SizedBox(height: 8),
SizedBox(
width: double.infinity,
child: ElevatedButton.icon(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const TileProviderManagementScreen(),
),
);
},
icon: const Icon(Icons.settings),
label: Text(locService.t('mapTiles.manageProviders')),
),
),
if (providers.isEmpty)
Center(
child: Padding(
padding: const EdgeInsets.all(16),
child: Text(locService.t('tileProviders.noProvidersConfigured')),
),
)
else
...providers.map((provider) => _buildProviderTile(context, provider, appState)).toList(),
],
);
},
);
}
Widget _buildProviderTile(BuildContext context, TileProvider provider, AppState appState) {
final locService = LocalizationService.instance;
final isSelected = appState.selectedTileProvider?.id == provider.id;
return Card(
margin: const EdgeInsets.symmetric(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: appState.tileProviders.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')),
),
],
),
);
}
}