Extract settings and harden geofence automation
This commit is contained in:
@@ -22,8 +22,6 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
final _keyCtrl = TextEditingController();
|
||||
final _latCtrl = TextEditingController();
|
||||
final _lonCtrl = TextEditingController();
|
||||
final _radiusCtrl = TextEditingController();
|
||||
bool _geofenceEnabled = false;
|
||||
bool _saving = false;
|
||||
|
||||
bool get _isEdit => widget.home != null;
|
||||
@@ -44,14 +42,10 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
if (widget.home!.longitude != null) {
|
||||
_lonCtrl.text = widget.home!.longitude.toString();
|
||||
}
|
||||
_radiusCtrl.text = widget.home!.geofenceRadiusMeters.toString();
|
||||
_geofenceEnabled = widget.home!.geofenceEnabled;
|
||||
_loadApiKey();
|
||||
} else {
|
||||
_radiusCtrl.text = HomeConfig.defaultGeofenceRadiusMeters.toString();
|
||||
}
|
||||
|
||||
// Следим за полями координат чтобы обновлять доступность Switch
|
||||
// Следим за полями координат, чтобы обновлять подсказки экрана.
|
||||
_latCtrl.addListener(_onCoordsChanged);
|
||||
_lonCtrl.addListener(_onCoordsChanged);
|
||||
}
|
||||
@@ -66,12 +60,7 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
}
|
||||
|
||||
void _onCoordsChanged() {
|
||||
// Если координаты очистили -- выключаем геофенс
|
||||
if (!_hasCoordinates && _geofenceEnabled) {
|
||||
setState(() => _geofenceEnabled = false);
|
||||
} else {
|
||||
setState(() {}); // перерисовать Switch enabled/disabled
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -83,7 +72,6 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
_keyCtrl.dispose();
|
||||
_latCtrl.dispose();
|
||||
_lonCtrl.dispose();
|
||||
_radiusCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -229,64 +217,17 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
controller: _radiusCtrl,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Радиус geofence, м',
|
||||
hintText: '500',
|
||||
helperText: 'Автовыключение сработает после выхода за этот радиус',
|
||||
prefixIcon: Icon(Icons.radar),
|
||||
),
|
||||
keyboardType: TextInputType.number,
|
||||
validator: (value) {
|
||||
final normalized = value?.trim() ?? '';
|
||||
final radius = int.tryParse(normalized);
|
||||
if (radius == null) {
|
||||
return 'Введите радиус в метрах';
|
||||
}
|
||||
if (radius < 100 || radius > 5000) {
|
||||
return 'От 100 до 5000 м';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
SwitchListTile(
|
||||
title: const Text('Выключать свет при уходе'),
|
||||
subtitle: Text(
|
||||
_hasCoordinates
|
||||
? 'Автовыключение после выхода за радиус geofence'
|
||||
: 'Задайте координаты для активации',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: _hasCoordinates ? Colors.white38 : Colors.white24,
|
||||
),
|
||||
),
|
||||
value: _geofenceEnabled,
|
||||
activeThumbColor: Colors.deepOrange,
|
||||
onChanged: _hasCoordinates
|
||||
? (v) => setState(() => _geofenceEnabled = v)
|
||||
: null,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
secondary: Icon(
|
||||
Icons.directions_walk,
|
||||
color: _geofenceEnabled && _hasCoordinates
|
||||
? Colors.deepOrange
|
||||
: Colors.white24,
|
||||
),
|
||||
),
|
||||
if (_geofenceEnabled && _hasCoordinates)
|
||||
if (_hasCoordinates)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 40, bottom: 4),
|
||||
padding: EdgeInsets.only(bottom: 24),
|
||||
child: Text(
|
||||
'Работает только для текущего активного дома.\n'
|
||||
'Использует системный Android geofence, а не polling.\n'
|
||||
'Нужны фоновые разрешения на геолокацию.',
|
||||
style: TextStyle(fontSize: 11, color: Colors.white24),
|
||||
'Geofence и радиус настраиваются отдельно на экране настроек.',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white38),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
)
|
||||
else
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
height: 48,
|
||||
@@ -327,9 +268,8 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
final key = _keyCtrl.text.trim();
|
||||
final latText = _latCtrl.text.trim();
|
||||
final lonText = _lonCtrl.text.trim();
|
||||
final radiusText = _radiusCtrl.text.trim();
|
||||
|
||||
if (name.isEmpty || rawUrl.isEmpty || key.isEmpty || radiusText.isEmpty) {
|
||||
if (name.isEmpty || rawUrl.isEmpty || key.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Заполните все обязательные поля')),
|
||||
);
|
||||
@@ -376,14 +316,6 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
final radiusMeters = int.tryParse(radiusText);
|
||||
if (radiusMeters == null || radiusMeters < 100 || radiusMeters > 5000) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Радиус geofence должен быть от 100 до 5000 м')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
setState(() => _saving = true);
|
||||
|
||||
final clearCoords = latText.isEmpty && lonText.isEmpty;
|
||||
@@ -394,8 +326,6 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
url: url,
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
geofenceEnabled: clearCoords ? false : _geofenceEnabled,
|
||||
geofenceRadiusMeters: radiusMeters,
|
||||
clearCoordinates: clearCoords,
|
||||
)
|
||||
: HomeConfig(
|
||||
@@ -404,8 +334,6 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
url: url,
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
geofenceEnabled: _geofenceEnabled,
|
||||
geofenceRadiusMeters: radiusMeters,
|
||||
);
|
||||
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user