import 'dart:async'; import 'dart:convert'; import 'package:app_ta/detail%20copy.dart'; import 'package:app_ta/theme.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; class Home extends StatefulWidget { @override State createState() => _HomeState(); } class _HomeState extends State { TextEditingController _ipController = TextEditingController(); Map> _esp32Data = {}; // New structure to hold more information Timer? _timer; @override void initState() { super.initState(); _timer = Timer.periodic(Duration(seconds: 1), (timer) { _updateTimeForAllDevices(); }); } @override void dispose() { _timer?.cancel(); super.dispose(); } Future _sendRequest() async { String ipAddress = _ipController.text.trim(); if (_esp32Data.containsKey(ipAddress)) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Device already connected')), ); return Navigator.of(context).pop(); } try { final response = await http.get(Uri.parse('http://$ipAddress/find')); if (response.statusCode == 200) { setState(() { _esp32Data[ipAddress] = { 'name': ipAddress, 'time': 'loading...', }; }); _ipController.clear(); Navigator.of(context).pop(); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Failed to connect to $ipAddress')), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Error connecting to $ipAddress')), ); return Navigator.of(context).pop(); } } void _updateTimeForAllDevices() { _esp32Data.forEach((ip, data) async { try { final response = await http.get(Uri.parse('http://$ip/get-time')); if (response.statusCode == 200) { var timeData = jsonDecode(response.body); setState(() { _esp32Data[ip]!['time'] = "${timeData['hours'].toString().padLeft(2, '0')}:${timeData['minutes'].toString().padLeft(2, '0') }:${timeData['seconds'].toString().padLeft(2, '0')}"; }); } } catch (e) { print('Failed to update time for $ip'); } }); } Widget deviceWidget(String ip) { var data = _esp32Data[ip]; return Container( margin: EdgeInsets.only(bottom: 10, left: 30, right: 30), height: 100, width: 320, decoration: BoxDecoration( border: Border.all(width: 2, color: primaryColor), borderRadius: BorderRadius.circular(14), ), child: Row(children: [ Container( margin: EdgeInsets.only(left: 16), height: 64, width: 64, decoration: BoxDecoration( image: DecorationImage( image: AssetImage('assets/images/ps.png'), )), ), Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Container( width: 144, // color: Colors.yellow, margin: EdgeInsets.only(left: 22), child: Text(data!['name'], style: primaryTextStyle.copyWith( fontSize: 22, fontWeight: semiBold))), // SizedBox(width: 20,), Container( // margin: EdgeInsets.only(left: 22), child: Text(data['time'], style: primaryTextStyle.copyWith( fontSize: 14, fontWeight: semiBold, color: Colors.blue))), ], ), SizedBox( height: 8, ), Row( children: [ GestureDetector( onTap: () { _navigateToDetail(ip); }, child: Container( margin: EdgeInsets.only(left: 22), height: 26, width: 78, decoration: BoxDecoration( borderRadius: BorderRadius.circular(6), color: primaryColor), child: Center( child: Text( 'detail', style: secondTextStyle, )), ), ), GestureDetector( onTap: () { _removeDevice(ip); }, child: Container( margin: EdgeInsets.only(left: 22), height: 26, width: 78, decoration: BoxDecoration( borderRadius: BorderRadius.circular(6), color: Colors.red), child: Center( child: Text('delete', style: secondTextStyle), ), ), ), ], ) ], ) ]) ); } void _removeDevice(String ip) { setState(() { _esp32Data.remove(ip); }); } void _navigateToDetail(String ip) { Navigator.push( context, MaterialPageRoute( builder: (context) => DetailTest(ip), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( 'ev center', style: primaryTextStyle.copyWith( fontSize: 28, fontWeight: FontWeight.bold), ), actions: [ IconButton( icon: Icon( Icons.add_circle_outline, color: Color(0xFF020518), ), onPressed: () => _showAddDialog(), ) ], elevation: 0, backgroundColor: Colors.transparent, ), body: _esp32Data.isEmpty ? Center( child: Text( 'belum ada perangkat terhubung', style: primaryTextStyle, ), ) : ListView( children: _esp32Data.keys.map((ip) => deviceWidget(ip)).toList(), ), ); } void _showAddDialog() { showDialog( context: context, builder: (BuildContext context) { return AlertDialog( contentPadding: EdgeInsets.all(16), // Atur padding konten content: Column( mainAxisSize: MainAxisSize.min, children: [ Align( alignment: Alignment.centerLeft, child: Text( 'IP Address', style: primaryTextStyle.copyWith( fontWeight: semiBold, ), ), ), Container( margin: EdgeInsets.only(top: 8), height: 45, width: 283, decoration: BoxDecoration( borderRadius: BorderRadius.circular(14), border: Border.all(width: 1)), child: Center( child: Container( padding: EdgeInsets.only(left: 10), child: TextFormField( controller: _ipController, style: primaryTextStyle, cursorColor: primaryColor, keyboardType: TextInputType.number, decoration: InputDecoration.collapsed( hintText: 'xxx.xxx.x.xx', hintStyle: primaryTextStyle.copyWith( color: Colors.grey.shade400)), ), ), ), ), SizedBox(height: 20.0), Container( width: 123, height: 45, decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), color: primaryColor), child: TextButton( onPressed: _sendRequest, child: Text( 'connect', style: secondTextStyle, ), ), ), ], ), ); }, ); } }