mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt: multiSelect (#935)
This commit is contained in:
committed by
GitHub
parent
d246462535
commit
7b51f15753
91
lib/common/widgets/appbar/appbar.dart
Normal file
91
lib/common/widgets/appbar/appbar.dart
Normal file
@@ -0,0 +1,91 @@
|
||||
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AppBarWidget extends StatelessWidget implements PreferredSizeWidget {
|
||||
const AppBarWidget({
|
||||
required this.child1,
|
||||
required this.child2,
|
||||
required this.visible,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final PreferredSizeWidget child1;
|
||||
final PreferredSizeWidget child2;
|
||||
final bool visible;
|
||||
@override
|
||||
Size get preferredSize => child1.preferredSize;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
transitionBuilder: (Widget child, Animation<double> animation) {
|
||||
return ScaleTransition(
|
||||
scale: animation,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: !visible
|
||||
? KeyedSubtree.wrap(child1, 0)
|
||||
: KeyedSubtree.wrap(child2, 1),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MultiSelectAppBarWidget extends StatelessWidget
|
||||
implements PreferredSizeWidget {
|
||||
final MultiSelectMixin ctr;
|
||||
final bool? visible;
|
||||
final AppBar child;
|
||||
final List<Widget>? children;
|
||||
|
||||
const MultiSelectAppBarWidget({
|
||||
super.key,
|
||||
required this.ctr,
|
||||
this.visible,
|
||||
this.children,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBarWidget(
|
||||
visible: visible ?? ctr.enableMultiSelect.value,
|
||||
child1: child,
|
||||
child2: AppBar(
|
||||
bottom: child.bottom,
|
||||
leading: IconButton(
|
||||
tooltip: '取消',
|
||||
onPressed: ctr.handleSelect,
|
||||
icon: const Icon(Icons.close_outlined),
|
||||
),
|
||||
title: Obx(() => Text('已选: ${ctr.checkedCount}')),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () => ctr.handleSelect(true),
|
||||
child: const Text('全选'),
|
||||
),
|
||||
...?children,
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: ctr.onConfirm,
|
||||
child: Text(
|
||||
'移除',
|
||||
style: TextStyle(color: Get.theme.colorScheme.error),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Size get preferredSize => child.preferredSize;
|
||||
}
|
||||
@@ -312,7 +312,7 @@ class FavHttp {
|
||||
|
||||
static Future delNote({
|
||||
required bool isPublish,
|
||||
required List noteIds,
|
||||
required Iterable noteIds,
|
||||
}) async {
|
||||
final res = await Request().post(
|
||||
isPublish ? Api.delPublishNote : Api.delNote,
|
||||
@@ -637,13 +637,13 @@ class FavHttp {
|
||||
}
|
||||
}
|
||||
|
||||
static Future copyOrMoveFav({
|
||||
static Future<LoadingState> copyOrMoveFav({
|
||||
required bool isCopy,
|
||||
required bool isFav,
|
||||
required dynamic srcMediaId,
|
||||
required dynamic tarMediaId,
|
||||
dynamic mid,
|
||||
required List resources,
|
||||
required Iterable resources,
|
||||
}) async {
|
||||
var res = await Request().post(
|
||||
isFav
|
||||
@@ -664,21 +664,21 @@ class FavHttp {
|
||||
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||
);
|
||||
if (res.data['code'] == 0) {
|
||||
return {'status': true};
|
||||
return const Success(null);
|
||||
} else {
|
||||
return {'status': false, 'msg': res.data['message']};
|
||||
return Error(res.data['message']);
|
||||
}
|
||||
}
|
||||
|
||||
static Future allFavFolders(mid) async {
|
||||
static Future<LoadingState<FavFolderData>> allFavFolders(Object mid) async {
|
||||
var res = await Request().get(
|
||||
Api.favFolder,
|
||||
queryParameters: {'up_mid': mid},
|
||||
);
|
||||
if (res.data['code'] == 0) {
|
||||
return {'status': true, 'data': FavFolderData.fromJson(res.data['data'])};
|
||||
return Success(FavFolderData.fromJson(res.data['data']));
|
||||
} else {
|
||||
return {'status': false, 'msg': res.data['message']};
|
||||
return Error(res.data['message']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ class UserHttp {
|
||||
}
|
||||
|
||||
// 移除已观看
|
||||
static Future toViewDel({required List<int?> aids}) async {
|
||||
static Future toViewDel({required Iterable<int> aids}) async {
|
||||
final Map<String, dynamic> params = {
|
||||
'csrf': Accounts.main.csrf,
|
||||
'resources': aids.join(','),
|
||||
@@ -204,7 +204,7 @@ class UserHttp {
|
||||
}
|
||||
|
||||
// 删除历史记录
|
||||
static Future delHistory(List<String> kidList) async {
|
||||
static Future delHistory(Iterable<String> kidList) async {
|
||||
var res = await Request().post(
|
||||
Api.delHistory,
|
||||
data: {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -5,35 +6,60 @@ mixin MultiSelectData {
|
||||
bool? checked;
|
||||
}
|
||||
|
||||
abstract class MultiSelectController<R, T extends MultiSelectData>
|
||||
extends CommonListController<R, T> {
|
||||
mixin MultiSelectMixin<T> {
|
||||
late final RxBool enableMultiSelect = false.obs;
|
||||
late final RxInt checkedCount = 0.obs;
|
||||
late final allSelected = false.obs;
|
||||
|
||||
int get checkedCount;
|
||||
|
||||
void onSelect(T item, [bool disableSelect = true]);
|
||||
void handleSelect([bool checked = false, bool disableSelect = true]);
|
||||
void onConfirm();
|
||||
}
|
||||
|
||||
abstract class MultiSelectController<R, T extends MultiSelectData>
|
||||
extends CommonListController<R, T>
|
||||
with MultiSelectMixin<T>, CommonMultiSelectMixin, DeleteItemMixin {}
|
||||
|
||||
mixin CommonMultiSelectMixin<T extends MultiSelectData> on MultiSelectMixin<T> {
|
||||
Rx<LoadingState<List<T>?>> get loadingState;
|
||||
late final RxInt rxCount = 0.obs;
|
||||
|
||||
@override
|
||||
int get checkedCount => rxCount.value;
|
||||
|
||||
Iterable<T> get allChecked =>
|
||||
loadingState.value.data!.where((v) => v.checked == true);
|
||||
|
||||
@override
|
||||
void onSelect(T item, [bool disableSelect = true]) {
|
||||
List<T> list = loadingState.value.data!;
|
||||
item.checked = !(item.checked ?? false);
|
||||
checkedCount.value = list.where((item) => item.checked == true).length;
|
||||
if (item.checked!) {
|
||||
rxCount.value++;
|
||||
} else {
|
||||
rxCount.value--;
|
||||
}
|
||||
loadingState.refresh();
|
||||
if (disableSelect) {
|
||||
if (checkedCount.value == 0) {
|
||||
if (checkedCount == 0) {
|
||||
enableMultiSelect.value = false;
|
||||
}
|
||||
} else {
|
||||
allSelected.value = checkedCount.value == list.length;
|
||||
allSelected.value = checkedCount == list.length;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleSelect([bool checked = false, bool disableSelect = true]) {
|
||||
if (loadingState.value.isSuccess) {
|
||||
List<T>? list = loadingState.value.data;
|
||||
final list = loadingState.value.data;
|
||||
if (list?.isNotEmpty == true) {
|
||||
for (T item in list!) {
|
||||
for (var item in list!) {
|
||||
item.checked = checked;
|
||||
}
|
||||
loadingState.refresh();
|
||||
checkedCount.value = checked ? list.length : 0;
|
||||
rxCount.value = checked ? list.length : 0;
|
||||
}
|
||||
}
|
||||
if (disableSelect && !checked) {
|
||||
@@ -41,3 +67,75 @@ abstract class MultiSelectController<R, T extends MultiSelectData>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin DeleteItemMixin<R, T extends MultiSelectData>
|
||||
on CommonListController<R, T>, CommonMultiSelectMixin<T> {
|
||||
Future<void> afterDelete(Set<T> result) async {
|
||||
// TODO: result require hash
|
||||
final remainList = loadingState.value.data!;
|
||||
if (result.length == 1) {
|
||||
remainList.remove(result.single);
|
||||
} else {
|
||||
remainList.removeWhere(result.contains);
|
||||
}
|
||||
if (remainList.isNotEmpty) {
|
||||
loadingState.refresh();
|
||||
} else if (!isEnd) {
|
||||
onReload();
|
||||
}
|
||||
if (enableMultiSelect.value) {
|
||||
rxCount.value = 0;
|
||||
enableMultiSelect.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// abstract class SetMultiSelectController<R, T, I>
|
||||
// extends CommonListController<R, T>
|
||||
// with MultiSelectMixin<T>, SetCommonMultiSelectMixin<T, I> {}
|
||||
|
||||
// mixin SetCommonMultiSelectMixin<T, R> on MultiSelectMixin<T> {
|
||||
// Rx<LoadingState<List<T>?>> get loadingState;
|
||||
// RxSet<R> get selected;
|
||||
|
||||
// @override
|
||||
// int get checkedCount => selected.length;
|
||||
|
||||
// R getId(T item);
|
||||
|
||||
// @override
|
||||
// void onSelect(T item, [bool disableSelect = true]) {
|
||||
// final id = getId(item);
|
||||
// if (selected.contains(id)) {
|
||||
// selected.remove(id);
|
||||
// } else {
|
||||
// selected.add(id);
|
||||
// }
|
||||
// loadingState.refresh();
|
||||
// if (disableSelect) {
|
||||
// if (checkedCount == 0) {
|
||||
// enableMultiSelect.value = false;
|
||||
// }
|
||||
// } else {
|
||||
// allSelected.value = checkedCount == loadingState.value.data!.length;
|
||||
// }
|
||||
// }
|
||||
|
||||
// @override
|
||||
// void handleSelect([bool checked = false, bool disableSelect = true]) {
|
||||
// if (loadingState.value.isSuccess) {
|
||||
// final list = loadingState.value.data;
|
||||
// if (list?.isNotEmpty == true) {
|
||||
// if (checked) {
|
||||
// selected.addAll(list!.map(getId));
|
||||
// } else {
|
||||
// selected.clear();
|
||||
// }
|
||||
// loadingState.refresh();
|
||||
// }
|
||||
// }
|
||||
// if (disableSelect && !checked) {
|
||||
// enableMultiSelect.value = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -97,7 +97,7 @@ class _CreateVotePageState extends State<CreateVotePage> {
|
||||
..add(
|
||||
_buildInput(
|
||||
theme,
|
||||
key: ValueKey(e.hashCode),
|
||||
key: ObjectKey(e),
|
||||
showDel: showDel,
|
||||
onDel: () {
|
||||
FocusManager.instance.primaryFocus?.unfocus();
|
||||
|
||||
@@ -115,11 +115,11 @@ class _FavNoteChildPageState extends State<FavNoteChildPage>
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: () {
|
||||
if (_favNoteController.checkedCount.value != 0) {
|
||||
if (_favNoteController.checkedCount != 0) {
|
||||
showConfirmDialog(
|
||||
context: context,
|
||||
title: '确定删除已选中的笔记吗?',
|
||||
onConfirm: _favNoteController.onRemove,
|
||||
onConfirm: _favNoteController.onConfirm,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -34,24 +34,15 @@ class FavNoteController
|
||||
: FavHttp.noteList(page: page);
|
||||
}
|
||||
|
||||
Future<void> onRemove() async {
|
||||
List<FavNoteItemModel> dataList = loadingState.value.data!;
|
||||
Set<FavNoteItemModel> removeList = dataList
|
||||
.where((item) => item.checked == true)
|
||||
.toSet();
|
||||
@override
|
||||
Future<void> onConfirm() async {
|
||||
Set<FavNoteItemModel> removeList = allChecked.toSet();
|
||||
final res = await FavHttp.delNote(
|
||||
isPublish: isPublish,
|
||||
noteIds: removeList
|
||||
.map((item) => isPublish ? item.cvid : item.noteId)
|
||||
.toList(),
|
||||
noteIds: removeList.map((item) => isPublish ? item.cvid : item.noteId),
|
||||
);
|
||||
if (res['status']) {
|
||||
List<FavNoteItemModel> remainList = dataList
|
||||
.toSet()
|
||||
.difference(removeList)
|
||||
.toList();
|
||||
loadingState.value = Success(remainList);
|
||||
enableMultiSelect.value = false;
|
||||
afterDelete(removeList);
|
||||
SmartDialog.showToast('删除成功');
|
||||
} else {
|
||||
SmartDialog.showToast(res['msg']);
|
||||
@@ -59,7 +50,7 @@ class FavNoteController
|
||||
}
|
||||
|
||||
void onDisable() {
|
||||
if (checkedCount.value != 0) {
|
||||
if (checkedCount != 0) {
|
||||
handleSelect();
|
||||
}
|
||||
enableMultiSelect.value = false;
|
||||
|
||||
@@ -128,8 +128,7 @@ class _FavPgcChildPageState extends State<FavPgcChildPage>
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {
|
||||
if (_favPgcController.checkedCount.value !=
|
||||
0) {
|
||||
if (_favPgcController.checkedCount != 0) {
|
||||
_favPgcController.onUpdateList(
|
||||
item.followStatus,
|
||||
);
|
||||
|
||||
@@ -48,7 +48,7 @@ class FavPgcController
|
||||
);
|
||||
|
||||
void onDisable() {
|
||||
if (checkedCount.value != 0) {
|
||||
if (checkedCount != 0) {
|
||||
handleSelect();
|
||||
}
|
||||
enableMultiSelect.value = false;
|
||||
@@ -65,22 +65,19 @@ class FavPgcController
|
||||
SmartDialog.showToast(result['msg']);
|
||||
}
|
||||
|
||||
@override
|
||||
void onConfirm() {
|
||||
assert(false, 'call onUpdateList');
|
||||
}
|
||||
|
||||
Future<void> onUpdateList(int followStatus) async {
|
||||
List<FavPgcItemModel> dataList = loadingState.value.data!;
|
||||
Set<FavPgcItemModel> updateList = dataList
|
||||
.where((item) => item.checked == true)
|
||||
.toSet();
|
||||
final updateList = allChecked.toSet();
|
||||
final res = await VideoHttp.pgcUpdate(
|
||||
seasonId: updateList.map((item) => item.seasonId).toList(),
|
||||
status: followStatus,
|
||||
);
|
||||
if (res['status']) {
|
||||
List<FavPgcItemModel> remainList = dataList
|
||||
.toSet()
|
||||
.difference(updateList)
|
||||
.toList();
|
||||
loadingState.value = Success(remainList);
|
||||
enableMultiSelect.value = false;
|
||||
afterDelete(updateList);
|
||||
try {
|
||||
final ctr = Get.find<FavPgcController>(tag: '$type$followStatus');
|
||||
if (ctr.loadingState.value.isSuccess) {
|
||||
|
||||
@@ -18,7 +18,7 @@ class FavPgcItem extends StatelessWidget {
|
||||
});
|
||||
|
||||
final FavPgcItemModel item;
|
||||
final MultiSelectController ctr;
|
||||
final MultiSelectMixin ctr;
|
||||
final VoidCallback onSelect;
|
||||
final VoidCallback onUpdateStatus;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
|
||||
import 'package:PiliPlus/http/fav.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/common/fav_order_type.dart';
|
||||
@@ -11,7 +12,6 @@ import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -90,61 +90,28 @@ class FavDetailController
|
||||
order: order.value,
|
||||
);
|
||||
|
||||
void onDelChecked(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('确认删除所选收藏吗?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
List<FavDetailItemModel> list = loadingState.value.data!
|
||||
.where((e) => e.checked == true)
|
||||
.toList();
|
||||
@override
|
||||
void onConfirm() {
|
||||
showConfirmDialog(
|
||||
context: Get.context!,
|
||||
content: '确认删除所选收藏吗?',
|
||||
title: '提示',
|
||||
onConfirm: () async {
|
||||
final checked = allChecked.toSet();
|
||||
var result = await FavHttp.favVideo(
|
||||
resources: list
|
||||
.map((item) => '${item.id}:${item.type}')
|
||||
.join(','),
|
||||
resources: checked.map((item) => '${item.id}:${item.type}').join(','),
|
||||
delIds: mediaId.toString(),
|
||||
);
|
||||
if (result['status']) {
|
||||
List<FavDetailItemModel> dataList = loadingState.value.data!;
|
||||
List<FavDetailItemModel> remainList = dataList
|
||||
.toSet()
|
||||
.difference(list.toSet())
|
||||
.toList();
|
||||
afterDelete(checked);
|
||||
folderInfo
|
||||
..value.mediaCount -= list.length
|
||||
..value.mediaCount -= checked.length
|
||||
..refresh();
|
||||
if (remainList.isNotEmpty) {
|
||||
loadingState.value = Success(remainList);
|
||||
} else {
|
||||
onReload();
|
||||
}
|
||||
SmartDialog.showToast('取消收藏');
|
||||
checkedCount.value = 0;
|
||||
enableMultiSelect.value = false;
|
||||
} else {
|
||||
SmartDialog.showToast(result['msg']);
|
||||
}
|
||||
},
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
||||
Obx(
|
||||
() {
|
||||
return Text(
|
||||
'已选: ${_favDetailController.checkedCount.value}',
|
||||
'已选: ${_favDetailController.checkedCount}',
|
||||
style: const TextStyle(fontSize: 15),
|
||||
);
|
||||
},
|
||||
@@ -327,7 +327,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () => _favDetailController.onDelChecked(context),
|
||||
onPressed: _favDetailController.onConfirm,
|
||||
child: Text(
|
||||
'删除',
|
||||
style: TextStyle(color: theme.colorScheme.error),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/user.dart';
|
||||
import 'package:PiliPlus/models_new/history/data.dart';
|
||||
@@ -26,6 +27,12 @@ class HistoryController
|
||||
int? max;
|
||||
int? viewAt;
|
||||
|
||||
@override
|
||||
RxInt get rxCount => baseCtr.checkedCount;
|
||||
|
||||
@override
|
||||
RxBool get enableMultiSelect => baseCtr.enableMultiSelect;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
@@ -40,36 +47,6 @@ class HistoryController
|
||||
return super.onRefresh();
|
||||
}
|
||||
|
||||
@override
|
||||
void onSelect(HistoryItemModel item, [bool disableSelect = true]) {
|
||||
List<HistoryItemModel> list = loadingState.value.data!;
|
||||
item.checked = !(item.checked ?? false);
|
||||
baseCtr.checkedCount.value = list
|
||||
.where((item) => item.checked == true)
|
||||
.length;
|
||||
loadingState.refresh();
|
||||
if (baseCtr.checkedCount.value == 0) {
|
||||
baseCtr.enableMultiSelect.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleSelect([bool checked = false, bool disableSelect = true]) {
|
||||
if (loadingState.value.isSuccess) {
|
||||
List<HistoryItemModel>? list = loadingState.value.data;
|
||||
if (list?.isNotEmpty == true) {
|
||||
for (HistoryItemModel item in list!) {
|
||||
item.checked = checked;
|
||||
}
|
||||
baseCtr.checkedCount.value = checked ? list.length : 0;
|
||||
loadingState.refresh();
|
||||
}
|
||||
}
|
||||
if (!checked) {
|
||||
baseCtr.enableMultiSelect.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
List<HistoryItemModel>? getDataList(HistoryData response) {
|
||||
return response.list;
|
||||
@@ -108,82 +85,43 @@ class HistoryController
|
||||
|
||||
// 删除某条历史记录
|
||||
void delHistory(HistoryItemModel item) {
|
||||
_onDelete([item]);
|
||||
_onDelete({item});
|
||||
}
|
||||
|
||||
// 删除已看历史记录
|
||||
void onDelHistory() {
|
||||
if (loadingState.value.isSuccess) {
|
||||
List<HistoryItemModel> list = loadingState.value.data!
|
||||
final set = loadingState.value.data!
|
||||
.where((e) => e.progress == -1)
|
||||
.toList();
|
||||
if (list.isNotEmpty) {
|
||||
_onDelete(list);
|
||||
.toSet();
|
||||
if (set.isNotEmpty) {
|
||||
_onDelete(set);
|
||||
} else {
|
||||
SmartDialog.showToast('无已看记录');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _onDelete(List<HistoryItemModel> result) async {
|
||||
Future<void> _onDelete(Set<HistoryItemModel> result) async {
|
||||
SmartDialog.showLoading(msg: '请求中');
|
||||
List<String> kidList = result.map((item) {
|
||||
return '${item.history.business}_${item.kid}';
|
||||
}).toList();
|
||||
var response = await UserHttp.delHistory(kidList);
|
||||
final response = await UserHttp.delHistory(
|
||||
result.map((item) => '${item.history.business}_${item.kid}'),
|
||||
);
|
||||
if (response['status']) {
|
||||
List<HistoryItemModel> remainList = loadingState.value.data!
|
||||
.toSet()
|
||||
.difference(result.toSet())
|
||||
.toList();
|
||||
if (remainList.isNotEmpty) {
|
||||
loadingState.value = Success(remainList);
|
||||
} else {
|
||||
onReload();
|
||||
}
|
||||
if (baseCtr.enableMultiSelect.value) {
|
||||
baseCtr.checkedCount.value = 0;
|
||||
baseCtr.enableMultiSelect.value = false;
|
||||
}
|
||||
afterDelete(result);
|
||||
}
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(response['msg']);
|
||||
}
|
||||
|
||||
// 删除选中的记录
|
||||
void onDelCheckedHistory(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('确认删除所选历史记录吗?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
if (loadingState.value.isSuccess) {
|
||||
_onDelete(
|
||||
loadingState.value.data!
|
||||
.where((e) => e.checked == true)
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
@override
|
||||
void onConfirm() {
|
||||
showConfirmDialog(
|
||||
context: Get.context!,
|
||||
content: '确认删除所选历史记录吗?',
|
||||
title: '提示',
|
||||
onConfirm: () => _onDelete(allChecked.toSet()),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/skeleton/video_card_h.dart';
|
||||
import 'package:PiliPlus/common/widgets/appbar/appbar.dart';
|
||||
import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
@@ -65,9 +66,10 @@ class _HistoryPageState extends State<HistoryPage>
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
appBar: AppBarWidget(
|
||||
appBar: MultiSelectAppBarWidget(
|
||||
visible: enableMultiSelect,
|
||||
child1: AppBar(
|
||||
ctr: currCtr(),
|
||||
child: AppBar(
|
||||
title: const Text('观看记录'),
|
||||
bottom: _buildPauseTip,
|
||||
actions: [
|
||||
@@ -153,36 +155,6 @@ class _HistoryPageState extends State<HistoryPage>
|
||||
const SizedBox(width: 6),
|
||||
],
|
||||
),
|
||||
child2: AppBar(
|
||||
bottom: _buildPauseTip,
|
||||
leading: IconButton(
|
||||
tooltip: '取消',
|
||||
onPressed: currCtr().handleSelect,
|
||||
icon: const Icon(Icons.close_outlined),
|
||||
),
|
||||
title: Obx(
|
||||
() => Text(
|
||||
'已选: ${_historyController.baseCtr.checkedCount.value}',
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => currCtr().handleSelect(true),
|
||||
child: const Text('全选'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () =>
|
||||
currCtr().onDelCheckedHistory(context),
|
||||
child: Text(
|
||||
'删除',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
],
|
||||
),
|
||||
),
|
||||
body: Obx(
|
||||
() => _historyController.tabs.isNotEmpty
|
||||
@@ -288,8 +260,7 @@ class _HistoryPageState extends State<HistoryPage>
|
||||
final item = response[index];
|
||||
return HistoryItem(
|
||||
item: item,
|
||||
ctr: _historyController.baseCtr,
|
||||
onChoose: () => _historyController.onSelect(item),
|
||||
ctr: _historyController,
|
||||
onDelete: (kid, business) =>
|
||||
_historyController.delHistory(item),
|
||||
);
|
||||
@@ -359,32 +330,3 @@ class _HistoryPageState extends State<HistoryPage>
|
||||
@override
|
||||
bool get wantKeepAlive => widget.type != null;
|
||||
}
|
||||
|
||||
class AppBarWidget extends StatelessWidget implements PreferredSizeWidget {
|
||||
const AppBarWidget({
|
||||
required this.child1,
|
||||
required this.child2,
|
||||
required this.visible,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final PreferredSizeWidget child1;
|
||||
final PreferredSizeWidget child2;
|
||||
final bool visible;
|
||||
@override
|
||||
Size get preferredSize => child1.preferredSize;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
transitionBuilder: (Widget child, Animation<double> animation) {
|
||||
return ScaleTransition(
|
||||
scale: animation,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
child: !visible ? child1 : child2,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/badge.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/image_save.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/common/widgets/progress_bar/video_progress_indicator.dart';
|
||||
import 'package:PiliPlus/http/search.dart';
|
||||
@@ -9,7 +8,6 @@ import 'package:PiliPlus/models/common/badge_type.dart';
|
||||
import 'package:PiliPlus/models/common/history_business_type.dart';
|
||||
import 'package:PiliPlus/models_new/history/list.dart';
|
||||
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
||||
import 'package:PiliPlus/pages/history/base_controller.dart';
|
||||
import 'package:PiliPlus/utils/date_util.dart';
|
||||
import 'package:PiliPlus/utils/duration_util.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
@@ -23,15 +21,13 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
|
||||
|
||||
class HistoryItem extends StatelessWidget {
|
||||
final HistoryItemModel item;
|
||||
final dynamic ctr;
|
||||
final Function? onChoose;
|
||||
final Function(dynamic kid, dynamic business) onDelete;
|
||||
final MultiSelectMixin ctr;
|
||||
final void Function(int kid, String business) onDelete;
|
||||
|
||||
const HistoryItem({
|
||||
super.key,
|
||||
required this.item,
|
||||
this.ctr,
|
||||
this.onChoose,
|
||||
required this.ctr,
|
||||
required this.onDelete,
|
||||
});
|
||||
|
||||
@@ -45,12 +41,10 @@ class HistoryItem extends StatelessWidget {
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
if (ctr is MultiSelectController || ctr is HistoryBaseController) {
|
||||
if (ctr.enableMultiSelect.value) {
|
||||
onChoose?.call();
|
||||
ctr.onSelect(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (item.history.business?.contains('article') == true) {
|
||||
PageUtils.toDupNamed(
|
||||
'/articlePage',
|
||||
@@ -97,18 +91,16 @@ class HistoryItem extends StatelessWidget {
|
||||
}
|
||||
},
|
||||
onLongPress: () {
|
||||
if (ctr is MultiSelectController || ctr is HistoryBaseController) {
|
||||
if (!ctr.enableMultiSelect.value) {
|
||||
ctr.enableMultiSelect.value = true;
|
||||
onChoose?.call();
|
||||
ctr.onSelect(item);
|
||||
}
|
||||
return;
|
||||
}
|
||||
imageSaveDialog(
|
||||
title: item.title,
|
||||
cover: item.cover,
|
||||
bvid: bvid,
|
||||
);
|
||||
// imageSaveDialog(
|
||||
// title: item.title,
|
||||
// cover: item.cover,
|
||||
// bvid: bvid,
|
||||
// );
|
||||
},
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
@@ -205,7 +197,7 @@ class HistoryItem extends StatelessWidget {
|
||||
),
|
||||
onPressed: () {
|
||||
feedBack();
|
||||
onChoose?.call();
|
||||
ctr.onSelect(item);
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.done_all_outlined,
|
||||
@@ -287,7 +279,7 @@ class HistoryItem extends StatelessWidget {
|
||||
),
|
||||
PopupMenuItem<String>(
|
||||
onTap: () =>
|
||||
onDelete(item.kid, item.history.business),
|
||||
onDelete(item.kid!, item.history.business!),
|
||||
height: 35,
|
||||
child: const Row(
|
||||
children: [
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/user.dart';
|
||||
import 'package:PiliPlus/models_new/history/data.dart';
|
||||
import 'package:PiliPlus/models_new/history/list.dart';
|
||||
import 'package:PiliPlus/pages/common/common_search_controller.dart';
|
||||
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class HistorySearchController
|
||||
extends CommonSearchController<HistoryData, HistoryItemModel> {
|
||||
extends CommonSearchController<HistoryData, HistoryItemModel>
|
||||
with
|
||||
MultiSelectMixin<HistoryItemModel>,
|
||||
CommonMultiSelectMixin,
|
||||
DeleteItemMixin {
|
||||
@override
|
||||
Future<LoadingState<HistoryData>> customGetData() => UserHttp.searchHistory(
|
||||
pn: page,
|
||||
@@ -18,12 +25,14 @@ class HistorySearchController
|
||||
return response.list;
|
||||
}
|
||||
|
||||
Future<void> onDelHistory(int index, kid, business) async {
|
||||
String resKid = 'archive_$kid';
|
||||
Future<void> onDelHistory(int index, kid, String business) async {
|
||||
final String resKid;
|
||||
if (business == 'live') {
|
||||
resKid = 'live_$kid';
|
||||
} else if (business.contains('article')) {
|
||||
resKid = 'article_$kid';
|
||||
} else {
|
||||
resKid = 'archive_$kid';
|
||||
}
|
||||
|
||||
var res = await UserHttp.delHistory([resKid]);
|
||||
@@ -34,4 +43,26 @@ class HistorySearchController
|
||||
}
|
||||
SmartDialog.showToast(res['msg']);
|
||||
}
|
||||
|
||||
@override
|
||||
void onConfirm() {
|
||||
showConfirmDialog(
|
||||
context: Get.context!,
|
||||
content: '确认删除所选历史记录吗?',
|
||||
title: '提示',
|
||||
onConfirm: () async {
|
||||
SmartDialog.showLoading(msg: '请求中');
|
||||
final result = allChecked.toSet();
|
||||
final kidList = result.map(
|
||||
(item) => '${item.history.business!}_${item.kid!}',
|
||||
);
|
||||
var response = await UserHttp.delHistory(kidList);
|
||||
if (response['status']) {
|
||||
afterDelete(result);
|
||||
}
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast(response['msg']);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'package:PiliPlus/common/widgets/appbar/appbar.dart';
|
||||
import 'package:PiliPlus/models_new/history/data.dart';
|
||||
import 'package:PiliPlus/models_new/history/list.dart';
|
||||
import 'package:PiliPlus/pages/common/common_search_page.dart';
|
||||
@@ -28,6 +29,31 @@ class _HistorySearchPageState
|
||||
tag: Utils.generateRandomString(8),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// TODO: refa
|
||||
return Obx(() {
|
||||
final parent = super.build(context) as Scaffold;
|
||||
final enableMultiSelect = controller.enableMultiSelect.value;
|
||||
return PopScope(
|
||||
canPop: !enableMultiSelect,
|
||||
onPopInvokedWithResult: (didPop, result) {
|
||||
if (enableMultiSelect) {
|
||||
controller.handleSelect();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: parent.resizeToAvoidBottomInset,
|
||||
appBar: MultiSelectAppBarWidget(
|
||||
ctr: controller,
|
||||
child: parent.appBar as AppBar,
|
||||
),
|
||||
body: parent.body,
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildList(List<HistoryItemModel> list) {
|
||||
return SliverGrid(
|
||||
@@ -42,10 +68,8 @@ class _HistorySearchPageState
|
||||
return HistoryItem(
|
||||
item: item,
|
||||
ctr: controller,
|
||||
onChoose: null,
|
||||
onDelete: (kid, business) {
|
||||
controller.onDelHistory(index, kid, business);
|
||||
},
|
||||
onDelete: (kid, business) =>
|
||||
controller.onDelHistory(index, kid, business),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@@ -27,6 +27,12 @@ class LaterController extends MultiSelectController<LaterData, LaterItemModel> {
|
||||
|
||||
final LaterBaseController baseCtr = Get.put(LaterBaseController());
|
||||
|
||||
@override
|
||||
RxBool get enableMultiSelect => baseCtr.enableMultiSelect;
|
||||
|
||||
@override
|
||||
RxInt get rxCount => baseCtr.checkedCount;
|
||||
|
||||
@override
|
||||
Future<LoadingState<LaterData>> customGetData() => UserHttp.seeYouLater(
|
||||
page: page,
|
||||
@@ -34,36 +40,6 @@ class LaterController extends MultiSelectController<LaterData, LaterItemModel> {
|
||||
asc: asc.value,
|
||||
);
|
||||
|
||||
@override
|
||||
void onSelect(LaterItemModel item, [bool disableSelect = true]) {
|
||||
List<LaterItemModel> list = loadingState.value.data!;
|
||||
item.checked = !(item.checked ?? false);
|
||||
baseCtr.checkedCount.value = list
|
||||
.where((item) => item.checked == true)
|
||||
.length;
|
||||
loadingState.refresh();
|
||||
if (baseCtr.checkedCount.value == 0) {
|
||||
baseCtr.enableMultiSelect.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void handleSelect([bool checked = false, bool disableSelect = true]) {
|
||||
if (loadingState.value.isSuccess) {
|
||||
List<LaterItemModel>? list = loadingState.value.data;
|
||||
if (list?.isNotEmpty == true) {
|
||||
for (LaterItemModel item in list!) {
|
||||
item.checked = checked;
|
||||
}
|
||||
baseCtr.checkedCount.value = checked ? list.length : 0;
|
||||
loadingState.refresh();
|
||||
}
|
||||
}
|
||||
if (!checked) {
|
||||
baseCtr.enableMultiSelect.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
@@ -102,7 +78,7 @@ class LaterController extends MultiSelectController<LaterData, LaterItemModel> {
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
Get.back();
|
||||
var res = await UserHttp.toViewDel(aids: [aid]);
|
||||
final res = await UserHttp.toViewDel(aids: {aid!});
|
||||
if (res['status']) {
|
||||
baseCtr.counts[laterViewType] =
|
||||
baseCtr.counts[laterViewType]! - 1;
|
||||
@@ -148,51 +124,24 @@ class LaterController extends MultiSelectController<LaterData, LaterItemModel> {
|
||||
);
|
||||
}
|
||||
|
||||
void onDelChecked(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: const Text('提示'),
|
||||
content: const Text('确认删除所选稍后再看吗?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
_onDelete(
|
||||
loadingState.value.data!
|
||||
.where((e) => e.checked == true)
|
||||
.toList(),
|
||||
);
|
||||
},
|
||||
child: const Text('确认'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
@override
|
||||
void onConfirm() {
|
||||
showConfirmDialog(
|
||||
context: Get.context!,
|
||||
content: '确认删除所选稍后再看吗?',
|
||||
title: '提示',
|
||||
onConfirm: () => _onDelete(allChecked.toSet()),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _onDelete(List<LaterItemModel> result) async {
|
||||
Future<void> _onDelete(Set<LaterItemModel> result) async {
|
||||
SmartDialog.showLoading(msg: '请求中');
|
||||
List<int?> aids = result.map((item) => item.aid).toList();
|
||||
var res = await UserHttp.toViewDel(aids: aids);
|
||||
final res = await UserHttp.toViewDel(aids: result.map((item) => item.aid!));
|
||||
if (res['status']) {
|
||||
Set<LaterItemModel> remainList = loadingState.value.data!
|
||||
.toSet()
|
||||
.difference(result.toSet());
|
||||
afterDelete(result);
|
||||
|
||||
baseCtr.counts[laterViewType] =
|
||||
baseCtr.counts[laterViewType]! - aids.length;
|
||||
loadingState.value = Success(remainList.toList());
|
||||
baseCtr.counts[laterViewType]! - result.length;
|
||||
if (baseCtr.enableMultiSelect.value) {
|
||||
baseCtr.checkedCount.value = 0;
|
||||
baseCtr.enableMultiSelect.value = false;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:PiliPlus/common/widgets/appbar/appbar.dart';
|
||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||
import 'package:PiliPlus/models/common/later_view_type.dart';
|
||||
import 'package:PiliPlus/models_new/later/data.dart';
|
||||
import 'package:PiliPlus/models_new/later/list.dart';
|
||||
import 'package:PiliPlus/pages/history/view.dart' show AppBarWidget;
|
||||
import 'package:PiliPlus/pages/later/base_controller.dart';
|
||||
import 'package:PiliPlus/pages/later/controller.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
@@ -128,9 +128,54 @@ class _LaterPageState extends State<LaterPage>
|
||||
final theme = Theme.of(context);
|
||||
Color color = theme.colorScheme.secondary;
|
||||
|
||||
return AppBarWidget(
|
||||
return MultiSelectAppBarWidget(
|
||||
visible: enableMultiSelect,
|
||||
child1: AppBar(
|
||||
ctr: currCtr(),
|
||||
children: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () {
|
||||
final ctr = currCtr();
|
||||
RequestUtils.onCopyOrMove<LaterData, LaterItemModel>(
|
||||
context: context,
|
||||
isCopy: true,
|
||||
ctr: ctr,
|
||||
mediaId: null,
|
||||
mid: ctr.accountService.mid,
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'复制',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () {
|
||||
final ctr = currCtr();
|
||||
RequestUtils.onCopyOrMove<LaterData, LaterItemModel>(
|
||||
context: context,
|
||||
isCopy: false,
|
||||
ctr: ctr,
|
||||
mediaId: null,
|
||||
mid: ctr.accountService.mid,
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'移动',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
child: AppBar(
|
||||
title: const Text('稍后再看'),
|
||||
actions: [
|
||||
IconButton(
|
||||
@@ -251,76 +296,6 @@ class _LaterPageState extends State<LaterPage>
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
child2: AppBar(
|
||||
leading: IconButton(
|
||||
tooltip: '取消',
|
||||
onPressed: currCtr().handleSelect,
|
||||
icon: const Icon(Icons.close_outlined),
|
||||
),
|
||||
title: Obx(() => Text('已选: ${_baseCtr.checkedCount.value}')),
|
||||
actions: [
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () => currCtr().handleSelect(true),
|
||||
child: const Text('全选'),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () {
|
||||
final ctr = currCtr();
|
||||
RequestUtils.onCopyOrMove<LaterData, LaterItemModel>(
|
||||
context: context,
|
||||
isCopy: true,
|
||||
ctr: ctr,
|
||||
mediaId: null,
|
||||
mid: ctr.accountService.mid,
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'复制',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () {
|
||||
final ctr = currCtr();
|
||||
RequestUtils.onCopyOrMove<LaterData, LaterItemModel>(
|
||||
context: context,
|
||||
isCopy: false,
|
||||
ctr: ctr,
|
||||
mediaId: null,
|
||||
mid: ctr.accountService.mid,
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
'移动',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
visualDensity: VisualDensity.compact,
|
||||
),
|
||||
onPressed: () => currCtr().onDelChecked(context),
|
||||
child: Text(
|
||||
'移除',
|
||||
style: TextStyle(color: theme.colorScheme.error),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class LaterSearchController
|
||||
return response.list;
|
||||
}
|
||||
|
||||
Future<void> toViewDel(BuildContext context, int index, aid) async {
|
||||
Future<void> toViewDel(BuildContext context, int index, int aid) async {
|
||||
var res = await UserHttp.toViewDel(aids: [aid]);
|
||||
if (res['status']) {
|
||||
loadingState.value.data!.removeAt(index);
|
||||
@@ -31,4 +31,25 @@ class LaterSearchController
|
||||
}
|
||||
SmartDialog.showToast(res['msg']);
|
||||
}
|
||||
|
||||
// @override
|
||||
// void onConfirm() {
|
||||
// showConfirmDialog(
|
||||
// context: Get.context!,
|
||||
// content: '确认删除所选稍后再看吗?',
|
||||
// title: '提示',
|
||||
// onConfirm: () async {
|
||||
// final result = allChecked.toSet();
|
||||
// SmartDialog.showLoading(msg: '请求中');
|
||||
// var res = await UserHttp.toViewDel(
|
||||
// aids: result.map((item) => item.aid!),
|
||||
// );
|
||||
// if (res['status']) {
|
||||
// afterDelete(result);
|
||||
// }
|
||||
// SmartDialog.dismiss();
|
||||
// SmartDialog.showToast(res['msg']);
|
||||
// },
|
||||
// );
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -27,6 +27,31 @@ class _LaterSearchPageState
|
||||
tag: Utils.generateRandomString(8),
|
||||
);
|
||||
|
||||
// @override
|
||||
// Widget build(BuildContext context) {
|
||||
// // TODO: refa
|
||||
// return Obx(() {
|
||||
// final parent = super.build(context) as Scaffold;
|
||||
// final enableMultiSelect = controller.enableMultiSelect.value;
|
||||
// return PopScope(
|
||||
// canPop: !enableMultiSelect,
|
||||
// onPopInvokedWithResult: (didPop, result) {
|
||||
// if (enableMultiSelect) {
|
||||
// controller.handleSelect();
|
||||
// }
|
||||
// },
|
||||
// child: Scaffold(
|
||||
// resizeToAvoidBottomInset: parent.resizeToAvoidBottomInset,
|
||||
// appBar: MultiSelectAppBarWidget(
|
||||
// ctr: controller,
|
||||
// child: parent.appBar as AppBar,
|
||||
// ),
|
||||
// body: parent.body,
|
||||
// ),
|
||||
// );
|
||||
// });
|
||||
// }
|
||||
|
||||
@override
|
||||
Widget buildList(List<LaterItemModel> list) {
|
||||
return SliverGrid(
|
||||
@@ -73,7 +98,7 @@ class _LaterSearchPageState
|
||||
onConfirm: () => controller.toViewDel(
|
||||
context,
|
||||
index,
|
||||
item.aid,
|
||||
item.aid!,
|
||||
),
|
||||
),
|
||||
icon: Icons.clear,
|
||||
|
||||
@@ -14,7 +14,6 @@ import 'package:PiliPlus/models/common/reply/reply_sort_type.dart';
|
||||
import 'package:PiliPlus/models/common/settings_type.dart';
|
||||
import 'package:PiliPlus/models/common/super_resolution_type.dart';
|
||||
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_folder/data.dart';
|
||||
import 'package:PiliPlus/pages/common/common_slide_page.dart';
|
||||
import 'package:PiliPlus/pages/home/controller.dart';
|
||||
import 'package:PiliPlus/pages/hot/controller.dart';
|
||||
@@ -786,9 +785,8 @@ List<SettingsModel> get extraSettings => [
|
||||
onTap: () async {
|
||||
if (Accounts.main.isLogin) {
|
||||
final res = await FavHttp.allFavFolders(Accounts.main.mid);
|
||||
if (res['status']) {
|
||||
final FavFolderData data = res['data'];
|
||||
final list = data.list;
|
||||
if (res.isSuccess) {
|
||||
final list = res.data.list;
|
||||
if (list.isNullOrEmpty) {
|
||||
return;
|
||||
}
|
||||
@@ -821,7 +819,7 @@ List<SettingsModel> get extraSettings => [
|
||||
),
|
||||
);
|
||||
} else {
|
||||
SmartDialog.showToast('${res['msg']}');
|
||||
res.toast();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -18,7 +18,6 @@ import 'package:PiliPlus/http/validate.dart';
|
||||
import 'package:PiliPlus/http/video.dart';
|
||||
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||
import 'package:PiliPlus/models/login/model.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_folder/list.dart';
|
||||
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_tab/controller.dart';
|
||||
import 'package:PiliPlus/pages/group_panel/view.dart';
|
||||
@@ -376,11 +375,9 @@ class RequestUtils {
|
||||
required dynamic mid,
|
||||
}) {
|
||||
FavHttp.allFavFolders(mid).then((res) {
|
||||
if (context.mounted &&
|
||||
res['status'] &&
|
||||
(res['data'].list as List?)?.isNotEmpty == true) {
|
||||
List<FavFolderInfo> list = res['data'].list;
|
||||
dynamic checkedId;
|
||||
if (context.mounted && res.dataOrNull?.list?.isNotEmpty == true) {
|
||||
final list = res.data.list!;
|
||||
int? checkedId;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
@@ -392,7 +389,7 @@ class RequestUtils {
|
||||
builder: (context) => Column(
|
||||
children: List.generate(list.length, (index) {
|
||||
final item = list[index];
|
||||
return RadioWidget(
|
||||
return RadioWidget<int>(
|
||||
padding: const EdgeInsets.only(left: 14),
|
||||
title: item.title,
|
||||
groupValue: checkedId,
|
||||
@@ -421,9 +418,7 @@ class RequestUtils {
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
if (checkedId != null) {
|
||||
List resources = ctr.loadingState.value.data!
|
||||
.where((e) => e.checked == true)
|
||||
.toList();
|
||||
Set resources = ctr.allChecked.toSet();
|
||||
SmartDialog.showLoading();
|
||||
FavHttp.copyOrMoveFav(
|
||||
isCopy: isCopy,
|
||||
@@ -439,22 +434,20 @@ class RequestUtils {
|
||||
.toList(),
|
||||
mid: isCopy ? mid : null,
|
||||
).then((res) {
|
||||
if (res['status']) {
|
||||
if (res.isSuccess) {
|
||||
ctr.handleSelect(false);
|
||||
if (!isCopy) {
|
||||
List<T> dataList = ctr.loadingState.value.data!;
|
||||
List<T> remainList = dataList
|
||||
.toSet()
|
||||
.difference(resources.toSet())
|
||||
.toList();
|
||||
ctr.loadingState.value = Success(remainList);
|
||||
ctr.loadingState.value.data!.removeWhere(
|
||||
resources.contains,
|
||||
);
|
||||
ctr.loadingState.refresh();
|
||||
}
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast('${isCopy ? '复制' : '移动'}成功');
|
||||
Get.back();
|
||||
} else {
|
||||
SmartDialog.dismiss();
|
||||
SmartDialog.showToast('${res['msg']}');
|
||||
res.toast();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -466,7 +459,7 @@ class RequestUtils {
|
||||
},
|
||||
);
|
||||
} else {
|
||||
SmartDialog.showToast('${res['msg']}');
|
||||
res.toast();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user