opt: live danmaku

This commit is contained in:
bggRGjQaUbCoE
2024-11-04 14:07:58 +08:00
parent 2190336638
commit e2708e7728
8 changed files with 156 additions and 80 deletions

View File

@@ -3,6 +3,7 @@ import 'package:PiliPalaX/http/constants.dart';
import 'package:PiliPalaX/http/live.dart';
import 'package:PiliPalaX/models/live/room_info.dart';
import 'package:PiliPalaX/plugin/pl_player/index.dart';
import 'package:ns_danmaku/danmaku_controller.dart';
import '../../models/live/room_info_h5.dart';
import '../../utils/video_utils.dart';
@@ -21,6 +22,8 @@ class LiveRoomController extends GetxController {
RxList<dynamic> messages = [].obs;
RxBool disableAutoScroll = false.obs;
double? brightness;
DanmakuController? controller;
@override
void onInit() {

View File

@@ -9,6 +9,10 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/common/widgets/network_img_layer.dart';
import 'package:PiliPalaX/plugin/pl_player/index.dart';
import 'package:ns_danmaku/danmaku_controller.dart';
import 'package:ns_danmaku/danmaku_view.dart';
import 'package:ns_danmaku/models/danmaku_option.dart';
import 'package:screen_brightness/screen_brightness.dart';
import '../../utils/storage.dart';
import 'controller.dart';
@@ -24,7 +28,7 @@ class LiveRoomPage extends StatefulWidget {
class _LiveRoomPageState extends State<LiveRoomPage> {
late final int _roomId;
final LiveRoomController _liveRoomController = Get.put(LiveRoomController());
PlPlayerController? plPlayerController;
late final PlPlayerController plPlayerController;
late Future? _futureBuilder;
late Future? _futureBuilderFuture;
@@ -36,8 +40,18 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
late final _node = FocusNode();
late final _ctr = TextEditingController();
late bool enableShowDanmaku;
late List blockTypes;
late double showArea;
late double opacityVal;
late double fontSizeVal;
late double danmakuDurationVal;
late double strokeWidth;
late int fontWeight;
int latestAddedPosition = -1;
void playCallBack() {
plPlayerController?.play();
plPlayerController.play();
}
@override
@@ -50,20 +64,28 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
}
videoSourceInit();
_futureBuilderFuture = _liveRoomController.queryLiveInfo();
plPlayerController!.autoEnterFullscreen();
plPlayerController.autoEnterFullscreen();
}
Future<void> videoSourceInit() async {
_futureBuilder = _liveRoomController.queryLiveInfoH5();
plPlayerController = _liveRoomController.plPlayerController;
blockTypes = plPlayerController.blockTypes;
showArea = plPlayerController.showArea;
opacityVal = plPlayerController.opacityVal;
fontSizeVal = plPlayerController.fontSizeVal;
strokeWidth = plPlayerController.strokeWidth;
fontWeight = plPlayerController.fontWeight;
danmakuDurationVal = plPlayerController.danmakuDurationVal;
}
@override
void dispose() {
ScreenBrightness().resetApplicationScreenBrightness();
PlPlayerController.setPlayCallBack(null);
floating?.dispose();
_node.dispose();
plPlayerController?.dispose();
plPlayerController.dispose();
_ctr.dispose();
super.dispose();
}
@@ -75,12 +97,39 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData && snapshot.data['status']) {
return PLVideoPlayer(
controller: plPlayerController!,
controller: plPlayerController,
bottomControl: BottomControl(
controller: plPlayerController,
liveRoomCtr: _liveRoomController,
floating: floating,
),
danmuWidget: Obx(
() => AnimatedOpacity(
opacity: plPlayerController.isOpenDanmu.value ? 1 : 0,
duration: const Duration(milliseconds: 100),
child: DanmakuView(
createdController: (DanmakuController e) async {
plPlayerController.danmakuController =
_liveRoomController.controller = e;
},
option: DanmakuOption(
fontSize: 15 * fontSizeVal,
fontWeight: fontWeight,
area: showArea,
opacity: opacityVal,
hideTop: blockTypes.contains(5),
hideScroll: blockTypes.contains(2),
hideBottom: blockTypes.contains(4),
duration:
danmakuDurationVal / plPlayerController.playbackSpeed,
strokeWidth: strokeWidth,
// initDuration /
// (danmakuSpeedVal * widget.playerController.playbackSpeed),
),
statusChanged: (isPlaying) {},
),
),
),
);
} else {
return const SizedBox();
@@ -236,10 +285,10 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
),
),
PopScope(
canPop: plPlayerController?.isFullScreen.value != true,
canPop: plPlayerController.isFullScreen.value != true,
onPopInvokedWithResult: (bool didPop, Object? result) {
if (plPlayerController?.isFullScreen.value == true) {
plPlayerController!.triggerFullScreen(status: false);
if (plPlayerController.isFullScreen.value == true) {
plPlayerController.triggerFullScreen(status: false);
}
if (MediaQuery.of(context).orientation ==
Orientation.landscape) {
@@ -273,9 +322,9 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
),
Container(
padding: EdgeInsets.only(
left: 16,
left: 10,
top: 10,
right: 16,
right: 10,
bottom: 25 + MediaQuery.of(context).padding.bottom,
),
decoration: BoxDecoration(
@@ -290,6 +339,21 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
),
child: Row(
children: [
Obx(
() => IconButton(
onPressed: () {
plPlayerController.isOpenDanmu.value =
!plPlayerController.isOpenDanmu.value;
GStorage.setting.put(SettingBoxKey.enableShowDanmaku,
plPlayerController.isOpenDanmu.value);
},
icon: Icon(
plPlayerController.isOpenDanmu.value
? Icons.subtitles_outlined
: Icons.subtitles_off_outlined,
),
),
),
Expanded(
child: TextField(
focusNode: _node,

View File

@@ -6,12 +6,13 @@ import 'package:PiliPalaX/models/live/danmu_info.dart';
import 'package:PiliPalaX/pages/live_room/controller.dart';
import 'package:PiliPalaX/services/loggeer.dart';
import 'package:PiliPalaX/tcp/live.dart';
import 'package:PiliPalaX/utils/danmaku.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:ns_danmaku/models/danmaku_item.dart';
import '../../../utils/storage.dart';
@@ -50,56 +51,58 @@ class _LiveRoomChatState extends State<LiveRoomChat> {
Widget build(BuildContext context) {
return Stack(
children: [
ListView.separated(
controller: _scrollController,
separatorBuilder: (_, index) => const SizedBox(height: 6),
itemCount: widget.liveRoomController.messages.length,
itemBuilder: (context, index) {
return Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: const BoxDecoration(
color: Color(0x15FFFFFF),
borderRadius: BorderRadius.all(Radius.circular(18)),
),
child: Text.rich(
TextSpan(
children: [
TextSpan(
text:
'${widget.liveRoomController.messages[index]['info'][0][15]['user']['base']['name']}: ',
style: const TextStyle(
color: Color(0xFFAAAAAA),
fontSize: 14,
Obx(
() => ListView.separated(
controller: _scrollController,
separatorBuilder: (_, index) => const SizedBox(height: 6),
itemCount: widget.liveRoomController.messages.length,
itemBuilder: (context, index) {
return Container(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: const BoxDecoration(
color: Color(0x15FFFFFF),
borderRadius: BorderRadius.all(Radius.circular(18)),
),
child: Text.rich(
TextSpan(
children: [
TextSpan(
text:
'${widget.liveRoomController.messages[index]['info'][0][15]['user']['base']['name']}: ',
style: const TextStyle(
color: Color(0xFFAAAAAA),
fontSize: 14,
),
recognizer: TapGestureRecognizer()
..onTap = () {
try {
dynamic uid =
widget.liveRoomController.messages[index]
['info'][0][15]['user']['uid'];
Get.toNamed(
'/member?mid=$uid',
arguments: {
'heroTag': Utils.makeHeroTag(uid),
},
);
} catch (err) {
print(err.toString());
// SmartDialog.showToast(err.toString());
}
},
),
recognizer: TapGestureRecognizer()
..onTap = () {
try {
dynamic uid =
widget.liveRoomController.messages[index]
['info'][0][15]['user']['uid'];
Get.toNamed(
'/member?mid=$uid',
arguments: {
'heroTag': Utils.makeHeroTag(uid),
},
);
} catch (err) {
print(err.toString());
// SmartDialog.showToast(err.toString());
}
},
),
_buildMsg(widget.liveRoomController.messages[index]),
],
_buildMsg(widget.liveRoomController.messages[index]),
],
),
),
),
),
);
},
);
},
),
),
Obx(
() => widget.liveRoomController.disableAutoScroll.value
@@ -138,12 +141,19 @@ class _LiveRoomChatState extends State<LiveRoomChat> {
msgStream?.addEventListener((obj) {
if (obj['cmd'] == 'DANMU_MSG') {
// logger.i(' 原始弹幕消息 ======> ${jsonEncode(obj)}');
setState(() {
widget.liveRoomController.messages.add(obj);
WidgetsBinding.instance.addPostFrameCallback(
(_) => _scrollToBottom(),
);
});
widget.liveRoomController.messages.add(obj);
Map json = jsonDecode(obj['info'][0][15]['extra']);
widget.liveRoomController.controller?.addItems([
DanmakuItem(
json['content'],
color: DmUtils.decimalToColor(json['color']),
// time: e.progress,
type: DmUtils.getPosition(json['mode']),
)
]);
WidgetsBinding.instance.addPostFrameCallback(
(_) => _scrollToBottom(),
);
}
});
msgStream?.init();

View File

@@ -115,16 +115,15 @@ class VideoReplyReplyController extends CommonController
begin: Theme.of(Get.context!).colorScheme.onInverseSurface,
end: Theme.of(Get.context!).colorScheme.surface,
).animate(controller!);
() async {
await Future.delayed(const Duration(milliseconds: 200));
WidgetsBinding.instance.addPostFrameCallback((_) async {
itemScrollCtr.jumpTo(
index: hasRoot ? index! + 3 : index! + 1, alignment: 0.25,
// duration: const Duration(milliseconds: 200),
index: hasRoot ? index! + 3 : index! + 1,
alignment: 0.25,
);
await Future.delayed(const Duration(milliseconds: 800));
await controller?.forward();
index = null;
}();
});
}
id = null;
}

View File

@@ -276,7 +276,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
@override
void dispose() {
if (!Get.previousRoute.startsWith('/video')) {
ScreenBrightness().resetScreenBrightness();
ScreenBrightness().resetApplicationScreenBrightness();
PlPlayerController.setPlayCallBack(null);
}
videoDetailController.positionSubscription?.cancel();
@@ -310,7 +310,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
void didPushNext() async {
// _bufferedListener?.cancel();
ScreenBrightness().resetScreenBrightness();
ScreenBrightness().resetApplicationScreenBrightness();
videoDetailController.positionSubscription?.cancel();
videoIntroController.canelTimer();
@@ -344,13 +344,13 @@ class _VideoDetailPageState extends State<VideoDetailPage>
plPlayerController
?.setCurrBrightness(videoDetailController.brightness!);
if (videoDetailController.brightness != -1.0) {
ScreenBrightness()
.setScreenBrightness(videoDetailController.brightness!);
ScreenBrightness().setApplicationScreenBrightness(
videoDetailController.brightness!);
} else {
ScreenBrightness().resetScreenBrightness();
ScreenBrightness().resetApplicationScreenBrightness();
}
} else {
ScreenBrightness().resetScreenBrightness();
ScreenBrightness().resetApplicationScreenBrightness();
}
}
super.didPopNext();

View File

@@ -1035,7 +1035,7 @@ class PlPlayerController {
Future<void> setBrightness(double brightness) async {
try {
this.brightness.value = brightness;
ScreenBrightness().setScreenBrightness(brightness);
ScreenBrightness().setApplicationScreenBrightness(brightness);
// setVideoBrightness();
} catch (e) {
throw 'Failed to set brightness';

View File

@@ -205,7 +205,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
Future<void> setBrightness(double value) async {
try {
await ScreenBrightness().setScreenBrightness(value);
await ScreenBrightness().setApplicationScreenBrightness(value);
} catch (_) {}
_brightnessIndicator.value = true;
_brightnessTimer?.cancel();

View File

@@ -216,13 +216,13 @@ class LiveMessageStream {
}
_processingData(decompressedData);
} catch (e) {
logger.w(e);
logger.i(e);
}
}
}
socket.close();
} catch (e) {
logger.e('$logTag ===> TCP连接失败: $e');
logger.i('$logTag ===> TCP连接失败: $e');
}
}
@@ -241,7 +241,7 @@ class LiveMessageStream {
}
}
} catch (e) {
logger.e('ParseHeader错误: $e');
logger.i('ParseHeader错误: $e');
}
}