import 'package:flutter/material.dart'; import 'package:firebase_database/firebase_database.dart'; import 'package:percent_indicator/linear_percent_indicator.dart'; class AgeControlPage extends StatefulWidget { @override _AgeControlPageState createState() => _AgeControlPageState(); } class _AgeControlPageState extends State { final DatabaseReference _dbRef = FirebaseDatabase.instance.ref(); int ageInWeeks = 1; // Default umur ayam Map ranges = {}; bool showRangeControl = false; @override void initState() { super.initState(); _fetchAgeFromFirebase(); _fetchRangesFromFirebase(); } // Ambil umur ayam dari Firebase void _fetchAgeFromFirebase() { _dbRef.child("chicken_age").onValue.listen((event) { final data = event.snapshot.value; if (data != null) { setState(() { ageInWeeks = int.tryParse(data.toString()) ?? 1; }); } }); } // Ambil rentang dari Firebase void _fetchRangesFromFirebase() { _dbRef.child("ranges").onValue.listen((event) { final data = event.snapshot.value; if (data != null) { setState(() { ranges = Map.from(data as Map); }); } }); } // Update umur ayam ke Firebase Future _updateAge(int newAge) async { if (newAge < 1 || newAge > 4) return; // Batasan umur ayam (1-4 minggu) await _dbRef.child("chicken_age").set(newAge); // Simpan ke Firebase setState(() { ageInWeeks = newAge; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text("Umur ayam diperbarui ke $newAge minggu"), backgroundColor: Color(0xFFA82429), behavior: SnackBarBehavior.floating, action: SnackBarAction( label: 'OK', textColor: Colors.white, onPressed: () {}, ), ), ); } // Update rentang ke Firebase Future _updateRange(String type, String value, double newValue) async { String path = "ranges/week$ageInWeeks/$type/$value"; await _dbRef.child(path).set(newValue); } // Widget untuk slider rentang Widget _buildRangeSlider(String type, String value, double min, double max) { Color sliderColor = type == 'temperature' ? Color(0xFFA82429) : Colors.blue; IconData typeIcon = type == 'temperature' ? Icons.thermostat : Icons.water_drop; double currentValue = ranges['week$ageInWeeks']?[type]?[value]?.toDouble() ?? min; String valueName = value == 'min' ? 'Minimum' : value == 'max' ? 'Maksimum' : 'Target'; return Card( elevation: 3, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ Row( children: [ Icon(typeIcon, color: sliderColor), SizedBox(width: 10), Expanded( child: Text( "${type == 'temperature' ? 'Suhu' : 'Kelembapan'} $valueName", style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6), decoration: BoxDecoration( color: sliderColor.withOpacity(0.2), borderRadius: BorderRadius.circular(12), ), child: Text( "${currentValue.toStringAsFixed(1)}${type == 'temperature' ? '°C' : '%'}", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: sliderColor, ), ), ), ], ), SizedBox(height: 16), SliderTheme( data: SliderThemeData( activeTrackColor: sliderColor, inactiveTrackColor: sliderColor.withOpacity(0.2), thumbColor: sliderColor, overlayColor: sliderColor.withOpacity(0.3), valueIndicatorColor: sliderColor, valueIndicatorTextStyle: TextStyle(color: Colors.white), ), child: Slider( value: currentValue, min: min, max: max, divisions: (max - min).toInt() * 2, label: currentValue.toStringAsFixed(1), onChanged: (newValue) { setState(() { // Update local state for immediate feedback if (ranges['week$ageInWeeks'] == null) { ranges['week$ageInWeeks'] = {}; } if (ranges['week$ageInWeeks'][type] == null) { ranges['week$ageInWeeks'][type] = {}; } ranges['week$ageInWeeks'][type][value] = newValue; }); _updateRange(type, value, newValue); }, ), ), SizedBox(height: 10), LinearPercentIndicator( lineHeight: 8.0, percent: ((currentValue - min) / (max - min)).clamp(0.0, 1.0), progressColor: sliderColor, backgroundColor: sliderColor.withOpacity(0.1), barRadius: Radius.circular(4), padding: EdgeInsets.symmetric(horizontal: 0), animation: true, animationDuration: 500, ), ], ), ), ); } Widget _buildAgeSelector() { return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), ), child: Padding( padding: const EdgeInsets.all(20.0), child: Column( children: [ Text( "Umur Ayam", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.grey[800], ), ), SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate(4, (index) { final week = index + 1; final isSelected = ageInWeeks == week; return GestureDetector( onTap: () => _updateAge(week), child: Container( width: 60, margin: EdgeInsets.symmetric(horizontal: 8), child: Column( children: [ AnimatedContainer( duration: Duration(milliseconds: 300), width: 60, height: 60, decoration: BoxDecoration( color: isSelected ? Color(0xFFA82429) : Colors.grey[200], shape: BoxShape.circle, boxShadow: isSelected ? [ BoxShadow( color: Color(0xFFA82429).withOpacity(0.4), blurRadius: 8, offset: Offset(0, 4), ) ] : null, ), child: Center( child: Text( "$week", style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, color: isSelected ? Colors.white : Colors.grey[600], ), ), ), ), SizedBox(height: 8), Text( "Minggu", style: TextStyle( fontSize: 12, color: isSelected ? Color(0xFFA82429) : Colors.grey[600], ), ) ], ), ), ); }), ), SizedBox(height: 20), LinearPercentIndicator( lineHeight: 10.0, percent: ageInWeeks / 4, center: Text( "$ageInWeeks dari 4 minggu", style: TextStyle( fontSize: 12, fontWeight: FontWeight.bold, color: Colors.white, ), ), progressColor: Color(0xFFA82429), backgroundColor: Colors.grey[200], barRadius: Radius.circular(5), padding: EdgeInsets.symmetric(horizontal: 0), animation: true, animationDuration: 500, ), ], ), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: Color(0xFFA82429), elevation: 0, leading: IconButton( icon: Icon(Icons.arrow_back, color: Colors.white), onPressed: () { Navigator.pop(context); }, ), title: Text( "Kontrol Umur & Rentang", style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, ), ), actions: [ IconButton( icon: Icon( showRangeControl ? Icons.visibility_off : Icons.visibility, color: Colors.white, ), onPressed: () { setState(() { showRangeControl = !showRangeControl; }); }, ), ], ), body: Column( children: [ // Header curved Container( padding: EdgeInsets.only(bottom: 20), decoration: BoxDecoration( color: Color(0xFFA82429), borderRadius: BorderRadius.only( bottomLeft: Radius.circular(30), bottomRight: Radius.circular(30), ), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.5), spreadRadius: 2, blurRadius: 5, offset: Offset(0, 3), ), ], ), child: Center( child: Column( children: [ SizedBox(height: 10), CircleAvatar( backgroundColor: Colors.white, radius: 40, child: Icon( Icons.pets, size: 50, color: Color(0xFFA82429), ), ), SizedBox(height: 10), Text( "Kontrol Umur & Pengaturan Rentang", style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), SizedBox(height: 5), Text( "Pengelolaan Umur Ayam dan Rentang Sensor", style: TextStyle( color: Colors.white.withOpacity(0.9), fontSize: 14, ), ), ], ), ), ), // Content Expanded( child: SingleChildScrollView( padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Age selector _buildAgeSelector(), SizedBox(height: 20), // Range toggles Card( elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), child: ListTile( leading: Icon( showRangeControl ? Icons.tune : Icons.tune_outlined, color: Color(0xFFA82429), ), title: Text( "Pengaturan Rentang", style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text( "Atur rentang suhu dan kelembapan yang optimal berdasarkan umur ayam", ), trailing: Switch( value: showRangeControl, activeColor: Color(0xFFA82429), onChanged: (value) { setState(() { showRangeControl = value; }); }, ), ), ), SizedBox(height: 20), // Bagian kontrol rentang (muncul saat toggle diaktifkan) if (showRangeControl) ...[ // Header untuk rentang suhu Padding( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 8.0), child: Row( children: [ Icon(Icons.thermostat, color: Color(0xFFA82429)), SizedBox(width: 8), Text( "Rentang Suhu", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFFA82429), ), ), ], ), ), SizedBox(height: 8), _buildRangeSlider("temperature", "min", 20, 40), SizedBox(height: 10), _buildRangeSlider("temperature", "target", 20, 40), SizedBox(height: 10), _buildRangeSlider("temperature", "max", 20, 40), SizedBox(height: 24), // Header untuk rentang kelembapan Padding( padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 8.0), child: Row( children: [ Icon(Icons.water_drop, color: Colors.blue), SizedBox(width: 8), Text( "Rentang Kelembapan", style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.blue, ), ), ], ), ), SizedBox(height: 8), _buildRangeSlider("humidity", "min", 30, 80), SizedBox(height: 10), _buildRangeSlider("humidity", "target", 30, 80), SizedBox(height: 10), _buildRangeSlider("humidity", "max", 30, 80), SizedBox(height: 30), // Info card Card( elevation: 2, color: Colors.blue.withOpacity(0.1), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( children: [ Row( children: [ Icon(Icons.info, color: Colors.blue), SizedBox(width: 8), Text( "Informasi Rentang", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.blue, ), ), ], ), SizedBox(height: 10), Text( "Pengaturan rentang akan mempengaruhi perilaku otomatis dalam pengendalian suhu dan kelembapan kandang ayam. Pastikan nilainya sesuai dengan kondisi optimal untuk setiap umur.", style: TextStyle( color: Colors.black87, ), ), ], ), ), ), ], ], ), ), ), ], ), ); } }