diff --git a/Source Code Mobile/ir_provider.dart b/Source Code Mobile/ir_provider.dart new file mode 100644 index 0000000..e36cb6f --- /dev/null +++ b/Source Code Mobile/ir_provider.dart @@ -0,0 +1,37 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:firebase_database/firebase_database.dart'; + +import '../models/ir_received_model.dart'; +import '../services/firebase_service.dart'; + +class IrProvider extends ChangeNotifier { + IrReceivedModel? _lastSignal; + IrReceivedModel? get lastSignal => _lastSignal; + + StreamSubscription? _subscription; + + void startListening() { + _subscription?.cancel(); + + // ESP32 terbaru: saveIrReceived menggunakan setJSON (flat object) bukan pushJSON + // Gunakan onValue untuk mendengarkan perubahan flat object di /ir_received + _subscription = FirebaseService.irReceivedRef.onValue.listen((event) { + if (event.snapshot.value == null) return; + try { + final data = Map.from(event.snapshot.value as Map); + _lastSignal = IrReceivedModel.fromMap(data); + notifyListeners(); + } catch (_) { + // Abaikan error parsing + } + }); + } + + @override + void dispose() { + _subscription?.cancel(); + super.dispose(); + } +} diff --git a/Source Code Mobile/notification_provider.dart b/Source Code Mobile/notification_provider.dart new file mode 100644 index 0000000..06dc0fa --- /dev/null +++ b/Source Code Mobile/notification_provider.dart @@ -0,0 +1,64 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:firebase_database/firebase_database.dart'; + +import '../models/notification_model.dart'; +import '../services/firebase_service.dart'; +import '../services/notification_service.dart'; + +class NotificationProvider extends ChangeNotifier { + List _notifications = []; + List get notifications => _notifications; + + /// Track how many notifications existed on the previous update so we can + /// detect newly added entries and fire an OS push for them. + int _previousCount = 0; + + StreamSubscription? subscription; + + void startListening() { + subscription?.cancel(); + + subscription = FirebaseService.notificationRef.onValue.listen((event) { + final prev = _previousCount; + + _notifications = []; + + if (event.snapshot.value == null) { + _previousCount = 0; + notifyListeners(); + return; + } + + final data = Map.from(event.snapshot.value as Map); + + data.forEach((key, value) { + _notifications.add( + NotificationModel.fromMap(Map.from(value)), + ); + }); + + _notifications = _notifications.reversed.toList(); + _previousCount = _notifications.length; + + // If new entries appeared, fire an OS notification for the latest one + if (_notifications.isNotEmpty && _notifications.length > prev) { + final latest = _notifications.first; + NotificationService.showNotification( + title: latest.title, + body: latest.message, + id: DateTime.now().millisecondsSinceEpoch ~/ 1000, + ); + } + + notifyListeners(); + }); + } + + @override + void dispose() { + subscription?.cancel(); + super.dispose(); + } +} diff --git a/Source Code Mobile/sensor_provider.dart b/Source Code Mobile/sensor_provider.dart new file mode 100644 index 0000000..a720b9a --- /dev/null +++ b/Source Code Mobile/sensor_provider.dart @@ -0,0 +1,65 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:firebase_database/firebase_database.dart'; + +import '../models/sensor_model.dart'; +import '../services/firebase_service.dart'; + +class SensorProvider extends ChangeNotifier { + SensorModel? _sensor; + + SensorModel? get sensor => _sensor; + + bool _isLoading = true; + + bool get isLoading => _isLoading; + + String? _errorMessage; + + String? get errorMessage => _errorMessage; + + StreamSubscription? _subscription; + + void startListening() { + _subscription?.cancel(); + _isLoading = true; + _errorMessage = null; + + _subscription = FirebaseService.currentRef.onValue.listen((event) { + if (event.snapshot.value == null) { + _sensor = null; + _isLoading = false; + notifyListeners(); + return; + } + + try { + final data = Map.from(event.snapshot.value as Map); + _sensor = SensorModel.fromMap(data); + _errorMessage = null; + } catch (e) { + _sensor = null; + _errorMessage = 'Parsing Error: $e'; + } + + _isLoading = false; + notifyListeners(); + }, onError: (error) { + _sensor = null; + _errorMessage = 'Firebase Error: $error'; + _isLoading = false; + notifyListeners(); + }); + } + + void stopListening() { + _subscription?.cancel(); + } + + @override + void dispose() { + _subscription?.cancel(); + super.dispose(); + } +}