From ea1af967a01642b13c71159dc40a0c8ee4cfa022 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Sun, 28 Jun 2026 20:17:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(client):=20=E7=BB=9F=E8=AE=A1=E9=A1=B5/?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E9=A1=B5=20=E5=8A=A0=E8=BD=BD=E6=97=B6?= =?UTF-8?q?=E6=95=B4=E9=A1=B5=E8=BD=AC=E5=9C=88,=E5=85=88=E6=8B=89?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=86=8D=E6=B8=B2=E6=9F=93(=E4=B8=8D?= =?UTF-8?q?=E9=97=AA=E9=BB=98=E8=AE=A4=E6=80=81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 之前 .valueOrNull ?? 默认 → 数据没到时先渲染默认态(统计 0 / 连接页免费广告), me/usage 到了再跳真实态,闪烁体验差。改为关键 provider 首拉(loading 且无缓存)时 整页 CircularProgressIndicator: - 统计页:gate on usageProvider(30) - 连接页:gate on 新增 meLoadingProvider(me 是常驻 Notifier,只首启转一下) 未登录/golden 场景 me 同步返回默认=不加载,不影响 golden。 Co-Authored-By: Claude Opus 4.8 --- client/lib/screens/connect_page.dart | 5 +++++ client/lib/screens/stats_page.dart | 9 +++++++-- client/lib/state/app_providers.dart | 7 +++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/lib/screens/connect_page.dart b/client/lib/screens/connect_page.dart index 5100214..22f255c 100644 --- a/client/lib/screens/connect_page.dart +++ b/client/lib/screens/connect_page.dart @@ -34,6 +34,11 @@ class ConnectPage extends ConsumerWidget { final isFree = ref.watch(isFreePlanProvider); final quota = ref.watch(quotaProvider); final stats = ref.watch(vpnStatsProvider).valueOrNull; + // 账户首拉中 → 整页转圈,先拉到 me(决定免费/会员)再渲染, + // 避免「先闪免费广告、me 到了再跳会员」。me 是常驻 Notifier,只首启时转一下。 + if (ref.watch(meLoadingProvider)) { + return Center(child: CircularProgressIndicator(color: c.accent, strokeWidth: 2.6)); + } final down = formatSpeed(stats?.downloadSpeed); final up = formatSpeed(stats?.uploadSpeed); // 延迟来源:连接后优先用内核 urltest 实测(代理真实 RTT);urltest 还没探过时 diff --git a/client/lib/screens/stats_page.dart b/client/lib/screens/stats_page.dart index bd1164d..49f28df 100644 --- a/client/lib/screens/stats_page.dart +++ b/client/lib/screens/stats_page.dart @@ -20,7 +20,10 @@ class StatsPage extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final c = context.pangolin; final t = ref.watch(appTextProvider); - final usage = ref.watch(usageProvider(30)).valueOrNull ?? const []; + final usageAsync = ref.watch(usageProvider(30)); + final usage = usageAsync.valueOrNull ?? const []; + // 加载中且无缓存 → 整页转圈(先拉数据再渲染,不闪默认 0)。 + final loading = usageAsync.isLoading && !usageAsync.hasValue; // 周期聚合:取最后 N 天的点求和。最后一点即今日(避开 UTC/本地日期换算)。 (int down, int up, int min) sumLast(int days) { @@ -49,7 +52,9 @@ class StatsPage extends ConsumerWidget { final chartVals = chartPts.map((p) => p.gbTotal).toList(); final chartDates = chartPts.map((p) => p.date).toList(); - final body = RefreshIndicator( + final body = loading + ? Center(child: CircularProgressIndicator(color: c.accent, strokeWidth: 2.6)) + : RefreshIndicator( color: c.accent, backgroundColor: c.surface, onRefresh: () async { diff --git a/client/lib/state/app_providers.dart b/client/lib/state/app_providers.dart index 509941d..c2b3895 100644 --- a/client/lib/state/app_providers.dart +++ b/client/lib/state/app_providers.dart @@ -25,3 +25,10 @@ final isFreePlanProvider = Provider((ref) { final me = ref.watch(meProvider).valueOrNull; return me?.isFree ?? true; }); + +/// 账户聚合是否仍在「首拉」(加载中且无缓存)。连接页/统计页据此先转圈再渲染, +/// 避免免费默认态闪一下(广告/0)再跳成真实数据。 +final meLoadingProvider = Provider((ref) { + final me = ref.watch(meProvider); + return me.isLoading && !me.hasValue; +});