import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/mqtt_provider.dart'; import '../widgets/webcam_view.dart'; import '../widgets/control_panel.dart'; class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Kontrol AC Ruang Kelas'), backgroundColor: Colors.blue[800], foregroundColor: Colors.white, actions: [ IconButton( icon: const Icon(Icons.refresh), onPressed: () { Provider.of(context, listen: false).connect(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Menghubungkan ulang...'), duration: Duration(seconds: 1)), ); }, ), ], ), body: Consumer( builder: (context, provider, child) { return RefreshIndicator( onRefresh: () async => provider.connect(), child: SingleChildScrollView( physics: const AlwaysScrollableScrollPhysics(), padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildConnectionStatus(provider), const SizedBox(height: 16), _buildWebcamSection(provider), const SizedBox(height: 16), _buildModeSwitch(context, provider), const SizedBox(height: 16), _buildStatusCards(provider), const SizedBox(height: 8), if (provider.acStatus == "on") _buildActiveTime(provider), const SizedBox(height: 16), if (provider.isAutoMode) _buildTimerSlider(provider), const SizedBox(height: 16), if (!provider.isAutoMode) ControlPanel(provider: provider), if (provider.isDelayActive) _buildDelayIndicator(provider), const SizedBox(height: 16), _buildModeInfo(provider), ], ), ), ); }, ), ); } Widget _buildConnectionStatus(MQTTProvider provider) { Color statusColor; IconData statusIcon; switch (provider.connectionStatus) { case "Connected": statusColor = Colors.green; statusIcon = Icons.check_circle; break; case "Connecting...": statusColor = Colors.orange; statusIcon = Icons.hourglass_empty; break; default: statusColor = Colors.red; statusIcon = Icons.error; } return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: statusColor.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: statusColor), ), child: Row( children: [ Icon(statusIcon, color: statusColor), const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Status Koneksi', style: TextStyle(fontSize: 12, color: Colors.grey[600])), Text(provider.connectionStatus, style: TextStyle( fontWeight: FontWeight.bold, color: statusColor)), ], ), ), if (provider.connectionStatus != "Connected") TextButton( onPressed: () => provider.connect(), child: const Text('Hubungkan'), ), ], ), ); } Widget _buildWebcamSection(MQTTProvider provider) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(Icons.videocam, color: Colors.blue), SizedBox(width: 8), Text('Monitoring Ruangan', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), ], ), const SizedBox(height: 8), const Text('Deteksi kehadiran real-time', style: TextStyle(fontSize: 12, color: Colors.grey)), const SizedBox(height: 12), SizedBox(height: 300, child: WebcamView()), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon(Icons.people, size: 16, color: provider.presenceColor), const SizedBox(width: 4), Text( 'Status: ${provider.presenceStatus == "ada" ? "👥 Ada orang" : "🚪 Ruangan kosong"}', style: TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: provider.presenceColor), ), ], ), Text( 'Frame: ${provider.detectionCount}', style: const TextStyle(fontSize: 12, color: Colors.grey), ), ], ), ], ); } // ==================== MODE SWITCH (RESPONSIF UNTUK HP & DESKTOP) ==================== Widget _buildModeSwitch(BuildContext context, MQTTProvider provider) { // Deteksi ukuran layar final screenWidth = MediaQuery.of(context).size.width; final isSmallScreen = screenWidth < 500; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( gradient: LinearGradient( colors: provider.isAutoMode ? [Colors.green.shade700, Colors.green.shade500] : [Colors.orange.shade700, Colors.orange.shade500], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(16), ), child: isSmallScreen ? _buildMobileModeSwitch(provider, context) : _buildDesktopModeSwitch(provider, context), ); } // Layout untuk Desktop/Laptop (lebar layar > 500px) Widget _buildDesktopModeSwitch(MQTTProvider provider, BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon(provider.isAutoMode ? Icons.autorenew : Icons.touch_app, color: Colors.white, size: 28), const SizedBox(width: 12), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( provider.isAutoMode ? 'Mode Otomatis' : 'Mode Manual', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white), ), Text( provider.isAutoMode ? 'AC dikontrol berdasarkan kehadiran' : 'Kontrol AC secara manual dari tombol', style: TextStyle( fontSize: 12, color: Colors.white.withOpacity(0.9)), ), ], ), ], ), ElevatedButton( onPressed: () { provider.toggleAutoMode(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(provider.isAutoMode ? '✅ Mode Auto aktif' : '✋ Mode Manual aktif'), backgroundColor: provider.isAutoMode ? Colors.green : Colors.orange, duration: const Duration(seconds: 2), ), ); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: provider.isAutoMode ? Colors.green : Colors.orange, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(provider.isAutoMode ? Icons.smart_toy : Icons.people, size: 20), const SizedBox(width: 8), Text(provider.isAutoMode ? 'Ganti ke Manual' : 'Ganti ke Auto'), ], ), ), ], ); } // Layout untuk Mobile/HP (lebar layar < 500px) Widget _buildMobileModeSwitch(MQTTProvider provider, BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Baris atas: icon dan teks Row( children: [ Icon(provider.isAutoMode ? Icons.autorenew : Icons.touch_app, color: Colors.white, size: 28), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( provider.isAutoMode ? 'Mode Otomatis' : 'Mode Manual', style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white), ), Text( provider.isAutoMode ? 'AC dikontrol berdasarkan kehadiran' : 'Kontrol AC secara manual', style: TextStyle( fontSize: 11, color: Colors.white.withOpacity(0.9)), ), ], ), ), ], ), const SizedBox(height: 12), // Baris bawah: tombol (lebar penuh) ElevatedButton( onPressed: () { provider.toggleAutoMode(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(provider.isAutoMode ? '✅ Mode Auto aktif' : '✋ Mode Manual aktif'), backgroundColor: provider.isAutoMode ? Colors.green : Colors.orange, duration: const Duration(seconds: 2), ), ); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: provider.isAutoMode ? Colors.green : Colors.orange, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30)), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(provider.isAutoMode ? Icons.smart_toy : Icons.people, size: 18), const SizedBox(width: 8), Text(provider.isAutoMode ? 'Ganti ke Manual' : 'Ganti ke Auto'), ], ), ), ], ); } // ==================== END MODE SWITCH ==================== Widget _buildStatusCards(MQTTProvider provider) { return Row( children: [ Expanded( child: _buildStatusCard( title: 'Status AC', value: provider.acStatus == "on" ? "❄️ MENYALA" : "⭕ MATI", icon: provider.acIcon, color: provider.acColor, ), ), const SizedBox(width: 16), Expanded( child: _buildStatusCard( title: 'Mode Operasi', value: provider.isAutoMode ? "🤖 OTOMATIS" : "👆 MANUAL", icon: provider.isAutoMode ? Icons.autorenew : Icons.touch_app, color: provider.isAutoMode ? Colors.green : Colors.orange, ), ), ], ); } Widget _buildStatusCard( {required String title, required String value, required IconData icon, required Color color}) { return Container( decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topLeft, end: Alignment.bottomRight, colors: [color.withOpacity(0.2), color.withOpacity(0.05)], ), borderRadius: BorderRadius.circular(16), border: Border.all(color: color.withOpacity(0.3)), ), child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: color.withOpacity(0.2), borderRadius: BorderRadius.circular(12), ), child: Icon(icon, color: color, size: 24), ), const SizedBox(width: 12), Text(title, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.grey[600])), ], ), const SizedBox(height: 12), Text(value, style: TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: color)), ], ), ), ); } Widget _buildActiveTime(MQTTProvider provider) { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.blue.shade200), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.timer, color: Colors.blue, size: 20), const SizedBox(width: 8), Text( 'Waktu Aktif: ${provider.activeTime}', style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.blue), ), ], ), ); } Widget _buildTimerSlider(MQTTProvider provider) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade300), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(Icons.timer, color: Colors.orange), SizedBox(width: 8), Text('Timer Mati Otomatis', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)), ], ), const SizedBox(height: 8), const Text( 'AC akan mati otomatis setelah ruangan kosong selama waktu yang ditentukan', style: TextStyle(fontSize: 12, color: Colors.grey)), const SizedBox(height: 12), Row( children: [ const Text('Delay: ', style: TextStyle(fontWeight: FontWeight.bold)), Expanded( child: Slider( value: provider.delayTimer.toDouble(), min: 1, max: 60, divisions: 59, label: _formatDelayTime(provider.delayTimer), onChanged: (value) { provider.setDelayTimer(value.toInt()); }, ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 4), decoration: BoxDecoration( color: Colors.orange.shade100, borderRadius: BorderRadius.circular(20), ), child: Text( _formatDelayTime(provider.delayTimer), style: TextStyle( fontWeight: FontWeight.bold, color: Colors.orange.shade800), ), ), ], ), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: [1, 5, 10, 15, 30, 45, 60].map((minutes) { return ActionChip( label: Text(_formatDelayTimeShort(minutes)), onPressed: () => provider.setDelayTimer(minutes), backgroundColor: provider.delayTimer == minutes ? Colors.orange : Colors.grey.shade200, labelStyle: TextStyle( color: provider.delayTimer == minutes ? Colors.white : Colors.black87, fontSize: 12, ), ); }).toList(), ), ], ), ); } Widget _buildDelayIndicator(MQTTProvider provider) { final minutes = provider.delayRemaining ~/ 60; final seconds = provider.delayRemaining % 60; return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.orange.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.orange), ), child: Row( children: [ const Icon(Icons.hourglass_empty, color: Colors.orange), const SizedBox(width: 8), Expanded( child: Text( '⏰ AC akan mati dalam ${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}', style: const TextStyle( color: Colors.orange, fontWeight: FontWeight.w500), ), ), ], ), ); } Widget _buildModeInfo(MQTTProvider provider) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: provider.isAutoMode ? Colors.green.withOpacity(0.1) : Colors.orange.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all( color: provider.isAutoMode ? Colors.green : Colors.orange), ), child: Row( children: [ Icon(provider.isAutoMode ? Icons.info_outline : Icons.warning_amber, color: provider.isAutoMode ? Colors.green : Colors.orange), const SizedBox(width: 8), Expanded( child: Text( provider.isAutoMode ? '🤖 Mode Otomatis: AC dikontrol berdasarkan kehadiran. Mati otomatis setelah ${provider.delayTimer} menit ruangan kosong' : '👆 Mode Manual: Kontrol AC manual dari tombol di bawah. Timer tidak aktif', style: TextStyle( color: provider.isAutoMode ? Colors.green[800] : Colors.orange[800], fontSize: 13), ), ), ], ), ); } String _formatDelayTime(int minutes) { if (minutes < 60) { return '$minutes menit'; } else { return '1 jam'; } } String _formatDelayTimeShort(int minutes) { if (minutes < 60) { return '${minutes}m'; } else { return '1j'; } } }