More camera -> node, notifications for approaching

This commit is contained in:
stopflock
2025-09-29 19:22:22 -05:00
parent 6b5f05d036
commit 71fa212d71
28 changed files with 737 additions and 72 deletions
+3
View File
@@ -8,6 +8,7 @@ import 'settings_screen_sections/offline_areas_section.dart';
import 'settings_screen_sections/offline_mode_section.dart';
import 'settings_screen_sections/about_section.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 'settings_screen_sections/language_section.dart';
import '../services/localization_service.dart';
@@ -40,6 +41,8 @@ class SettingsScreen extends StatelessWidget {
const Divider(),
const MaxNodesSection(),
const Divider(),
const ProximityAlertsSection(),
const Divider(),
const TileProviderSection(),
const Divider(),
const OfflineModeSection(),
@@ -0,0 +1,120 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import '../../app_state.dart';
import '../../services/localization_service.dart';
import '../../dev_config.dart';
/// Settings section for proximity alerts configuration
/// Follows brutalist principles: simple, explicit UI that matches existing patterns
class ProximityAlertsSection extends StatefulWidget {
const ProximityAlertsSection({super.key});
@override
State<ProximityAlertsSection> createState() => _ProximityAlertsSectionState();
}
class _ProximityAlertsSectionState extends State<ProximityAlertsSection> {
late final TextEditingController _distanceController;
@override
void initState() {
super.initState();
final appState = context.read<AppState>();
_distanceController = TextEditingController(
text: appState.proximityAlertDistance.toString(),
);
}
@override
void dispose() {
_distanceController.dispose();
super.dispose();
}
void _updateDistance(AppState appState) {
final text = _distanceController.text.trim();
final distance = int.tryParse(text);
if (distance != null) {
appState.setProximityAlertDistance(distance);
} else {
// Reset to current value if invalid
_distanceController.text = appState.proximityAlertDistance.toString();
}
}
@override
Widget build(BuildContext context) {
return Consumer<AppState>(
builder: (context, appState, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Proximity Alerts',
style: Theme.of(context).textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
// Enable/disable toggle
SwitchListTile(
title: const Text('Enable proximity alerts'),
subtitle: const Text(
'Get notified when approaching surveillance devices\n'
'Uses extra battery for continuous location monitoring',
style: TextStyle(fontSize: 12),
),
value: appState.proximityAlertsEnabled,
onChanged: (enabled) {
appState.setProximityAlertsEnabled(enabled);
},
contentPadding: EdgeInsets.zero,
),
// Distance setting (only show when enabled)
if (appState.proximityAlertsEnabled) ...[
const SizedBox(height: 12),
Row(
children: [
const Text('Alert distance: '),
SizedBox(
width: 80,
child: TextField(
controller: _distanceController,
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
decoration: const InputDecoration(
isDense: true,
contentPadding: EdgeInsets.symmetric(
horizontal: 8,
vertical: 8,
),
border: OutlineInputBorder(),
),
onSubmitted: (_) => _updateDistance(appState),
onEditingComplete: () => _updateDistance(appState),
),
),
const SizedBox(width: 8),
const Text('meters'),
],
),
const SizedBox(height: 8),
Text(
'Range: $kProximityAlertMinDistance-$kProximityAlertMaxDistance meters (default: $kProximityAlertDefaultDistance)',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).textTheme.bodySmall?.color?.withOpacity(0.6),
),
),
],
],
);
},
);
}
}