Workforce rotation settings and location permission handling
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import '../models/rotation_config.dart';
|
||||
import 'supabase_provider.dart';
|
||||
|
||||
/// Key used to store the rotation configuration in `app_settings`.
|
||||
const _settingsKey = 'rotation_config';
|
||||
|
||||
/// Provides the current [RotationConfig] from `app_settings`.
|
||||
final rotationConfigProvider = FutureProvider<RotationConfig>((ref) async {
|
||||
final client = ref.watch(supabaseClientProvider);
|
||||
final row = await client
|
||||
.from('app_settings')
|
||||
.select()
|
||||
.eq('key', _settingsKey)
|
||||
.maybeSingle();
|
||||
if (row == null) return RotationConfig();
|
||||
final value = row['value'];
|
||||
if (value is Map<String, dynamic>) {
|
||||
return RotationConfig.fromJson(value);
|
||||
}
|
||||
if (value is String) {
|
||||
return RotationConfig.fromJson(jsonDecode(value) as Map<String, dynamic>);
|
||||
}
|
||||
return RotationConfig();
|
||||
});
|
||||
|
||||
/// Controller for persisting [RotationConfig] changes.
|
||||
final rotationConfigControllerProvider = Provider<RotationConfigController>((
|
||||
ref,
|
||||
) {
|
||||
final client = ref.watch(supabaseClientProvider);
|
||||
return RotationConfigController(client, ref);
|
||||
});
|
||||
|
||||
class RotationConfigController {
|
||||
RotationConfigController(this._client, this._ref);
|
||||
|
||||
final dynamic _client;
|
||||
final Ref _ref;
|
||||
|
||||
Future<void> save(RotationConfig config) async {
|
||||
await _client.from('app_settings').upsert({
|
||||
'key': _settingsKey,
|
||||
'value': config.toJson(),
|
||||
});
|
||||
_ref.invalidate(rotationConfigProvider);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import 'package:supabase_flutter/supabase_flutter.dart';
|
||||
|
||||
import '../models/live_position.dart';
|
||||
import '../services/background_location_service.dart';
|
||||
import '../utils/location_permission.dart';
|
||||
import 'profile_provider.dart';
|
||||
import 'supabase_provider.dart';
|
||||
import 'stream_recovery.dart';
|
||||
@@ -49,10 +50,27 @@ class WhereaboutsController {
|
||||
return data as bool? ?? false;
|
||||
}
|
||||
|
||||
/// Public convenience: fetch device position and upsert to live_positions.
|
||||
/// Call after check-in / check-out to ensure immediate data freshness.
|
||||
Future<void> updatePositionNow() => _updatePositionNow();
|
||||
|
||||
/// Toggle allow_tracking preference.
|
||||
///
|
||||
/// When enabling, requests location permission and immediately saves the
|
||||
/// current position to `live_positions`. When disabling, updates position
|
||||
/// one last time (so the final location is recorded) then removes the entry.
|
||||
Future<void> setTracking(bool allow) async {
|
||||
final userId = _client.auth.currentUser?.id;
|
||||
if (userId == null) throw Exception('Not authenticated');
|
||||
|
||||
if (allow) {
|
||||
// Ensure location permission before enabling
|
||||
final granted = await ensureLocationPermission();
|
||||
if (!granted) {
|
||||
throw Exception('Location permission is required for tracking');
|
||||
}
|
||||
}
|
||||
|
||||
await _client
|
||||
.from('profiles')
|
||||
.update({'allow_tracking': allow})
|
||||
@@ -61,12 +79,43 @@ class WhereaboutsController {
|
||||
// Start or stop background location updates
|
||||
if (allow) {
|
||||
await startBackgroundLocationUpdates();
|
||||
// Immediately save current position
|
||||
await _updatePositionNow();
|
||||
} else {
|
||||
// Record final position before removing
|
||||
await _updatePositionNow();
|
||||
await stopBackgroundLocationUpdates();
|
||||
// Remove the live position entry
|
||||
await _client.from('live_positions').delete().eq('user_id', userId);
|
||||
}
|
||||
}
|
||||
|
||||
/// Immediately fetches current position and upserts into live_positions.
|
||||
Future<void> _updatePositionNow() async {
|
||||
try {
|
||||
final serviceEnabled = await Geolocator.isLocationServiceEnabled();
|
||||
if (!serviceEnabled) return;
|
||||
|
||||
var permission = await Geolocator.checkPermission();
|
||||
if (permission == LocationPermission.denied ||
|
||||
permission == LocationPermission.deniedForever) {
|
||||
return;
|
||||
}
|
||||
|
||||
final position = await Geolocator.getCurrentPosition(
|
||||
locationSettings: const LocationSettings(
|
||||
accuracy: LocationAccuracy.high,
|
||||
),
|
||||
);
|
||||
|
||||
await _client.rpc(
|
||||
'update_live_position',
|
||||
params: {'p_lat': position.latitude, 'p_lng': position.longitude},
|
||||
);
|
||||
} catch (_) {
|
||||
// Best-effort; don't block the toggle action
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Background location reporting service.
|
||||
|
||||
Reference in New Issue
Block a user