feat: ui rework and gear generator

This commit is contained in:
2026-04-28 17:13:30 +02:00
parent 82ea8125e1
commit 57a14134a6
300 changed files with 2901 additions and 135 deletions

View File

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:abawo_bt_app/controller/shifter_device_telemetry.dart';
import 'package:abawo_bt_app/model/firmware_file_selection.dart';
import 'package:abawo_bt_app/model/shifter_types.dart';
import 'package:abawo_bt_app/service/firmware_file_selection_service.dart';
@ -69,6 +70,8 @@ class _DeviceDetailsPageState extends ConsumerState<DeviceDetailsPage> {
String? _gearRatiosError;
List<double> _gearRatios = const [];
int _defaultGearIndex = 0;
bool _isDeviceTelemetryLoading = false;
bool _hasLoadedDeviceTelemetry = false;
late final FirmwareFileSelectionService _firmwareFileSelectionService;
FirmwareUpdateService? _firmwareUpdateService;
@ -195,6 +198,9 @@ class _DeviceDetailsPageState extends ConsumerState<DeviceDetailsPage> {
if (!_hasLoadedGearRatios && !_isGearRatiosLoading) {
unawaited(_loadGearRatios());
}
if (!_hasLoadedDeviceTelemetry && !_isDeviceTelemetryLoading) {
unawaited(_loadDeviceTelemetry());
}
return;
}
final asyncBluetooth = ref.read(bluetoothProvider);
@ -238,6 +244,7 @@ class _DeviceDetailsPageState extends ConsumerState<DeviceDetailsPage> {
_shifterService = service;
});
unawaited(_loadGearRatios());
unawaited(_loadDeviceTelemetry());
}
Future<void> _showPairingRecoveryDialog() async {
@ -276,6 +283,8 @@ class _DeviceDetailsPageState extends ConsumerState<DeviceDetailsPage> {
await _disposeFirmwareUpdateService();
await _shifterService?.dispose();
_shifterService = null;
_isDeviceTelemetryLoading = false;
_hasLoadedDeviceTelemetry = false;
}
Future<void> _disposeFirmwareUpdateService() async {
@ -285,6 +294,34 @@ class _DeviceDetailsPageState extends ConsumerState<DeviceDetailsPage> {
_firmwareUpdateService = null;
}
Future<void> _loadDeviceTelemetry({bool force = false}) async {
final shifter = _shifterService;
if (shifter == null || _isDeviceTelemetryLoading) {
return;
}
if (_hasLoadedDeviceTelemetry && !force) {
return;
}
_isDeviceTelemetryLoading = true;
final result = await shifter.readDeviceTelemetry();
if (!mounted) {
return;
}
_isDeviceTelemetryLoading = false;
if (result.isErr()) {
_hasLoadedDeviceTelemetry = false;
return;
}
ref.read(shifterDeviceTelemetryCacheProvider.notifier).upsert(
widget.deviceAddress,
result.unwrap(),
);
_hasLoadedDeviceTelemetry = true;
}
Future<void> _loadGearRatios() async {
final shifter = _shifterService;
if (shifter == null || _isGearRatiosLoading || _isFirmwareUpdateBusy) {
@ -539,6 +576,11 @@ class _DeviceDetailsPageState extends ConsumerState<DeviceDetailsPage> {
_firmwareUserMessage = result.unwrapErr().toString();
}
});
if (result.isOk()) {
_hasLoadedDeviceTelemetry = false;
unawaited(_loadDeviceTelemetry(force: true));
}
}
String _dfuPhaseText(DfuUpdateState state) {
@ -1208,6 +1250,11 @@ Widget _buildDeviceOverviewCard(
required CentralStatus? status,
}) {
final asyncSavedDevices = ref.watch(nConnectedDevicesProvider);
final telemetry = ref.watch(
shifterDeviceTelemetryCacheProvider.select(
(cache) => cache[deviceAddress],
),
);
return asyncSavedDevices.when(
data: (devices) {
@ -1229,12 +1276,11 @@ Widget _buildDeviceOverviewCard(
);
}
// TODO(yannik): Replace these overview placeholder metrics with actual
// battery, signal, and firmware values once the device exposes them.
return _DeviceOverviewCard(
device: currentDeviceData,
connectionStatus: connectionStatus,
status: status,
telemetry: telemetry,
);
},
loading: () => const Card(
@ -1257,11 +1303,13 @@ class _DeviceOverviewCard extends StatelessWidget {
required this.device,
required this.connectionStatus,
required this.status,
required this.telemetry,
});
final ConnectedDevice device;
final ConnectionStatus connectionStatus;
final CentralStatus? status;
final ShifterDeviceTelemetry? telemetry;
@override
Widget build(BuildContext context) {
@ -1317,27 +1365,27 @@ class _DeviceOverviewCard extends StatelessWidget {
),
const SizedBox(height: 18),
Row(
children: const [
children: [
Expanded(
child: _OverviewMetricTile(
label: 'Battery',
value: '--',
value: telemetry?.batteryLabel ?? '--',
icon: Icons.battery_charging_full_rounded,
),
),
SizedBox(width: 10),
Expanded(
const SizedBox(width: 10),
const Expanded(
child: _OverviewMetricTile(
label: 'Signal',
value: 'Ready',
icon: Icons.signal_cellular_alt_rounded,
),
),
SizedBox(width: 10),
const SizedBox(width: 10),
Expanded(
child: _OverviewMetricTile(
label: 'Firmware',
value: '--',
value: telemetry?.firmwareLabel ?? '--',
icon: Icons.memory_rounded,
),
),