Replace geofence polling with native Android geofence
This commit is contained in:
@@ -1,226 +0,0 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
|
||||
import '../../../app/load_state.dart';
|
||||
import '../../../models/home_config.dart';
|
||||
import '../geofence_logic.dart';
|
||||
import '../models/geofence_diagnostics.dart';
|
||||
import '../models/geofence_runtime_state.dart';
|
||||
import '../services/geofence_notifications_service.dart';
|
||||
import '../services/geofence_runtime_store.dart';
|
||||
import 'homes_providers.dart';
|
||||
|
||||
final geofenceRuntimeStoreProvider = Provider((ref) => GeofenceRuntimeStore());
|
||||
|
||||
final geofenceNotificationsServiceProvider = Provider(
|
||||
(ref) => GeofenceNotificationsService(),
|
||||
);
|
||||
|
||||
final geofenceDiagnosticsProvider =
|
||||
NotifierProvider<
|
||||
GeofenceDiagnosticsNotifier,
|
||||
LoadState<GeofenceDiagnostics>
|
||||
>(GeofenceDiagnosticsNotifier.new);
|
||||
|
||||
class GeofenceDiagnosticsNotifier
|
||||
extends Notifier<LoadState<GeofenceDiagnostics>> {
|
||||
bool _refreshing = false;
|
||||
|
||||
@override
|
||||
LoadState<GeofenceDiagnostics> build() {
|
||||
return const LoadState.idle(GeofenceDiagnostics.initial());
|
||||
}
|
||||
|
||||
Future<void> refresh() async {
|
||||
if (_refreshing) return;
|
||||
_refreshing = true;
|
||||
|
||||
final previous = state.data;
|
||||
state = LoadState.loading(previous);
|
||||
|
||||
try {
|
||||
final currentHome = ref.read(currentHomeProvider);
|
||||
final runtime = await ref.read(geofenceRuntimeStoreProvider).load();
|
||||
|
||||
if (currentHome == null) {
|
||||
state = LoadState.data(
|
||||
GeofenceDiagnostics(
|
||||
activeHome: null,
|
||||
status: GeofenceStatusKind.noActiveHome,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: LocationPermission.denied,
|
||||
notificationsEnabled: true,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentHome.geofenceEnabled) {
|
||||
state = LoadState.data(
|
||||
GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.disabled,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: LocationPermission.denied,
|
||||
notificationsEnabled: true,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!currentHome.hasCoordinates) {
|
||||
state = LoadState.data(
|
||||
GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.missingCoordinates,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: LocationPermission.denied,
|
||||
notificationsEnabled: true,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final locationServicesEnabled =
|
||||
await Geolocator.isLocationServiceEnabled();
|
||||
final locationPermission = await Geolocator.checkPermission();
|
||||
final notificationsEnabled = await ref
|
||||
.read(geofenceNotificationsServiceProvider)
|
||||
.areNotificationsEnabled();
|
||||
|
||||
final diagnostics = _buildDiagnostics(
|
||||
currentHome: currentHome,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: locationServicesEnabled,
|
||||
locationPermission: locationPermission,
|
||||
notificationsEnabled: notificationsEnabled,
|
||||
);
|
||||
state = LoadState.data(diagnostics);
|
||||
} catch (error) {
|
||||
state = LoadState.error(
|
||||
previous,
|
||||
'Не удалось обновить состояние geofence: $error',
|
||||
);
|
||||
} finally {
|
||||
_refreshing = false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> requestLocationPermission() async {
|
||||
await Geolocator.requestPermission();
|
||||
await refresh();
|
||||
}
|
||||
|
||||
Future<void> requestBackgroundLocationPermission() async {
|
||||
final result = await Geolocator.requestPermission();
|
||||
if (!hasBackgroundLocationAccess(result)) {
|
||||
await Geolocator.openAppSettings();
|
||||
}
|
||||
await refresh();
|
||||
}
|
||||
|
||||
Future<void> requestNotificationPermission() async {
|
||||
await ref
|
||||
.read(geofenceNotificationsServiceProvider)
|
||||
.requestNotificationsPermission();
|
||||
await refresh();
|
||||
}
|
||||
|
||||
Future<void> openAppSettings() async {
|
||||
await Geolocator.openAppSettings();
|
||||
}
|
||||
|
||||
Future<void> openLocationSettings() async {
|
||||
await Geolocator.openLocationSettings();
|
||||
}
|
||||
|
||||
GeofenceDiagnostics _buildDiagnostics({
|
||||
required HomeConfig currentHome,
|
||||
required GeofenceRuntimeState runtime,
|
||||
required bool locationServicesEnabled,
|
||||
required LocationPermission locationPermission,
|
||||
required bool notificationsEnabled,
|
||||
}) {
|
||||
if (!locationServicesEnabled) {
|
||||
return GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.locationServicesDisabled,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: false,
|
||||
locationPermission: locationPermission,
|
||||
notificationsEnabled: notificationsEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasForegroundLocationAccess(locationPermission)) {
|
||||
return GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.locationPermissionDenied,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: locationPermission,
|
||||
notificationsEnabled: notificationsEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasBackgroundLocationAccess(locationPermission)) {
|
||||
return GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.backgroundPermissionDenied,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: locationPermission,
|
||||
notificationsEnabled: notificationsEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
if (!notificationsEnabled) {
|
||||
return GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.notificationsPermissionDenied,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: locationPermission,
|
||||
notificationsEnabled: false,
|
||||
);
|
||||
}
|
||||
|
||||
final failureAt = runtime.failureAtFor(currentHome.id);
|
||||
final retryRemaining = geofenceRetryRemaining(failureAt);
|
||||
if (retryRemaining != null) {
|
||||
return GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.cooldown,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: locationPermission,
|
||||
notificationsEnabled: true,
|
||||
retryRemaining: retryRemaining,
|
||||
detail: runtime.failureMessageFor(currentHome.id),
|
||||
);
|
||||
}
|
||||
|
||||
if (runtime.isTriggeredFor(currentHome.id)) {
|
||||
return GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.triggered,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: locationPermission,
|
||||
notificationsEnabled: true,
|
||||
);
|
||||
}
|
||||
|
||||
return GeofenceDiagnostics(
|
||||
activeHome: currentHome,
|
||||
status: GeofenceStatusKind.ready,
|
||||
runtime: runtime,
|
||||
locationServicesEnabled: true,
|
||||
locationPermission: locationPermission,
|
||||
notificationsEnabled: true,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../../../models/home_config.dart';
|
||||
import '../geofence_task_sync.dart';
|
||||
import '../services/geofence_runtime_store.dart';
|
||||
import '../../auth/providers/auth_providers.dart';
|
||||
import '../../shared/providers/core_providers.dart';
|
||||
|
||||
@@ -22,6 +20,7 @@ class CurrentHomeNotifier extends Notifier<HomeConfig?> {
|
||||
if (state != null) {
|
||||
await _initApi(state!);
|
||||
}
|
||||
await ref.read(geofenceAutomationServiceProvider).syncActiveHome(state);
|
||||
}
|
||||
|
||||
/// Переключиться на другой дом
|
||||
@@ -30,6 +29,7 @@ class CurrentHomeNotifier extends Notifier<HomeConfig?> {
|
||||
await svc.setCurrentHomeId(home.id);
|
||||
state = home;
|
||||
await _initApi(home);
|
||||
await ref.read(geofenceAutomationServiceProvider).syncActiveHome(state);
|
||||
}
|
||||
|
||||
/// Выбрать дом как активный и сразу проверить auth-state.
|
||||
@@ -41,11 +41,9 @@ class CurrentHomeNotifier extends Notifier<HomeConfig?> {
|
||||
try {
|
||||
await switchTo(home);
|
||||
await ref.read(authInfoProvider.notifier).load(failOnError: true);
|
||||
await syncGeofenceTask(ref.read(homesProvider), currentHome: state);
|
||||
} catch (error) {
|
||||
await _restoreSelection(previousHome);
|
||||
ref.read(authInfoProvider.notifier).restore(previousAuthState);
|
||||
await syncGeofenceTask(ref.read(homesProvider), currentHome: state);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -53,7 +51,7 @@ class CurrentHomeNotifier extends Notifier<HomeConfig?> {
|
||||
Future<void> clear() async {
|
||||
await ref.read(settingsServiceProvider).setCurrentHomeId(null);
|
||||
state = null;
|
||||
await syncGeofenceTask(ref.read(homesProvider), currentHome: null);
|
||||
await ref.read(geofenceAutomationServiceProvider).syncActiveHome(null);
|
||||
}
|
||||
|
||||
/// Инициализировать API-клиент текущим домом
|
||||
@@ -74,6 +72,7 @@ class CurrentHomeNotifier extends Notifier<HomeConfig?> {
|
||||
await svc.setCurrentHomeId(home.id);
|
||||
state = home;
|
||||
await _initApi(home);
|
||||
await ref.read(geofenceAutomationServiceProvider).syncActiveHome(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +95,6 @@ class HomesNotifier extends Notifier<List<HomeConfig>> {
|
||||
|
||||
Future<void> remove(String id) async {
|
||||
await ref.read(settingsServiceProvider).deleteHome(id);
|
||||
await GeofenceRuntimeStore().removeHome(id);
|
||||
await load();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user