opt: pages

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2024-11-21 18:06:33 +08:00
parent 5b2a4fa681
commit c5f5c00d37
66 changed files with 1504 additions and 1534 deletions

View File

@@ -2,47 +2,64 @@ import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
class HttpError extends StatelessWidget { class HttpError extends StatelessWidget {
const HttpError( const HttpError({
{required this.errMsg, required this.fn, this.btnText, super.key}); this.isSliver = true,
this.errMsg,
this.callback,
this.btnText,
super.key,
});
final bool isSliver;
final String? errMsg; final String? errMsg;
final Function()? fn; final Function()? callback;
final String? btnText; final String? btnText;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SliverToBoxAdapter( return isSliver
child: Column( ? SliverToBoxAdapter(child: content(context))
: SizedBox(
width: double.infinity,
child: content(context),
);
}
Widget content(BuildContext context) => Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const SizedBox(height: 40),
SvgPicture.asset( SvgPicture.asset(
"assets/images/error.svg", "assets/images/error.svg",
height: 200, height: 200,
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
Text( Padding(
errMsg ?? '请求异常', padding: const EdgeInsets.symmetric(horizontal: 16),
textAlign: TextAlign.center, child: SelectableText(
style: Theme.of(context).textTheme.titleSmall, errMsg ?? '没有数据',
), textAlign: TextAlign.center,
const SizedBox(height: 20), style: Theme.of(context).textTheme.titleSmall,
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),
), ),
), ),
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),
], ],
), );
);
}
} }

View File

@@ -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,
);

View File

@@ -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,
),
],
),
),
);
}
}

View File

@@ -1,5 +1,4 @@
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/utils/extension.dart';
import '../models/bangumi/list.dart'; import '../models/bangumi/list.dart';
import 'index.dart'; import 'index.dart';
@@ -10,11 +9,7 @@ class BangumiHttp {
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
BangumiListDataModel data = BangumiListDataModel data =
BangumiListDataModel.fromJson(res.data['data']); BangumiListDataModel.fromJson(res.data['data']);
if (!data.list.isNullOrEmpty) { return LoadingState.success(data.list);
return LoadingState.success(data.list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }
@@ -25,11 +20,7 @@ class BangumiHttp {
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
BangumiListDataModel data = BangumiListDataModel data =
BangumiListDataModel.fromJson(res.data['data']); BangumiListDataModel.fromJson(res.data['data']);
if (!data.list.isNullOrEmpty) { return LoadingState.success(data.list);
return LoadingState.success(data.list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }

View File

@@ -1,5 +1,4 @@
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/utils/extension.dart';
import '../models/user/black.dart'; import '../models/user/black.dart';
import 'index.dart'; import 'index.dart';
@@ -15,11 +14,7 @@ class BlackHttp {
}); });
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
BlackListDataModel data = BlackListDataModel.fromJson(res.data['data']); BlackListDataModel data = BlackListDataModel.fromJson(res.data['data']);
if (!data.list.isNullOrEmpty) { return LoadingState.success(data);
return LoadingState.success(data);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }

View File

@@ -1,5 +1,4 @@
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/utils/extension.dart';
import '../models/dynamics/result.dart'; import '../models/dynamics/result.dart';
import '../models/dynamics/up.dart'; import '../models/dynamics/up.dart';
@@ -25,11 +24,7 @@ class DynamicsHttp {
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
try { try {
DynamicsDataModel data = DynamicsDataModel.fromJson(res.data['data']); DynamicsDataModel data = DynamicsDataModel.fromJson(res.data['data']);
if (!data.items.isNullOrEmpty) { return LoadingState.success(data);
return LoadingState.success(data);
} else {
return LoadingState.empty();
}
} catch (err) { } catch (err) {
return LoadingState.error(err.toString()); return LoadingState.error(err.toString());
} }

View File

@@ -17,11 +17,7 @@ class LiveHttp {
List<LiveItemModel> list = res.data['data']['list'] List<LiveItemModel> list = res.data['data']['list']
.map<LiveItemModel>((e) => LiveItemModel.fromJson(e)) .map<LiveItemModel>((e) => LiveItemModel.fromJson(e))
.toList(); .toList();
if (list.isNotEmpty) { return LoadingState.success(list);
return LoadingState.success(list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }

View File

@@ -2,7 +2,7 @@ abstract class LoadingState<T> {
const LoadingState(); const LoadingState();
factory LoadingState.loading() = Loading; factory LoadingState.loading() = Loading;
factory LoadingState.empty() = Empty; // factory LoadingState.empty() = Empty;
factory LoadingState.success(T response) = Success<T>; factory LoadingState.success(T response) = Success<T>;
factory LoadingState.error(String errMsg) = Error; factory LoadingState.error(String errMsg) = Error;
} }
@@ -11,9 +11,9 @@ class Loading extends LoadingState<Never> {
const Loading(); const Loading();
} }
class Empty extends LoadingState<Never> { // class Empty extends LoadingState<Never> {
const Empty(); // const Empty();
} // }
class Success<T> extends LoadingState<T> { class Success<T> extends LoadingState<T> {
final T response; final T response;

View File

@@ -55,11 +55,7 @@ class UserHttp {
'up_mid': mid, 'up_mid': mid,
}); });
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
if (res.data['data'] != null) { return LoadingState.success(FavFolderData.fromJson(res.data['data']));
return LoadingState.success(FavFolderData.fromJson(res.data['data']));
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message'] ?? '账号未登录'); return LoadingState.error(res.data['message'] ?? '账号未登录');
} }
@@ -153,7 +149,7 @@ class UserHttp {
var res = await Request().get(Api.seeYouLater); var res = await Request().get(Api.seeYouLater);
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
if (res.data['data']['count'] == 0) { if (res.data['data']['count'] == 0) {
return LoadingState.empty(); return LoadingState.success([]);
} }
List<HotVideoItemModel> list = []; List<HotVideoItemModel> list = [];
for (var i in res.data['data']['list']) { for (var i in res.data['data']['list']) {

View File

@@ -67,11 +67,7 @@ class VideoHttp {
} }
} }
} }
if (list.isNotEmpty) { return LoadingState.success(list);
return LoadingState.success(list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }
@@ -161,11 +157,7 @@ class VideoHttp {
} }
} }
} }
if (list.isNotEmpty) { return LoadingState.success(list);
return LoadingState.success(list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }
@@ -189,11 +181,7 @@ class VideoHttp {
list.add(HotVideoItemModel.fromJson(i)); list.add(HotVideoItemModel.fromJson(i));
} }
} }
if (list.isNotEmpty) { return LoadingState.success(list);
return LoadingState.success(list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }
@@ -210,11 +198,7 @@ class VideoHttp {
list.add(item); list.add(item);
} }
} }
if (list.isNotEmpty) { return LoadingState.success(list);
return LoadingState.success(list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res['msg']); return LoadingState.error(res['msg']);
} }
@@ -357,11 +341,7 @@ class VideoHttp {
list.add(videoItem); list.add(videoItem);
} }
} }
if (list.isNotEmpty) { return LoadingState.success(list);
return LoadingState.success(list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }
@@ -970,11 +950,7 @@ class VideoHttp {
list.add(HotVideoItemModel.fromJson(i)); list.add(HotVideoItemModel.fromJson(i));
} }
} }
if (list.isNotEmpty) { return LoadingState.success(list);
return LoadingState.success(list);
} else {
return LoadingState.empty();
}
} else { } else {
return LoadingState.error(res.data['message']); return LoadingState.error(res.data['message']);
} }

View File

@@ -216,7 +216,7 @@ class MyApp extends StatelessWidget {
centerTitle: false, centerTitle: false,
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
backgroundColor: Platform.isIOS ? colorScheme.surface : null, backgroundColor: Platform.isIOS ? colorScheme.surface : null,
titleTextStyle: Theme.of(context).textTheme.titleMedium, titleTextStyle: TextStyle(fontSize: 16, color: colorScheme.onSurface),
), ),
navigationBarTheme: NavigationBarThemeData( navigationBarTheme: NavigationBarThemeData(
surfaceTintColor: surfaceTintColor, surfaceTintColor: surfaceTintColor,

View File

@@ -6,10 +6,5 @@ enum UpPanelPosition {
} }
extension UpPanelPositionDesc on UpPanelPosition { extension UpPanelPositionDesc on UpPanelPosition {
String get values => ['left_fixed', 'right_fixed', 'left_drawer', 'right_drawer'][index]; String get labels => ['左侧常驻', '右侧常驻', '左侧抽屉', '右侧抽屉'][index];
String get labels => ['左侧常驻','右侧常驻','左侧抽屉','右侧抽屉'][index];
}
extension UpPanelPositionCode on UpPanelPosition {
int get code => [0, 1, 2, 3][index];
} }

View File

@@ -69,31 +69,32 @@ class _BangumiIntroPanelState extends State<BangumiIntroPanel>
} }
_buildBody(LoadingState loadingState) { _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? BangumiInfo( Loading() => BangumiInfo(
heroTag: widget.heroTag, heroTag: widget.heroTag,
loadingStatus: false, loadingStatus: true,
bangumiDetail: loadingState.response, bangumiDetail: null,
cid: cid, cid: cid,
showEpisodes: widget.showEpisodes, showEpisodes: widget.showEpisodes,
showIntroDetail: () => widget.showIntroDetail( showIntroDetail: widget.showIntroDetail,
loadingState.response, ),
bangumiIntroController.videoTags, Success() => BangumiInfo(
), heroTag: widget.heroTag,
) loadingStatus: false,
: loadingState is Error bangumiDetail: loadingState.response,
? HttpError( cid: cid,
errMsg: loadingState.errMsg, showEpisodes: widget.showEpisodes,
fn: bangumiIntroController.onReload, showIntroDetail: () => widget.showIntroDetail(
) loadingState.response,
: BangumiInfo( bangumiIntroController.videoTags,
heroTag: widget.heroTag, ),
loadingStatus: true, ),
bangumiDetail: null, Error() => HttpError(
cid: cid, errMsg: loadingState.errMsg,
showEpisodes: widget.showEpisodes, callback: bangumiIntroController.onReload,
showIntroDetail: widget.showIntroDetail, ),
); LoadingState() => throw UnimplementedError(),
};
} }
} }

View File

