diff --git a/lib/http/api.dart b/lib/http/api.dart index 93226946..6cb4659a 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -559,6 +559,12 @@ class Api { static const String systemMarkRead = '${HttpString.messageBaseUrl}/x/sys-msg/update_cursor'; + /// 编辑收藏夹 + static const String editFavFolder = '/x/v3/fav/folder/edit'; + + /// 新建收藏夹 + static const String addFavFolder = '/x/v3/fav/folder/add'; + /// 直播间弹幕信息 static const String getDanmuInfo = '${HttpString.liveBaseUrl}/xlive/web-room/v1/index/getDanmuInfo'; diff --git a/lib/http/fav.dart b/lib/http/fav.dart new file mode 100644 index 00000000..6f49d68a --- /dev/null +++ b/lib/http/fav.dart @@ -0,0 +1,67 @@ +import 'index.dart'; + +class FavHttp { + /// 编辑收藏夹 + static Future editFolder({ + required String title, + required String intro, + required String mediaId, + String? cover, + int? privacy, + }) async { + var res = await Request().post( + Api.editFavFolder, + queryParameters: { + 'title': title, + 'intro': intro, + 'media_id': mediaId, + 'cover': cover ?? '', + 'privacy': privacy ?? 0, + 'csrf': await Request.getCsrf(), + }, + ); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': res.data['data'], + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } + + /// 新建收藏夹 + static Future addFolder({ + required String title, + required String intro, + String? cover, + int? privacy, + }) async { + var res = await Request().post( + Api.addFavFolder, + queryParameters: { + 'title': title, + 'intro': intro, + 'cover': cover ?? '', + 'privacy': privacy ?? 0, + 'csrf': await Request.getCsrf(), + }, + ); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': res.data['data'], + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } +} diff --git a/lib/http/user.dart b/lib/http/user.dart index 972acfdd..7d0b29a3 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -57,6 +57,8 @@ class UserHttp { if (res.data['data'] != null) { data = FavFolderData.fromJson(res.data['data']); return {'status': true, 'data': data}; + } else { + return {'status': false, 'msg': '收藏夹为空'}; } } else { return { diff --git a/lib/pages/dynamics/widgets/video_panel.dart b/lib/pages/dynamics/widgets/video_panel.dart index 828fb283..75f16a3b 100644 --- a/lib/pages/dynamics/widgets/video_panel.dart +++ b/lib/pages/dynamics/widgets/video_panel.dart @@ -86,7 +86,7 @@ Widget videoSeasonWidget(item, context, type, {floor = 1}) { height: width / StyleString.aspectRatio, src: content.cover, ), - if (content.badge != null && type == 'pgc') + if (content.badge != null && content.badge['text'] != null) PBadge( text: content.badge['text'], top: 8.0, diff --git a/lib/pages/fav/view.dart b/lib/pages/fav/view.dart index 7010ba0d..f6164609 100644 --- a/lib/pages/fav/view.dart +++ b/lib/pages/fav/view.dart @@ -55,6 +55,22 @@ class _FavPageState extends State { tooltip: 'Ta的订阅', ) : const SizedBox.shrink()), + + // 新建收藏夹 + Obx(() => _favController.isOwner.value + ? IconButton( + onPressed: () async { + await Get.toNamed('/favEdit'); + _favController.hasMore.value = true; + _favController.currentPage = 1; + setState(() { + _futureBuilderFuture = _favController.queryFavFolder(); + }); + }, + icon: const Icon(Icons.add_outlined), + tooltip: '新建收藏夹', + ) + : const SizedBox.shrink()), IconButton( onPressed: () => Get.toNamed( '/favSearch?searchType=1&mediaId=${_favController.favFolderData.value.list!.first.id}'), diff --git a/lib/pages/fav/widgets/item.dart b/lib/pages/fav/widgets/item.dart index 9d453fb5..25b92a5c 100644 --- a/lib/pages/fav/widgets/item.dart +++ b/lib/pages/fav/widgets/item.dart @@ -74,7 +74,7 @@ class VideoContent extends StatelessWidget { Widget build(BuildContext context) { return Expanded( child: Padding( - padding: const EdgeInsets.fromLTRB(10, 2, 6, 0), + padding: const EdgeInsets.fromLTRB(10, 2, 6, 10), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -94,6 +94,15 @@ class VideoContent extends StatelessWidget { color: Theme.of(context).colorScheme.outline, ), ), + const Spacer(), + Text( + [23, 1].contains(favFolderItem.attr) ? '私密' : '公开', + textAlign: TextAlign.start, + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + color: Theme.of(context).colorScheme.outline, + ), + ), ], ), ), diff --git a/lib/pages/fav_detail/controller.dart b/lib/pages/fav_detail/controller.dart index 3f87c226..e0158587 100644 --- a/lib/pages/fav_detail/controller.dart +++ b/lib/pages/fav_detail/controller.dart @@ -115,4 +115,17 @@ class FavDetailController extends GetxController { }, ); } + + onEditFavFolder() async { + Get.toNamed( + '/favEdit', + arguments: { + 'mediaId': mediaId.toString(), + 'title': item!.title, + 'intro': item!.intro, + 'cover': item!.cover, + 'privacy': item!.attr, + }, + ); + } } diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index cb9d7e7b..c1865355 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -106,6 +106,11 @@ class _FavDetailPageState extends State { position: PopupMenuPosition.under, onSelected: (String type) {}, itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + onTap: () => _favDetailController.onEditFavFolder(), + value: 'edit', + child: const Text('编辑收藏夹'), + ), PopupMenuItem( onTap: () => _favDetailController.onDelFavFolder(), value: 'pause', diff --git a/lib/pages/fav_edit/controller.dart b/lib/pages/fav_edit/controller.dart new file mode 100644 index 00000000..4772caee --- /dev/null +++ b/lib/pages/fav_edit/controller.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/http/fav.dart'; + +class FavEditController extends GetxController { + final GlobalKey formKey = GlobalKey(); + final TextEditingController titleController = TextEditingController(); + final TextEditingController contentController = TextEditingController(); + + final FocusNode titleTextFieldNode = FocusNode(); + final FocusNode contentTextFieldNode = FocusNode(); + + // 默认新建 + RxString type = 'add'.obs; + + String? mediaId; + String cover = ''; // 封面 + String title = ''; // 名称 + String intro = ''; // 简介 + RxInt privacy = 0.obs; // 是否公开 0公开 1私密 + + @override + void onInit() { + super.onInit(); + var args = Get.arguments; + if (args != null) { + type.value = 'edit'; + mediaId = args['mediaId']; + title = args['title']; + intro = args['intro']; + cover = args['cover']; + privacy.value = args['privacy']; + titleController.text = title; + contentController.text = intro; + } + } + + void onSubmit() async { + // 表单验证 + if ((formKey.currentState as FormState).validate()) { + if (type.value == 'edit') { + await editFolder(); + } else { + await addFolder(); + } + } + } + + Future editFolder() async { + var res = await FavHttp.editFolder( + title: title, + intro: intro, + mediaId: mediaId!, + cover: cover, + ); + if (res['status']) { + SmartDialog.showToast('编辑成功'); + Get.back(); + } else { + SmartDialog.showToast(res['msg']); + } + } + + Future addFolder() async { + var res = await FavHttp.addFolder( + title: title, + intro: intro, + ); + if (res['status']) { + SmartDialog.showToast('新建成功'); + Get.back(); + } else { + SmartDialog.showToast(res['msg']); + } + } +} diff --git a/lib/pages/fav_edit/index.dart b/lib/pages/fav_edit/index.dart new file mode 100644 index 00000000..872df8d4 --- /dev/null +++ b/lib/pages/fav_edit/index.dart @@ -0,0 +1,4 @@ +library fav_edit; + +export './controller.dart'; +export './view.dart'; diff --git a/lib/pages/fav_edit/view.dart b/lib/pages/fav_edit/view.dart new file mode 100644 index 00000000..3ef7cda3 --- /dev/null +++ b/lib/pages/fav_edit/view.dart @@ -0,0 +1,111 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'controller.dart'; + +class FavEditPage extends StatefulWidget { + const FavEditPage({super.key}); + + @override + State createState() => _FavEditPageState(); +} + +class _FavEditPageState extends State { + final FavEditController _favEditController = Get.put(FavEditController()); + String title = ''; + String content = ''; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + elevation: 0, + scrolledUnderElevation: 0, + title: Obx( + () => _favEditController.type.value == 'add' + ? Text( + '新建收藏夹', + style: Theme.of(context).textTheme.titleMedium, + ) + : Text( + '编辑收藏夹', + style: Theme.of(context).textTheme.titleMedium, + ), + ), + centerTitle: false, + actions: [ + Obx( + () => _favEditController.privacy.value == 0 + ? IconButton( + onPressed: () { + _favEditController.privacy.value = 1; + }, + icon: const Icon(Icons.lock_open_outlined)) + : IconButton( + onPressed: () { + _favEditController.privacy.value = 0; + }, + icon: Icon( + Icons.lock_outlined, + color: Theme.of(context).colorScheme.error, + )), + ), + TextButton( + onPressed: _favEditController.onSubmit, child: const Text('保存')), + const SizedBox(width: 14), + ], + ), + body: Form( + key: _favEditController.formKey, //设置globalKey,用于后面获取FormState + autovalidateMode: AutovalidateMode.disabled, + child: Column( + children: [ + Container( + padding: const EdgeInsets.fromLTRB(14, 10, 14, 5), + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Theme.of(context).dividerColor.withOpacity(0.2), + ), + ), + ), + child: TextFormField( + autofocus: true, + controller: _favEditController.titleController, + focusNode: _favEditController.titleTextFieldNode, + decoration: const InputDecoration( + hintText: "收藏夹名称", + enabledBorder: InputBorder.none, + focusedBorder: InputBorder.none, + ), + // 校验标题 + validator: (v) { + return v!.trim().isNotEmpty ? null : "请输入收藏夹名称"; + }, + onChanged: (val) { + _favEditController.title = val; + }, + ), + ), + Expanded( + child: Container( + padding: + const EdgeInsets.symmetric(horizontal: 14, vertical: 5), + child: TextFormField( + controller: _favEditController.contentController, + minLines: 1, + maxLines: 5, + decoration: const InputDecoration( + hintText: '输入收藏夹简介', border: InputBorder.none), + style: Theme.of(context).textTheme.bodyLarge, + onChanged: (val) { + _favEditController.intro = val; + }, + )), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/follow/widgets/follow_item.dart b/lib/pages/follow/widgets/follow_item.dart index 3d393277..6ee93a98 100644 --- a/lib/pages/follow/widgets/follow_item.dart +++ b/lib/pages/follow/widgets/follow_item.dart @@ -49,7 +49,10 @@ class FollowItem extends StatelessWidget { child: TextButton( onPressed: () async { await showFlexibleBottomSheet( - bottomSheetColor: Colors.transparent, + bottomSheetBorderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), minHeight: 1, initHeight: 1, maxHeight: 1, diff --git a/lib/pages/setting/pages/navigation_bar_set.dart b/lib/pages/setting/pages/navigation_bar_set.dart index 09e92bc3..05407c16 100644 --- a/lib/pages/setting/pages/navigation_bar_set.dart +++ b/lib/pages/setting/pages/navigation_bar_set.dart @@ -74,7 +74,6 @@ class _NavigationbarSetPageState extends State { }, title: Text(defaultNavTabs[i]['label']), secondary: const Icon(Icons.drag_indicator_rounded), - enabled: defaultNavTabs[i]['id'] != 0, ) ] ]; diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index a80ee41a..18487f91 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -519,7 +519,10 @@ class VideoIntroController extends GetxController { // 设置关注分组 void setFollowGroup() { showFlexibleBottomSheet( - bottomSheetColor: Colors.transparent, + bottomSheetBorderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), minHeight: 0.6, initHeight: 0.6, maxHeight: 1, diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index c2e9e2e4..27e39760 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -230,7 +230,10 @@ class _VideoInfoState extends State with TickerProviderStateMixin { void _showFavPanel() { showFlexibleBottomSheet( - bottomSheetColor: Colors.transparent, + bottomSheetBorderRadius: const BorderRadius.only( + topLeft: Radius.circular(16), + topRight: Radius.circular(16), + ), minHeight: 0.6, initHeight: 0.6, maxHeight: 1, diff --git a/lib/pages/video/detail/introduction/widgets/fav_panel.dart b/lib/pages/video/detail/introduction/widgets/fav_panel.dart index a4e98df7..2cf7d236 100644 --- a/lib/pages/video/detail/introduction/widgets/fav_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/fav_panel.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/widgets/http_error.dart'; @@ -26,128 +27,118 @@ class _FavPanelState extends State { @override Widget build(BuildContext context) { - return Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), + return Column( + children: [ + AppBar( + centerTitle: false, + elevation: 0, + automaticallyImplyLeading: false, + leadingWidth: 0, + title: Text( + '选择收藏夹', + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith(fontWeight: FontWeight.bold), + ), ), - ), - child: Column( - children: [ - AppBar( - centerTitle: false, - elevation: 0, - automaticallyImplyLeading: false, - leadingWidth: 0, - title: Text( - '选择收藏夹', - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(fontWeight: FontWeight.bold), - ), - ), - Expanded( - child: Material( - child: FutureBuilder( - future: _futureBuilderFuture, - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - Map data = snapshot.data as Map; - if (data['status']) { - return Obx( - () => ListView.builder( - controller: widget.scrollController, - itemCount: - widget.ctr!.favFolderData.value.list!.length, - itemBuilder: (context, index) { - final item = - widget.ctr!.favFolderData.value.list![index]; - return ListTile( - onTap: () => widget.ctr! - .onChoose(item.favState != 1, index), - dense: true, - leading: const Icon(Icons.folder_outlined), - minLeadingWidth: 0, - title: Text(widget.ctr!.favFolderData.value - .list![index].title!), - subtitle: Text( - '${item.mediaCount}个内容 ', + Expanded( + child: Material( + child: FutureBuilder( + future: _futureBuilderFuture, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + Map data = snapshot.data as Map; + if (data['status']) { + return Obx( + () => ListView.builder( + controller: widget.scrollController, + itemCount: widget.ctr!.favFolderData.value.list!.length, + itemBuilder: (context, index) { + final item = + widget.ctr!.favFolderData.value.list![index]; + return ListTile( + onTap: () => + widget.ctr!.onChoose(item.favState != 1, index), + dense: true, + leading: Icon([23, 1].contains(item.attr) + ? Icons.lock_outline + : Icons.folder_outlined), + minLeadingWidth: 0, + title: Text(item.title!), + subtitle: Text( + '${item.mediaCount}个内容 - ${[ + 23, + 1 + ].contains(item.attr) ? '私密' : '公开'}', + ), + trailing: Transform.scale( + scale: 0.9, + child: Checkbox( + value: item.favState == 1, + onChanged: (bool? checkValue) => + widget.ctr!.onChoose(checkValue!, index), ), - trailing: Transform.scale( - scale: 0.9, - child: Checkbox( - value: widget.ctr!.favFolderData.value - .list![index].favState == - 1, - onChanged: (bool? checkValue) => - widget.ctr!.onChoose(checkValue!, index), - ), - ), - ); - }, - ), - ); - } else { - return HttpError( - errMsg: data['msg'], - fn: () => setState(() {}), - ); - } + ), + ); + }, + ), + ); } else { - // 骨架屏 - return const Text('请求中'); + 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: () => Get.back(), + style: TextButton.styleFrom( + padding: const EdgeInsets.only(left: 30, right: 30), + backgroundColor: + Theme.of(context).colorScheme.onInverseSurface, // 设置按钮背景色 + ), + child: 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: () => Get.back(), - style: TextButton.styleFrom( - padding: const EdgeInsets.only(left: 30, right: 30), - backgroundColor: Theme.of(context) - .colorScheme - .onInverseSurface, // 设置按钮背景色 - ), - child: const Text('取消'), + const SizedBox(width: 10), + TextButton( + onPressed: () async { + feedBack(); + await widget.ctr!.actionFavVideo(); + }, + style: TextButton.styleFrom( + padding: const EdgeInsets.only(left: 30, right: 30), + foregroundColor: Theme.of(context).colorScheme.onPrimary, + backgroundColor: + Theme.of(context).colorScheme.primary, // 设置按钮背景色 ), - const SizedBox(width: 10), - TextButton( - onPressed: () async { - feedBack(); - await widget.ctr!.actionFavVideo(); - }, - style: TextButton.styleFrom( - padding: const EdgeInsets.only(left: 30, right: 30), - foregroundColor: Theme.of(context).colorScheme.onPrimary, - backgroundColor: - Theme.of(context).colorScheme.primary, // 设置按钮背景色 - ), - child: const Text('确认选择'), - ), - ], - ), + child: const Text('确认'), + ), + ], ), - ], - ), + ), + ], ); } } diff --git a/lib/pages/video/detail/introduction/widgets/group_panel.dart b/lib/pages/video/detail/introduction/widgets/group_panel.dart index 4bb0980c..c007d52d 100644 --- a/lib/pages/video/detail/introduction/widgets/group_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/group_panel.dart @@ -54,112 +54,101 @@ class _GroupPanelState extends State { @override Widget build(BuildContext context) { - return Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), + return 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), ), - ), - 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: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.connectionState == ConnectionState.done) { - Map data = snapshot.data as Map; - if (data['status']) { - tagsList = data['data']; - return ListView.builder( - controller: widget.scrollController, - 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(() {}); - }, - ), + Expanded( + child: Material( + child: FutureBuilder( + future: _futureBuilderFuture, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + Map data = snapshot.data as Map; + if (data['status']) { + tagsList = data['data']; + return ListView.builder( + controller: widget.scrollController, + 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('请求中'); + return HttpError( + errMsg: data['msg'], + fn: () => setState(() {}), + ); } - }, - ), + } else { + // 骨架屏 + return const Text('请求中'); + } + }, ), ), - Divider( - height: 1, - color: Theme.of(context).disabledColor.withOpacity(0.08), + ), + 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, ), - 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 ? '保存至默认分组' : '保存'), + 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 ? '保存至默认分组' : '保存'), + ), + ], ), - ], - ), + ), + ], ); } } diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index e3e14caf..55e3cf02 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -26,6 +26,7 @@ import 'widgets/app_bar_ani.dart'; import 'widgets/backward_seek.dart'; import 'widgets/bottom_control.dart'; import 'widgets/common_btn.dart'; +import 'widgets/control_bar.dart'; import 'widgets/forward_seek.dart'; import 'widgets/play_pause_btn.dart'; @@ -484,104 +485,27 @@ class _PLVideoPlayerState extends State /// 音量🔊 控制条展示 Obx( - () => Align( - child: AnimatedOpacity( - curve: Curves.easeInOut, - opacity: _volumeIndicator.value ? 1.0 : 0.0, - duration: const Duration(milliseconds: 150), - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color(0x88000000), - borderRadius: BorderRadius.circular(64.0), - ), - height: 34.0, - width: 70.0, - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - height: 34.0, - width: 28.0, - alignment: Alignment.centerRight, - child: Icon( - _volumeValue.value == 0.0 - ? Icons.volume_off - : _volumeValue.value < 0.5 - ? Icons.volume_down - : Icons.volume_up, - color: const Color(0xFFFFFFFF), - size: 20.0, - ), - ), - Expanded( - child: Text( - '${(_volumeValue.value * 100.0).round()}%', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 13.0, - color: Color(0xFFFFFFFF), - ), - ), - ), - const SizedBox(width: 6.0), - ], - ), - ), - ), + () => ControlBar( + visible: _volumeIndicator.value, + icon: _volumeValue.value < 1.0 / 3.0 + ? Icons.volume_mute + : _volumeValue.value < 2.0 / 3.0 + ? Icons.volume_down + : Icons.volume_up, + value: _volumeValue.value, ), ), /// 亮度🌞 控制条展示 Obx( - () => Align( - child: AnimatedOpacity( - curve: Curves.easeInOut, - opacity: _brightnessIndicator.value ? 1.0 : 0.0, - duration: const Duration(milliseconds: 150), - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - color: const Color(0x88000000), - borderRadius: BorderRadius.circular(64.0), - ), - height: 34.0, - width: 70.0, - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - height: 30.0, - width: 28.0, - alignment: Alignment.centerRight, - child: Icon( - _brightnessValue.value < 1.0 / 3.0 - ? Icons.brightness_low - : _brightnessValue.value < 2.0 / 3.0 - ? Icons.brightness_medium - : Icons.brightness_high, - color: const Color(0xFFFFFFFF), - size: 18.0, - ), - ), - const SizedBox(width: 2.0), - Expanded( - child: Text( - '${(_brightnessValue.value * 100.0).round()}%', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 13.0, - color: Color(0xFFFFFFFF), - ), - ), - ), - const SizedBox(width: 6.0), - ], - ), - ), - ), + () => ControlBar( + visible: _brightnessIndicator.value, + icon: _brightnessValue.value < 1.0 / 3.0 + ? Icons.brightness_low + : _brightnessValue.value < 2.0 / 3.0 + ? Icons.brightness_medium + : Icons.brightness_high, + value: _brightnessValue.value, ), ), diff --git a/lib/plugin/pl_player/widgets/control_bar.dart b/lib/plugin/pl_player/widgets/control_bar.dart new file mode 100644 index 00000000..44e2abfa --- /dev/null +++ b/lib/plugin/pl_player/widgets/control_bar.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +class ControlBar extends StatelessWidget { + final bool visible; + final IconData icon; + final double value; + + const ControlBar({ + Key? key, + required this.visible, + required this.icon, + required this.value, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + Color color = const Color(0xFFFFFFFF); + return Align( + child: AnimatedOpacity( + curve: Curves.easeInOut, + opacity: visible ? 1.0 : 0.0, + duration: const Duration(milliseconds: 150), + child: IntrinsicWidth( + child: Container( + padding: const EdgeInsets.fromLTRB(10, 2, 10, 2), + decoration: BoxDecoration( + color: const Color(0x88000000), + borderRadius: BorderRadius.circular(64.0), + ), + height: 34.0, + child: Row( + children: [ + Icon(icon, color: color, size: 18.0), + const SizedBox(width: 4.0), + Container( + constraints: const BoxConstraints(minWidth: 30.0), + child: Text( + '${(value * 100.0).round()}%', + textAlign: TextAlign.center, + style: TextStyle(fontSize: 13.0, color: color), + ), + ) + ], + ), + ), + ), + ), + ); + } +} diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index 7840c126..136de91f 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; +import 'package:pilipala/pages/fav_edit/index.dart'; import 'package:pilipala/pages/follow_search/view.dart'; import 'package:pilipala/pages/message/at/index.dart'; import 'package:pilipala/pages/message/like/index.dart'; @@ -183,6 +184,8 @@ class Routes { // 系统通知 CustomGetPage( name: '/messageSystem', page: () => const MessageSystemPage()), + // 收藏夹编辑 + CustomGetPage(name: '/favEdit', page: () => const FavEditPage()), ]; }