feat: harden geofence and distance diagnostics
This commit is contained in:
123
lib/features/homes/models/geofence_diagnostics.dart
Normal file
123
lib/features/homes/models/geofence_diagnostics.dart
Normal file
@@ -0,0 +1,123 @@
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
|
||||
import '../../../models/home_config.dart';
|
||||
import '../geofence_logic.dart';
|
||||
import 'geofence_runtime_state.dart';
|
||||
|
||||
enum GeofenceStatusKind {
|
||||
noActiveHome,
|
||||
disabled,
|
||||
missingCoordinates,
|
||||
locationServicesDisabled,
|
||||
locationPermissionDenied,
|
||||
backgroundPermissionDenied,
|
||||
notificationsPermissionDenied,
|
||||
cooldown,
|
||||
triggered,
|
||||
ready,
|
||||
}
|
||||
|
||||
class GeofenceDiagnostics {
|
||||
final HomeConfig? activeHome;
|
||||
final GeofenceStatusKind status;
|
||||
final GeofenceRuntimeState runtime;
|
||||
final bool locationServicesEnabled;
|
||||
final LocationPermission locationPermission;
|
||||
final bool notificationsEnabled;
|
||||
final Duration? retryRemaining;
|
||||
final String? detail;
|
||||
|
||||
const GeofenceDiagnostics({
|
||||
required this.activeHome,
|
||||
required this.status,
|
||||
required this.runtime,
|
||||
required this.locationServicesEnabled,
|
||||
required this.locationPermission,
|
||||
required this.notificationsEnabled,
|
||||
this.retryRemaining,
|
||||
this.detail,
|
||||
});
|
||||
|
||||
const GeofenceDiagnostics.initial()
|
||||
: activeHome = null,
|
||||
status = GeofenceStatusKind.noActiveHome,
|
||||
runtime = const GeofenceRuntimeState(),
|
||||
locationServicesEnabled = true,
|
||||
locationPermission = LocationPermission.denied,
|
||||
notificationsEnabled = true,
|
||||
retryRemaining = null,
|
||||
detail = null;
|
||||
|
||||
String get title {
|
||||
return switch (status) {
|
||||
GeofenceStatusKind.noActiveHome => 'Геофенс не активен',
|
||||
GeofenceStatusKind.disabled => 'Автовыключение выключено',
|
||||
GeofenceStatusKind.missingCoordinates => 'Нет координат дома',
|
||||
GeofenceStatusKind.locationServicesDisabled => 'Геолокация выключена',
|
||||
GeofenceStatusKind.locationPermissionDenied => 'Нет доступа к геолокации',
|
||||
GeofenceStatusKind.backgroundPermissionDenied =>
|
||||
'Нет фонового доступа к геолокации',
|
||||
GeofenceStatusKind.notificationsPermissionDenied =>
|
||||
'Нет доступа к уведомлениям',
|
||||
GeofenceStatusKind.cooldown => 'Повтор отложен',
|
||||
GeofenceStatusKind.triggered => 'Геофенс уже сработал',
|
||||
GeofenceStatusKind.ready => 'Геофенс активен',
|
||||
};
|
||||
}
|
||||
|
||||
String get message {
|
||||
final homeName = activeHome?.name ?? 'активного дома';
|
||||
return switch (status) {
|
||||
GeofenceStatusKind.noActiveHome =>
|
||||
'Сначала выберите активный дом. Без этого фоновой автоматике нечего отслеживать.',
|
||||
GeofenceStatusKind.disabled =>
|
||||
'Для дома "$homeName" автовыключение пока отключено.',
|
||||
GeofenceStatusKind.missingCoordinates =>
|
||||
'У дома "$homeName" не заданы координаты. Без них расстояние считать не из чего.',
|
||||
GeofenceStatusKind.locationServicesDisabled =>
|
||||
'На устройстве выключена геолокация. И карта расстояний, и фоновый geofence сейчас слепые как кроты.',
|
||||
GeofenceStatusKind.locationPermissionDenied =>
|
||||
'Приложению не дали доступ к геолокации. Разрешите доступ хотя бы во время использования.',
|
||||
GeofenceStatusKind.backgroundPermissionDenied =>
|
||||
'Для фонового geofence нужен доступ к локации "Всегда". Иначе в фоне Android эту магию задушит.',
|
||||
GeofenceStatusKind.notificationsPermissionDenied =>
|
||||
'Свет выключить мы ещё попробуем, но честно отчитаться пользователю не сможем, пока уведомления запрещены.',
|
||||
GeofenceStatusKind.cooldown =>
|
||||
'Последняя попытка выключить свет сорвалась. Повторим позже, чтобы не долбить backend без остановки.',
|
||||
GeofenceStatusKind.triggered =>
|
||||
'Свет уже был автоматически выключен. Повторно бахать не будем, пока вы не вернётесь в домашний радиус.',
|
||||
GeofenceStatusKind.ready =>
|
||||
'Фоновая автоматика готова следить за домом "$homeName" и выключить свет после ухода.',
|
||||
};
|
||||
}
|
||||
|
||||
String? get secondaryMessage {
|
||||
if (status == GeofenceStatusKind.cooldown && retryRemaining != null) {
|
||||
return 'Повтор через ${formatGeofenceRetry(retryRemaining!)}.';
|
||||
}
|
||||
|
||||
if (status == GeofenceStatusKind.triggered &&
|
||||
runtime.lastSuccessAt != null &&
|
||||
runtime.lastSuccessHomeId == activeHome?.id) {
|
||||
return 'Последнее успешное срабатывание уже зафиксировано.';
|
||||
}
|
||||
|
||||
if (detail != null && detail!.trim().isNotEmpty) {
|
||||
return detail;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool get canRequestLocation =>
|
||||
status == GeofenceStatusKind.locationPermissionDenied;
|
||||
|
||||
bool get canRequestBackgroundLocation =>
|
||||
status == GeofenceStatusKind.backgroundPermissionDenied;
|
||||
|
||||
bool get canOpenLocationSettings =>
|
||||
status == GeofenceStatusKind.locationServicesDisabled;
|
||||
|
||||
bool get canRequestNotifications =>
|
||||
status == GeofenceStatusKind.notificationsPermissionDenied;
|
||||
}
|
||||
Reference in New Issue
Block a user