mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
@@ -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),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
10
lib/common/widgets/loading_widget.dart
Normal file
10
lib/common/widgets/loading_widget.dart
Normal 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,
|
||||
);
|
||||
@@ -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,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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']);
|
||||
}
|
||||
|
||||
@@ -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']);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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']);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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']) {
|
||||
|
||||
@@ -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']);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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']);
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -91,7 +91,7 @@ class _HotPageState extends State<HotPage> with AutomaticKeepAliveClientMixin {
|
||||
? (_hotController.loadingState.value as Error)
|
||||
.errMsg
|
||||
: '没有相关数据',
|
||||
fn: _hotController.onReload,
|
||||
callback: _hotController.onReload,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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']);
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -91,7 +91,7 @@ class _ZonePageState extends State<ZonePage>
|
||||
? (_zoneController.loadingState.value as Error)
|
||||
.errMsg
|
||||
: '没有相关数据',
|
||||
fn: _zoneController.onReload,
|
||||
callback: _zoneController.onReload,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -195,7 +195,7 @@ class _SearchPageState extends State<SearchPage> with RouteAware {
|
||||
slivers: [
|
||||
HttpError(
|
||||
errMsg: data['msg'],
|
||||
fn: () => setState(() {
|
||||
callback: () => setState(() {
|
||||
_futureBuilderFuture =
|
||||
_searchController.queryHotSearchList();
|
||||
}),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -206,7 +206,7 @@ Widget searchArticlePanel(BuildContext context, searchPanelCtr, loadingState) {
|
||||
)
|
||||
: HttpError(
|
||||
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
|
||||
fn: searchPanelCtr.onReload,
|
||||
callback: searchPanelCtr.onReload,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -192,7 +192,7 @@ Widget searchBangumiPanel(BuildContext context, ctr, loadingState) {
|
||||
)
|
||||
: HttpError(
|
||||
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
|
||||
fn: ctr.onReload,
|
||||
callback: ctr.onReload,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -150,7 +150,7 @@ Widget searchUserPanel(BuildContext context, searchPanelCtr, loadingState) {
|
||||
)
|
||||
: HttpError(
|
||||
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
|
||||
fn: searchPanelCtr.onReload,
|
||||
callback: searchPanelCtr.onReload,
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
@@ -123,7 +123,7 @@ class SearchVideoPanel extends StatelessWidget {
|
||||
)
|
||||
: HttpError(
|
||||
errMsg: loadingState is Error ? loadingState.errMsg : '没有相关数据',
|
||||
fn: ctr.onReload,
|
||||
callback: ctr.onReload,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ class _RecommendSettingState extends State<RecommendSetting> {
|
||||
leading: Icon(Icons.refresh),
|
||||
setKey: SettingBoxKey.enableSaveLastData,
|
||||
defaultVal: false,
|
||||
needReboot: true,
|
||||
),
|
||||
// 分割线
|
||||
const Divider(height: 1),
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -80,7 +80,7 @@ class _SubPageState extends State<SubPage> {
|
||||
slivers: [
|
||||
HttpError(
|
||||
errMsg: data?['msg'],
|
||||
fn: () => setState(() {}),
|
||||
callback: () => setState(() {}),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
slivers: [
|
||||
HttpError(
|
||||
errMsg: _errMsg,
|
||||
fn: _getFolderInfo,
|
||||
callback: _getFolderInfo,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -147,7 +147,7 @@ class _FavPanelState extends State<FavPanel> {
|
||||
slivers: [
|
||||
HttpError(
|
||||
errMsg: data['msg'],
|
||||
fn: () => setState(() {
|
||||
callback: () => setState(() {
|
||||
_futureBuilderFuture =
|
||||
widget.ctr!.queryVideoInFolder();
|
||||
}),
|
||||
|
||||
@@ -144,7 +144,7 @@ class _GroupPanelState extends State<GroupPanel> {
|
||||
slivers: [
|
||||
HttpError(
|
||||
errMsg: data['msg'],
|
||||
fn: () => setState(() {}),
|
||||
callback: () => setState(() {}),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -333,7 +333,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
|
||||
slivers: [
|
||||
HttpError(
|
||||
errMsg: loadingState.errMsg,
|
||||
fn: _videoReplyReplyController.onReload,
|
||||
callback: _videoReplyReplyController.onReload,
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user