diff --git a/lib/api/get-locations.dart b/lib/api/get-locations.dart index 1ec9b8a9..fbd26c49 100644 --- a/lib/api/get-locations.dart +++ b/lib/api/get-locations.dart @@ -16,6 +16,7 @@ VoidCallback getLocations({ required void Function(LocationPointService) onLocationFetched, required void Function() onEnd, final VoidCallback? onEmptyEnd, + final VoidCallback? onError, int? limit, DateTime? from, DateTime? until, @@ -26,7 +27,7 @@ VoidCallback getLocations({ authors: [nostrPublicKey], limit: limit, until: - until == null ? null : (until.millisecondsSinceEpoch / 1000).floor(), + until == null ? null : (until.millisecondsSinceEpoch / 1000).floor(), since: from == null ? null : (from.millisecondsSinceEpoch / 1000).floor(), ), ]); @@ -44,31 +45,22 @@ VoidCallback getLocations({ "New message. Decrypting...", ); - try { - final location = await LocationPointService.fromEncrypted( - message.message.content, - encryptionPassword, - ); - - FlutterLogs.logInfo( - LOG_TAG, - "GetLocations", - "New message. Decrypting... Done!", - ); - - onLocationFetched(location); - } catch (error) { - FlutterLogs.logError( - LOG_TAG, - "GetLocations", - "Error decrypting message: $error", - ); - - return; - } + final location = await LocationPointService.fromEncrypted( + message.message.content, + encryptionPassword, + ); + + FlutterLogs.logInfo( + LOG_TAG, + "GetLocations", + "New message. Decrypting... Done!", + ); + + onLocationFetched(location); }, onEnd: onEnd, onEmptyEnd: onEmptyEnd, + onError: onError, ); } @@ -82,8 +74,29 @@ Future> getLocationsAsFuture({ }) async { final completer = Completer>(); + int doneAmount = 0; final List locations = []; + final onAnyEnd = () { + doneAmount++; + + FlutterLogs.logInfo( + LOG_TAG, + "GetLocations", + "Relay done! $doneAmount / ${relays.length}", + ); + + if (doneAmount == relays.length) { + FlutterLogs.logInfo( + LOG_TAG, + "GetLocations", + "All relays done!", + ); + + completer.complete(locations); + } + }; + getLocations( nostrPublicKey: nostrPublicKey, encryptionPassword: encryptionPassword, @@ -94,9 +107,9 @@ Future> getLocationsAsFuture({ onLocationFetched: (final LocationPointService location) { locations.add(location); }, - onEnd: () { - completer.complete(locations); - }, + onEnd: onAnyEnd, + onEmptyEnd: onAnyEnd, + onError: onAnyEnd, ); return completer.future; diff --git a/lib/api/nostr-fetch.dart b/lib/api/nostr-fetch.dart index dd368cb8..17a43f69 100644 --- a/lib/api/nostr-fetch.dart +++ b/lib/api/nostr-fetch.dart @@ -105,6 +105,7 @@ class NostrFetch { required final Future Function(Message message, String relay) onEvent, required final void Function() onEnd, final void Function()? onEmptyEnd, + final VoidCallback? onError, }) { final List sockets = []; @@ -136,6 +137,8 @@ class NostrFetch { "Nostr Socket", "Error for socket: $error", ); + + onError?.call(); }); } diff --git a/lib/screens/view_alarm_screen_widgets/ViewAlarmScreen.dart b/lib/screens/view_alarm_screen_widgets/ViewAlarmScreen.dart index cf5b8bf9..d80cce1f 100644 --- a/lib/screens/view_alarm_screen_widgets/ViewAlarmScreen.dart +++ b/lib/screens/view_alarm_screen_widgets/ViewAlarmScreen.dart @@ -22,6 +22,8 @@ import 'package:locus/widgets/ModalSheet.dart'; import 'package:locus/widgets/ModalSheetContent.dart'; import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; import 'package:provider/provider.dart'; +import 'package:locus/services/manager_service/helpers.dart'; +import 'package:locus/services/current_location_service.dart'; import '../../models/log.dart'; import '../../utils/PageRoute.dart'; @@ -365,10 +367,27 @@ class _ViewAlarmScreenState extends State { child: Text(l10n.location_manageAlarms_addNewAlarm_actionLabel), ), ), - Padding( - padding: const EdgeInsets.symmetric(vertical: MEDIUM_SPACE), - child: Text(l10n.location_manageAlarms_lastCheck_description( - widget.view.lastAlarmCheck)), + GestureDetector( + onTap: () async { + final l10n = AppLocalizations.of(context); + final views = context.read(); + final currentLocation = context.read(); + + checkViewAlarms( + l10n: l10n, + views: views.viewsWithAlarms, + viewService: views, + userLocation: await LocationPointService.fromPosition( + currentLocation.currentPosition!), + ); + }, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: MEDIUM_SPACE), + child: Text( + l10n.location_manageAlarms_lastCheck_description( + widget.view.lastAlarmCheck), + ), + ), ), ], ), diff --git a/lib/screens/view_alarm_screen_widgets/ViewAlarmSelectRadiusBasedScreen.dart b/lib/screens/view_alarm_screen_widgets/ViewAlarmSelectRadiusBasedScreen.dart index 11f1d85f..8bddf78a 100644 --- a/lib/screens/view_alarm_screen_widgets/ViewAlarmSelectRadiusBasedScreen.dart +++ b/lib/screens/view_alarm_screen_widgets/ViewAlarmSelectRadiusBasedScreen.dart @@ -125,8 +125,8 @@ class _ViewAlarmSelectRadiusBasedScreenState final zoom = _hasSetInitialPosition ? (16 - log(position.accuracy / 200) / log(2)).toDouble() : flutterMapController?.zoom ?? - (await appleMapController?.getZoomLevel()) ?? - 16.0; + (await appleMapController?.getZoomLevel()) ?? + 16.0; flutterMapController?.move( LatLng(position.latitude, position.longitude), @@ -151,39 +151,38 @@ class _ViewAlarmSelectRadiusBasedScreenState showHelperSheet( context: context, - builder: (context) => - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text(l10n.location_addAlarm_radiusBased_help_description), - const SizedBox(height: MEDIUM_SPACE), - if (widget.type == LocationAlarmType.geo) ...[ - Row( - children: [ - const Icon(Icons.touch_app_rounded), - const SizedBox(width: MEDIUM_SPACE), - Flexible( - child: Text( - l10n.location_addAlarm_geo_help_tapDescription, - ), - ), - ], + builder: (context) => Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text(l10n.location_addAlarm_radiusBased_help_description), + const SizedBox(height: MEDIUM_SPACE), + if (widget.type == LocationAlarmType.geo) ...[ + Row( + children: [ + const Icon(Icons.touch_app_rounded), + const SizedBox(width: MEDIUM_SPACE), + Flexible( + child: Text( + l10n.location_addAlarm_geo_help_tapDescription, + ), ), ], - const SizedBox(height: MEDIUM_SPACE), - Row( - children: [ - const Icon(Icons.pinch_rounded), - const SizedBox(width: MEDIUM_SPACE), - Flexible( - child: Text( - l10n.location_addAlarm_radiusBased_help_pinchDescription, - ), - ), - ], + ), + ], + const SizedBox(height: MEDIUM_SPACE), + Row( + children: [ + const Icon(Icons.pinch_rounded), + const SizedBox(width: MEDIUM_SPACE), + Flexible( + child: Text( + l10n.location_addAlarm_radiusBased_help_pinchDescription, + ), ), ], ), + ], + ), title: l10n.location_addAlarm_radiusBased_help_title, sheetName: HelperSheet.radiusBasedAlarms, ); @@ -224,11 +223,10 @@ class _ViewAlarmSelectRadiusBasedScreenState isDismissible: true, isScrollControlled: true, ), - builder: (_) => - GeoAlarmMetaDataSheet( - center: alarmCenter!, - radius: radius.toDouble(), - ), + builder: (_) => GeoAlarmMetaDataSheet( + center: alarmCenter!, + radius: radius.toDouble(), + ), ); break; case LocationAlarmType.proximity: @@ -239,10 +237,9 @@ class _ViewAlarmSelectRadiusBasedScreenState isDismissible: true, isScrollControlled: true, ), - builder: (_) => - ProximityAlarmMetaDataSheet( - radius: radius, - ), + builder: (_) => ProximityAlarmMetaDataSheet( + radius: radius, + ), ); } @@ -251,7 +248,7 @@ class _ViewAlarmSelectRadiusBasedScreenState } final hasGrantedNotificationAccess = - await showNotificationPermissionDialog(); + await showNotificationPermissionDialog(); if (!hasGrantedNotificationAccess || !mounted) { return; @@ -281,28 +278,25 @@ class _ViewAlarmSelectRadiusBasedScreenState }; return PlatformScaffold( - material: (_, __) => - MaterialScaffoldData( - resizeToAvoidBottomInset: false, - ), + material: (_, __) => MaterialScaffoldData( + resizeToAvoidBottomInset: false, + ), appBar: PlatformAppBar( title: Text(TYPE_TITLE_MAP[widget.type]!), trailingActions: [ PlatformIconButton( - cupertino: (_, __) => - CupertinoIconButtonData( - padding: EdgeInsets.zero, - ), + cupertino: (_, __) => CupertinoIconButtonData( + padding: EdgeInsets.zero, + ), icon: Icon(context.platformIcons.help), onPressed: showHelp, ), ], - cupertino: (_, __) => - CupertinoNavigationBarData( - backgroundColor: isInScaleMode - ? null - : getCupertinoAppBarColorForMapScreen(context), - ), + cupertino: (_, __) => CupertinoNavigationBarData( + backgroundColor: isInScaleMode + ? null + : getCupertinoAppBarColorForMapScreen(context), + ), ), body: Column( crossAxisAlignment: CrossAxisAlignment.stretch, diff --git a/lib/services/manager_service/helpers.dart b/lib/services/manager_service/helpers.dart index 58114261..7cc34d7c 100644 --- a/lib/services/manager_service/helpers.dart +++ b/lib/services/manager_service/helpers.dart @@ -9,6 +9,8 @@ import 'package:geolocator/geolocator.dart'; import 'package:locus/constants/notifications.dart'; import 'package:locus/constants/values.dart'; import 'package:locus/models/log.dart'; +import 'package:locus/services/location_alarm_service/ProximityLocationAlarm.dart'; +import 'package:locus/services/location_alarm_service/enums.dart'; import 'package:locus/services/location_alarm_service/index.dart'; import 'package:locus/services/location_point_service.dart'; import 'package:locus/services/log_service.dart'; @@ -112,22 +114,36 @@ Future checkViewAlarms({ required final ViewService viewService, required final LocationPointService userLocation, }) async { + FlutterLogs.logInfo( + LOG_TAG, + "Headless Task; Check View Alarms", + "Checking ${views.length} views...", + ); + for (final view in views) { await view.checkAlarm( userLocation: userLocation, onTrigger: (alarm, location, __) async { - if (alarm is GeoLocationAlarm) { - final flutterLocalNotificationsPlugin = - FlutterLocalNotificationsPlugin(); + final notifications = FlutterLocalNotificationsPlugin(); + final id = int.parse( + "${location.createdAt.millisecond}${location.createdAt.microsecond}", + ); - flutterLocalNotificationsPlugin.show( - int.parse( - "${location.createdAt.millisecond}${location.createdAt.microsecond}"), + if (alarm is GeoLocationAlarm) { + notifications.show( + id, StringUtils.truncate( - l10n.locationAlarm_radiusBasedRegion_notificationTitle_whenEnter( - view.name, - "test", - ), + alarm.type == LocationRadiusBasedTriggerType.whenEnter + ? l10n + .locationAlarm_radiusBasedRegion_notificationTitle_whenEnter( + view.name, + alarm.zoneName, + ) + : l10n + .locationAlarm_radiusBasedRegion_notificationTitle_whenLeave( + view.name, + alarm.zoneName, + ), 76, ), l10n.locationAlarm_notification_description, @@ -146,37 +162,31 @@ Future checkViewAlarms({ "taskViewID": view.id, }), ); - } - }, - onMaybeTrigger: (alarm, _, __) async { - if (view.lastMaybeTrigger != null && - view.lastMaybeTrigger!.difference(DateTime.now()).abs() < - MAYBE_TRIGGER_MINIMUM_TIME_BETWEEN) { return; } - if (alarm is GeoLocationAlarm) { - final flutterLocalNotificationsPlugin = - FlutterLocalNotificationsPlugin(); - - flutterLocalNotificationsPlugin.show( - int.parse( - "${DateTime.now().millisecond}${DateTime.now().microsecond}"), + if (alarm is ProximityLocationAlarm) { + notifications.show( + id, StringUtils.truncate( - l10n.locationAlarm_radiusBasedRegion_notificationTitle_whenEnter( - view.name, - alarm.zoneName, - ), + alarm.type == LocationRadiusBasedTriggerType.whenEnter + ? l10n + .locationAlarm_proximityLocation_notificationTitle_whenEnter( + view.name, + alarm.radius.round(), + ) + : l10n + .locationAlarm_proximityLocation_notificationTitle_whenLeave( + view.name, + alarm.radius.round(), + ), 76, ), l10n.locationAlarm_notification_description, NotificationDetails( android: AndroidNotificationDetails( AndroidChannelIDs.locationAlarms.name, - l10n.locationAlarm_radiusBasedRegion_notificationTitle_maybe( - view.name, - alarm.zoneName, - ), + l10n.androidNotificationChannel_locationAlarms_name, channelDescription: l10n.androidNotificationChannel_locationAlarms_description, importance: Importance.max, @@ -188,15 +198,25 @@ Future checkViewAlarms({ "taskViewID": view.id, }), ); - - view.lastMaybeTrigger = DateTime.now(); - await viewService.update(view); } }, + onMaybeTrigger: (alarm, _, __) async {}, ); } + FlutterLogs.logInfo( + LOG_TAG, + "Headless Task; Check View Alarms", + "Checking ${views.length} views... Done! Saving...", + ); + await viewService.save(); + + FlutterLogs.logInfo( + LOG_TAG, + "Headless Task; Check View Alarms", + "Checking ${views.length} views... Done! Saving... Done!", + ); } Future checkViewAlarmsFromBackground( diff --git a/lib/services/view_service.dart b/lib/services/view_service.dart index dbd91752..d251e3eb 100644 --- a/lib/services/view_service.dart +++ b/lib/services/view_service.dart @@ -290,13 +290,31 @@ class TaskView extends ChangeNotifier with LocationBase { onMaybeTrigger, required final LocationPointService userLocation, }) async { + FlutterLogs.logInfo( + LOG_TAG, + "Headless Task; Check View Alarms", + "Checking view $name from $lastAlarmCheck...", + ); + final locations = await getLocationsAsFuture( from: lastAlarmCheck, ); lastAlarmCheck = DateTime.now(); + FlutterLogs.logInfo( + LOG_TAG, + "Headless Task; Check View Alarms", + "Checking view $name... ${locations.length} locations", + ); + if (locations.isEmpty) { + FlutterLogs.logInfo( + LOG_TAG, + "Headless Task; Check View Alarms", + "Checking view $name... No locations", + ); + return; }