import 'dart:async'; import 'package:flutter/material.dart'; import 'package:firebase_database/firebase_database.dart'; import '../models/ac_model.dart'; import '../services/firebase_service.dart'; class ACProvider extends ChangeNotifier { ACModel _ac = ACModel(power: false, mode: 'COOL', temp: 24, fan: 'AUTO', swing: false, controlMode: 'auto'); ACModel get ac => _ac; bool _isSending = false; bool get isSending => _isSending; StreamSubscription? _subscription; // ================= LISTENER ================= void startListening() { _subscription?.cancel(); _subscription = FirebaseService.acStateRef.onValue.listen((event) { if (event.snapshot.value == null) return; final data = Map.from(event.snapshot.value as Map); _ac = ACModel.fromMap(data); notifyListeners(); }); } // ================= SEND COMMAND ================= Future _sendCommand(String cmd, String val) async { try { _isSending = true; notifyListeners(); await FirebaseService.acCommandRef.set({'command': cmd, 'value': val}); // Write control history record to Firebase String actionText = '$cmd: $val'; if (cmd == 'power') { actionText = val == 'on' ? 'Menyalakan AC' : 'Mematikan AC'; } else if (cmd == 'mode') { actionText = 'Mengubah Mode ke ${val.toUpperCase()}'; } else if (cmd == 'temp') { actionText = 'Mengatur Suhu ke $val°C'; } else if (cmd == 'fan') { actionText = 'Mengatur Kipas ke ${val.toUpperCase()}'; } else if (cmd == 'swing') { actionText = val == 'on' ? 'Mengaktifkan Swing' : 'Mematikan Swing'; } else if (cmd == 'control_mode') { actionText = 'Mengubah Mode Kontrol ke ${val.toUpperCase()}'; } final timestamp = DateTime.now().millisecondsSinceEpoch ~/ 1000; await FirebaseService.controlHistoryRef.push().set({ 'action': actionText, 'source': 'Mobile', 'timestamp': timestamp, }); _isSending = false; notifyListeners(); } catch (e) { _isSending = false; notifyListeners(); rethrow; } } // ================= SINGLE FIELD UPDATES ================= Future setPower(bool value) async { await _sendCommand('power', value ? 'on' : 'off'); _ac = _ac.copyWith(power: value); notifyListeners(); } Future setMode(String value) async { await _sendCommand('mode', value.toLowerCase()); _ac = _ac.copyWith(mode: value); notifyListeners(); } Future setTemp(int value) async { if (value < 16 || value > 30) return; await _sendCommand('temp', value.toString()); _ac = _ac.copyWith(temp: value); notifyListeners(); } Future setFan(String value) async { await _sendCommand('fan', value.toLowerCase()); _ac = _ac.copyWith(fan: value); notifyListeners(); } Future toggleSwing() async { final nextValue = !_ac.swing; await _sendCommand('swing', nextValue ? 'on' : 'off'); _ac = _ac.copyWith(swing: nextValue); notifyListeners(); } Future setControlMode(String value) async { await _sendCommand('control_mode', value.toLowerCase()); _ac = _ac.copyWith(controlMode: value); notifyListeners(); } // ================= CYCLE HELPERS ================= /// Cycles through: COOL → DRY → HEAT → FAN → AUTO → COOL Future cycleMode() async { const modes = ['COOL', 'DRY', 'HEAT', 'FAN', 'AUTO']; final idx = modes.indexOf(_ac.mode.toUpperCase()); final next = modes[(idx == -1 ? 0 : idx + 1) % modes.length]; await setMode(next); } /// Cycles through: AUTO → LOW → MED → HIGH → MAX → AUTO Future cycleFan() async { const fans = ['AUTO', 'LOW', 'MED', 'HIGH', 'MAX']; final idx = fans.indexOf(_ac.fan.toUpperCase()); final next = fans[(idx == -1 ? 0 : idx + 1) % fans.length]; await setFan(next); } @override void dispose() { _subscription?.cancel(); super.dispose(); } }