mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt: follow dialog
fix: add user tags
This commit is contained in:
@@ -390,6 +390,10 @@ class Api {
|
|||||||
// 0 添加至默认分组 否则使用,分割tagid
|
// 0 添加至默认分组 否则使用,分割tagid
|
||||||
static const String addUsers = '/x/relation/tags/addUsers';
|
static const String addUsers = '/x/relation/tags/addUsers';
|
||||||
|
|
||||||
|
static const String addSpecial = '/x/relation/tag/special/add';
|
||||||
|
|
||||||
|
static const String delSpecial = '/x/relation/tag/special/del';
|
||||||
|
|
||||||
// 获取指定分组下的up
|
// 获取指定分组下的up
|
||||||
static const String followUpGroup = '/x/relation/tag';
|
static const String followUpGroup = '/x/relation/tag';
|
||||||
|
|
||||||
|
|||||||
@@ -210,15 +210,44 @@ class MemberHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future specialAction({
|
||||||
|
int? fid,
|
||||||
|
bool isAdd = true,
|
||||||
|
}) async {
|
||||||
|
var res = await Request().post(
|
||||||
|
isAdd ? Api.addSpecial : Api.delSpecial,
|
||||||
|
data: {
|
||||||
|
'fid': fid,
|
||||||
|
'csrf': await Request.getCsrf(),
|
||||||
|
},
|
||||||
|
options: Options(
|
||||||
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 设置分组
|
// 设置分组
|
||||||
static Future addUsers(int? fids, String? tagids) async {
|
static Future addUsers(int? fids, String? tagids) async {
|
||||||
var res = await Request().post(Api.addUsers, queryParameters: {
|
var res = await Request().post(
|
||||||
|
Api.addUsers,
|
||||||
|
data: {
|
||||||
'fids': fids,
|
'fids': fids,
|
||||||
'tagids': tagids ?? '0',
|
'tagids': tagids ?? '0',
|
||||||
'csrf': await Request.getCsrf(),
|
'csrf': await Request.getCsrf(),
|
||||||
}, data: {
|
// 'cross_domain': true
|
||||||
'cross_domain': true
|
},
|
||||||
});
|
options: Options(
|
||||||
|
contentType: Headers.formUrlEncodedContentType,
|
||||||
|
),
|
||||||
|
);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {'status': true, 'data': [], 'msg': '操作成功'};
|
return {'status': true, 'data': [], 'msg': '操作成功'};
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ class MemberController extends GetxController {
|
|||||||
mid = mid ?? int.parse(Get.parameters['mid']!);
|
mid = mid ?? int.parse(Get.parameters['mid']!);
|
||||||
userInfo = userInfoCache.get('userInfoCache');
|
userInfo = userInfoCache.get('userInfoCache');
|
||||||
ownerMid = userInfo != null ? userInfo.mid : -1;
|
ownerMid = userInfo != null ? userInfo.mid : -1;
|
||||||
|
try {
|
||||||
face.value = Get.arguments['face'] ?? '';
|
face.value = Get.arguments['face'] ?? '';
|
||||||
heroTag = Get.arguments['heroTag'] ?? '';
|
heroTag = Get.arguments['heroTag'] ?? '';
|
||||||
|
} catch (_) {}
|
||||||
relationSearch();
|
relationSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:PiliPalaX/http/loading_state.dart';
|
import 'package:PiliPalaX/http/loading_state.dart';
|
||||||
|
import 'package:PiliPalaX/http/member.dart';
|
||||||
import 'package:PiliPalaX/utils/utils.dart';
|
import 'package:PiliPalaX/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
@@ -30,7 +31,8 @@ import '../../../../models/model_hot_video_item.dart';
|
|||||||
import '../related/index.dart';
|
import '../related/index.dart';
|
||||||
import 'widgets/group_panel.dart';
|
import 'widgets/group_panel.dart';
|
||||||
|
|
||||||
class VideoIntroController extends GetxController {
|
class VideoIntroController extends GetxController
|
||||||
|
with GetTickerProviderStateMixin {
|
||||||
// 视频bvid
|
// 视频bvid
|
||||||
late String bvid;
|
late String bvid;
|
||||||
|
|
||||||
@@ -507,15 +509,140 @@ class VideoIntroController extends GetxController {
|
|||||||
SmartDialog.showToast('账号未登录');
|
SmartDialog.showToast('账号未登录');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (videoDetail.value.owner?.mid == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
feedBack();
|
feedBack();
|
||||||
int mid = videoDetail.value.owner!.mid!;
|
int mid = videoDetail.value.owner!.mid!;
|
||||||
MemberController _ = Get.put<MemberController>(MemberController(mid: mid),
|
if ((followStatus['attribute'] ?? 0) == 0) {
|
||||||
tag: mid.toString());
|
var res = await VideoHttp.relationMod(
|
||||||
await _.getInfo();
|
mid: mid,
|
||||||
if (context.mounted) await _.actionRelationMod(context);
|
act: 1,
|
||||||
followStatus['attribute'] = _.attribute.value;
|
reSrc: 11,
|
||||||
|
);
|
||||||
|
SmartDialog.showToast(res['status'] ? "关注成功" : res['msg']);
|
||||||
|
if (res['status']) {
|
||||||
|
followStatus['attribute'] = 2;
|
||||||
followStatus.refresh();
|
followStatus.refresh();
|
||||||
Get.delete<MemberController>(tag: mid.toString());
|
}
|
||||||
|
} else {
|
||||||
|
/// TODO
|
||||||
|
showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (_) {
|
||||||
|
bool isSpecialFollowed = followStatus['special'] == 1;
|
||||||
|
String text = isSpecialFollowed ? '移除特别关注' : '加入特别关注';
|
||||||
|
return AlertDialog(
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
onTap: () async {
|
||||||
|
Get.back();
|
||||||
|
final res = await MemberHttp.specialAction(
|
||||||
|
fid: mid,
|
||||||
|
isAdd: !isSpecialFollowed,
|
||||||
|
);
|
||||||
|
if (res['status']) {
|
||||||
|
followStatus['special'] = isSpecialFollowed ? 0 : 1;
|
||||||
|
List tags = followStatus['tag'] ?? [];
|
||||||
|
if (isSpecialFollowed) {
|
||||||
|
tags.remove(-10);
|
||||||
|
} else {
|
||||||
|
tags.add(-10);
|
||||||
|
}
|
||||||
|
followStatus['tag'] = tags;
|
||||||
|
followStatus.refresh();
|
||||||
|
SmartDialog.showToast('$text成功');
|
||||||
|
} else {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: Text(
|
||||||
|
text,
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
onTap: () async {
|
||||||
|
Get.back();
|
||||||
|
dynamic result = await showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
useSafeArea: true,
|
||||||
|
isScrollControlled: true,
|
||||||
|
transitionAnimationController: AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
vsync: this,
|
||||||
|
),
|
||||||
|
sheetAnimationStyle: AnimationStyle(curve: Curves.ease),
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return DraggableScrollableSheet(
|
||||||
|
minChildSize: 0,
|
||||||
|
maxChildSize: 1,
|
||||||
|
initialChildSize: 0.6,
|
||||||
|
snap: true,
|
||||||
|
expand: false,
|
||||||
|
snapSizes: const [0.6],
|
||||||
|
builder: (BuildContext context,
|
||||||
|
ScrollController scrollController) {
|
||||||
|
return GroupPanel(
|
||||||
|
mid: mid,
|
||||||
|
tags: followStatus['tag'],
|
||||||
|
scrollController: scrollController,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await Future.delayed(const Duration(milliseconds: 500));
|
||||||
|
if (result == true) {
|
||||||
|
queryFollowStatus();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: const Text(
|
||||||
|
'设置分组',
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
onTap: () async {
|
||||||
|
Get.back();
|
||||||
|
var res = await VideoHttp.relationMod(
|
||||||
|
mid: mid,
|
||||||
|
act: 2,
|
||||||
|
reSrc: 11,
|
||||||
|
);
|
||||||
|
SmartDialog.showToast(
|
||||||
|
res['status'] ? "取消关注成功" : res['msg']);
|
||||||
|
if (res['status']) {
|
||||||
|
followStatus['attribute'] = 0;
|
||||||
|
followStatus.refresh();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: const Text(
|
||||||
|
'取消关注',
|
||||||
|
style: TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MemberController _ = Get.put<MemberController>(MemberController(mid: mid),
|
||||||
|
// tag: mid.toString());
|
||||||
|
// await _.getInfo();
|
||||||
|
// if (context.mounted) await _.actionRelationMod(context);
|
||||||
|
// followStatus['attribute'] = _.attribute.value;
|
||||||
|
// followStatus.refresh();
|
||||||
|
// Get.delete<MemberController>(tag: mid.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改分P或番剧分集
|
// 修改分P或番剧分集
|
||||||
|
|||||||
@@ -10,7 +10,14 @@ import '../../../../../utils/utils.dart';
|
|||||||
|
|
||||||
class GroupPanel extends StatefulWidget {
|
class GroupPanel extends StatefulWidget {
|
||||||
final int? mid;
|
final int? mid;
|
||||||
const GroupPanel({super.key, this.mid});
|
final List? tags;
|
||||||
|
final ScrollController? scrollController;
|
||||||
|
const GroupPanel({
|
||||||
|
super.key,
|
||||||
|
this.mid,
|
||||||
|
this.tags,
|
||||||
|
this.scrollController,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<GroupPanel> createState() => _GroupPanelState();
|
State<GroupPanel> createState() => _GroupPanelState();
|
||||||
@@ -19,12 +26,25 @@ class GroupPanel extends StatefulWidget {
|
|||||||
class _GroupPanelState extends State<GroupPanel> {
|
class _GroupPanelState extends State<GroupPanel> {
|
||||||
late Future _futureBuilderFuture;
|
late Future _futureBuilderFuture;
|
||||||
late List<MemberTagItemModel> tagsList;
|
late List<MemberTagItemModel> tagsList;
|
||||||
bool showDefault = true;
|
bool showDefaultBtn = true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_futureBuilderFuture = MemberHttp.followUpTags();
|
_futureBuilderFuture = MemberHttp.followUpTags();
|
||||||
|
() async {
|
||||||
|
dynamic result = await _futureBuilderFuture;
|
||||||
|
if (result['status']) {
|
||||||
|
tagsList = result['data'];
|
||||||
|
tagsList.removeWhere((item) => item.tagid == 0);
|
||||||
|
tagsList = tagsList.map((item) {
|
||||||
|
return item..checked = widget.tags?.contains(item.tagid) == true;
|
||||||
|
}).toList();
|
||||||
|
setState(() {
|
||||||
|
showDefaultBtn = !tagsList.any((e) => e.checked == true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onSave() async {
|
void onSave() async {
|
||||||
@@ -46,26 +66,40 @@ class _GroupPanelState extends State<GroupPanel> {
|
|||||||
final res = await MemberHttp.addUsers(widget.mid, tagids);
|
final res = await MemberHttp.addUsers(widget.mid, tagids);
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
Get.back();
|
Get.back(result: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return NotificationListener<DraggableScrollableNotification>(
|
||||||
height: Utils.getSheetHeight(context),
|
onNotification: (notification) {
|
||||||
color: Theme.of(context).colorScheme.background,
|
if (notification.extent <= 1e-5) {
|
||||||
|
Get.back();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(18),
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
AppBar(
|
AppBar(
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(
|
||||||
|
top: Radius.circular(18),
|
||||||
|
),
|
||||||
|
),
|
||||||
centerTitle: false,
|
centerTitle: false,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
leading: IconButton(
|
leading: IconButton(
|
||||||
tooltip: '关闭',
|
tooltip: '关闭',
|
||||||
onPressed: () => Get.back(),
|
onPressed: Get.back,
|
||||||
icon: const Icon(Icons.close_outlined)),
|
icon: const Icon(Icons.close_outlined)),
|
||||||
title:
|
title: Text('设置关注分组',
|
||||||
Text('设置关注分组', style: Theme.of(context).textTheme.titleMedium),
|
style: Theme.of(context).textTheme.titleMedium),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Material(
|
child: Material(
|
||||||
@@ -75,33 +109,33 @@ class _GroupPanelState extends State<GroupPanel> {
|
|||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
Map data = snapshot.data as Map;
|
Map data = snapshot.data as Map;
|
||||||
if (data['status']) {
|
if (data['status']) {
|
||||||
tagsList = data['data'];
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: data['data'].length,
|
controller: widget.scrollController,
|
||||||
|
itemCount: tagsList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
data['data'][index].checked =
|
tagsList[index].checked =
|
||||||
!data['data'][index].checked;
|
!tagsList[index].checked!;
|
||||||
showDefault =
|
showDefaultBtn =
|
||||||
!data['data'].any((e) => e.checked == true);
|
!tagsList.any((e) => e.checked == true);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
dense: true,
|
dense: true,
|
||||||
leading: const Icon(Icons.group_outlined),
|
leading: const Icon(Icons.group_outlined),
|
||||||
minLeadingWidth: 0,
|
minLeadingWidth: 0,
|
||||||
title: Text(data['data'][index].name),
|
title: Text(tagsList[index].name ?? ''),
|
||||||
subtitle: data['data'][index].tip != ''
|
subtitle: tagsList[index].tip != ''
|
||||||
? Text(data['data'][index].tip)
|
? Text(tagsList[index].tip ?? '')
|
||||||
: null,
|
: null,
|
||||||
trailing: Transform.scale(
|
trailing: Transform.scale(
|
||||||
scale: 0.9,
|
scale: 0.9,
|
||||||
child: Checkbox(
|
child: Checkbox(
|
||||||
value: data['data'][index].checked,
|
value: tagsList[index].checked,
|
||||||
onChanged: (bool? checkValue) {
|
onChanged: (bool? checkValue) {
|
||||||
data['data'][index].checked = checkValue;
|
tagsList[index].checked = checkValue;
|
||||||
showDefault = !data['data']
|
showDefaultBtn =
|
||||||
.any((e) => e.checked == true);
|
!tagsList.any((e) => e.checked == true);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -110,14 +144,21 @@ class _GroupPanelState extends State<GroupPanel> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return HttpError(
|
return CustomScrollView(
|
||||||
|
controller: widget.scrollController,
|
||||||
|
slivers: [
|
||||||
|
HttpError(
|
||||||
errMsg: data['msg'],
|
errMsg: data['msg'],
|
||||||
fn: () => setState(() {}),
|
fn: () => setState(() {}),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 骨架屏
|
// 骨架屏
|
||||||
return const Text('请求中');
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -145,13 +186,14 @@ class _GroupPanelState extends State<GroupPanel> {
|
|||||||
backgroundColor:
|
backgroundColor:
|
||||||
Theme.of(context).colorScheme.primary, // 设置按钮背景色
|
Theme.of(context).colorScheme.primary, // 设置按钮背景色
|
||||||
),
|
),
|
||||||
child: Text(showDefault ? '保存至默认分组' : '保存'),
|
child: Text(showDefaultBtn ? '保存至默认分组' : '保存'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user