feat: videoDetail menu edit

This commit is contained in:
guozhigq
2024-05-19 19:57:13 +08:00
parent 780ada983e
commit 04dd99c02f
8 changed files with 249 additions and 39 deletions

BIN
assets/images/coin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

View File

@ -0,0 +1,94 @@
// 操作类型的枚举值:点赞 不喜欢 收藏 投币 稍后再看 下载封面 后台播放 听视频 分享 下载视频
import 'package:flutter/material.dart';
import 'package:get/get.dart';
enum ActionType {
like,
coin,
collect,
watchLater,
share,
dislike,
downloadCover,
copyLink,
threeAction,
// backgroundPlay,
// listenVideo,
// downloadVideo,
}
extension ActionTypeExtension on ActionType {
String get value => [
'like',
'coin',
'collect',
'watchLater',
'share',
'dislike',
'downloadCover',
'copyLink',
// 'backgroundPlay',
// 'listenVideo',
// 'downloadVideo',
][index];
String get label => [
'点赞视频',
'投币',
'收藏视频',
'稍后再看',
'视频分享',
'不喜欢',
'下载封面',
'复制链接',
// '后台播放',
// '听视频',
// '下载视频',
][index];
}
List<Map> actionMenuConfig = [
{
'icon': const Icon(Icons.thumb_up_alt_outlined),
'label': '点赞视频',
'value': ActionType.like,
},
{
'icon': Image.asset(
'assets/images/coin.png',
width: 26,
color: IconTheme.of(Get.context!).color!.withOpacity(0.65),
),
'label': '投币',
'value': ActionType.coin,
},
{
'icon': const Icon(Icons.star_border),
'label': '收藏视频',
'value': ActionType.collect,
},
{
'icon': const Icon(Icons.watch_later_outlined),
'label': '稍后再看',
'value': ActionType.watchLater,
},
{
'icon': const Icon(Icons.share),
'label': '视频分享',
'value': ActionType.share,
},
{
'icon': const Icon(Icons.thumb_down_alt_outlined),
'label': '不喜欢',
'value': ActionType.dislike,
},
{
'icon': const Icon(Icons.image_outlined),
'label': '下载封面',
'value': ActionType.downloadCover,
},
{
'icon': const Icon(Icons.link_outlined),
'label': '复制链接',
'value': ActionType.copyLink,
},
];

View File

@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/models/common/action_type.dart';
import '../../../utils/storage.dart';
class ActionMenuSetPage extends StatefulWidget {
const ActionMenuSetPage({super.key});
@override
State<ActionMenuSetPage> createState() => _ActionMenuSetPageState();
}
class _ActionMenuSetPageState extends State<ActionMenuSetPage> {
Box settingStorage = GStrorage.setting;
late List<String> actionTypeSort;
late List<Map> allLabels;
@override
void initState() {
super.initState();
actionTypeSort = settingStorage.get(SettingBoxKey.actionTypeSort,
defaultValue: ['like', 'coin', 'collect', 'watchLater', 'share']);
allLabels = actionMenuConfig;
allLabels.sort((a, b) {
int indexA = actionTypeSort.indexOf((a['value'] as ActionType).value);
int indexB = actionTypeSort.indexOf((b['value'] as ActionType).value);
if (indexA == -1) indexA = actionTypeSort.length;
if (indexB == -1) indexB = actionTypeSort.length;
return indexA.compareTo(indexB);
});
}
void saveEdit() {
List<String> sortedTabbar = allLabels
.where((i) => actionTypeSort.contains((i['value'] as ActionType).value))
.map<String>((i) => (i['value'] as ActionType).value)
.toList();
settingStorage.put(SettingBoxKey.actionTypeSort, sortedTabbar);
SmartDialog.showToast('保存成功,下次启动时生效');
}
void onReorder(int oldIndex, int newIndex) {
setState(() {
if (newIndex > oldIndex) {
newIndex -= 1;
}
final tabsItem = allLabels.removeAt(oldIndex);
allLabels.insert(newIndex, tabsItem);
});
}
@override
Widget build(BuildContext context) {
final listTiles = [
for (int i = 0; i < allLabels.length; i++) ...[
CheckboxListTile(
key: Key((allLabels[i]['value'] as ActionType).value),
value: actionTypeSort
.contains((allLabels[i]['value'] as ActionType).value),
onChanged: (bool? newValue) {
String actionTypeId = (allLabels[i]['value'] as ActionType).value;
if (!newValue!) {
actionTypeSort.remove(actionTypeId);
} else {
actionTypeSort.add(actionTypeId);
}
setState(() {});
},
title: Row(
children: [
allLabels[i]['icon'],
const SizedBox(width: 8),
Text(allLabels[i]['label']),
],
),
secondary: const Icon(Icons.drag_indicator_rounded),
)
]
];
return Scaffold(
appBar: AppBar(
title: const Text('视频操作菜单'),
actions: [
TextButton(onPressed: () => saveEdit(), child: const Text('保存')),
const SizedBox(width: 12)
],
),
body: ReorderableListView(
onReorder: onReorder,
physics: const NeverScrollableScrollPhysics(),
footer: SizedBox(
height: MediaQuery.of(context).padding.bottom + 30,
),
children: listTiles,
),
);
}
}

