diff --git a/lib/view/page/server/card/metric.dart b/lib/view/page/server/card/metric.dart index cd179a6e78..459c520d6b 100644 --- a/lib/view/page/server/card/metric.dart +++ b/lib/view/page/server/card/metric.dart @@ -3,6 +3,7 @@ import 'package:icons_plus/icons_plus.dart'; import 'package:material_ui/material_ui.dart'; import 'package:server_box/core/extension/context/locale.dart'; import 'package:server_box/data/model/app/server_detail_card.dart'; +import 'package:server_box/data/model/server/battery.dart'; import 'package:server_box/data/model/server/gpu.dart'; import 'package:server_box/data/model/server/server.dart'; import 'package:server_box/data/provider/server/single.dart'; @@ -58,6 +59,10 @@ const kNetTrafficIcon = MingCute.chart_bar_line; /// and the extra slot's ranking all mean the same thing by "over". const kServerAlertPercent = 85.0; +/// The charge at which a battery running on itself is worth a look: the one +/// reading whose trouble is at the bottom rather than the top. +const kServerBatteryLowPercent = 20.0; + /// One reading, as a card draws it. /// /// The same object is the row and the chart: promoting a row is choosing which @@ -76,7 +81,8 @@ final class ServerMetric { required this.format, this.percent, this.binary = false, - }); + bool? over, + }) : _over = over; final ServerMetricKind kind; final String label; @@ -128,8 +134,12 @@ final class ServerMetric { /// rather than of 10. final bool binary; - /// Whether this reading is past [kServerAlertPercent]. - bool get over => percent != null && percent! * 100 >= kServerAlertPercent; + final bool? _over; + + /// Whether this reading is past its line: [kServerAlertPercent] for a share + /// of something that runs out, unless the reading says otherwise. + bool get over => + _over ?? (percent != null && percent! * 100 >= kServerAlertPercent); } /// Which reading a machine is being watched by, remembered per machine. @@ -661,6 +671,12 @@ List _readings(ServerState srv) { note: [battery.status.name, ?battery.name].join(' · '), bigNote: battery.status.name, percent: percent == null ? null : percent / 100, + // Full is where a battery should be. Low is only trouble while it is + // what the machine runs on. + over: + percent != null && + percent <= kServerBatteryLowPercent && + battery.status == BatteryStatus.discharging, samples: h.battery.toList(), times: times, format: ReadingFmt.pct, diff --git a/test/unit/server/server_card_readings_test.dart b/test/unit/server/server_card_readings_test.dart index c27af3a141..664926f8fe 100644 --- a/test/unit/server/server_card_readings_test.dart +++ b/test/unit/server/server_card_readings_test.dart @@ -1,4 +1,5 @@ import 'package:flutter_test/flutter_test.dart'; +import 'package:server_box/data/model/server/battery.dart'; import 'package:server_box/data/model/server/conn.dart'; import 'package:server_box/data/model/server/cpu.dart'; import 'package:server_box/data/model/server/disk.dart'; @@ -8,6 +9,7 @@ import 'package:server_box/data/model/server/server.dart'; import 'package:server_box/data/model/server/system.dart'; import 'package:server_box/data/model/server/temp.dart'; import 'package:server_box/data/provider/server/single.dart'; +import 'package:server_box/data/res/chart_palette.dart'; import 'package:server_box/view/page/server/card/metric.dart'; import '../../helpers/spi_fixture.dart'; @@ -153,4 +155,26 @@ void main() { srv.status.cpu.brand.clear(); expect(serverCardReadings(srv).all.first.note, '×2'); }); + + test('a battery is over its line when low and discharging, not when full', () { + ServerMetric battery(int percent, BatteryStatus status) { + final srv = state(); + srv.status.batteries.add(Battery(status: status, percent: percent)); + return serverCardReadings(srv).all.firstWhere( + (m) => m.kind == ServerMetricKind.battery, + ); + } + + // #1673: a charged laptop turned its machine's dot yellow. + expect(battery(97, BatteryStatus.discharging).over, isFalse); + expect(battery(100, BatteryStatus.full).over, isFalse); + expect(battery(15, BatteryStatus.discharging).over, isTrue); + expect(battery(15, BatteryStatus.charging).over, isFalse); + + final srv = state(); + srv.status.batteries.add( + const Battery(status: BatteryStatus.discharging, percent: 97), + ); + expect(serverStateDot(srv), StatePalette.running); + }); }