Project

General

Profile

Feeding pagedart » History » Version 1

cristobal hernandez, 12/18/2025 01:45 AM

1 1 cristobal hernandez
---
2 1 cristobal hernandez
3 1 cristobal hernandez
| [[Interfaz|⌂]] | [[home_page.dart]] | [[history_page.dart]] | [[connection_page.dart]] | [[config_page.dart]] | 
4 1 cristobal hernandez
5 1 cristobal hernandez
---
6 1 cristobal hernandez
7 1 cristobal hernandez
h1. feeding_page.dart
8 1 cristobal hernandez
9 1 cristobal hernandez
<pre><code class="java">
10 1 cristobal hernandez
11 1 cristobal hernandez
import 'package:flutter/material.dart';
12 1 cristobal hernandez
import 'package:cloud_firestore/cloud_firestore.dart';
13 1 cristobal hernandez
14 1 cristobal hernandez
class FeedingPage extends StatefulWidget {
15 1 cristobal hernandez
  final String aquariumId;
16 1 cristobal hernandez
17 1 cristobal hernandez
  const FeedingPage({super.key, required this.aquariumId});
18 1 cristobal hernandez
19 1 cristobal hernandez
  @override
20 1 cristobal hernandez
  State<FeedingPage> createState() => _FeedingPageState();
21 1 cristobal hernandez
}
22 1 cristobal hernandez
23 1 cristobal hernandez
class _FeedingPageState extends State<FeedingPage> {
24 1 cristobal hernandez
  bool _isAutoFeedOn = true;
25 1 cristobal hernandez
  List<TimeOfDay> _feedTimes = [];
26 1 cristobal hernandez
  bool _loading = true;
27 1 cristobal hernandez
28 1 cristobal hernandez
  late DocumentReference _configRef;
29 1 cristobal hernandez
30 1 cristobal hernandez
  @override
31 1 cristobal hernandez
  void initState() {
32 1 cristobal hernandez
    super.initState();
33 1 cristobal hernandez
    _configRef = FirebaseFirestore.instance
34 1 cristobal hernandez
        .collection('acuarios')
35 1 cristobal hernandez
        .doc(widget.aquariumId)
36 1 cristobal hernandez
        .collection('data')
37 1 cristobal hernandez
        .doc('config');
38 1 cristobal hernandez
        
39 1 cristobal hernandez
    _cargarDatos();
40 1 cristobal hernandez
  }
41 1 cristobal hernandez
42 1 cristobal hernandez
  void _cargarDatos() async {
43 1 cristobal hernandez
    try {
44 1 cristobal hernandez
      DocumentSnapshot doc = await _configRef.get();
45 1 cristobal hernandez
      if (doc.exists) {
46 1 cristobal hernandez
        Map<String, dynamic> data = doc.data() as Map<String, dynamic>;
47 1 cristobal hernandez
        bool estadoSwitch = data['sistema_alimentacion_on'] ?? true;
48 1 cristobal hernandez
        List<dynamic> horasString = data['horarios_comida'] ?? [];
49 1 cristobal hernandez
        
50 1 cristobal hernandez
        setState(() {
51 1 cristobal hernandez
          _isAutoFeedOn = estadoSwitch;
52 1 cristobal hernandez
          _feedTimes = horasString.map((s) {
53 1 cristobal hernandez
            final parts = s.split(":");
54 1 cristobal hernandez
            return TimeOfDay(hour: int.parse(parts[0]), minute: int.parse(parts[1]));
55 1 cristobal hernandez
          }).toList();
56 1 cristobal hernandez
          _loading = false;
57 1 cristobal hernandez
        });
58 1 cristobal hernandez
      } else {
59 1 cristobal hernandez
        setState(() => _loading = false);
60 1 cristobal hernandez
      }
61 1 cristobal hernandez
    } catch (e) { setState(() => _loading = false); }
62 1 cristobal hernandez
  }
63 1 cristobal hernandez
64 1 cristobal hernandez
  void _guardarCambios() async {
65 1 cristobal hernandez
    List<String> horasString = _feedTimes.map((t) {
66 1 cristobal hernandez
      String h = t.hour.toString().padLeft(2, '0');
67 1 cristobal hernandez
      String m = t.minute.toString().padLeft(2, '0');
68 1 cristobal hernandez
      return "$h:$m";
69 1 cristobal hernandez
    }).toList();
70 1 cristobal hernandez
71 1 cristobal hernandez
    await _configRef.update({
72 1 cristobal hernandez
      'horarios_comida': horasString,
73 1 cristobal hernandez
      'sistema_alimentacion_on': _isAutoFeedOn 
74 1 cristobal hernandez
    });
75 1 cristobal hernandez
  }
76 1 cristobal hernandez
77 1 cristobal hernandez
  Future<void> _addTime() async {
78 1 cristobal hernandez
    final TimeOfDay? newTime = await showTimePicker(
79 1 cristobal hernandez
      context: context,
80 1 cristobal hernandez
      initialTime: TimeOfDay.now(),
81 1 cristobal hernandez
      builder: (context, child) {
82 1 cristobal hernandez
        return Theme(
83 1 cristobal hernandez
          data: ThemeData.dark().copyWith(
84 1 cristobal hernandez
            colorScheme: const ColorScheme.dark(
85 1 cristobal hernandez
              primary: Color(0xFFFF5400),
86 1 cristobal hernandez
              onPrimary: Colors.white,
87 1 cristobal hernandez
              surface: Color(0xFF001B2E),
88 1 cristobal hernandez
            ),
89 1 cristobal hernandez
          ),
90 1 cristobal hernandez
          child: child!,
91 1 cristobal hernandez
        );
92 1 cristobal hernandez
      },
93 1 cristobal hernandez
    );
94 1 cristobal hernandez
95 1 cristobal hernandez
    if (newTime != null) {
96 1 cristobal hernandez
      setState(() {
97 1 cristobal hernandez
        _feedTimes.add(newTime);
98 1 cristobal hernandez
        _feedTimes.sort((a, b) => (a.hour * 60 + a.minute).compareTo(b.hour * 60 + b.minute));
99 1 cristobal hernandez
      });
100 1 cristobal hernandez
      _guardarCambios(); 
101 1 cristobal hernandez
    }
102 1 cristobal hernandez
  }
103 1 cristobal hernandez
104 1 cristobal hernandez
  void _removeTime(int index) {
105 1 cristobal hernandez
    setState(() {
106 1 cristobal hernandez
      _feedTimes.removeAt(index);
107 1 cristobal hernandez
    });
108 1 cristobal hernandez
    _guardarCambios(); 
109 1 cristobal hernandez
  }
110 1 cristobal hernandez
111 1 cristobal hernandez
  @override
112 1 cristobal hernandez
  Widget build(BuildContext context) {
113 1 cristobal hernandez
    return Scaffold(
114 1 cristobal hernandez
      appBar: AppBar(
115 1 cristobal hernandez
        title: const Text('Alimentación', style: TextStyle(fontWeight: FontWeight.bold, color: Colors.white)),
116 1 cristobal hernandez
        backgroundColor: Colors.transparent,
117 1 cristobal hernandez
        iconTheme: const IconThemeData(color: Colors.white),
118 1 cristobal hernandez
        elevation: 0,
119 1 cristobal hernandez
      ),
120 1 cristobal hernandez
      body: _loading 
121 1 cristobal hernandez
        ? const Center(child: CircularProgressIndicator(color: Color(0xFFFF5400))) 
122 1 cristobal hernandez
        : SingleChildScrollView(
123 1 cristobal hernandez
          padding: const EdgeInsets.all(20),
124 1 cristobal hernandez
          child: Column(
125 1 cristobal hernandez
            crossAxisAlignment: CrossAxisAlignment.start,
126 1 cristobal hernandez
            children: [
127 1 cristobal hernandez
              Container(
128 1 cristobal hernandez
                decoration: BoxDecoration(
129 1 cristobal hernandez
                  color: _isAutoFeedOn ? const Color(0xFFFF5400) : Colors.grey.shade800,
130 1 cristobal hernandez
                  borderRadius: BorderRadius.circular(20),
131 1 cristobal hernandez
                  border: Border.all(color: Colors.black, width: 3),
132 1 cristobal hernandez
                  boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.5), blurRadius: 10, offset: const Offset(0, 5))],
133 1 cristobal hernandez
                ),
134 1 cristobal hernandez
                child: SwitchListTile(
135 1 cristobal hernandez
                  contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
136 1 cristobal hernandez
                  title: Text(_isAutoFeedOn ? 'Dispensador ACTIVO' : 'Dispensador APAGADO', style: const TextStyle(color: Colors.white, fontWeight: FontWeight.w900, fontSize: 20)),
137 1 cristobal hernandez
                  subtitle: Text(_isAutoFeedOn ? 'El sistema alimentará a las horas indicadas.' : 'El sistema NO alimentará.', style: TextStyle(color: Colors.white.withOpacity(0.8), fontSize: 12)),
138 1 cristobal hernandez
                  activeColor: Colors.white,
139 1 cristobal hernandez
                  activeTrackColor: Colors.black26,
140 1 cristobal hernandez
                  value: _isAutoFeedOn,
141 1 cristobal hernandez
                  onChanged: (bool value) {
142 1 cristobal hernandez
                    setState(() => _isAutoFeedOn = value);
143 1 cristobal hernandez
                    _guardarCambios();
144 1 cristobal hernandez
                  },
145 1 cristobal hernandez
                  secondary: const Icon(Icons.set_meal, color: Colors.white, size: 30),
146 1 cristobal hernandez
                ),
147 1 cristobal hernandez
              ),
148 1 cristobal hernandez
              const SizedBox(height: 30),
149 1 cristobal hernandez
              Opacity(
150 1 cristobal hernandez
                opacity: _isAutoFeedOn ? 1.0 : 0.5,
151 1 cristobal hernandez
                child: Column(
152 1 cristobal hernandez
                  crossAxisAlignment: CrossAxisAlignment.start,
153 1 cristobal hernandez
                  children: [
154 1 cristobal hernandez
                    const Text('Horarios Programados', style: TextStyle(color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold)),
155 1 cristobal hernandez
                    const SizedBox(height: 15),
156 1 cristobal hernandez
                    ListView.builder(
157 1 cristobal hernandez
                      shrinkWrap: true,
158 1 cristobal hernandez
                      physics: const NeverScrollableScrollPhysics(),
159 1 cristobal hernandez
                      itemCount: _feedTimes.length,
160 1 cristobal hernandez
                      itemBuilder: (context, index) {
161 1 cristobal hernandez
                        final time = _feedTimes[index];
162 1 cristobal hernandez
                        return Container(
163 1 cristobal hernandez
                          margin: const EdgeInsets.only(bottom: 10),
164 1 cristobal hernandez
                          decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(15), border: Border.all(color: const Color(0xFFFF5400), width: 3)),
165 1 cristobal hernandez
                          child: ListTile(
166 1 cristobal hernandez
                            leading: const Icon(Icons.access_time_filled, color: Colors.black87),
167 1 cristobal hernandez
                            title: Text(time.format(context), style: const TextStyle(color: Colors.black87, fontSize: 20, fontWeight: FontWeight.bold)),
168 1 cristobal hernandez
                            trailing: IconButton(
169 1 cristobal hernandez
                              icon: const Icon(Icons.delete, color: Color(0xFFD32F2F)),
170 1 cristobal hernandez
                              onPressed: _isAutoFeedOn ? () => _removeTime(index) : null,
171 1 cristobal hernandez
                            ),
172 1 cristobal hernandez
                          ),
173 1 cristobal hernandez
                        );
174 1 cristobal hernandez
                      },
175 1 cristobal hernandez
                    ),
176 1 cristobal hernandez
                    const SizedBox(height: 20),
177 1 cristobal hernandez
                    Center(
178 1 cristobal hernandez
                      child: ElevatedButton.icon(
179 1 cristobal hernandez
                        onPressed: _isAutoFeedOn ? _addTime : null,
180 1 cristobal hernandez
                        style: ElevatedButton.styleFrom(backgroundColor: const Color(0xFFFF5400), foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 30, vertical: 15)),
181 1 cristobal hernandez
                        icon: const Icon(Icons.add_alarm),
182 1 cristobal hernandez
                        label: const Text('Agregar Horario', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)),
183 1 cristobal hernandez
                      ),
184 1 cristobal hernandez
                    ),
185 1 cristobal hernandez
                  ],
186 1 cristobal hernandez
                ),
187 1 cristobal hernandez
              )
188 1 cristobal hernandez
            ],
189 1 cristobal hernandez
          ),
190 1 cristobal hernandez
        ),
191 1 cristobal hernandez
    );
192 1 cristobal hernandez
  }
193 1 cristobal hernandez
}
194 1 cristobal hernandez
   
195 1 cristobal hernandez
</code></pre>