/// 相册列表 Riverpod 状态(P3 计划 Task 4)。 /// /// 首帧后自动拉首页(build 返回加载态,microtask 里触发首次加载, /// 不在 build 内改 state);游标加载更多(失败保留已加载条目并提供 /// 重试标记);下拉刷新重置到第一页。创建/编辑/删除成功后由调用方 /// 调 [AlbumListNotifier.refresh] 同步。 library; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/api_client.dart'; import '../../core/app_exception.dart'; import '../../core/error_codes.dart'; import 'models.dart'; /// 相册列表状态。 class AlbumListState { const AlbumListState({ this.items = const [], this.nextCursor, this.hasMore = false, this.loading = false, this.loadingMore = false, this.loadMoreFailed = false, this.errorCode, }); /// 已加载条目(跨页累积)。 final List items; /// 下一页游标;null = 没有更多。 final String? nextCursor; /// 是否还有下一页(与 [nextCursor] 成对)。 final bool hasMore; /// 首次加载/刷新进行中。 final bool loading; /// 加载更多进行中。 final bool loadingMore; /// 最近一次加载更多失败(保留已加载条目,页脚显示重试)。 final bool loadMoreFailed; /// 首屏/刷新失败的错误码([AppException.code]);null = 无错误。 final String? errorCode; } /// 相册列表 Notifier(游标分页状态机)。 class AlbumListNotifier extends Notifier { /// 每页条数(契约列表端点通用上限内取 20)。 static const int pageSize = 20; @override AlbumListState build() { // microtask:确保不在 build 执行期内改 state。 Future.microtask(refresh); return const AlbumListState(loading: true); } /// 重置到第一页(下拉刷新/数据变更后同步)。 Future refresh() async { state = const AlbumListState(loading: true); try { final page = await ref .read(apiClientProvider) .listAlbums(limit: pageSize); state = AlbumListState( items: page.items, nextCursor: page.nextCursor, hasMore: page.hasMore, ); } on AppException catch (e) { state = AlbumListState(errorCode: e.code); } on Object { state = const AlbumListState(errorCode: ErrorCodes.internalError); } } /// 游标加载下一页(加载中/无更多时为空操作)。 Future loadMore() async { if (state.loading || state.loadingMore || !state.hasMore) return; state = AlbumListState( items: state.items, nextCursor: state.nextCursor, hasMore: true, loadingMore: true, ); try { final page = await ref.read(apiClientProvider).listAlbums( cursor: state.nextCursor, limit: pageSize, ); state = AlbumListState( items: [...state.items, ...page.items], nextCursor: page.nextCursor, hasMore: page.hasMore, ); } on AppException catch (e) { // 保留已加载条目:页脚给重试入口,错误码用于一次性提示语义。 state = AlbumListState( items: state.items, nextCursor: state.nextCursor, hasMore: true, loadMoreFailed: true, errorCode: e.code, ); } on Object { state = AlbumListState( items: state.items, nextCursor: state.nextCursor, hasMore: true, loadMoreFailed: true, errorCode: ErrorCodes.internalError, ); } } } /// 相册列表 Provider(首页相册 tab 消费)。 final albumListProvider = NotifierProvider( AlbumListNotifier.new, );