@@ -109,17 +109,10 @@ class _BangumiPageState extends State<BangumiPage>
), ),
SizedBox( SizedBox(
height: Grid.maxRowWidth * 1, height: Grid.maxRowWidth * 1,
child: Obx(() => child: Obx(
_bangumiController.followState.value is Empty () => _buildFollowBody(
? const SizedBox( _bangumiController.followState.value),
child: Center( ),
child: Text('还没有追番'),
),
)
: _bangumiController.followState.value is Success
? _buildFollowList(_bangumiController
.followState.value as Success)
: const SizedBox()),
), ),
], ],
), ),
@@ -144,19 +137,7 @@ class _BangumiPageState extends State<BangumiPage>
padding: const EdgeInsets.fromLTRB( padding: const EdgeInsets.fromLTRB(
StyleString.safeSpace, 0, StyleString.safeSpace, 0), StyleString.safeSpace, 0, StyleString.safeSpace, 0),
sliver: Obx( sliver: Obx(
() => _bangumiController.loadingState.value is Loading () => _buildBody(_bangumiController.loadingState.value),
? 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,
),
), ),
), ),
], ],
@@ -164,6 +145,40 @@ class _BangumiPageState extends State<BangumiPage>
); );
} }
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) { Widget _buildFollowList(Success loadingState) {
return ListView.builder( return ListView.builder(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
@@ -185,24 +200,14 @@ class _BangumiPageState extends State<BangumiPage>
); );
} }
Widget contentGrid(List list) { Widget _buildFollowBody(LoadingState loadingState) {
return SliverGrid( return switch (loadingState) {
gridDelegate: SliverGridDelegateWithExtentAndRatio( Loading() => nil,
// 行间距 Success() => (loadingState.response as List?)?.isNotEmpty == true
mainAxisSpacing: StyleString.cardSpace - 2, ? _buildFollowList(loadingState)
// 列间距 : const Center(child: Text('还没有追番')),
crossAxisSpacing: StyleString.cardSpace, Error() => Center(child: Text(loadingState.errMsg)),
// 最大宽度 LoadingState() => throw UnimplementedError(),
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,
),
);
} }
} }

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/common/common_controller.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:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.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/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/http/black.dart'; import 'package:PiliPalaX/http/black.dart';
import 'package:PiliPalaX/utils/storage.dart'; import 'package:PiliPalaX/utils/storage.dart';
@@ -63,51 +63,52 @@ class _BlackListPageState extends State<BlackListPage> {
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? ListView.builder( Loading() => loadingWidget,
controller: _blackListController.scrollController, Success() => (loadingState.response as List?)?.isNotEmpty == true
itemCount: loadingState.response.length, ? ListView.builder(
itemBuilder: (BuildContext context, int index) { controller: _blackListController.scrollController,
return ListTile( itemCount: loadingState.response.length,
onTap: () {}, itemBuilder: (BuildContext context, int index) {
leading: NetworkImgLayer( return ListTile(
width: 45, onTap: () {},
height: 45, leading: NetworkImgLayer(
type: 'avatar', width: 45,
src: loadingState.response[index].face, height: 45,
), type: 'avatar',
title: Text( src: loadingState.response[index].face,
loadingState.response[index].uname!, ),
maxLines: 1, title: Text(
overflow: TextOverflow.ellipsis, loadingState.response[index].uname!,
style: const TextStyle(fontSize: 14), maxLines: 1,
), overflow: TextOverflow.ellipsis,
subtitle: Text( style: const TextStyle(fontSize: 14),
Utils.dateFormat(loadingState.response[index].mtime), ),
maxLines: 1, subtitle: Text(
style: Utils.dateFormat(loadingState.response[index].mtime),
TextStyle(color: Theme.of(context).colorScheme.outline), maxLines: 1,
overflow: TextOverflow.ellipsis, style:
), TextStyle(color: Theme.of(context).colorScheme.outline),
dense: true, overflow: TextOverflow.ellipsis,
trailing: TextButton( ),
onPressed: () => _blackListController dense: true,
.removeBlack(loadingState.response[index].mid), trailing: TextButton(
child: const Text('移除'), onPressed: () => _blackListController
), .removeBlack(loadingState.response[index].mid),
); child: const Text('移除'),
}, ),
) );
: loadingState is Error },
? CustomScrollView( )
slivers: [ : errorWidget(
HttpError( callback: _blackListController.onReload,
errMsg: loadingState.errMsg, ),
fn: _blackListController.onReload, Error() => errorWidget(
) errMsg: loadingState.errMsg,
], callback: _blackListController.onReload,
) ),
: const SizedBox(); LoadingState() => throw UnimplementedError(),
};
} }
} }
@@ -130,9 +131,7 @@ class BlackListController extends CommonController {
List dataList = currentPage == 1 List dataList = currentPage == 1
? response.response.list ? response.response.list
: currentList + response.response.list; : currentList + response.response.list;
loadingState.value = dataList.isNotEmpty loadingState.value = LoadingState.success(dataList);
? LoadingState.success(dataList)
: LoadingState.empty();
return true; return true;
} }

View File

@@ -72,21 +72,21 @@ abstract class ReplyController extends CommonController {
} }
} }
cursor = replies.cursor; 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) { if (currentPage != 1) {
List<ReplyInfo> list = loadingState.value is Success List<ReplyInfo> list = loadingState.value is Success
? (loadingState.value as Success).response.replies ? (loadingState.value as Success).response.replies
: <ReplyInfo>[]; : <ReplyInfo>[];
replies.replies.insertAll(0, list); 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); loadingState.value = LoadingState.success(replies);
return true; return true;
} }

View File

@@ -349,63 +349,68 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
} }
Widget replyList(LoadingState loadingState) { Widget replyList(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? SliverList( Loading() => SliverList(
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(context, index) { (context, index) {
if (index == loadingState.response.replies.length) { return const VideoReplySkeleton();
return Container( },
padding: EdgeInsets.only( childCount: 8,
bottom: MediaQuery.of(context).padding.bottom), ),
height: MediaQuery.of(context).padding.bottom + 100, ),
child: Center( Success() => (loadingState.response.replies as List?)?.isNotEmpty == true
child: Obx( ? SliverList(
() => Text( delegate: SliverChildBuilderDelegate(
_dynamicDetailController.noMore.value, (context, index) {
style: TextStyle( if (index == loadingState.response.replies.length) {
fontSize: 12, return Container(
color: Theme.of(context).colorScheme.outline, 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 {
} else { return ReplyItemGrpc(
return ReplyItemGrpc( replyItem: loadingState.response.replies[index],
replyItem: loadingState.response.replies[index], showReplyRow: true,
showReplyRow: true, replyLevel: '1',
replyLevel: '1', replyReply: replyReply,
replyReply: replyReply, replyType: ReplyType.values[replyType],
replyType: ReplyType.values[replyType], onReply: () {
onReply: () { _dynamicDetailController.onReply(
_dynamicDetailController.onReply( context,
context, replyItem: loadingState.response.replies[index],
replyItem: loadingState.response.replies[index], index: index,
index: index, );
); },
}, onDelete: _dynamicDetailController.onMDelete,
onDelete: _dynamicDetailController.onMDelete, isTop: _dynamicDetailController.hasUpTop && index == 0,
isTop: _dynamicDetailController.hasUpTop && index == 0, upMid: loadingState.response.subjectControl.upMid,
upMid: loadingState.response.subjectControl.upMid, );
); }
} },
}, childCount: loadingState.response.replies.length + 1,
childCount: loadingState.response.replies.length + 1, ),
)
: HttpError(
callback: _dynamicDetailController.onReload,
), ),
) Error() => HttpError(
: loadingState is Error errMsg: loadingState.errMsg,
? HttpError( callback: _dynamicDetailController.onReload,
errMsg: loadingState.errMsg, ),
fn: _dynamicDetailController.onReload, LoadingState() => throw UnimplementedError(),
) };
: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return const VideoReplySkeleton();
},
childCount: 8,
),
);
} }
} }

View File

@@ -55,11 +55,7 @@ class DynamicsTabController extends CommonController {
if (res['status']) { if (res['status']) {
List list = (loadingState.value as Success).response; List list = (loadingState.value as Success).response;
list.removeWhere((item) => item.idStr == dynamicId); list.removeWhere((item) => item.idStr == dynamicId);
if (list.isNotEmpty) { loadingState.value = LoadingState.success(list);
loadingState.value = LoadingState.success(list);
} else {
loadingState.value = LoadingState.empty();
}
SmartDialog.showToast('删除成功'); SmartDialog.showToast('删除成功');
} else { } else {
SmartDialog.showToast(res['msg']); SmartDialog.showToast(res['msg']);

View File

@@ -10,7 +10,6 @@ import 'package:flutter/rendering.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:PiliPalaX/common/constants.dart'; import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/http_error.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 'package:waterfall_flow/waterfall_flow.dart';
import '../../../common/skeleton/dynamic_card.dart'; import '../../../common/skeleton/dynamic_card.dart';
@@ -146,71 +145,74 @@ class _DynamicsTabPageState extends State<DynamicsTabPage>
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? dynamicsWaterfallFlow Loading() => skeleton(),
? SliverWaterfallFlow.extent( Success() => (loadingState.response as List?)?.isNotEmpty == true
maxCrossAxisExtent: Grid.maxRowWidth * 2, ? dynamicsWaterfallFlow
//cacheExtent: 0.0, ? SliverWaterfallFlow.extent(
crossAxisSpacing: StyleString.cardSpace / 2, maxCrossAxisExtent: Grid.maxRowWidth * 2,
mainAxisSpacing: StyleString.cardSpace / 2, //cacheExtent: 0.0,
crossAxisSpacing: StyleString.cardSpace / 2,
mainAxisSpacing: StyleString.cardSpace / 2,
lastChildLayoutTypeBuilder: (index) => lastChildLayoutTypeBuilder: (index) =>
index == loadingState.response.length index == loadingState.response.length
? LastChildLayoutType.foot ? LastChildLayoutType.foot
: LastChildLayoutType.none, : LastChildLayoutType.none,
children: [ children: [
if (dynamicsController.tabController.index == 4 && if (dynamicsController.tabController.index == 4 &&
dynamicsController.mid.value != -1) ...[ dynamicsController.mid.value != -1) ...[
for (var i in loadingState.response) 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))
DynamicPanel( DynamicPanel(
item: i, item: i,
onRemove: _dynamicsTabController.onRemove, onRemove: _dynamicsTabController.onRemove,
), ),
] ] else ...[
], for (var i in loadingState.response)
) if (!dynamicsController.tempBannedList
: SliverCrossAxisGroup( .contains(i.modules?.moduleAuthor?.mid))
slivers: [ DynamicPanel(
const SliverFillRemaining(), item: i,
SliverConstrainedCrossAxis( onRemove: _dynamicsTabController.onRemove,
maxExtent: Grid.maxRowWidth * 2, ),
sliver: SliverList( ]
delegate: SliverChildBuilderDelegate( ],
(context, index) { )
if ((dynamicsController.tabController.index == 4 && : SliverCrossAxisGroup(
dynamicsController.mid.value != -1) || slivers: [
!dynamicsController.tempBannedList.contains( const SliverFillRemaining(),
loadingState.response[index].modules SliverConstrainedCrossAxis(
?.moduleAuthor?.mid)) { maxExtent: Grid.maxRowWidth * 2,
return DynamicPanel( sliver: SliverList(
item: loadingState.response[index], delegate: SliverChildBuilderDelegate(
onRemove: _dynamicsTabController.onRemove, (context, index) {
); if ((dynamicsController.tabController.index == 4 &&
} dynamicsController.mid.value != -1) ||
return const SizedBox(); !dynamicsController.tempBannedList.contains(
}, loadingState.response[index].modules
childCount: loadingState.response.length, ?.moduleAuthor?.mid)) {
return DynamicPanel(
item: loadingState.response[index],
onRemove: _dynamicsTabController.onRemove,
);
}
return const SizedBox();
},
childCount: loadingState.response.length,
),
), ),
), ),
), const SliverFillRemaining(),
const SliverFillRemaining(), ],
], )
) : HttpError(
: loadingState is Empty callback: _dynamicsTabController.onReload,
? const NoData() ),
: loadingState is Error Error() => HttpError(
? HttpError( errMsg: loadingState.errMsg,
errMsg: loadingState.errMsg, callback: _dynamicsTabController.onReload,
fn: _dynamicsTabController.onReload, ),
) LoadingState() => throw UnimplementedError(),
: skeleton(); };
} }
} }

