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(
'fids': fids, Api.addUsers,
'tagids': tagids ?? '0', data: {
'csrf': await Request.getCsrf(), 'fids': fids,
}, data: { 'tagids': tagids ?? '0',
'cross_domain': true 'csrf': await Request.getCsrf(),
}); // '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;
face.value = Get.arguments['face'] ?? ''; try {
heroTag = Get.arguments['heroTag'] ?? ''; face.value = Get.arguments['face'] ?? '';
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,
followStatus.refresh(); );
Get.delete<MemberController>(tag: mid.toString()); SmartDialog.showToast(res['status'] ? "关注成功" : res['msg']);
if (res['status']) {
followStatus['attribute'] = 2;
followStatus.refresh();
}
} 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,111 +66,133 @@ 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) {
child: Column( Get.back();
children: <Widget>[ }
AppBar( return false;
centerTitle: false, },
elevation: 0, child: Container(
leading: IconButton( decoration: BoxDecoration(
tooltip: '关闭', borderRadius: BorderRadius.circular(18),
onPressed: () => Get.back(), color: Theme.of(context).colorScheme.surface,
icon: const Icon(Icons.close_outlined)), ),
title: child: Column(
Text('设置关注分组', style: Theme.of(context).textTheme.titleMedium), children: <Widget>[
), AppBar(
Expanded( shape: const RoundedRectangleBorder(
child: Material( borderRadius: BorderRadius.vertical(
child: FutureBuilder( top: Radius.circular(18),
future: _futureBuilderFuture, ),
builder: (BuildContext context, AsyncSnapshot snapshot) { ),
if (snapshot.connectionState == ConnectionState.done) { centerTitle: false,
Map data = snapshot.data as Map; elevation: 0,
if (data['status']) { leading: IconButton(
tagsList = data['data']; tooltip: '关闭',
return ListView.builder( onPressed: Get.back,
itemCount: data['data'].length, icon: const Icon(Icons.close_outlined)),
itemBuilder: (context, index) { title: Text('设置关注分组',
return ListTile( style: Theme.of(context).textTheme.titleMedium),
onTap: () { ),
data['data'][index].checked = Expanded(
!data['data'][index].checked; child: Material(
showDefault = child: FutureBuilder(
!data['data'].any((e) => e.checked == true); future: _futureBuilderFuture,
setState(() {}); builder: (BuildContext context, AsyncSnapshot snapshot) {
}, if (snapshot.connectionState == ConnectionState.done) {
dense: true, Map data = snapshot.data as Map;
leading: const Icon(Icons.group_outlined), if (data['status']) {
minLeadingWidth: 0, return ListView.builder(
title: Text(data['data'][index].name), controller: widget.scrollController,
subtitle: data['data'][index].tip != '' itemCount: tagsList.length,
? Text(data['data'][index].tip) itemBuilder: (context, index) {
: null, return ListTile(
trailing: Transform.scale( onTap: () {
scale: 0.9, tagsList[index].checked =
child: Checkbox( !tagsList[index].checked!;
value: data['data'][index].checked, showDefaultBtn =
onChanged: (bool? checkValue) { !tagsList.any((e) => e.checked == true);
data['data'][index].checked = checkValue; setState(() {});
showDefault = !data['data'] },
.any((e) => e.checked == true); dense: true,
setState(() {}); leading: const Icon(Icons.group_outlined),
}, minLeadingWidth: 0,
title: Text(tagsList[index].name ?? ''),
subtitle: tagsList[index].tip != ''
? Text(tagsList[index].tip ?? '')
: null,
trailing: Transform.scale(
scale: 0.9,
child: Checkbox(
value: tagsList[index].checked,
onChanged: (bool? checkValue) {
tagsList[index].checked = checkValue;
showDefaultBtn =
!tagsList.any((e) => e.checked == true);
setState(() {});
},
),
), ),
);
},
);
} else {
return CustomScrollView(
controller: widget.scrollController,
slivers: [
HttpError(
errMsg: data['msg'],
fn: () => setState(() {}),
), ),
); ],
}, );
); }
} else { } else {
return HttpError( // 骨架屏
errMsg: data['msg'], return const Center(
fn: () => setState(() {}), child: CircularProgressIndicator(),
); );
} }
} else { },
// 骨架屏 ),
return const Text('请求中');
}
},
), ),
), ),
), Divider(
Divider( height: 1,
height: 1, color: Theme.of(context).disabledColor.withOpacity(0.08),
color: Theme.of(context).disabledColor.withOpacity(0.08),
),
Padding(
padding: EdgeInsets.only(
left: 20,
right: 20,
top: 12,
bottom: MediaQuery.of(context).padding.bottom + 12,
), ),
child: Row( Padding(
mainAxisAlignment: MainAxisAlignment.end, padding: EdgeInsets.only(
children: [ left: 20,
TextButton( right: 20,
onPressed: () => onSave(), top: 12,
style: TextButton.styleFrom( bottom: MediaQuery.of(context).padding.bottom + 12,
padding: const EdgeInsets.only(left: 30, right: 30), ),
foregroundColor: Theme.of(context).colorScheme.onPrimary, child: Row(
backgroundColor: mainAxisAlignment: MainAxisAlignment.end,
Theme.of(context).colorScheme.primary, // 设置按钮背景色 children: [
TextButton(
onPressed: () => onSave(),
style: TextButton.styleFrom(
padding: const EdgeInsets.only(left: 30, right: 30),
foregroundColor: Theme.of(context).colorScheme.onPrimary,
backgroundColor:
Theme.of(context).colorScheme.primary, // 设置按钮背景色
),
child: Text(showDefaultBtn ? '保存至默认分组' : '保存'),
), ),
child: Text(showDefault ? '保存至默认分组' : '保存'), ],
), ),
],
), ),
), ],
], ),
), ),
); );
} }