View File

@ -289,6 +289,11 @@ class _StyleSettingState extends State<StyleSetting> {
onTap: () => Get.toNamed('/navbarSetting'),
title: Text('底部导航栏设置', style: titleStyle),
),
ListTile(
dense: false,
onTap: () => Get.toNamed('/actionMenuSet'),
title: Text('操作菜单设置', style: titleStyle),
),
if (Platform.isAndroid)
ListTile(
dense: false,

View File

@ -1,7 +1,6 @@
import 'package:expandable/expandable.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
@ -529,26 +528,21 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
builder: (BuildContext context, BoxConstraints constraints) {
return Container(
margin: const EdgeInsets.only(top: 6, bottom: 4),
height: constraints.maxWidth / 5 * 0.8,
child: GridView.count(
physics: const NeverScrollableScrollPhysics(),
primary: false,
padding: EdgeInsets.zero,
crossAxisCount: 5,
childAspectRatio: 1.25,
children: <Widget>[
height: constraints.maxWidth / 5,
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Obx(
() => ActionItem(
icon: const Icon(FontAwesomeIcons.thumbsUp),
selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
icon: const Icon(Icons.thumb_up_alt_outlined),
selectIcon: const Icon(Icons.thumb_up),
onTap: handleState(videoIntroController.actionLikeVideo),
selectStatus: videoIntroController.hasLike.value,
text: widget.videoDetail!.stat!.like!.toString()),
),
Obx(
() => ActionItem(
icon: const Icon(FontAwesomeIcons.b),
selectIcon: const Icon(FontAwesomeIcons.b),
icon: Image.asset('assets/images/coin.png', width: 30),
onTap: handleState(videoIntroController.actionCoinVideo),
selectStatus: videoIntroController.hasCoin.value,
text: widget.videoDetail!.stat!.coin!.toString(),
@ -556,8 +550,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
),
Obx(
() => ActionItem(
icon: const Icon(FontAwesomeIcons.star),
selectIcon: const Icon(FontAwesomeIcons.solidStar),
icon: const Icon(Icons.star_border),
selectIcon: const Icon(Icons.star),
onTap: () => showFavBottomSheet(),
onLongPress: () => showFavBottomSheet(type: 'longPress'),
selectStatus: videoIntroController.hasFav.value,
@ -565,7 +559,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
),
),
ActionItem(
icon: const Icon(FontAwesomeIcons.clock),
icon: const Icon(Icons.watch_later_outlined),
onTap: () async {
final res =
await UserHttp.toViewLater(bvid: widget.videoDetail!.bvid);
@ -575,7 +569,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
text: '稍后看',
),
ActionItem(
icon: const Icon(FontAwesomeIcons.shareFromSquare),
icon: const Icon(Icons.share),
onTap: () => videoIntroController.actionShareVideo(),
selectStatus: false,
text: '分享',

View File

@ -1,9 +1,10 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart';
import 'package:pilipala/utils/feed_back.dart';
class ActionItem extends StatelessWidget {
final Icon? icon;
final dynamic icon;
final Icon? selectIcon;
final Function? onTap;
final Function? onLongPress;
@ -31,27 +32,38 @@ class ActionItem extends StatelessWidget {
if (onLongPress != null) {onLongPress!()}
},
borderRadius: StyleString.mdRadius,
child: SizedBox(
width: (Get.size.width - 24) / 5,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 4),
selectStatus
? Icon(selectIcon!.icon!,
size: 18, color: Theme.of(context).colorScheme.primary)
: Icon(icon!.icon!,
size: 18, color: Theme.of(context).colorScheme.outline),
icon is Icon
? Icon(
selectStatus ? selectIcon!.icon ?? icon!.icon : icon!.icon,
color: selectStatus
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline,
)
: Image.asset(
'assets/images/coin.png',
width: 25,
color: selectStatus
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline,
),
const SizedBox(height: 6),
Text(
text ?? '',
style: TextStyle(
color: selectStatus
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.outline,
color:
selectStatus ? Theme.of(context).colorScheme.primary : null,
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize,
),
)
],
),
),
);
}
}

View File

@ -35,6 +35,7 @@ import '../pages/search/index.dart';
import '../pages/search_result/index.dart';
import '../pages/setting/extra_setting.dart';
import '../pages/setting/index.dart';
import '../pages/setting/pages/action_menu_set.dart';
import '../pages/setting/pages/color_select.dart';
import '../pages/setting/pages/display_mode.dart';
import '../pages/setting/pages/font_size_select.dart';
@ -174,6 +175,9 @@ class Routes {
// navigation bar
CustomGetPage(
name: '/navbarSetting', page: () => const NavigationBarSetPage()),
// 操作菜单
CustomGetPage(
name: '/actionMenuSet', page: () => const ActionMenuSetPage()),
];
}

View File

@ -149,7 +149,8 @@ class SettingBoxKey {
tabbarSort = 'tabbarSort', // 首页tabbar
dynamicBadgeMode = 'dynamicBadgeMode',
enableGradientBg = 'enableGradientBg',
navBarSort = 'navBarSort';
navBarSort = 'navBarSort',
actionTypeSort = 'actionTypeSort';
}
class LocalCacheKey {