mod: tabbar

This commit is contained in:
bggRGjQaUbCoE
2024-09-25 12:04:33 +08:00
parent 02d69b7c55
commit 1705c0a02e
6 changed files with 148 additions and 100 deletions

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" data-pointer="none" viewBox="0 0 24 24"><path fill-rule="evenodd" d="m8.085 4.891-.999-1.499a1.008 1.008 0 0 1 1.679-1.118l1.709 2.566c.54-.008 1.045-.012 1.515-.012h.13c.345 0 .707.003 1.088.007l1.862-2.59a1.008 1.008 0 0 1 1.637 1.177l-1.049 1.46c.788.02 1.631.046 2.53.078 1.958.069 3.468 1.6 3.74 3.507.088.613.13 2.158.16 3.276l.001.027c.01.333.017.63.025.856a.987.987 0 0 1-1.974.069c-.008-.23-.016-.539-.025-.881v-.002c-.028-1.103-.066-2.541-.142-3.065-.143-1.004-.895-1.78-1.854-1.813-2.444-.087-4.466-.13-6.064-.131-1.598 0-3.619.044-6.063.13a2.037 2.037 0 0 0-1.945 1.748c-.15 1.04-.225 2.341-.225 3.904 0 1.874.11 3.474.325 4.798.154.949.95 1.66 1.91 1.708a97.58 97.58 0 0 0 5.416.139.988.988 0 0 1 0 1.975c-2.196 0-3.61-.047-5.513-.141A4.012 4.012 0 0 1 2.197 17.7c-.236-1.446-.351-3.151-.351-5.116 0-1.64.08-3.035.245-4.184A4.013 4.013 0 0 1 5.92 4.96c.761-.027 1.483-.05 2.164-.069Zm4.436 4.707h-1.32v4.63h2.222v.848h-2.618v1.078h2.431a5.01 5.01 0 0 1 3.575-3.115V9.598h-1.276a8.59 8.59 0 0 0 .748-1.42l-1.089-.384a14.232 14.232 0 0 1-.814 1.804h-1.518l.693-.308a8.862 8.862 0 0 0-.814-1.408l-1.045.352c.297.396.572.847.825 1.364Zm-4.18 3.564.154-1.485h1.98V8.289h-3.2v.979h2.067v1.43H7.483l-.308 3.454h2.277c0 1.166-.044 1.925-.12 2.277-.078.352-.386.528-.936.528-.308 0-.616-.022-.902-.055l.297 1.067.062.004c.285.02.551.04.818.04 1.001-.066 1.562-.418 1.694-1.056.11-.638.176-1.903.176-3.795h-2.2Zm7.458.11v-.858h-1.254v.858H15.8Zm-2.376-.858v.858h-1.199v-.858h1.2Zm-1.199-.946h1.2v-.902h-1.2v.902Zm2.321 0v-.902H15.8v.902h-1.254Zm3.517 10.594a4 4 0 1 0 0-8 4 4 0 0 0 0 8Zm-.002-1.502a2.5 2.5 0 0 1-2.217-3.657l3.326 3.398a2.49 2.49 0 0 1-1.109.259Zm2.5-2.5c0 .42-.103.815-.286 1.162l-3.328-3.401a2.5 2.5 0 0 1 3.614 2.239Z" clip-rule="evenodd"></path></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" data-pointer="none" viewBox="0 0 24 24" id="svgcontent" overflow="visible" width="24" height="24" x="597" y="286"><g class="layer" style="pointer-events:all"><title style="pointer-events:inherit">Layer 1</title><path fill-rule="evenodd" d="M11.99,4.83C11.52,4.83 11.01,4.83 10.47,4.84L8.76,2.27A1.01,1.01 0 0 0 7.09,3.39L8.08,4.89C7.4,4.91 6.68,4.93 5.92,4.96A4.01,4.01 0 0 0 2.09,8.4C1.93,9.55 1.85,10.94 1.85,12.58C1.85,14.55 1.96,16.25 2.2,17.7A4.01,4.01 0 0 0 5.96,21.06L6.86,21.11C8.07,21.17 8.67,21.2 10.47,21.2A0.99,0.99 0 0 0 10.47,19.23C8.71,19.23 8.13,19.2 6.97,19.14L6.06,19.09A2.04,2.04 0 0 1 4.15,17.38C3.93,16.06 3.82,14.46 3.82,12.58C3.82,11.02 3.9,9.72 4.05,8.68C4.19,7.7 5.01,6.97 5.99,6.93C8.43,6.85 10.46,6.8 12.05,6.8C13.65,6.8 15.67,6.85 18.12,6.93C19.08,6.97 19.83,7.74 19.97,8.75C20.05,9.27 20.09,10.71 20.11,11.81L20.11,11.81C20.12,12.16 20.13,12.46 20.14,12.69A0.99,0.99 0 1 0 22.11,12.63C22.1,12.4 22.1,12.1 22.09,11.77L22.09,11.74C22.06,10.62 22.01,9.08 21.93,8.47C21.65,6.56 20.14,5.03 18.19,4.96C17.29,4.93 16.44,4.9 15.66,4.88L16.71,3.42A1.01,1.01 0 0 0 15.07,2.24L13.21,4.83C12.83,4.83 12.46,4.83 12.12,4.83L11.99,4.83zM12.51,9.6L11.19,9.6L11.19,14.23L13.41,14.23L13.41,15.08L10.79,15.08L10.79,16.16L13.41,16.16L13.42,16.84C13.78,16.86 14.13,17 14.43,17.24L14.54,17.24L14.54,16.16L17.23,16.16L17.23,15.08L14.53,15.08L14.53,14.23L16.8,14.23L16.8,9.6L15.52,9.6A8.59,8.59 0 0 0 16.27,8.18L15.18,7.8A14.23,14.23 0 0 1 14.37,9.6L12.85,9.6L13.54,9.3A8.86,8.86 0 0 0 12.73,7.89L11.68,8.24C11.98,8.64 12.26,9.09 12.51,9.6zM8.33,13.17L8.48,11.68L10.46,11.68L10.46,8.29L7.26,8.29L7.26,9.27L9.33,9.27L9.33,10.7L7.47,10.7L7.16,14.16L9.44,14.16C9.44,15.32 9.4,16.08 9.32,16.43C9.24,16.79 8.94,16.96 8.39,16.96C8.08,16.96 7.77,16.94 7.48,16.91L7.78,17.97L7.84,17.98C8.13,18 8.39,18.02 8.66,18.02C9.66,17.95 10.22,17.6 10.35,16.96C10.46,16.32 10.53,15.06 10.53,13.17L8.33,13.17zM15.79,13.28L15.79,12.42L14.53,12.42L14.53,13.28L15.79,13.28zM13.41,12.42L13.41,13.28L12.21,13.28L12.21,12.42L13.41,12.42zM12.21,11.47L13.41,11.47L13.41,10.57L12.21,10.57L12.21,11.47zM14.53,11.47L14.53,10.57L15.79,10.57L15.79,11.47L14.53,11.47z" clip-rule="evenodd" id="svg_1"></path><path fill="#000000" fill-rule="evenodd" d="M22.85,14.63A1,1 0 0 0 21.43,14.7L16.34,20.41L14.13,18.13L14.03,18.04L14.02,18.04A1,1 0 0 0 12.7,19.53L15.66,22.57L15.76,22.66L15.76,22.66C16.17,22.98 16.76,22.93 17.12,22.54L22.93,16.03L23.01,15.93L23.01,15.92A1,1 0 0 0 22.85,14.63z" clip-rule="evenodd" id="svg_2"></path></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'package:PiliPalaX/http/danmaku.dart';
import 'package:floating/floating.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -14,6 +15,7 @@ import 'package:PiliPalaX/plugin/pl_player/index.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:PiliPalaX/utils/video_utils.dart';
import 'package:ns_danmaku/models/danmaku_item.dart';
import '../../../utils/id_utils.dart';
import 'widgets/header_control.dart';
@@ -147,6 +149,85 @@ class VideoDetailController extends GetxController
oid.value = IdUtils.bv2av(Get.parameters['bvid']!);
}
/// 发送弹幕
void showShootDanmakuSheet() {
final TextEditingController textController = TextEditingController();
bool isSending = false; // 追踪是否正在发送
showDialog(
context: Get.context!,
builder: (BuildContext context) {
// TODO: 支持更多类型和颜色的弹幕
return AlertDialog(
title: const Text('发送弹幕'),
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return TextField(
controller: textController,
autofocus: true,
);
}),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'取消',
style: TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return TextButton(
onPressed: isSending
? null
: () async {
final String msg = textController.text;
if (msg.isEmpty) {
SmartDialog.showToast('弹幕内容不能为空');
return;
} else if (msg.length > 100) {
SmartDialog.showToast('弹幕内容不能超过100个字符');
return;
}
isSending = true; // 开始发送,更新状态
//修改按钮文字
// SmartDialog.showToast('弹幕发送中,\n$msg');
final dynamic res = await DanmakaHttp.shootDanmaku(
oid: cid.value,
msg: textController.text,
bvid: bvid,
progress:
plPlayerController.position.value.inMilliseconds,
type: 1,
);
isSending = false; // 发送结束,更新状态
if (res['status']) {
SmartDialog.showToast('发送成功');
// 发送成功,自动预览该弹幕,避免重新请求
// TODO: 暂停状态下预览弹幕仍会移动与计时可考虑添加到dmSegList或其他方式实现
plPlayerController.danmakuController!.addItems([
DanmakuItem(
msg,
color: Colors.white,
time: plPlayerController
.position.value.inMilliseconds,
type: DanmakuItemType.scroll,
isSend: true,
)
]);
Get.back();
} else {
SmartDialog.showToast('发送失败,错误信息为${res['msg']}');
}
},
child: Text(isSending ? '发送中...' : '发送'),
);
})
],
);
},
);
}
/// 更新画质、音质
/// TODO 继续进度播放
updatePlayer() {

View File

@@ -19,6 +19,7 @@ import 'package:auto_orientation/auto_orientation.dart';
import 'package:floating/floating.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:flutter_svg/svg.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
@@ -1162,6 +1163,52 @@ class _VideoDetailPageState extends State<VideoDetailPage>
),
),
),
Flexible(
flex: 1,
child: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
height: 32,
child: TextButton(
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: videoDetailController.showShootDanmakuSheet,
child:
const Text('发弹幕', style: TextStyle(fontSize: 12)),
),
),
SizedBox(
width: 38,
height: 38,
child: Obx(
() => IconButton(
onPressed: () {
if (plPlayerController != null) {
videoDetailController
.plPlayerController.isOpenDanmu.value =
!videoDetailController
.plPlayerController.isOpenDanmu.value;
}
},
icon: SvgPicture.asset(
videoDetailController
.plPlayerController.isOpenDanmu.value
? 'assets/images/video/danmu_open.svg'
: 'assets/images/video/danmu_close.svg',
// ignore: deprecated_member_use
color: Theme.of(context).colorScheme.outline,
),
),
),
),
const SizedBox(width: 14),
],
),
),
),
],
),
),

