Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-09-18 16:33:33 +08:00
parent 64e893e36f
commit cef7e478f5
19 changed files with 492 additions and 456 deletions

View File

@@ -2,7 +2,7 @@
import 'package:flutter/widgets.dart';
class CustomIcon {
class CustomIcons {
static const IconData coin = _CustomIconData(0xe800);
static const IconData dm_off = _CustomIconData(0xe801);
static const IconData dm_on = _CustomIconData(0xe802);

View File

@@ -682,7 +682,7 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
Expanded(
child: textIconButton(
text: '分享',
icon: CustomIcon.share_node,
icon: CustomIcons.share_node,
stat: null,
onPressed: () => Utils.shareText(controller.url),
),

View File

@@ -52,7 +52,7 @@ Widget content(
padding: const EdgeInsets.only(right: 4),
child: Icon(
size: 18,
CustomIcon.topic_tag,
CustomIcons.topic_tag,
color: theme.colorScheme.primary,
),
),

View File

@@ -147,7 +147,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
child: Padding(
padding: const EdgeInsets.only(right: 5),
child: Icon(
CustomIcon.topic_tag,
CustomIcons.topic_tag,
size: 18,
color: hasTopic
? null
@@ -604,7 +604,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState<CreateDynPanel> {
children: [
item(
onTap: _onReserve,
icon: Icon(CustomIcon.live_reserve, size: 28, color: color),
icon: Icon(CustomIcons.live_reserve, size: 28, color: color),
title: '直播预约',
),
],

View File

@@ -293,7 +293,7 @@ class _DynamicDetailPageState extends CommonDynPageState<DynamicDetailPage> {
),
Expanded(
child: textIconButton(
icon: CustomIcon.share_node,
icon: CustomIcons.share_node,
text: '分享',
stat: null,
onPressed: () => Utils.shareText(

View File

@@ -28,7 +28,7 @@ class DynTopicItem extends StatelessWidget {
child: Padding(
padding: EdgeInsets.only(right: 5),
child: Icon(
CustomIcon.topic_tag,
CustomIcons.topic_tag,
size: 18,
),
),

View File

@@ -58,7 +58,7 @@ class _DynTopicPageState extends State<DynTopicPage> with DynMixin {
SmartDialog.showToast('账号未登录');
}
},
icon: const Icon(CustomIcon.topic_tag, size: 20),
icon: const Icon(CustomIcons.topic_tag, size: 20),
label: const Text('参与话题'),
),
body: refreshIndicator(

View File

@@ -2,6 +2,7 @@ import 'dart:io';
import 'dart:ui';
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart';
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
@@ -798,12 +799,12 @@ class _LiveRoomPageState extends State<LiveRoomPage>
icon: enableShowLiveDanmaku
? const Icon(
size: 22,
Icons.subtitles_outlined,
CustomIcons.dm_on,
color: Color(0xFFEEEEEE),
)
: const Icon(
size: 22,
Icons.subtitles_off_outlined,
CustomIcons.dm_off,
color: Color(0xFFEEEEEE),
),
),

View File

@@ -1,3 +1,4 @@
import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/pages/live_room/controller.dart';
import 'package:PiliPlus/plugin/pl_player/controller.dart';
import 'package:PiliPlus/plugin/pl_player/models/video_fit_type.dart';
@@ -76,12 +77,12 @@ class BottomControl extends StatelessWidget {
icon: enableShowLiveDanmaku
? const Icon(
size: 18,
Icons.subtitles_outlined,
CustomIcons.dm_on,
color: Colors.white,
)
: const Icon(
size: 18,
Icons.subtitles_off_outlined,
CustomIcons.dm_off,
color: Colors.white,
),
onTap: () {

View File

@@ -286,7 +286,7 @@ class _MusicDetailPageState extends CommonDynPageState<MusicDetailPage> {
// ),
Expanded(
child: textIconButton(
icon: CustomIcon.share_node,
icon: CustomIcons.share_node,
text: '分享',
onPressed: () =>
Utils.shareText(controller.shareUrl),

View File

@@ -254,13 +254,13 @@ class _PgcReviewChildPageState extends State<PgcReviewChildPage>
(index) {
if (index <= item.score - 1) {
return const Icon(
CustomIcon.star_favorite_solid,
CustomIcons.star_favorite_solid,
size: 13,
color: Color(0xFFFFAD35),
);
}
return const Icon(
CustomIcon.star_favorite_line,
CustomIcons.star_favorite_line,
size: 14,
color: Colors.grey,
);

View File

@@ -94,12 +94,12 @@ class _PgcReviewPostPanelState extends State<PgcReviewPostPanel> {
return Obx(
() => index <= _score.value - 1
? const Icon(
CustomIcon.star_favorite_solid,
CustomIcons.star_favorite_solid,
size: 50,
color: Color(0xFFFFAD35),
)
: const Icon(
CustomIcon.star_favorite_line,
CustomIcons.star_favorite_line,
size: 50,
color: Colors.grey,
),

View File

@@ -1,6 +1,7 @@
import 'dart:io';
import 'dart:math' show pi, max;
import 'package:PiliPlus/common/widgets/custom_icon.dart';
import 'package:PiliPlus/common/widgets/image/custom_grid_view.dart'
show CustomGridView, ImageModel;
import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
@@ -243,7 +244,7 @@ List<SettingsModel> get extraSettings => [
title: '弹幕行高',
subtitle: '默认1.6',
setKey: SettingBoxKey.danmakuLineHeight,
leading: const Icon(Icons.subtitles_outlined),
leading: const Icon(CustomIcons.dm_settings),
getTrailing: () => Text(
Pref.danmakuLineHeight.toString(),
style: Get.theme.textTheme.titleSmall,

View File

@@ -24,7 +24,7 @@ List<SettingsModel> get playSettings => [
settingsType: SettingsType.sw1tch,
title: '弹幕开关',
subtitle: '是否展示弹幕',
leading: Icon(CustomIcon.dm_settings),
leading: Icon(CustomIcons.dm_settings),
setKey: SettingBoxKey.enableShowDanmaku,
defaultVal: true,
),
@@ -204,7 +204,7 @@ List<SettingsModel> get playSettings => [
settingsType: SettingsType.sw1tch,
title: '画中画不加载弹幕',
subtitle: '当弹幕开关开启时,小窗屏蔽弹幕以获得较好的体验',
leading: Icon(Icons.subtitles_off_outlined),
leading: Icon(CustomIcons.dm_off),
setKey: SettingBoxKey.pipNoDanmaku,
defaultVal: false,
),

View File

@@ -1490,6 +1490,13 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
? ugcIntroController
: pgcIntroController,
onSendDanmaku: videoDetailController.showShootDanmakuSheet,
canPlay: () {
if (videoDetailController.autoPlay.value) {
return true;
}
handlePlay();
return false;
},
child: child,
);
return videoDetailController.plPlayerController.darkVideoPage
@@ -1627,8 +1634,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
icon: Icon(
size: 22,
enableShowDanmaku
? CustomIcon.dm_on
: CustomIcon.dm_off,
? CustomIcons.dm_on
: CustomIcons.dm_off,
color: enableShowDanmaku
? themeData.colorScheme.secondary
: themeData.colorScheme.outline,

View File

@@ -100,7 +100,7 @@ class HeaderControlState extends TripleState<HeaderControl> {
@override
void dispose() {
clock?.cancel();
cancelClock();
super.dispose();
}
@@ -416,7 +416,7 @@ class HeaderControlState extends TripleState<HeaderControl> {
Get.back();
showSetDanmaku();
},
leading: const Icon(CustomIcon.dm_settings, size: 20),
leading: const Icon(CustomIcons.dm_settings, size: 20),
title: const Text('弹幕设置', style: titleStyle),
),
ListTile(
@@ -780,7 +780,7 @@ class HeaderControlState extends TripleState<HeaderControl> {
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
: null,
),
],
],
@@ -857,7 +857,7 @@ class HeaderControlState extends TripleState<HeaderControl> {
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
: null,
),
],
],
@@ -1819,7 +1819,7 @@ class HeaderControlState extends TripleState<HeaderControl> {
Icons.done,
color: theme.colorScheme.primary,
)
: const SizedBox.shrink(),
: null,
),
],
],
@@ -1835,376 +1835,369 @@ class HeaderControlState extends TripleState<HeaderControl> {
void startClock() {
clock ??= Timer.periodic(const Duration(seconds: 1), (Timer t) {
if (!mounted) {
clock?.cancel();
cancelClock();
return;
}
now.value = _format.format(DateTime.now());
});
}
Widget _buildHeader(bool showFSActionItem) => AppBar(
elevation: 0,
scrolledUnderElevation: 0,
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
primary: false,
automaticallyImplyLeading: false,
toolbarHeight: showFSActionItem && isFullScreen ? 112 : null,
flexibleSpace: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 11),
Row(
children: [
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '返回',
icon: const Icon(
FontAwesomeIcons.arrowLeft,
size: 15,
color: Colors.white,
),
onPressed: () {
if (isFullScreen) {
plPlayerController.triggerFullScreen(status: false);
} else if (!horizontalScreen && !isPortrait) {
verticalScreenForTwoSeconds();
} else {
Get.back();
}
},
),
),
if (!isFullScreen || !isPortrait)
void cancelClock() {
clock?.cancel();
clock = null;
}
@override
Widget build(BuildContext context) {
final showFSActionItem =
plPlayerController.showFSActionItem && isFullScreen;
return AppBar(
elevation: 0,
scrolledUnderElevation: 0,
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
primary: false,
automaticallyImplyLeading: false,
toolbarHeight: showFSActionItem ? 112 : null,
flexibleSpace: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 11),
Row(
children: [
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '返回主页',
tooltip: '返回',
icon: const Icon(
FontAwesomeIcons.house,
FontAwesomeIcons.arrowLeft,
size: 15,
color: Colors.white,
),
onPressed: () {
videoDetailCtr.plPlayerController.backToHome = true;
Get.until((route) => route.isFirst);
if (isFullScreen) {
plPlayerController.triggerFullScreen(status: false);
} else if (!horizontalScreen && !isPortrait) {
verticalScreenForTwoSeconds();
} else {
Get.back();
}
},
),
),
if ((introController.videoDetail.value.title != null) &&
(isFullScreen || (!horizontalScreen && !isPortrait)))
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: isPortrait
? EdgeInsets.zero
: const EdgeInsets.only(right: 10),
child: Obx(
() {
final videoDetail = introController.videoDetail.value;
final String title;
if (videoDetail.videos == 1) {
title = videoDetail.title!;
} else {
title =
videoDetail.pages
?.firstWhereOrNull(
(e) => e.cid == videoDetailCtr.cid.value,
)
?.pagePart ??
videoDetail.title!;
}
return MarqueeText(
title,
spacing: 30,
velocity: 30,
if (!isFullScreen || !isPortrait)
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '返回主页',
icon: const Icon(
FontAwesomeIcons.house,
size: 15,
color: Colors.white,
),
onPressed: () {
videoDetailCtr.plPlayerController.backToHome = true;
Get.until((route) => route.isFirst);
},
),
),
if ((introController.videoDetail.value.title != null) &&
(isFullScreen || (!horizontalScreen && !isPortrait)))
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: isPortrait
? EdgeInsets.zero
: const EdgeInsets.only(right: 10),
child: Obx(
() {
final videoDetail =
introController.videoDetail.value;
final String title;
if (videoDetail.videos == 1) {
title = videoDetail.title!;
} else {
title =
videoDetail.pages
?.firstWhereOrNull(
(e) =>
e.cid == videoDetailCtr.cid.value,
)
?.pagePart ??
videoDetail.title!;
}
return MarqueeText(
title,
spacing: 30,
velocity: 30,
style: const TextStyle(
color: Colors.white,
fontSize: 16,
),
provider: provider,
);
},
),
),
if (introController.isShowOnlineTotal)
Obx(
() => Text(
'${introController.total.value}人正在看',
style: const TextStyle(
color: Colors.white,
fontSize: 16,
fontSize: 11,
),
provider: provider,
);
},
),
),
if (introController.isShowOnlineTotal)
Obx(
() => Text(
'${introController.total.value}人正在看',
style: const TextStyle(
color: Colors.white,
fontSize: 11,
),
),
),
],
),
)
else
const Spacer(),
// show current datetime
Obx(
() {
if ((isFullScreen || !horizontalScreen) && !isPortrait) {
startClock();
return Text(
now.value,
style: const TextStyle(
color: Colors.white,
fontSize: 13,
),
);
}
clock?.cancel();
clock = null;
return const SizedBox.shrink();
},
),
if (plPlayerController.enableSponsorBlock == true)
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '提交片段',
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: () => videoDetailCtr.onBlock(context),
icon: const Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(
Icons.shield_outlined,
size: 19,
color: Colors.white,
),
Icon(
Icons.play_arrow_rounded,
size: 13,
color: Colors.white,
),
],
),
),
),
Obx(
() => videoDetailCtr.segmentList.isNotEmpty
? SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '片段信息',
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: () => videoDetailCtr.showSBDetail(context),
icon: const Icon(
MdiIcons.advertisements,
size: 19,
color: Colors.white,
),
),
)
: const SizedBox.shrink(),
),
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '发弹幕',
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: videoDetailCtr.showShootDanmakuSheet,
icon: const Icon(
Icons.comment_outlined,
size: 19,
color: Colors.white,
),
),
),
SizedBox(
width: 42,
height: 34,
child: Obx(
)
else
const Spacer(),
// show current datetime
Obx(
() {
final enableShowDanmaku =
plPlayerController.enableShowDanmaku.value;
return IconButton(
tooltip: "${enableShowDanmaku ? '关闭' : '开启'}弹幕",
if ((isFullScreen || !horizontalScreen) && !isPortrait) {
startClock();
return Text(
now.value,
style: const TextStyle(
color: Colors.white,
fontSize: 13,
),
);
}
cancelClock();
return const SizedBox.shrink();
},
),
if (plPlayerController.enableSponsorBlock == true)
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '提交片段',
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: () {
final newVal = !enableShowDanmaku;
plPlayerController.enableShowDanmaku.value = newVal;
if (!plPlayerController.tempPlayerConf) {
setting.put(SettingBoxKey.enableShowDanmaku, newVal);
}
},
icon: Icon(
enableShowDanmaku
? Icons.subtitles_outlined
: Icons.subtitles_off_outlined,
size: 19,
color: Colors.white,
onPressed: () => videoDetailCtr.onBlock(context),
icon: const Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(
Icons.shield_outlined,
size: 19,
color: Colors.white,
),
Icon(
Icons.play_arrow_rounded,
size: 13,
color: Colors.white,
),
],
),
);
},
),
),
Obx(
() => videoDetailCtr.segmentList.isNotEmpty
? SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '片段信息',
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: () => videoDetailCtr.showSBDetail(context),
icon: const Icon(
MdiIcons.advertisements,
size: 19,
color: Colors.white,
),
),
)
: const SizedBox.shrink(),
),
),
if (Platform.isAndroid)
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '画中画',
tooltip: '发弹幕',
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: () async {
bool canUsePiP = await Floating().isPipAvailable;
plPlayerController.hiddenControls(false);
if (canUsePiP) {
if (!videoPlayerServiceHandler!.enableBackgroundPlay &&
mounted) {
final theme = Theme.of(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Column(
children: [
const Row(
children: [
Icon(
Icons.check,
color: Colors.green,
),
SizedBox(width: 10),
Text(
'画中画',
style: TextStyle(
fontSize: 15,
height: 1.5,
),
),
],
),
const SizedBox(height: 10),
const Text(
'建议开启【后台音频服务】\n'
'避免画中画没有暂停按钮',
style: TextStyle(fontSize: 12.5, height: 1.5),
),
Row(
children: [
TextButton(
style: ButtonStyle(
foregroundColor: WidgetStatePropertyAll(
theme.snackBarTheme.actionTextColor,
),
),
onPressed: () {
plPlayerController.setBackgroundPlay(
true,
);
SmartDialog.showToast("请重新载入本页面刷新");
},
child: const Text('启用后台音频服务'),
),
const SizedBox(width: 10),
TextButton(
style: ButtonStyle(
foregroundColor: WidgetStatePropertyAll(
theme.snackBarTheme.actionTextColor,
),
),
onPressed: () {},
child: const Text('不启用'),
),
],
),
],
),
duration: const Duration(seconds: 2),
showCloseIcon: true,
),
);
await Future.delayed(const Duration(seconds: 3));
}
if (!context.mounted) return;
PageUtils.enterPip(
width: widget.videoDetailCtr.firstVideo.width,
height: widget.videoDetailCtr.firstVideo.height,
);
}
},
onPressed: videoDetailCtr.showShootDanmakuSheet,
icon: const Icon(
Icons.picture_in_picture_outlined,
Icons.comment_outlined,
size: 19,
color: Colors.white,
),
),
),
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: "更多设置",
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: showSettingSheet,
icon: const Icon(
Icons.more_vert_outlined,
size: 19,
color: Colors.white,
),
),
),
],
),
if (showFSActionItem && isFullScreen)
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
expand: false,
() {
final enableShowDanmaku =
plPlayerController.enableShowDanmaku.value;
return IconButton(
tooltip: "${enableShowDanmaku ? '关闭' : '开启'}弹幕",
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: () {
final newVal = !enableShowDanmaku;
plPlayerController.enableShowDanmaku.value = newVal;
if (!plPlayerController.tempPlayerConf) {
setting.put(SettingBoxKey.enableShowDanmaku, newVal);
}
},
icon: enableShowDanmaku
? const Icon(
size: 20,
CustomIcons.dm_on,
color: Colors.white,
)
: const Icon(
size: 20,
CustomIcons.dm_off,
color: Colors.white,
),
);
},
),
),
if (Platform.isAndroid)
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: '画中画',
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: () async {
bool canUsePiP = await Floating().isPipAvailable;
plPlayerController.hiddenControls(false);
if (canUsePiP) {
if (context.mounted &&
!videoPlayerServiceHandler!.enableBackgroundPlay) {
final theme = Theme.of(context);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Column(
children: [
const Row(
children: [
Icon(
Icons.check,
color: Colors.green,
),
SizedBox(width: 10),
Text(
'画中画',
style: TextStyle(
fontSize: 15,
height: 1.5,
),
),
],
),
const SizedBox(height: 10),
const Text(
'建议开启【后台音频服务】\n'
'避免画中画没有暂停按钮',
style: TextStyle(
fontSize: 12.5,
height: 1.5,
),
),
Row(
children: [
TextButton(
style: ButtonStyle(
foregroundColor:
WidgetStatePropertyAll(
theme
.snackBarTheme
.actionTextColor,
),
),
onPressed: () {
plPlayerController.setBackgroundPlay(
true,
);
SmartDialog.showToast("请重新载入本页面刷新");
},
child: const Text('启用后台音频服务'),
),
const SizedBox(width: 10),
TextButton(
style: ButtonStyle(
foregroundColor:
WidgetStatePropertyAll(
theme
.snackBarTheme
.actionTextColor,
),
),
onPressed: () {},
child: const Text('不启用'),
),
],
),
],
),
duration: const Duration(seconds: 2),
showCloseIcon: true,
),
);
await Future.delayed(const Duration(seconds: 3));
}
if (!context.mounted) return;
PageUtils.enterPip(
width: widget.videoDetailCtr.firstVideo.width,
height: widget.videoDetailCtr.firstVideo.height,
);
}
},
icon: const Icon(
FontAwesomeIcons.thumbsUp,
Icons.picture_in_picture_outlined,
size: 19,
color: Colors.white,
),
selectIcon: const Icon(
FontAwesomeIcons.solidThumbsUp,
),
selectStatus: introController.hasLike.value,
semanticsLabel: '点赞',
animation: tripleAnimation,
onStartTriple: () {
plPlayerController.tripling = true;
onStartTriple();
},
onCancelTriple: ([bool isTap = false]) {
plPlayerController
..tripling = false
..hideTaskControls();
onCancelTriple(isTap);
},
),
),
SizedBox(
width: 42,
height: 34,
child: IconButton(
tooltip: "更多设置",
style: const ButtonStyle(
padding: WidgetStatePropertyAll(EdgeInsets.zero),
),
onPressed: showSettingSheet,
icon: const Icon(
Icons.more_vert_outlined,
size: 19,
color: Colors.white,
),
),
),
if (introController case UgcIntroController ugc)
],
),
if (showFSActionItem)
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 42,
height: 34,
@@ -2212,82 +2205,106 @@ class HeaderControlState extends TripleState<HeaderControl> {
() => ActionItem(
expand: false,
icon: const Icon(
FontAwesomeIcons.thumbsDown,
FontAwesomeIcons.thumbsUp,
color: Colors.white,
),
selectIcon: const Icon(
FontAwesomeIcons.solidThumbsDown,
FontAwesomeIcons.solidThumbsUp,
),
onTap: () => ugc.handleAction(ugc.actionDislikeVideo),
selectStatus: ugc.hasDislike.value,
semanticsLabel: '点踩',
selectStatus: introController.hasLike.value,
semanticsLabel: '点赞',
animation: tripleAnimation,
onStartTriple: () {
plPlayerController.tripling = true;
onStartTriple();
},
onCancelTriple: ([bool isTap = false]) {
plPlayerController
..tripling = false
..hideTaskControls();
onCancelTriple(isTap);
},
),
),
),
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
if (introController case UgcIntroController ugc)
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
expand: false,
icon: const Icon(
FontAwesomeIcons.thumbsDown,
color: Colors.white,
),
selectIcon: const Icon(
FontAwesomeIcons.solidThumbsDown,
),
onTap: () => ugc.handleAction(ugc.actionDislikeVideo),
selectStatus: ugc.hasDislike.value,
semanticsLabel: '点踩',
),
),
),
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
expand: false,
animation: tripleAnimation,
icon: const Icon(
FontAwesomeIcons.b,
color: Colors.white,
),
selectIcon: const Icon(FontAwesomeIcons.b),
onTap: introController.actionCoinVideo,
selectStatus: introController.hasCoin,
semanticsLabel: '投币',
),
),
),
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
expand: false,
animation: tripleAnimation,
icon: const Icon(
FontAwesomeIcons.star,
color: Colors.white,
),
selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () => introController.showFavBottomSheet(context),
onLongPress: () => introController.showFavBottomSheet(
context,
isLongPress: true,
),
selectStatus: introController.hasFav.value,
semanticsLabel: '收藏',
),
),
),
SizedBox(
width: 42,
height: 34,
child: ActionItem(
expand: false,
animation: tripleAnimation,
icon: const Icon(
FontAwesomeIcons.b,
FontAwesomeIcons.shareFromSquare,
color: Colors.white,
),
selectIcon: const Icon(FontAwesomeIcons.b),
onTap: introController.actionCoinVideo,
selectStatus: introController.hasCoin,
semanticsLabel: '投币',
onTap: () => introController.actionShareVideo(context),
semanticsLabel: '分享',
),
),
),
SizedBox(
width: 42,
height: 34,
child: Obx(
() => ActionItem(
expand: false,
animation: tripleAnimation,
icon: const Icon(
FontAwesomeIcons.star,
color: Colors.white,
),
selectIcon: const Icon(FontAwesomeIcons.solidStar),
onTap: () => introController.showFavBottomSheet(context),
onLongPress: () => introController.showFavBottomSheet(
context,
isLongPress: true,
),
selectStatus: introController.hasFav.value,
semanticsLabel: '收藏',
),
),
),
SizedBox(
width: 42,
height: 34,
child: ActionItem(
expand: false,
icon: const Icon(
FontAwesomeIcons.shareFromSquare,
color: Colors.white,
),
onTap: () => introController.actionShareVideo(context),
semanticsLabel: '分享',
),
),
],
),
],
),
);
@override
Widget build(BuildContext context) {
return plPlayerController.showFSActionItem
? Obx(() => _buildHeader(true))
: _buildHeader(false);
],
),
],
),
);
}
}

