diff --git a/client/lib/screens/stats_page.dart b/client/lib/screens/stats_page.dart index f7649ee..b9b319b 100644 --- a/client/lib/screens/stats_page.dart +++ b/client/lib/screens/stats_page.dart @@ -3,6 +3,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import '../l10n/app_text.dart'; +import '../models/device_usage.dart'; import '../models/usage_point.dart'; import '../pangolin_theme.dart'; import '../state/account_providers.dart'; @@ -74,7 +76,7 @@ class StatsPage extends ConsumerWidget { style: PangolinText.display.copyWith(color: c.fg1, fontSize: 20, fontWeight: FontWeight.w700)) else const SizedBox.shrink(), - _DeviceDropdown(label: t.allDevices), + _DeviceDropdown(t: t), ]), const SizedBox(height: 14), PeriodCard(period: t.periodMonth, metrics: metricsFor(30)), @@ -129,16 +131,28 @@ class StatsPage extends ConsumerWidget { return ((bytes / mb).toStringAsFixed(1), 'MB'); } -/// 设备下拉(右上角):全部 + 近30天用过的设备名。 -/// 当前每设备归因未打通(usage_device_daily 常空),先只挂「全部」; -/// 设备注册打通后(TODO #9/#10)填充设备名 + 按设备过滤。 -class _DeviceDropdown extends StatelessWidget { - const _DeviceDropdown({required this.label}); - final String label; +/// 统计页选中的设备(null = 全部;否则 device uuid)。第②层(按设备过滤卡/图) +/// 待 per-device 每日曲线 API(#10);本层先把下拉内容接成真实设备。 +final statsDeviceProvider = StateProvider((ref) => null); + +/// 设备下拉(右上角):「全部」+ 近 30 天有用量的真实设备名(来自 deviceUsageProvider)。 +/// 无每设备用量时只显示「全部」(稀疏,正常)。 +class _DeviceDropdown extends ConsumerWidget { + const _DeviceDropdown({required this.t}); + final AppText t; @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { final c = context.pangolin; + final devices = ref.watch(deviceUsageProvider(30)).valueOrNull ?? const []; + final selected = ref.watch(statsDeviceProvider); + String nameOf(String uuid) => devices + .firstWhere((d) => d.uuid == uuid, orElse: () => const DeviceUsage(uuid: '', name: '', platform: '', bytesUp: 0, bytesDown: 0, minutesUsed: 0)) + .name; + final label = selected == null + ? t.allDevices + : (nameOf(selected).isNotEmpty ? nameOf(selected) : t.allDevices); + return PopupMenuButton( tooltip: '', offset: const Offset(0, 38), @@ -147,8 +161,14 @@ class _DeviceDropdown extends StatelessWidget { borderRadius: BorderRadius.circular(PangolinRadius.md), side: BorderSide(color: c.border), ), + onSelected: (v) => ref.read(statsDeviceProvider.notifier).state = v.isEmpty ? null : v, itemBuilder: (_) => [ - PopupMenuItem(value: '', child: Text(label, style: PangolinText.sm.copyWith(color: c.fg1))), + PopupMenuItem(value: '', child: Text(t.allDevices, style: PangolinText.sm.copyWith(color: c.fg1))), + for (final d in devices) + PopupMenuItem( + value: d.uuid, + child: Text(d.name.isNotEmpty ? d.name : d.platform, style: PangolinText.sm.copyWith(color: c.fg1)), + ), ], child: Container( padding: const EdgeInsets.fromLTRB(12, 6, 10, 6),