import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class SettingsScreen extends StatefulWidget { const SettingsScreen({super.key}); @override State createState() => _SettingsScreenState(); } class _SettingsScreenState extends State { List _cameraIPs = List.generate(6, (index) => 'Not Set'); final List _defaultIPs = [ '192.168.0.134:9081', '192.168.0.134:9082', '192.168.0.134:9083', '192.168.0.134:9084', '192.168.0.134:9085', '192.168.0.134:9086', ]; String _selectedBulletColor = 'Blue'; final List _bulletColors = [ 'Blue', 'Green', 'Yellow', 'Purple', 'Cyan', 'Teal', 'Indigo', 'Pink', 'Lime', 'Mint', 'Sky', 'Violet', ]; @override void initState() { super.initState(); _loadCameraIPs(); _loadBulletColor(); _loadBulletColor(); } Color _getColorFromName(String colorName) { switch (colorName.toLowerCase()) { case 'blue': return Colors.blue; case 'green': return Colors.green; case 'yellow': return Colors.yellow; case 'purple': return Colors.purple; case 'cyan': return Colors.cyan; case 'teal': return Colors.teal; case 'indigo': return Colors.indigo; case 'pink': return Colors.pink; case 'lime': return Colors.lime; case 'mint': return Colors.greenAccent; case 'sky': return Colors.orange; case 'violet': return Colors.deepPurpleAccent; default: return Colors.blue; // fallback } } Future _loadBulletColor() async { final prefs = await SharedPreferences.getInstance(); String savedColor = prefs.getString('bulletColor') ?? 'Blue'; // Fallback in case old color is no longer valid if (!_bulletColors.contains(savedColor)) { savedColor = 'Blue'; await prefs.setString('bulletColor', savedColor); } setState(() { _selectedBulletColor = savedColor; }); } Future _saveBulletColor(String color) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('bulletColor', color); setState(() => _selectedBulletColor = color); } Future _loadCameraIPs() async { final prefs = await SharedPreferences.getInstance(); List tempIPs = []; for (int i = 0; i < 6; i++) { String key = 'cameraIP_${i + 1}'; String? savedIP = prefs.getString(key); // If not saved, use default and write it to prefs if (savedIP == null) { await prefs.setString(key, _defaultIPs[i]); tempIPs.add(_defaultIPs[i]); } else { tempIPs.add(savedIP); } } setState(() { _cameraIPs = tempIPs; }); } Future _saveCameraIP(int index, String ip) async { final prefs = await SharedPreferences.getInstance(); await prefs.setString('cameraIP_${index + 1}', ip); _loadCameraIPs(); } Future _clearCameraIP(int index) async { final prefs = await SharedPreferences.getInstance(); await prefs.remove('cameraIP_${index + 1}'); _loadCameraIPs(); } void _editCameraIP(int index) { TextEditingController controller = TextEditingController( text: _cameraIPs[index], ); showDialog( context: context, builder: (context) { return Dialog( backgroundColor: Colors.grey[900], shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: const EdgeInsets.all(24.0), child: StatefulBuilder( builder: (context, setState) { return Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( "Camera ${index + 1}", style: const TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), const SizedBox(height: 16), SizedBox( width: double.infinity, child: TextField( controller: controller, style: const TextStyle(color: Colors.white), textAlign: TextAlign.center, decoration: InputDecoration( filled: true, fillColor: Colors.grey[800], hintText: "Enter Camera IP", hintStyle: const TextStyle(color: Colors.white54), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none, ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide(color: _getColorFromName(_selectedBulletColor)), ), ), ), ), const SizedBox(height: 24), // Save Button SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () async { String newIP = controller.text.trim(); if (newIP.isNotEmpty) { await _saveCameraIP(index, newIP); Navigator.pop(context); } }, style: ElevatedButton.styleFrom( backgroundColor: _getColorFromName(_selectedBulletColor), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text("Save"), ), ), const SizedBox(height: 12), // Reset Button SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () async { await _clearCameraIP(index); Navigator.pop(context); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.grey[700], foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text("Reset to Default"), ), ), const SizedBox(height: 12), // Cancel Button SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () => Navigator.pop(context), style: ElevatedButton.styleFrom( backgroundColor: Colors.grey[800], foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text("Cancel"), ), ), ], ); }, ), ), ); }, ); } @override Widget build(BuildContext context) { return Scaffold( body: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16), child: Column( children: [ const SizedBox(height: 8), _buildBulletColorSelector(), const SizedBox(height: 16), _buildCameraList(), ], ), ), ); } Widget _buildBulletColorSelector() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Select Bullet Color", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87, ), ), const SizedBox(height: 8), GestureDetector( onTap: _showBulletColorPopup, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Container( width: 16, height: 16, margin: const EdgeInsets.only(right: 12), decoration: BoxDecoration( color: _getColorFromName(_selectedBulletColor), shape: BoxShape.circle, border: Border.all(color: Colors.black26), ), ), Expanded( child: Text( _selectedBulletColor, style: const TextStyle(color: Colors.black87, fontSize: 14), ), ), const Icon(Icons.chevron_right, color: Colors.black54), ], ), ), ), ], ); } void _showBulletColorPopup() { showDialog( context: context, builder: (context) { return Dialog( backgroundColor: Colors.grey[900], shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ const Text( "Select Bullet Color", style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), const SizedBox(height: 20), Wrap( spacing: 12, runSpacing: 12, children: _bulletColors.map((colorName) { final color = _getColorFromName(colorName); final isSelected = colorName == _selectedBulletColor; return GestureDetector( onTap: () async { await _saveBulletColor(colorName); Navigator.of(context).pop(); }, child: Container( width: 48, height: 48, decoration: BoxDecoration( color: color, shape: BoxShape.circle, border: Border.all( color: isSelected ? Colors.white : Colors.white24, width: isSelected ? 3 : 1, ), ), ), ); }).toList(), ), const SizedBox(height: 20), TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text("Cancel", style: TextStyle(color: Colors.white70)), ), ], ), ), ); }, ); } Widget _buildCameraList() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Camera Settings", style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black87, ), ), const SizedBox(height: 8), ...List.generate(6, (index) { return GestureDetector( onTap: () => _editCameraIP(index), child: Container( margin: const EdgeInsets.symmetric(vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Camera ${index + 1}", style: const TextStyle( fontWeight: FontWeight.bold, color: Colors.black87, ), ), Text( _cameraIPs[index], style: const TextStyle(color: Colors.black54), ), ], ), const Icon(Icons.chevron_right, color: Colors.black45), ], ), ), ); }), ], ); } }