diff --git a/lib/common/widgets/http_error.dart b/lib/common/widgets/http_error.dart index 102a68f1..bec2cf4f 100644 --- a/lib/common/widgets/http_error.dart +++ b/lib/common/widgets/http_error.dart @@ -2,47 +2,64 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; class HttpError extends StatelessWidget { - const HttpError( - {required this.errMsg, required this.fn, this.btnText, super.key}); + const HttpError({ + this.isSliver = true, + this.errMsg, + this.callback, + this.btnText, + super.key, + }); + final bool isSliver; final String? errMsg; - final Function()? fn; + final Function()? callback; final String? btnText; @override Widget build(BuildContext context) { - return SliverToBoxAdapter( - child: Column( + return isSliver + ? SliverToBoxAdapter(child: content(context)) + : SizedBox( + width: double.infinity, + child: content(context), + ); + } + + Widget content(BuildContext context) => Column( + mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ + const SizedBox(height: 40), SvgPicture.asset( "assets/images/error.svg", height: 200, ), const SizedBox(height: 30), - Text( - errMsg ?? '请求异常', - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleSmall, - ), - const SizedBox(height: 20), - FilledButton.tonal( - onPressed: () { - fn!(); - }, - style: ButtonStyle( - backgroundColor: WidgetStateProperty.resolveWith((states) { - return Theme.of(context).colorScheme.primary.withAlpha(20); - }), - ), - child: Text( - btnText ?? '点击重试', - style: TextStyle(color: Theme.of(context).colorScheme.primary), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: SelectableText( + errMsg ?? '没有数据', + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.titleSmall, ), ), + if (callback != null) ...[ + const SizedBox(height: 20), + FilledButton.tonal( + onPressed: callback, + style: ButtonStyle( + backgroundColor: WidgetStateProperty.resolveWith((states) { + return Theme.of(context).colorScheme.primary.withAlpha(20); + }), + ), + child: Text( + btnText ?? '点击重试', + style: TextStyle(color: Theme.of(context).colorScheme.primary), + ), + ), + ], + SizedBox(height: 40 + MediaQuery.paddingOf(context).bottom), ], - ), - ); - } + ); } diff --git a/lib/common/widgets/loading_widget.dart b/lib/common/widgets/loading_widget.dart new file mode 100644 index 00000000..1d35aeca --- /dev/null +++ b/lib/common/widgets/loading_widget.dart @@ -0,0 +1,10 @@ +import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:flutter/material.dart'; + +Widget get loadingWidget => Center(child: CircularProgressIndicator()); + +Widget errorWidget({errMsg, callback}) => HttpError( + isSliver: false, + errMsg: errMsg, + callback: callback, + ); diff --git a/lib/common/widgets/no_data.dart b/lib/common/widgets/no_data.dart deleted file mode 100644 index 8b6a8214..00000000 --- a/lib/common/widgets/no_data.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; - -class NoData extends StatelessWidget { - const NoData({super.key}); - - @override - Widget build(BuildContext context) { - return SliverToBoxAdapter( - child: SizedBox( - height: 400, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SvgPicture.asset( - "assets/images/error.svg", - height: 200, - ), - const SizedBox(height: 20), - Text( - '没有数据', - textAlign: TextAlign.center, - style: Theme.of(context).textTheme.titleSmall, - ), - ], - ), - ), - ); - } -} diff --git a/lib/http/bangumi.dart b/lib/http/bangumi.dart index 01c806fc..6dcbdaf8 100644 --- a/lib/http/bangumi.dart +++ b/lib/http/bangumi.dart @@ -1,5 +1,4 @@ import 'package:PiliPalaX/http/loading_state.dart'; -import 'package:PiliPalaX/utils/extension.dart'; import '../models/bangumi/list.dart'; import 'index.dart'; @@ -10,11 +9,7 @@ class BangumiHttp { if (res.data['code'] == 0) { BangumiListDataModel data = BangumiListDataModel.fromJson(res.data['data']); - if (!data.list.isNullOrEmpty) { - return LoadingState.success(data.list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(data.list); } else { return LoadingState.error(res.data['message']); } @@ -25,11 +20,7 @@ class BangumiHttp { if (res.data['code'] == 0) { BangumiListDataModel data = BangumiListDataModel.fromJson(res.data['data']); - if (!data.list.isNullOrEmpty) { - return LoadingState.success(data.list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(data.list); } else { return LoadingState.error(res.data['message']); } diff --git a/lib/http/black.dart b/lib/http/black.dart index 78f12d4c..555f2c3b 100644 --- a/lib/http/black.dart +++ b/lib/http/black.dart @@ -1,5 +1,4 @@ import 'package:PiliPalaX/http/loading_state.dart'; -import 'package:PiliPalaX/utils/extension.dart'; import '../models/user/black.dart'; import 'index.dart'; @@ -15,11 +14,7 @@ class BlackHttp { }); if (res.data['code'] == 0) { BlackListDataModel data = BlackListDataModel.fromJson(res.data['data']); - if (!data.list.isNullOrEmpty) { - return LoadingState.success(data); - } else { - return LoadingState.empty(); - } + return LoadingState.success(data); } else { return LoadingState.error(res.data['message']); } diff --git a/lib/http/dynamics.dart b/lib/http/dynamics.dart index 739f138b..26da8148 100644 --- a/lib/http/dynamics.dart +++ b/lib/http/dynamics.dart @@ -1,5 +1,4 @@ import 'package:PiliPalaX/http/loading_state.dart'; -import 'package:PiliPalaX/utils/extension.dart'; import '../models/dynamics/result.dart'; import '../models/dynamics/up.dart'; @@ -25,11 +24,7 @@ class DynamicsHttp { if (res.data['code'] == 0) { try { DynamicsDataModel data = DynamicsDataModel.fromJson(res.data['data']); - if (!data.items.isNullOrEmpty) { - return LoadingState.success(data); - } else { - return LoadingState.empty(); - } + return LoadingState.success(data); } catch (err) { return LoadingState.error(err.toString()); } diff --git a/lib/http/live.dart b/lib/http/live.dart index 4f6c4f00..bcfb836c 100644 --- a/lib/http/live.dart +++ b/lib/http/live.dart @@ -17,11 +17,7 @@ class LiveHttp { List list = res.data['data']['list'] .map((e) => LiveItemModel.fromJson(e)) .toList(); - if (list.isNotEmpty) { - return LoadingState.success(list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(list); } else { return LoadingState.error(res.data['message']); } diff --git a/lib/http/loading_state.dart b/lib/http/loading_state.dart index 8423329b..048d3003 100644 --- a/lib/http/loading_state.dart +++ b/lib/http/loading_state.dart @@ -2,7 +2,7 @@ abstract class LoadingState { const LoadingState(); factory LoadingState.loading() = Loading; - factory LoadingState.empty() = Empty; + // factory LoadingState.empty() = Empty; factory LoadingState.success(T response) = Success; factory LoadingState.error(String errMsg) = Error; } @@ -11,9 +11,9 @@ class Loading extends LoadingState { const Loading(); } -class Empty extends LoadingState { - const Empty(); -} +// class Empty extends LoadingState { +// const Empty(); +// } class Success extends LoadingState { final T response; diff --git a/lib/http/user.dart b/lib/http/user.dart index a54cd709..2d220524 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -55,11 +55,7 @@ class UserHttp { 'up_mid': mid, }); if (res.data['code'] == 0) { - if (res.data['data'] != null) { - return LoadingState.success(FavFolderData.fromJson(res.data['data'])); - } else { - return LoadingState.empty(); - } + return LoadingState.success(FavFolderData.fromJson(res.data['data'])); } else { return LoadingState.error(res.data['message'] ?? '账号未登录'); } @@ -153,7 +149,7 @@ class UserHttp { var res = await Request().get(Api.seeYouLater); if (res.data['code'] == 0) { if (res.data['data']['count'] == 0) { - return LoadingState.empty(); + return LoadingState.success([]); } List list = []; for (var i in res.data['data']['list']) { diff --git a/lib/http/video.dart b/lib/http/video.dart index c31ba7db..7b0b2238 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -67,11 +67,7 @@ class VideoHttp { } } } - if (list.isNotEmpty) { - return LoadingState.success(list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(list); } else { return LoadingState.error(res.data['message']); } @@ -161,11 +157,7 @@ class VideoHttp { } } } - if (list.isNotEmpty) { - return LoadingState.success(list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(list); } else { return LoadingState.error(res.data['message']); } @@ -189,11 +181,7 @@ class VideoHttp { list.add(HotVideoItemModel.fromJson(i)); } } - if (list.isNotEmpty) { - return LoadingState.success(list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(list); } else { return LoadingState.error(res.data['message']); } @@ -210,11 +198,7 @@ class VideoHttp { list.add(item); } } - if (list.isNotEmpty) { - return LoadingState.success(list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(list); } else { return LoadingState.error(res['msg']); } @@ -357,11 +341,7 @@ class VideoHttp { list.add(videoItem); } } - if (list.isNotEmpty) { - return LoadingState.success(list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(list); } else { return LoadingState.error(res.data['message']); } @@ -970,11 +950,7 @@ class VideoHttp { list.add(HotVideoItemModel.fromJson(i)); } } - if (list.isNotEmpty) { - return LoadingState.success(list); - } else { - return LoadingState.empty(); - } + return LoadingState.success(list); } else { return LoadingState.error(res.data['message']); } diff --git a/lib/main.dart b/lib/main.dart index 770a9d8e..a2f24868 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -216,7 +216,7 @@ class MyApp extends StatelessWidget { centerTitle: false, scrolledUnderElevation: 0, backgroundColor: Platform.isIOS ? colorScheme.surface : null, - titleTextStyle: Theme.of(context).textTheme.titleMedium, + titleTextStyle: TextStyle(fontSize: 16, color: colorScheme.onSurface), ), navigationBarTheme: NavigationBarThemeData( surfaceTintColor: surfaceTintColor, diff --git a/lib/models/common/up_panel_position.dart b/lib/models/common/up_panel_position.dart index cbb58237..658d3643 100644 --- a/lib/models/common/up_panel_position.dart +++ b/lib/models/common/up_panel_position.dart @@ -6,10 +6,5 @@ enum UpPanelPosition { } extension UpPanelPositionDesc on UpPanelPosition { - String get values => ['left_fixed', 'right_fixed', 'left_drawer', 'right_drawer'][index]; - String get labels => ['左侧常驻','右侧常驻','左侧抽屉','右侧抽屉'][index]; -} - -extension UpPanelPositionCode on UpPanelPosition { - int get code => [0, 1, 2, 3][index]; + String get labels => ['左侧常驻', '右侧常驻', '左侧抽屉', '右侧抽屉'][index]; } diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index 5eb34468..e6181f7a 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -69,31 +69,32 @@ class _BangumiIntroPanelState extends State } _buildBody(LoadingState loadingState) { - return loadingState is Success - ? BangumiInfo( - heroTag: widget.heroTag, - loadingStatus: false, - bangumiDetail: loadingState.response, - cid: cid, - showEpisodes: widget.showEpisodes, - showIntroDetail: () => widget.showIntroDetail( - loadingState.response, - bangumiIntroController.videoTags, - ), - ) - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: bangumiIntroController.onReload, - ) - : BangumiInfo( - heroTag: widget.heroTag, - loadingStatus: true, - bangumiDetail: null, - cid: cid, - showEpisodes: widget.showEpisodes, - showIntroDetail: widget.showIntroDetail, - ); + return switch (loadingState) { + Loading() => BangumiInfo( + heroTag: widget.heroTag, + loadingStatus: true, + bangumiDetail: null, + cid: cid, + showEpisodes: widget.showEpisodes, + showIntroDetail: widget.showIntroDetail, + ), + Success() => BangumiInfo( + heroTag: widget.heroTag, + loadingStatus: false, + bangumiDetail: loadingState.response, + cid: cid, + showEpisodes: widget.showEpisodes, + showIntroDetail: () => widget.showIntroDetail( + loadingState.response, + bangumiIntroController.videoTags, + ), + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: bangumiIntroController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/bangumi/view.dart b/lib/pages/bangumi/view.dart index 480b7e95..936d2a22 100644 --- a/lib/pages/bangumi/view.dart +++ b/lib/pages/bangumi/view.dart @@ -109,17 +109,10 @@ class _BangumiPageState extends State ), SizedBox( height: Grid.maxRowWidth * 1, - child: Obx(() => - _bangumiController.followState.value is Empty - ? const SizedBox( - child: Center( - child: Text('还没有追番'), - ), - ) - : _bangumiController.followState.value is Success - ? _buildFollowList(_bangumiController - .followState.value as Success) - : const SizedBox()), + child: Obx( + () => _buildFollowBody( + _bangumiController.followState.value), + ), ), ], ), @@ -144,19 +137,7 @@ class _BangumiPageState extends State padding: const EdgeInsets.fromLTRB( StyleString.safeSpace, 0, StyleString.safeSpace, 0), sliver: Obx( - () => _bangumiController.loadingState.value is Loading - ? contentGrid([]) - : _bangumiController.loadingState.value is Success - ? contentGrid( - (_bangumiController.loadingState.value as Success) - .response) - : HttpError( - errMsg: _bangumiController.loadingState.value is Error - ? (_bangumiController.loadingState.value as Error) - .errMsg - : '没有相关数据', - fn: _bangumiController.onReload, - ), + () => _buildBody(_bangumiController.loadingState.value), ), ), ], @@ -164,6 +145,40 @@ class _BangumiPageState extends State ); } + Widget _buildBody(LoadingState loadingState) { + return switch (loadingState) { + Loading() => const SliverToBoxAdapter(), + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + // 行间距 + mainAxisSpacing: StyleString.cardSpace - 2, + // 列间距 + crossAxisSpacing: StyleString.cardSpace, + // 最大宽度 + maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2, + childAspectRatio: 0.65, + mainAxisExtent: MediaQuery.textScalerOf(context).scale(60), + ), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return BangumiCardV( + bangumiItem: loadingState.response[index]); + }, + childCount: loadingState.response.length, + ), + ) + : HttpError( + callback: _bangumiController.onReload, + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _bangumiController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; + } + Widget _buildFollowList(Success loadingState) { return ListView.builder( scrollDirection: Axis.horizontal, @@ -185,24 +200,14 @@ class _BangumiPageState extends State ); } - Widget contentGrid(List list) { - return SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - // 行间距 - mainAxisSpacing: StyleString.cardSpace - 2, - // 列间距 - crossAxisSpacing: StyleString.cardSpace, - // 最大宽度 - maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2, - childAspectRatio: 0.65, - mainAxisExtent: MediaQuery.textScalerOf(context).scale(60), - ), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return list.isNotEmpty ? BangumiCardV(bangumiItem: list[index]) : nil; - }, - childCount: list.isNotEmpty ? list.length : 10, - ), - ); + Widget _buildFollowBody(LoadingState loadingState) { + return switch (loadingState) { + Loading() => nil, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? _buildFollowList(loadingState) + : const Center(child: Text('还没有追番')), + Error() => Center(child: Text(loadingState.errMsg)), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/blacklist/index.dart b/lib/pages/blacklist/index.dart index 3a2dcba6..9c2510cb 100644 --- a/lib/pages/blacklist/index.dart +++ b/lib/pages/blacklist/index.dart @@ -1,3 +1,4 @@ +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/common/common_controller.dart'; @@ -5,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/http/black.dart'; import 'package:PiliPalaX/utils/storage.dart'; @@ -63,51 +63,52 @@ class _BlackListPageState extends State { } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? ListView.builder( - controller: _blackListController.scrollController, - itemCount: loadingState.response.length, - itemBuilder: (BuildContext context, int index) { - return ListTile( - onTap: () {}, - leading: NetworkImgLayer( - width: 45, - height: 45, - type: 'avatar', - src: loadingState.response[index].face, - ), - title: Text( - loadingState.response[index].uname!, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 14), - ), - subtitle: Text( - Utils.dateFormat(loadingState.response[index].mtime), - maxLines: 1, - style: - TextStyle(color: Theme.of(context).colorScheme.outline), - overflow: TextOverflow.ellipsis, - ), - dense: true, - trailing: TextButton( - onPressed: () => _blackListController - .removeBlack(loadingState.response[index].mid), - child: const Text('移除'), - ), - ); - }, - ) - : loadingState is Error - ? CustomScrollView( - slivers: [ - HttpError( - errMsg: loadingState.errMsg, - fn: _blackListController.onReload, - ) - ], - ) - : const SizedBox(); + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? ListView.builder( + controller: _blackListController.scrollController, + itemCount: loadingState.response.length, + itemBuilder: (BuildContext context, int index) { + return ListTile( + onTap: () {}, + leading: NetworkImgLayer( + width: 45, + height: 45, + type: 'avatar', + src: loadingState.response[index].face, + ), + title: Text( + loadingState.response[index].uname!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 14), + ), + subtitle: Text( + Utils.dateFormat(loadingState.response[index].mtime), + maxLines: 1, + style: + TextStyle(color: Theme.of(context).colorScheme.outline), + overflow: TextOverflow.ellipsis, + ), + dense: true, + trailing: TextButton( + onPressed: () => _blackListController + .removeBlack(loadingState.response[index].mid), + child: const Text('移除'), + ), + ); + }, + ) + : errorWidget( + callback: _blackListController.onReload, + ), + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _blackListController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } @@ -130,9 +131,7 @@ class BlackListController extends CommonController { List dataList = currentPage == 1 ? response.response.list : currentList + response.response.list; - loadingState.value = dataList.isNotEmpty - ? LoadingState.success(dataList) - : LoadingState.empty(); + loadingState.value = LoadingState.success(dataList); return true; } diff --git a/lib/pages/common/reply_controller.dart b/lib/pages/common/reply_controller.dart index 5acb2da1..9f4e9f8f 100644 --- a/lib/pages/common/reply_controller.dart +++ b/lib/pages/common/reply_controller.dart @@ -72,21 +72,21 @@ abstract class ReplyController extends CommonController { } } cursor = replies.cursor; - if (replies.replies.isNotEmpty) { - noMore.value = '加载中...'; - if (replies.cursor.isEnd) { - noMore.value = '没有更多了'; - } - } else { - // 未登录状态replies可能返回null - noMore.value = currentPage == 1 ? '还没有评论' : '没有更多了'; - } if (currentPage != 1) { List list = loadingState.value is Success ? (loadingState.value as Success).response.replies : []; replies.replies.insertAll(0, list); } + if (replies.replies.isNotEmpty) { + noMore.value = '加载中...'; + if (replies.cursor.isEnd || replies.replies.length >= count.value) { + noMore.value = '没有更多了'; + } + } else { + // 未登录状态replies可能返回null + noMore.value = currentPage == 1 ? '还没有评论' : '没有更多了'; + } loadingState.value = LoadingState.success(replies); return true; } diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index 2aeb67f4..482e5ff3 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -349,63 +349,68 @@ class _DynamicDetailPageState extends State } Widget replyList(LoadingState loadingState) { - return loadingState is Success - ? SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == loadingState.response.replies.length) { - return Container( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom), - height: MediaQuery.of(context).padding.bottom + 100, - child: Center( - child: Obx( - () => Text( - _dynamicDetailController.noMore.value, - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.outline, + return switch (loadingState) { + Loading() => SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + return const VideoReplySkeleton(); + }, + childCount: 8, + ), + ), + Success() => (loadingState.response.replies as List?)?.isNotEmpty == true + ? SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == loadingState.response.replies.length) { + return Container( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom), + height: MediaQuery.of(context).padding.bottom + 100, + child: Center( + child: Obx( + () => Text( + _dynamicDetailController.noMore.value, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), ), ), ), - ), - ); - } else { - return ReplyItemGrpc( - replyItem: loadingState.response.replies[index], - showReplyRow: true, - replyLevel: '1', - replyReply: replyReply, - replyType: ReplyType.values[replyType], - onReply: () { - _dynamicDetailController.onReply( - context, - replyItem: loadingState.response.replies[index], - index: index, - ); - }, - onDelete: _dynamicDetailController.onMDelete, - isTop: _dynamicDetailController.hasUpTop && index == 0, - upMid: loadingState.response.subjectControl.upMid, - ); - } - }, - childCount: loadingState.response.replies.length + 1, + ); + } else { + return ReplyItemGrpc( + replyItem: loadingState.response.replies[index], + showReplyRow: true, + replyLevel: '1', + replyReply: replyReply, + replyType: ReplyType.values[replyType], + onReply: () { + _dynamicDetailController.onReply( + context, + replyItem: loadingState.response.replies[index], + index: index, + ); + }, + onDelete: _dynamicDetailController.onMDelete, + isTop: _dynamicDetailController.hasUpTop && index == 0, + upMid: loadingState.response.subjectControl.upMid, + ); + } + }, + childCount: loadingState.response.replies.length + 1, + ), + ) + : HttpError( + callback: _dynamicDetailController.onReload, ), - ) - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: _dynamicDetailController.onReload, - ) - : SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - return const VideoReplySkeleton(); - }, - childCount: 8, - ), - ); + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _dynamicDetailController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/dynamics/tab/controller.dart b/lib/pages/dynamics/tab/controller.dart index 6f173325..25b9692d 100644 --- a/lib/pages/dynamics/tab/controller.dart +++ b/lib/pages/dynamics/tab/controller.dart @@ -55,11 +55,7 @@ class DynamicsTabController extends CommonController { if (res['status']) { List list = (loadingState.value as Success).response; list.removeWhere((item) => item.idStr == dynamicId); - if (list.isNotEmpty) { - loadingState.value = LoadingState.success(list); - } else { - loadingState.value = LoadingState.empty(); - } + loadingState.value = LoadingState.success(list); SmartDialog.showToast('删除成功'); } else { SmartDialog.showToast(res['msg']); diff --git a/lib/pages/dynamics/tab/view.dart b/lib/pages/dynamics/tab/view.dart index 22f70262..7e45eba9 100644 --- a/lib/pages/dynamics/tab/view.dart +++ b/lib/pages/dynamics/tab/view.dart @@ -10,7 +10,6 @@ import 'package:flutter/rendering.dart'; import 'package:get/get.dart'; import 'package:PiliPalaX/common/constants.dart'; import 'package:PiliPalaX/common/widgets/http_error.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import 'package:waterfall_flow/waterfall_flow.dart'; import '../../../common/skeleton/dynamic_card.dart'; @@ -146,71 +145,74 @@ class _DynamicsTabPageState extends State } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? dynamicsWaterfallFlow - ? SliverWaterfallFlow.extent( - maxCrossAxisExtent: Grid.maxRowWidth * 2, - //cacheExtent: 0.0, - crossAxisSpacing: StyleString.cardSpace / 2, - mainAxisSpacing: StyleString.cardSpace / 2, + return switch (loadingState) { + Loading() => skeleton(), + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? dynamicsWaterfallFlow + ? SliverWaterfallFlow.extent( + maxCrossAxisExtent: Grid.maxRowWidth * 2, + //cacheExtent: 0.0, + crossAxisSpacing: StyleString.cardSpace / 2, + mainAxisSpacing: StyleString.cardSpace / 2, - lastChildLayoutTypeBuilder: (index) => - index == loadingState.response.length - ? LastChildLayoutType.foot - : LastChildLayoutType.none, - children: [ - if (dynamicsController.tabController.index == 4 && - dynamicsController.mid.value != -1) ...[ - for (var i in loadingState.response) - DynamicPanel( - item: i, - onRemove: _dynamicsTabController.onRemove, - ), - ] else ...[ - for (var i in loadingState.response) - if (!dynamicsController.tempBannedList - .contains(i.modules?.moduleAuthor?.mid)) + lastChildLayoutTypeBuilder: (index) => + index == loadingState.response.length + ? LastChildLayoutType.foot + : LastChildLayoutType.none, + children: [ + if (dynamicsController.tabController.index == 4 && + dynamicsController.mid.value != -1) ...[ + for (var i in loadingState.response) DynamicPanel( item: i, onRemove: _dynamicsTabController.onRemove, ), - ] - ], - ) - : SliverCrossAxisGroup( - slivers: [ - const SliverFillRemaining(), - SliverConstrainedCrossAxis( - maxExtent: Grid.maxRowWidth * 2, - sliver: SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - if ((dynamicsController.tabController.index == 4 && - dynamicsController.mid.value != -1) || - !dynamicsController.tempBannedList.contains( - loadingState.response[index].modules - ?.moduleAuthor?.mid)) { - return DynamicPanel( - item: loadingState.response[index], - onRemove: _dynamicsTabController.onRemove, - ); - } - return const SizedBox(); - }, - childCount: loadingState.response.length, + ] else ...[ + for (var i in loadingState.response) + if (!dynamicsController.tempBannedList + .contains(i.modules?.moduleAuthor?.mid)) + DynamicPanel( + item: i, + onRemove: _dynamicsTabController.onRemove, + ), + ] + ], + ) + : SliverCrossAxisGroup( + slivers: [ + const SliverFillRemaining(), + SliverConstrainedCrossAxis( + maxExtent: Grid.maxRowWidth * 2, + sliver: SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + if ((dynamicsController.tabController.index == 4 && + dynamicsController.mid.value != -1) || + !dynamicsController.tempBannedList.contains( + loadingState.response[index].modules + ?.moduleAuthor?.mid)) { + return DynamicPanel( + item: loadingState.response[index], + onRemove: _dynamicsTabController.onRemove, + ); + } + return const SizedBox(); + }, + childCount: loadingState.response.length, + ), ), ), - ), - const SliverFillRemaining(), - ], - ) - : loadingState is Empty - ? const NoData() - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: _dynamicsTabController.onReload, - ) - : skeleton(); + const SliverFillRemaining(), + ], + ) + : HttpError( + callback: _dynamicsTabController.onReload, + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _dynamicsTabController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/dynamics/view.dart b/lib/pages/dynamics/view.dart index 924a378e..173d0579 100644 --- a/lib/pages/dynamics/view.dart +++ b/lib/pages/dynamics/view.dart @@ -15,6 +15,7 @@ import 'package:PiliPalaX/utils/feed_back.dart'; import 'package:PiliPalaX/utils/storage.dart'; import 'package:image_picker/image_picker.dart'; import 'package:intl/intl.dart'; +import 'package:nil/nil.dart'; import 'controller.dart'; import 'widgets/up_panel.dart'; @@ -98,7 +99,7 @@ class _DynamicsPageState extends State }); upPanelPosition = UpPanelPosition.values[setting.get( SettingBoxKey.upPanelPosition, - defaultValue: UpPanelPosition.leftFixed.code)]; + defaultValue: UpPanelPosition.leftFixed.index)]; debugPrint('upPanelPosition: $upPanelPosition'); if (GStorage.setting .get(SettingBoxKey.dynamicsShowAllFollowedUp, defaultValue: false)) { @@ -128,7 +129,7 @@ class _DynamicsPageState extends State padding: const EdgeInsets.symmetric(horizontal: 4), child: Container( //抽屉模式增加底色 - color: upPanelPosition.code > 1 + color: upPanelPosition.index > 1 ? Theme.of(context).colorScheme.surface : Colors.transparent, width: 56, @@ -137,20 +138,27 @@ class _DynamicsPageState extends State builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.data == null) { - return const SizedBox(); + return nil; } Map data = snapshot.data; if (data['status']) { return Obx(() => UpPanel(_dynamicsController.upData.value, _dynamicsController.scrollController)); } else { - return const SizedBox(); + return Center( + child: IconButton( + icon: Icon(Icons.refresh), + onPressed: () { + setState(() { + _futureBuilderFutureUp = + _dynamicsController.queryFollowUp(); + }); + }, + ), + ); } } else { - return const SizedBox( - width: 56, - child: UpPanelSkeleton(), - ); + return nil; } }, ), diff --git a/lib/pages/emote/view.dart b/lib/pages/emote/view.dart index a86f881a..3a20ee4e 100644 --- a/lib/pages/emote/view.dart +++ b/lib/pages/emote/view.dart @@ -1,3 +1,4 @@ +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/models/video/reply/emote.dart'; import 'package:flutter/material.dart'; @@ -28,90 +29,99 @@ class _EmotePanelState extends State } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? Column( - children: [ - Expanded( - child: TabBarView( - controller: _emotePanelController.tabController, - children: (loadingState.response as List).map( - (e) { - int size = e.emote!.first.meta!.size!; - int type = e.type!; - return Padding( - padding: const EdgeInsets.fromLTRB(12, 6, 12, 0), - child: GridView.builder( - gridDelegate: - SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: - type == 4 ? 100 : (size == 1 ? 40 : 60), - crossAxisSpacing: 8, - mainAxisSpacing: 8, - mainAxisExtent: size == 1 ? 40 : 60, - ), - itemCount: e.emote!.length, - itemBuilder: (context, index) { - return Material( - color: Colors.transparent, - child: InkWell( - borderRadius: BorderRadius.circular(8), - onTap: () { - widget.onChoose(e, e.emote![index]); - }, - child: Padding( - padding: const EdgeInsets.all(6), - child: type == 4 - ? Center( - child: Text( - e.emote![index].text!, - overflow: TextOverflow.clip, - maxLines: 1, + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? Column( + children: [ + Expanded( + child: TabBarView( + controller: _emotePanelController.tabController, + children: (loadingState.response as List).map( + (e) { + int size = e.emote!.first.meta!.size!; + int type = e.type!; + return Padding( + padding: const EdgeInsets.fromLTRB(12, 6, 12, 0), + child: GridView.builder( + gridDelegate: + SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: + type == 4 ? 100 : (size == 1 ? 40 : 60), + crossAxisSpacing: 8, + mainAxisSpacing: 8, + mainAxisExtent: size == 1 ? 40 : 60, + ), + itemCount: e.emote!.length, + itemBuilder: (context, index) { + return Material( + color: Colors.transparent, + child: InkWell( + borderRadius: BorderRadius.circular(8), + onTap: () { + widget.onChoose(e, e.emote![index]); + }, + child: Padding( + padding: const EdgeInsets.all(6), + child: type == 4 + ? Center( + child: Text( + e.emote![index].text!, + overflow: TextOverflow.clip, + maxLines: 1, + ), + ) + : NetworkImgLayer( + src: e.emote![index].url!, + width: size * 38, + height: size * 38, + semanticsLabel: + e.emote![index].text!, + type: 'emote', ), - ) - : NetworkImgLayer( - src: e.emote![index].url!, - width: size * 38, - height: size * 38, - semanticsLabel: e.emote![index].text!, - type: 'emote', - ), + ), ), - ), - ); - }, - ), - ); - }, - ).toList(), + ); + }, + ), + ); + }, + ).toList(), + ), ), - ), - Divider( - height: 1, - color: Theme.of(context).dividerColor.withOpacity(0.1), - ), - TabBar( - controller: _emotePanelController.tabController, - dividerColor: Colors.transparent, - isScrollable: true, - tabs: (loadingState.response as List) - .map( - (e) => Padding( - padding: const EdgeInsets.all(8), - child: NetworkImgLayer( - width: 24, - height: 24, - type: 'emote', - src: e.url, + Divider( + height: 1, + color: Theme.of(context).dividerColor.withOpacity(0.1), + ), + TabBar( + controller: _emotePanelController.tabController, + dividerColor: Colors.transparent, + isScrollable: true, + tabs: (loadingState.response as List) + .map( + (e) => Padding( + padding: const EdgeInsets.all(8), + child: NetworkImgLayer( + width: 24, + height: 24, + type: 'emote', + src: e.url, + ), ), - ), - ) - .toList(), - ), - SizedBox(height: MediaQuery.of(context).padding.bottom), - ], - ) - : loadingState is Error - ? Center(child: Text(loadingState.errMsg)) - : const Center(child: Text('加载中...')); + ) + .toList(), + ), + SizedBox(height: MediaQuery.of(context).padding.bottom), + ], + ) + : errorWidget( + callback: _emotePanelController.onReload, + ), + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _emotePanelController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/fan/view.dart b/lib/pages/fan/view.dart index da4ae7ec..a996bda1 100644 --- a/lib/pages/fan/view.dart +++ b/lib/pages/fan/view.dart @@ -4,7 +4,6 @@ import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPalaX/common/widgets/http_error.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import '../../common/constants.dart'; import '../../utils/grid.dart'; @@ -67,33 +66,32 @@ class _FansPageState extends State { } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? loadingState.response.isNotEmpty - ? SliverGrid( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - mainAxisExtent: 56), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return fanItem(item: loadingState.response[index]); - }, - childCount: loadingState.response.length, - )) - : const NoData() - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: _fansController.onReload, - ) - : const SliverToBoxAdapter( - child: SizedBox( - height: 200, - child: Center( - child: CircularProgressIndicator(), - ), - ), - ); + return switch (loadingState) { + Loading() => HttpError( + callback: _fansController.onReload, + ), + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? SliverGrid( + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + mainAxisSpacing: StyleString.cardSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + mainAxisExtent: 56), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return fanItem(item: loadingState.response[index]); + }, + childCount: loadingState.response.length, + ), + ) + : HttpError( + callback: _fansController.onReload, + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _fansController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/fav/view.dart b/lib/pages/fav/view.dart index 1ee01ffb..3ce9272b 100644 --- a/lib/pages/fav/view.dart +++ b/lib/pages/fav/view.dart @@ -108,63 +108,68 @@ class _FavPageState extends State { } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0), - delegate: SliverChildBuilderDelegate( - childCount: loadingState.response.length, - (BuildContext context, int index) { - String heroTag = - Utils.makeHeroTag(loadingState.response[index].fid); - return FavItem( - heroTag: heroTag, - favFolderItem: loadingState.response[index], - onTap: () { - Get.toNamed( - '/favDetail', - arguments: loadingState.response[index], - parameters: { - 'heroTag': heroTag, - 'mediaId': loadingState.response[index].id.toString(), - }, - )?.then((res) { - if (res == true) { - List list = - (_favController.loadingState.value as Success) - .response; - list.removeAt(index); - _favController.loadingState.value = - LoadingState.success(list); - } - }); - }, - ); - }, + return switch (loadingState) { + Loading() => SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.cardSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0), + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + return const VideoCardHSkeleton(); + }, + childCount: 10, + ), + ), + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.cardSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0), + delegate: SliverChildBuilderDelegate( + childCount: loadingState.response.length, + (BuildContext context, int index) { + String heroTag = + Utils.makeHeroTag(loadingState.response[index].fid); + return FavItem( + heroTag: heroTag, + favFolderItem: loadingState.response[index], + onTap: () { + Get.toNamed( + '/favDetail', + arguments: loadingState.response[index], + parameters: { + 'heroTag': heroTag, + 'mediaId': loadingState.response[index].id.toString(), + }, + )?.then((res) { + if (res == true) { + List list = + (_favController.loadingState.value as Success) + .response; + list.removeAt(index); + _favController.loadingState.value = + LoadingState.success(list); + } + }); + }, + ); + }, + ), + ) + : HttpError( + callback: _favController.onReload, ), - ) - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: _favController.onReload, - ) - : SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0), - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return const VideoCardHSkeleton(); - }, - childCount: 10, - ), - ); + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _favController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index 77f59b7f..27043b1c 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -238,52 +238,27 @@ class _FavDetailPageState extends State { } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? loadingState.response.isEmpty - ? const SliverToBoxAdapter(child: SizedBox()) - : SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom), - sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0, - ), - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == loadingState.response.length) { - return Container( - height: 60, - alignment: Alignment.center, - child: Obx( - () => Text( - _favDetailController.loadingText.value, - style: TextStyle( - color: Theme.of(context).colorScheme.outline, - fontSize: 13), - ), - ), - ); - } - return FavVideoCardH( - videoItem: loadingState.response[index], - callFn: () => _favDetailController - .onCancelFav(loadingState.response[index].id), - ); - }, - childCount: loadingState.response.length + 1, - ), - ), - ) - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: _favDetailController.onReload, - ) - : SliverGrid( + return switch (loadingState) { + Loading() => SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.cardSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0, + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + return const VideoCardHSkeleton(); + }, + childCount: 10, + ), + ), + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom), + sliver: SliverGrid( gridDelegate: SliverGridDelegateWithExtentAndRatio( mainAxisSpacing: StyleString.cardSpace, crossAxisSpacing: StyleString.safeSpace, @@ -293,10 +268,38 @@ class _FavDetailPageState extends State { ), delegate: SliverChildBuilderDelegate( (context, index) { - return const VideoCardHSkeleton(); + if (index == loadingState.response.length) { + return Container( + height: 60, + alignment: Alignment.center, + child: Obx( + () => Text( + _favDetailController.loadingText.value, + style: TextStyle( + color: Theme.of(context).colorScheme.outline, + fontSize: 13), + ), + ), + ); + } + return FavVideoCardH( + videoItem: loadingState.response[index], + callFn: () => _favDetailController + .onCancelFav(loadingState.response[index].id), + ); }, - childCount: 10, + childCount: loadingState.response.length + 1, ), - ); + ), + ) + : HttpError( + callback: _favDetailController.onReload, + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _favDetailController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/fav_search/view.dart b/lib/pages/fav_search/view.dart index f8b19b00..9506ecdf 100644 --- a/lib/pages/fav_search/view.dart +++ b/lib/pages/fav_search/view.dart @@ -1,5 +1,5 @@ import 'package:PiliPalaX/common/constants.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/follow/widgets/follow_item.dart'; import 'package:PiliPalaX/pages/history/widgets/item.dart'; @@ -7,7 +7,6 @@ import 'package:PiliPalaX/utils/grid.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import 'package:PiliPalaX/pages/fav_detail/widget/fav_video_card.dart'; import 'controller.dart'; @@ -83,88 +82,76 @@ class _FavSearchPageState extends State { } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? loadingState.response.isEmpty - ? CustomScrollView( - slivers: [ - HttpError( - errMsg: '没有数据', - fn: _favSearchCtr.onReload, - ), - ], - ) - : _favSearchCtr.searchType == SearchType.fav - ? ListView.builder( - controller: _favSearchCtr.scrollController, - itemCount: loadingState.response.length + 1, - itemBuilder: (context, index) { - if (index == loadingState.response.length) { - return Container( - height: MediaQuery.of(context).padding.bottom + 60, - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom, - ), + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? _favSearchCtr.searchType == SearchType.fav + ? ListView.builder( + controller: _favSearchCtr.scrollController, + itemCount: loadingState.response.length + 1, + itemBuilder: (context, index) { + if (index == loadingState.response.length) { + return Container( + height: MediaQuery.of(context).padding.bottom + 60, + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom, + ), + ); + } else { + return FavVideoCardH( + videoItem: loadingState.response[index], + searchType: _favSearchCtr.type, + callFn: () => _favSearchCtr.type != 1 + ? _favSearchCtr + .onCancelFav(loadingState.response[index].id!) + : {}, + ); + } + }, + ) + : _favSearchCtr.searchType == SearchType.follow + ? ListView.builder( + controller: _favSearchCtr.scrollController, + itemCount: loadingState.response.length, + itemBuilder: ((context, index) { + return FollowItem( + item: loadingState.response[index], ); - } else { - return FavVideoCardH( - videoItem: loadingState.response[index], - searchType: _favSearchCtr.type, - callFn: () => _favSearchCtr.type != 1 - ? _favSearchCtr - .onCancelFav(loadingState.response[index].id!) - : {}, - ); - } - }, - ) - : _favSearchCtr.searchType == SearchType.follow - ? ListView.builder( - controller: _favSearchCtr.scrollController, - itemCount: loadingState.response.length, - itemBuilder: ((context, index) { - return FollowItem( - item: loadingState.response[index], - ); - }), - ) - : CustomScrollView( - physics: const AlwaysScrollableScrollPhysics(), - controller: _favSearchCtr.scrollController, - slivers: [ - SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0), - delegate: SliverChildBuilderDelegate( - (context, index) { - return HistoryItem( - videoItem: loadingState.response[index], - ctr: _favSearchCtr, - onChoose: null, - onUpdateMultiple: () => null, - ); - }, - childCount: loadingState.response.length, - ), + }), + ) + : CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + controller: _favSearchCtr.scrollController, + slivers: [ + SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.cardSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0), + delegate: SliverChildBuilderDelegate( + (context, index) { + return HistoryItem( + videoItem: loadingState.response[index], + ctr: _favSearchCtr, + onChoose: null, + onUpdateMultiple: () => null, + ); + }, + childCount: loadingState.response.length, ), - ], - ) - : loadingState is Error - ? CustomScrollView( - slivers: [ - HttpError( - errMsg: loadingState.errMsg, - fn: _favSearchCtr.onReload, - ), - ], - ) - : const CustomScrollView( - slivers: [ - NoData(), - ], - ); + ), + ], + ) + : errorWidget( + callback: _favSearchCtr.onReload, + ), + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _favSearchCtr.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/follow/widgets/follow_list.dart b/lib/pages/follow/widgets/follow_list.dart index ff617792..30c66064 100644 --- a/lib/pages/follow/widgets/follow_list.dart +++ b/lib/pages/follow/widgets/follow_list.dart @@ -1,9 +1,8 @@ +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import 'package:PiliPalaX/models/follow/result.dart'; import 'package:PiliPalaX/pages/follow/index.dart'; @@ -92,16 +91,14 @@ class _FollowListState extends State { } }, ) - : const CustomScrollView(slivers: [NoData()]), + : errorWidget( + callback: () => widget.ctr.queryFollowings('init'), + ), ); } else { - return CustomScrollView( - slivers: [ - HttpError( - errMsg: data['msg'], - fn: () => widget.ctr.queryFollowings('init'), - ) - ], + return errorWidget( + errMsg: data['msg'], + callback: () => widget.ctr.queryFollowings('init'), ); } } else { diff --git a/lib/pages/follow/widgets/owner_follow_list.dart b/lib/pages/follow/widgets/owner_follow_list.dart index 464a81e1..7a094572 100644 --- a/lib/pages/follow/widgets/owner_follow_list.dart +++ b/lib/pages/follow/widgets/owner_follow_list.dart @@ -1,9 +1,8 @@ +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import 'package:PiliPalaX/http/member.dart'; import 'package:PiliPalaX/models/follow/result.dart'; import 'package:PiliPalaX/models/member/tags.dart'; @@ -110,16 +109,14 @@ class _OwnerFollowListState extends State } }, ) - : const CustomScrollView(slivers: [NoData()]), + : errorWidget( + callback: () => widget.ctr.queryFollowings('init'), + ), ); } else { - return CustomScrollView( - slivers: [ - HttpError( - errMsg: data['msg'], - fn: () => widget.ctr.queryFollowings('init'), - ) - ], + return errorWidget( + errMsg: data['msg'], + callback: () => widget.ctr.queryFollowings('init'), ); } } else { diff --git a/lib/pages/history/view.dart b/lib/pages/history/view.dart index 7a634f26..7651474d 100644 --- a/lib/pages/history/view.dart +++ b/lib/pages/history/view.dart @@ -1,11 +1,10 @@ +import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; import 'package:PiliPalaX/pages/fav_search/view.dart' show SearchType; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPalaX/common/skeleton/video_card_h.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import 'package:PiliPalaX/pages/history/index.dart'; import '../../common/constants.dart'; @@ -215,12 +214,20 @@ class _HistoryPageState extends State { ? const SliverToBoxAdapter( child: Center(child: Text('加载中')), ) - : const NoData(), + : HttpError( + callback: () => setState(() { + _futureBuilderFuture = + _historyController.queryHistoryList(); + }), + ), ); } else { return HttpError( errMsg: data['msg'], - fn: () => setState(() {}), + callback: () => setState(() { + _futureBuilderFuture = + _historyController.queryHistoryList(); + }), ); } } else { diff --git a/lib/pages/hot/view.dart b/lib/pages/hot/view.dart index a131a6d5..04993f5e 100644 --- a/lib/pages/hot/view.dart +++ b/lib/pages/hot/view.dart @@ -91,7 +91,7 @@ class _HotPageState extends State with AutomaticKeepAliveClientMixin { ? (_hotController.loadingState.value as Error) .errMsg : '没有相关数据', - fn: _hotController.onReload, + callback: _hotController.onReload, ), ), ), diff --git a/lib/pages/html/view.dart b/lib/pages/html/view.dart index ae9c6aca..838a9635 100644 --- a/lib/pages/html/view.dart +++ b/lib/pages/html/view.dart @@ -320,59 +320,64 @@ class _HtmlRenderPageState extends State } Widget replyList(LoadingState loadingState) { - return loadingState is Success - ? SliverList.builder( - itemCount: loadingState.response.replies.length + 1, - itemBuilder: (context, index) { - if (index == loadingState.response.replies.length) { - return Container( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom), - height: MediaQuery.of(context).padding.bottom + 100, - child: Center( - child: Obx( - () => Text( - _htmlRenderCtr.noMore.value, - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.outline, + return switch (loadingState) { + Loading() => SliverList.builder( + itemCount: 5, + itemBuilder: (context, index) { + return const VideoReplySkeleton(); + }, + ), + Success() => (loadingState.response.replies as List?)?.isNotEmpty == true + ? SliverList.builder( + itemCount: loadingState.response.replies.length + 1, + itemBuilder: (context, index) { + if (index == loadingState.response.replies.length) { + return Container( + padding: EdgeInsets.only( + bottom: MediaQuery.of(context).padding.bottom), + height: MediaQuery.of(context).padding.bottom + 100, + child: Center( + child: Obx( + () => Text( + _htmlRenderCtr.noMore.value, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), ), ), ), - ), - ); - } else { - return ReplyItemGrpc( - replyItem: loadingState.response.replies[index], - showReplyRow: true, - replyLevel: '1', - replyReply: replyReply, - replyType: ReplyType.values[type], - onReply: () { - _htmlRenderCtr.onReply( - context, - replyItem: loadingState.response.replies[index], - index: index, - ); - }, - onDelete: _htmlRenderCtr.onMDelete, - isTop: _htmlRenderCtr.hasUpTop && index == 0, - upMid: loadingState.response.subjectControl.upMid, - ); - } - }, - ) - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: _htmlRenderCtr.onReload, - ) - : SliverList.builder( - itemCount: 5, - itemBuilder: (context, index) { - return const VideoReplySkeleton(); - }, - ); + ); + } else { + return ReplyItemGrpc( + replyItem: loadingState.response.replies[index], + showReplyRow: true, + replyLevel: '1', + replyReply: replyReply, + replyType: ReplyType.values[type], + onReply: () { + _htmlRenderCtr.onReply( + context, + replyItem: loadingState.response.replies[index], + index: index, + ); + }, + onDelete: _htmlRenderCtr.onMDelete, + isTop: _htmlRenderCtr.hasUpTop && index == 0, + upMid: loadingState.response.subjectControl.upMid, + ); + } + }, + ) + : HttpError( + callback: _htmlRenderCtr.onReload, + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _htmlRenderCtr.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } Container replyHeader() { diff --git a/lib/pages/later/controller.dart b/lib/pages/later/controller.dart index 513c3522..8ad21154 100644 --- a/lib/pages/later/controller.dart +++ b/lib/pages/later/controller.dart @@ -88,7 +88,7 @@ class LaterController extends CommonController { onPressed: () async { var res = await UserHttp.toViewClear(); if (res['status']) { - loadingState.value = LoadingState.empty(); + loadingState.value = LoadingState.success([]); } Get.back(); SmartDialog.showToast(res['msg']); diff --git a/lib/pages/later/view.dart b/lib/pages/later/view.dart index a2486412..b5356669 100644 --- a/lib/pages/later/view.dart +++ b/lib/pages/later/view.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPalaX/common/skeleton/video_card_h.dart'; import 'package:PiliPalaX/common/widgets/http_error.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import 'package:PiliPalaX/common/widgets/video_card_h.dart'; import 'package:PiliPalaX/pages/later/index.dart'; @@ -74,48 +73,51 @@ class _LaterPageState extends State { } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0, + return switch (loadingState) { + Loading() => SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.safeSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0, + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + return const VideoCardHSkeleton(); + }, + childCount: 10, + ), + ), + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.safeSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0, + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + var videoItem = loadingState.response[index]; + return VideoCardH( + videoItem: videoItem, + source: 'later', + longPress: () => _laterController.toViewDel(context, + aid: videoItem.aid)); + }, + childCount: loadingState.response.length, + ), + ) + : HttpError( + callback: _laterController.onReload, ), - delegate: SliverChildBuilderDelegate( - (context, index) { - var videoItem = loadingState.response[index]; - return VideoCardH( - videoItem: videoItem, - source: 'later', - longPress: () => _laterController.toViewDel(context, - aid: videoItem.aid)); - }, - childCount: loadingState.response.length, - ), - ) - : loadingState is Empty - ? const NoData() - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: _laterController.onReload, - ) - : SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0, - ), - delegate: SliverChildBuilderDelegate( - (context, index) { - return const VideoCardHSkeleton(); - }, - childCount: 10, - ), - ); + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _laterController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/member/new/content/member_contribute/content/article/member_article.dart b/lib/pages/member/new/content/member_contribute/content/article/member_article.dart index ce86b11e..263f8f2e 100644 --- a/lib/pages/member/new/content/member_contribute/content/article/member_article.dart +++ b/lib/pages/member/new/content/member_contribute/content/article/member_article.dart @@ -1,6 +1,6 @@ import 'package:PiliPalaX/common/constants.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/models/space_article/item.dart'; @@ -40,79 +40,75 @@ class _MemberArticleState extends State } _buildBody(LoadingState loadingState) { - return loadingState is Success - ? MediaQuery.removePadding( - context: context, - removeTop: true, - child: refreshIndicator( - onRefresh: () async { - await _controller.onRefresh(); - }, - child: ListView.separated( - itemCount: loadingState.response.length, - itemBuilder: (_, index) { - if (index == loadingState.response.length - 1) { - _controller.onLoadMore(); - } - Item item = loadingState.response[index]; - return ListTile( - dense: true, - onTap: () { - PiliScheme.routePush(Uri.parse(item.uri ?? '')); - }, - leading: item.originImageUrls?.isNotEmpty == true - ? Container( - margin: const EdgeInsets.symmetric(vertical: 6), - child: LayoutBuilder( - builder: (_, constraints) { - return NetworkImgLayer( - radius: 6, - src: item.originImageUrls!.first, - width: constraints.maxHeight * - StyleString.aspectRatio, - height: constraints.maxHeight, - ); - }, - ), - ) - : null, - title: Text( - item.title ?? '', - style: TextStyle( - fontSize: 15, - ), - ), - subtitle: item.summary?.isNotEmpty == true - ? Text( - item.summary!, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 13, - color: Theme.of(context).colorScheme.outline, - ), - ) - : null, - ); + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? MediaQuery.removePadding( + context: context, + removeTop: true, + child: refreshIndicator( + onRefresh: () async { + await _controller.onRefresh(); }, - separatorBuilder: (_, index) => Divider(height: 1), - ), - ), - ) - : loadingState is Error - ? Center( - child: CustomScrollView( - shrinkWrap: true, - slivers: [ - HttpError( - errMsg: loadingState.errMsg, - fn: _controller.onReload, - ), - ], + child: ListView.separated( + itemCount: loadingState.response.length, + itemBuilder: (_, index) { + if (index == loadingState.response.length - 1) { + _controller.onLoadMore(); + } + Item item = loadingState.response[index]; + return ListTile( + dense: true, + onTap: () { + PiliScheme.routePush(Uri.parse(item.uri ?? '')); + }, + leading: item.originImageUrls?.isNotEmpty == true + ? Container( + margin: const EdgeInsets.symmetric(vertical: 6), + child: LayoutBuilder( + builder: (_, constraints) { + return NetworkImgLayer( + radius: 6, + src: item.originImageUrls!.first, + width: constraints.maxHeight * + StyleString.aspectRatio, + height: constraints.maxHeight, + ); + }, + ), + ) + : null, + title: Text( + item.title ?? '', + style: TextStyle( + fontSize: 15, + ), + ), + subtitle: item.summary?.isNotEmpty == true + ? Text( + item.summary!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.outline, + ), + ) + : null, + ); + }, + separatorBuilder: (_, index) => Divider(height: 1), ), - ) - : Center( - child: CircularProgressIndicator(), - ); + ), + ) + : errorWidget( + callback: _controller.onReload, + ), + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _controller.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart b/lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart index 0490be6d..b5d48e7c 100644 --- a/lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart +++ b/lib/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart @@ -1,6 +1,6 @@ import 'package:PiliPalaX/common/constants.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/bangumi/widgets/bangumi_card_v_member_home.dart'; import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/bangumi/member_bangumi_ctr.dart'; @@ -42,60 +42,56 @@ class _MemberBangumiState extends State } _buildBody(LoadingState loadingState) { - return loadingState is Success - ? refreshIndicator( - onRefresh: () async { - await _controller.onRefresh(); - }, - child: CustomScrollView( - slivers: [ - SliverPadding( - padding: EdgeInsets.only( - left: StyleString.safeSpace, - right: StyleString.safeSpace, - top: StyleString.safeSpace, - bottom: StyleString.safeSpace + - MediaQuery.of(context).padding.bottom, - ), - sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace - 2, - crossAxisSpacing: StyleString.cardSpace, - maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2, - childAspectRatio: 0.65, - mainAxisExtent: - MediaQuery.textScalerOf(context).scale(60), + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? refreshIndicator( + onRefresh: () async { + await _controller.onRefresh(); + }, + child: CustomScrollView( + slivers: [ + SliverPadding( + padding: EdgeInsets.only( + left: StyleString.safeSpace, + right: StyleString.safeSpace, + top: StyleString.safeSpace, + bottom: StyleString.safeSpace + + MediaQuery.of(context).padding.bottom, ), - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == loadingState.response.length - 1) { - _controller.onLoadMore(); - } - return BangumiCardVMemberHome( - bangumiItem: loadingState.response[index], - ); - }, - childCount: loadingState.response.length, + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.cardSpace - 2, + crossAxisSpacing: StyleString.cardSpace, + maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2, + childAspectRatio: 0.65, + mainAxisExtent: + MediaQuery.textScalerOf(context).scale(60), + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == loadingState.response.length - 1) { + _controller.onLoadMore(); + } + return BangumiCardVMemberHome( + bangumiItem: loadingState.response[index], + ); + }, + childCount: loadingState.response.length, + ), ), ), - ), - ], + ], + ), + ) + : errorWidget( + callback: _controller.onReload, ), - ) - : loadingState is Error - ? Center( - child: CustomScrollView( - shrinkWrap: true, - slivers: [ - HttpError( - errMsg: loadingState.errMsg, - fn: _controller.onReload, - ), - ], - ), - ) - : Center( - child: CircularProgressIndicator(), - ); + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _controller.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart b/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart index 1066bbc0..a1531e75 100644 --- a/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart +++ b/lib/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart @@ -1,7 +1,7 @@ import 'package:PiliPalaX/common/constants.dart'; import 'package:PiliPalaX/common/widgets/badge.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/models/space_fav/datum.dart'; @@ -44,54 +44,50 @@ class _MemberFavoriteState extends State } _buildBody(LoadingState loadingState) { - return loadingState is Success - ? refreshIndicator( - onRefresh: () async { - await _controller.onRefresh(); - }, - child: CustomScrollView( - slivers: [ - SliverToBoxAdapter( - child: Obx( - () => _controller.first.value.mediaListResponse?.list - ?.isNotEmpty == - true - ? _buildItem(_controller.first.value, true) - : const SizedBox.shrink(), - ), - ), - SliverToBoxAdapter( - child: Obx( - () => _controller.second.value.mediaListResponse?.list - ?.isNotEmpty == - true - ? _buildItem(_controller.second.value, false) - : const SizedBox.shrink(), - ), - ), - SliverToBoxAdapter( - child: SizedBox( - height: 12 + MediaQuery.of(context).padding.bottom, - ), - ) - ], - ), - ) - : loadingState is Error - ? Center( - child: CustomScrollView( - shrinkWrap: true, - slivers: [ - HttpError( - errMsg: loadingState.errMsg, - fn: _controller.onReload, + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? refreshIndicator( + onRefresh: () async { + await _controller.onRefresh(); + }, + child: CustomScrollView( + slivers: [ + SliverToBoxAdapter( + child: Obx( + () => _controller.first.value.mediaListResponse?.list + ?.isNotEmpty == + true + ? _buildItem(_controller.first.value, true) + : const SizedBox.shrink(), ), - ], - ), - ) - : Center( - child: CircularProgressIndicator(), - ); + ), + SliverToBoxAdapter( + child: Obx( + () => _controller.second.value.mediaListResponse?.list + ?.isNotEmpty == + true + ? _buildItem(_controller.second.value, false) + : const SizedBox.shrink(), + ), + ), + SliverToBoxAdapter( + child: SizedBox( + height: 12 + MediaQuery.of(context).padding.bottom, + ), + ) + ], + ), + ) + : errorWidget( + callback: _controller.onReload, + ), + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _controller.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } _buildItem(Datum data, bool isFirst) { diff --git a/lib/pages/member/new/content/member_contribute/content/video/member_video.dart b/lib/pages/member/new/content/member_contribute/content/video/member_video.dart index f59cc9da..009de1ca 100644 --- a/lib/pages/member/new/content/member_contribute/content/video/member_video.dart +++ b/lib/pages/member/new/content/member_contribute/content/video/member_video.dart @@ -1,6 +1,6 @@ import 'package:PiliPalaX/common/constants.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/common/widgets/video_card_h_member_video.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/video/member_video_ctr.dart'; @@ -54,106 +54,100 @@ class _MemberVideoState extends State } _buildBody(LoadingState loadingState) { - return loadingState is Success && loadingState.response is List - ? refreshIndicator( - onRefresh: () async { - await _controller.onRefresh(); - }, - child: CustomScrollView( - slivers: [ - SliverPersistentHeader( - pinned: false, - floating: true, - delegate: MySliverPersistentHeaderDelegate( - child: Container( - height: 40, - padding: const EdgeInsets.fromLTRB(12, 0, 6, 0), - color: Theme.of(context).colorScheme.surface, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Obx( - () => Text( - _controller.count.value != -1 - ? '共${_controller.count.value}视频' - : '', - style: const TextStyle(fontSize: 13), - ), - ), - SizedBox( - height: 35, - child: TextButton.icon( - onPressed: _controller.queryBySort, - icon: const Icon(Icons.sort, size: 16), - label: Obx( - () => Text( - widget.type == ContributeType.video - ? _controller.order.value == 'pubdate' - ? '最新发布' - : '最多播放' - : _controller.sort.value == 'desc' - ? '默认' - : '倒序', - style: const TextStyle(fontSize: 13), - ), + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? refreshIndicator( + onRefresh: () async { + await _controller.onRefresh(); + }, + child: CustomScrollView( + slivers: [ + SliverPersistentHeader( + pinned: false, + floating: true, + delegate: MySliverPersistentHeaderDelegate( + child: Container( + height: 40, + padding: const EdgeInsets.fromLTRB(12, 0, 6, 0), + color: Theme.of(context).colorScheme.surface, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Obx( + () => Text( + _controller.count.value != -1 + ? '共${_controller.count.value}视频' + : '', + style: const TextStyle(fontSize: 13), ), ), - ) - ], + SizedBox( + height: 35, + child: TextButton.icon( + onPressed: _controller.queryBySort, + icon: const Icon(Icons.sort, size: 16), + label: Obx( + () => Text( + widget.type == ContributeType.video + ? _controller.order.value == 'pubdate' + ? '最新发布' + : '最多播放' + : _controller.sort.value == 'desc' + ? '默认' + : '倒序', + style: const TextStyle(fontSize: 13), + ), + ), + ), + ) + ], + ), ), ), ), - ), - SliverPadding( - // 单列布局 EdgeInsets.zero - padding: EdgeInsets.fromLTRB( - StyleString.safeSpace, - StyleString.safeSpace - 5, - StyleString.safeSpace, - MediaQuery.of(context).padding.bottom + 10, - ), - sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0, + SliverPadding( + // 单列布局 EdgeInsets.zero + padding: EdgeInsets.fromLTRB( + StyleString.safeSpace, + StyleString.safeSpace - 5, + StyleString.safeSpace, + MediaQuery.of(context).padding.bottom + 10, ), - delegate: SliverChildBuilderDelegate( - (context, index) { - if (widget.type != ContributeType.season && - index == loadingState.response.length - 1) { - _controller.onLoadMore(); - } - return VideoCardHMemberVideo( - videoItem: loadingState.response[index], - showPubdate: true, - ); - }, - childCount: loadingState.response.length, + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.safeSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0, + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + if (widget.type != ContributeType.season && + index == loadingState.response.length - 1) { + _controller.onLoadMore(); + } + return VideoCardHMemberVideo( + videoItem: loadingState.response[index], + showPubdate: true, + ); + }, + childCount: loadingState.response.length, + ), ), ), - ), - ], + ], + ), + ) + : errorWidget( + callback: _controller.onReload, ), - ) - : loadingState is Loading - ? Center( - child: CircularProgressIndicator(), - ) - : Center( - child: CustomScrollView( - shrinkWrap: true, - slivers: [ - HttpError( - errMsg: loadingState is Error - ? (loadingState as Error?)?.errMsg - : 'EMPTY', - fn: _controller.onReload, - ), - ], - ), - ); + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _controller.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/member/new/content/member_dynamic/member_dynamic.dart b/lib/pages/member/new/content/member_dynamic/member_dynamic.dart index 55575288..adbfd557 100644 --- a/lib/pages/member/new/content/member_dynamic/member_dynamic.dart +++ b/lib/pages/member/new/content/member_dynamic/member_dynamic.dart @@ -1,5 +1,5 @@ +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/dynamics/widgets/dynamic_panel_grpc.dart'; import 'package:PiliPalaX/pages/member/new/content/member_dynamic/member_dynamic_ctr.dart'; @@ -32,38 +32,34 @@ class _MemberDynamicState extends State } _buildBody(LoadingState loadingState) { - return loadingState is Success - ? refreshIndicator( - onRefresh: () async { - await _controller.onRefresh(); - }, - child: ListView.separated( - itemCount: loadingState.response.length, - itemBuilder: (_, index) { - if (index == loadingState.response.length - 1) { - _controller.onLoadMore(); - } - return DynamicPanelGrpc( - item: loadingState.response[index], - ); + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? refreshIndicator( + onRefresh: () async { + await _controller.onRefresh(); }, - separatorBuilder: (_, index) => const SizedBox(height: 10), + child: ListView.separated( + itemCount: loadingState.response.length, + itemBuilder: (_, index) { + if (index == loadingState.response.length - 1) { + _controller.onLoadMore(); + } + return DynamicPanelGrpc( + item: loadingState.response[index], + ); + }, + separatorBuilder: (_, index) => const SizedBox(height: 10), + ), + ) + : errorWidget( + callback: _controller.onReload, ), - ) - : loadingState is Error - ? Center( - child: CustomScrollView( - shrinkWrap: true, - slivers: [ - HttpError( - errMsg: loadingState.errMsg, - fn: _controller.onReload, - ), - ], - ), - ) - : Center( - child: CircularProgressIndicator(), - ); + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _controller.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/member/new/content/member_home/member_home.dart b/lib/pages/member/new/content/member_home/member_home.dart index 89435fe6..ed05ff1a 100644 --- a/lib/pages/member/new/content/member_home/member_home.dart +++ b/lib/pages/member/new/content/member_home/member_home.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:PiliPalaX/common/constants.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/common/widgets/video_card_v_member_home.dart'; import 'package:PiliPalaX/http/loading_state.dart'; @@ -39,171 +40,183 @@ class _MemberHomeState extends State } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success && loadingState.response is Data - ? CustomScrollView( - slivers: [ - if (loadingState.response?.archive?.item?.isNotEmpty == true) ...[ - _videoHeader( - title: '视频', - param: 'contribute', - param1: 'video', - count: loadingState.response.archive.count, - ), - SliverPadding( - padding: const EdgeInsets.symmetric( - horizontal: StyleString.safeSpace, + return switch (loadingState) { + Loading() => loadingWidget, + Success() => loadingState.response is Data + ? CustomScrollView( + slivers: [ + if (loadingState.response?.archive?.item?.isNotEmpty == + true) ...[ + _videoHeader( + title: '视频', + param: 'contribute', + param1: 'video', + count: loadingState.response.archive.count, ), - sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace, - crossAxisSpacing: StyleString.cardSpace, - maxCrossAxisExtent: Grid.maxRowWidth, - childAspectRatio: StyleString.aspectRatio, - mainAxisExtent: - MediaQuery.textScalerOf(context).scale(90), + SliverPadding( + padding: const EdgeInsets.symmetric( + horizontal: StyleString.safeSpace, ), - delegate: SliverChildBuilderDelegate( - (context, index) { - return VideoCardVMemberHome( - videoItem: loadingState.response.archive.item[index], - ); - }, - childCount: - min(4, loadingState.response.archive.item.length), - ), - ), - ), - ], - if (loadingState.response?.favourite2?.item?.isNotEmpty == - true) ...[ - _videoHeader( - title: '收藏', - param: 'favorite', - count: loadingState.response.favourite2.count, - ), - // TODO - ], - if (loadingState.response?.coinArchive?.item?.isNotEmpty == - true) ...[ - _videoHeader( - title: '最近投币的视频', - param: 'coinArchive', - count: loadingState.response.coinArchive.count, - ), - // TODO - ], - if (loadingState.response?.likeArchive?.item?.isNotEmpty == - true) ...[ - _videoHeader( - title: '最近点赞的视频', - param: 'likeArchive', - count: loadingState.response.likeArchive.count, - ), - // TODO - ], - if (loadingState.response?.article?.item?.isNotEmpty == true) ...[ - _videoHeader( - title: '专栏', - param: 'contribute', - param1: 'article', - count: loadingState.response.article.count, - ), - SliverToBoxAdapter( - child: ListTile( - dense: true, - onTap: () { - PiliScheme.routePush(Uri.parse( - loadingState.response.article.item.first.uri ?? '')); - }, - leading: loadingState.response.article.item.first - .originImageUrls?.isNotEmpty == - true - ? Container( - margin: const EdgeInsets.symmetric(vertical: 6), - child: LayoutBuilder( - builder: (_, constraints) { - return NetworkImgLayer( - radius: 6, - src: loadingState.response.article.item.first - .originImageUrls!.first, - width: constraints.maxHeight * - StyleString.aspectRatio, - height: constraints.maxHeight, - ); - }, - ), - ) - : null, - title: Text( - loadingState.response.article.item.first.title ?? '', - style: TextStyle( - fontSize: 15, + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.cardSpace, + crossAxisSpacing: StyleString.cardSpace, + maxCrossAxisExtent: Grid.maxRowWidth, + childAspectRatio: StyleString.aspectRatio, + mainAxisExtent: + MediaQuery.textScalerOf(context).scale(90), + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + return VideoCardVMemberHome( + videoItem: + loadingState.response.archive.item[index], + ); + }, + childCount: + min(4, loadingState.response.archive.item.length), ), ), - subtitle: loadingState.response.article.item.first.summary - ?.isNotEmpty == - true - ? Text( - loadingState.response.article.item.first.summary!, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 13, - color: Theme.of(context).colorScheme.outline, - ), - ) - : null, ), - ), - ], - if (loadingState.response?.audios?.item?.isNotEmpty == true) ...[ - _videoHeader( - title: '音频', - param: 'contribute', - param1: 'audio', - count: loadingState.response.audios.count, - ), - // TODO - ], - if (loadingState.response?.season?.item?.isNotEmpty == true) ...[ - _videoHeader( - title: '追番', - param: 'bangumi', - count: loadingState.response.season.count, - ), - SliverPadding( - padding: const EdgeInsets.symmetric( - horizontal: StyleString.safeSpace, + ], + if (loadingState.response?.favourite2?.item?.isNotEmpty == + true) ...[ + _videoHeader( + title: '收藏', + param: 'favorite', + count: loadingState.response.favourite2.count, ), - sliver: SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.cardSpace - 2, - crossAxisSpacing: StyleString.cardSpace, - maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2, - childAspectRatio: 0.65, - mainAxisExtent: - MediaQuery.textScalerOf(context).scale(60), - ), - delegate: SliverChildBuilderDelegate( - (context, index) { - return BangumiCardVMemberHome( - bangumiItem: loadingState.response.season.item[index], - ); + // TODO + ], + if (loadingState.response?.coinArchive?.item?.isNotEmpty == + true) ...[ + _videoHeader( + title: '最近投币的视频', + param: 'coinArchive', + count: loadingState.response.coinArchive.count, + ), + // TODO + ], + if (loadingState.response?.likeArchive?.item?.isNotEmpty == + true) ...[ + _videoHeader( + title: '最近点赞的视频', + param: 'likeArchive', + count: loadingState.response.likeArchive.count, + ), + // TODO + ], + if (loadingState.response?.article?.item?.isNotEmpty == + true) ...[ + _videoHeader( + title: '专栏', + param: 'contribute', + param1: 'article', + count: loadingState.response.article.count, + ), + SliverToBoxAdapter( + child: ListTile( + dense: true, + onTap: () { + PiliScheme.routePush(Uri.parse( + loadingState.response.article.item.first.uri ?? + '')); }, - childCount: - min(3, loadingState.response.season.item.length), + leading: loadingState.response.article.item.first + .originImageUrls?.isNotEmpty == + true + ? Container( + margin: const EdgeInsets.symmetric(vertical: 6), + child: LayoutBuilder( + builder: (_, constraints) { + return NetworkImgLayer( + radius: 6, + src: loadingState.response.article.item + .first.originImageUrls!.first, + width: constraints.maxHeight * + StyleString.aspectRatio, + height: constraints.maxHeight, + ); + }, + ), + ) + : null, + title: Text( + loadingState.response.article.item.first.title ?? '', + style: TextStyle( + fontSize: 15, + ), + ), + subtitle: loadingState.response.article.item.first.summary + ?.isNotEmpty == + true + ? Text( + loadingState.response.article.item.first.summary!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.outline, + ), + ) + : null, ), ), + ], + if (loadingState.response?.audios?.item?.isNotEmpty == + true) ...[ + _videoHeader( + title: '音频', + param: 'contribute', + param1: 'audio', + count: loadingState.response.audios.count, + ), + // TODO + ], + if (loadingState.response?.season?.item?.isNotEmpty == + true) ...[ + _videoHeader( + title: '追番', + param: 'bangumi', + count: loadingState.response.season.count, + ), + SliverPadding( + padding: const EdgeInsets.symmetric( + horizontal: StyleString.safeSpace, + ), + sliver: SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.cardSpace - 2, + crossAxisSpacing: StyleString.cardSpace, + maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2, + childAspectRatio: 0.65, + mainAxisExtent: + MediaQuery.textScalerOf(context).scale(60), + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + return BangumiCardVMemberHome( + bangumiItem: + loadingState.response.season.item[index], + ); + }, + childCount: + min(3, loadingState.response.season.item.length), + ), + ), + ), + ], + SliverToBoxAdapter( + child: SizedBox( + height: 12 + MediaQuery.of(context).padding.bottom, + ), ), ], - SliverToBoxAdapter( - child: SizedBox( - height: 12 + MediaQuery.of(context).padding.bottom, - ), - ), - ], - ) - : const SizedBox.shrink(); + ) + : errorWidget(), + Error() => errorWidget(), + LoadingState() => throw UnimplementedError(), + }; } Widget _videoHeader({ diff --git a/lib/pages/member/new/member_page.dart b/lib/pages/member/new/member_page.dart index e11ace7f..e8b019a0 100644 --- a/lib/pages/member/new/member_page.dart +++ b/lib/pages/member/new/member_page.dart @@ -1,7 +1,7 @@ import 'dart:math'; import 'package:PiliPalaX/common/widgets/dynamic_sliver_appbar.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/bangumi/member_bangumi.dart'; import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart'; @@ -291,28 +291,19 @@ class _MemberPageNewState extends State ); Widget _errorWidget(msg) { - return CustomScrollView( - shrinkWrap: true, - slivers: [ - HttpError( - errMsg: msg, - fn: () { - _userController.loadingState.value = LoadingState.loading(); - _userController.onRefresh(); - }, - ) - ], + return errorWidget( + errMsg: msg, + callback: () { + _userController.loadingState.value = LoadingState.loading(); + _userController.onRefresh(); + }, ); } Widget _buildUserInfo(LoadingState userState, [bool isV = true]) { - switch (userState) { - case Empty(): - return _errorWidget('EMPTY'); - case Error(): - return _errorWidget(userState.errMsg); - case Success(): - return Obx( + return switch (userState) { + Loading() => const CircularProgressIndicator(), + Success() => Obx( () => Padding( padding: EdgeInsets.only( bottom: (_userController.tab2?.length ?? 0) > 1 ? 48 : 0), @@ -326,8 +317,9 @@ class _MemberPageNewState extends State onFollow: () => _userController.onFollow(context), ), ), - ); - } - return const CircularProgressIndicator(); + ), + Error() => _errorWidget(userState.errMsg), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/member/new/widget/edit_profile_page.dart b/lib/pages/member/new/widget/edit_profile_page.dart index b2a32e51..2eaabf80 100644 --- a/lib/pages/member/new/widget/edit_profile_page.dart +++ b/lib/pages/member/new/widget/edit_profile_page.dart @@ -1,5 +1,5 @@ import 'package:PiliPalaX/common/constants.dart'; -import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/http/constants.dart'; import 'package:PiliPalaX/http/index.dart'; import 'package:PiliPalaX/http/loading_state.dart'; @@ -99,19 +99,9 @@ class _EditProfilePageState extends State { ); Widget _buildBody(LoadingState loadingState) { - switch (loadingState) { - case Error(): - return CustomScrollView( - shrinkWrap: true, - slivers: [ - HttpError( - errMsg: loadingState.errMsg, - fn: _getInfo, - ), - ], - ); - case Success(): - return SingleChildScrollView( + return switch (loadingState) { + Loading() => loadingWidget, + Success() => SingleChildScrollView( child: Column( children: [ _item( @@ -226,11 +216,13 @@ class _EditProfilePageState extends State { _divider, ], ), - ); - } - return Center( - child: CircularProgressIndicator(), - ); + ), + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: _getInfo, + ), + LoadingState() => throw UnimplementedError(), + }; } Widget _sexDialog(int current) { diff --git a/lib/pages/member_archive/view.dart b/lib/pages/member_archive/view.dart index dcaa3dc3..20b92fad 100644 --- a/lib/pages/member_archive/view.dart +++ b/lib/pages/member_archive/view.dart @@ -109,13 +109,13 @@ class _MemberArchivePageState extends State { } else { return HttpError( errMsg: snapshot.data['msg'], - fn: () {}, + callback: () {}, ); } } else { return HttpError( errMsg: "投稿页出现错误", - fn: () {}, + callback: () {}, ); } } else { diff --git a/lib/pages/member_dynamics/view.dart b/lib/pages/member_dynamics/view.dart index f7fd6352..228ce910 100644 --- a/lib/pages/member_dynamics/view.dart +++ b/lib/pages/member_dynamics/view.dart @@ -72,72 +72,79 @@ class _MemberDynamicsPageState extends State ); _buildContent(LoadingState loadingState) { - return loadingState is Success - ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom, - ), - sliver: dynamicsWaterfallFlow - ? SliverWaterfallFlow.extent( - maxCrossAxisExtent: Grid.maxRowWidth * 2, - //cacheExtent: 0.0, - crossAxisSpacing: StyleString.safeSpace, - mainAxisSpacing: StyleString.safeSpace, + return switch (loadingState) { + Loading() => HttpError( + callback: _memberDynamicController.onReload, + ), + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom, + ), + sliver: dynamicsWaterfallFlow + ? SliverWaterfallFlow.extent( + maxCrossAxisExtent: Grid.maxRowWidth * 2, + //cacheExtent: 0.0, + crossAxisSpacing: StyleString.safeSpace, + mainAxisSpacing: StyleString.safeSpace, - /// follow max child trailing layout offset and layout with full cross axis extend - /// last child as loadmore item/no more item in [GridView] and [WaterfallFlow] - /// with full cross axis extend - // LastChildLayoutType.fullCrossAxisExtend, + /// follow max child trailing layout offset and layout with full cross axis extend + /// last child as loadmore item/no more item in [GridView] and [WaterfallFlow] + /// with full cross axis extend + // LastChildLayoutType.fullCrossAxisExtend, - /// as foot at trailing and layout with full cross axis extend - /// show no more item at trailing when children are not full of viewport - /// if children is full of viewport, it's the same as fullCrossAxisExtend - // LastChildLayoutType.foot, - lastChildLayoutTypeBuilder: (index) { - if (index == loadingState.response.length - 1) { - EasyThrottle.throttle('member_dynamics', - const Duration(milliseconds: 1000), () { - _memberDynamicController.onLoadMore(); - }); - } - return index == loadingState.response.length - ? LastChildLayoutType.foot - : LastChildLayoutType.none; - }, - children: (loadingState.response as List) - .map((item) => DynamicPanel(item: item)) - .toList(), - ) - : SliverCrossAxisGroup( - slivers: [ - const SliverFillRemaining(), - SliverConstrainedCrossAxis( - maxExtent: Grid.maxRowWidth * 2, - sliver: SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - if (index == loadingState.response.length - 1) { - EasyThrottle.throttle('member_dynamics', - const Duration(milliseconds: 1000), () { - _memberDynamicController.onLoadMore(); - }); - } - return DynamicPanel( - item: loadingState.response[index]); - }, - childCount: loadingState.response.length, + /// as foot at trailing and layout with full cross axis extend + /// show no more item at trailing when children are not full of viewport + /// if children is full of viewport, it's the same as fullCrossAxisExtend + // LastChildLayoutType.foot, + lastChildLayoutTypeBuilder: (index) { + if (index == loadingState.response.length - 1) { + EasyThrottle.throttle('member_dynamics', + const Duration(milliseconds: 1000), () { + _memberDynamicController.onLoadMore(); + }); + } + return index == loadingState.response.length + ? LastChildLayoutType.foot + : LastChildLayoutType.none; + }, + children: (loadingState.response as List) + .map((item) => DynamicPanel(item: item)) + .toList(), + ) + : SliverCrossAxisGroup( + slivers: [ + const SliverFillRemaining(), + SliverConstrainedCrossAxis( + maxExtent: Grid.maxRowWidth * 2, + sliver: SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == loadingState.response.length - 1) { + EasyThrottle.throttle('member_dynamics', + const Duration(milliseconds: 1000), () { + _memberDynamicController.onLoadMore(); + }); + } + return DynamicPanel( + item: loadingState.response[index]); + }, + childCount: loadingState.response.length, + ), ), ), - ), - const SliverFillRemaining(), - ], - ), - ) - : HttpError( - errMsg: loadingState is Error ? loadingState.errMsg : null, - fn: () { - _memberDynamicController.onReload(); - }, - ); + const SliverFillRemaining(), + ], + ), + ) + : HttpError( + callback: _memberDynamicController.onReload, + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _memberDynamicController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/member_search/view.dart b/lib/pages/member_search/view.dart index 58e37599..18913a4b 100644 --- a/lib/pages/member_search/view.dart +++ b/lib/pages/member_search/view.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPalaX/common/skeleton/video_card_h.dart'; import 'package:PiliPalaX/common/widgets/http_error.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import 'package:PiliPalaX/common/widgets/video_card_h.dart'; import '../../common/constants.dart'; @@ -148,12 +147,14 @@ class _MemberSearchPageState extends State (context, index) { return const VideoCardHSkeleton(); }, childCount: 10)) - : const NoData(), + : HttpError( + callback: () => setState(() {}), + ), )); } else { return HttpError( errMsg: data['msg'], - fn: () => setState(() {}), + callback: () => setState(() {}), ); } } else { diff --git a/lib/pages/rank/zone/view.dart b/lib/pages/rank/zone/view.dart index a878f846..57f5f844 100644 --- a/lib/pages/rank/zone/view.dart +++ b/lib/pages/rank/zone/view.dart @@ -91,7 +91,7 @@ class _ZonePageState extends State ? (_zoneController.loadingState.value as Error) .errMsg : '没有相关数据', - fn: _zoneController.onReload, + callback: _zoneController.onReload, ), ), ), diff --git a/lib/pages/rcmd/view.dart b/lib/pages/rcmd/view.dart index 8fb63847..8ed5233b 100644 --- a/lib/pages/rcmd/view.dart +++ b/lib/pages/rcmd/view.dart @@ -102,7 +102,7 @@ class _RcmdPageState extends State errMsg: _controller.loadingState.value is Error ? (_controller.loadingState.value as Error).errMsg : '没有相关数据', - fn: _controller.onReload, + callback: _controller.onReload, ), ), ), diff --git a/lib/pages/search/view.dart b/lib/pages/search/view.dart index 022377b6..c5ab6283 100644 --- a/lib/pages/search/view.dart +++ b/lib/pages/search/view.dart @@ -195,7 +195,7 @@ class _SearchPageState extends State with RouteAware { slivers: [ HttpError( errMsg: data['msg'], - fn: () => setState(() { + callback: () => setState(() { _futureBuilderFuture = _searchController.queryHotSearchList(); }), diff --git a/lib/pages/search_panel/controller.dart b/lib/pages/search_panel/controller.dart index 228079f1..b34477e6 100644 --- a/lib/pages/search_panel/controller.dart +++ b/lib/pages/search_panel/controller.dart @@ -45,14 +45,14 @@ class SearchPanelController extends CommonController { if (dataList.isNotEmpty) { loadingState.value = LoadingState.success(dataList); } else { - loadingState.value = LoadingState.empty(); + loadingState.value = LoadingState.success([]); } if (currentPage == 1) { onPushDetail(response.response.list); } } else { if (currentPage == 1) { - loadingState.value = LoadingState.empty(); + loadingState.value = LoadingState.success([]); } } return true; diff --git a/lib/pages/search_panel/widgets/article_panel.dart b/lib/pages/search_panel/widgets/article_panel.dart index 9b5278b9..a88986c2 100644 --- a/lib/pages/search_panel/widgets/article_panel.dart +++ b/lib/pages/search_panel/widgets/article_panel.dart @@ -206,7 +206,7 @@ Widget searchArticlePanel(BuildContext context, searchPanelCtr, loadingState) { ) : HttpError( errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', - fn: searchPanelCtr.onReload, + callback: searchPanelCtr.onReload, ), ], ); diff --git a/lib/pages/search_panel/widgets/live_panel.dart b/lib/pages/search_panel/widgets/live_panel.dart index aeb0e28b..d4f5ae08 100644 --- a/lib/pages/search_panel/widgets/live_panel.dart +++ b/lib/pages/search_panel/widgets/live_panel.dart @@ -1,4 +1,4 @@ -import 'package:PiliPalaX/common/widgets/http_error.dart'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:PiliPalaX/http/loading_state.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -8,36 +8,39 @@ import 'package:PiliPalaX/utils/utils.dart'; import '../../../utils/grid.dart'; -Widget searchLivePanel(BuildContext context, ctr, loadingState) { - return loadingState is Success - ? GridView.builder( - padding: const EdgeInsets.only( - left: StyleString.safeSpace, - right: StyleString.safeSpace, - bottom: StyleString.safeSpace, - ), - primary: false, - controller: ctr!.scrollController, - gridDelegate: SliverGridDelegateWithExtentAndRatio( - maxCrossAxisExtent: Grid.maxRowWidth, - crossAxisSpacing: StyleString.safeSpace, - mainAxisSpacing: StyleString.safeSpace, - childAspectRatio: StyleString.aspectRatio, - mainAxisExtent: MediaQuery.textScalerOf(context).scale(80), - ), - itemCount: loadingState.response.length, - itemBuilder: (context, index) { - return LiveItem(liveItem: loadingState.response[index]); - }, - ) - : CustomScrollView( - slivers: [ - HttpError( - errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', - fn: ctr.onReload, +Widget searchLivePanel(BuildContext context, ctr, LoadingState loadingState) { + return switch (loadingState) { + Loading() => loadingWidget, + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? GridView.builder( + padding: const EdgeInsets.only( + left: StyleString.safeSpace, + right: StyleString.safeSpace, + bottom: StyleString.safeSpace, ), - ], - ); + primary: false, + controller: ctr!.scrollController, + gridDelegate: SliverGridDelegateWithExtentAndRatio( + maxCrossAxisExtent: Grid.maxRowWidth, + crossAxisSpacing: StyleString.safeSpace, + mainAxisSpacing: StyleString.safeSpace, + childAspectRatio: StyleString.aspectRatio, + mainAxisExtent: MediaQuery.textScalerOf(context).scale(80), + ), + itemCount: loadingState.response.length, + itemBuilder: (context, index) { + return LiveItem(liveItem: loadingState.response[index]); + }, + ) + : errorWidget( + callback: ctr.onReload, + ), + Error() => errorWidget( + errMsg: loadingState.errMsg, + callback: ctr.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } class LiveItem extends StatelessWidget { diff --git a/lib/pages/search_panel/widgets/media_bangumi_panel.dart b/lib/pages/search_panel/widgets/media_bangumi_panel.dart index 63aecd68..17ab19dc 100644 --- a/lib/pages/search_panel/widgets/media_bangumi_panel.dart +++ b/lib/pages/search_panel/widgets/media_bangumi_panel.dart @@ -192,7 +192,7 @@ Widget searchBangumiPanel(BuildContext context, ctr, loadingState) { ) : HttpError( errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', - fn: ctr.onReload, + callback: ctr.onReload, ), ], ); diff --git a/lib/pages/search_panel/widgets/user_panel.dart b/lib/pages/search_panel/widgets/user_panel.dart index 3ac3677d..d44a8b34 100644 --- a/lib/pages/search_panel/widgets/user_panel.dart +++ b/lib/pages/search_panel/widgets/user_panel.dart @@ -150,7 +150,7 @@ Widget searchUserPanel(BuildContext context, searchPanelCtr, loadingState) { ) : HttpError( errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', - fn: searchPanelCtr.onReload, + callback: searchPanelCtr.onReload, ) ], ); diff --git a/lib/pages/search_panel/widgets/video_panel.dart b/lib/pages/search_panel/widgets/video_panel.dart index ca1768e4..757d539e 100644 --- a/lib/pages/search_panel/widgets/video_panel.dart +++ b/lib/pages/search_panel/widgets/video_panel.dart @@ -123,7 +123,7 @@ class SearchVideoPanel extends StatelessWidget { ) : HttpError( errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', - fn: ctr.onReload, + callback: ctr.onReload, ), ], ); diff --git a/lib/pages/search_result/view.dart b/lib/pages/search_result/view.dart index 63ed7d56..fb576753 100644 --- a/lib/pages/search_result/view.dart +++ b/lib/pages/search_result/view.dart @@ -64,7 +64,6 @@ class _SearchResultPageState extends State const SizedBox(height: 4), Container( width: double.infinity, - padding: const EdgeInsets.only(left: 8), color: Theme.of(context).colorScheme.surface, child: Theme( data: ThemeData( @@ -72,6 +71,7 @@ class _SearchResultPageState extends State highlightColor: Colors.transparent, // 点击时的背景高亮颜色设置为透明 ), child: TabBar( + padding: const EdgeInsets.symmetric(horizontal: 8), controller: _tabController, tabs: SearchType.values .map( diff --git a/lib/pages/setting/pages/logs.dart b/lib/pages/setting/pages/logs.dart index 53c5bfaa..49b1e445 100644 --- a/lib/pages/setting/pages/logs.dart +++ b/lib/pages/setting/pages/logs.dart @@ -1,7 +1,7 @@ import 'dart:io'; +import 'package:PiliPalaX/common/widgets/loading_widget.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../../services/loggeer.dart'; @@ -194,11 +194,7 @@ class _LogsPageState extends State { ); }, ) - : const CustomScrollView( - slivers: [ - NoData(), - ], - ), + : errorWidget(), ); } } diff --git a/lib/pages/setting/recommend_setting.dart b/lib/pages/setting/recommend_setting.dart index 5ac36621..763d1942 100644 --- a/lib/pages/setting/recommend_setting.dart +++ b/lib/pages/setting/recommend_setting.dart @@ -105,6 +105,7 @@ class _RecommendSettingState extends State { leading: Icon(Icons.refresh), setKey: SettingBoxKey.enableSaveLastData, defaultVal: false, + needReboot: true, ), // 分割线 const Divider(height: 1), diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart index 9bb00799..40802c70 100644 --- a/lib/pages/setting/style_setting.dart +++ b/lib/pages/setting/style_setting.dart @@ -44,7 +44,7 @@ class _StyleSettingState extends State { setting.get(SettingBoxKey.maxRowWidth, defaultValue: 240.0) as double; upPanelPosition = UpPanelPosition.values[setting.get( SettingBoxKey.upPanelPosition, - defaultValue: UpPanelPosition.leftFixed.code)]; + defaultValue: UpPanelPosition.leftFixed.index)]; } @override @@ -67,10 +67,10 @@ class _StyleSettingState extends State { callFn: (value) { if (value) { autoScreen(); - SmartDialog.showToast('已开启横屏适配'); + // SmartDialog.showToast('已开启横屏适配'); } else { AutoOrientation.portraitUpMode(); - SmartDialog.showToast('已关闭横屏适配'); + // SmartDialog.showToast('已关闭横屏适配'); } }), const SetSwitchItem( @@ -171,7 +171,7 @@ class _StyleSettingState extends State { ); if (result != null) { upPanelPosition = result; - setting.put(SettingBoxKey.upPanelPosition, result.code); + setting.put(SettingBoxKey.upPanelPosition, result.index); SmartDialog.showToast('重启生效'); setState(() {}); } @@ -307,7 +307,7 @@ class _StyleSettingState extends State { if (result != null) { _tempThemeValue = result; settingController.themeType.value = result; - setting.put(SettingBoxKey.themeMode, result.code); + setting.put(SettingBoxKey.themeMode, result.index); Get.forceAppUpdate(); } }, diff --git a/lib/pages/subscription/view.dart b/lib/pages/subscription/view.dart index df0b4e4e..bd1a5223 100644 --- a/lib/pages/subscription/view.dart +++ b/lib/pages/subscription/view.dart @@ -80,7 +80,7 @@ class _SubPageState extends State { slivers: [ HttpError( errMsg: data?['msg'], - fn: () => setState(() {}), + callback: () => setState(() {}), ), ], ); diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index f819932d..a21b7ddf 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -6,7 +6,6 @@ import 'package:get/get.dart'; import 'package:PiliPalaX/common/skeleton/video_card_h.dart'; import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; -import 'package:PiliPalaX/common/widgets/no_data.dart'; import '../../models/user/sub_folder.dart'; import '../../utils/utils.dart'; @@ -206,7 +205,12 @@ class _SubDetailPageState extends State { Map data = snapshot.data; if (data['status']) { if (_subDetailController.item.mediaCount == 0) { - return const NoData(); + return HttpError( + callback: () => setState(() { + _futureBuilderFuture = + _subDetailController.queryUserSubFolderDetail(); + }), + ); } else { List subList = _subDetailController.subList; return Obx( @@ -225,7 +229,10 @@ class _SubDetailPageState extends State { } else { return HttpError( errMsg: data['msg'], - fn: () => setState(() {}), + callback: () => setState(() { + _futureBuilderFuture = + _subDetailController.queryUserSubFolderDetail(); + }), ); } } else { diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index acb5dd34..428ec793 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -699,7 +699,10 @@ class VideoIntroController extends GetxController late RelatedController relatedCtr; try { relatedCtr = Get.find(tag: heroTag); - if (relatedCtr.loadingState.value is Empty) { + if (relatedCtr.loadingState.value is! Success) { + return false; + } + if ((relatedCtr.loadingState.value as Success).response.isEmpty == true) { SmartDialog.showToast('暂无相关视频,停止连播'); return false; } diff --git a/lib/pages/video/detail/introduction/widgets/create_fav_page.dart b/lib/pages/video/detail/introduction/widgets/create_fav_page.dart index 712a919c..fb720991 100644 --- a/lib/pages/video/detail/introduction/widgets/create_fav_page.dart +++ b/lib/pages/video/detail/introduction/widgets/create_fav_page.dart @@ -101,7 +101,7 @@ class _CreateFavPageState extends State { slivers: [ HttpError( errMsg: _errMsg, - fn: _getFolderInfo, + callback: _getFolderInfo, ), ], ), diff --git a/lib/pages/video/detail/introduction/widgets/fav_panel.dart b/lib/pages/video/detail/introduction/widgets/fav_panel.dart index 62e352f5..1affea80 100644 --- a/lib/pages/video/detail/introduction/widgets/fav_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/fav_panel.dart @@ -147,7 +147,7 @@ class _FavPanelState extends State { slivers: [ HttpError( errMsg: data['msg'], - fn: () => setState(() { + callback: () => setState(() { _futureBuilderFuture = widget.ctr!.queryVideoInFolder(); }), diff --git a/lib/pages/video/detail/introduction/widgets/group_panel.dart b/lib/pages/video/detail/introduction/widgets/group_panel.dart index c44c9f0a..04c264fd 100644 --- a/lib/pages/video/detail/introduction/widgets/group_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/group_panel.dart @@ -144,7 +144,7 @@ class _GroupPanelState extends State { slivers: [ HttpError( errMsg: data['msg'], - fn: () => setState(() {}), + callback: () => setState(() {}), ), ], ); diff --git a/lib/pages/video/detail/related/view.dart b/lib/pages/video/detail/related/view.dart index d2e99654..a6d5b97d 100644 --- a/lib/pages/video/detail/related/view.dart +++ b/lib/pages/video/detail/related/view.dart @@ -43,54 +43,58 @@ class _RelatedVideoPanelState extends State } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0), - delegate: SliverChildBuilderDelegate((context, index) { - if (index == loadingState.response.length) { - return SizedBox(height: MediaQuery.of(context).padding.bottom); - } else { - return Material( - child: VideoCardH( - videoItem: loadingState.response[index], - showPubdate: true, - longPress: () { - _relatedController.popupDialog.add( - _createPopupDialog(loadingState.response[index])); - Overlay.of(context) - .insert(_relatedController.popupDialog.last!); - }, - longPressEnd: _relatedController.removePopupDialog, - ), - ); - } - }, childCount: loadingState.response.length + 1), - ) - : loadingState is Error - ? HttpError( - errMsg: '出错了', - fn: _relatedController.onReload, - ) - : loadingState is Empty - ? const SliverToBoxAdapter(child: SizedBox.shrink()) - : SliverGrid( - gridDelegate: SliverGridDelegateWithExtentAndRatio( - mainAxisSpacing: StyleString.safeSpace, - crossAxisSpacing: StyleString.safeSpace, - maxCrossAxisExtent: Grid.maxRowWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, - mainAxisExtent: 0), - delegate: SliverChildBuilderDelegate( - (context, index) { - return const VideoCardHSkeleton(); + return switch (loadingState) { + Loading() => SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.safeSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0), + delegate: SliverChildBuilderDelegate( + (context, index) { + return const VideoCardHSkeleton(); + }, + childCount: 5, + ), + ), + Success() => (loadingState.response as List?)?.isNotEmpty == true + ? SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: StyleString.safeSpace, + crossAxisSpacing: StyleString.safeSpace, + maxCrossAxisExtent: Grid.maxRowWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.4, + mainAxisExtent: 0), + delegate: SliverChildBuilderDelegate((context, index) { + if (index == loadingState.response.length) { + return SizedBox( + height: MediaQuery.of(context).padding.bottom); + } else { + return Material( + child: VideoCardH( + videoItem: loadingState.response[index], + showPubdate: true, + longPress: () { + _relatedController.popupDialog.add( + _createPopupDialog(loadingState.response[index])); + Overlay.of(context) + .insert(_relatedController.popupDialog.last!); }, - childCount: 5, + longPressEnd: _relatedController.removePopupDialog, ), ); + } + }, childCount: loadingState.response.length + 1), + ) + : HttpError( + callback: _relatedController.onReload, + ), + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _relatedController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index 09125a53..6c41593f 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -200,63 +200,68 @@ class _VideoReplyPanelState extends State } Widget _buildBody(LoadingState loadingState) { - return loadingState is Success - ? SliverList( - delegate: SliverChildBuilderDelegate( - (BuildContext context, index) { - double bottom = MediaQuery.of(context).padding.bottom; - if (index == loadingState.response.replies.length) { - return Container( - padding: EdgeInsets.only(bottom: bottom), - height: bottom + 100, - child: Center( - child: Obx( - () => Text( - _videoReplyController.noMore.value, - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.outline, + return switch (loadingState) { + Loading() => SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, index) { + return const VideoReplySkeleton(); + }, + childCount: 5, + ), + ), + Success() => (loadingState.response.replies as List?)?.isNotEmpty == true + ? SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, index) { + double bottom = MediaQuery.of(context).padding.bottom; + if (index == loadingState.response.replies.length) { + return Container( + padding: EdgeInsets.only(bottom: bottom), + height: bottom + 100, + child: Center( + child: Obx( + () => Text( + _videoReplyController.noMore.value, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), ), ), ), - ), - ); - } else { - return ReplyItemGrpc( - replyItem: loadingState.response.replies[index], - showReplyRow: true, - replyLevel: replyLevel, - replyReply: widget.replyReply, - replyType: ReplyType.video, - onReply: () { - _videoReplyController.onReply( - context, - replyItem: loadingState.response.replies[index], - index: index, - ); - }, - onDelete: _videoReplyController.onMDelete, - isTop: _videoReplyController.hasUpTop && index == 0, - upMid: loadingState.response.subjectControl.upMid, - ); - } - }, - childCount: loadingState.response.replies.length + 1, + ); + } else { + return ReplyItemGrpc( + replyItem: loadingState.response.replies[index], + showReplyRow: true, + replyLevel: replyLevel, + replyReply: widget.replyReply, + replyType: ReplyType.video, + onReply: () { + _videoReplyController.onReply( + context, + replyItem: loadingState.response.replies[index], + index: index, + ); + }, + onDelete: _videoReplyController.onMDelete, + isTop: _videoReplyController.hasUpTop && index == 0, + upMid: loadingState.response.subjectControl.upMid, + ); + } + }, + childCount: loadingState.response.replies.length + 1, + ), + ) + : HttpError( + callback: _videoReplyController.onReload, ), - ) - : loadingState is Error - ? HttpError( - errMsg: loadingState.errMsg, - fn: _videoReplyController.onReload, - ) - : SliverList( - delegate: SliverChildBuilderDelegate( - (BuildContext context, index) { - return const VideoReplySkeleton(); - }, - childCount: 5, - ), - ); + Error() => HttpError( + errMsg: loadingState.errMsg, + callback: _videoReplyController.onReload, + ), + LoadingState() => throw UnimplementedError(), + }; } } diff --git a/lib/pages/video/detail/reply_reply/controller.dart b/lib/pages/video/detail/reply_reply/controller.dart index fd5df0b6..9da0a527 100644 --- a/lib/pages/video/detail/reply_reply/controller.dart +++ b/lib/pages/video/detail/reply_reply/controller.dart @@ -146,10 +146,20 @@ class VideoReplyReplyController extends CommonController } upMid ??= replies.subjectControl.upMid.toInt(); cursor = replies.cursor; + if (currentPage != 1) { + List list = loadingState.value is Success + ? (loadingState.value as Success).response + : []; + if (isDialogue) { + replies.replies.insertAll(0, list); + } else { + replies.root.replies.insertAll(0, list); + } + } if (isDialogue) { if (replies.replies.isNotEmpty) { noMore.value = '加载中...'; - if (replies.cursor.isEnd) { + if (replies.cursor.isEnd || count.value >= replies.replies.length) { noMore.value = '没有更多了'; } } else { @@ -159,7 +169,8 @@ class VideoReplyReplyController extends CommonController } else { if (replies.root.replies.isNotEmpty) { noMore.value = '加载中...'; - if (replies.cursor.isEnd) { + if (replies.cursor.isEnd || + count.value >= replies.root.replies.length) { noMore.value = '没有更多了'; } } else { @@ -167,16 +178,6 @@ class VideoReplyReplyController extends CommonController noMore.value = currentPage == 1 ? '还没有评论' : '没有更多了'; } } - if (currentPage != 1) { - List list = loadingState.value is Success - ? (loadingState.value as Success).response - : []; - if (isDialogue) { - replies.replies.insertAll(0, list); - } else { - replies.root.replies.insertAll(0, list); - } - } if (isDialogue) { loadingState.value = LoadingState.success(replies.replies); } else { diff --git a/lib/pages/video/detail/reply_reply/view.dart b/lib/pages/video/detail/reply_reply/view.dart index 8a45efd6..672d6189 100644 --- a/lib/pages/video/detail/reply_reply/view.dart +++ b/lib/pages/video/detail/reply_reply/view.dart @@ -333,7 +333,7 @@ class _VideoReplyReplyPanelState extends State { slivers: [ HttpError( errMsg: loadingState.errMsg, - fn: _videoReplyReplyController.onReload, + callback: _videoReplyReplyController.onReload, ) ], );