From ab477c08a9441a5cd942339106efe2b4b3cc65d2 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Tue, 10 Oct 2023 14:06:26 +0200 Subject: [PATCH] Get a table to be displayed --- frontend/lib/devices.dart | 133 +++++++++++++++++++++++--------------- frontend/lib/main.dart | 81 +++++++---------------- src/db.rs | 12 ++-- src/devices.rs | 9 ++- 4 files changed, 119 insertions(+), 116 deletions(-) diff --git a/frontend/lib/devices.dart b/frontend/lib/devices.dart index 7922e47..604d621 100644 --- a/frontend/lib/devices.dart +++ b/frontend/lib/devices.dart @@ -11,8 +11,6 @@ class Category { List devices; static Future> fetch(String base_url) async { - print("fetch: http://$base_url/devices"); - final response = await http.get(Uri.parse("http://$base_url/devices")); if (response.statusCode != 200) { @@ -21,54 +19,43 @@ class Category { final List categories = []; - print(response.body); - print("body type: ${response.body.runtimeType}"); + final Map> json = + Map.castFrom(jsonDecode(jsonDecode(response.body))); - final json = jsonDecode(response.body); + for (MapEntry> category_entry in json.entries) { + final Category category = Category(category_entry.key); - print(json); - print("json type: ${json.runtimeType}"); + for (dynamic device_info_dyn in category_entry.value) { + final Map device_info = device_info_dyn; - final Map>> test = jsonDecode(json); + final String device_id = device_info['id']; + final String? device_descriptor = device_info['desc']; + final bool power_control = device_info['toggle']; - print(test); - print("test type: ${test.runtimeType}"); + final response = + await http.get(Uri.parse("http://$base_url/plug_state/$device_id")); - // final Map>> json = jsonDecode(response.body); + if (response.statusCode != 200) { + throw Exception("Failed to fetch plug_state for $device_id"); + } - // for (MapEntry>> category_entry in json.entries) { - // final Category category = Category(category_entry.key); + final Map device_state = + Map.castFrom(jsonDecode(jsonDecode(response.body))); - // for (List device_info in category_entry.value) { - // final String device_id = device_info[0]; - // final String? device_descriptor = device_info[1]; - // final bool power_control = device_info[2]; + final Device device = Device( + device_id, + device_descriptor, + device_state["led"], + device_state["power"], + device_state["power_draw"], + power_control && device_state["power_draw"] < 15, + ); - // final response = - // await http.get(Uri.parse("$base_url/plug_state/$device_id")); + category.devices.add(device); + } - // if (response.statusCode != 200) { - // throw Exception("Failed to fetch plug_state for $device_id"); - // } - - // print(response.body); - - // final Map device_state = jsonDecode(response.body); - - // final Device device = Device( - // device_id, - // device_descriptor, - // device_state["led"], - // device_state["power"], - // device_state["power_draw"], - // power_control && device_state["power_draw"] < 15, - // ); - - // category.devices.add(device); - // } - - // categories.add(category); - // } + categories.add(category); + } return categories; } @@ -79,28 +66,68 @@ class CategoryWidget extends StatelessWidget { CategoryWidget({super.key, required this.category}); + String capitalize(String s) { + return "${s[0].toUpperCase()}${s.substring(1)}"; + } + @override Widget build(BuildContext context) { var list = category.devices .map((device) => TableRow(children: [ - Text(device.device_descriptor ?? device.device_id), - Text(device.led_state.toString()), - Text(device.power_state.toString()), - Text("${device.power_draw} W") + Text( + textAlign: TextAlign.center, + device.device_descriptor ?? device.device_id), + TextButton( + child: Text( + textAlign: TextAlign.center, + device.led_state ? 'On' : 'Off'), + onPressed: () {}, + ), + TextButton( + child: Text( + textAlign: TextAlign.center, + device.power_state ? 'On' : 'Off'), + onPressed: () {}, + ), + Text(textAlign: TextAlign.center, "${device.power_draw} W") ])) .toList(); list.insert( 0, - const TableRow(children: [ - Text("Name"), - Text("LED"), - Text("Power"), - Text("Power Draw"), - ])); + const TableRow( + decoration: BoxDecoration( + color: Colors.blueGrey, + ), + children: [ + Text( + style: TextStyle(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + "Name"), + Text( + style: TextStyle(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + "LED"), + Text( + style: TextStyle(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + "Power"), + Text( + style: TextStyle(fontWeight: FontWeight.bold), + textAlign: TextAlign.center, + "Power Draw"), + ])); - return Column( - children: [Text(category.name), Table(children: list)]); + return Column(children: [ + Text( + style: const TextStyle(fontWeight: FontWeight.bold), + textScaleFactor: 2.0, + capitalize(category.name)), + Table( + border: TableBorder.all(), + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + children: list) + ]); } } diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart index b2280c3..97b332b 100644 --- a/frontend/lib/main.dart +++ b/frontend/lib/main.dart @@ -13,27 +13,12 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - title: 'Flutter Demo', + title: 'SmartHome', theme: ThemeData( - // This is the theme of your application. - // - // TRY THIS: Try running your application with "flutter run". You'll see - // the application has a blue toolbar. Then, without quitting the app, - // try changing the seedColor in the colorScheme below to Colors.green - // and then invoke "hot reload" (save your changes or press the "hot - // reload" button in a Flutter-supported IDE, or press "r" if you used - // the command line to start the app). - // - // Notice that the counter didn't reset back to zero; the application - // state is not lost during the reload. To reset the state, use hot - // restart instead. - // - // This works for code too, not just values: Most code changes can be - // tested with just a hot reload. colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), - home: const MyHomePage(title: 'Flutter Demo Home Page'), + home: const MyHomePage(title: 'SmartHome Main Page'), ); } } @@ -41,15 +26,6 @@ class MyApp extends StatelessWidget { class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); - // This widget is the home page of your application. It is stateful, meaning - // that it has a State object (defined below) that contains fields that affect - // how it looks. - - // This class is the configuration for the state. It holds the values (in this - // case the title) provided by the parent (in this case the App widget) and - // used by the build method of the State. Fields in a Widget subclass are - // always marked "final". - final String title; @override @@ -59,38 +35,27 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { @override Widget build(BuildContext context) { - final Future> fut = Category.fetch("127.0.0.1:8062"); - // final Future> fut = Category.fetch("smart.gavania.de"); + return FutureBuilder>( + // future: Category.fetch("smart.gavania.de"), + future: Category.fetch("127.0.0.1:8062"), + builder: (context, AsyncSnapshot> categories) { + if (!categories.hasData) { + return const Text("still loading"); + } - List children = List.empty(); - - fut.then((categories) { - children = categories - .map((category) => CategoryWidget(category: category)) - .toList(); - }); - - // return FutureBuilder>( - // future: Category.fetch("smart.gavania.de"), - // builder: (context, AsyncSnapshot> categories) { - // if (!categories.hasData) { - // return const Text("still loading"); - // } - - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text(widget.title), - ), - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - // children: categories.data! - // .map((category) => CategoryWidget(category: category)) - // .toList(), - children: children, - ), - )); - // }); + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: Text(widget.title), + ), + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: categories.data! + .map((category) => CategoryWidget(category: category)) + .toList(), + ), + )); + }); } } diff --git a/src/db.rs b/src/db.rs index 78781ca..72c6d91 100644 --- a/src/db.rs +++ b/src/db.rs @@ -3,7 +3,7 @@ use std::path::Path; use anyhow::Result; use rusqlite::{Connection, OptionalExtension, ToSql}; -use crate::devices::{Devices, DevicesWithName}; +use crate::devices::{DeviceWithName, Devices, DevicesWithName}; pub struct DataBase { sql: Connection, @@ -151,7 +151,11 @@ impl DataBase { let (device, dev_type, name, control): (String, String, Option, i32) = row?; match dev_type.as_str() { - "plug" => devices.plugs.push((device, name, control != 0)), + "plug" => devices.plugs.push(DeviceWithName { + id: device, + desc: name, + toggle: control != 0, + }), _ => panic!(), } @@ -313,8 +317,8 @@ mod test { let devices = db.devices()?; - assert_eq!(devices.plugs[0].1.as_ref().unwrap(), device_descriptor); - assert_eq!(devices.plugs[0].0, device_name); + assert_eq!(devices.plugs[0].desc.as_ref().unwrap(), device_descriptor); + assert_eq!(devices.plugs[0].id, device_name); fs::remove_file("write_test.db")?; diff --git a/src/devices.rs b/src/devices.rs index 172021f..1ca757b 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -24,9 +24,16 @@ impl Devices { } } +#[derive(Debug, Clone, Deserialize, Serialize, Default)] +pub struct DeviceWithName { + pub id: String, + pub desc: Option, + pub toggle: bool, +} + #[derive(Debug, Clone, Deserialize, Serialize, Default)] pub struct DevicesWithName { - pub plugs: Vec<(String, Option, bool)>, + pub plugs: Vec, } impl DevicesWithName {