feat: sort fav folder

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-12 18:50:19 +08:00
parent 0b867c254f
commit 8d633377ae
7 changed files with 258 additions and 55 deletions

View File

@@ -116,6 +116,8 @@ class Api {
static const String sortFav = '/x/v3/fav/resource/sort'; static const String sortFav = '/x/v3/fav/resource/sort';
static const String sortFavFolder = '/x/v3/fav/folder/sort';
// 判断视频是否被收藏双端GET // 判断视频是否被收藏双端GET
/// aid /// aid
// https://api.bilibili.com/x/v2/fav/video/favoured // https://api.bilibili.com/x/v2/fav/video/favoured

View File

@@ -66,6 +66,28 @@ class UserHttp {
} }
} }
static Future sortFavFolder({
required List<int?> sort,
}) async {
Map<String, dynamic> data = {
'sort': sort.join(','),
'csrf': await Request.getCsrf(),
};
Utils.appSign(data);
var res = await Request().post(
Api.sortFavFolder,
data: data,
options: Options(
contentType: Headers.formUrlEncodedContentType,
),
);
if (res.data['code'] == 0) {
return {'status': true, 'data': res.data['data']};
} else {
return {'status': false, 'msg': res.data['message']};
}
}
static Future sortFav({ static Future sortFav({
required dynamic mediaId, required dynamic mediaId,
required List<String> sort, required List<String> sort,

View File

@@ -39,7 +39,7 @@ class FavController
@override @override
Future<LoadingState<FavFolderData>> customGetData() => UserHttp.userfavFolder( Future<LoadingState<FavFolderData>> customGetData() => UserHttp.userfavFolder(
pn: currentPage, pn: currentPage,
ps: 10, ps: 20,
mid: mid, mid: mid,
); );
} }

View File

@@ -0,0 +1,138 @@
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/user.dart';
import 'package:PiliPlus/models/user/fav_folder.dart';
import 'package:PiliPlus/pages/fav/video/controller.dart';
import 'package:PiliPlus/pages/fav/video/widgets/item.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
class FavFolderSortPage extends StatefulWidget {
const FavFolderSortPage({super.key, required this.favController});
final FavController favController;
@override
State<FavFolderSortPage> createState() => _FavFolderSortPageState();
}
class _FavFolderSortPageState extends State<FavFolderSortPage> {
FavController get _favController => widget.favController;
final GlobalKey _key = GlobalKey();
late List<FavFolderItemData> sortList = List<FavFolderItemData>.from(
(_favController.loadingState.value as Success).response);
final ScrollController _scrollController = ScrollController();
void listener() {
if (_favController.isEnd) {
return;
}
if (_scrollController.position.pixels >=
_scrollController.position.maxScrollExtent - 200) {
_favController.onLoadMore().then((_) {
try {
if (_favController.loadingState.value is Success) {
List<FavFolderItemData> list =
(_favController.loadingState.value as Success).response;
sortList.addAll(list.sublist(sortList.length));
if (mounted) {
setState(() {});
}
}
} catch (_) {}
});
}
}
@override
void initState() {
super.initState();
if (_favController.isEnd.not) {
_scrollController.addListener(listener);
}
}
@override
void dispose() {
_scrollController.removeListener(listener);
_scrollController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('收藏夹排序'),
actions: [
TextButton(
onPressed: () async {
dynamic res = await UserHttp.sortFavFolder(
sort: sortList.map((item) => item.id).toList(),
);
if (res['status']) {
SmartDialog.showToast('排序完成');
_favController.loadingState.value =
LoadingState.success(sortList);
Get.back();
} else {
SmartDialog.showToast(res['msg']);
}
},
child: const Text('完成'),
),
const SizedBox(width: 16),
],
),
body: _buildBody,
);
}
void onReorder(int oldIndex, int newIndex) {
if (oldIndex == 0 || newIndex == 0) {
SmartDialog.showToast('默认收藏夹不支持排序');
return;
}
if (newIndex > oldIndex) {
newIndex -= 1;
}
final tabsItem = sortList.removeAt(oldIndex);
sortList.insert(newIndex, tabsItem);
setState(() {});
}
Widget get _buildBody {
return ReorderableListView(
key: _key,
scrollController: _scrollController,
onReorder: onReorder,
physics: const AlwaysScrollableScrollPhysics(),
footer: SizedBox(
height: MediaQuery.of(context).padding.bottom + 80,
),
children: List.generate(
sortList.length,
(index) {
final item = sortList[index];
final key = item.id.toString();
return FavItem(
key: Key(key),
heroTag: key,
favFolderItem: item,
onLongPress: index == 0
? () {
SmartDialog.showToast('默认收藏夹不支持排序');
}
: null,
);
},
),
);
}
}

View File

