import 'package:flutter/cupertino.dart'; import 'package:get/get.dart'; import 'package:isekai_wiki/api/mw/list.dart'; import 'package:isekai_wiki/api/mw/mw_api.dart'; import 'package:isekai_wiki/api/response/page_info.dart'; import 'package:isekai_wiki/components/page_card.dart'; import 'package:isekai_wiki/models/favorite_list.dart'; import 'package:isekai_wiki/models/user.dart'; import 'package:isekai_wiki/pages/home.dart'; class RecentPageListController extends GetxController { Function? _handleReload; ScrollController? scrollController; UserController? uc; FavoriteListController? flc; var shouldRefresh = true; var pageList = RxList(); var continueInfo = RxMap(); var errorList = RxList(); var hasNextPage = true.obs; var isLoading = false.obs; RecentPageListController({this.scrollController}); @override void onInit() { scrollController?.addListener(() { if (scrollController!.position.pixels > scrollController!.position.maxScrollExtent - 10) { // 滚动到底部 if (hasNextPage.value && !isLoading.value) { loadNextPages(); } } }); super.onInit(); uc = Get.find(); flc = Get.find(); loadNextPages(); var homeController = Get.find(); homeController.onRefresh = refreshPages; } @override void dispose() { var homeController = Get.find(); homeController.onRefresh = refreshPages; super.dispose(); } Future refreshPages() async { continueInfo.clear(); errorList.clear(); hasNextPage.value = true; shouldRefresh = true; await loadNextPages(); } Future loadNextPages() async { // 如果没有下一页,则阻止加载 if (!hasNextPage.value) return; isLoading.value = true; var rcListRes = await MWApiList.getMixedRecentChanges( limit: 10, continueInfo: continueInfo.isNotEmpty ? continueInfo : null); if (!rcListRes.ok) { // 发生错误,展示错误列表 errorList.value = rcListRes.errorList ?? []; isLoading.value = false; hasNextPage.value = false; if (shouldRefresh) { pageList.clear(); } return; } var pageIds = rcListRes.data!.map((rcInfo) => rcInfo.pageid).toList(); var pageListRes = await MWApiList.getPageInfoList( pageids: pageIds, extractChars: 515, getInWatchlist: uc!.isLoggedIn); if (!pageListRes.ok) { // 发生错误,展示错误列表 errorList.value = pageListRes.errorList ?? []; isLoading.value = false; hasNextPage.value = false; if (shouldRefresh) { pageList.clear(); } return; } if (uc!.isLoggedIn) { // 更新收藏列表信息 flc!.updateFromPageList(pageListRes.data!); } // 加载完成,设置信息 if (shouldRefresh) { // 初次加载,替换全部数据 pageList.value = pageListRes.data!; shouldRefresh = false; } else { pageList.addAll(pageListRes.data!); } hasNextPage.value = rcListRes.continueInfo != null; continueInfo.value = rcListRes.continueInfo ?? {}; isLoading.value = false; } Future reload() async { if (_handleReload != null) { await _handleReload!(); } } void setReloadHandler(Function? reloadHandler) { _handleReload = reloadHandler; } } class RecentPageList extends StatelessWidget { final ScrollController? scrollController; const RecentPageList({ super.key, this.scrollController, }); Widget _buildSkeletonList() { return Column( key: key, children: [ for (var i = 0; i < 6; i++) PageCard(key: ValueKey("rpl-card-$i"), isLoading: true), ], ); } Widget _buildPageCard( int index, PageInfo pageInfo, RecentPageListController c, FavoriteListController fc) { return PageCard( key: ValueKey("rpl-card-$index"), pageInfo: c.pageList[index], isFavorite: fc.isFavorite(c.pageList[index]), onSetFavorite: fc.setFavorite, ); } SliverChildBuilderDelegate _buildPageListDelegate() { var c = Get.find(); var flc = Get.find(); return SliverChildBuilderDelegate( childCount: c.pageList.length + 1, (context, index) { if (index == 0) { // 第一页数据,直接加载 if (c.pageList.isEmpty) { return _buildSkeletonList(); } else { return _buildPageCard(index, c.pageList[index], c, flc); } } // 后续页数据 if (index < c.pageList.length) { return _buildPageCard(index, c.pageList[index], c, flc); } else if (index == c.pageList.length) { // 显示加载动画 return Padding( padding: const EdgeInsets.symmetric(vertical: 12), child: Center( child: c.isLoading.value ? const CupertinoActivityIndicator( radius: 14, ) : const SizedBox( width: 28, height: 28, ), ), ); } return null; }, ); } @override Widget build(BuildContext context) { Get.put(RecentPageListController(scrollController: scrollController)); return Obx( () => SliverList( delegate: _buildPageListDelegate(), ), ); } }