View File

@@ -15,6 +15,7 @@ import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/storage.dart'; import 'package:PiliPalaX/utils/storage.dart';
import 'package:image_picker/image_picker.dart'; import 'package:image_picker/image_picker.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:nil/nil.dart';
import 'controller.dart'; import 'controller.dart';
import 'widgets/up_panel.dart'; import 'widgets/up_panel.dart';
@@ -98,7 +99,7 @@ class _DynamicsPageState extends State<DynamicsPage>
}); });
upPanelPosition = UpPanelPosition.values[setting.get( upPanelPosition = UpPanelPosition.values[setting.get(
SettingBoxKey.upPanelPosition, SettingBoxKey.upPanelPosition,
defaultValue: UpPanelPosition.leftFixed.code)]; defaultValue: UpPanelPosition.leftFixed.index)];
debugPrint('upPanelPosition: $upPanelPosition'); debugPrint('upPanelPosition: $upPanelPosition');
if (GStorage.setting if (GStorage.setting
.get(SettingBoxKey.dynamicsShowAllFollowedUp, defaultValue: false)) { .get(SettingBoxKey.dynamicsShowAllFollowedUp, defaultValue: false)) {
@@ -128,7 +129,7 @@ class _DynamicsPageState extends State<DynamicsPage>
padding: const EdgeInsets.symmetric(horizontal: 4), padding: const EdgeInsets.symmetric(horizontal: 4),
child: Container( child: Container(
//抽屉模式增加底色 //抽屉模式增加底色
color: upPanelPosition.code > 1 color: upPanelPosition.index > 1
? Theme.of(context).colorScheme.surface ? Theme.of(context).colorScheme.surface
: Colors.transparent, : Colors.transparent,
width: 56, width: 56,
@@ -137,20 +138,27 @@ class _DynamicsPageState extends State<DynamicsPage>
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.data == null) { if (snapshot.data == null) {
return const SizedBox(); return nil;
} }
Map data = snapshot.data; Map data = snapshot.data;
if (data['status']) { if (data['status']) {
return Obx(() => UpPanel(_dynamicsController.upData.value, return Obx(() => UpPanel(_dynamicsController.upData.value,
_dynamicsController.scrollController)); _dynamicsController.scrollController));
} else { } else {
return const SizedBox(); return Center(
child: IconButton(
icon: Icon(Icons.refresh),
onPressed: () {
setState(() {
_futureBuilderFutureUp =
_dynamicsController.queryFollowUp();
});
},
),
);
} }
} else { } else {
return const SizedBox( return nil;
width: 56,
child: UpPanelSkeleton(),
);
} }
}, },
), ),

View File