View File

@@ -19,12 +19,14 @@ class PlayerFocus extends StatelessWidget {
required this.plPlayerController,
this.introController,
required this.onSendDanmaku,
this.canPlay,
});
final Widget child;
final PlPlayerController plPlayerController;
final CommonIntroController? introController;
final VoidCallback onSendDanmaku;
final bool Function()? canPlay;
static bool _shouldHandled(KeyEvent event) {
return event.logicalKey == LogicalKeyboardKey.tab ||
@@ -57,8 +59,10 @@ class PlayerFocus extends StatelessWidget {
if (event is KeyDownEvent) {
switch (key) {
case LogicalKeyboardKey.space:
if (hasPlayer) {
plPlayerController.onDoubleTapCenter();
if (plPlayerController.isLive || canPlay!()) {
if (hasPlayer) {
plPlayerController.onDoubleTapCenter();
}
}
return true;

View File

@@ -100,36 +100,39 @@ class ReplyUtils {
}
void showReplyCheckResult(String message, {bool isBan = false}) {
Get.dialog(
barrierDismissible: isManual,
AlertDialog(
title: const Text('评论检查结果'),
content: SelectableText(message),
actions: isBan
? [
TextButton(
onPressed: () {
Get.back();
String? uri;
switch (type) {
case 1:
uri = IdUtils.av2bv(oid);
case 17:
uri = 'https://www.bilibili.com/opus/$oid';
}
if (uri != null) {
Utils.copyText(uri);
}
Get.toNamed(
'/webview',
parameters: {
'url':
'https://www.bilibili.com/h5/comment/appeal?native.theme=2&night=${Get.isDarkMode ? 1 : 0}',
},
);
},
child: const Text('申诉'),
),
]
: null,
actions: [
TextButton(
onPressed: () {
Get.back();
String? uri;
switch (type) {
case 1:
uri = IdUtils.av2bv(oid);
case 17:
uri = 'https://www.bilibili.com/opus/$oid';
}
if (uri != null) {
Utils.copyText(uri);
}
Get.toNamed(
'/webview',
parameters: {
'url':
'https://www.bilibili.com/h5/comment/appeal?native.theme=2&night=${Get.isDarkMode ? 1 : 0}',
},
);
},
child: const Text('申诉'),
),
TextButton(
onPressed: Get.back,
child: const Text('关闭'),
),
],
),
);
}

View File

@@ -285,7 +285,7 @@ abstract class RequestUtils {
static Future<void> insertCreatedDyn(dynamic id) async {
try {
if (id != null) {
await Future.delayed(const Duration(milliseconds: 200));
await Future.delayed(const Duration(milliseconds: 450));
var res = await DynamicsHttp.dynamicDetail(id: id);
if (res.isSuccess) {
final ctr = Get.find<DynamicsTabController>(tag: 'all');
@@ -317,31 +317,33 @@ abstract class RequestUtils {
await Future.delayed(const Duration(seconds: 5));
}
var res = await DynamicsHttp.dynamicDetail(id: id, clearCookie: true);
bool isBan = !res.isSuccess;
Get.dialog(
barrierDismissible: isManual,
AlertDialog(
title: const Text('动态检查结果'),
content: SelectableText(
'${!isBan ? '无账号状态下找到了你的动态,动态正常!' : '你的动态被shadow ban仅自己可见'}${dynText != null ? ' \n\n动态内容: $dynText' : ''}',
'${res.isSuccess ? '无账号状态下找到了你的动态,动态正常!' : '你的动态被shadow ban仅自己可见'}${dynText != null ? ' \n\n动态内容: $dynText' : ''}',
),
actions: isBan
? [
TextButton(
onPressed: () {
Get.back();
Utils.copyText('https://www.bilibili.com/opus/$id');
Get.toNamed(
'/webview',
parameters: {
'url':
'https://www.bilibili.com/h5/comment/appeal?native.theme=2&night=${Get.isDarkMode ? 1 : 0}',
},
);
},
child: const Text('申诉'),
),
]
: null,
actions: [
TextButton(
onPressed: () {
Get.back();
Utils.copyText('https://www.bilibili.com/opus/$id');
Get.toNamed(
'/webview',
parameters: {
'url':
'https://www.bilibili.com/h5/comment/appeal?native.theme=2&night=${Get.isDarkMode ? 1 : 0}',
},
);
},
child: const Text('申诉'),
),
TextButton(
onPressed: Get.back,
child: const Text('关闭'),
),
],
),
);
}