Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-30 13:58:14 +08:00
parent 9a63e23478
commit 5f2e863cc2
8 changed files with 95 additions and 129 deletions

View File

@@ -44,7 +44,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
bool isShowCover = true; bool isShowCover = true;
bool isPlay = true; bool isPlay = true;
Floating? floating;
StreamSubscription? _listener; StreamSubscription? _listener;
@@ -69,9 +68,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
tag: heroTag, tag: heroTag,
); );
PlPlayerController.setPlayCallBack(playCallBack); PlPlayerController.setPlayCallBack(playCallBack);
if (Platform.isAndroid) {
floating = Floating();
}
videoSourceInit(); videoSourceInit();
_futureBuilderFuture = _liveRoomController.queryLiveInfo(); _futureBuilderFuture = _liveRoomController.queryLiveInfo();
plPlayerController plPlayerController
@@ -145,7 +141,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
final GlobalKey videoPlayerKey = GlobalKey(); final GlobalKey videoPlayerKey = GlobalKey();
final GlobalKey playerKey = GlobalKey(); final GlobalKey playerKey = GlobalKey();
double? padding;
Widget videoPlayerPanel({Color? fill, Alignment? alignment}) { Widget videoPlayerPanel({Color? fill, Alignment? alignment}) {
return PopScope( return PopScope(
@@ -167,7 +162,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
plPlayerController: plPlayerController, plPlayerController: plPlayerController,
headerControl: LiveHeaderControl( headerControl: LiveHeaderControl(
plPlayerController: plPlayerController, plPlayerController: plPlayerController,
floating: floating,
onSendDanmaku: onSendDanmaku, onSendDanmaku: onSendDanmaku,
), ),
bottomControl: BottomControl( bottomControl: BottomControl(
@@ -243,7 +237,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
), ),
), ),
SafeArea( SafeArea(
top: false, top: !isFullScreen,
left: !isFullScreen, left: !isFullScreen,
right: !isFullScreen, right: !isFullScreen,
bottom: false, bottom: false,
@@ -251,10 +245,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
? Obx( ? Obx(
() { () {
if (_liveRoomController.isPortrait.value) { if (_liveRoomController.isPortrait.value) {
if (padding == null) {
final padding = MediaQuery.paddingOf(context);
this.padding = padding.bottom + padding.top;
}
return _buildPP; return _buildPP;
} }
return _buildPH; return _buildPH;
@@ -285,51 +275,41 @@ class _LiveRoomPageState extends State<LiveRoomPage>
_buildAppBar, _buildAppBar,
Column( Column(
children: [ children: [
Obx( Expanded(
() => Container( child: Stack(
color: Colors.black, clipBehavior: Clip.none,
width: Get.width, children: [
margin: isFullScreen Obx(
? null () => Container(
: EdgeInsets.only( margin: isFullScreen
top: 56 + MediaQuery.paddingOf(context).top, ? null
: const EdgeInsets.only(top: 56),
color: Colors.black,
child: videoPlayerPanel(
alignment: isFullScreen ? null : Alignment.topCenter,
), ),
height: isFullScreen ),
? Get.height - ),
(context.orientation == Orientation.landscape Obx(
? 0 () => isFullScreen
: MediaQuery.paddingOf(context).top) ? const SizedBox.shrink()
: Get.height - 56 - 85 - padding!, : Positioned(
child: videoPlayerPanel( left: 0,
alignment: isFullScreen ? null : Alignment.topCenter, right: 0,
), bottom: 55,
child: SizedBox(
height: 125,
child: _buildChatWidget(true),
),
),
),
],
), ),
), ),
Obx(() =>
isFullScreen ? const SizedBox.shrink() : _buildInputWidget),
], ],
), ),
Obx(
() => isFullScreen
? const SizedBox.shrink()
: Positioned(
left: 0,
right: 0,
bottom: 125 + MediaQuery.paddingOf(context).bottom,
child: SizedBox(
height: 125,
child: _buildChatWidget(true),
),
),
),
Obx(
() => isFullScreen
? const SizedBox.shrink()
: Positioned(
left: 0,
right: 0,
bottom: 0,
child: _buildInputWidget,
),
),
], ],
); );
@@ -341,12 +321,9 @@ class _LiveRoomPageState extends State<LiveRoomPage>
return OrientationBuilder( return OrientationBuilder(
builder: (BuildContext context, Orientation orientation) { builder: (BuildContext context, Orientation orientation) {
if (Platform.isAndroid) { if (Platform.isAndroid) {
return PiPSwitcher( return Floating().isPipMode
getChildWhenDisabled: () => ? videoPlayerPanel()
childWhenDisabled(orientation == Orientation.portrait), : childWhenDisabled(orientation == Orientation.portrait);
getChildWhenEnabled: () => videoPlayerPanel(),
floating: floating,
);
} else { } else {
return childWhenDisabled(orientation == Orientation.portrait); return childWhenDisabled(orientation == Orientation.portrait);
} }

View File

@@ -10,12 +10,10 @@ import 'package:material_design_icons_flutter/material_design_icons_flutter.dart
class LiveHeaderControl extends StatelessWidget implements PreferredSizeWidget { class LiveHeaderControl extends StatelessWidget implements PreferredSizeWidget {
const LiveHeaderControl({ const LiveHeaderControl({
required this.plPlayerController, required this.plPlayerController,
this.floating,
required this.onSendDanmaku, required this.onSendDanmaku,
super.key, super.key,
}); });
final Floating? floating;
final PlPlayerController plPlayerController; final PlPlayerController plPlayerController;
final VoidCallback onSendDanmaku; final VoidCallback onSendDanmaku;
@@ -77,9 +75,15 @@ class LiveHeaderControl extends StatelessWidget implements PreferredSizeWidget {
), ),
onPressed: () async { onPressed: () async {
try { try {
if ((await floating?.isPipAvailable) == true) { var floating = Floating();
if ((await floating.isPipAvailable) == true) {
plPlayerController.hiddenControls(false); plPlayerController.hiddenControls(false);
floating!.enable(const EnableManual()); floating.enable(
plPlayerController.direction.value == 'vertical'
? const EnableManual(
aspectRatio: Rational.vertical())
: const EnableManual(),
);
} }
} catch (_) {} } catch (_) {}
}, },

View File

@@ -1,5 +1,4 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:ui'; import 'dart:ui';
@@ -48,7 +47,6 @@ import 'package:PiliPlus/utils/video_utils.dart';
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:easy_debounce/easy_throttle.dart'; import 'package:easy_debounce/easy_throttle.dart';
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:floating/floating.dart';
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';
import 'package:flutter_volume_controller/flutter_volume_controller.dart'; import 'package:flutter_volume_controller/flutter_volume_controller.dart';
@@ -103,7 +101,6 @@ class VideoDetailController extends GetxController
// 亮度 // 亮度
double? brightness; double? brightness;
Floating? floating;
late final headerCtrKey = GlobalKey<HeaderControlState>(); late final headerCtrKey = GlobalKey<HeaderControlState>();
Box get setting => GStorage.setting; Box get setting => GStorage.setting;
@@ -287,10 +284,6 @@ class VideoDetailController extends GetxController
if (autoPlay.value) isShowCover.value = false; if (autoPlay.value) isShowCover.value = false;
danmakuCid.value = cid.value; danmakuCid.value = cid.value;
if (Platform.isAndroid) {
floating = Floating();
}
// 预设的解码格式 // 预设的解码格式
cacheDecode = setting.get(SettingBoxKey.defaultDecode, cacheDecode = setting.get(SettingBoxKey.defaultDecode,
defaultValue: VideoDecodeFormatType.values.last.code); defaultValue: VideoDecodeFormatType.values.last.code);
@@ -1109,6 +1102,8 @@ class VideoDetailController extends GetxController
} }
setSubtitle(vttSubtitlesIndex.value); setSubtitle(vttSubtitlesIndex.value);
}, },
width: data.dash!.video!.first.width,
height: data.dash!.video!.first.height,
); );
initSkip(); initSkip();
@@ -1121,9 +1116,7 @@ class VideoDetailController extends GetxController
_getDmTrend(); _getDmTrend();
} }
if (defaultST != null) { defaultST = null;
defaultST = null;
}
} }
bool isQuerying = false; bool isQuerying = false;