@@ -1,3 +1,4 @@
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/video/reply/emote.dart'; import 'package:PiliPalaX/models/video/reply/emote.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -28,90 +29,99 @@ class _EmotePanelState extends State<EmotePanel>
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? Column( Loading() => loadingWidget,
children: [ Success() => (loadingState.response as List?)?.isNotEmpty == true
Expanded( ? Column(
child: TabBarView( children: [
controller: _emotePanelController.tabController, Expanded(
children: (loadingState.response as List<Packages>).map( child: TabBarView(
(e) { controller: _emotePanelController.tabController,
int size = e.emote!.first.meta!.size!; children: (loadingState.response as List<Packages>).map(
int type = e.type!; (e) {
return Padding( int size = e.emote!.first.meta!.size!;
padding: const EdgeInsets.fromLTRB(12, 6, 12, 0), int type = e.type!;
child: GridView.builder( return Padding(
gridDelegate: padding: const EdgeInsets.fromLTRB(12, 6, 12, 0),
SliverGridDelegateWithMaxCrossAxisExtent( child: GridView.builder(
maxCrossAxisExtent: gridDelegate:
type == 4 ? 100 : (size == 1 ? 40 : 60), SliverGridDelegateWithMaxCrossAxisExtent(
crossAxisSpacing: 8, maxCrossAxisExtent:
mainAxisSpacing: 8, type == 4 ? 100 : (size == 1 ? 40 : 60),
mainAxisExtent: size == 1 ? 40 : 60, crossAxisSpacing: 8,
), mainAxisSpacing: 8,
itemCount: e.emote!.length, mainAxisExtent: size == 1 ? 40 : 60,
itemBuilder: (context, index) { ),
return Material( itemCount: e.emote!.length,
color: Colors.transparent, itemBuilder: (context, index) {
child: InkWell( return Material(
borderRadius: BorderRadius.circular(8), color: Colors.transparent,
onTap: () { child: InkWell(
widget.onChoose(e, e.emote![index]); borderRadius: BorderRadius.circular(8),
}, onTap: () {
child: Padding( widget.onChoose(e, e.emote![index]);
padding: const EdgeInsets.all(6), },
child: type == 4 child: Padding(
? Center( padding: const EdgeInsets.all(6),
child: Text( child: type == 4
e.emote![index].text!, ? Center(
overflow: TextOverflow.clip, child: Text(
maxLines: 1, 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(
Divider( height: 1,
height: 1, color: Theme.of(context).dividerColor.withOpacity(0.1),
color: Theme.of(context).dividerColor.withOpacity(0.1), ),
), TabBar(
TabBar( controller: _emotePanelController.tabController,
controller: _emotePanelController.tabController, dividerColor: Colors.transparent,
dividerColor: Colors.transparent, isScrollable: true,
isScrollable: true, tabs: (loadingState.response as List<Packages>)
tabs: (loadingState.response as List<Packages>) .map(
.map( (e) => Padding(
(e) => Padding( padding: const EdgeInsets.all(8),
padding: const EdgeInsets.all(8), child: NetworkImgLayer(
child: NetworkImgLayer( width: 24,
width: 24, height: 24,
height: 24, type: 'emote',
type: 'emote', src: e.url,
src: e.url, ),
), ),
), )
) .toList(),
.toList(), ),
), SizedBox(height: MediaQuery.of(context).padding.bottom),
SizedBox(height: MediaQuery.of(context).padding.bottom), ],
], )
) : errorWidget(
: loadingState is Error callback: _emotePanelController.onReload,
? Center(child: Text(loadingState.errMsg)) ),
: const Center(child: Text('加载中...')); Error() => errorWidget(
errMsg: loadingState.errMsg,
callback: _emotePanelController.onReload,
),
LoadingState() => throw UnimplementedError(),
};
} }
} }

View File

@@ -4,7 +4,6 @@ import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/common/widgets/no_data.dart';
import '../../common/constants.dart'; import '../../common/constants.dart';
import '../../utils/grid.dart'; import '../../utils/grid.dart';
@@ -67,33 +66,32 @@ class _FansPageState extends State<FansPage> {
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? loadingState.response.isNotEmpty Loading() => HttpError(
? SliverGrid( callback: _fansController.onReload,
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( ),
mainAxisSpacing: StyleString.cardSpace, Success() => (loadingState.response as List?)?.isNotEmpty == true
crossAxisSpacing: StyleString.safeSpace, ? SliverGrid(
maxCrossAxisExtent: Grid.maxRowWidth * 2, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
mainAxisExtent: 56), mainAxisSpacing: StyleString.cardSpace,
delegate: SliverChildBuilderDelegate( crossAxisSpacing: StyleString.safeSpace,
(BuildContext context, int index) { maxCrossAxisExtent: Grid.maxRowWidth * 2,
return fanItem(item: loadingState.response[index]); mainAxisExtent: 56),
}, delegate: SliverChildBuilderDelegate(
childCount: loadingState.response.length, (BuildContext context, int index) {
)) return fanItem(item: loadingState.response[index]);
: const NoData() },
: loadingState is Error childCount: loadingState.response.length,
? HttpError( ),
errMsg: loadingState.errMsg, )
fn: _fansController.onReload, : HttpError(
) callback: _fansController.onReload,
: const SliverToBoxAdapter( ),
child: SizedBox( Error() => HttpError(
height: 200, errMsg: loadingState.errMsg,
child: Center( callback: _fansController.onReload,
child: CircularProgressIndicator(), ),
), LoadingState() => throw UnimplementedError(),
), };
);
} }
} }

View File

@@ -108,63 +108,68 @@ class _FavPageState extends State<FavPage> {
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? SliverGrid( Loading() => SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio( gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace, mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.safeSpace, crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2, maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4, childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0), mainAxisExtent: 0),
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
childCount: loadingState.response.length, (BuildContext context, int index) {
(BuildContext context, int index) { return const VideoCardHSkeleton();
String heroTag = },
Utils.makeHeroTag(loadingState.response[index].fid); childCount: 10,
return FavItem( ),
heroTag: heroTag, ),
favFolderItem: loadingState.response[index], Success() => (loadingState.response as List?)?.isNotEmpty == true
onTap: () { ? SliverGrid(
Get.toNamed( gridDelegate: SliverGridDelegateWithExtentAndRatio(
'/favDetail', mainAxisSpacing: StyleString.cardSpace,
arguments: loadingState.response[index], crossAxisSpacing: StyleString.safeSpace,
parameters: { maxCrossAxisExtent: Grid.maxRowWidth * 2,
'heroTag': heroTag, childAspectRatio: StyleString.aspectRatio * 2.4,
'mediaId': loadingState.response[index].id.toString(), mainAxisExtent: 0),
}, delegate: SliverChildBuilderDelegate(
)?.then((res) { childCount: loadingState.response.length,
if (res == true) { (BuildContext context, int index) {
List list = String heroTag =
(_favController.loadingState.value as Success) Utils.makeHeroTag(loadingState.response[index].fid);
.response; return FavItem(
list.removeAt(index); heroTag: heroTag,
_favController.loadingState.value = favFolderItem: loadingState.response[index],
LoadingState.success(list); 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,
), ),
) Error() => HttpError(
: loadingState is Error errMsg: loadingState.errMsg,
? HttpError( callback: _favController.onReload,
errMsg: loadingState.errMsg, ),
fn: _favController.onReload, LoadingState() => throw UnimplementedError(),
) };
: 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,
),
);
} }
} }

View File

@@ -238,52 +238,27 @@ class _FavDetailPageState extends State<FavDetailPage> {
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? loadingState.response.isEmpty Loading() => SliverGrid(
? const SliverToBoxAdapter(child: SizedBox()) gridDelegate: SliverGridDelegateWithExtentAndRatio(
: SliverPadding( mainAxisSpacing: StyleString.cardSpace,
padding: EdgeInsets.only( crossAxisSpacing: StyleString.safeSpace,
bottom: MediaQuery.of(context).padding.bottom), maxCrossAxisExtent: Grid.maxRowWidth * 2,
sliver: SliverGrid( childAspectRatio: StyleString.aspectRatio * 2.4,
gridDelegate: SliverGridDelegateWithExtentAndRatio( mainAxisExtent: 0,
mainAxisSpacing: StyleString.cardSpace, ),
crossAxisSpacing: StyleString.safeSpace, delegate: SliverChildBuilderDelegate(
maxCrossAxisExtent: Grid.maxRowWidth * 2, (context, index) {
childAspectRatio: StyleString.aspectRatio * 2.4, return const VideoCardHSkeleton();
mainAxisExtent: 0, },
), childCount: 10,
delegate: SliverChildBuilderDelegate( ),
(context, index) { ),
if (index == loadingState.response.length) { Success() => (loadingState.response as List?)?.isNotEmpty == true
return Container( ? SliverPadding(
height: 60, padding: EdgeInsets.only(
alignment: Alignment.center, bottom: MediaQuery.of(context).padding.bottom),
child: Obx( sliver: SliverGrid(
() => 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(
gridDelegate: SliverGridDelegateWithExtentAndRatio( gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace, mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.safeSpace, crossAxisSpacing: StyleString.safeSpace,
@@ -293,10 +268,38 @@ class _FavDetailPageState extends State<FavDetailPage> {
), ),
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(context, index) { (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(),
};
} }
} }

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/common/constants.dart'; 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/http/loading_state.dart';
import 'package:PiliPalaX/pages/follow/widgets/follow_item.dart'; import 'package:PiliPalaX/pages/follow/widgets/follow_item.dart';
import 'package:PiliPalaX/pages/history/widgets/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:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.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 'package:PiliPalaX/pages/fav_detail/widget/fav_video_card.dart';
import 'controller.dart'; import 'controller.dart';
@@ -83,88 +82,76 @@ class _FavSearchPageState extends State<FavSearchPage> {
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? loadingState.response.isEmpty Loading() => loadingWidget,
? CustomScrollView( Success() => (loadingState.response as List?)?.isNotEmpty == true
slivers: <Widget>[ ? _favSearchCtr.searchType == SearchType.fav
HttpError( ? ListView.builder(
errMsg: '没有数据', controller: _favSearchCtr.scrollController,
fn: _favSearchCtr.onReload, itemCount: loadingState.response.length + 1,
), itemBuilder: (context, index) {
], if (index == loadingState.response.length) {
) return Container(
: _favSearchCtr.searchType == SearchType.fav height: MediaQuery.of(context).padding.bottom + 60,
? ListView.builder( padding: EdgeInsets.only(
controller: _favSearchCtr.scrollController, bottom: MediaQuery.of(context).padding.bottom,
itemCount: loadingState.response.length + 1, ),
itemBuilder: (context, index) { );
if (index == loadingState.response.length) { } else {
return Container( return FavVideoCardH(
height: MediaQuery.of(context).padding.bottom + 60, videoItem: loadingState.response[index],
padding: EdgeInsets.only( searchType: _favSearchCtr.type,
bottom: MediaQuery.of(context).padding.bottom, 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], : CustomScrollView(
searchType: _favSearchCtr.type, physics: const AlwaysScrollableScrollPhysics(),
callFn: () => _favSearchCtr.type != 1 controller: _favSearchCtr.scrollController,
? _favSearchCtr slivers: [
.onCancelFav(loadingState.response[index].id!) SliverGrid(
: {}, gridDelegate: SliverGridDelegateWithExtentAndRatio(
); mainAxisSpacing: StyleString.cardSpace,
} crossAxisSpacing: StyleString.safeSpace,
}, maxCrossAxisExtent: Grid.maxRowWidth * 2,
) childAspectRatio: StyleString.aspectRatio * 2.4,
: _favSearchCtr.searchType == SearchType.follow mainAxisExtent: 0),
? ListView.builder( delegate: SliverChildBuilderDelegate(
controller: _favSearchCtr.scrollController, (context, index) {
itemCount: loadingState.response.length, return HistoryItem(
itemBuilder: ((context, index) { videoItem: loadingState.response[index],
return FollowItem( ctr: _favSearchCtr,
item: loadingState.response[index], onChoose: null,
); onUpdateMultiple: () => null,
}), );
) },
: CustomScrollView( childCount: loadingState.response.length,
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( : errorWidget(
slivers: <Widget>[ callback: _favSearchCtr.onReload,
HttpError( ),
errMsg: loadingState.errMsg, Error() => errorWidget(
fn: _favSearchCtr.onReload, errMsg: loadingState.errMsg,
), callback: _favSearchCtr.onReload,
], ),
) LoadingState() => throw UnimplementedError(),
: const CustomScrollView( };
slivers: <Widget>[
NoData(),
],
);
} }
} }

View File

@@ -1,9 +1,8 @@
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:easy_debounce/easy_throttle.dart'; import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.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/models/follow/result.dart';
import 'package:PiliPalaX/pages/follow/index.dart'; import 'package:PiliPalaX/pages/follow/index.dart';
@@ -92,16 +91,14 @@ class _FollowListState extends State<FollowList> {
} }
}, },
) )
: const CustomScrollView(slivers: [NoData()]), : errorWidget(
callback: () => widget.ctr.queryFollowings('init'),
),
); );
} else { } else {
return CustomScrollView( return errorWidget(
slivers: [ errMsg: data['msg'],
HttpError( callback: () => widget.ctr.queryFollowings('init'),
errMsg: data['msg'],
fn: () => widget.ctr.queryFollowings('init'),
)
],
); );
} }
} else { } else {

View File

@@ -1,9 +1,8 @@
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:easy_debounce/easy_throttle.dart'; import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.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/http/member.dart';
import 'package:PiliPalaX/models/follow/result.dart'; import 'package:PiliPalaX/models/follow/result.dart';
import 'package:PiliPalaX/models/member/tags.dart'; import 'package:PiliPalaX/models/member/tags.dart';
@@ -110,16 +109,14 @@ class _OwnerFollowListState extends State<OwnerFollowList>
} }
}, },
) )
: const CustomScrollView(slivers: [NoData()]), : errorWidget(
callback: () => widget.ctr.queryFollowings('init'),
),
); );
} else { } else {
return CustomScrollView( return errorWidget(
slivers: [ errMsg: data['msg'],
HttpError( callback: () => widget.ctr.queryFollowings('init'),
errMsg: data['msg'],
fn: () => widget.ctr.queryFollowings('init'),
)
],
); );
} }
} else { } else {

View File

@@ -1,11 +1,10 @@
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart'; import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:PiliPalaX/pages/fav_search/view.dart' show SearchType; import 'package:PiliPalaX/pages/fav_search/view.dart' show SearchType;
import 'package:easy_debounce/easy_throttle.dart'; import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:PiliPalaX/common/skeleton/video_card_h.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 'package:PiliPalaX/pages/history/index.dart';
import '../../common/constants.dart'; import '../../common/constants.dart';
@@ -215,12 +214,20 @@ class _HistoryPageState extends State<HistoryPage> {
? const SliverToBoxAdapter( ? const SliverToBoxAdapter(
child: Center(child: Text('加载中')), child: Center(child: Text('加载中')),
) )
: const NoData(), : HttpError(
callback: () => setState(() {
_futureBuilderFuture =
_historyController.queryHistoryList();
}),
),
); );
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() {}), callback: () => setState(() {
_futureBuilderFuture =
_historyController.queryHistoryList();
}),
); );
} }
} else { } else {

View File

@@ -91,7 +91,7 @@ class _HotPageState extends State<HotPage> with AutomaticKeepAliveClientMixin {
? (_hotController.loadingState.value as Error) ? (_hotController.loadingState.value as Error)
.errMsg .errMsg
: '没有相关数据', : '没有相关数据',
fn: _hotController.onReload, callback: _hotController.onReload,
), ),
), ),
), ),

View File

