Files
ignis_app/lib/features/homes/providers/geofence_providers.dart
2026-05-01 09:13:23 +07:00

227 lines
6.8 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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,
);
}
}