Responsive banner saying to wait for up to minute, as well as battery status.

This commit is contained in:
2026-03-21 00:00:35 -05:00
parent 80a2884077
commit 9d291652ac

View File

@@ -32,6 +32,8 @@ class _PeripheralScreenState extends State<PeripheralScreen> {
double _blindPosition = 5.0; double _blindPosition = 5.0;
DateTime? lastSet; DateTime? lastSet;
String lastSetMessage = ""; String lastSetMessage = "";
int? batterySoc;
bool _movementPending = false;
final _peripheralRenameController = TextEditingController(); final _peripheralRenameController = TextEditingController();
@@ -130,6 +132,7 @@ class _PeripheralScreenState extends State<PeripheralScreen> {
if (!mounted) return; if (!mounted) return;
final type = data['type'] as String? ?? ''; final type = data['type'] as String? ?? '';
final soc = data['soc'] as int? ?? 0; final soc = data['soc'] as int? ?? 0;
setState(() => batterySoc = soc);
final (String message, Color color) = switch (type) { final (String message, Color color) = switch (type) {
'overvoltage' => ('Battery fault detected. Please check your charger.', Colors.red), 'overvoltage' => ('Battery fault detected. Please check your charger.', Colors.red),
'critical_low' => ('Battery critically low ($soc%). Device shutting down.', Colors.red), 'critical_low' => ('Battery critically low ($soc%). Device shutting down.', Colors.red),
@@ -169,6 +172,7 @@ class _PeripheralScreenState extends State<PeripheralScreen> {
if (!mounted) return; if (!mounted) return;
setState(() { setState(() {
_blindPosition = (data['pos'] as int).toDouble(); _blindPosition = (data['pos'] as int).toDouble();
_movementPending = false;
}); });
} }
} }
@@ -341,6 +345,20 @@ class _PeripheralScreenState extends State<PeripheralScreen> {
} }
} }
Future<void> getDeviceBatterySoc() async {
try {
final payload = {'deviceId': widget.deviceId};
final response = await secureGet('device_name', queryParameters: payload);
if (response == null) throw Exception("auth error");
if (response.statusCode != 200) throw Exception("Server Error");
final body = json.decode(response.body);
if (!mounted) return;
setState(() => batterySoc = body['battery_soc'] as int?);
} catch (e) {
// Battery SOC is non-critical; swallow silently
}
}
Future<void> checkDeviceConnection() async { Future<void> checkDeviceConnection() async {
try { try {
final payload = { final payload = {
@@ -413,6 +431,7 @@ class _PeripheralScreenState extends State<PeripheralScreen> {
getName(); getName();
checkDeviceConnection(); checkDeviceConnection();
fetchState(); fetchState();
getDeviceBatterySoc();
} }
void rename() { void rename() {
@@ -548,37 +567,50 @@ class _PeripheralScreenState extends State<PeripheralScreen> {
), ),
backgroundColor: Theme.of(context).primaryColorLight, backgroundColor: Theme.of(context).primaryColorLight,
foregroundColor: Colors.white, foregroundColor: Colors.white,
bottom: !deviceConnected ? PreferredSize( actions: [
preferredSize: const Size.fromHeight(48.0), if (batterySoc != null)
child: Container( Padding(
width: double.infinity, padding: const EdgeInsets.symmetric(horizontal: 16),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16), child: Row(
color: Colors.orange.shade700, children: [
child: Row( Icon(
children: [ batterySoc! <= 10 ? Icons.battery_alert
const Icon( : batterySoc! <= 20 ? Icons.battery_1_bar
Icons.wifi_off, : batterySoc! <= 40 ? Icons.battery_2_bar
color: Colors.white, : batterySoc! <= 60 ? Icons.battery_3_bar
size: 20, : batterySoc! <= 80 ? Icons.battery_5_bar
), : Icons.battery_full,
const SizedBox(width: 12), color: batterySoc! <= 10 ? Colors.red : Colors.white,
const Expanded(
child: Text(
'Device Disconnected',
style: TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w500,
),
), ),
), const SizedBox(width: 4),
], Text('$batterySoc%', style: const TextStyle(color: Colors.white)),
],
),
), ),
), ],
) : null,
), ),
body: loaded body: Column(
children: [
if (_movementPending)
Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
color: Colors.orange.shade700,
child: Row(
children: [
const Icon(Icons.access_time, color: Colors.white, size: 20),
const SizedBox(width: 12),
const Expanded(
child: Text(
'Movement pending... Will take up to 1 minute',
style: TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.w500),
),
),
],
),
),
Expanded(child: loaded
? (calibrating ? (calibrating
? RefreshIndicator( ? RefreshIndicator(
onRefresh: initAll, onRefresh: initAll,
@@ -666,8 +698,9 @@ class _PeripheralScreenState extends State<PeripheralScreen> {
onPositionChanged: (value) { onPositionChanged: (value) {
setState(() { setState(() {
_blindPosition = value; _blindPosition = value;
updateBlindPosition(); _movementPending = true;
}); });
updateBlindPosition();
}, },
), ),
Container( Container(
@@ -718,7 +751,9 @@ class _PeripheralScreenState extends State<PeripheralScreen> {
) )
) )
))) )))
: BlindmasterProgressIndicator(), : BlindmasterProgressIndicator()),
],
),
floatingActionButton: Container( floatingActionButton: Container(
padding: EdgeInsets.all(25), padding: EdgeInsets.all(25),
child: Row( child: Row(