@@ -7,10 +7,13 @@ import 'package:PiliPlus/common/widgets/network_img_layer.dart';
class FavItem extends StatelessWidget { class FavItem extends StatelessWidget {
final String heroTag; final String heroTag;
final dynamic favFolderItem; final dynamic favFolderItem;
final GestureTapCallback onTap; final VoidCallback? onTap;
final VoidCallback? onLongPress;
const FavItem({ const FavItem({
super.key, super.key,
required this.onTap, this.onTap,
this.onLongPress,
required this.heroTag, required this.heroTag,
required this.favFolderItem, required this.favFolderItem,
}); });
@@ -19,11 +22,14 @@ class FavItem extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return InkWell( return InkWell(
onTap: onTap, onTap: onTap,
onLongPress: () => imageSaveDialog( onLongPress: onLongPress ??
(onTap == null
? null
: () => imageSaveDialog(
context: context, context: context,
title: favFolderItem.title, title: favFolderItem.title,
cover: favFolderItem.cover, cover: favFolderItem.cover,
), )),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5),
child: LayoutBuilder( child: LayoutBuilder(

View File

@@ -4,6 +4,7 @@ import 'package:PiliPlus/models/user/fav_folder.dart';
import 'package:PiliPlus/pages/fav/article/view.dart'; import 'package:PiliPlus/pages/fav/article/view.dart';
import 'package:PiliPlus/pages/fav/note/view.dart'; import 'package:PiliPlus/pages/fav/note/view.dart';
import 'package:PiliPlus/pages/fav/pgc/view.dart'; import 'package:PiliPlus/pages/fav/pgc/view.dart';
import 'package:PiliPlus/pages/fav/video/fav_folder_sort_page.dart';
import 'package:PiliPlus/pages/fav/video/index.dart'; import 'package:PiliPlus/pages/fav/video/index.dart';
import 'package:PiliPlus/pages/fav_search/view.dart'; import 'package:PiliPlus/pages/fav_search/view.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@@ -31,15 +32,29 @@ class FavPage extends StatefulWidget {
} }
class _FavPageState extends State<FavPage> with SingleTickerProviderStateMixin { class _FavPageState extends State<FavPage> with SingleTickerProviderStateMixin {
late final TabController _tabController = TabController( late final TabController _tabController;
final FavController _favController = Get.put(FavController());
late final RxInt _tabIndex;
void listener() {
_tabIndex.value = _tabController.index;
}
@override
void initState() {
super.initState();
_tabIndex = (Get.arguments is int ? Get.arguments as int : 0).obs;
_tabController = TabController(
length: _FavType.values.length, length: _FavType.values.length,
vsync: this, vsync: this,
initialIndex: Get.arguments is int ? Get.arguments : 0, initialIndex: _tabIndex.value,
); );
final FavController _favController = Get.put(FavController()); _tabController.addListener(listener);
}
@override @override
void dispose() { void dispose() {
_tabController.removeListener(listener);
_tabController.dispose(); _tabController.dispose();
super.dispose(); super.dispose();
} }
@@ -50,13 +65,15 @@ class _FavPageState extends State<FavPage> with SingleTickerProviderStateMixin {
appBar: AppBar( appBar: AppBar(
title: const Text('我的收藏'), title: const Text('我的收藏'),
actions: [ actions: [
IconButton( Obx(
() => _tabIndex.value == 0
? IconButton(
onPressed: () { onPressed: () {
Get.toNamed('/createFav')?.then( Get.toNamed('/createFav')?.then(
(data) { (data) {
if (data != null) { if (data != null) {
List<FavFolderItemData> list = List<FavFolderItemData> list = _favController
_favController.loadingState.value is Success .loadingState.value is Success
? (_favController.loadingState.value as Success) ? (_favController.loadingState.value as Success)
.response .response
: <FavFolderItemData>[]; : <FavFolderItemData>[];
@@ -68,12 +85,28 @@ class _FavPageState extends State<FavPage> with SingleTickerProviderStateMixin {
}, },
icon: const Icon(Icons.add), icon: const Icon(Icons.add),
tooltip: '新建收藏夹', tooltip: '新建收藏夹',
)
: const SizedBox.shrink(),
), ),
IconButton( Obx(
() => _tabIndex.value == 0
? IconButton(
onPressed: () {
Get.to(FavFolderSortPage(favController: _favController));
},
icon: const Icon(Icons.sort),
tooltip: '收藏夹排序',
)
: const SizedBox.shrink(),
),
Obx(
() => _tabIndex.value == 0
? IconButton(
onPressed: () { onPressed: () {
if (_favController.loadingState.value is Success) { if (_favController.loadingState.value is Success) {
try { try {
final item = (_favController.loadingState.value as Success) final item =
(_favController.loadingState.value as Success)
.response .response
.first; .first;
Get.toNamed( Get.toNamed(
@@ -92,6 +125,8 @@ class _FavPageState extends State<FavPage> with SingleTickerProviderStateMixin {
}, },
icon: const Icon(Icons.search_outlined), icon: const Icon(Icons.search_outlined),
tooltip: '搜索', tooltip: '搜索',
)
: const SizedBox.shrink(),
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
], ],

View File

@@ -39,7 +39,7 @@ class _FavSortPageState extends State<FavSortPage> {
if (_favDetailController.loadingState.value is Success) { if (_favDetailController.loadingState.value is Success) {
List<FavDetailItemData> list = List<FavDetailItemData> list =
(_favDetailController.loadingState.value as Success).response; (_favDetailController.loadingState.value as Success).response;
this.sortList.addAll(list.sublist(this.sortList.length)); sortList.addAll(list.sublist(sortList.length));
if (mounted) { if (mounted) {
setState(() {}); setState(() {});
} }