feat: 直播弹幕2
This commit is contained in:
@ -2,8 +2,9 @@ import 'package:pilipala/http/danmaku.dart';
|
|||||||
import 'package:pilipala/models/danmaku/dm.pb.dart';
|
import 'package:pilipala/models/danmaku/dm.pb.dart';
|
||||||
|
|
||||||
class PlDanmakuController {
|
class PlDanmakuController {
|
||||||
PlDanmakuController(this.cid);
|
PlDanmakuController(this.cid, this.type);
|
||||||
final int cid;
|
final int cid;
|
||||||
|
final String type;
|
||||||
Map<int, List<DanmakuElem>> dmSegMap = {};
|
Map<int, List<DanmakuElem>> dmSegMap = {};
|
||||||
// 已请求的段落标记
|
// 已请求的段落标记
|
||||||
List<bool> requestedSeg = [];
|
List<bool> requestedSeg = [];
|
||||||
|
@ -12,11 +12,15 @@ import 'package:pilipala/utils/storage.dart';
|
|||||||
class PlDanmaku extends StatefulWidget {
|
class PlDanmaku extends StatefulWidget {
|
||||||
final int cid;
|
final int cid;
|
||||||
final PlPlayerController playerController;
|
final PlPlayerController playerController;
|
||||||
|
final String type;
|
||||||
|
final Function(DanmakuController)? createdController;
|
||||||
|
|
||||||
const PlDanmaku({
|
const PlDanmaku({
|
||||||
super.key,
|
super.key,
|
||||||
required this.cid,
|
required this.cid,
|
||||||
required this.playerController,
|
required this.playerController,
|
||||||
|
this.type = 'video',
|
||||||
|
this.createdController,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -43,9 +47,9 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
super.initState();
|
super.initState();
|
||||||
enableShowDanmaku =
|
enableShowDanmaku =
|
||||||
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
|
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
|
||||||
_plDanmakuController = PlDanmakuController(widget.cid);
|
_plDanmakuController = PlDanmakuController(widget.cid, widget.type);
|
||||||
if (mounted) {
|
playerController = widget.playerController;
|
||||||
playerController = widget.playerController;
|
if (mounted && widget.type == 'video') {
|
||||||
if (enableShowDanmaku || playerController.isOpenDanmu.value) {
|
if (enableShowDanmaku || playerController.isOpenDanmu.value) {
|
||||||
_plDanmakuController.initiate(
|
_plDanmakuController.initiate(
|
||||||
playerController.duration.value.inMilliseconds,
|
playerController.duration.value.inMilliseconds,
|
||||||
@ -55,13 +59,15 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
..addStatusLister(playerListener)
|
..addStatusLister(playerListener)
|
||||||
..addPositionListener(videoPositionListen);
|
..addPositionListener(videoPositionListen);
|
||||||
}
|
}
|
||||||
playerController.isOpenDanmu.listen((p0) {
|
if (widget.type == 'video') {
|
||||||
if (p0 && !_plDanmakuController.initiated) {
|
playerController.isOpenDanmu.listen((p0) {
|
||||||
_plDanmakuController.initiate(
|
if (p0 && !_plDanmakuController.initiated) {
|
||||||
playerController.duration.value.inMilliseconds,
|
_plDanmakuController.initiate(
|
||||||
playerController.position.value.inMilliseconds);
|
playerController.duration.value.inMilliseconds,
|
||||||
}
|
playerController.position.value.inMilliseconds);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
blockTypes = playerController.blockTypes;
|
blockTypes = playerController.blockTypes;
|
||||||
showArea = playerController.showArea;
|
showArea = playerController.showArea;
|
||||||
opacityVal = playerController.opacityVal;
|
opacityVal = playerController.opacityVal;
|
||||||
@ -128,6 +134,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
child: DanmakuView(
|
child: DanmakuView(
|
||||||
createdController: (DanmakuController e) async {
|
createdController: (DanmakuController e) async {
|
||||||
playerController.danmakuController = _controller = e;
|
playerController.danmakuController = _controller = e;
|
||||||
|
widget.createdController?.call(e);
|
||||||
},
|
},
|
||||||
option: DanmakuOption(
|
option: DanmakuOption(
|
||||||
fontSize: 15 * fontSizeVal,
|
fontSize: 15 * fontSizeVal,
|
||||||
@ -136,8 +143,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
hideTop: blockTypes.contains(5),
|
hideTop: blockTypes.contains(5),
|
||||||
hideScroll: blockTypes.contains(2),
|
hideScroll: blockTypes.contains(2),
|
||||||
hideBottom: blockTypes.contains(4),
|
hideBottom: blockTypes.contains(4),
|
||||||
duration:
|
duration: danmakuDurationVal / playerController.playbackSpeed,
|
||||||
danmakuDurationVal / playerController.playbackSpeed,
|
|
||||||
strokeWidth: strokeWidth,
|
strokeWidth: strokeWidth,
|
||||||
// initDuration /
|
// initDuration /
|
||||||
// (danmakuSpeedVal * widget.playerController.playbackSpeed),
|
// (danmakuSpeedVal * widget.playerController.playbackSpeed),
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:ui';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:ns_danmaku/ns_danmaku.dart';
|
||||||
import 'package:pilipala/http/constants.dart';
|
import 'package:pilipala/http/constants.dart';
|
||||||
import 'package:pilipala/http/init.dart';
|
import 'package:pilipala/http/init.dart';
|
||||||
import 'package:pilipala/http/live.dart';
|
import 'package:pilipala/http/live.dart';
|
||||||
@ -37,6 +39,7 @@ class LiveRoomController extends GetxController {
|
|||||||
String token = '';
|
String token = '';
|
||||||
// 弹幕消息列表
|
// 弹幕消息列表
|
||||||
RxList<LiveMessageModel> messageList = <LiveMessageModel>[].obs;
|
RxList<LiveMessageModel> messageList = <LiveMessageModel>[].obs;
|
||||||
|
DanmakuController? danmakuController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -172,9 +175,28 @@ class LiveRoomController extends GetxController {
|
|||||||
final List<LiveMessageModel>? liveMsg =
|
final List<LiveMessageModel>? liveMsg =
|
||||||
LiveUtils.decodeMessage(message);
|
LiveUtils.decodeMessage(message);
|
||||||
if (liveMsg != null) {
|
if (liveMsg != null) {
|
||||||
messageList.addAll(liveMsg
|
// 过滤出聊天消息
|
||||||
.where((msg) => msg.type == LiveMessageType.chat)
|
var chatMessages =
|
||||||
.toList());
|
liveMsg.where((msg) => msg.type == LiveMessageType.chat).toList();
|
||||||
|
|
||||||
|
// 添加到 messageList
|
||||||
|
messageList.addAll(chatMessages);
|
||||||
|
|
||||||
|
// 将 chatMessages 转换为 danmakuItems 列表
|
||||||
|
List<DanmakuItem> danmakuItems = chatMessages.map<DanmakuItem>((e) {
|
||||||
|
return DanmakuItem(
|
||||||
|
e.message ?? '',
|
||||||
|
color: Color.fromARGB(
|
||||||
|
255,
|
||||||
|
e.color.r,
|
||||||
|
e.color.g,
|
||||||
|
e.color.b,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
// 添加到 danmakuController
|
||||||
|
danmakuController?.addItems(danmakuItems);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onErrorCb: (e) {
|
onErrorCb: (e) {
|
||||||
|
@ -7,6 +7,7 @@ import 'package:flutter/rendering.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/models/live/message.dart';
|
import 'package:pilipala/models/live/message.dart';
|
||||||
|
import 'package:pilipala/pages/danmaku/index.dart';
|
||||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
|
|
||||||
import 'controller.dart';
|
import 'controller.dart';
|
||||||
@ -22,7 +23,7 @@ class LiveRoomPage extends StatefulWidget {
|
|||||||
class _LiveRoomPageState extends State<LiveRoomPage>
|
class _LiveRoomPageState extends State<LiveRoomPage>
|
||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
final LiveRoomController _liveRoomController = Get.put(LiveRoomController());
|
final LiveRoomController _liveRoomController = Get.put(LiveRoomController());
|
||||||
PlPlayerController? plPlayerController;
|
late PlPlayerController plPlayerController;
|
||||||
late Future? _futureBuilder;
|
late Future? _futureBuilder;
|
||||||
late Future? _futureBuilderFuture;
|
late Future? _futureBuilderFuture;
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
|||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
late AnimationController fabAnimationCtr;
|
late AnimationController fabAnimationCtr;
|
||||||
bool _shouldAutoScroll = true;
|
bool _shouldAutoScroll = true;
|
||||||
|
final int roomId = int.parse(Get.parameters['roomid']!);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -110,8 +112,9 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
|||||||
future: _futureBuilderFuture,
|
future: _futureBuilderFuture,
|
||||||
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
builder: (BuildContext context, AsyncSnapshot snapshot) {
|
||||||
if (snapshot.hasData && snapshot.data['status']) {
|
if (snapshot.hasData && snapshot.data['status']) {
|
||||||
|
plPlayerController = _liveRoomController.plPlayerController;
|
||||||
return PLVideoPlayer(
|
return PLVideoPlayer(
|
||||||
controller: plPlayerController!,
|
controller: plPlayerController,
|
||||||
bottomControl: BottomControl(
|
bottomControl: BottomControl(
|
||||||
controller: plPlayerController,
|
controller: plPlayerController,
|
||||||
liveRoomCtr: _liveRoomController,
|
liveRoomCtr: _liveRoomController,
|
||||||
@ -122,6 +125,14 @@ class _LiveRoomPageState extends State<LiveRoomPage>
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
danmuWidget: PlDanmaku(
|
||||||
|
cid: roomId,
|
||||||
|
playerController: plPlayerController,
|
||||||
|
type: 'live',
|
||||||
|
createdController: (e) {
|
||||||
|
_liveRoomController.danmakuController = e;
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
|
Reference in New Issue
Block a user