Background location tracking
This commit is contained in:
@@ -24,6 +24,7 @@ import '../../providers/workforce_provider.dart';
|
||||
import '../../theme/m3_motion.dart';
|
||||
import '../../utils/app_time.dart';
|
||||
import '../../utils/location_permission.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import '../../widgets/face_verification_overlay.dart';
|
||||
import '../../utils/snackbar.dart';
|
||||
import '../../widgets/gemini_animated_text_field.dart';
|
||||
@@ -42,6 +43,10 @@ class _AttendanceScreenState extends ConsumerState<AttendanceScreen>
|
||||
late TabController _tabController;
|
||||
bool _fabMenuOpen = false;
|
||||
|
||||
// (moved into _CheckInTabState) local tracking state for optimistic UI updates
|
||||
// bool _trackingLocal = false;
|
||||
// bool _trackingSaving = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -261,6 +266,9 @@ class _CheckInTab extends ConsumerStatefulWidget {
|
||||
|
||||
class _CheckInTabState extends ConsumerState<_CheckInTab> {
|
||||
bool _loading = false;
|
||||
// local tracking state for optimistic UI updates (optimistic toggle in UI)
|
||||
bool _trackingLocal = false;
|
||||
bool _trackingSaving = false;
|
||||
final _justCheckedIn = <String>{};
|
||||
final _checkInLogIds = <String, String>{};
|
||||
String? _overtimeLogId;
|
||||
@@ -352,6 +360,17 @@ class _CheckInTabState extends ConsumerState<_CheckInTab> {
|
||||
final schedulesAsync = ref.watch(dutySchedulesProvider);
|
||||
final logsAsync = ref.watch(attendanceLogsProvider);
|
||||
final allowTracking = profile?.allowTracking ?? false;
|
||||
// local state for optimistic switch update and to avoid flicker while the
|
||||
// profile stream lags. Once the network request completes we keep the
|
||||
// local value until the provider returns the same value.
|
||||
bool effectiveTracking;
|
||||
if (_trackingSaving) {
|
||||
effectiveTracking = _trackingLocal;
|
||||
} else if (_trackingLocal != allowTracking) {
|
||||
effectiveTracking = _trackingLocal;
|
||||
} else {
|
||||
effectiveTracking = allowTracking;
|
||||
}
|
||||
|
||||
if (profile == null) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
@@ -409,11 +428,14 @@ class _CheckInTabState extends ConsumerState<_CheckInTab> {
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: allowTracking,
|
||||
value: effectiveTracking,
|
||||
onChanged: (v) async {
|
||||
if (_trackingSaving) return; // ignore while pending
|
||||
|
||||
if (v) {
|
||||
final granted = await ensureLocationPermission();
|
||||
if (!granted) {
|
||||
// first ensure foreground & background location perms
|
||||
final grantedFg = await ensureLocationPermission();
|
||||
if (!grantedFg) {
|
||||
if (context.mounted) {
|
||||
showWarningSnackBar(
|
||||
context,
|
||||
@@ -422,8 +444,50 @@ class _CheckInTabState extends ConsumerState<_CheckInTab> {
|
||||
}
|
||||
return;
|
||||
}
|
||||
final grantedBg =
|
||||
await ensureBackgroundLocationPermission();
|
||||
if (!grantedBg) {
|
||||
// if permanently denied, open settings so the user can
|
||||
// manually grant the permission; otherwise just warn.
|
||||
if (await Permission
|
||||
.locationAlways
|
||||
.isPermanentlyDenied ||
|
||||
await Permission.location.isPermanentlyDenied) {
|
||||
openAppSettings();
|
||||
}
|
||||
if (context.mounted) {
|
||||
showWarningSnackBar(
|
||||
context,
|
||||
'Background location permission is required.',
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// optimistically flip
|
||||
setState(() {
|
||||
_trackingLocal = v;
|
||||
_trackingSaving = true;
|
||||
});
|
||||
|
||||
try {
|
||||
await ref
|
||||
.read(whereaboutsControllerProvider)
|
||||
.setTracking(v);
|
||||
} catch (e) {
|
||||
if (context.mounted) {
|
||||
showWarningSnackBar(context, e.toString());
|
||||
}
|
||||
// revert to actual stored value
|
||||
setState(() {
|
||||
_trackingLocal = allowTracking;
|
||||
});
|
||||
} finally {
|
||||
setState(() {
|
||||
_trackingSaving = false;
|
||||
});
|
||||
}
|
||||
ref.read(whereaboutsControllerProvider).setTracking(v);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user