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';
class HttpError extends StatelessWidget {
const HttpError(
{required this.errMsg, required this.fn, this.btnText, super.key});
const HttpError({
this.isSliver = true,
this.errMsg,
this.callback,
this.btnText,
super.key,
});
final bool isSliver;
final String? errMsg;
final Function()? fn;
final Function()? callback;
final String? btnText;
@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: Column(
return isSliver
? SliverToBoxAdapter(child: content(context))
: SizedBox(
width: double.infinity,
child: content(context),
);
}
Widget content(BuildContext context) => Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 40),
SvgPicture.asset(
"assets/images/error.svg",
height: 200,
),
const SizedBox(height: 30),
Text(
errMsg ?? '请求异常',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleSmall,
),
const SizedBox(height: 20),
FilledButton.tonal(
onPressed: () {
fn!();
},
style: ButtonStyle(
backgroundColor: WidgetStateProperty.resolveWith((states) {
return Theme.of(context).colorScheme.primary.withAlpha(20);
}),
),
child: Text(
btnText ?? '点击重试',
style: TextStyle(color: Theme.of(context).colorScheme.primary),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: SelectableText(
errMsg ?? '没有数据',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleSmall,
),
),
if (callback != null) ...[
const SizedBox(height: 20),
FilledButton.tonal(
onPressed: callback,
style: ButtonStyle(
backgroundColor: WidgetStateProperty.resolveWith((states) {
return Theme.of(context).colorScheme.primary.withAlpha(20);
}),
),
child: Text(
btnText ?? '点击重试',
style: TextStyle(color: Theme.of(context).colorScheme.primary),
),
),
],
SizedBox(height: 40 + MediaQuery.paddingOf(context).bottom),
],
),
);
}
);
}

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/utils/extension.dart';
import '../models/bangumi/list.dart';
import 'index.dart';
@@ -10,11 +9,7 @@ class BangumiHttp {
if (res.data['code'] == 0) {
BangumiListDataModel data =
BangumiListDataModel.fromJson(res.data['data']);
if (!data.list.isNullOrEmpty) {
return LoadingState.success(data.list);
} else {
return LoadingState.empty();
}
return LoadingState.success(data.list);
} else {
return LoadingState.error(res.data['message']);
}
@@ -25,11 +20,7 @@ class BangumiHttp {
if (res.data['code'] == 0) {
BangumiListDataModel data =
BangumiListDataModel.fromJson(res.data['data']);
if (!data.list.isNullOrEmpty) {
return LoadingState.success(data.list);
} else {
return LoadingState.empty();
}
return LoadingState.success(data.list);
} else {
return LoadingState.error(res.data['message']);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

@@ -72,21 +72,21 @@ abstract class ReplyController extends CommonController {
}
}
cursor = replies.cursor;
if (replies.replies.isNotEmpty) {
noMore.value = '加载中...';
if (replies.cursor.isEnd) {
noMore.value = '没有更多了';
}
} else {
// 未登录状态replies可能返回null
noMore.value = currentPage == 1 ? '还没有评论' : '没有更多了';
}
if (currentPage != 1) {
List<ReplyInfo> list = loadingState.value is Success
? (loadingState.value as Success).response.replies
: <ReplyInfo>[];
replies.replies.insertAll(0, list);
}
if (replies.replies.isNotEmpty) {
noMore.value = '加载中...';
if (replies.cursor.isEnd || replies.replies.length >= count.value) {
noMore.value = '没有更多了';
}
} else {
// 未登录状态replies可能返回null
noMore.value = currentPage == 1 ? '还没有评论' : '没有更多了';
}
loadingState.value = LoadingState.success(replies);
return true;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -238,52 +238,27 @@ class _FavDetailPageState extends State<FavDetailPage> {
}
Widget _buildBody(LoadingState loadingState) {
return loadingState is Success
? loadingState.response.isEmpty
? const SliverToBoxAdapter(child: SizedBox())
: SliverPadding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == loadingState.response.length) {
return Container(
height: 60,
alignment: Alignment.center,
child: Obx(
() => Text(
_favDetailController.loadingText.value,
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize: 13),
),
),
);
}
return FavVideoCardH(
videoItem: loadingState.response[index],
callFn: () => _favDetailController
.onCancelFav(loadingState.response[index].id),
);
},
childCount: loadingState.response.length + 1,
),
),
)
: loadingState is Error
? HttpError(
errMsg: loadingState.errMsg,
fn: _favDetailController.onReload,
)
: SliverGrid(
return switch (loadingState) {
Loading() => SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return const VideoCardHSkeleton();
},
childCount: 10,
),
),
Success() => (loadingState.response as List?)?.isNotEmpty == true
? SliverPadding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.safeSpace,
@@ -293,10 +268,38 @@ class _FavDetailPageState extends State<FavDetailPage> {
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return const VideoCardHSkeleton();
if (index == loadingState.response.length) {
return Container(
height: 60,
alignment: Alignment.center,
child: Obx(
() => Text(
_favDetailController.loadingText.value,
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize: 13),
),
),
);
}
return FavVideoCardH(
videoItem: loadingState.response[index],
callFn: () => _favDetailController
.onCancelFav(loadingState.response[index].id),
);
},
childCount: 10,
childCount: loadingState.response.length + 1,
),
);
),
)
: HttpError(
callback: _favDetailController.onReload,
),
Error() => HttpError(
errMsg: loadingState.errMsg,
callback: _favDetailController.onReload,
),
LoadingState() => throw UnimplementedError(),
};
}
}

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/common/skeleton/video_card_h.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/common/widgets/no_data.dart';
import 'package:PiliPalaX/common/widgets/video_card_h.dart';
import 'package:PiliPalaX/pages/later/index.dart';
@@ -74,48 +73,51 @@ class _LaterPageState extends State<LaterPage> {
}
Widget _buildBody(LoadingState loadingState) {
return loadingState is Success
? SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.safeSpace,
crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0,
return switch (loadingState) {
Loading() => SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.safeSpace,
crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return const VideoCardHSkeleton();
},
childCount: 10,
),
),
Success() => (loadingState.response as List?)?.isNotEmpty == true
? SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.safeSpace,
crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
var videoItem = loadingState.response[index];
return VideoCardH(
videoItem: videoItem,
source: 'later',
longPress: () => _laterController.toViewDel(context,
aid: videoItem.aid));
},
childCount: loadingState.response.length,
),
)
: HttpError(
callback: _laterController.onReload,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
var videoItem = loadingState.response[index];
return VideoCardH(
videoItem: videoItem,
source: 'later',
longPress: () => _laterController.toViewDel(context,
aid: videoItem.aid));
},
childCount: loadingState.response.length,
),
)
: loadingState is Empty
? const NoData()
: loadingState is Error
? HttpError(
errMsg: loadingState.errMsg,
fn: _laterController.onReload,
)
: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.safeSpace,
crossAxisSpacing: StyleString.safeSpace,
maxCrossAxisExtent: Grid.maxRowWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.4,
mainAxisExtent: 0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return const VideoCardHSkeleton();
},
childCount: 10,
),
);
Error() => HttpError(
errMsg: loadingState.errMsg,
callback: _laterController.onReload,
),
LoadingState() => throw UnimplementedError(),
};
}
}

View File

@@ -1,6 +1,6 @@
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/space_article/item.dart';
@@ -40,79 +40,75 @@ class _MemberArticleState extends State<MemberArticle>
}
_buildBody(LoadingState loadingState) {
return loadingState is Success
? MediaQuery.removePadding(
context: context,
removeTop: true,
child: refreshIndicator(
onRefresh: () async {
await _controller.onRefresh();
},
child: ListView.separated(
itemCount: loadingState.response.length,
itemBuilder: (_, index) {
if (index == loadingState.response.length - 1) {
_controller.onLoadMore();
}
Item item = loadingState.response[index];
return ListTile(
dense: true,
onTap: () {
PiliScheme.routePush(Uri.parse(item.uri ?? ''));
},
leading: item.originImageUrls?.isNotEmpty == true
? Container(
margin: const EdgeInsets.symmetric(vertical: 6),
child: LayoutBuilder(
builder: (_, constraints) {
return NetworkImgLayer(
radius: 6,
src: item.originImageUrls!.first,
width: constraints.maxHeight *
StyleString.aspectRatio,
height: constraints.maxHeight,
);
},
),
)
: null,
title: Text(
item.title ?? '',
style: TextStyle(
fontSize: 15,
),
),
subtitle: item.summary?.isNotEmpty == true
? Text(
item.summary!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: Theme.of(context).colorScheme.outline,
),
)
: null,
);
return switch (loadingState) {
Loading() => loadingWidget,
Success() => (loadingState.response as List?)?.isNotEmpty == true
? MediaQuery.removePadding(
context: context,
removeTop: true,
child: refreshIndicator(
onRefresh: () async {
await _controller.onRefresh();
},
separatorBuilder: (_, index) => Divider(height: 1),
),
),
)
: loadingState is Error
? Center(
child: CustomScrollView(
shrinkWrap: true,
slivers: [
HttpError(
errMsg: loadingState.errMsg,
fn: _controller.onReload,
),
],
child: ListView.separated(
itemCount: loadingState.response.length,
itemBuilder: (_, index) {
if (index == loadingState.response.length - 1) {
_controller.onLoadMore();
}
Item item = loadingState.response[index];
return ListTile(
dense: true,
onTap: () {
PiliScheme.routePush(Uri.parse(item.uri ?? ''));
},
leading: item.originImageUrls?.isNotEmpty == true
? Container(
margin: const EdgeInsets.symmetric(vertical: 6),
child: LayoutBuilder(
builder: (_, constraints) {
return NetworkImgLayer(
radius: 6,
src: item.originImageUrls!.first,
width: constraints.maxHeight *
StyleString.aspectRatio,
height: constraints.maxHeight,
);
},
),
)
: null,
title: Text(
item.title ?? '',
style: TextStyle(
fontSize: 15,
),
),
subtitle: item.summary?.isNotEmpty == true
? Text(
item.summary!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: Theme.of(context).colorScheme.outline,
),
)
: null,
);
},
separatorBuilder: (_, index) => Divider(height: 1),
),
)
: Center(
child: CircularProgressIndicator(),
);
),
)
: errorWidget(
callback: _controller.onReload,
),
Error() => errorWidget(
errMsg: loadingState.errMsg,
callback: _controller.onReload,
),
LoadingState() => throw UnimplementedError(),
};
}
}

