feat: Add task execution callback registration to BackgroundTaskService and update geofence dispatcher to use it

This commit is contained in:
Achintha Isuru
2026-03-14 00:59:39 -04:00
parent 2889098f9f
commit 08a4326da4
2 changed files with 36 additions and 24 deletions

View File

@@ -55,4 +55,16 @@ class BackgroundTaskService extends BaseDeviceService {
Future<void> cancelAll() async { Future<void> cancelAll() async {
return action(() => Workmanager().cancelAll()); return action(() => Workmanager().cancelAll());
} }
/// Registers the task execution callback for the background isolate.
///
/// Must be called inside the top-level callback dispatcher function.
/// The [callback] receives the task name and optional input data, and
/// must return `true` on success or `false` on failure.
void executeTask(
Future<bool> Function(String task, Map<String, dynamic>? inputData)
callback,
) {
Workmanager().executeTask(callback);
}
} }

View File

@@ -1,6 +1,6 @@
// ignore_for_file: avoid_print // ignore_for_file: avoid_print
import 'package:krow_core/core.dart'; import 'package:krow_core/core.dart';
import 'package:workmanager/workmanager.dart'; import 'package:krow_domain/src/core/models/device_location.dart';
/// Top-level callback dispatcher for background geofence tasks. /// Top-level callback dispatcher for background geofence tasks.
/// ///
@@ -13,7 +13,7 @@ import 'package:workmanager/workmanager.dart';
/// is retained solely for this entry-point pattern. /// is retained solely for this entry-point pattern.
@pragma('vm:entry-point') @pragma('vm:entry-point')
void backgroundGeofenceDispatcher() { void backgroundGeofenceDispatcher() {
Workmanager().executeTask( const BackgroundTaskService().executeTask(
(String task, Map<String, dynamic>? inputData) async { (String task, Map<String, dynamic>? inputData) async {
print('[BackgroundGeofence] Task triggered: $task'); print('[BackgroundGeofence] Task triggered: $task');
print('[BackgroundGeofence] Input data: $inputData'); print('[BackgroundGeofence] Input data: $inputData');
@@ -39,7 +39,7 @@ void backgroundGeofenceDispatcher() {
try { try {
const LocationService locationService = LocationService(); const LocationService locationService = LocationService();
final location = await locationService.getCurrentLocation(); final DeviceLocation location = await locationService.getCurrentLocation();
print( print(
'[BackgroundGeofence] Current position: ' '[BackgroundGeofence] Current position: '
'lat=${location.latitude}, lng=${location.longitude}', 'lat=${location.latitude}, lng=${location.longitude}',
@@ -93,6 +93,15 @@ void backgroundGeofenceDispatcher() {
/// Uses core services for foreground operations. The background isolate logic /// Uses core services for foreground operations. The background isolate logic
/// lives in the top-level [backgroundGeofenceDispatcher] function above. /// lives in the top-level [backgroundGeofenceDispatcher] function above.
class BackgroundGeofenceService { class BackgroundGeofenceService {
/// Creates a [BackgroundGeofenceService] instance.
BackgroundGeofenceService({
required BackgroundTaskService backgroundTaskService,
required NotificationService notificationService,
required StorageService storageService,
}) : _backgroundTaskService = backgroundTaskService,
_notificationService = notificationService,
_storageService = storageService;
/// The core background task service for scheduling periodic work. /// The core background task service for scheduling periodic work.
final BackgroundTaskService _backgroundTaskService; final BackgroundTaskService _backgroundTaskService;
@@ -103,25 +112,25 @@ class BackgroundGeofenceService {
final StorageService _storageService; final StorageService _storageService;
/// Storage key for the target latitude. /// Storage key for the target latitude.
static const _keyTargetLat = 'geofence_target_lat'; static const String _keyTargetLat = 'geofence_target_lat';
/// Storage key for the target longitude. /// Storage key for the target longitude.
static const _keyTargetLng = 'geofence_target_lng'; static const String _keyTargetLng = 'geofence_target_lng';
/// Storage key for the shift identifier. /// Storage key for the shift identifier.
static const _keyShiftId = 'geofence_shift_id'; static const String _keyShiftId = 'geofence_shift_id';
/// Storage key for the active tracking flag. /// Storage key for the active tracking flag.
static const _keyTrackingActive = 'geofence_tracking_active'; static const String _keyTrackingActive = 'geofence_tracking_active';
/// Unique task name for the periodic background check. /// Unique task name for the periodic background check.
static const taskUniqueName = 'geofence_background_check'; static const String taskUniqueName = 'geofence_background_check';
/// Task name identifier for the workmanager callback. /// Task name identifier for the workmanager callback.
static const taskName = 'geofenceCheck'; static const String taskName = 'geofenceCheck';
/// Notification ID for clock-in greeting notifications. /// Notification ID for clock-in greeting notifications.
static const _clockInNotificationId = 1; static const int _clockInNotificationId = 1;
/// Notification ID for left-geofence warnings. /// Notification ID for left-geofence warnings.
static const int leftGeofenceNotificationId = 2; static const int leftGeofenceNotificationId = 2;
@@ -130,16 +139,7 @@ class BackgroundGeofenceService {
static const double geofenceRadiusMeters = 500; static const double geofenceRadiusMeters = 500;
/// Notification ID for clock-out notifications. /// Notification ID for clock-out notifications.
static const _clockOutNotificationId = 3; static const int _clockOutNotificationId = 3;
/// Creates a [BackgroundGeofenceService] instance.
BackgroundGeofenceService({
required BackgroundTaskService backgroundTaskService,
required NotificationService notificationService,
required StorageService storageService,
}) : _backgroundTaskService = backgroundTaskService,
_notificationService = notificationService,
_storageService = storageService;
/// Starts periodic 15-minute background geofence checks. /// Starts periodic 15-minute background geofence checks.
/// ///
@@ -150,7 +150,7 @@ class BackgroundGeofenceService {
required double targetLng, required double targetLng,
required String shiftId, required String shiftId,
}) async { }) async {
await Future.wait([ await Future.wait(<Future<bool>>[
_storageService.setDouble(_keyTargetLat, targetLat), _storageService.setDouble(_keyTargetLat, targetLat),
_storageService.setDouble(_keyTargetLng, targetLng), _storageService.setDouble(_keyTargetLng, targetLng),
_storageService.setString(_keyShiftId, shiftId), _storageService.setString(_keyShiftId, shiftId),
@@ -161,7 +161,7 @@ class BackgroundGeofenceService {
uniqueName: taskUniqueName, uniqueName: taskUniqueName,
taskName: taskName, taskName: taskName,
frequency: const Duration(seconds: 10), frequency: const Duration(seconds: 10),
inputData: { inputData: <String, dynamic>{
'targetLat': targetLat, 'targetLat': targetLat,
'targetLng': targetLng, 'targetLng': targetLng,
'shiftId': shiftId, 'shiftId': shiftId,
@@ -175,7 +175,7 @@ class BackgroundGeofenceService {
Future<void> stopBackgroundTracking() async { Future<void> stopBackgroundTracking() async {
await _backgroundTaskService.cancelByUniqueName(taskUniqueName); await _backgroundTaskService.cancelByUniqueName(taskUniqueName);
await Future.wait([ await Future.wait(<Future<bool>>[
_storageService.remove(_keyTargetLat), _storageService.remove(_keyTargetLat),
_storageService.remove(_keyTargetLng), _storageService.remove(_keyTargetLng),
_storageService.remove(_keyShiftId), _storageService.remove(_keyShiftId),
@@ -185,7 +185,7 @@ class BackgroundGeofenceService {
/// Whether background tracking is currently active. /// Whether background tracking is currently active.
Future<bool> get isTrackingActive async { Future<bool> get isTrackingActive async {
final active = await _storageService.getBool(_keyTrackingActive); final bool? active = await _storageService.getBool(_keyTrackingActive);
return active ?? false; return active ?? false;
} }