mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
wip
This commit is contained in:
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user