mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-26 20:16:26 +08:00
opt live room
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -30,45 +30,46 @@ import 'package:get/get.dart';
|
||||
class LiveRoomController extends GetxController {
|
||||
LiveRoomController(this.heroTag);
|
||||
final String heroTag;
|
||||
late int roomId;
|
||||
dynamic liveItem;
|
||||
double volume = 0.0;
|
||||
// 静音状态
|
||||
RxBool volumeOff = false.obs;
|
||||
|
||||
int roomId = int.parse(Get.parameters['roomid']!);
|
||||
PlPlayerController plPlayerController = PlPlayerController.getInstance(
|
||||
isLive: true,
|
||||
);
|
||||
|
||||
RxBool isLoaded = false.obs;
|
||||
Rx<RoomInfoH5Data?> roomInfoH5 = Rx<RoomInfoH5Data?>(null);
|
||||
|
||||
// dm
|
||||
LiveDmInfoData? dmInfo;
|
||||
bool showDanmaku = true;
|
||||
DanmakuController? controller;
|
||||
List<RichTextItem>? savedDanmaku;
|
||||
RxList<dynamic> messages = [].obs;
|
||||
RxBool disableAutoScroll = false.obs;
|
||||
double? brightness;
|
||||
DanmakuController? controller;
|
||||
bool showDanmaku = true;
|
||||
LiveMessageStream? msgStream;
|
||||
late final ScrollController scrollController = ScrollController()
|
||||
..addListener(listener);
|
||||
|
||||
int? currentQn;
|
||||
late List<({int code, String desc})> acceptQnList = [];
|
||||
RxString currentQnDesc = ''.obs;
|
||||
final RxBool isPortrait = false.obs;
|
||||
late List<({int code, String desc})> acceptQnList = [];
|
||||
|
||||
List<RichTextItem>? savedDanmaku;
|
||||
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
late final isLogin = accountService.isLogin.value;
|
||||
|
||||
LiveDmInfoData? dmInfo;
|
||||
AccountService accountService = Get.find<AccountService>();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
roomId = int.parse(Get.parameters['roomid']!);
|
||||
queryLiveUrl();
|
||||
queryLiveInfoH5();
|
||||
if (Accounts.get(AccountType.heartbeat).isLogin && !Pref.historyPause) {
|
||||
VideoHttp.roomEntryAction(roomId: roomId);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> playerInit(String source) async {
|
||||
await plPlayerController.setDataSource(
|
||||
Future<void> playerInit(String source) {
|
||||
return plPlayerController.setDataSource(
|
||||
DataSource(
|
||||
videoSource: source,
|
||||
audioSource: null,
|
||||
@@ -84,9 +85,7 @@ class LiveRoomController extends GetxController {
|
||||
);
|
||||
}
|
||||
|
||||
final RxBool isPortrait = false.obs;
|
||||
|
||||
Future<void> queryLiveInfo() async {
|
||||
Future<void> queryLiveUrl() async {
|
||||
if (currentQn == null) {
|
||||
await Connectivity().checkConnectivity().then((res) {
|
||||
currentQn = res.contains(ConnectivityResult.wifi)
|
||||
@@ -102,7 +101,7 @@ class LiveRoomController extends GetxController {
|
||||
if (res['status']) {
|
||||
RoomPlayInfoData data = res['data'];
|
||||
if (data.liveStatus != 1) {
|
||||
_dialog(title: '当前直播间未开播');
|
||||
_showDialog('当前直播间未开播');
|
||||
return;
|
||||
}
|
||||
if (data.roomId != null) {
|
||||
@@ -127,7 +126,7 @@ class LiveRoomController extends GetxController {
|
||||
.description;
|
||||
String videoUrl = VideoUtils.getCdnUrl(item);
|
||||
await playerInit(videoUrl);
|
||||
return res;
|
||||
isLoaded.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,14 +142,12 @@ class LiveRoomController extends GetxController {
|
||||
);
|
||||
} else {
|
||||
if (res['msg'] != null) {
|
||||
_dialog(title: res['msg']);
|
||||
_showDialog(res['msg']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _dialog({
|
||||
required String title,
|
||||
}) {
|
||||
void _showDialog(String title) {
|
||||
Get.dialog(
|
||||
AlertDialog(
|
||||
title: Text(title),
|
||||
@@ -173,10 +170,6 @@ class LiveRoomController extends GetxController {
|
||||
);
|
||||
}
|
||||
|
||||
LiveMessageStream? msgStream;
|
||||
late final ScrollController scrollController = ScrollController()
|
||||
..addListener(listener);
|
||||
|
||||
void scrollToBottom() {
|
||||
if (disableAutoScroll.value) return;
|
||||
if (scrollController.hasClients) {
|
||||
@@ -264,7 +257,7 @@ class LiveRoomController extends GetxController {
|
||||
currentQnDesc.value = LiveQuality.values
|
||||
.firstWhere((element) => element.code == currentQn)
|
||||
.description;
|
||||
return queryLiveInfo();
|
||||
return queryLiveUrl();
|
||||
}
|
||||
|
||||
void initDm(LiveDmInfoData info) {
|
||||
|
||||
@@ -37,26 +37,22 @@ class LiveRoomPage extends StatefulWidget {
|
||||
|
||||
class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
with WidgetsBindingObserver {
|
||||
late final String heroTag;
|
||||
late final int _roomId;
|
||||
late final LiveRoomController _liveRoomController;
|
||||
late final PlPlayerController plPlayerController;
|
||||
late Future? _futureBuilderFuture;
|
||||
bool get isFullScreen => plPlayerController.isFullScreen.value;
|
||||
|
||||
bool isShowCover = true;
|
||||
bool isPlay = true;
|
||||
|
||||
StreamSubscription? _listener;
|
||||
|
||||
int latestAddedPosition = -1;
|
||||
bool? _isFullScreen;
|
||||
bool? _isPipMode;
|
||||
|
||||
void playCallBack() {
|
||||
plPlayerController.play();
|
||||
}
|
||||
final GlobalKey chatKey = GlobalKey();
|
||||
final GlobalKey playerKey = GlobalKey();
|
||||
final GlobalKey videoPlayerKey = GlobalKey();
|
||||
|
||||
late final String heroTag;
|
||||
final Color _color = const Color(0xFFEEEEEE);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -68,9 +64,8 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
LiveRoomController(heroTag),
|
||||
tag: heroTag,
|
||||
);
|
||||
PlPlayerController.setPlayCallBack(playCallBack);
|
||||
videoSourceInit();
|
||||
_futureBuilderFuture = _liveRoomController.queryLiveInfo();
|
||||
plPlayerController = _liveRoomController.plPlayerController;
|
||||
PlPlayerController.setPlayCallBack(plPlayerController.play);
|
||||
plPlayerController
|
||||
..autoEnterFullscreen()
|
||||
..addStatusLister(playerListener);
|
||||
@@ -115,10 +110,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
: 15 * plPlayerController.danmakuFontScaleFS;
|
||||
}
|
||||
|
||||
void videoSourceInit() {
|
||||
plPlayerController = _liveRoomController.plPlayerController;
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
videoPlayerServiceHandler.onVideoDetailDispose(heroTag);
|
||||
@@ -145,8 +136,21 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
}
|
||||
}
|
||||
|
||||
final GlobalKey videoPlayerKey = GlobalKey();
|
||||
final GlobalKey playerKey = GlobalKey();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_updateFontSize();
|
||||
});
|
||||
|
||||
final isPortrait = context.isPortrait;
|
||||
if (Platform.isAndroid) {
|
||||
return Floating().isPipMode
|
||||
? videoPlayerPanel()
|
||||
: childWhenDisabled(isPortrait);
|
||||
} else {
|
||||
return childWhenDisabled(isPortrait);
|
||||
}
|
||||
}
|
||||
|
||||
Widget videoPlayerPanel({Color? fill, Alignment? alignment}) {
|
||||
return PopScope(
|
||||
@@ -156,66 +160,59 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
plPlayerController.triggerFullScreen(status: false);
|
||||
}
|
||||
},
|
||||
child: FutureBuilder(
|
||||
key: videoPlayerKey,
|
||||
future: _futureBuilderFuture,
|
||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||
if (snapshot.hasData && snapshot.data['status']) {
|
||||
final roomInfoH5 = _liveRoomController.roomInfoH5.value;
|
||||
return PLVideoPlayer(
|
||||
key: playerKey,
|
||||
fill: fill,
|
||||
alignment: alignment,
|
||||
child: Obx(() {
|
||||
if (_liveRoomController.isLoaded.value) {
|
||||
final roomInfoH5 = _liveRoomController.roomInfoH5.value;
|
||||
return PLVideoPlayer(
|
||||
key: playerKey,
|
||||
fill: fill,
|
||||
alignment: alignment,
|
||||
plPlayerController: plPlayerController,
|
||||
headerControl: LiveHeaderControl(
|
||||
title: roomInfoH5?.roomInfo?.title,
|
||||
upName: roomInfoH5?.anchorInfo?.baseInfo?.uname,
|
||||
plPlayerController: plPlayerController,
|
||||
headerControl: LiveHeaderControl(
|
||||
title: roomInfoH5?.roomInfo?.title,
|
||||
upName: roomInfoH5?.anchorInfo?.baseInfo?.uname,
|
||||
plPlayerController: plPlayerController,
|
||||
onSendDanmaku: onSendDanmaku,
|
||||
onPlayAudio: _liveRoomController.queryLiveInfo,
|
||||
),
|
||||
bottomControl: BottomControl(
|
||||
plPlayerController: plPlayerController,
|
||||
liveRoomCtr: _liveRoomController,
|
||||
onRefresh: () {
|
||||
_futureBuilderFuture = _liveRoomController.queryLiveInfo();
|
||||
},
|
||||
),
|
||||
danmuWidget: Obx(
|
||||
() => AnimatedOpacity(
|
||||
opacity: plPlayerController.enableShowDanmaku.value ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
child: DanmakuScreen(
|
||||
createdController: (DanmakuController e) {
|
||||
plPlayerController.danmakuController =
|
||||
_liveRoomController.controller = e;
|
||||
},
|
||||
option: DanmakuOption(
|
||||
fontSize: _getFontSize(isFullScreen),
|
||||
fontWeight: plPlayerController.fontWeight,
|
||||
area: plPlayerController.showArea,
|
||||
opacity: plPlayerController.danmakuOpacity,
|
||||
hideTop: plPlayerController.blockTypes.contains(5),
|
||||
hideScroll: plPlayerController.blockTypes.contains(2),
|
||||
hideBottom: plPlayerController.blockTypes.contains(4),
|
||||
duration:
|
||||
plPlayerController.danmakuDuration /
|
||||
plPlayerController.playbackSpeed,
|
||||
staticDuration:
|
||||
plPlayerController.danmakuStaticDuration /
|
||||
plPlayerController.playbackSpeed,
|
||||
strokeWidth: plPlayerController.strokeWidth,
|
||||
lineHeight: plPlayerController.danmakuLineHeight,
|
||||
),
|
||||
onSendDanmaku: onSendDanmaku,
|
||||
onPlayAudio: _liveRoomController.queryLiveUrl,
|
||||
),
|
||||
bottomControl: BottomControl(
|
||||
plPlayerController: plPlayerController,
|
||||
liveRoomCtr: _liveRoomController,
|
||||
onRefresh: _liveRoomController.queryLiveUrl,
|
||||
),
|
||||
danmuWidget: Obx(
|
||||
() => AnimatedOpacity(
|
||||
opacity: plPlayerController.enableShowDanmaku.value ? 1 : 0,
|
||||
duration: const Duration(milliseconds: 100),
|
||||
child: DanmakuScreen(
|
||||
createdController: (DanmakuController e) {
|
||||
plPlayerController.danmakuController =
|
||||
_liveRoomController.controller = e;
|
||||
},
|
||||
option: DanmakuOption(
|
||||
fontSize: _getFontSize(isFullScreen),
|
||||
fontWeight: plPlayerController.fontWeight,
|
||||
area: plPlayerController.showArea,
|
||||
opacity: plPlayerController.danmakuOpacity,
|
||||
hideTop: plPlayerController.blockTypes.contains(5),
|
||||
hideScroll: plPlayerController.blockTypes.contains(2),
|
||||
hideBottom: plPlayerController.blockTypes.contains(4),
|
||||
duration:
|
||||
plPlayerController.danmakuDuration /
|
||||
plPlayerController.playbackSpeed,
|
||||
staticDuration:
|
||||
plPlayerController.danmakuStaticDuration /
|
||||
plPlayerController.playbackSpeed,
|
||||
strokeWidth: plPlayerController.strokeWidth,
|
||||
lineHeight: plPlayerController.danmakuLineHeight,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -256,21 +253,23 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
.value
|
||||
?.roomInfo
|
||||
?.appBackground;
|
||||
Widget child;
|
||||
if (appBackground?.isNotEmpty == true) {
|
||||
final size = Get.size;
|
||||
child = CachedNetworkImage(
|
||||
fit: BoxFit.cover,
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
imageUrl: appBackground!.http2https,
|
||||
);
|
||||
} else {
|
||||
child = Image.asset(
|
||||
'assets/images/live/default_bg.webp',
|
||||
fit: BoxFit.cover,
|
||||
);
|
||||
}
|
||||
return Positioned.fill(
|
||||
child: Opacity(
|
||||
opacity: 0.6,
|
||||
child: appBackground?.isNotEmpty == true
|
||||
? CachedNetworkImage(
|
||||
fit: BoxFit.cover,
|
||||
width: Get.width,
|
||||
height: Get.height,
|
||||
imageUrl: appBackground!.http2https,
|
||||
)
|
||||
: Image.asset(
|
||||
'assets/images/live/default_bg.webp',
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
child: Opacity(opacity: 0.6, child: child),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -285,7 +284,25 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
if (_liveRoomController.isPortrait.value) {
|
||||
return _buildPP;
|
||||
}
|
||||
return _buildPH;
|
||||
return Column(
|
||||
children: [
|
||||
_buildAppBar,
|
||||
Obx(
|
||||
() {
|
||||
final size = Get.size;
|
||||
return Container(
|
||||
color: Colors.black,
|
||||
width: size.width,
|
||||
height: isFullScreen
|
||||
? size.height
|
||||
: size.width * 9 / 16,
|
||||
child: videoPlayerPanel(),
|
||||
);
|
||||
},
|
||||
),
|
||||
..._buildBottomWidget,
|
||||
],
|
||||
);
|
||||
},
|
||||
)
|
||||
: Column(
|
||||
@@ -301,13 +318,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _buildPH => Column(
|
||||
children: [
|
||||
_buildAppBar,
|
||||
..._buildBodyP,
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _buildPP => Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
@@ -351,26 +361,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
],
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_updateFontSize();
|
||||
});
|
||||
return OrientationBuilder(
|
||||
builder: (BuildContext context, Orientation orientation) {
|
||||
if (Platform.isAndroid) {
|
||||
return Floating().isPipMode
|
||||
? videoPlayerPanel()
|
||||
: childWhenDisabled(orientation == Orientation.portrait);
|
||||
} else {
|
||||
return childWhenDisabled(orientation == Orientation.portrait);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final Color _color = const Color(0xFFEEEEEE);
|
||||
|
||||
PreferredSizeWidget get _buildAppBar {
|
||||
final color = Theme.of(context).colorScheme.onSurfaceVariant;
|
||||
return AppBar(
|
||||
@@ -421,8 +411,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
actions: [
|
||||
IconButton(
|
||||
tooltip: '刷新',
|
||||
onPressed: () =>
|
||||
_futureBuilderFuture = _liveRoomController.queryLiveInfo(),
|
||||
onPressed: _liveRoomController.queryLiveUrl,
|
||||
icon: const Icon(Icons.refresh, size: 20),
|
||||
),
|
||||
PopupMenuButton(
|
||||
@@ -497,15 +486,18 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
child: Row(
|
||||
children: [
|
||||
Obx(
|
||||
() => Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
color: isFullScreen ? Colors.black : null,
|
||||
width: isFullScreen ? Get.size.width : videoWidth,
|
||||
height: isFullScreen ? Get.size.height : Get.size.width * 9 / 16,
|
||||
child: videoPlayerPanel(fill: Colors.transparent),
|
||||
),
|
||||
() {
|
||||
final size = Get.size;
|
||||
return Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
color: isFullScreen ? Colors.black : null,
|
||||
width: isFullScreen ? size.width : videoWidth,
|
||||
height: isFullScreen ? size.height : size.width * 9 / 16,
|
||||
child: videoPlayerPanel(fill: Colors.transparent),
|
||||
);
|
||||
},
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
@@ -518,20 +510,6 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> get _buildBodyP => [
|
||||
Obx(
|
||||
() => Container(
|
||||
color: Colors.black,
|
||||
width: Get.size.width,
|
||||
height: isFullScreen ? Get.size.height : Get.size.width * 9 / 16,
|
||||
child: videoPlayerPanel(),
|
||||
),
|
||||
),
|
||||
..._buildBottomWidget,
|
||||
];
|
||||
|
||||
final GlobalKey chatKey = GlobalKey();
|
||||
|
||||
List<Widget> get _buildBottomWidget => [
|
||||
Expanded(child: _buildChatWidget()),
|
||||
_buildInputWidget,
|
||||
|
||||
@@ -252,9 +252,7 @@ class _SavePanelState extends State<SavePanel> {
|
||||
mimeType: 'image/png',
|
||||
),
|
||||
],
|
||||
sharePositionOrigin: await Utils.isIpad()
|
||||
? Rect.fromLTWH(0, 0, Get.width, Get.height / 2)
|
||||
: null,
|
||||
sharePositionOrigin: await Utils.sharePositionOrigin,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -53,6 +53,7 @@ class _ColorSelectPageState extends State<ColorSelectPage> {
|
||||
TextStyle subTitleStyle = theme.textTheme.labelMedium!.copyWith(
|
||||
color: theme.colorScheme.outline,
|
||||
);
|
||||
final size = Get.size;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('选择应用主题')),
|
||||
body: SafeArea(
|
||||
@@ -240,8 +241,8 @@ class _ColorSelectPageState extends State<ColorSelectPage> {
|
||||
...[
|
||||
IgnorePointer(
|
||||
child: Container(
|
||||
height: Get.height / 2,
|
||||
width: Get.width,
|
||||
height: size.height / 2,
|
||||
width: size.width,
|
||||
color: theme.colorScheme.surface,
|
||||
child: const HomePage(),
|
||||
),
|
||||
|
||||
@@ -136,10 +136,10 @@ class VideoDetailController extends GetxController
|
||||
duration: const Duration(milliseconds: 200),
|
||||
);
|
||||
late final double minVideoHeight = Get.mediaQuery.size.shortestSide * 9 / 16;
|
||||
late final double maxVideoHeight = max(
|
||||
Get.mediaQuery.size.longestSide * 0.65,
|
||||
Get.mediaQuery.size.shortestSide,
|
||||
);
|
||||
late final double maxVideoHeight = () {
|
||||
final size = Get.mediaQuery.size;
|
||||
return max(size.longestSide * 0.65, size.shortestSide);
|
||||
}();
|
||||
late double videoHeight = minVideoHeight;
|
||||
|
||||
void animToTop() {
|
||||
@@ -1304,7 +1304,7 @@ class VideoDetailController extends GetxController
|
||||
videoUrl = VideoUtils.getCdnUrl(firstVideo);
|
||||
|
||||
/// 优先顺序 设置中指定质量 -> 当前可选的最高质量
|
||||
late AudioItem? firstAudio;
|
||||
AudioItem? firstAudio;
|
||||
final List<AudioItem> audiosList = data.dash!.audio ?? <AudioItem>[];
|
||||
if (data.dash!.dolby?.audio != null &&
|
||||
data.dash!.dolby!.audio!.isNotEmpty) {
|
||||
|
||||
@@ -190,10 +190,11 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
final isVertical = videoDetailController.isVertical.value;
|
||||
final mode = plPlayerController?.mode;
|
||||
|
||||
late final size = Get.size;
|
||||
if (!(mode == FullScreenMode.vertical ||
|
||||
(mode == FullScreenMode.auto && isVertical) ||
|
||||
(mode == FullScreenMode.ratio &&
|
||||
(Get.height / Get.width < 1.25 || isVertical)))) {
|
||||
(isVertical || size.height / size.width < 1.25)))) {
|
||||
landScape();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -895,14 +895,8 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
mimeType: Headers.jsonContentType,
|
||||
),
|
||||
],
|
||||
sharePositionOrigin: await Utils.isIpad()
|
||||
? Rect.fromLTWH(
|
||||
0,
|
||||
0,
|
||||
Get.width,
|
||||
Get.height / 2,
|
||||
)
|
||||
: null,
|
||||
sharePositionOrigin:
|
||||
await Utils.sharePositionOrigin,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user