opt: follow dialog

fix: add user tags
This commit is contained in:
bggRGjQaUbCoE
2024-10-08 10:35:55 +08:00
parent 5d0e4ed441
commit e6b71d375f
5 changed files with 313 additions and 109 deletions

View File

@@ -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';

View File

@@ -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 {

View File

@@ -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();
} }

View File

@@ -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或番剧分集

View File

@@ -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 ? '保存至默认分组' : '保存'),
), ),
], ],
), ),
), ),
], ],
), ),
),
); );
} }
} }