@@ -320,59 +320,64 @@ class _HtmlRenderPageState extends State<HtmlRenderPage>
} }
Widget replyList(LoadingState loadingState) { Widget replyList(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? SliverList.builder( Loading() => SliverList.builder(
itemCount: loadingState.response.replies.length + 1, itemCount: 5,
itemBuilder: (context, index) { itemBuilder: (context, index) {
if (index == loadingState.response.replies.length) { return const VideoReplySkeleton();
return Container( },
padding: EdgeInsets.only( ),
bottom: MediaQuery.of(context).padding.bottom), Success() => (loadingState.response.replies as List?)?.isNotEmpty == true
height: MediaQuery.of(context).padding.bottom + 100, ? SliverList.builder(
child: Center( itemCount: loadingState.response.replies.length + 1,
child: Obx( itemBuilder: (context, index) {
() => Text( if (index == loadingState.response.replies.length) {
_htmlRenderCtr.noMore.value, return Container(
style: TextStyle( padding: EdgeInsets.only(
fontSize: 12, bottom: MediaQuery.of(context).padding.bottom),
color: Theme.of(context).colorScheme.outline, 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 {
} else { return ReplyItemGrpc(
return ReplyItemGrpc( replyItem: loadingState.response.replies[index],
replyItem: loadingState.response.replies[index], showReplyRow: true,
showReplyRow: true, replyLevel: '1',
replyLevel: '1', replyReply: replyReply,
replyReply: replyReply, replyType: ReplyType.values[type],
replyType: ReplyType.values[type], onReply: () {
onReply: () { _htmlRenderCtr.onReply(
_htmlRenderCtr.onReply( context,
context, replyItem: loadingState.response.replies[index],
replyItem: loadingState.response.replies[index], index: index,
index: index, );
); },
}, onDelete: _htmlRenderCtr.onMDelete,
onDelete: _htmlRenderCtr.onMDelete, isTop: _htmlRenderCtr.hasUpTop && index == 0,
isTop: _htmlRenderCtr.hasUpTop && index == 0, upMid: loadingState.response.subjectControl.upMid,
upMid: loadingState.response.subjectControl.upMid, );
); }
} },
}, )
) : HttpError(
: loadingState is Error callback: _htmlRenderCtr.onReload,
? HttpError( ),
errMsg: loadingState.errMsg, Error() => HttpError(
fn: _htmlRenderCtr.onReload, errMsg: loadingState.errMsg,
) callback: _htmlRenderCtr.onReload,
: SliverList.builder( ),
itemCount: 5, LoadingState() => throw UnimplementedError(),
itemBuilder: (context, index) { };
return const VideoReplySkeleton();
},
);
} }
Container replyHeader() { Container replyHeader() {

View File

@@ -88,7 +88,7 @@ class LaterController extends CommonController {
onPressed: () async { onPressed: () async {
var res = await UserHttp.toViewClear(); var res = await UserHttp.toViewClear();
if (res['status']) { if (res['status']) {
loadingState.value = LoadingState.empty(); loadingState.value = LoadingState.success([]);
} }
Get.back(); Get.back();
SmartDialog.showToast(res['msg']); SmartDialog.showToast(res['msg']);

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:PiliPalaX/common/skeleton/video_card_h.dart'; import 'package:PiliPalaX/common/skeleton/video_card_h.dart';
import 'package:PiliPalaX/common/widgets/http_error.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/common/widgets/video_card_h.dart';
import 'package:PiliPalaX/pages/later/index.dart'; import 'package:PiliPalaX/pages/later/index.dart';
@@ -74,48 +73,51 @@ class _LaterPageState extends State<LaterPage> {
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? SliverGrid( Loading() => SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio( gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.safeSpace, mainAxisSpacing: StyleString.safeSpace,
crossAxisSpacing: StyleString.safeSpace, crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2, maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4, childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0, 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( Error() => HttpError(
(context, index) { errMsg: loadingState.errMsg,
var videoItem = loadingState.response[index]; callback: _laterController.onReload,
return VideoCardH( ),
videoItem: videoItem, LoadingState() => throw UnimplementedError(),
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,
),
);
} }
} }

View File

@@ -1,6 +1,6 @@
import 'package:PiliPalaX/common/constants.dart'; 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/refresh_indicator.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/space_article/item.dart'; import 'package:PiliPalaX/models/space_article/item.dart';
@@ -40,79 +40,75 @@ class _MemberArticleState extends State<MemberArticle>
} }
_buildBody(LoadingState loadingState) { _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? MediaQuery.removePadding( Loading() => loadingWidget,
context: context, Success() => (loadingState.response as List?)?.isNotEmpty == true
removeTop: true, ? MediaQuery.removePadding(
child: refreshIndicator( context: context,
onRefresh: () async { removeTop: true,
await _controller.onRefresh(); child: refreshIndicator(
}, onRefresh: () async {
child: ListView.separated( await _controller.onRefresh();
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), child: ListView.separated(
), itemCount: loadingState.response.length,
), itemBuilder: (_, index) {
) if (index == loadingState.response.length - 1) {
: loadingState is Error _controller.onLoadMore();
? Center( }
child: CustomScrollView( Item item = loadingState.response[index];
shrinkWrap: true, return ListTile(
slivers: [ dense: true,
HttpError( onTap: () {
errMsg: loadingState.errMsg, PiliScheme.routePush(Uri.parse(item.uri ?? ''));
fn: _controller.onReload, },
), 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(),
};
} }
} }

View File

@@ -1,6 +1,6 @@
import 'package:PiliPalaX/common/constants.dart'; 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/refresh_indicator.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/bangumi/widgets/bangumi_card_v_member_home.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'; import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/bangumi/member_bangumi_ctr.dart';
@@ -42,60 +42,56 @@ class _MemberBangumiState extends State<MemberBangumi>
} }
_buildBody(LoadingState loadingState) { _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? refreshIndicator( Loading() => loadingWidget,
onRefresh: () async { Success() => (loadingState.response as List?)?.isNotEmpty == true
await _controller.onRefresh(); ? refreshIndicator(
}, onRefresh: () async {
child: CustomScrollView( await _controller.onRefresh();
slivers: [ },
SliverPadding( child: CustomScrollView(
padding: EdgeInsets.only( slivers: [
left: StyleString.safeSpace, SliverPadding(
right: StyleString.safeSpace, padding: EdgeInsets.only(
top: StyleString.safeSpace, left: StyleString.safeSpace,
bottom: StyleString.safeSpace + right: StyleString.safeSpace,
MediaQuery.of(context).padding.bottom, top: StyleString.safeSpace,
), bottom: StyleString.safeSpace +
sliver: SliverGrid( MediaQuery.of(context).padding.bottom,
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( sliver: SliverGrid(
(context, index) { gridDelegate: SliverGridDelegateWithExtentAndRatio(
if (index == loadingState.response.length - 1) { mainAxisSpacing: StyleString.cardSpace - 2,
_controller.onLoadMore(); crossAxisSpacing: StyleString.cardSpace,
} maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2,
return BangumiCardVMemberHome( childAspectRatio: 0.65,
bangumiItem: loadingState.response[index], mainAxisExtent:
); MediaQuery.textScalerOf(context).scale(60),
}, ),
childCount: loadingState.response.length, 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,
), ),
) Error() => errorWidget(
: loadingState is Error errMsg: loadingState.errMsg,
? Center( callback: _controller.onReload,
child: CustomScrollView( ),
shrinkWrap: true, LoadingState() => throw UnimplementedError(),
slivers: [ };
HttpError(
errMsg: loadingState.errMsg,
fn: _controller.onReload,
),
],
),
)
: Center(
child: CircularProgressIndicator(),
);
} }
} }

View File

@@ -1,7 +1,7 @@
import 'package:PiliPalaX/common/constants.dart'; import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/badge.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/refresh_indicator.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/space_fav/datum.dart'; import 'package:PiliPalaX/models/space_fav/datum.dart';
@@ -44,54 +44,50 @@ class _MemberFavoriteState extends State<MemberFavorite>
} }
_buildBody(LoadingState loadingState) { _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? refreshIndicator( Loading() => loadingWidget,
onRefresh: () async { Success() => (loadingState.response as List?)?.isNotEmpty == true
await _controller.onRefresh(); ? refreshIndicator(
}, onRefresh: () async {
child: CustomScrollView( await _controller.onRefresh();
slivers: [ },
SliverToBoxAdapter( child: CustomScrollView(
child: Obx( slivers: [
() => _controller.first.value.mediaListResponse?.list SliverToBoxAdapter(
?.isNotEmpty == child: Obx(
true () => _controller.first.value.mediaListResponse?.list
? _buildItem(_controller.first.value, true) ?.isNotEmpty ==
: const SizedBox.shrink(), 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,
), ),
], ),
), SliverToBoxAdapter(
) child: Obx(
: Center( () => _controller.second.value.mediaListResponse?.list
child: CircularProgressIndicator(), ?.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) { _buildItem(Datum data, bool isFirst) {

View File

@@ -1,6 +1,6 @@
import 'package:PiliPalaX/common/constants.dart'; 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/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/common/widgets/video_card_h_member_video.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/video/member_video_ctr.dart'; import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/video/member_video_ctr.dart';
@@ -54,106 +54,100 @@ class _MemberVideoState extends State<MemberVideo>
} }
_buildBody(LoadingState loadingState) { _buildBody(LoadingState loadingState) {
return loadingState is Success && loadingState.response is List return switch (loadingState) {
? refreshIndicator( Loading() => loadingWidget,
onRefresh: () async { Success() => (loadingState.response as List?)?.isNotEmpty == true
await _controller.onRefresh(); ? refreshIndicator(
}, onRefresh: () async {
child: CustomScrollView( await _controller.onRefresh();
slivers: [ },
SliverPersistentHeader( child: CustomScrollView(
pinned: false, slivers: [
floating: true, SliverPersistentHeader(
delegate: MySliverPersistentHeaderDelegate( pinned: false,
child: Container( floating: true,
height: 40, delegate: MySliverPersistentHeaderDelegate(
padding: const EdgeInsets.fromLTRB(12, 0, 6, 0), child: Container(
color: Theme.of(context).colorScheme.surface, height: 40,
child: Row( padding: const EdgeInsets.fromLTRB(12, 0, 6, 0),
mainAxisAlignment: MainAxisAlignment.spaceBetween, color: Theme.of(context).colorScheme.surface,
children: [ child: Row(
Obx( mainAxisAlignment: MainAxisAlignment.spaceBetween,
() => Text( children: [
_controller.count.value != -1 Obx(
? '${_controller.count.value}视频' () => Text(
: '', _controller.count.value != -1
style: const TextStyle(fontSize: 13), ? '${_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),
),
), ),
), ),
) 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(
SliverPadding( // 单列布局 EdgeInsets.zero
// 单列布局 EdgeInsets.zero padding: EdgeInsets.fromLTRB(
padding: EdgeInsets.fromLTRB( StyleString.safeSpace,
StyleString.safeSpace, StyleString.safeSpace - 5,
StyleString.safeSpace - 5, StyleString.safeSpace,
StyleString.safeSpace, MediaQuery.of(context).padding.bottom + 10,
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,
), ),
delegate: SliverChildBuilderDelegate( sliver: SliverGrid(
(context, index) { gridDelegate: SliverGridDelegateWithExtentAndRatio(
if (widget.type != ContributeType.season && mainAxisSpacing: StyleString.safeSpace,
index == loadingState.response.length - 1) { crossAxisSpacing: StyleString.safeSpace,
_controller.onLoadMore(); maxCrossAxisExtent: Grid.maxRowWidth * 2,
} childAspectRatio: StyleString.aspectRatio * 2.4,
return VideoCardHMemberVideo( mainAxisExtent: 0,
videoItem: loadingState.response[index], ),
showPubdate: true, delegate: SliverChildBuilderDelegate(
); (context, index) {
}, if (widget.type != ContributeType.season &&
childCount: loadingState.response.length, index == loadingState.response.length - 1) {
_controller.onLoadMore();
}
return VideoCardHMemberVideo(
videoItem: loadingState.response[index],
showPubdate: true,
);
},
childCount: loadingState.response.length,
),
), ),
), ),
), ],
], ),
)
: errorWidget(
callback: _controller.onReload,
), ),
) Error() => errorWidget(
: loadingState is Loading errMsg: loadingState.errMsg,
? Center( callback: _controller.onReload,
child: CircularProgressIndicator(), ),
) LoadingState() => throw UnimplementedError(),
: Center( };
child: CustomScrollView(
shrinkWrap: true,
slivers: [
HttpError(
errMsg: loadingState is Error
? (loadingState as Error?)?.errMsg
: 'EMPTY',
fn: _controller.onReload,
),
],
),
);
} }
} }

View File

@@ -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/refresh_indicator.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/pages/dynamics/widgets/dynamic_panel_grpc.dart'; import 'package:PiliPalaX/pages/dynamics/widgets/dynamic_panel_grpc.dart';
import 'package:PiliPalaX/pages/member/new/content/member_dynamic/member_dynamic_ctr.dart'; import 'package:PiliPalaX/pages/member/new/content/member_dynamic/member_dynamic_ctr.dart';
@@ -32,38 +32,34 @@ class _MemberDynamicState extends State<MemberDynamic>
} }
_buildBody(LoadingState loadingState) { _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? refreshIndicator( Loading() => loadingWidget,
onRefresh: () async { Success() => (loadingState.response as List?)?.isNotEmpty == true
await _controller.onRefresh(); ? refreshIndicator(
}, onRefresh: () async {
child: ListView.separated( await _controller.onRefresh();
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), 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,
), ),
) Error() => errorWidget(
: loadingState is Error errMsg: loadingState.errMsg,
? Center( callback: _controller.onReload,
child: CustomScrollView( ),
shrinkWrap: true, LoadingState() => throw UnimplementedError(),
slivers: [ };
HttpError(
errMsg: loadingState.errMsg,
fn: _controller.onReload,
),
],
),
)
: Center(
child: CircularProgressIndicator(),
);
} }
} }

View File

@@ -1,6 +1,7 @@
import 'dart:math'; import 'dart:math';
import 'package:PiliPalaX/common/constants.dart'; 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/network_img_layer.dart';
import 'package:PiliPalaX/common/widgets/video_card_v_member_home.dart'; import 'package:PiliPalaX/common/widgets/video_card_v_member_home.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
@@ -39,171 +40,183 @@ class _MemberHomeState extends State<MemberHome>
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success && loadingState.response is Data return switch (loadingState) {
? CustomScrollView( Loading() => loadingWidget,
slivers: [ Success() => loadingState.response is Data
if (loadingState.response?.archive?.item?.isNotEmpty == true) ...[ ? CustomScrollView(
_videoHeader( slivers: [
title: '视频', if (loadingState.response?.archive?.item?.isNotEmpty ==
param: 'contribute', true) ...[
param1: 'video', _videoHeader(
count: loadingState.response.archive.count, title: '视频',
), param: 'contribute',
SliverPadding( param1: 'video',
padding: const EdgeInsets.symmetric( count: loadingState.response.archive.count,
horizontal: StyleString.safeSpace,
), ),
sliver: SliverGrid( SliverPadding(
gridDelegate: SliverGridDelegateWithExtentAndRatio( padding: const EdgeInsets.symmetric(
mainAxisSpacing: StyleString.cardSpace, horizontal: StyleString.safeSpace,
crossAxisSpacing: StyleString.cardSpace,
maxCrossAxisExtent: Grid.maxRowWidth,
childAspectRatio: StyleString.aspectRatio,
mainAxisExtent:
MediaQuery.textScalerOf(context).scale(90),
), ),
delegate: SliverChildBuilderDelegate( sliver: SliverGrid(
(context, index) { gridDelegate: SliverGridDelegateWithExtentAndRatio(
return VideoCardVMemberHome( mainAxisSpacing: StyleString.cardSpace,
videoItem: loadingState.response.archive.item[index], crossAxisSpacing: StyleString.cardSpace,
); maxCrossAxisExtent: Grid.maxRowWidth,
}, childAspectRatio: StyleString.aspectRatio,
childCount: mainAxisExtent:
min(4, loadingState.response.archive.item.length), MediaQuery.textScalerOf(context).scale(90),
), ),
), delegate: SliverChildBuilderDelegate(
), (context, index) {
], return VideoCardVMemberHome(
if (loadingState.response?.favourite2?.item?.isNotEmpty == videoItem:
true) ...[ loadingState.response.archive.item[index],
_videoHeader( );
title: '收藏', },
param: 'favorite', childCount:
count: loadingState.response.favourite2.count, min(4, loadingState.response.archive.item.length),
),
// 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,
), ),
), ),
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?.favourite2?.item?.isNotEmpty ==
if (loadingState.response?.audios?.item?.isNotEmpty == true) ...[ true) ...[
_videoHeader( _videoHeader(
title: '音频', title: '收藏',
param: 'contribute', param: 'favorite',
param1: 'audio', count: loadingState.response.favourite2.count,
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( // TODO
gridDelegate: SliverGridDelegateWithExtentAndRatio( ],
mainAxisSpacing: StyleString.cardSpace - 2, if (loadingState.response?.coinArchive?.item?.isNotEmpty ==
crossAxisSpacing: StyleString.cardSpace, true) ...[
maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2, _videoHeader(
childAspectRatio: 0.65, title: '最近投币的视频',
mainAxisExtent: param: 'coinArchive',
MediaQuery.textScalerOf(context).scale(60), count: loadingState.response.coinArchive.count,
), ),
delegate: SliverChildBuilderDelegate( // TODO
(context, index) { ],
return BangumiCardVMemberHome( if (loadingState.response?.likeArchive?.item?.isNotEmpty ==
bangumiItem: loadingState.response.season.item[index], 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: leading: loadingState.response.article.item.first
min(3, loadingState.response.season.item.length), .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( : errorWidget(),
height: 12 + MediaQuery.of(context).padding.bottom, Error() => errorWidget(),
), LoadingState() => throw UnimplementedError(),
), };
],
)
: const SizedBox.shrink();
} }
Widget _videoHeader({ Widget _videoHeader({

View File

@@ -1,7 +1,7 @@
import 'dart:math'; import 'dart:math';
import 'package:PiliPalaX/common/widgets/dynamic_sliver_appbar.dart'; 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/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/bangumi/member_bangumi.dart';
import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart'; import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/favorite/member_favorite.dart';
@@ -291,28 +291,19 @@ class _MemberPageNewState extends State<MemberPageNew>
); );
Widget _errorWidget(msg) { Widget _errorWidget(msg) {
return CustomScrollView( return errorWidget(
shrinkWrap: true, errMsg: msg,
slivers: [ callback: () {
HttpError( _userController.loadingState.value = LoadingState.loading();
errMsg: msg, _userController.onRefresh();
fn: () { },
_userController.loadingState.value = LoadingState.loading();
_userController.onRefresh();
},
)
],
); );
} }
Widget _buildUserInfo(LoadingState userState, [bool isV = true]) { Widget _buildUserInfo(LoadingState userState, [bool isV = true]) {
switch (userState) { return switch (userState) {
case Empty(): Loading() => const CircularProgressIndicator(),
return _errorWidget('EMPTY'); Success() => Obx(
case Error():
return _errorWidget(userState.errMsg);
case Success():
return Obx(
() => Padding( () => Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
bottom: (_userController.tab2?.length ?? 0) > 1 ? 48 : 0), bottom: (_userController.tab2?.length ?? 0) > 1 ? 48 : 0),
@@ -326,8 +317,9 @@ class _MemberPageNewState extends State<MemberPageNew>
onFollow: () => _userController.onFollow(context), onFollow: () => _userController.onFollow(context),
), ),
), ),
); ),
} Error() => _errorWidget(userState.errMsg),
return const CircularProgressIndicator(); LoadingState() => throw UnimplementedError(),
};
} }
} }

View File

@@ -1,5 +1,5 @@
import 'package:PiliPalaX/common/constants.dart'; 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/constants.dart';
import 'package:PiliPalaX/http/index.dart'; import 'package:PiliPalaX/http/index.dart';
import 'package:PiliPalaX/http/loading_state.dart'; import 'package:PiliPalaX/http/loading_state.dart';
@@ -99,19 +99,9 @@ class _EditProfilePageState extends State<EditProfilePage> {
); );
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
switch (loadingState) { return switch (loadingState) {
case Error(): Loading() => loadingWidget,
return CustomScrollView( Success() => SingleChildScrollView(
shrinkWrap: true,
slivers: [
HttpError(
errMsg: loadingState.errMsg,
fn: _getInfo,
),
],
);
case Success():
return SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
_item( _item(
@@ -226,11 +216,13 @@ class _EditProfilePageState extends State<EditProfilePage> {
_divider, _divider,
], ],
), ),
); ),
} Error() => errorWidget(
return Center( errMsg: loadingState.errMsg,
child: CircularProgressIndicator(), callback: _getInfo,
); ),
LoadingState() => throw UnimplementedError(),
};
} }
Widget _sexDialog(int current) { Widget _sexDialog(int current) {

View File

@@ -109,13 +109,13 @@ class _MemberArchivePageState extends State<MemberArchivePage> {
} else { } else {
return HttpError( return HttpError(
errMsg: snapshot.data['msg'], errMsg: snapshot.data['msg'],
fn: () {}, callback: () {},
); );
} }
} else { } else {
return HttpError( return HttpError(
errMsg: "投稿页出现错误", errMsg: "投稿页出现错误",
fn: () {}, callback: () {},
); );
} }
} else { } else {

View File

@@ -72,72 +72,79 @@ class _MemberDynamicsPageState extends State<MemberDynamicsPage>
); );
_buildContent(LoadingState loadingState) { _buildContent(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? SliverPadding( Loading() => HttpError(
padding: EdgeInsets.only( callback: _memberDynamicController.onReload,
bottom: MediaQuery.paddingOf(context).bottom, ),
), Success() => (loadingState.response as List?)?.isNotEmpty == true
sliver: dynamicsWaterfallFlow ? SliverPadding(
? SliverWaterfallFlow.extent( padding: EdgeInsets.only(
maxCrossAxisExtent: Grid.maxRowWidth * 2, bottom: MediaQuery.paddingOf(context).bottom,
//cacheExtent: 0.0, ),
crossAxisSpacing: StyleString.safeSpace, sliver: dynamicsWaterfallFlow
mainAxisSpacing: StyleString.safeSpace, ? 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 /// 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] /// last child as loadmore item/no more item in [GridView] and [WaterfallFlow]
/// with full cross axis extend /// with full cross axis extend
// LastChildLayoutType.fullCrossAxisExtend, // LastChildLayoutType.fullCrossAxisExtend,
/// as foot at trailing and layout with full cross axis extend /// as foot at trailing and layout with full cross axis extend
/// show no more item at trailing when children are not full of viewport /// 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 /// if children is full of viewport, it's the same as fullCrossAxisExtend
// LastChildLayoutType.foot, // LastChildLayoutType.foot,
lastChildLayoutTypeBuilder: (index) { lastChildLayoutTypeBuilder: (index) {
if (index == loadingState.response.length - 1) { if (index == loadingState.response.length - 1) {
EasyThrottle.throttle('member_dynamics', EasyThrottle.throttle('member_dynamics',
const Duration(milliseconds: 1000), () { const Duration(milliseconds: 1000), () {
_memberDynamicController.onLoadMore(); _memberDynamicController.onLoadMore();
}); });
} }
return index == loadingState.response.length return index == loadingState.response.length
? LastChildLayoutType.foot ? LastChildLayoutType.foot
: LastChildLayoutType.none; : LastChildLayoutType.none;
}, },
children: (loadingState.response as List) children: (loadingState.response as List)
.map((item) => DynamicPanel(item: item)) .map((item) => DynamicPanel(item: item))
.toList(), .toList(),
) )
: SliverCrossAxisGroup( : SliverCrossAxisGroup(
slivers: [ slivers: [
const SliverFillRemaining(), const SliverFillRemaining(),
SliverConstrainedCrossAxis( SliverConstrainedCrossAxis(
maxExtent: Grid.maxRowWidth * 2, maxExtent: Grid.maxRowWidth * 2,
sliver: SliverList( sliver: SliverList(
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(context, index) { (context, index) {
if (index == loadingState.response.length - 1) { if (index == loadingState.response.length - 1) {
EasyThrottle.throttle('member_dynamics', EasyThrottle.throttle('member_dynamics',
const Duration(milliseconds: 1000), () { const Duration(milliseconds: 1000), () {
_memberDynamicController.onLoadMore(); _memberDynamicController.onLoadMore();
}); });
} }
return DynamicPanel( return DynamicPanel(
item: loadingState.response[index]); item: loadingState.response[index]);
}, },
childCount: loadingState.response.length, childCount: loadingState.response.length,
),
), ),
), ),
), const SliverFillRemaining(),
const SliverFillRemaining(), ],
], ),
), )
) : HttpError(
: HttpError( callback: _memberDynamicController.onReload,
errMsg: loadingState is Error ? loadingState.errMsg : null, ),
fn: () { Error() => HttpError(
_memberDynamicController.onReload(); errMsg: loadingState.errMsg,
}, callback: _memberDynamicController.onReload,
); ),
LoadingState() => throw UnimplementedError(),
};
} }
} }

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:PiliPalaX/common/skeleton/video_card_h.dart'; import 'package:PiliPalaX/common/skeleton/video_card_h.dart';
import 'package:PiliPalaX/common/widgets/http_error.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/common/widgets/video_card_h.dart';
import '../../common/constants.dart'; import '../../common/constants.dart';
@@ -148,12 +147,14 @@ class _MemberSearchPageState extends State<MemberSearchPage>
(context, index) { (context, index) {
return const VideoCardHSkeleton(); return const VideoCardHSkeleton();
}, childCount: 10)) }, childCount: 10))
: const NoData(), : HttpError(
callback: () => setState(() {}),
),
)); ));
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() {}), callback: () => setState(() {}),
); );
} }
} else { } else {

View File

@@ -91,7 +91,7 @@ class _ZonePageState extends State<ZonePage>
? (_zoneController.loadingState.value as Error) ? (_zoneController.loadingState.value as Error)
.errMsg .errMsg
: '没有相关数据', : '没有相关数据',
fn: _zoneController.onReload, callback: _zoneController.onReload,
), ),
), ),
), ),

