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