Show explicit geofence permission status
This commit is contained in:
@@ -7,6 +7,7 @@ import '../app/error_message.dart';
|
||||
import '../app/load_state.dart';
|
||||
import '../features/settings/models/app_theme_preset.dart';
|
||||
import '../features/settings/models/geofence_system_state.dart';
|
||||
import '../features/settings/models/notification_permission_status.dart';
|
||||
import '../features/settings/providers/settings_providers.dart';
|
||||
import '../models/home_config.dart';
|
||||
import '../providers/providers.dart';
|
||||
@@ -44,6 +45,7 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen>
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
ref.invalidate(geofenceSystemStatusProvider);
|
||||
ref.invalidate(notificationPermissionStatusProvider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,6 +56,8 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen>
|
||||
final themePreset = ref.watch(appThemeProvider);
|
||||
final geofenceStatus = ref.watch(geofenceSystemStatusProvider);
|
||||
final geofenceState = geofenceStatus.asData?.value;
|
||||
final notificationStatus = ref.watch(notificationPermissionStatusProvider);
|
||||
final notificationPermission = notificationStatus.asData?.value;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('НАСТРОЙКИ')),
|
||||
@@ -140,6 +144,25 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen>
|
||||
title: _statusTitle(geofenceState, currentHome),
|
||||
subtitle: _statusSubtitle(geofenceState, currentHome),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
_PermissionTile(
|
||||
icon: _locationPermissionIcon(geofenceState),
|
||||
color: _locationPermissionColor(context, geofenceState),
|
||||
title: 'Геолокация',
|
||||
subtitle: _locationPermissionSubtitle(geofenceState),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_PermissionTile(
|
||||
icon: _notificationPermissionIcon(notificationPermission),
|
||||
color: _notificationPermissionColor(
|
||||
context,
|
||||
notificationPermission,
|
||||
),
|
||||
title: 'Уведомления',
|
||||
subtitle: _notificationPermissionSubtitle(
|
||||
notificationPermission,
|
||||
),
|
||||
),
|
||||
if (_savingGeofence)
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
@@ -165,6 +188,7 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen>
|
||||
context: context,
|
||||
home: currentHome,
|
||||
systemState: geofenceState,
|
||||
notificationPermission: notificationPermission,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -238,8 +262,12 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen>
|
||||
required BuildContext context,
|
||||
required HomeConfig home,
|
||||
required GeofenceSystemState? systemState,
|
||||
required NotificationPermissionStatus? notificationPermission,
|
||||
}) {
|
||||
final locationNotifier = ref.read(userLocationProvider.notifier);
|
||||
final notificationNotifier = ref.read(
|
||||
notificationPermissionStatusServiceProvider,
|
||||
);
|
||||
final issue = systemState?.issue;
|
||||
|
||||
if (!home.hasCoordinates) {
|
||||
@@ -252,7 +280,7 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen>
|
||||
];
|
||||
}
|
||||
|
||||
return switch (issue) {
|
||||
final actions = switch (issue) {
|
||||
GeofenceSystemIssue.locationServicesDisabled => [
|
||||
FilledButton.tonalIcon(
|
||||
onPressed: () async {
|
||||
@@ -292,6 +320,21 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
if (notificationPermission == NotificationPermissionStatus.disabled) {
|
||||
actions.add(
|
||||
OutlinedButton.icon(
|
||||
onPressed: () async {
|
||||
await notificationNotifier.openSettings();
|
||||
ref.invalidate(notificationPermissionStatusProvider);
|
||||
},
|
||||
icon: const Icon(Icons.notifications_outlined),
|
||||
label: const Text('Уведомления Android'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return actions;
|
||||
}
|
||||
|
||||
Future<void> _setGeofenceEnabled(HomeConfig home, bool enabled) async {
|
||||
@@ -536,6 +579,89 @@ class _SettingsScreenState extends ConsumerState<SettingsScreen>
|
||||
};
|
||||
}
|
||||
|
||||
IconData _locationPermissionIcon(GeofenceSystemState? state) {
|
||||
return switch (state?.issue) {
|
||||
GeofenceSystemIssue.ready => Icons.verified_outlined,
|
||||
GeofenceSystemIssue.locationServicesDisabled => Icons.location_disabled,
|
||||
GeofenceSystemIssue.permissionDenied ||
|
||||
GeofenceSystemIssue.permissionDeniedForever ||
|
||||
GeofenceSystemIssue.backgroundPermissionRequired =>
|
||||
Icons.gpp_bad_outlined,
|
||||
_ => Icons.my_location_outlined,
|
||||
};
|
||||
}
|
||||
|
||||
Color _locationPermissionColor(
|
||||
BuildContext context,
|
||||
GeofenceSystemState? state,
|
||||
) {
|
||||
return switch (state?.issue) {
|
||||
GeofenceSystemIssue.ready => Colors.green,
|
||||
GeofenceSystemIssue.locationServicesDisabled ||
|
||||
GeofenceSystemIssue.permissionDenied ||
|
||||
GeofenceSystemIssue.permissionDeniedForever ||
|
||||
GeofenceSystemIssue.backgroundPermissionRequired => Theme.of(
|
||||
context,
|
||||
).colorScheme.error,
|
||||
_ => Colors.white70,
|
||||
};
|
||||
}
|
||||
|
||||
String _locationPermissionSubtitle(GeofenceSystemState? state) {
|
||||
return switch (state?.issue) {
|
||||
GeofenceSystemIssue.ready =>
|
||||
'Доступ «Всегда», geofence может работать в фоне.',
|
||||
GeofenceSystemIssue.locationServicesDisabled =>
|
||||
'Системная геолокация сейчас выключена.',
|
||||
GeofenceSystemIssue.permissionDenied =>
|
||||
'Разрешение на геолокацию ещё не выдано.',
|
||||
GeofenceSystemIssue.permissionDeniedForever =>
|
||||
'Доступ к геолокации запрещён в Android.',
|
||||
GeofenceSystemIssue.backgroundPermissionRequired =>
|
||||
'Есть только доступ при использовании приложения.',
|
||||
GeofenceSystemIssue.missingCoordinates =>
|
||||
'Сначала задай координаты дома, потом появится полный статус.',
|
||||
GeofenceSystemIssue.noActiveHome =>
|
||||
'Без активного дома проверять нечего.',
|
||||
null => 'Проверяем системный статус геолокации.',
|
||||
};
|
||||
}
|
||||
|
||||
IconData _notificationPermissionIcon(NotificationPermissionStatus? status) {
|
||||
return switch (status) {
|
||||
NotificationPermissionStatus.enabled =>
|
||||
Icons.notifications_active_outlined,
|
||||
NotificationPermissionStatus.disabled => Icons.notifications_off_outlined,
|
||||
NotificationPermissionStatus.unsupported ||
|
||||
null => Icons.notifications_none_outlined,
|
||||
};
|
||||
}
|
||||
|
||||
Color _notificationPermissionColor(
|
||||
BuildContext context,
|
||||
NotificationPermissionStatus? status,
|
||||
) {
|
||||
return switch (status) {
|
||||
NotificationPermissionStatus.enabled => Colors.green,
|
||||
NotificationPermissionStatus.disabled => Theme.of(
|
||||
context,
|
||||
).colorScheme.error,
|
||||
NotificationPermissionStatus.unsupported || null => Colors.white70,
|
||||
};
|
||||
}
|
||||
|
||||
String _notificationPermissionSubtitle(NotificationPermissionStatus? status) {
|
||||
return switch (status) {
|
||||
NotificationPermissionStatus.enabled =>
|
||||
'После срабатывания geofence приложение сможет прислать подтверждение.',
|
||||
NotificationPermissionStatus.disabled =>
|
||||
'Автовыключение сработает и без них, но подтверждение ты не увидишь.',
|
||||
NotificationPermissionStatus.unsupported =>
|
||||
'На этой платформе отдельный статус уведомлений не используется.',
|
||||
null => 'Проверяем, доступны ли уведомления для подтверждения.',
|
||||
};
|
||||
}
|
||||
|
||||
Future<void> _openHomeEditor(BuildContext context, HomeConfig home) async {
|
||||
await Navigator.of(
|
||||
context,
|
||||
@@ -679,6 +805,41 @@ class _StatusTile extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _PermissionTile extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final Color color;
|
||||
final String title;
|
||||
final String subtitle;
|
||||
|
||||
const _PermissionTile({
|
||||
required this.icon,
|
||||
required this.color,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(icon, color: color, size: 20),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||
const SizedBox(height: 2),
|
||||
Text(subtitle, style: const TextStyle(color: Colors.white54)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _EmptySectionState extends StatelessWidget {
|
||||
final IconData icon;
|
||||
final String title;
|
||||
|
||||
Reference in New Issue
Block a user