mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-28 22:40:13 +08:00
59
lib/common/widgets/sliver/video_header.dart
Normal file
59
lib/common/widgets/sliver/video_header.dart
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import 'package:PiliPlus/common/widgets/sliver/sliver_pinned_dynamic_header.dart';
|
||||||
|
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||||
|
import 'package:flutter/foundation.dart' show clampDouble;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class VideoHeader extends SliverPinnedDynamicHeader {
|
||||||
|
const VideoHeader({
|
||||||
|
super.key,
|
||||||
|
required super.minExtent,
|
||||||
|
required super.maxExtent,
|
||||||
|
required this.minVideoHeight,
|
||||||
|
required this.onScrollRatioChanged,
|
||||||
|
required super.child,
|
||||||
|
});
|
||||||
|
|
||||||
|
final double minVideoHeight;
|
||||||
|
final ValueChanged<double> onScrollRatioChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
RenderObject createRenderObject(BuildContext context) {
|
||||||
|
return RenderVideoHeader(
|
||||||
|
minExtent: minExtent,
|
||||||
|
maxExtent: maxExtent,
|
||||||
|
minVideoHeight: minVideoHeight,
|
||||||
|
onScrollRatioChanged: onScrollRatioChanged,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RenderVideoHeader extends RenderSliverPinnedDynamicHeader {
|
||||||
|
RenderVideoHeader({
|
||||||
|
required super.minExtent,
|
||||||
|
required super.maxExtent,
|
||||||
|
required this.minVideoHeight,
|
||||||
|
required this.onScrollRatioChanged,
|
||||||
|
});
|
||||||
|
|
||||||
|
double? _scrollRatio;
|
||||||
|
final double minVideoHeight;
|
||||||
|
final ValueChanged<double> onScrollRatioChanged;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void performLayout() {
|
||||||
|
super.performLayout();
|
||||||
|
final scrollOffset = constraints.scrollOffset;
|
||||||
|
final offset = scrollOffset - (maxExtent - minVideoHeight);
|
||||||
|
final scrollRatio = clampDouble(
|
||||||
|
offset.toPrecision(2) / (minVideoHeight - kToolbarHeight).toPrecision(2),
|
||||||
|
0.0,
|
||||||
|
1.0,
|
||||||
|
);
|
||||||
|
if (_scrollRatio != scrollRatio) {
|
||||||
|
_scrollRatio = scrollRatio;
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
onScrollRatioChanged(scrollRatio);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -486,7 +486,7 @@ class LiveRoomController extends GetxController {
|
|||||||
|
|
||||||
void addDm(dynamic msg, [DanmakuContentItem<DanmakuExtra>? item]) {
|
void addDm(dynamic msg, [DanmakuContentItem<DanmakuExtra>? item]) {
|
||||||
if (plPlayerController.showDanmaku) {
|
if (plPlayerController.showDanmaku) {
|
||||||
if (item != null) {
|
if (item != null && plPlayerController.enableShowLiveDanmaku.value) {
|
||||||
danmakuController?.addDanmaku(item);
|
danmakuController?.addDanmaku(item);
|
||||||
}
|
}
|
||||||
if (autoScroll && !disableAutoScroll.value) {
|
if (autoScroll && !disableAutoScroll.value) {
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
|||||||
plPlayerController.removeStatusLister(playerListener);
|
plPlayerController.removeStatusLister(playerListener);
|
||||||
_liveRoomController
|
_liveRoomController
|
||||||
..danmakuController?.clear()
|
..danmakuController?.clear()
|
||||||
..danmakuController?.pause()
|
|
||||||
..cancelLiveTimer()
|
..cancelLiveTimer()
|
||||||
..closeLiveMsg()
|
..closeLiveMsg()
|
||||||
..isPlaying = plPlayerController.playerStatus.isPlaying;
|
..isPlaying = plPlayerController.playerStatus.isPlaying;
|
||||||
@@ -809,7 +808,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
|||||||
Obx(
|
Obx(
|
||||||
() {
|
() {
|
||||||
final enableShowLiveDanmaku =
|
final enableShowLiveDanmaku =
|
||||||
plPlayerController.enableShowDanmaku.value;
|
plPlayerController.enableShowLiveDanmaku.value;
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: 34,
|
width: 34,
|
||||||
height: 34,
|
height: 34,
|
||||||
@@ -817,7 +816,8 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
|||||||
style: IconButton.styleFrom(padding: .zero),
|
style: IconButton.styleFrom(padding: .zero),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final newVal = !enableShowLiveDanmaku;
|
final newVal = !enableShowLiveDanmaku;
|
||||||
plPlayerController.enableShowDanmaku.value = newVal;
|
plPlayerController.enableShowLiveDanmaku.value =
|
||||||
|
newVal;
|
||||||
if (!plPlayerController.tempPlayerConf) {
|
if (!plPlayerController.tempPlayerConf) {
|
||||||
GStorage.setting.put(
|
GStorage.setting.put(
|
||||||
SettingBoxKey.enableShowLiveDanmaku,
|
SettingBoxKey.enableShowLiveDanmaku,
|
||||||
@@ -1091,7 +1091,7 @@ class _LiveDanmakuState extends State<LiveDanmaku> {
|
|||||||
final option = DanmakuOptions.get(notFullscreen: widget.notFullscreen);
|
final option = DanmakuOptions.get(notFullscreen: widget.notFullscreen);
|
||||||
return Obx(
|
return Obx(
|
||||||
() => AnimatedOpacity(
|
() => AnimatedOpacity(
|
||||||
opacity: plPlayerController.enableShowDanmaku.value
|
opacity: plPlayerController.enableShowLiveDanmaku.value
|
||||||
? plPlayerController.danmakuOpacity.value
|
? plPlayerController.danmakuOpacity.value
|
||||||
: 0,
|
: 0,
|
||||||
duration: const Duration(milliseconds: 100),
|
duration: const Duration(milliseconds: 100),
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class _BottomControlState extends State<BottomControl> with HeaderMixin {
|
|||||||
Obx(
|
Obx(
|
||||||
() {
|
() {
|
||||||
final enableShowLiveDanmaku =
|
final enableShowLiveDanmaku =
|
||||||
plPlayerController.enableShowDanmaku.value;
|
plPlayerController.enableShowLiveDanmaku.value;
|
||||||
return ComBtn(
|
return ComBtn(
|
||||||
height: 30,
|
height: 30,
|
||||||
tooltip: "${enableShowLiveDanmaku ? '关闭' : '开启'}弹幕",
|
tooltip: "${enableShowLiveDanmaku ? '关闭' : '开启'}弹幕",
|
||||||
@@ -105,7 +105,7 @@ class _BottomControlState extends State<BottomControl> with HeaderMixin {
|
|||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final newVal = !enableShowLiveDanmaku;
|
final newVal = !enableShowLiveDanmaku;
|
||||||
plPlayerController.enableShowDanmaku.value = newVal;
|
plPlayerController.enableShowLiveDanmaku.value = newVal;
|
||||||
if (!plPlayerController.tempPlayerConf) {
|
if (!plPlayerController.tempPlayerConf) {
|
||||||
GStorage.setting.put(
|
GStorage.setting.put(
|
||||||
SettingBoxKey.enableShowLiveDanmaku,
|
SettingBoxKey.enableShowLiveDanmaku,
|
||||||
|
|||||||
@@ -65,7 +65,8 @@ import 'package:PiliPlus/utils/theme_utils.dart';
|
|||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:PiliPlus/utils/video_utils.dart';
|
import 'package:PiliPlus/utils/video_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
|
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'
|
||||||
|
show ExtendedNestedScrollViewState;
|
||||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
@@ -169,8 +170,7 @@ class VideoDetailController extends GetxController
|
|||||||
late final RxDouble scrollRatio = 0.0.obs;
|
late final RxDouble scrollRatio = 0.0.obs;
|
||||||
|
|
||||||
ScrollController? _scrollCtr;
|
ScrollController? _scrollCtr;
|
||||||
ScrollController get scrollCtr =>
|
ScrollController get scrollCtr => _scrollCtr ??= ScrollController();
|
||||||
_scrollCtr ??= ScrollController()..addListener(scrollListener);
|
|
||||||
|
|
||||||
late bool isExpanding = false;
|
late bool isExpanding = false;
|
||||||
late bool isCollapsing = false;
|
late bool isCollapsing = false;
|
||||||
@@ -315,26 +315,6 @@ class VideoDetailController extends GetxController
|
|||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
void scrollListener() {
|
|
||||||
if (scrollCtr.hasClients) {
|
|
||||||
if (scrollCtr.offset == 0) {
|
|
||||||
scrollRatio.value = 0;
|
|
||||||
} else {
|
|
||||||
double offset = scrollCtr.offset - (videoHeight - minVideoHeight);
|
|
||||||
if (offset > 0) {
|
|
||||||
scrollRatio.value = clampDouble(
|
|
||||||
offset.toPrecision(2) /
|
|
||||||
(minVideoHeight - kToolbarHeight).toPrecision(2),
|
|
||||||
0.0,
|
|
||||||
1.0,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
scrollRatio.value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final isLoginVideo = Accounts.get(AccountType.video).isLogin;
|
final isLoginVideo = Accounts.get(AccountType.video).isLogin;
|
||||||
|
|
||||||
late final watchProgress = GStorage.watchProgress;
|
late final watchProgress = GStorage.watchProgress;
|
||||||
@@ -1247,9 +1227,7 @@ class VideoDetailController extends GetxController
|
|||||||
introScrollCtr?.dispose();
|
introScrollCtr?.dispose();
|
||||||
introScrollCtr = null;
|
introScrollCtr = null;
|
||||||
tabCtr.dispose();
|
tabCtr.dispose();
|
||||||
_scrollCtr
|
_scrollCtr?.dispose();
|
||||||
?..removeListener(scrollListener)
|
|
||||||
..dispose();
|
|
||||||
animController
|
animController
|
||||||
?..removeListener(_animListener)
|
?..removeListener(_animListener)
|
||||||
..dispose();
|
..dispose();
|
||||||
@@ -1268,10 +1246,6 @@ class VideoDetailController extends GetxController
|
|||||||
videoUrl = null;
|
videoUrl = null;
|
||||||
audioUrl = null;
|
audioUrl = null;
|
||||||
|
|
||||||
if (scrollRatio.value != 0) {
|
|
||||||
scrollRatio.refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
// danmaku
|
// danmaku
|
||||||
savedDanmaku = null;
|
savedDanmaku = null;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart';
|
import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart';
|
||||||
import 'package:PiliPlus/common/widgets/route_aware_mixin.dart';
|
import 'package:PiliPlus/common/widgets/route_aware_mixin.dart';
|
||||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||||
import 'package:PiliPlus/common/widgets/sliver/sliver_pinned_dynamic_header.dart';
|
import 'package:PiliPlus/common/widgets/sliver/video_header.dart';
|
||||||
import 'package:PiliPlus/common/widgets/svg/play_icon.dart';
|
import 'package:PiliPlus/common/widgets/svg/play_icon.dart';
|
||||||
import 'package:PiliPlus/models/common/episode_panel_type.dart';
|
import 'package:PiliPlus/models/common/episode_panel_type.dart';
|
||||||
import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart';
|
import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart';
|
||||||
@@ -493,24 +493,21 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
() {
|
() {
|
||||||
final scrollRatio =
|
final scrollRatio =
|
||||||
videoDetailController.scrollRatio.value;
|
videoDetailController.scrollRatio.value;
|
||||||
final flag =
|
|
||||||
isPortrait &&
|
|
||||||
videoDetailController.scrollCtr.offset != 0;
|
|
||||||
return AppBar(
|
return AppBar(
|
||||||
backgroundColor: flag && scrollRatio > 0
|
toolbarHeight: 0,
|
||||||
|
backgroundColor: isPortrait && scrollRatio > 0
|
||||||
? Color.lerp(
|
? Color.lerp(
|
||||||
Colors.black,
|
Colors.black,
|
||||||
themeData.colorScheme.surface,
|
themeData.colorScheme.surface,
|
||||||
scrollRatio,
|
scrollRatio,
|
||||||
)
|
)
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
toolbarHeight: 0,
|
|
||||||
systemOverlayStyle: Platform.isAndroid
|
systemOverlayStyle: Platform.isAndroid
|
||||||
? SystemUiOverlayStyle(
|
? SystemUiOverlayStyle(
|
||||||
statusBarIconBrightness:
|
statusBarIconBrightness:
|
||||||
flag && scrollRatio >= 0.5
|
isPortrait && scrollRatio >= 0.5
|
||||||
? themeData.brightness.reverse
|
? themeData.brightness.reverse
|
||||||
: Brightness.light,
|
: .light,
|
||||||
systemNavigationBarIconBrightness:
|
systemNavigationBarIconBrightness:
|
||||||
themeData.brightness.reverse,
|
themeData.brightness.reverse,
|
||||||
)
|
)
|
||||||
@@ -557,179 +554,20 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
? videoDetailController.animHeight
|
? videoDetailController.animHeight
|
||||||
: videoDetailController.videoHeight;
|
: videoDetailController.videoHeight;
|
||||||
return [
|
return [
|
||||||
SliverPinnedDynamicHeader(
|
VideoHeader(
|
||||||
minExtent: kToolbarHeight,
|
minExtent: kToolbarHeight,
|
||||||
maxExtent: height,
|
maxExtent: height,
|
||||||
|
minVideoHeight: videoDetailController.minVideoHeight,
|
||||||
|
onScrollRatioChanged: videoDetailController.scrollRatio.call,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: .none,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: maxWidth,
|
width: maxWidth,
|
||||||
height: height,
|
height: height,
|
||||||
child: videoPlayer(
|
child: videoPlayer(width: maxWidth, height: height),
|
||||||
width: maxWidth,
|
|
||||||
height: height,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Obx(
|
|
||||||
() {
|
|
||||||
Widget toolbar() => Opacity(
|
|
||||||
opacity: videoDetailController.scrollRatio.value,
|
|
||||||
child: Container(
|
|
||||||
color: themeData.colorScheme.surface,
|
|
||||||
alignment: Alignment.topCenter,
|
|
||||||
child: SizedBox(
|
|
||||||
height: kToolbarHeight,
|
|
||||||
child: Stack(
|
|
||||||
clipBehavior: Clip.none,
|
|
||||||
children: [
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
width: 42,
|
|
||||||
height: 34,
|
|
||||||
child: IconButton(
|
|
||||||
tooltip: '返回',
|
|
||||||
icon: Icon(
|
|
||||||
FontAwesomeIcons.arrowLeft,
|
|
||||||
size: 15,
|
|
||||||
color: themeData
|
|
||||||
.colorScheme
|
|
||||||
.onSurface,
|
|
||||||
),
|
|
||||||
onPressed: Get.back,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 42,
|
|
||||||
height: 34,
|
|
||||||
child: IconButton(
|
|
||||||
tooltip: '返回主页',
|
|
||||||
icon: Icon(
|
|
||||||
FontAwesomeIcons.house,
|
|
||||||
size: 15,
|
|
||||||
color: themeData
|
|
||||||
.colorScheme
|
|
||||||
.onSurface,
|
|
||||||
),
|
|
||||||
onPressed: videoDetailController
|
|
||||||
.plPlayerController
|
|
||||||
.onCloseAll,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Center(
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.play_arrow_rounded,
|
|
||||||
color:
|
|
||||||
themeData.colorScheme.primary,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'${videoDetailController.playedTime == null
|
|
||||||
? '立即'
|
|
||||||
: plPlayerController!.isCompleted
|
|
||||||
? '重新'
|
|
||||||
: '继续'}播放',
|
|
||||||
style: TextStyle(
|
|
||||||
color:
|
|
||||||
themeData.colorScheme.primary,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
child:
|
|
||||||
videoDetailController.playedTime ==
|
|
||||||
null
|
|
||||||
? _moreBtn(
|
|
||||||
themeData.colorScheme.onSurface,
|
|
||||||
)
|
|
||||||
: SizedBox(
|
|
||||||
width: 42,
|
|
||||||
height: 34,
|
|
||||||
child: IconButton(
|
|
||||||
tooltip: "更多设置",
|
|
||||||
style: const ButtonStyle(
|
|
||||||
padding:
|
|
||||||
WidgetStatePropertyAll(
|
|
||||||
EdgeInsets.zero,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onPressed: () =>
|
|
||||||
(videoDetailController
|
|
||||||
.headerCtrKey
|
|
||||||
.currentState
|
|
||||||
as HeaderControlState?)
|
|
||||||
?.showSettingSheet(),
|
|
||||||
icon: Icon(
|
|
||||||
Icons.more_vert_outlined,
|
|
||||||
size: 19,
|
|
||||||
color: themeData
|
|
||||||
.colorScheme
|
|
||||||
.onSurface,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return videoDetailController.scrollRatio.value == 0 ||
|
|
||||||
videoDetailController.scrollCtr.offset == 0 ||
|
|
||||||
!isPortrait
|
|
||||||
? const SizedBox.shrink()
|
|
||||||
: Positioned.fill(
|
|
||||||
bottom: -2,
|
|
||||||
child: GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
if (!videoDetailController.isFileSource) {
|
|
||||||
if (videoDetailController.isQuerying) {
|
|
||||||
if (kDebugMode) {
|
|
||||||
debugPrint('handlePlay: querying');
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (videoDetailController.videoUrl ==
|
|
||||||
null ||
|
|
||||||
videoDetailController.audioUrl ==
|
|
||||||
null) {
|
|
||||||
if (kDebugMode) {
|
|
||||||
debugPrint(
|
|
||||||
'handlePlay: videoUrl/audioUrl not initialized',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
videoDetailController.queryVideoUrl();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
videoDetailController.scrollRatio.value =
|
|
||||||
0;
|
|
||||||
if (plPlayerController == null ||
|
|
||||||
videoDetailController.playedTime ==
|
|
||||||
null) {
|
|
||||||
handlePlay();
|
|
||||||
} else {
|
|
||||||
plPlayerController!.onDoubleTapCenter();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
behavior: HitTestBehavior.opaque,
|
|
||||||
child: toolbar(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
|
_buildHeaderOverlay(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -766,6 +604,163 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildOverlayToolBar(double scrollRatio) {
|
||||||
|
final Icon icon;
|
||||||
|
final double spacing;
|
||||||
|
final String playStat;
|
||||||
|
if (videoDetailController.playedTime == null) {
|
||||||
|
spacing = 2;
|
||||||
|
icon = Icon(
|
||||||
|
Icons.play_arrow_rounded,
|
||||||
|
color: themeData.colorScheme.primary,
|
||||||
|
);
|
||||||
|
playStat = '立即';
|
||||||
|
} else if (plPlayerController!.isCompleted) {
|
||||||
|
spacing = 4;
|
||||||
|
icon = Icon(
|
||||||
|
size: 18,
|
||||||
|
Icons.replay_rounded,
|
||||||
|
color: themeData.colorScheme.primary,
|
||||||
|
);
|
||||||
|
playStat = '重新';
|
||||||
|
} else {
|
||||||
|
spacing = 2;
|
||||||
|
icon = Icon(
|
||||||
|
Icons.play_arrow_rounded,
|
||||||
|
color: themeData.colorScheme.primary,
|
||||||
|
);
|
||||||
|
playStat = '继续';
|
||||||
|
}
|
||||||
|
final playBtn = Row(
|
||||||
|
spacing: spacing,
|
||||||
|
mainAxisSize: .min,
|
||||||
|
children: [
|
||||||
|
icon,
|
||||||
|
Text(
|
||||||
|
'$playStat播放',
|
||||||
|
style: TextStyle(color: themeData.colorScheme.primary),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
return Opacity(
|
||||||
|
opacity: videoDetailController.scrollRatio.value,
|
||||||
|
child: Container(
|
||||||
|
color: themeData.colorScheme.surface,
|
||||||
|
alignment: .topCenter,
|
||||||
|
child: SizedBox(
|
||||||
|
height: kToolbarHeight,
|
||||||
|
child: Stack(
|
||||||
|
clipBehavior: .none,
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: .centerLeft,
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: .min,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 42,
|
||||||
|
height: 34,
|
||||||
|
child: IconButton(
|
||||||
|
tooltip: '返回',
|
||||||
|
icon: Icon(
|
||||||
|
FontAwesomeIcons.arrowLeft,
|
||||||
|
size: 15,
|
||||||
|
color: themeData.colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
onPressed: Get.back,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 42,
|
||||||
|
height: 34,
|
||||||
|
child: IconButton(
|
||||||
|
tooltip: '返回主页',
|
||||||
|
icon: Icon(
|
||||||
|
FontAwesomeIcons.house,
|
||||||
|
size: 15,
|
||||||
|
color: themeData.colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
onPressed:
|
||||||
|
videoDetailController.plPlayerController.onCloseAll,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Center(child: playBtn),
|
||||||
|
Align(
|
||||||
|
alignment: .centerRight,
|
||||||
|
child: videoDetailController.playedTime == null
|
||||||
|
? _moreBtn(themeData.colorScheme.onSurface)
|
||||||
|
: SizedBox(
|
||||||
|
width: 42,
|
||||||
|
height: 34,
|
||||||
|
child: IconButton(
|
||||||
|
tooltip: "更多设置",
|
||||||
|
style: const ButtonStyle(
|
||||||
|
padding: WidgetStatePropertyAll(EdgeInsets.zero),
|
||||||
|
),
|
||||||
|
onPressed: () =>
|
||||||
|
(videoDetailController.headerCtrKey.currentState
|
||||||
|
as HeaderControlState?)
|
||||||
|
?.showSettingSheet(),
|
||||||
|
icon: Icon(
|
||||||
|
Icons.more_vert_outlined,
|
||||||
|
size: 19,
|
||||||
|
color: themeData.colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildHeaderOverlay() {
|
||||||
|
return Obx(
|
||||||
|
() {
|
||||||
|
final scrollRatio = videoDetailController.scrollRatio.value;
|
||||||
|
if (scrollRatio == 0) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
return Positioned.fill(
|
||||||
|
bottom: -2,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
if (!videoDetailController.isFileSource) {
|
||||||
|
if (videoDetailController.isQuerying) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
debugPrint('handlePlay: querying');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (videoDetailController.videoUrl == null ||
|
||||||
|
videoDetailController.audioUrl == null) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
debugPrint('handlePlay: videoUrl/audioUrl not initialized');
|
||||||
|
}
|
||||||
|
videoDetailController.queryVideoUrl();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (plPlayerController == null ||
|
||||||
|
videoDetailController.playedTime == null) {
|
||||||
|
handlePlay();
|
||||||
|
} else {
|
||||||
|
plPlayerController!.onDoubleTapCenter();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
behavior: .opaque,
|
||||||
|
child: _buildOverlayToolBar(scrollRatio),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Widget get childWhenDisabledLandscape => Obx(
|
Widget get childWhenDisabledLandscape => Obx(
|
||||||
() {
|
() {
|
||||||
final isFullScreen = this.isFullScreen;
|
final isFullScreen = this.isFullScreen;
|
||||||
|
|||||||
@@ -180,8 +180,8 @@ class PlayerFocus extends StatelessWidget {
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case LogicalKeyboardKey.keyD:
|
case LogicalKeyboardKey.keyD:
|
||||||
final newVal = !plPlayerController.enableShowDanmaku.value;
|
final newVal = !plPlayerController.enableShowDanmakuAdaptive.value;
|
||||||
plPlayerController.enableShowDanmaku.value = newVal;
|
plPlayerController.enableShowDanmakuAdaptive.value = newVal;
|
||||||
if (!plPlayerController.tempPlayerConf) {
|
if (!plPlayerController.tempPlayerConf) {
|
||||||
GStorage.setting.put(
|
GStorage.setting.put(
|
||||||
plPlayerController.isLive
|
plPlayerController.isLive
|
||||||
|
|||||||
@@ -184,10 +184,10 @@ class PlPlayerController with BlockConfigMixin {
|
|||||||
bool get isVertical => _isVertical;
|
bool get isVertical => _isVertical;
|
||||||
|
|
||||||
/// 弹幕开关
|
/// 弹幕开关
|
||||||
late final RxBool _enableShowDanmaku = Pref.enableShowDanmaku.obs;
|
late final RxBool enableShowDanmaku = Pref.enableShowDanmaku.obs;
|
||||||
late final RxBool _enableShowLiveDanmaku = Pref.enableShowLiveDanmaku.obs;
|
late final RxBool enableShowLiveDanmaku = Pref.enableShowLiveDanmaku.obs;
|
||||||
RxBool get enableShowDanmaku =>
|
RxBool get enableShowDanmakuAdaptive =>
|
||||||
isLive ? _enableShowLiveDanmaku : _enableShowDanmaku;
|
isLive ? enableShowLiveDanmaku : enableShowDanmaku;
|
||||||
|
|
||||||
late final bool autoPiP = Pref.autoPiP;
|
late final bool autoPiP = Pref.autoPiP;
|
||||||
bool get isPipMode =>
|
bool get isPipMode =>
|
||||||
|
|||||||
Reference in New Issue
Block a user