View File

@@ -102,7 +102,7 @@ class _RcmdPageState extends State<RcmdPage>
errMsg: _controller.loadingState.value is Error errMsg: _controller.loadingState.value is Error
? (_controller.loadingState.value as Error).errMsg ? (_controller.loadingState.value as Error).errMsg
: '没有相关数据', : '没有相关数据',
fn: _controller.onReload, callback: _controller.onReload,
), ),
), ),
), ),

View File

@@ -195,7 +195,7 @@ class _SearchPageState extends State<SearchPage> with RouteAware {
slivers: [ slivers: [
HttpError( HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() { callback: () => setState(() {
_futureBuilderFuture = _futureBuilderFuture =
_searchController.queryHotSearchList(); _searchController.queryHotSearchList();
}), }),

View File

@@ -45,14 +45,14 @@ class SearchPanelController extends CommonController {
if (dataList.isNotEmpty) { if (dataList.isNotEmpty) {
loadingState.value = LoadingState.success(dataList); loadingState.value = LoadingState.success(dataList);
} else { } else {
loadingState.value = LoadingState.empty(); loadingState.value = LoadingState.success([]);
} }
if (currentPage == 1) { if (currentPage == 1) {
onPushDetail(response.response.list); onPushDetail(response.response.list);
} }
} else { } else {
if (currentPage == 1) { if (currentPage == 1) {
loadingState.value = LoadingState.empty(); loadingState.value = LoadingState.success([]);
} }
} }
return true; return true;

View File

@@ -206,7 +206,7 @@ Widget searchArticlePanel(BuildContext context, searchPanelCtr, loadingState) {
) )
: HttpError( : HttpError(
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
fn: searchPanelCtr.onReload, callback: searchPanelCtr.onReload,
), ),
], ],
); );