View File

@@ -20,7 +20,6 @@ import 'package:PiliPalaX/pages/video/detail/introduction/widgets/menu_row.dart'
import 'package:PiliPalaX/plugin/pl_player/index.dart';
import 'package:PiliPalaX/plugin/pl_player/models/play_repeat.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:PiliPalaX/http/danmaku.dart';
import 'package:PiliPalaX/services/shutdown_timer_service.dart';
import '../../../../models/video/play/CDN.dart';
import '../../../../models/video_detail_res.dart';
@@ -117,7 +116,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 500,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@@ -154,7 +153,7 @@ class _HeaderControlState extends State<HeaderControl> {
// trailing: Transform.scale(
// scale: 0.75,
// child: Switch(
// thumbIcon: MaterialStateProperty.resolveWith<Icon?>(
// thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
// (Set<MaterialState> states) {
// if (states.isNotEmpty &&
// states.first == MaterialState.selected) {
@@ -461,88 +460,6 @@ class _HeaderControlState extends State<HeaderControl> {
);
}
/// 发送弹幕
void showShootDanmakuSheet() {
final TextEditingController textController = TextEditingController();
bool isSending = false; // 追踪是否正在发送
showDialog(
context: Get.context!,
builder: (BuildContext context) {
// TODO: 支持更多类型和颜色的弹幕
return AlertDialog(
title: const Text('发送弹幕'),
content: StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return TextField(
controller: textController,
);
}),
actions: [
TextButton(
onPressed: () => Get.back(),
child: Text(
'取消',
style: TextStyle(color: Theme.of(context).colorScheme.outline),
),
),
StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return TextButton(
onPressed: isSending
? null
: () async {
final String msg = textController.text;
if (msg.isEmpty) {
SmartDialog.showToast('弹幕内容不能为空');
return;
} else if (msg.length > 100) {
SmartDialog.showToast('弹幕内容不能超过100个字符');
return;
}
setState(() {
isSending = true; // 开始发送,更新状态
});
//修改按钮文字
// SmartDialog.showToast('弹幕发送中,\n$msg');
final dynamic res = await DanmakaHttp.shootDanmaku(
oid: widget.videoDetailCtr!.cid.value,
msg: textController.text,
bvid: widget.videoDetailCtr!.bvid,
progress:
widget.controller!.position.value.inMilliseconds,
type: 1,
);
setState(() {
isSending = false; // 发送结束,更新状态
});
if (res['status']) {
SmartDialog.showToast('发送成功');
// 发送成功,自动预览该弹幕,避免重新请求
// TODO: 暂停状态下预览弹幕仍会移动与计时可考虑添加到dmSegList或其他方式实现
widget.controller!.danmakuController!.addItems([
DanmakuItem(
msg,
color: Colors.white,
time: widget
.controller!.position.value.inMilliseconds,
type: DanmakuItemType.scroll,
isSend: true,
)
]);
Get.back();
} else {
SmartDialog.showToast('发送失败,错误信息为${res['msg']}');
}
},
child: Text(isSending ? '发送中...' : '发送'),
);
})
],
);
},
);
}
/// 定时关闭
void scheduleExit() async {
const List<int> scheduleTimeChoices = [
@@ -564,7 +481,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 500,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@@ -624,7 +541,7 @@ class _HeaderControlState extends State<HeaderControl> {
inactiveThumbColor:
Theme.of(context).colorScheme.primaryContainer,
inactiveTrackColor:
Theme.of(context).colorScheme.background,
Theme.of(context).colorScheme.surface,
splashRadius: 10.0,
// boolean variable value
value: shutdownTimerService.waitForPlayingCompleted,
@@ -704,7 +621,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 310,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@@ -803,7 +720,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 250,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@@ -889,7 +806,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 250,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@@ -985,7 +902,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 580,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@@ -1345,7 +1262,7 @@ class _HeaderControlState extends State<HeaderControl> {
height: 300,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(12),
@@ -1529,11 +1446,11 @@ class _HeaderControlState extends State<HeaderControl> {
child: IconButton(
tooltip: '发弹幕',
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.zero),
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () => showShootDanmakuSheet(),
onPressed: widget.videoDetailCtr?.showShootDanmakuSheet,
icon: const Icon(
Icons.add_comment_outlined,
Icons.comment_outlined,
size: 19,
color: Colors.white,
),
@@ -1558,8 +1475,8 @@ class _HeaderControlState extends State<HeaderControl> {
},
icon: Icon(
_.isOpenDanmu.value
? Icons.comment_outlined
: Icons.comments_disabled_outlined,
? Icons.subtitles_outlined
: Icons.subtitles_off_outlined,
size: 19,
color: Colors.white,
),
@@ -1612,7 +1529,7 @@ class _HeaderControlState extends State<HeaderControl> {
TextButton(
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.resolveWith(
WidgetStateProperty.resolveWith(
(states) {
return Theme.of(context)
.snackBarTheme
@@ -1629,7 +1546,7 @@ class _HeaderControlState extends State<HeaderControl> {
TextButton(
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.resolveWith(
WidgetStateProperty.resolveWith(
(states) {
return Theme.of(context)
.snackBarTheme
@@ -1669,7 +1586,7 @@ class _HeaderControlState extends State<HeaderControl> {
child: IconButton(
tooltip: "更多设置",
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.zero),
padding: WidgetStateProperty.all(EdgeInsets.zero),
),
onPressed: () => showSettingSheet(),
icon: const Icon(

View File

@@ -249,6 +249,7 @@ flutter:
- assets/images/lv/
- assets/images/logo/
- assets/images/live/
- assets/images/video/
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware