Closes #979

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-08-11 16:18:30 +08:00
parent 2c92845af0
commit 60c25e4b65
8 changed files with 112 additions and 48 deletions

View File

@@ -4,8 +4,6 @@ import 'package:PiliPlus/build_config.dart';
import 'package:PiliPlus/common/widgets/custom_toast.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/models/common/theme/theme_color_type.dart';
import 'package:PiliPlus/pages/main/view.dart';
import 'package:PiliPlus/pages/video/view.dart';
import 'package:PiliPlus/router/app_pages.dart';
import 'package:PiliPlus/services/account_service.dart';
import 'package:PiliPlus/services/loggeer.dart';
@@ -13,6 +11,7 @@ import 'package:PiliPlus/services/service_locator.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/cache_manage.dart';
import 'package:PiliPlus/utils/date_util.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/request_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart';
@@ -227,8 +226,7 @@ class MyApp extends StatelessWidget {
),
navigatorObservers: [
FlutterSmartDialog.observer,
VideoDetailPageV.routeObserver,
MainApp.routeObserver,
PageUtils.routeObserver,
],
);
}),

View File

@@ -259,6 +259,7 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
),
const Spacer(),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => Get.to(const LiveFollowPage()),
child: Row(
mainAxisSize: MainAxisSize.min,
@@ -293,6 +294,7 @@ class _LivePageState extends CommonPageState<LivePage, LiveController>
return SizedBox(
width: 65,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => PageUtils.toLiveRoom(item.roomid),
onLongPress: () {
Feedback.forLongPress(context);

View File

@@ -32,6 +32,7 @@ class LiveRoomController extends GetxController {
final String heroTag;
int roomId = Get.arguments;
DanmakuController? danmakuController;
PlPlayerController plPlayerController = PlPlayerController.getInstance(
isLive: true,
);
@@ -61,7 +62,7 @@ class LiveRoomController extends GetxController {
List<RichTextItem>? savedDanmaku;
RxList<dynamic> messages = [].obs;
RxBool disableAutoScroll = false.obs;
LiveMessageStream? msgStream;
LiveMessageStream? _msgStream;
late final ScrollController scrollController = ScrollController()
..addListener(listener);
@@ -73,6 +74,10 @@ class LiveRoomController extends GetxController {
late final isLogin = accountService.isLogin.value;
AccountService accountService = Get.find<AccountService>();
String? videoUrl;
bool? isPlaying;
late bool isFullScreen = false;
@override
void onInit() {
super.onInit();
@@ -83,10 +88,13 @@ class LiveRoomController extends GetxController {
}
}
Future<void> playerInit(String source) {
Future<void>? playerInit({bool autoplay = true}) {
if (videoUrl == null) {
return null;
}
return plPlayerController.setDataSource(
DataSource(
videoSource: source,
videoSource: videoUrl,
audioSource: null,
type: DataSourceType.network,
httpHeaders: {
@@ -95,7 +103,8 @@ class LiveRoomController extends GetxController {
'referer': HttpString.baseUrl,
},
),
autoplay: true,
isLive: true,
autoplay: autoplay,
isVertical: isPortrait.value,
);
}
@@ -145,8 +154,8 @@ class LiveRoomController extends GetxController {
.firstWhereOrNull((element) => element.code == currentQn)
?.description ??
currentQn.toString();
String videoUrl = VideoUtils.getCdnUrl(item);
await playerInit(videoUrl);
videoUrl = VideoUtils.getCdnUrl(item);
await playerInit();
isLoaded.value = true;
}
}
@@ -198,7 +207,12 @@ class LiveRoomController extends GetxController {
}
}
void liveMsg() {
void closeLiveMsg() {
_msgStream?.close();
_msgStream = null;
}
void startLiveMsg() {
if (messages.isEmpty) {
LiveHttp.liveRoomDanmaPrefetch(roomId: roomId).then((v) {
if (v['status']) {
@@ -225,7 +239,7 @@ class LiveRoomController extends GetxController {
}
});
}
if (msgStream != null) {
if (_msgStream != null) {
return;
}
if (dmInfo != null) {
@@ -259,8 +273,7 @@ class LiveRoomController extends GetxController {
cancelLiveTimer();
savedDanmaku?.clear();
savedDanmaku = null;
msgStream?.close();
msgStream = null;
closeLiveMsg();
scrollController
..removeListener(listener)
..dispose();
@@ -285,7 +298,7 @@ class LiveRoomController extends GetxController {
if (info.hostList.isNullOrEmpty) {
return;
}
msgStream =
_msgStream =
LiveMessageStream(
streamToken: info.token!,
roomId: roomId,
@@ -321,9 +334,11 @@ class LiveRoomController extends GetxController {
selfSend: isLogin && uid == accountService.mid,
),
);
WidgetsBinding.instance.addPostFrameCallback(
(_) => scrollToBottom(),
);
if (!isFullScreen) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => scrollToBottom(),
);
}
}
}
} catch (_) {}

View File

@@ -37,7 +37,7 @@ class LiveRoomPage extends StatefulWidget {
}
class _LiveRoomPageState extends State<LiveRoomPage>
with WidgetsBindingObserver {
with WidgetsBindingObserver, RouteAware {
final String heroTag = Utils.generateRandomString(6);
late final LiveRoomController _liveRoomController;
late final PlPlayerController plPlayerController;
@@ -63,18 +63,64 @@ class _LiveRoomPageState extends State<LiveRoomPage>
..addStatusLister(playerListener);
}
void playerListener(PlayerStatus? status) {
if (status != PlayerStatus.playing) {
plPlayerController.danmakuController?.pause();
@override
void didChangeDependencies() {
super.didChangeDependencies();
PageUtils.routeObserver.subscribe(
this,
ModalRoute.of(context)! as PageRoute,
);
}
@override
Future<void> didPopNext() async {
WidgetsBinding.instance.addObserver(this);
PlPlayerController.setPlayCallBack(plPlayerController.play);
plPlayerController.danmakuController =
_liveRoomController.danmakuController;
_liveRoomController.startLiveTimer();
if (plPlayerController.playerStatus.playing) {
_liveRoomController
..cancelLiveTimer()
..msgStream?.close()
..msgStream = null;
..danmakuController?.resume()
..startLiveMsg();
} else {
plPlayerController.danmakuController?.resume();
final shouldPlay = _liveRoomController.isPlaying ?? false;
if (shouldPlay) {
_liveRoomController
..danmakuController?.resume()
..startLiveMsg();
}
await _liveRoomController.playerInit(autoplay: shouldPlay);
}
plPlayerController.addStatusLister(playerListener);
super.didPopNext();
}
@override
void didPushNext() {
WidgetsBinding.instance.removeObserver(this);
plPlayerController.removeStatusLister(playerListener);
_liveRoomController
..danmakuController?.clear()
..danmakuController?.pause()
..cancelLiveTimer()
..closeLiveMsg()
..isPlaying = plPlayerController.playerStatus.playing;
super.didPushNext();
}
void playerListener(PlayerStatus? status) {
if (status == PlayerStatus.playing) {
_liveRoomController
..danmakuController?.resume()
..startLiveTimer()
..liveMsg();
..startLiveMsg();
} else {
_liveRoomController
..danmakuController?.pause()
..cancelLiveTimer()
..closeLiveMsg();
}
}
@@ -87,6 +133,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
plPlayerController
..removeStatusLister(playerListener)
..dispose();
PageUtils.routeObserver.unsubscribe(this);
super.dispose();
}
@@ -150,6 +197,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
Alignment? alignment,
bool needDm = true,
}) {
_liveRoomController.isFullScreen = isFullScreen;
return PopScope(
canPop: !isFullScreen,
onPopInvokedWithResult: (bool didPop, Object? result) {
@@ -182,6 +230,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
danmuWidget: !needDm
? null
: LiveDanmaku(
liveRoomController: _liveRoomController,
plPlayerController: plPlayerController,
isFullScreen: isFullScreen,
isPipMode: isPipMode,
@@ -743,12 +792,14 @@ class _LiveRoomPageState extends State<LiveRoomPage>
}
class LiveDanmaku extends StatefulWidget {
final LiveRoomController liveRoomController;
final PlPlayerController plPlayerController;
final bool isPipMode;
final bool isFullScreen;
const LiveDanmaku({
super.key,
required this.liveRoomController,
required this.plPlayerController,
this.isPipMode = false,
required this.isFullScreen,
@@ -791,7 +842,8 @@ class _LiveDanmakuState extends State<LiveDanmaku> {
duration: const Duration(milliseconds: 100),
child: DanmakuScreen(
createdController: (DanmakuController e) {
plPlayerController.danmakuController = e;
widget.liveRoomController.danmakuController =
plPlayerController.danmakuController = e;
},
option: DanmakuOption(
fontSize: _fontSize,

View File

@@ -11,6 +11,7 @@ import 'package:PiliPlus/pages/mine/controller.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/context_ext.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
@@ -23,9 +24,6 @@ class MainApp extends StatefulWidget {
@override
State<MainApp> createState() => _MainAppState();
static final RouteObserver<PageRoute> routeObserver =
RouteObserver<PageRoute>();
}
class _MainAppState extends State<MainApp>
@@ -43,7 +41,10 @@ class _MainAppState extends State<MainApp>
super.didChangeDependencies();
NetworkImgLayer.reduce =
NetworkImgLayer.reduceLuxColor != null && context.isDarkMode;
MainApp.routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute);
PageUtils.routeObserver.subscribe(
this,
ModalRoute.of(context) as PageRoute,
);
}
@override
@@ -74,7 +75,7 @@ class _MainAppState extends State<MainApp>
@override
void dispose() {
MainApp.routeObserver.unsubscribe(this);
PageUtils.routeObserver.unsubscribe(this);
WidgetsBinding.instance.removeObserver(this);
GStorage.close();
PiliScheme.listener?.cancel();

View File

@@ -68,8 +68,6 @@ class VideoDetailPageV extends StatefulWidget {
@override
State<VideoDetailPageV> createState() => _VideoDetailPageVState();
static final RouteObserver<PageRoute> routeObserver =
RouteObserver<PageRoute>();
}
class _VideoDetailPageVState extends State<VideoDetailPageV>
@@ -381,7 +379,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
} else {
PlPlayerController.updatePlayCount();
}
VideoDetailPageV.routeObserver.unsubscribe(this);
PageUtils.routeObserver.unsubscribe(this);
showStatusBar();
_introScrollController?.dispose();
super.dispose();
@@ -476,7 +474,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
@override
void didChangeDependencies() {
super.didChangeDependencies();
VideoDetailPageV.routeObserver.subscribe(
PageUtils.routeObserver.subscribe(
this,
ModalRoute.of(context)! as PageRoute,
);

View File

@@ -507,14 +507,17 @@ class PlPlayerController {
// 获取实例 传参
static PlPlayerController getInstance({bool isLive = false}) {
// 如果实例尚未创建,则创建一个新实例
_instance ??= PlPlayerController._().._isLive = isLive;
_instance!._playerCount.value += 1;
_instance ??= PlPlayerController._();
_instance!
.._isLive = isLive
.._playerCount.value += 1;
return _instance!;
}
// 初始化资源
Future<void> setDataSource(
DataSource dataSource, {
bool isLive = false,
List<Segment>? segmentList,
List<Segment>? viewPointList,
bool? showVP,
@@ -542,6 +545,7 @@ class PlPlayerController {
VoidCallback? callback,
}) async {
try {
_isLive = isLive;
_videoType = videoType ?? VideoType.ugc;
this.width = width;
this.height = height;

View File

@@ -15,7 +15,6 @@ import 'package:PiliPlus/pages/contact/view.dart';
import 'package:PiliPlus/pages/fav_panel/view.dart';
import 'package:PiliPlus/pages/share/view.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/menu_row.dart';
import 'package:PiliPlus/plugin/pl_player/controller.dart';
import 'package:PiliPlus/services/shutdown_timer_service.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/context_ext.dart';
@@ -35,6 +34,9 @@ import 'package:get/get.dart' hide ContextExtensionss;
import 'package:url_launcher/url_launcher.dart';
class PageUtils {
static final RouteObserver<PageRoute> routeObserver =
RouteObserver<PageRoute>();
static Future<void> imageView({
int initialPage = 0,
required List<SourceModel> imgList,
@@ -690,10 +692,6 @@ class PageUtils {
if (roomId == null) {
return;
}
if (PlPlayerController.instanceExists()) {
SmartDialog.showToast('unsupported');
return;
}
if (off) {
Get.offNamed('/liveRoom', arguments: roomId);
} else {
@@ -716,10 +714,6 @@ class PageUtils {
int? id,
bool off = false,
}) {
if (PlPlayerController.instance?.isLive == true) {
SmartDialog.showToast('Living');
return;
}
final arguments = {
'aid': aid ?? IdUtils.bv2av(bvid!),
'bvid': bvid ?? IdUtils.av2bv(aid!),