TKK_E32220565/newata2/lib/provider.dart

207 lines
5.4 KiB
Dart

// =================================================================
// STATE MANAGEMENT (PROVIDER)
// =================================================================
import 'package:CCTV_App/main.dart';
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
class AppState extends ChangeNotifier {
bool _isLoading = false;
String? _deviceId;
List<Map<String, dynamic>> _events = [];
Map<String, dynamic>? _deviceStatus;
User? _currentUser;
RealtimeChannel? _eventsChannel;
RealtimeChannel? _deviceStatusChannel;
bool get isLoading => _isLoading;
String? get deviceId => _deviceId;
List<Map<String, dynamic>> get events => _events;
Map<String, dynamic>? get deviceStatus => _deviceStatus;
User? get currentUser => _currentUser;
AppState() {
_currentUser = supabase.auth.currentUser;
supabase.auth.onAuthStateChange.listen((data) {
final session = data.session;
_currentUser = session?.user;
if (_currentUser == null) {
clearState();
}
notifyListeners();
});
}
void _unsubscribeFromChannels() {
if (_eventsChannel != null) {
supabase.removeChannel(_eventsChannel!);
_eventsChannel = null;
}
if (_deviceStatusChannel != null) {
supabase.removeChannel(_deviceStatusChannel!);
_deviceStatusChannel = null;
}
}
void clearState() {
_deviceId = null;
_events.clear();
_deviceStatus = null;
_unsubscribeFromChannels();
notifyListeners();
}
void _setLoading(bool value) {
_isLoading = value;
notifyListeners();
}
Future<bool> setDeviceIdAndFetchData(String deviceId) async {
_setLoading(true);
try {
final response = await supabase
.from('device_status')
.select('device_id')
.eq('device_id', deviceId)
.maybeSingle();
if (response == null) {
_setLoading(false);
return false;
}
_deviceId = deviceId;
await fetchInitialData();
_listenToRealtimeChanges();
notifyListeners();
_setLoading(false);
return true;
} catch (e) {
print('Error validating device ID: $e');
_setLoading(false);
return false;
}
}
Future<void> fetchInitialData() async {
if (_deviceId == null) return;
_setLoading(true);
await Future.wait([
fetchEvents(),
fetchDeviceStatus(),
]);
_setLoading(false);
}
Future<void> fetchEvents() async {
if (_deviceId == null) return;
try {
final response = await supabase
.from('events')
.select()
.eq('device_id', _deviceId!)
.order('timestamp', ascending: false);
_events = List<Map<String, dynamic>>.from(response);
} catch (e) {
print('Error fetching events: $e');
_events = [];
}
notifyListeners();
}
Future<void> fetchDeviceStatus() async {
if (_deviceId == null) return;
try {
final response = await supabase
.from('device_status')
.select()
.eq('device_id', _deviceId!)
.single();
_deviceStatus = response;
} catch (e) {
print('Error fetching device status: $e');
_deviceStatus = null;
}
notifyListeners();
}
void _listenToRealtimeChanges() {
if (_deviceId == null) return;
_unsubscribeFromChannels();
_eventsChannel = supabase.channel('public:events:device_id=$_deviceId');
_eventsChannel!
.onPostgresChanges(
event: PostgresChangeEvent.insert,
schema: 'public',
table: 'events',
filter: PostgresChangeFilter(
type: PostgresChangeFilterType.eq,
column: 'device_id',
value: _deviceId!,
),
callback: (payload) {
final newEvent = payload.newRecord;
if (!_events.any((e) => e['id'] == newEvent['id'])) {
_events.insert(0, newEvent);
notifyListeners();
}
},
)
.subscribe();
_deviceStatusChannel =
supabase.channel('public:device_status:device_id=$_deviceId');
_deviceStatusChannel!
.onPostgresChanges(
event: PostgresChangeEvent.update,
schema: 'public',
table: 'device_status',
filter: PostgresChangeFilter(
type: PostgresChangeFilterType.eq,
column: 'device_id',
value: _deviceId!,
),
callback: (payload) {
_deviceStatus = payload.newRecord;
notifyListeners();
},
)
.subscribe();
}
Future<void> signOut() async {
_setLoading(true);
await supabase.auth.signOut();
// clearState() akan dipanggil oleh listener onAuthStateChange
_setLoading(false);
}
Future<String?> setSleepSchedule(int durationMicroseconds) async {
if (_deviceId == null) {
return "Device not identified.";
}
_setLoading(true);
try {
await supabase.from('device_status').update({
'schedule_duration_microseconds': durationMicroseconds,
'last_update': DateTime.now().toIso8601String(),
}).eq('device_id', _deviceId!);
_setLoading(false);
return null;
} on PostgrestException catch (e) {
_setLoading(false);
print('Error setting sleep schedule: ${e.message}');
return e.message;
} catch (e) {
_setLoading(false);
print('Generic error setting sleep schedule: $e');
return 'An unexpected error occurred.';
}
}
}