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; +});