import 'package:flutter/material.dart'; import '../theme/app_color.dart'; import '../widgets/kontrol_widgets.dart'; import 'jadwal_management_page.dart'; import 'threshold_management_page.dart'; import '../services/kontrol_storage.dart'; import '../services/firebase_database_service.dart'; class KontrolPage extends StatefulWidget { const KontrolPage({super.key}); @override State createState() => _KontrolPageState(); } class _KontrolPageState extends State { String _selectedMode = 'Manual'; @override Widget build(BuildContext context) { return PopScope( canPop: true, child: Scaffold( backgroundColor: AppColor.background, body: SafeArea( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Kontrol', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: AppColor.textDark, ), ), const SizedBox(height: 20), Text( 'Mode Kontrol', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColor.textDark, ), ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ ModeButton( mode: 'Manual', isSelected: _selectedMode == 'Manual', onPressed: () { setState(() { _selectedMode = 'Manual'; }); }, ), ModeButton( mode: 'Waktu', isSelected: _selectedMode == 'Waktu', onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const JadwalManagementPage(), ), ); }, ), ModeButton( mode: 'Sensor', isSelected: _selectedMode == 'Sensor', onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const ThresholdManagementPage(), ), ); }, ), ], ), const SizedBox(height: 24), const Expanded( child: ManualControlPage(), ), ], ), ), ), ), ); } } // ==================== MANUAL CONTROL PAGE ==================== class ManualControlPage extends StatefulWidget { const ManualControlPage({super.key}); @override State createState() => _ManualControlPageState(); } class _ManualControlPageState extends State { final FirebaseDatabaseService _dbService = FirebaseDatabaseService(); bool _pompaAir = false; bool _pompaNutrisi = false; bool _pengaduk = false; List _potStatus = [ false, false, false, false, false, ]; bool _isLoading = true; bool _hasLocalChanges = false; bool _isSubmitting = false; @override void initState() { super.initState(); _loadFirebaseState(); } Future _loadFirebaseState() async { try { final aktuatorData = await _dbService.getAktuatorStream().first; if (!mounted) return; setState(() { _pompaAir = aktuatorData['mosvet_1'] ?? false; _pompaNutrisi = aktuatorData['mosvet_2'] ?? false; _pengaduk = aktuatorData['mosvet_8'] ?? false; _potStatus = [ aktuatorData['mosvet_3'] ?? false, aktuatorData['mosvet_4'] ?? false, aktuatorData['mosvet_5'] ?? false, aktuatorData['mosvet_6'] ?? false, aktuatorData['mosvet_7'] ?? false, ]; _isLoading = false; _hasLocalChanges = false; }); } catch (e) { debugPrint('Error loading Firebase state: $e'); if (!mounted) return; setState(() { _isLoading = false; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Gagal memuat data: $e'), backgroundColor: Colors.orange, ), ); } } List _getActivePots() { final activePots = []; for (int i = 0; i < _potStatus.length; i++) { if (_potStatus[i]) { activePots.add(i + 1); } } return activePots; } Future _jalankan() async { if (_isSubmitting) return; setState(() { _isSubmitting = true; }); try { await _dbService.setMultipleAktuator({ 'mosvet_1': _pompaAir, 'mosvet_2': _pompaNutrisi, 'mosvet_3': _potStatus[0], 'mosvet_4': _potStatus[1], 'mosvet_5': _potStatus[2], 'mosvet_6': _potStatus[3], 'mosvet_7': _potStatus[4], 'mosvet_8': _pengaduk, }); await KontrolStorage.saveManualControl( pompaAir: _pompaAir, pompaNutrisi: _pompaNutrisi, pots: _potStatus, ); final activePots = _getActivePots(); if (activePots.isNotEmpty && (_pompaAir || _pompaNutrisi)) { await _dbService.saveManualWateringHistory( pots: activePots, duration: 0, ); } if (!mounted) return; setState(() { _hasLocalChanges = false; _isSubmitting = false; }); final activeDevices = []; if (_pompaAir) activeDevices.add('Pompa Air'); if (_pompaNutrisi) activeDevices.add('Pompa Nutrisi'); if (_pengaduk) activeDevices.add('Pengaduk'); for (int i = 0; i < _potStatus.length; i++) { if (_potStatus[i]) { activeDevices.add('POT ${i + 1}'); } } if (activeDevices.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Tidak ada perangkat yang diaktifkan'), backgroundColor: Colors.orange, ), ); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( '✓ Berhasil dijalankan: ${activeDevices.join(', ')}', ), backgroundColor: AppColor.primary, duration: const Duration(seconds: 3), ), ); } } catch (e) { if (!mounted) return; setState(() { _isSubmitting = false; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Error: $e'), backgroundColor: Colors.red, ), ); } } void _markChanged() { setState(() { _hasLocalChanges = true; }); } @override Widget build(BuildContext context) { if (_isLoading) { return const Center( child: CircularProgressIndicator(), ); } return SingleChildScrollView( child: Column( children: [ ControlSwitchCard( title: 'Pompa Air', isActive: _pompaAir, onPressed: () { if (_isSubmitting) return; setState(() { _pompaAir = !_pompaAir; }); _markChanged(); }, ), ControlSwitchCard( title: 'Pompa Nutrisi', isActive: _pompaNutrisi, onPressed: () { if (_isSubmitting) return; setState(() { _pompaNutrisi = !_pompaNutrisi; }); _markChanged(); }, ), ControlSwitchCard( title: 'Pengaduk', isActive: _pengaduk, onPressed: () { if (_isSubmitting) return; setState(() { _pengaduk = !_pengaduk; }); _markChanged(); }, ), const SizedBox(height: 16), Align( alignment: Alignment.centerLeft, child: Text( 'Kontrol POT (Kran)', style: TextStyle( fontSize: 16, fontWeight: FontWeight.w600, color: AppColor.textDark, ), ), ), const SizedBox(height: 12), ...List.generate(5, (index) { return ControlSwitchCard( title: 'POT ${index + 1}', isActive: _potStatus[index], onPressed: () { if (_isSubmitting) return; setState(() { _potStatus[index] = !_potStatus[index]; }); _markChanged(); }, ); }), const SizedBox(height: 24), if (_hasLocalChanges) Container( padding: const EdgeInsets.all(12), margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: Colors.orange.shade50, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.orange.shade300), ), child: Row( children: [ Icon( Icons.info_outline, color: Colors.orange.shade700, size: 20, ), const SizedBox(width: 8), Expanded( child: Text( 'Ada perubahan yang belum disimpan', style: TextStyle( fontSize: 13, color: Colors.orange.shade700, ), ), ), ], ), ), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { if (_isSubmitting) return; _jalankan(); }, style: ElevatedButton.styleFrom( backgroundColor: _hasLocalChanges ? AppColor.primary : Colors.grey, foregroundColor: Colors.white, padding: const EdgeInsets.all(16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: _isSubmitting ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (_hasLocalChanges) const Padding( padding: EdgeInsets.only(right: 8), child: Icon(Icons.send, size: 18), ), Text( _hasLocalChanges ? 'Jalankan Sekarang' : 'Jalankan', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ], ), ), ), ], ), ); } }