import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../core/app_colors.dart'; import 'app_error_state.dart'; /// 基于 FutureBuilder 的四态封装:统一处理"加载中 / 失败", /// "空数据 / 有数据"交由 onData 自行判断(不同页面空态文案不同)。 /// /// onData 拿到非空数据后,自行判断 isEmpty 决定显示空态还是列表。 class AppFutureView extends StatelessWidget { final Future? future; final Widget Function(BuildContext context, T data) onData; final VoidCallback? onRetry; final Widget? loading; final String? errorTitle; const AppFutureView({ super.key, required this.future, required this.onData, this.onRetry, this.loading, this.errorTitle, }); @override Widget build(BuildContext context) { return FutureBuilder( future: future, builder: (ctx, snap) { // 失败优先于其它判断,避免把错误显示成"暂无数据" if (snap.hasError) { return AppErrorState(title: errorTitle ?? '加载失败', onRetry: onRetry); } // 首次加载、尚无数据 → 转圈 if (snap.connectionState == ConnectionState.waiting && !snap.hasData) { return loading ?? const Center( child: CircularProgressIndicator(color: AppColors.primary), ); } if (!snap.hasData) { return loading ?? const Center( child: CircularProgressIndicator(color: AppColors.primary), ); } return onData(ctx, snap.data as T); }, ); } } /// Riverpod 异步数据视图。Provider 会保留最近一次成功数据,刷新时不清空页面。 class AppAsyncValueView extends StatelessWidget { final AsyncValue value; final Widget Function(BuildContext context, T data) onData; final VoidCallback? onRetry; final Widget? loading; final String? errorTitle; const AppAsyncValueView({ super.key, required this.value, required this.onData, this.onRetry, this.loading, this.errorTitle, }); @override Widget build(BuildContext context) => value.when( skipLoadingOnRefresh: true, skipLoadingOnReload: true, data: (data) => onData(context, data), error: (_, _) => AppErrorState(title: errorTitle ?? '加载失败', onRetry: onRetry), loading: () => loading ?? const Center( child: CircularProgressIndicator(color: AppColors.primary), ), ); }