Files
blinds_flutter/lib/BlindMasterScreens/individualControl/devices_menu.dart

220 lines
8.5 KiB
Dart
Raw Normal View History

2025-07-10 18:52:04 -05:00
import 'dart:convert';
import 'package:blind_master/BlindMasterResources/error_snackbar.dart';
import 'package:blind_master/BlindMasterResources/secure_transmissions.dart';
import 'package:blind_master/BlindMasterScreens/addingDevices/add_device.dart';
import 'package:blind_master/BlindMasterScreens/individualControl/device_screen.dart';
2025-12-24 18:40:07 -06:00
import 'package:blind_master/BlindMasterScreens/individualControl/peripheral_screen.dart';
2025-07-10 18:52:04 -05:00
import 'package:flutter/material.dart';
class DevicesMenu extends StatefulWidget {
const DevicesMenu({super.key});
@override
State<DevicesMenu> createState() => _DevicesMenuState();
}
class _DevicesMenuState extends State<DevicesMenu> {
List<Map<String, dynamic>> devices = [];
Widget? deviceList;
@override
void initState() {
super.initState();
getDevices();
}
Future getDevices() async {
try{
final response = await secureGet('device_list');
if (response == null) throw Exception("no response!");
if (response.statusCode == 200) {
final body = json.decode(response.body) as Map<String, dynamic>;
final names = body['devices'] as List;
final ids = body['device_ids'] as List;
2025-12-24 18:40:07 -06:00
final maxPortsList = body['max_ports'] as List;
2025-07-10 18:52:04 -05:00
devices = List.generate(names.length, (i) => {
'id': ids[i],
'name': names[i],
2025-12-24 18:40:07 -06:00
'max_ports': maxPortsList[i],
2025-07-10 18:52:04 -05:00
});
}
} catch(e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
errorSnackbar(e)
);
}
setState(() {
deviceList = RefreshIndicator(
onRefresh: getDevices,
child: devices.isEmpty
? SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: const Center(
child: Text(
"No hubs found...\nAdd one using the '+' button",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16),
),
),
),
)
: ListView.builder(
itemCount: devices.length,
itemBuilder: (context, i) {
final device = devices[i];
return Dismissible(
key: Key(device['id'].toString()),
direction: DismissDirection.endToStart,
background: Container(
color: Colors.red,
alignment: Alignment.centerRight,
padding: const EdgeInsets.symmetric(horizontal: 20),
child: const Icon(Icons.delete, color: Colors.white),
),
confirmDismiss: (direction) async {
// Ask for confirmation (optional)
return await showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Delete Hub'),
content: const Text('Are you sure you want to delete this hub?'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Cancel'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text('Delete'),
),
],
),
);
},
onDismissed: (direction) {
// Actually delete the device
deleteDevice(device['id'], i);
},
child: Card(
child: ListTile(
leading: const Icon(Icons.blinds),
title: Text(device['name']),
trailing: const Icon(Icons.arrow_forward_ios_rounded),
2025-12-24 18:40:07 -06:00
onTap: () async {
final maxPorts = device['max_ports'] as int;
if (maxPorts == 1) {
// Single-port device (C6): Get the single peripheral and navigate directly
try {
final payload = {"deviceId": device['id']};
final response = await secureGet('peripheral_list', queryParameters: payload);
if (response != null && response.statusCode == 200) {
final body = json.decode(response.body) as Map<String, dynamic>;
final ids = body['peripheral_ids'] as List;
final portNums = body['port_nums'] as List;
if (ids.isNotEmpty && mounted) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PeripheralScreen(
peripheralId: ids[0],
deviceId: device['id'],
peripheralNum: portNums[0],
deviceName: device['name'],
),
),
).then((_) { getDevices(); });
} else {
// No peripheral found, show error
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('No peripheral configured for this device'))
);
}
}
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(errorSnackbar(e));
}
}
} else {
// Multi-port device: Navigate to device screen
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DeviceScreen(deviceId: device['id']),
),
).then((_) { getDevices(); });
}
2025-07-10 18:52:04 -05:00
},
),
),
);
},
),
);
});
return Future.delayed(Duration(milliseconds: 500));
}
Future deleteDevice(int id, int i) async {
setState(() {
devices.removeAt(i);
deviceList = null;
});
print("deleting");
final payload = {
'deviceId': id,
};
try {
final response = await securePost(payload, 'delete_device');
if (response == null) return;
if (response.statusCode != 204) {
if (response.statusCode == 404) {throw Exception('Device Not Found');}
else if (response.statusCode == 500) {throw Exception('Server Error');}
}
if (mounted){
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Deleted',
textAlign: TextAlign.center,
)
),
);
}
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(errorSnackbar(e));
}
getDevices();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: deviceList ?? const Center(child: CircularProgressIndicator()),
floatingActionButton: Container(
padding: EdgeInsets.all(25),
child:FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddDevice()),
);
},
foregroundColor: Theme.of(context).highlightColor,
backgroundColor: Theme.of(context).primaryColorDark,
child: Icon(Icons.add),
),
)
2025-07-10 18:52:04 -05:00
);
}
}