View File

@@ -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:PiliPalaX/http/loading_state.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -8,36 +8,39 @@ import 'package:PiliPalaX/utils/utils.dart';
import '../../../utils/grid.dart'; import '../../../utils/grid.dart';
Widget searchLivePanel(BuildContext context, ctr, loadingState) { Widget searchLivePanel(BuildContext context, ctr, LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? GridView.builder( Loading() => loadingWidget,
padding: const EdgeInsets.only( Success() => (loadingState.response as List?)?.isNotEmpty == true
left: StyleString.safeSpace, ? GridView.builder(
right: StyleString.safeSpace, padding: const EdgeInsets.only(
bottom: StyleString.safeSpace, left: StyleString.safeSpace,
), right: StyleString.safeSpace,
primary: false, bottom: StyleString.safeSpace,
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,
), ),
], 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 { class LiveItem extends StatelessWidget {

View File

@@ -192,7 +192,7 @@ Widget searchBangumiPanel(BuildContext context, ctr, loadingState) {
) )
: HttpError( : HttpError(
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
fn: ctr.onReload, callback: ctr.onReload,
), ),
], ],
); );

View File

@@ -150,7 +150,7 @@ Widget searchUserPanel(BuildContext context, searchPanelCtr, loadingState) {
) )
: HttpError( : HttpError(
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
fn: searchPanelCtr.onReload, callback: searchPanelCtr.onReload,
) )
], ],
); );

View File

@@ -123,7 +123,7 @@ class SearchVideoPanel extends StatelessWidget {
) )
: HttpError( : HttpError(
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据', errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
fn: ctr.onReload, callback: ctr.onReload,
), ),
], ],
); );

View File

@@ -64,7 +64,6 @@ class _SearchResultPageState extends State<SearchResultPage>
const SizedBox(height: 4), const SizedBox(height: 4),
Container( Container(
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.only(left: 8),
color: Theme.of(context).colorScheme.surface, color: Theme.of(context).colorScheme.surface,
child: Theme( child: Theme(
data: ThemeData( data: ThemeData(
@@ -72,6 +71,7 @@ class _SearchResultPageState extends State<SearchResultPage>
highlightColor: Colors.transparent, // 点击时的背景高亮颜色设置为透明 highlightColor: Colors.transparent, // 点击时的背景高亮颜色设置为透明
), ),
child: TabBar( child: TabBar(
padding: const EdgeInsets.symmetric(horizontal: 8),
controller: _tabController, controller: _tabController,
tabs: SearchType.values tabs: SearchType.values
.map( .map(

View File

@@ -1,7 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:PiliPalaX/common/widgets/no_data.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import '../../../services/loggeer.dart'; import '../../../services/loggeer.dart';
@@ -194,11 +194,7 @@ class _LogsPageState extends State<LogsPage> {
); );
}, },
) )
: const CustomScrollView( : errorWidget(),
slivers: <Widget>[
NoData(),
],
),
); );
} }
} }

View File

@@ -105,6 +105,7 @@ class _RecommendSettingState extends State<RecommendSetting> {
leading: Icon(Icons.refresh), leading: Icon(Icons.refresh),
setKey: SettingBoxKey.enableSaveLastData, setKey: SettingBoxKey.enableSaveLastData,
defaultVal: false, defaultVal: false,
needReboot: true,
), ),
// 分割线 // 分割线
const Divider(height: 1), const Divider(height: 1),

View File

@@ -44,7 +44,7 @@ class _StyleSettingState extends State<StyleSetting> {
setting.get(SettingBoxKey.maxRowWidth, defaultValue: 240.0) as double; setting.get(SettingBoxKey.maxRowWidth, defaultValue: 240.0) as double;
upPanelPosition = UpPanelPosition.values[setting.get( upPanelPosition = UpPanelPosition.values[setting.get(
SettingBoxKey.upPanelPosition, SettingBoxKey.upPanelPosition,
defaultValue: UpPanelPosition.leftFixed.code)]; defaultValue: UpPanelPosition.leftFixed.index)];
} }
@override @override
@@ -67,10 +67,10 @@ class _StyleSettingState extends State<StyleSetting> {
callFn: (value) { callFn: (value) {
if (value) { if (value) {
autoScreen(); autoScreen();
SmartDialog.showToast('已开启横屏适配'); // SmartDialog.showToast('已开启横屏适配');
} else { } else {
AutoOrientation.portraitUpMode(); AutoOrientation.portraitUpMode();
SmartDialog.showToast('已关闭横屏适配'); // SmartDialog.showToast('已关闭横屏适配');
} }
}), }),
const SetSwitchItem( const SetSwitchItem(
@@ -171,7 +171,7 @@ class _StyleSettingState extends State<StyleSetting> {
); );
if (result != null) { if (result != null) {
upPanelPosition = result; upPanelPosition = result;
setting.put(SettingBoxKey.upPanelPosition, result.code); setting.put(SettingBoxKey.upPanelPosition, result.index);
SmartDialog.showToast('重启生效'); SmartDialog.showToast('重启生效');
setState(() {}); setState(() {});
} }
@@ -307,7 +307,7 @@ class _StyleSettingState extends State<StyleSetting> {
if (result != null) { if (result != null) {
_tempThemeValue = result; _tempThemeValue = result;
settingController.themeType.value = result; settingController.themeType.value = result;
setting.put(SettingBoxKey.themeMode, result.code); setting.put(SettingBoxKey.themeMode, result.index);
Get.forceAppUpdate(); Get.forceAppUpdate();
} }
}, },

