This commit is contained in:
bggRGjQaUbCoE
2024-10-17 09:27:53 +08:00
parent 2e0f1477f5
commit 39b7670134
4 changed files with 290 additions and 76 deletions

View File

@@ -11,6 +11,7 @@ class PBadge extends StatelessWidget {
final String? stack;
final double? fs;
final String? semanticsLabel;
final bool bold;
const PBadge({
super.key,
@@ -24,6 +25,7 @@ class PBadge extends StatelessWidget {
this.stack = 'position',
this.fs = 11,
this.semanticsLabel,
this.bold = true,
});
@override
@@ -73,13 +75,13 @@ class PBadge extends StatelessWidget {
height: 1,
fontSize: fs ?? fontSize,
color: color,
fontWeight: FontWeight.bold,
fontWeight: bold ? FontWeight.bold : null,
),
strutStyle: StrutStyle(
leading: 0,
height: 1,
fontSize: fs ?? fontSize,
fontWeight: FontWeight.bold,
fontWeight: bold ? FontWeight.bold : null,
),
semanticsLabel: semanticsLabel,
),

View File

@@ -1,8 +1,14 @@
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/common/widgets/badge.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';
import 'package:PiliPalaX/models/space_fav/list.dart';
import 'package:PiliPalaX/models/user/sub_folder.dart';
import 'package:PiliPalaX/pages/member/new/content/member_contribute/content/favorite/member_favorite_ctr.dart';
import 'package:PiliPalaX/utils/app_scheme.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -42,78 +48,32 @@ class _MemberFavoriteState extends State<MemberFavorite>
onRefresh: () async {
await _controller.onRefresh();
},
child: ListView.builder(
itemCount: loadingState.response.length,
itemBuilder: (_, index) {
dynamic item = loadingState.response[index];
return item.mediaListResponse.list is List
? ExpansionTile(
dense: true,
title: Text.rich(
TextSpan(
children: [
TextSpan(
text: item.name,
style: TextStyle(fontSize: 14),
),
TextSpan(
text: ' ${item.mediaListResponse.count}',
style: TextStyle(fontSize: 13),
),
],
),
),
controlAffinity: ListTileControlAffinity.leading,
children: (item.mediaListResponse.list as List)
.map(
(item1) => ListTile(
onTap: () {
if (item1.state == 1) {
return;
}
if (item.id == 1) {
Get.toNamed(
'/favDetail',
parameters: {
'mediaId': item1.id.toString(),
'heroTag': widget.heroTag ?? '',
},
);
} else {
// TODO
}
},
leading: Container(
margin:
const EdgeInsets.symmetric(vertical: 6),
child: LayoutBuilder(
builder: (_, constraints) =>
NetworkImgLayer(
radius: 6,
src: item1.cover,
width: constraints.maxHeight *
StyleString.aspectRatio,
height: constraints.maxHeight,
),
),
),
title: Text(item1.title),
subtitle: Text(
'${item1.mediaCount}个内容 · ${item1.mid == widget.mid ? [
0,
22
].contains(item1.attr) ? '公开' : '私密' : item1.upper.name}',
style: TextStyle(
color:
Theme.of(context).colorScheme.outline,
),
),
),
)
.toList(),
)
: const SizedBox.shrink();
},
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
@@ -132,4 +92,170 @@ class _MemberFavoriteState extends State<MemberFavorite>
child: CircularProgressIndicator(),
);
}
_buildItem(Datum data, bool isFirst) {
return Theme(
data: Theme.of(context).copyWith(
dividerColor: Colors.transparent,
),
child: ExpansionTile(
dense: true,
initiallyExpanded: true,
title: Text.rich(
TextSpan(
children: [
TextSpan(
text: data.name,
style: TextStyle(fontSize: 14),
),
TextSpan(
text: ' ${data.mediaListResponse?.count}',
style: TextStyle(
fontSize: 13,
color: Theme.of(context).colorScheme.outline,
),
),
],
),
),
controlAffinity: ListTileControlAffinity.leading,
children: [
...(data.mediaListResponse?.list as List<FavList>).map(
(item1) => ListTile(
onTap: () {
if (item1.state == 1) {
// invalid
return;
}
if (item1.type == 0) {
Get.toNamed(
'/favDetail',
parameters: {
'mediaId': item1.id.toString(),
'heroTag': widget.heroTag ?? '',
},
);
} else if (item1.type == 21) {
PiliScheme.routePush(Uri.parse(item1.link ?? ''));
} else if (item1.type == 11) {
Get.toNamed(
'/subDetail',
arguments: SubFolderItemData(
type: 11,
title: item1.title,
cover: item1.cover,
upper: Upper(
mid: item1.upper?.mid,
name: item1.upper?.name,
face: item1.upper?.face,
),
mediaCount: item1.mediaCount,
viewCount: item1.viewCount,
),
parameters: {
'heroTag': widget.heroTag ?? '',
'id': item1.id.toString(),
},
);
}
},
leading: Container(
margin: const EdgeInsets.symmetric(vertical: 6),
child: LayoutBuilder(
builder: (_, constraints) {
return Stack(
children: [
NetworkImgLayer(
radius: 6,
src: item1.cover,
width:
constraints.maxHeight * StyleString.aspectRatio,
height: constraints.maxHeight,
),
if (item1.type == 21)
PBadge(
right: 3,
bottom: 3,
text: '合集',
bold: false,
size: 'small',
)
else if (item1.type == 0 || item1.type == 11)
Positioned(
right: 3,
bottom: 3,
child: Container(
padding: const EdgeInsets.all(5),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).colorScheme.primary,
),
child: Icon(
Icons.video_library_outlined,
size: 12,
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
],
);
},
),
),
title: Text(
item1.title ?? '',
style: TextStyle(
fontSize: 14,
),
),
subtitle: Text(
item1.type == 0
? '${item1.mediaCount}个内容 · ${[
0,
2,
22
].contains(item1.attr) ? '公开' : '私密'}'
: item1.type == 11
? '${item1.mediaCount}个内容 · ${item1.upper?.name}'
: item1.type == 21
? '创建者: ${item1.upper?.name}\n${item1.mediaCount}个视频 · ${Utils.numFormat(item1.viewCount)}播放'
: '${item1.mediaCount}个内容',
style: TextStyle(
fontSize: 13,
color: Theme.of(context).colorScheme.outline,
),
),
),
),
Obx(
() => (isFirst
? _controller.firstEnd.value
: _controller.secondEnd.value)
? const SizedBox.shrink()
: _buildLoadMoreItem(isFirst),
),
],
),
);
}
_buildLoadMoreItem(bool isFirst) {
return ListTile(
dense: true,
onTap: () {
if (isFirst) {
_controller.userfavFolder();
} else {
_controller.userSubFolder();
}
},
title: Text(
'查看更多内容',
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
),
);
}
}

View File

@@ -1,6 +1,14 @@
import 'package:PiliPalaX/http/api.dart';
import 'package:PiliPalaX/http/init.dart';
import 'package:PiliPalaX/http/loading_state.dart';
import 'package:PiliPalaX/http/member.dart';
import 'package:PiliPalaX/models/space_fav/datum.dart';
import 'package:PiliPalaX/models/space_fav/list.dart';
import 'package:PiliPalaX/models/space_fav/space_fav.dart';
import 'package:PiliPalaX/models/user/fav_folder.dart';
import 'package:PiliPalaX/pages/common/common_controller.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
class MemberFavoriteCtr extends CommonController {
MemberFavoriteCtr({
@@ -9,18 +17,95 @@ class MemberFavoriteCtr extends CommonController {
final int mid;
Rx<Datum> first = Datum().obs;
Rx<Datum> second = Datum().obs;
RxBool firstEnd = true.obs;
RxBool secondEnd = true.obs;
late int page = 2;
late int page1 = 2;
@override
void onInit() {
super.onInit();
queryData();
}
@override
Future onRefresh() {
page = 2;
page1 = 2;
return super.onRefresh();
}
@override
bool customHandleResponse(Success response) {
try {
List<Datum> res = response.response;
first.value = res.first;
second.value = res[1];
firstEnd.value = (res.first.mediaListResponse?.count ?? -1) <=
(res.first.mediaListResponse?.list?.length ?? -1);
secondEnd.value = (res[1].mediaListResponse?.count ?? -1) <=
(res[1].mediaListResponse?.list?.length ?? -1);
} catch (e) {
print(e.toString());
}
loadingState.value = response;
return true;
}
Future userfavFolder() async {
var res = await Request().get(Api.userFavFolder, data: {
'pn': page,
'ps': 20,
'up_mid': mid,
});
if (res.data['code'] == 0) {
page++;
firstEnd.value = res.data['data']['has_more'] == false;
if (res.data['data'] != null) {
List<FavList> list = (res.data['data']['list'] as List<dynamic>?)
?.map((item) => FavList.fromJson(item))
.toList() ??
<FavList>[];
first.value.mediaListResponse?.list?.addAll(list);
first.refresh();
} else {
firstEnd.value = true;
}
} else {
SmartDialog.showToast(res.data['message'] ?? '账号未登录');
}
}
Future userSubFolder() async {
var res = await Request().get(Api.userSubFolder, data: {
'up_mid': mid,
'ps': 20,
'pn': page1,
'platform': 'web',
});
if (res.data['code'] == 0) {
page++;
secondEnd.value = res.data['data']['has_more'] == false;
if (res.data['data'] != null) {
List<FavList> list = (res.data['data']['list'] as List<dynamic>?)
?.map((item) => FavList.fromJson(item))
.toList() ??
<FavList>[];
second.value.mediaListResponse?.list?.addAll(list);
second.refresh();
} else {
secondEnd.value = true;
}
} else {
SmartDialog.showToast(res.data['message'] ?? '账号未登录');
}
}
@override
Future<LoadingState> customGetData() => MemberHttp.spaceFav(mid: mid);
}

View File

@@ -34,7 +34,7 @@ class SubDetailController extends GetxController {
return;
}
isLoadingMore = true;
late Map<String,dynamic> res;
late Map<String, dynamic> res;
if (item.type! == 11) {
res = await UserHttp.favResourceList(
id: id,
@@ -42,7 +42,8 @@ class SubDetailController extends GetxController {
pn: currentPage,
);
} else {
res = await UserHttp.favSeasonList(// item.type! == 21
res = await UserHttp.favSeasonList(
// item.type! == 21
id: id,
ps: 20,
pn: currentPage,