View File

@@ -86,7 +86,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
late bool autoExitFullscreen; late bool autoExitFullscreen;
late bool autoPlayEnable; late bool autoPlayEnable;
late bool enableVerticalExpand; late bool enableVerticalExpand;
late bool autoPiP;
late bool pipNoDanmaku; late bool pipNoDanmaku;
late bool removeSafeArea; late bool removeSafeArea;
bool isShowing = true; bool isShowing = true;
@@ -142,7 +141,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
setting.get(SettingBoxKey.enableAutoExit, defaultValue: true); setting.get(SettingBoxKey.enableAutoExit, defaultValue: true);
autoPlayEnable = autoPlayEnable =
setting.get(SettingBoxKey.autoPlayEnable, defaultValue: false); setting.get(SettingBoxKey.autoPlayEnable, defaultValue: false);
autoPiP = setting.get(SettingBoxKey.autoPiP, defaultValue: false);
pipNoDanmaku = setting.get(SettingBoxKey.pipNoDanmaku, defaultValue: false); pipNoDanmaku = setting.get(SettingBoxKey.pipNoDanmaku, defaultValue: false);
enableVerticalExpand = enableVerticalExpand =
setting.get(SettingBoxKey.enableVerticalExpand, defaultValue: false); setting.get(SettingBoxKey.enableVerticalExpand, defaultValue: false);
@@ -151,17 +149,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
if (removeSafeArea) hideStatusBar(); if (removeSafeArea) hideStatusBar();
videoSourceInit(); videoSourceInit();
autoScreen(); autoScreen();
if (Platform.isAndroid) {
Utils.channel.setMethodCallHandler((call) async {
if (call.method == 'onUserLeaveHint') {
if (autoPiP &&
plPlayerController?.playerStatus.status.value ==
PlayerStatus.playing) {
enterPip();
}
}
});
}
if (videoDetailController.showReply) { if (videoDetailController.showReply) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -276,9 +263,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
} }
} }
// 播放完展示控制栏 // 播放完展示控制栏
if (videoDetailController.floating != null && !notExitFlag) { if (Platform.isAndroid && !notExitFlag) {
PiPStatus currentStatus = PiPStatus currentStatus = await Floating().pipStatus;
await videoDetailController.floating!.pipStatus;
if (currentStatus == PiPStatus.disabled) { if (currentStatus == PiPStatus.disabled) {
plPlayerController!.onLockControl(false); plPlayerController!.onLockControl(false);
} }
@@ -454,17 +440,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
: Theme.of(context); : Theme.of(context);
} }
void enterPip() {
if (Get.currentRoute.startsWith('/video') &&
videoDetailController.floating != null) {
PageUtils.enterPip(
videoDetailController.floating!,
videoDetailController.data.dash!.video!.first.width!,
videoDetailController.data.dash!.video!.first.height!,
);
}
}
void animListener() { void animListener() {
if (videoDetailController.animationController.isForwardOrCompleted) { if (videoDetailController.animationController.isForwardOrCompleted) {
cal(); cal();
@@ -1413,7 +1388,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
key: videoDetailController.headerCtrKey, key: videoDetailController.headerCtrKey,
controller: videoDetailController.plPlayerController, controller: videoDetailController.plPlayerController,
videoDetailCtr: videoDetailController, videoDetailCtr: videoDetailController,
floating: videoDetailController.floating,
heroTag: heroTag, heroTag: heroTag,
), ),
danmuWidget: Obx( danmuWidget: Obx(
@@ -1431,11 +1405,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
Widget autoChoose(Widget childWhenDisabled) { Widget autoChoose(Widget childWhenDisabled) {
if (Platform.isAndroid) { if (Platform.isAndroid) {
return PiPSwitcher( return Floating().isPipMode ? childWhenEnabled : childWhenDisabled;
getChildWhenDisabled: () => childWhenDisabled,
getChildWhenEnabled: () => childWhenEnabled,
floating: videoDetailController.floating,
);
} }
return childWhenDisabled; return childWhenDisabled;
} }

View File

@@ -47,13 +47,11 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
const HeaderControl({ const HeaderControl({
required this.controller, required this.controller,
required this.videoDetailCtr, required this.videoDetailCtr,
this.floating,
required this.heroTag, required this.heroTag,
super.key, super.key,
}); });
final PlPlayerController controller; final PlPlayerController controller;
final VideoDetailController videoDetailCtr; final VideoDetailController videoDetailCtr;
final Floating? floating;
final String heroTag; final String heroTag;
@override @override
@@ -2118,8 +2116,7 @@ class HeaderControlState extends State<HeaderControl> {
padding: WidgetStateProperty.all(EdgeInsets.zero), padding: WidgetStateProperty.all(EdgeInsets.zero),
), ),
onPressed: () async { onPressed: () async {
bool canUsePiP = widget.floating != null && bool canUsePiP = await Floating().isPipAvailable;
await widget.floating!.isPipAvailable;
widget.controller.hiddenControls(false); widget.controller.hiddenControls(false);
if (canUsePiP) { if (canUsePiP) {
bool enableBackgroundPlay = setting.get( bool enableBackgroundPlay = setting.get(
@@ -2189,10 +2186,9 @@ class HeaderControlState extends State<HeaderControl> {
} }
if (!context.mounted) return; if (!context.mounted) return;
PageUtils.enterPip( PageUtils.enterPip(
widget.floating!, width: widget
widget
.videoDetailCtr.data.dash!.video!.first.width!, .videoDetailCtr.data.dash!.video!.first.width!,
widget height: widget
.videoDetailCtr.data.dash!.video!.first.height!, .videoDetailCtr.data.dash!.video!.first.height!,
); );
} }

View File

@@ -23,6 +23,7 @@ import 'package:PiliPlus/plugin/pl_player/utils/fullscreen.dart';
import 'package:PiliPlus/services/service_locator.dart'; import 'package:PiliPlus/services/service_locator.dart';
import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/page_utils.dart' show PageUtils;
import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart'; import 'package:PiliPlus/utils/utils.dart';
import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart';
@@ -116,6 +117,8 @@ class PlPlayerController {
dynamic _seasonId; dynamic _seasonId;
dynamic _subType; dynamic _subType;
int _heartDuration = 0; int _heartDuration = 0;
int? width;
int? height;
late DataSource dataSource; late DataSource dataSource;
@@ -243,6 +246,15 @@ class PlPlayerController {
/// 弹幕开关 /// 弹幕开关
RxBool isOpenDanmu = false.obs; RxBool isOpenDanmu = false.obs;
bool autoPiP =
GStorage.setting.get(SettingBoxKey.autoPiP, defaultValue: false);
void enterPip() {
if (Get.currentRoute.startsWith('/video')) {
PageUtils.enterPip(width: width, height: height);
}
}
/// 弹幕权重 /// 弹幕权重
int danmakuWeight = 0; int danmakuWeight = 0;
late RuleFilter filters; late RuleFilter filters;
@@ -486,6 +498,16 @@ class PlPlayerController {
enableHeart = false; enableHeart = false;
} }
if (Platform.isAndroid) {
Utils.channel.setMethodCallHandler((call) async {
if (call.method == 'onUserLeaveHint') {
if (autoPiP && playerStatus.status.value == PlayerStatus.playing) {
enterPip();
}
}
});
}
// _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) { // _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
// if (status == PlayerStatus.playing) { // if (status == PlayerStatus.playing) {
// WakelockPlus.enable(); // WakelockPlus.enable();
@@ -520,8 +542,8 @@ class PlPlayerController {
Duration? seekTo, Duration? seekTo,
// 初始化播放速度 // 初始化播放速度
double speed = 1.0, double speed = 1.0,
double? width, int? width,
double? height, int? height,
Duration? duration, Duration? duration,
// 方向 // 方向
String? direction, String? direction,
@@ -534,6 +556,8 @@ class PlPlayerController {
VoidCallback? callback, VoidCallback? callback,
}) async { }) async {
try { try {
this.width = width;
this.height = height;
this.dataSource = dataSource; this.dataSource = dataSource;
this.segmentList.value = segmentList ?? <Segment>[]; this.segmentList.value = segmentList ?? <Segment>[];
this.viewPointList.value = viewPointList ?? <Segment>[]; this.viewPointList.value = viewPointList ?? <Segment>[];
@@ -568,8 +592,8 @@ class PlPlayerController {
return; return;
} }
// 配置Player 音轨、字幕等等 // 配置Player 音轨、字幕等等
_videoPlayerController = await _createVideoController( _videoPlayerController =
dataSource, _looping, width, height, seekTo); await _createVideoController(dataSource, _looping, seekTo);
callback?.call(); callback?.call();
// 获取视频时长 00:00 // 获取视频时长 00:00
_duration.value = duration ?? _videoPlayerController!.state.duration; _duration.value = duration ?? _videoPlayerController!.state.duration;
@@ -676,8 +700,6 @@ class PlPlayerController {
Future<Player> _createVideoController( Future<Player> _createVideoController(
DataSource dataSource, DataSource dataSource,
PlaylistMode looping, PlaylistMode looping,
double? width,
double? height,
Duration? seekTo, Duration? seekTo,
) async { ) async {
// 每次配置时先移除监听 // 每次配置时先移除监听

View File

@@ -330,17 +330,21 @@ class PageUtils {
); );
} }
static void enterPip(Floating floating, int width, int height) { static void enterPip({int? width, int? height}) {
Rational aspectRatio = Rational(width, height); if (width != null && height != null) {
floating.enable( Rational aspectRatio = Rational(width, height);
EnableManual( Floating().enable(
aspectRatio: aspectRatio.fitsInAndroidRequirements EnableManual(
? aspectRatio aspectRatio: aspectRatio.fitsInAndroidRequirements
: height > width ? aspectRatio
? const Rational.vertical() : height > width
: const Rational.landscape(), ? const Rational.vertical()
), : const Rational.landscape(),
); ),
);
} else {
Floating().enable(const EnableManual());
}
} }
static Future<void> pushDynDetail(DynamicItemModel item, floor, static Future<void> pushDynDetail(DynamicItemModel item, floor,

View File

@@ -607,7 +607,7 @@ packages:
description: description:
path: "." path: "."
ref: version-3 ref: version-3
resolved-ref: "44bd7a589f199e0b8f7f5bb1a6df08579079c570" resolved-ref: "929e9ec1312d9d1b4755d7589dd53db5b4d6d50d"
url: "https://github.com/bggRGjQaUbCoE/floating.git" url: "https://github.com/bggRGjQaUbCoE/floating.git"
source: git source: git
version: "3.0.0" version: "3.0.0"