From 6d982bdba26cff946363b1dac8c9797d251cde41 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 28 Sep 2023 19:58:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A7=86=E9=A2=91=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E9=A1=B5=E5=85=B3=E6=B3=A8=E5=88=86=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 7 + lib/http/member.dart | 40 +++++ lib/models/member/tags.dart | 23 +++ .../video/detail/introduction/controller.dart | 24 +++ .../introduction/widgets/group_panel.dart | 156 ++++++++++++++++++ 5 files changed, 250 insertions(+) create mode 100644 lib/models/member/tags.dart create mode 100644 lib/pages/video/detail/introduction/widgets/group_panel.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index 288f0b2b..2350715f 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -306,4 +306,11 @@ class Api { static const String onlineTotal = '/x/player/online/total'; static const String webDanmaku = '/x/v2/dm/web/seg.so'; + + // up主分组 + static const String followUpTag = '/x/relation/tags'; + + // 设置Up主分组 + // 0 添加至默认分组 否则使用,分割tagid + static const String addUsers = '/x/relation/tags/addUsers'; } diff --git a/lib/http/member.dart b/lib/http/member.dart index a9c158da..764d3af0 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -2,6 +2,7 @@ import 'package:pilipala/http/index.dart'; import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/models/member/archive.dart'; import 'package:pilipala/models/member/info.dart'; +import 'package:pilipala/models/member/tags.dart'; import 'package:pilipala/utils/wbi_sign.dart'; class MemberHttp { @@ -144,4 +145,43 @@ class MemberHttp { }; } } + + // 查询分组 + static Future followUpTags() async { + var res = await Request().get(Api.followUpTag); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': res.data['data'] + .map((e) => MemberTagItemModel.fromJson(e)) + .toList() + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } + + // 设置分组 + static Future addUsers(int? fids, String? tagids) async { + var res = await Request().post(Api.addUsers, queryParameters: { + 'fids': fids, + 'tagids': tagids ?? '0', + 'csrf': await Request.getCsrf(), + }, data: { + 'cross_domain': true + }); + if (res.data['code'] == 0) { + return {'status': true, 'data': [], 'msg': '操作成功'}; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } } diff --git a/lib/models/member/tags.dart b/lib/models/member/tags.dart new file mode 100644 index 00000000..33f7c1f8 --- /dev/null +++ b/lib/models/member/tags.dart @@ -0,0 +1,23 @@ +class MemberTagItemModel { + MemberTagItemModel({ + this.count, + this.name, + this.tagid, + this.tip, + this.checked, + }); + + int? count; + String? name; + int? tagid; + String? tip; + bool? checked; + + MemberTagItemModel.fromJson(Map json) { + count = json['count']; + name = json['name']; + tagid = json['tagid']; + tip = json['tip']; + checked = false; + } +} diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 04ece4a0..6c32dc33 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -17,6 +17,8 @@ import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:share_plus/share_plus.dart'; +import 'widgets/group_panel.dart'; + class VideoIntroController extends GetxController { // 视频bvid String bvid = Get.parameters['bvid']!; @@ -428,6 +430,20 @@ class VideoIntroController extends GetxController { } followStatus['attribute'] = actionStatus; followStatus.refresh(); + if (actionStatus == 2) { + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('关注成功'), + duration: const Duration(seconds: 2), + action: SnackBarAction( + label: '设置分组', + onPressed: setFollowGroup, + ), + ), + ); + } + } } SmartDialog.dismiss(); }, @@ -537,4 +553,12 @@ class VideoIntroController extends GetxController { int aid = episodes[nextIndex].aid!; changeSeasonOrbangu(bvid, cid, aid); } + + // 设置关注分组 + void setFollowGroup() { + Get.bottomSheet( + GroupPanel(mid: videoDetail.value.owner!.mid!), + isScrollControlled: true, + ); + } } diff --git a/lib/pages/video/detail/introduction/widgets/group_panel.dart b/lib/pages/video/detail/introduction/widgets/group_panel.dart new file mode 100644 index 00000000..0a105f9d --- /dev/null +++ b/lib/pages/video/detail/introduction/widgets/group_panel.dart @@ -0,0 +1,156 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:hive/hive.dart'; +import 'package:pilipala/common/widgets/http_error.dart'; +import 'package:pilipala/http/member.dart'; +import 'package:pilipala/models/member/tags.dart'; +import 'package:pilipala/utils/feed_back.dart'; +import 'package:pilipala/utils/storage.dart'; + +class GroupPanel extends StatefulWidget { + final int? mid; + const GroupPanel({super.key, this.mid}); + + @override + State createState() => _GroupPanelState(); +} + +class _GroupPanelState extends State { + Box localCache = GStrorage.localCache; + late double sheetHeight; + late Future _futureBuilderFuture; + late List tagsList; + bool showDefault = true; + + @override + void initState() { + super.initState(); + sheetHeight = localCache.get('sheetHeight'); + _futureBuilderFuture = MemberHttp.followUpTags(); + } + + void onSave() async { + feedBack(); + // 是否有选中的 有选中的带id,没选使用默认0 + bool anyHasChecked = tagsList.any((e) => e.checked == true); + late String tagids; + if (anyHasChecked) { + List checkedList = tagsList.where((e) => e.checked == true).toList(); + List tagidList = checkedList.map((e) => e.tagid).toList(); + tagids = tagidList.join(','); + } else { + tagids = '0'; + } + // 保存 + var res = await MemberHttp.addUsers(widget.mid, tagids); + SmartDialog.showToast(res['msg']); + if (res['status']) { + Get.back(); + } + } + + @override + Widget build(BuildContext context) { + return Container( + height: sheetHeight, + color: Theme.of(context).colorScheme.background, + child: Column( + children: [ + AppBar( + centerTitle: false, + elevation: 0, + leading: IconButton( + onPressed: () => Get.back(), + icon: const Icon(Icons.close_outlined)), + title: + Text('设置关注分组', style: Theme.of(context).textTheme.titleMedium), + ), + Expanded( + child: Material( + child: FutureBuilder( + future: _futureBuilderFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + Map data = snapshot.data as Map; + if (data['status']) { + tagsList = data['data']; + return ListView.builder( + itemCount: data['data'].length, + itemBuilder: (context, index) { + return ListTile( + onTap: () { + data['data'][index].checked = + !data['data'][index].checked; + showDefault = + !data['data'].any((e) => e.checked == true); + setState(() {}); + }, + dense: true, + leading: const Icon(Icons.group_outlined), + minLeadingWidth: 0, + title: Text(data['data'][index].name), + subtitle: data['data'][index].tip != '' + ? Text(data['data'][index].tip) + : null, + trailing: Transform.scale( + scale: 0.9, + child: Checkbox( + value: data['data'][index].checked, + onChanged: (bool? checkValue) { + data['data'][index].checked = checkValue; + showDefault = !data['data'] + .any((e) => e.checked == true); + setState(() {}); + }, + ), + ), + ); + }, + ); + } else { + return HttpError( + errMsg: data['msg'], + fn: () => setState(() {}), + ); + } + } else { + // 骨架屏 + return const Text('请求中'); + } + }, + ), + ), + ), + Divider( + height: 1, + 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( + mainAxisAlignment: MainAxisAlignment.end, + 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(showDefault ? '保存至默认分组' : '保存'), + ), + ], + ), + ), + ], + ), + ); + } +}