Replace geofence polling with native Android geofence
This commit is contained in:
@@ -22,6 +22,7 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
final _keyCtrl = TextEditingController();
|
||||
final _latCtrl = TextEditingController();
|
||||
final _lonCtrl = TextEditingController();
|
||||
final _radiusCtrl = TextEditingController();
|
||||
bool _geofenceEnabled = false;
|
||||
bool _saving = false;
|
||||
|
||||
@@ -43,8 +44,11 @@ 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
|
||||
@@ -79,6 +83,7 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
_keyCtrl.dispose();
|
||||
_latCtrl.dispose();
|
||||
_lonCtrl.dispose();
|
||||
_radiusCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -224,12 +229,34 @@ 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
|
||||
? 'Автовыключение при удалении на 500 м'
|
||||
? 'Автовыключение после выхода за радиус geofence'
|
||||
: 'Задайте координаты для активации',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
@@ -253,9 +280,9 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(left: 40, bottom: 4),
|
||||
child: Text(
|
||||
'Проверка раз в ~15 мин (ограничение Android).\n'
|
||||
'Работает только для текущего активного дома.\n'
|
||||
'Нужны фоновые разрешения на геолокацию и уведомления.',
|
||||
'Использует системный Android geofence, а не polling.\n'
|
||||
'Нужны фоновые разрешения на геолокацию.',
|
||||
style: TextStyle(fontSize: 11, color: Colors.white24),
|
||||
),
|
||||
),
|
||||
@@ -300,8 +327,9 @@ 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) {
|
||||
if (name.isEmpty || rawUrl.isEmpty || key.isEmpty || radiusText.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Заполните все обязательные поля')),
|
||||
);
|
||||
@@ -348,6 +376,14 @@ 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;
|
||||
@@ -359,6 +395,7 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
geofenceEnabled: clearCoords ? false : _geofenceEnabled,
|
||||
geofenceRadiusMeters: radiusMeters,
|
||||
clearCoordinates: clearCoords,
|
||||
)
|
||||
: HomeConfig(
|
||||
@@ -368,6 +405,7 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
geofenceEnabled: _geofenceEnabled,
|
||||
geofenceRadiusMeters: radiusMeters,
|
||||
);
|
||||
|
||||
try {
|
||||
@@ -384,13 +422,6 @@ class _HomeEditScreenState extends ConsumerState<HomeEditScreen> {
|
||||
await ref.read(currentHomeProvider.notifier).select(home);
|
||||
}
|
||||
|
||||
// Синхронизировать фоновый таск с новыми настройками
|
||||
final allHomes = ref.read(homesProvider);
|
||||
await syncGeofenceTask(
|
||||
allHomes,
|
||||
currentHome: ref.read(currentHomeProvider),
|
||||
);
|
||||
|
||||
if (mounted) Navigator.of(context).pop();
|
||||
} catch (e) {
|
||||
if (mounted) {
|
||||
|
||||
Reference in New Issue
Block a user