View File

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

View File

@@ -1,7 +1,7 @@
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/badge.dart';
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:PiliPalaX/common/widgets/refresh_indicator.dart';
import 'package:PiliPalaX/common/widgets/http_error.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/models/space_fav/datum.dart';
@@ -44,54 +44,50 @@ class _MemberFavoriteState extends State<MemberFavorite>
}
_buildBody(LoadingState loadingState) {
return loadingState is Success
? refreshIndicator(
onRefresh: () async {
await _controller.onRefresh();
},
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Obx(
() => _controller.first.value.mediaListResponse?.list
?.isNotEmpty ==
true
? _buildItem(_controller.first.value, true)
: const SizedBox.shrink(),
),
),
SliverToBoxAdapter(
child: Obx(
() => _controller.second.value.mediaListResponse?.list
?.isNotEmpty ==
true
? _buildItem(_controller.second.value, false)
: const SizedBox.shrink(),
),
),
SliverToBoxAdapter(
child: SizedBox(
height: 12 + MediaQuery.of(context).padding.bottom,
),
)
],
),
)
: loadingState is Error
? Center(
child: CustomScrollView(
shrinkWrap: true,
slivers: [
HttpError(
errMsg: loadingState.errMsg,
fn: _controller.onReload,
return switch (loadingState) {
Loading() => loadingWidget,
Success() => (loadingState.response as List?)?.isNotEmpty == true
? refreshIndicator(
onRefresh: () async {
await _controller.onRefresh();
},
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Obx(
() => _controller.first.value.mediaListResponse?.list
?.isNotEmpty ==
true
? _buildItem(_controller.first.value, true)
: const SizedBox.shrink(),
),
],
),
)
: Center(
child: CircularProgressIndicator(),
);
),
SliverToBoxAdapter(
child: Obx(
() => _controller.second.value.mediaListResponse?.list
?.isNotEmpty ==
true
? _buildItem(_controller.second.value, false)
: const SizedBox.shrink(),
),
),
SliverToBoxAdapter(
child: SizedBox(
height: 12 + MediaQuery.of(context).padding.bottom,
),
)
],
),
)
: errorWidget(
callback: _controller.onReload,
),
Error() => errorWidget(
errMsg: loadingState.errMsg,
callback: _controller.onReload,
),
LoadingState() => throw UnimplementedError(),
};
}
_buildItem(Datum data, bool isFirst) {

View File

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

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

View File

@@ -1,6 +1,7 @@
import 'dart:math';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/loading_widget.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/common/widgets/video_card_v_member_home.dart';
import 'package:PiliPalaX/http/loading_state.dart';
@@ -39,171 +40,183 @@ class _MemberHomeState extends State<MemberHome>
}
Widget _buildBody(LoadingState loadingState) {
return loadingState is Success && loadingState.response is Data
? CustomScrollView(
slivers: [
if (loadingState.response?.archive?.item?.isNotEmpty == true) ...[
_videoHeader(
title: '视频',
param: 'contribute',
param1: 'video',
count: loadingState.response.archive.count,
),
SliverPadding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
return switch (loadingState) {
Loading() => loadingWidget,
Success() => loadingState.response is Data
? CustomScrollView(
slivers: [
if (loadingState.response?.archive?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '视频',
param: 'contribute',
param1: 'video',
count: loadingState.response.archive.count,
),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.cardSpace,
maxCrossAxisExtent: Grid.maxRowWidth,
childAspectRatio: StyleString.aspectRatio,
mainAxisExtent:
MediaQuery.textScalerOf(context).scale(90),
SliverPadding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return VideoCardVMemberHome(
videoItem: loadingState.response.archive.item[index],
);
},
childCount:
min(4, loadingState.response.archive.item.length),
),
),
),
],
if (loadingState.response?.favourite2?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '收藏',
param: 'favorite',
count: loadingState.response.favourite2.count,
),
// TODO
],
if (loadingState.response?.coinArchive?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '最近投币的视频',
param: 'coinArchive',
count: loadingState.response.coinArchive.count,
),
// TODO
],
if (loadingState.response?.likeArchive?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '最近点赞的视频',
param: 'likeArchive',
count: loadingState.response.likeArchive.count,
),
// TODO
],
if (loadingState.response?.article?.item?.isNotEmpty == true) ...[
_videoHeader(
title: '专栏',
param: 'contribute',
param1: 'article',
count: loadingState.response.article.count,
),
SliverToBoxAdapter(
child: ListTile(
dense: true,
onTap: () {
PiliScheme.routePush(Uri.parse(
loadingState.response.article.item.first.uri ?? ''));
},
leading: loadingState.response.article.item.first
.originImageUrls?.isNotEmpty ==
true
? Container(
margin: const EdgeInsets.symmetric(vertical: 6),
child: LayoutBuilder(
builder: (_, constraints) {
return NetworkImgLayer(
radius: 6,
src: loadingState.response.article.item.first
.originImageUrls!.first,
width: constraints.maxHeight *
StyleString.aspectRatio,
height: constraints.maxHeight,
);
},
),
)
: null,
title: Text(
loadingState.response.article.item.first.title ?? '',
style: TextStyle(
fontSize: 15,
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace,
crossAxisSpacing: StyleString.cardSpace,
maxCrossAxisExtent: Grid.maxRowWidth,
childAspectRatio: StyleString.aspectRatio,
mainAxisExtent:
MediaQuery.textScalerOf(context).scale(90),
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return VideoCardVMemberHome(
videoItem:
loadingState.response.archive.item[index],
);
},
childCount:
min(4, loadingState.response.archive.item.length),
),
),
subtitle: loadingState.response.article.item.first.summary
?.isNotEmpty ==
true
? Text(
loadingState.response.article.item.first.summary!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: Theme.of(context).colorScheme.outline,
),
)
: null,
),
),
],
if (loadingState.response?.audios?.item?.isNotEmpty == true) ...[
_videoHeader(
title: '音频',
param: 'contribute',
param1: 'audio',
count: loadingState.response.audios.count,
),
// TODO
],
if (loadingState.response?.season?.item?.isNotEmpty == true) ...[
_videoHeader(
title: '追番',
param: 'bangumi',
count: loadingState.response.season.count,
),
SliverPadding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
],
if (loadingState.response?.favourite2?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '收藏',
param: 'favorite',
count: loadingState.response.favourite2.count,
),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace - 2,
crossAxisSpacing: StyleString.cardSpace,
maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2,
childAspectRatio: 0.65,
mainAxisExtent:
MediaQuery.textScalerOf(context).scale(60),
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return BangumiCardVMemberHome(
bangumiItem: loadingState.response.season.item[index],
);
// TODO
],
if (loadingState.response?.coinArchive?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '最近投币的视频',
param: 'coinArchive',
count: loadingState.response.coinArchive.count,
),
// TODO
],
if (loadingState.response?.likeArchive?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '最近点赞的视频',
param: 'likeArchive',
count: loadingState.response.likeArchive.count,
),
// TODO
],
if (loadingState.response?.article?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '专栏',
param: 'contribute',
param1: 'article',
count: loadingState.response.article.count,
),
SliverToBoxAdapter(
child: ListTile(
dense: true,
onTap: () {
PiliScheme.routePush(Uri.parse(
loadingState.response.article.item.first.uri ??
''));
},
childCount:
min(3, loadingState.response.season.item.length),
leading: loadingState.response.article.item.first
.originImageUrls?.isNotEmpty ==
true
? Container(
margin: const EdgeInsets.symmetric(vertical: 6),
child: LayoutBuilder(
builder: (_, constraints) {
return NetworkImgLayer(
radius: 6,
src: loadingState.response.article.item
.first.originImageUrls!.first,
width: constraints.maxHeight *
StyleString.aspectRatio,
height: constraints.maxHeight,
);
},
),
)
: null,
title: Text(
loadingState.response.article.item.first.title ?? '',
style: TextStyle(
fontSize: 15,
),
),
subtitle: loadingState.response.article.item.first.summary
?.isNotEmpty ==
true
? Text(
loadingState.response.article.item.first.summary!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: Theme.of(context).colorScheme.outline,
),
)
: null,
),
),
],
if (loadingState.response?.audios?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '音频',
param: 'contribute',
param1: 'audio',
count: loadingState.response.audios.count,
),
// TODO
],
if (loadingState.response?.season?.item?.isNotEmpty ==
true) ...[
_videoHeader(
title: '追番',
param: 'bangumi',
count: loadingState.response.season.count,
),
SliverPadding(
padding: const EdgeInsets.symmetric(
horizontal: StyleString.safeSpace,
),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: StyleString.cardSpace - 2,
crossAxisSpacing: StyleString.cardSpace,
maxCrossAxisExtent: Grid.maxRowWidth / 3 * 2,
childAspectRatio: 0.65,
mainAxisExtent:
MediaQuery.textScalerOf(context).scale(60),
),
delegate: SliverChildBuilderDelegate(
(context, index) {
return BangumiCardVMemberHome(
bangumiItem:
loadingState.response.season.item[index],
);
},
childCount:
min(3, loadingState.response.season.item.length),
),
),
),
],
SliverToBoxAdapter(
child: SizedBox(
height: 12 + MediaQuery.of(context).padding.bottom,
),
),
],
SliverToBoxAdapter(
child: SizedBox(
height: 12 + MediaQuery.of(context).padding.bottom,
),
),
],
)
: const SizedBox.shrink();
)
: errorWidget(),
Error() => errorWidget(),
LoadingState() => throw UnimplementedError(),
};
}
Widget _videoHeader({

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -102,7 +102,7 @@ class _RcmdPageState extends State<RcmdPage>
errMsg: _controller.loadingState.value is Error
? (_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: [
HttpError(
errMsg: data['msg'],
fn: () => setState(() {
callback: () => setState(() {
_futureBuilderFuture =
_searchController.queryHotSearchList();
}),

View File

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

View File

@@ -206,7 +206,7 @@ Widget searchArticlePanel(BuildContext context, searchPanelCtr, loadingState) {
)
: HttpError(
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:flutter/material.dart';
import 'package:get/get.dart';
@@ -8,36 +8,39 @@ import 'package:PiliPalaX/utils/utils.dart';
import '../../../utils/grid.dart';
Widget searchLivePanel(BuildContext context, ctr, loadingState) {
return loadingState is Success
? GridView.builder(
padding: const EdgeInsets.only(
left: StyleString.safeSpace,
right: StyleString.safeSpace,
bottom: StyleString.safeSpace,
),
primary: false,
controller: ctr!.scrollController,
gridDelegate: SliverGridDelegateWithExtentAndRatio(
maxCrossAxisExtent: Grid.maxRowWidth,
crossAxisSpacing: StyleString.safeSpace,
mainAxisSpacing: StyleString.safeSpace,
childAspectRatio: StyleString.aspectRatio,
mainAxisExtent: MediaQuery.textScalerOf(context).scale(80),
),
itemCount: loadingState.response.length,
itemBuilder: (context, index) {
return LiveItem(liveItem: loadingState.response[index]);
},
)
: CustomScrollView(
slivers: [
HttpError(
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
fn: ctr.onReload,
Widget searchLivePanel(BuildContext context, ctr, LoadingState loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Success() => (loadingState.response as List?)?.isNotEmpty == true
? GridView.builder(
padding: const EdgeInsets.only(
left: StyleString.safeSpace,
right: StyleString.safeSpace,
bottom: StyleString.safeSpace,
),
],
);
primary: false,
controller: ctr!.scrollController,
gridDelegate: SliverGridDelegateWithExtentAndRatio(
maxCrossAxisExtent: Grid.maxRowWidth,
crossAxisSpacing: StyleString.safeSpace,
mainAxisSpacing: StyleString.safeSpace,
childAspectRatio: StyleString.aspectRatio,
mainAxisExtent: MediaQuery.textScalerOf(context).scale(80),
),
itemCount: loadingState.response.length,
itemBuilder: (context, index) {
return LiveItem(liveItem: loadingState.response[index]);
},
)
: errorWidget(
callback: ctr.onReload,
),
Error() => errorWidget(
errMsg: loadingState.errMsg,
callback: ctr.onReload,
),
LoadingState() => throw UnimplementedError(),
};
}
class LiveItem extends StatelessWidget {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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