View File

@@ -80,7 +80,7 @@ class _SubPageState extends State<SubPage> {
slivers: [ slivers: [
HttpError( HttpError(
errMsg: data?['msg'], errMsg: data?['msg'],
fn: () => setState(() {}), callback: () => setState(() {}),
), ),
], ],
); );

View File

@@ -6,7 +6,6 @@ import 'package:get/get.dart';
import 'package:PiliPalaX/common/skeleton/video_card_h.dart'; import 'package:PiliPalaX/common/skeleton/video_card_h.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart'; import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.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 '../../models/user/sub_folder.dart';
import '../../utils/utils.dart'; import '../../utils/utils.dart';
@@ -206,7 +205,12 @@ class _SubDetailPageState extends State<SubDetailPage> {
Map data = snapshot.data; Map data = snapshot.data;
if (data['status']) { if (data['status']) {
if (_subDetailController.item.mediaCount == 0) { if (_subDetailController.item.mediaCount == 0) {
return const NoData(); return HttpError(
callback: () => setState(() {
_futureBuilderFuture =
_subDetailController.queryUserSubFolderDetail();
}),
);
} else { } else {
List subList = _subDetailController.subList; List subList = _subDetailController.subList;
return Obx( return Obx(
@@ -225,7 +229,10 @@ class _SubDetailPageState extends State<SubDetailPage> {
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() {}), callback: () => setState(() {
_futureBuilderFuture =
_subDetailController.queryUserSubFolderDetail();
}),
); );
} }
} else { } else {

View File

@@ -699,7 +699,10 @@ class VideoIntroController extends GetxController
late RelatedController relatedCtr; late RelatedController relatedCtr;
try { try {
relatedCtr = Get.find<RelatedController>(tag: heroTag); relatedCtr = Get.find<RelatedController>(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('暂无相关视频,停止连播'); SmartDialog.showToast('暂无相关视频,停止连播');
return false; return false;
} }

View File

@@ -101,7 +101,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
slivers: [ slivers: [
HttpError( HttpError(
errMsg: _errMsg, errMsg: _errMsg,
fn: _getFolderInfo, callback: _getFolderInfo,
), ),
], ],
), ),

View File

@@ -147,7 +147,7 @@ class _FavPanelState extends State<FavPanel> {
slivers: [ slivers: [
HttpError( HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() { callback: () => setState(() {
_futureBuilderFuture = _futureBuilderFuture =
widget.ctr!.queryVideoInFolder(); widget.ctr!.queryVideoInFolder();
}), }),

View File

@@ -144,7 +144,7 @@ class _GroupPanelState extends State<GroupPanel> {
slivers: [ slivers: [
HttpError( HttpError(
errMsg: data['msg'], errMsg: data['msg'],
fn: () => setState(() {}), callback: () => setState(() {}),
), ),
], ],
); );

View File

@@ -43,54 +43,58 @@ class _RelatedVideoPanelState extends State<RelatedVideoPanel>
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? SliverGrid( Loading() => SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio( gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.safeSpace, mainAxisSpacing: StyleString.safeSpace,
crossAxisSpacing: StyleString.safeSpace, crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2, maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4, childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0), mainAxisExtent: 0),
delegate: SliverChildBuilderDelegate((context, index) { delegate: SliverChildBuilderDelegate(
if (index == loadingState.response.length) { (context, index) {
return SizedBox(height: MediaQuery.of(context).padding.bottom); return const VideoCardHSkeleton();
} else { },
return Material( childCount: 5,
child: VideoCardH( ),
videoItem: loadingState.response[index], ),
showPubdate: true, Success() => (loadingState.response as List?)?.isNotEmpty == true
longPress: () { ? SliverGrid(
_relatedController.popupDialog.add( gridDelegate: SliverGridDelegateWithExtentAndRatio(
_createPopupDialog(loadingState.response[index])); mainAxisSpacing: StyleString.safeSpace,
Overlay.of(context) crossAxisSpacing: StyleString.safeSpace,
.insert(_relatedController.popupDialog.last!); maxCrossAxisExtent: Grid.maxRowWidth * 2,
}, childAspectRatio: StyleString.aspectRatio * 2.4,
longPressEnd: _relatedController.removePopupDialog, mainAxisExtent: 0),
), delegate: SliverChildBuilderDelegate((context, index) {
); if (index == loadingState.response.length) {
} return SizedBox(
}, childCount: loadingState.response.length + 1), height: MediaQuery.of(context).padding.bottom);
) } else {
: loadingState is Error return Material(
? HttpError( child: VideoCardH(
errMsg: '出错了', videoItem: loadingState.response[index],
fn: _relatedController.onReload, showPubdate: true,
) longPress: () {
: loadingState is Empty _relatedController.popupDialog.add(
? const SliverToBoxAdapter(child: SizedBox.shrink()) _createPopupDialog(loadingState.response[index]));
: SliverGrid( Overlay.of(context)
gridDelegate: SliverGridDelegateWithExtentAndRatio( .insert(_relatedController.popupDialog.last!);
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, longPressEnd: _relatedController.removePopupDialog,
), ),
); );
}
}, childCount: loadingState.response.length + 1),
)
: HttpError(
callback: _relatedController.onReload,
),
Error() => HttpError(
errMsg: loadingState.errMsg,
callback: _relatedController.onReload,
),
LoadingState() => throw UnimplementedError(),
};
} }
} }

View File

@@ -200,63 +200,68 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
} }
Widget _buildBody(LoadingState loadingState) { Widget _buildBody(LoadingState loadingState) {
return loadingState is Success return switch (loadingState) {
? SliverList( Loading() => SliverList(
delegate: SliverChildBuilderDelegate( delegate: SliverChildBuilderDelegate(
(BuildContext context, index) { (BuildContext context, index) {
double bottom = MediaQuery.of(context).padding.bottom; return const VideoReplySkeleton();
if (index == loadingState.response.replies.length) { },
return Container( childCount: 5,
padding: EdgeInsets.only(bottom: bottom), ),
height: bottom + 100, ),
child: Center( Success() => (loadingState.response.replies as List?)?.isNotEmpty == true
child: Obx( ? SliverList(
() => Text( delegate: SliverChildBuilderDelegate(
_videoReplyController.noMore.value, (BuildContext context, index) {
style: TextStyle( double bottom = MediaQuery.of(context).padding.bottom;
fontSize: 12, if (index == loadingState.response.replies.length) {
color: Theme.of(context).colorScheme.outline, 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 {
} else { return ReplyItemGrpc(
return ReplyItemGrpc( replyItem: loadingState.response.replies[index],
replyItem: loadingState.response.replies[index], showReplyRow: true,
showReplyRow: true, replyLevel: replyLevel,
replyLevel: replyLevel, replyReply: widget.replyReply,
replyReply: widget.replyReply, replyType: ReplyType.video,
replyType: ReplyType.video, onReply: () {
onReply: () { _videoReplyController.onReply(
_videoReplyController.onReply( context,
context, replyItem: loadingState.response.replies[index],
replyItem: loadingState.response.replies[index], index: index,
index: index, );
); },
}, onDelete: _videoReplyController.onMDelete,
onDelete: _videoReplyController.onMDelete, isTop: _videoReplyController.hasUpTop && index == 0,
isTop: _videoReplyController.hasUpTop && index == 0, upMid: loadingState.response.subjectControl.upMid,
upMid: loadingState.response.subjectControl.upMid, );
); }
} },
}, childCount: loadingState.response.replies.length + 1,
childCount: loadingState.response.replies.length + 1, ),
)
: HttpError(
callback: _videoReplyController.onReload,
), ),
) Error() => HttpError(
: loadingState is Error errMsg: loadingState.errMsg,
? HttpError( callback: _videoReplyController.onReload,
errMsg: loadingState.errMsg, ),
fn: _videoReplyController.onReload, LoadingState() => throw UnimplementedError(),
) };
: SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, index) {
return const VideoReplySkeleton();
},
childCount: 5,
),
);
} }
} }

View File

@@ -146,10 +146,20 @@ class VideoReplyReplyController extends CommonController
} }
upMid ??= replies.subjectControl.upMid.toInt(); upMid ??= replies.subjectControl.upMid.toInt();
cursor = replies.cursor; cursor = replies.cursor;
if (currentPage != 1) {
List<ReplyInfo> list = loadingState.value is Success
? (loadingState.value as Success).response
: <ReplyInfo>[];
if (isDialogue) {
replies.replies.insertAll(0, list);
} else {
replies.root.replies.insertAll(0, list);
}
}
if (isDialogue) { if (isDialogue) {
if (replies.replies.isNotEmpty) { if (replies.replies.isNotEmpty) {
noMore.value = '加载中...'; noMore.value = '加载中...';
if (replies.cursor.isEnd) { if (replies.cursor.isEnd || count.value >= replies.replies.length) {
noMore.value = '没有更多了'; noMore.value = '没有更多了';
} }
} else { } else {
@@ -159,7 +169,8 @@ class VideoReplyReplyController extends CommonController
} else { } else {
if (replies.root.replies.isNotEmpty) { if (replies.root.replies.isNotEmpty) {
noMore.value = '加载中...'; noMore.value = '加载中...';
if (replies.cursor.isEnd) { if (replies.cursor.isEnd ||
count.value >= replies.root.replies.length) {
noMore.value = '没有更多了'; noMore.value = '没有更多了';
} }
} else { } else {
@@ -167,16 +178,6 @@ class VideoReplyReplyController extends CommonController
noMore.value = currentPage == 1 ? '还没有评论' : '没有更多了'; noMore.value = currentPage == 1 ? '还没有评论' : '没有更多了';
} }
} }
if (currentPage != 1) {
List<ReplyInfo> list = loadingState.value is Success
? (loadingState.value as Success).response
: <ReplyInfo>[];
if (isDialogue) {
replies.replies.insertAll(0, list);
} else {
replies.root.replies.insertAll(0, list);
}
}
if (isDialogue) { if (isDialogue) {
loadingState.value = LoadingState.success(replies.replies); loadingState.value = LoadingState.success(replies.replies);
} else { } else {

View File

@@ -333,7 +333,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
slivers: [ slivers: [
HttpError( HttpError(
errMsg: loadingState.errMsg, errMsg: loadingState.errMsg,
fn: _videoReplyReplyController.onReload, callback: _videoReplyReplyController.onReload,
) )
], ],
); );