Replace geofence polling with native Android geofence

This commit is contained in:
Artem Kokos
2026-05-12 11:23:44 +07:00
parent 0a5ef9af17
commit 1963488479
38 changed files with 1099 additions and 1931 deletions

View File

@@ -0,0 +1,40 @@
import 'package:flutter/services.dart';
import '../../../models/home_config.dart';
import '../../../services/settings_service.dart';
class GeofenceAutomationService {
GeofenceAutomationService({SettingsService? settingsService})
: _settingsService = settingsService ?? SettingsService();
static const _channel = MethodChannel('ignis/geofence_automation');
final SettingsService _settingsService;
Future<void> syncActiveHome(HomeConfig? home) async {
if (home == null || !home.geofenceReady) {
await _invoke('disarmGeofence');
return;
}
final apiKey = await _settingsService.requireHomeApiKey(home.id);
await _invoke('armGeofence', {
'homeId': home.id,
'baseUrl': home.url,
'apiKey': apiKey,
'latitude': home.latitude,
'longitude': home.longitude,
'radiusMeters': home.geofenceRadiusMeters,
});
}
Future<void> _invoke(String method, [Map<String, Object?>? arguments]) async {
try {
await _channel.invokeMethod<void>(method, arguments);
} on MissingPluginException {
// В тестах и на не-Android средах platform channel может отсутствовать.
} on PlatformException {
rethrow;
}
}
}

View File

@@ -1,53 +0,0 @@
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class GeofenceNotificationsService {
final FlutterLocalNotificationsPlugin _plugin;
GeofenceNotificationsService({FlutterLocalNotificationsPlugin? plugin})
: _plugin = plugin ?? FlutterLocalNotificationsPlugin();
Future<void> initialize() async {
if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
return;
}
const settings = InitializationSettings(
android: AndroidInitializationSettings('@mipmap/ic_launcher'),
);
await _plugin.initialize(settings);
}
Future<bool> areNotificationsEnabled() async {
if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
return true;
}
try {
final android = _plugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>();
return await android?.areNotificationsEnabled() ?? true;
} catch (_) {
return true;
}
}
Future<bool> requestNotificationsPermission() async {
if (kIsWeb || defaultTargetPlatform != TargetPlatform.android) {
return true;
}
try {
final android = _plugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin
>();
final granted = await android?.requestNotificationsPermission();
return granted ?? await areNotificationsEnabled();
} catch (_) {
return false;
}
}
}

View File

@@ -1,53 +0,0 @@
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
import '../models/geofence_runtime_state.dart';
class GeofenceRuntimeStore {
static const String _runtimeKey = 'ignis_geofence_runtime';
Future<GeofenceRuntimeState> load() async {
final prefs = await SharedPreferences.getInstance();
final raw = prefs.getString(_runtimeKey);
if (raw == null || raw.isEmpty) {
return const GeofenceRuntimeState();
}
final decoded = jsonDecode(raw);
if (decoded is! Map<String, dynamic>) {
return const GeofenceRuntimeState();
}
return GeofenceRuntimeState.fromJson(decoded);
}
Future<void> save(GeofenceRuntimeState state) async {
final prefs = await SharedPreferences.getInstance();
final data = state.toJson();
if (data.isEmpty) {
await prefs.remove(_runtimeKey);
return;
}
await prefs.setString(_runtimeKey, jsonEncode(data));
}
Future<GeofenceRuntimeState> armForHome(String homeId) async {
final next = (await load()).armForHome(homeId);
await save(next);
return next;
}
Future<GeofenceRuntimeState> disarm() async {
final next = (await load()).disarm();
await save(next);
return next;
}
Future<GeofenceRuntimeState> removeHome(String homeId) async {
final next = (await load()).removeHome(homeId);
await save(next);
return next;
}
}