mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-23 18:46:53 +08:00
feat: danmaku api (#1530)
This commit is contained in:
committed by
GitHub
parent
88d207cc24
commit
e5f0742bf6
@@ -4,7 +4,7 @@ import 'package:flutter/material.dart';
|
|||||||
|
|
||||||
class CustomSliverPersistentHeaderDelegate
|
class CustomSliverPersistentHeaderDelegate
|
||||||
extends SliverPersistentHeaderDelegate {
|
extends SliverPersistentHeaderDelegate {
|
||||||
CustomSliverPersistentHeaderDelegate({
|
const CustomSliverPersistentHeaderDelegate({
|
||||||
required this.child,
|
required this.child,
|
||||||
required this.bgColor,
|
required this.bgColor,
|
||||||
double extent = 45,
|
double extent = 45,
|
||||||
|
|||||||
@@ -231,4 +231,34 @@ class ReportOptions {
|
|||||||
0: '其他',
|
0: '其他',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Map<String, Map<int, String>> get danmakuReport => const {
|
||||||
|
'': {
|
||||||
|
1: '违法违禁',
|
||||||
|
2: '色情低俗',
|
||||||
|
3: '赌博诈骗',
|
||||||
|
4: '人身攻击',
|
||||||
|
5: '侵犯隐私',
|
||||||
|
6: '垃圾广告',
|
||||||
|
7: '引战',
|
||||||
|
8: '剧透',
|
||||||
|
9: '恶意刷屏',
|
||||||
|
10: '视频无关',
|
||||||
|
12: '青少年不良信息',
|
||||||
|
13: '违法信息外链',
|
||||||
|
0: '其它', // 11
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static Map<String, Map<int, String>> get liveDanmakuReport => const {
|
||||||
|
'': {
|
||||||
|
1: '违法违规',
|
||||||
|
2: '低俗色情',
|
||||||
|
3: '垃圾广告',
|
||||||
|
4: '辱骂引战',
|
||||||
|
5: '政治敏感',
|
||||||
|
6: '青少年不良信息',
|
||||||
|
7: '其他 ', // avoid show form
|
||||||
|
},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -955,4 +955,15 @@ class Api {
|
|||||||
static const String popularPrecious = '/x/web-interface/popular/precious';
|
static const String popularPrecious = '/x/web-interface/popular/precious';
|
||||||
|
|
||||||
static const String userRealName = '/x/member/app/up/realname';
|
static const String userRealName = '/x/member/app/up/realname';
|
||||||
|
|
||||||
|
static const String liveDmReport =
|
||||||
|
'${HttpString.liveBaseUrl}/xlive/web-ucenter/v1/dMReport/Report';
|
||||||
|
|
||||||
|
static const String danmakuLike = '/x/v2/dm/thumbup/add';
|
||||||
|
|
||||||
|
static const String danmakuReport = '/x/dm/report/add';
|
||||||
|
|
||||||
|
static const String danmakuRecall = '/x/dm/recall';
|
||||||
|
|
||||||
|
static const String danmakuEditState = '/x/v2/dm/edit/state';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import 'package:PiliPlus/http/api.dart';
|
import 'package:PiliPlus/http/api.dart';
|
||||||
import 'package:PiliPlus/http/init.dart';
|
import 'package:PiliPlus/http/init.dart';
|
||||||
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/utils/accounts.dart';
|
import 'package:PiliPlus/utils/accounts.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
class DanmakuHttp {
|
abstract final class DanmakuHttp {
|
||||||
static Future shootDanmaku({
|
static Future shootDanmaku({
|
||||||
int type = 1, //弹幕类选择(1:视频弹幕 2:漫画弹幕)
|
int type = 1, //弹幕类选择(1:视频弹幕 2:漫画弹幕)
|
||||||
required int oid, // 视频cid
|
required int oid, // 视频cid
|
||||||
@@ -27,23 +28,23 @@ class DanmakuHttp {
|
|||||||
// assert(aid != null || bvid != null);
|
// assert(aid != null || bvid != null);
|
||||||
// assert(csrf != null || access_key != null);
|
// assert(csrf != null || access_key != null);
|
||||||
// 构建参数对象
|
// 构建参数对象
|
||||||
var data = <String, dynamic>{
|
var data = <String, Object>{
|
||||||
'type': type,
|
'type': type,
|
||||||
'oid': oid,
|
'oid': oid,
|
||||||
'msg': msg,
|
'msg': msg,
|
||||||
'mode': mode,
|
'mode': mode,
|
||||||
//'aid': aid,
|
//'aid': aid,
|
||||||
'bvid': bvid,
|
'bvid': bvid,
|
||||||
'progress': progress,
|
'progress': ?progress,
|
||||||
'color': colorful ? 16777215 : color,
|
'color': ?colorful ? 16777215 : color,
|
||||||
'fontsize': fontsize,
|
'fontsize': ?fontsize,
|
||||||
'pool': pool,
|
'pool': ?pool,
|
||||||
'rnd': DateTime.now().microsecondsSinceEpoch,
|
'rnd': DateTime.now().microsecondsSinceEpoch,
|
||||||
'colorful': colorful ? 60001 : null,
|
'colorful': ?colorful ? 60001 : null,
|
||||||
'checkbox_type': checkboxType,
|
'checkbox_type': ?checkboxType,
|
||||||
'csrf': Accounts.main.csrf,
|
'csrf': Accounts.main.csrf,
|
||||||
// 'access_key': access_key,
|
// 'access_key': access_key,
|
||||||
}..removeWhere((key, value) => value == null);
|
};
|
||||||
|
|
||||||
var response = await Request().post(
|
var response = await Request().post(
|
||||||
Api.shootDanmaku,
|
Api.shootDanmaku,
|
||||||
@@ -68,4 +69,132 @@ class DanmakuHttp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<Null>> danmakuLike({
|
||||||
|
required bool isLike,
|
||||||
|
required int cid,
|
||||||
|
required int id,
|
||||||
|
}) async {
|
||||||
|
final data = {
|
||||||
|
'op': isLike ? 2 : 1,
|
||||||
|
'dmid': id,
|
||||||
|
'oid': cid,
|
||||||
|
'platform': 'web_player',
|
||||||
|
'polaris_app_id': 100,
|
||||||
|
'polaris_platform': 5,
|
||||||
|
'spmid': '333.788.0.0',
|
||||||
|
'from_spmid': '333.788.0.0',
|
||||||
|
'statistics': '{"appId":100,"platform":5,"abtest":"","version":""}',
|
||||||
|
'csrf': Accounts.main.csrf,
|
||||||
|
};
|
||||||
|
final res = await Request().post(
|
||||||
|
Api.danmakuLike,
|
||||||
|
data: data,
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return const Success(null);
|
||||||
|
} else {
|
||||||
|
return Error(res.data['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<Map<String, dynamic>> danmakuReport({
|
||||||
|
required int reason,
|
||||||
|
required int cid,
|
||||||
|
required int id,
|
||||||
|
bool block = false,
|
||||||
|
String? content,
|
||||||
|
}) async {
|
||||||
|
final data = {
|
||||||
|
'cid': cid,
|
||||||
|
'dmid': id,
|
||||||
|
'reason': reason,
|
||||||
|
'block': block,
|
||||||
|
'originCid': cid,
|
||||||
|
'content': ?content,
|
||||||
|
'polaris_app_id': 100,
|
||||||
|
'polaris_platform': 5,
|
||||||
|
'spmid': '333.788.0.0',
|
||||||
|
'from_spmid': '333.788.0.0',
|
||||||
|
'statistics': '{"appId":100,"platform":5,"abtest":"","version":""}',
|
||||||
|
'csrf': Accounts.main.csrf,
|
||||||
|
};
|
||||||
|
final res = await Request().post(
|
||||||
|
Api.danmakuReport,
|
||||||
|
data: data,
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data']['block'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
|
||||||
|
/// {
|
||||||
|
/// 0: "举报已提交",
|
||||||
|
/// "-1": "举报失败,请先激活账号。",
|
||||||
|
/// "-2": "举报失败,系统拒绝受理您的举报请求。",
|
||||||
|
/// "-3": "举报失败,您已经被禁言。",
|
||||||
|
/// "-4": "您的操作过于频繁,请稍后再试。",
|
||||||
|
/// "-5": "您已经举报过这条弹幕了。",
|
||||||
|
/// "-6": "举报失败,系统错误。"
|
||||||
|
/// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<String?>> danmakuRecall({
|
||||||
|
required int cid,
|
||||||
|
required int id,
|
||||||
|
}) async {
|
||||||
|
final data = {
|
||||||
|
'dmid': id,
|
||||||
|
'cid': cid,
|
||||||
|
'type': 1,
|
||||||
|
'csrf': Accounts.main.csrf,
|
||||||
|
};
|
||||||
|
final res = await Request().post(
|
||||||
|
Api.danmakuRecall,
|
||||||
|
data: data,
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return Success(res.data['message']);
|
||||||
|
} else {
|
||||||
|
return Error(res.data['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<String?>> danmakuEditState({
|
||||||
|
required int oid,
|
||||||
|
required Iterable<int> ids,
|
||||||
|
required int state,
|
||||||
|
}) async {
|
||||||
|
/// 0: 取消删除
|
||||||
|
/// 1:删除弹幕
|
||||||
|
/// 2:弹幕保护
|
||||||
|
/// 3:取消保护
|
||||||
|
final data = {
|
||||||
|
'dmids': ids.join(','),
|
||||||
|
'oid': oid,
|
||||||
|
'state': state,
|
||||||
|
'type': 1,
|
||||||
|
'csrf': Accounts.main.csrf,
|
||||||
|
};
|
||||||
|
final res = await Request().post(
|
||||||
|
Api.danmakuRecall,
|
||||||
|
data: data,
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return Success(res.data['message']);
|
||||||
|
} else {
|
||||||
|
return Error(res.data['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -666,4 +666,41 @@ abstract final class LiveHttp {
|
|||||||
return Error(res.data['message']);
|
return Error(res.data['message']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<Null>> liveDmReport({
|
||||||
|
required Object roomId,
|
||||||
|
required int mid,
|
||||||
|
required String msg,
|
||||||
|
required String reason,
|
||||||
|
required int reasonId,
|
||||||
|
required String id,
|
||||||
|
}) async {
|
||||||
|
final csrf = Accounts.main.csrf;
|
||||||
|
final data = {
|
||||||
|
'id': 0,
|
||||||
|
'roomid': roomId,
|
||||||
|
'tuid': mid,
|
||||||
|
'msg': msg,
|
||||||
|
'reason': reason,
|
||||||
|
'sign': '',
|
||||||
|
'reason_id': reasonId,
|
||||||
|
'token': '',
|
||||||
|
'dm_type': '0',
|
||||||
|
'id_str': id,
|
||||||
|
'csrf_token': csrf,
|
||||||
|
'csrf': csrf,
|
||||||
|
'visit_id': '',
|
||||||
|
'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000,
|
||||||
|
};
|
||||||
|
final res = await Request().post(
|
||||||
|
Api.liveDmReport,
|
||||||
|
data: data,
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return const Success(null); // {"id": num}
|
||||||
|
} else {
|
||||||
|
return Error(res.data['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
27
lib/pages/danmaku/dnamaku_model.dart
Normal file
27
lib/pages/danmaku/dnamaku_model.dart
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
sealed class DanmakuExtra {
|
||||||
|
String get mid;
|
||||||
|
Object get id;
|
||||||
|
|
||||||
|
const DanmakuExtra();
|
||||||
|
}
|
||||||
|
|
||||||
|
class VideoDanmaku extends DanmakuExtra {
|
||||||
|
@override
|
||||||
|
final int id;
|
||||||
|
@override
|
||||||
|
final String mid;
|
||||||
|
|
||||||
|
bool isLike;
|
||||||
|
|
||||||
|
VideoDanmaku({required this.id, required this.mid, this.isLike = false});
|
||||||
|
}
|
||||||
|
|
||||||
|
class LiveDanmaku extends DanmakuExtra {
|
||||||
|
@override
|
||||||
|
final String id;
|
||||||
|
@override
|
||||||
|
final String mid;
|
||||||
|
final String uname;
|
||||||
|
|
||||||
|
const LiveDanmaku({required this.id, required this.mid, required this.uname});
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart';
|
import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart';
|
||||||
import 'package:PiliPlus/pages/danmaku/controller.dart';
|
import 'package:PiliPlus/pages/danmaku/controller.dart';
|
||||||
|
import 'package:PiliPlus/pages/danmaku/dnamaku_model.dart';
|
||||||
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
||||||
import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
|
import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
|
||||||
import 'package:PiliPlus/utils/danmaku_utils.dart';
|
import 'package:PiliPlus/utils/danmaku_utils.dart';
|
||||||
@@ -32,7 +33,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
PlPlayerController get playerController => widget.playerController;
|
PlPlayerController get playerController => widget.playerController;
|
||||||
|
|
||||||
late PlDanmakuController _plDanmakuController;
|
late PlDanmakuController _plDanmakuController;
|
||||||
DanmakuController? _controller;
|
DanmakuController<DanmakuExtra>? _controller;
|
||||||
int latestAddedPosition = -1;
|
int latestAddedPosition = -1;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -130,6 +131,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
e.colorful == DmColorfulType.VipGradualColor,
|
e.colorful == DmColorfulType.VipGradualColor,
|
||||||
count: e.hasCount() ? e.count : null,
|
count: e.hasCount() ? e.count : null,
|
||||||
selfSend: e.isSelf,
|
selfSend: e.isSelf,
|
||||||
|
extra: VideoDanmaku(id: e.id.toInt(), mid: e.midHash),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -154,8 +156,8 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
|||||||
? playerController.danmakuOpacity.value
|
? playerController.danmakuOpacity.value
|
||||||
: 0,
|
: 0,
|
||||||
duration: const Duration(milliseconds: 100),
|
duration: const Duration(milliseconds: 100),
|
||||||
child: DanmakuScreen(
|
child: DanmakuScreen<DanmakuExtra>(
|
||||||
createdController: (DanmakuController e) {
|
createdController: (e) {
|
||||||
playerController.danmakuController = _controller = e;
|
playerController.danmakuController = _controller = e;
|
||||||
},
|
},
|
||||||
option: DanmakuOption(
|
option: DanmakuOption(
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import 'package:PiliPlus/models_new/live/live_dm_info/data.dart';
|
|||||||
import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart';
|
import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart';
|
||||||
import 'package:PiliPlus/models_new/live/live_room_play_info/codec.dart';
|
import 'package:PiliPlus/models_new/live/live_room_play_info/codec.dart';
|
||||||
import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
|
import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
|
||||||
|
import 'package:PiliPlus/pages/danmaku/dnamaku_model.dart';
|
||||||
import 'package:PiliPlus/pages/live_room/send_danmaku/view.dart';
|
import 'package:PiliPlus/pages/live_room/send_danmaku/view.dart';
|
||||||
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
||||||
import 'package:PiliPlus/plugin/pl_player/models/data_source.dart';
|
import 'package:PiliPlus/plugin/pl_player/models/data_source.dart';
|
||||||
@@ -36,7 +37,7 @@ class LiveRoomController extends GetxController {
|
|||||||
final String heroTag;
|
final String heroTag;
|
||||||
|
|
||||||
int roomId = Get.arguments;
|
int roomId = Get.arguments;
|
||||||
DanmakuController? danmakuController;
|
DanmakuController<DanmakuExtra>? danmakuController;
|
||||||
PlPlayerController plPlayerController = PlPlayerController.getInstance(
|
PlPlayerController plPlayerController = PlPlayerController.getInstance(
|
||||||
isLive: true,
|
isLive: true,
|
||||||
);
|
);
|
||||||
@@ -340,7 +341,9 @@ class LiveRoomController extends GetxController {
|
|||||||
final info = obj['info'];
|
final info = obj['info'];
|
||||||
final first = info[0];
|
final first = info[0];
|
||||||
final content = first[15];
|
final content = first[15];
|
||||||
final extra = jsonDecode(content['extra']);
|
final Map<String, dynamic> extra = jsonDecode(
|
||||||
|
content['extra'],
|
||||||
|
);
|
||||||
final user = content['user'];
|
final user = content['user'];
|
||||||
final uid = user['uid'];
|
final uid = user['uid'];
|
||||||
BaseEmote? uemote;
|
BaseEmote? uemote;
|
||||||
@@ -368,6 +371,11 @@ class LiveRoomController extends GetxController {
|
|||||||
: DmUtils.decimalToColor(extra['color']),
|
: DmUtils.decimalToColor(extra['color']),
|
||||||
type: DmUtils.getPosition(extra['mode']),
|
type: DmUtils.getPosition(extra['mode']),
|
||||||
selfSend: extra['send_from_me'] ?? false,
|
selfSend: extra['send_from_me'] ?? false,
|
||||||
|
extra: LiveDanmaku(
|
||||||
|
id: extra['id_str'],
|
||||||
|
mid: uid,
|
||||||
|
uname: user['base']['name'],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (!disableAutoScroll.value) {
|
if (!disableAutoScroll.value) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
|||||||
import 'package:PiliPlus/models/common/image_type.dart';
|
import 'package:PiliPlus/models/common/image_type.dart';
|
||||||
import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart';
|
import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart';
|
||||||
import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
|
import 'package:PiliPlus/models_new/live/live_superchat/item.dart';
|
||||||
|
import 'package:PiliPlus/pages/danmaku/dnamaku_model.dart';
|
||||||
import 'package:PiliPlus/pages/live_room/controller.dart';
|
import 'package:PiliPlus/pages/live_room/controller.dart';
|
||||||
import 'package:PiliPlus/pages/live_room/superchat/superchat_card.dart';
|
import 'package:PiliPlus/pages/live_room/superchat/superchat_card.dart';
|
||||||
import 'package:PiliPlus/pages/live_room/superchat/superchat_panel.dart';
|
import 'package:PiliPlus/pages/live_room/superchat/superchat_panel.dart';
|
||||||
@@ -1039,8 +1040,8 @@ class _LiveDanmakuState extends State<LiveDanmaku> {
|
|||||||
? plPlayerController.danmakuOpacity.value
|
? plPlayerController.danmakuOpacity.value
|
||||||
: 0,
|
: 0,
|
||||||
duration: const Duration(milliseconds: 100),
|
duration: const Duration(milliseconds: 100),
|
||||||
child: DanmakuScreen(
|
child: DanmakuScreen<DanmakuExtra>(
|
||||||
createdController: (DanmakuController e) {
|
createdController: (e) {
|
||||||
widget.liveRoomController.danmakuController =
|
widget.liveRoomController.danmakuController =
|
||||||
plPlayerController.danmakuController = e;
|
plPlayerController.danmakuController = e;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import 'package:PiliPlus/http/danmaku.dart';
|
|||||||
import 'package:PiliPlus/main.dart';
|
import 'package:PiliPlus/main.dart';
|
||||||
import 'package:PiliPlus/models/common/publish_panel_type.dart';
|
import 'package:PiliPlus/models/common/publish_panel_type.dart';
|
||||||
import 'package:PiliPlus/pages/common/publish/common_text_pub_page.dart';
|
import 'package:PiliPlus/pages/common/publish/common_text_pub_page.dart';
|
||||||
|
import 'package:PiliPlus/pages/danmaku/dnamaku_model.dart';
|
||||||
import 'package:PiliPlus/pages/setting/slide_color_picker.dart';
|
import 'package:PiliPlus/pages/setting/slide_color_picker.dart';
|
||||||
|
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
||||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||||
import 'package:canvas_danmaku/models/danmaku_content_item.dart';
|
import 'package:canvas_danmaku/models/danmaku_content_item.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -20,7 +22,7 @@ class SendDanmakuPanel extends CommonTextPubPage {
|
|||||||
final dynamic bvid;
|
final dynamic bvid;
|
||||||
final dynamic progress;
|
final dynamic progress;
|
||||||
|
|
||||||
final ValueChanged<DanmakuContentItem> callback;
|
final ValueChanged<DanmakuContentItem<DanmakuExtra>> callback;
|
||||||
final bool darkVideoPage;
|
final bool darkVideoPage;
|
||||||
|
|
||||||
// config
|
// config
|
||||||
@@ -473,6 +475,10 @@ class _SendDanmakuPanelState extends CommonTextPubPageState<SendDanmakuPanel> {
|
|||||||
},
|
},
|
||||||
selfSend: true,
|
selfSend: true,
|
||||||
isColorful: isColorful,
|
isColorful: isColorful,
|
||||||
|
extra: VideoDanmaku(
|
||||||
|
id: res['dmid'],
|
||||||
|
mid: PlPlayerController.instance!.midHash,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
||||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||||
|
import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart';
|
||||||
|
import 'package:PiliPlus/common/widgets/dialog/report.dart';
|
||||||
import 'package:PiliPlus/common/widgets/marquee.dart';
|
import 'package:PiliPlus/common/widgets/marquee.dart';
|
||||||
|
import 'package:PiliPlus/http/danmaku.dart';
|
||||||
|
import 'package:PiliPlus/http/danmaku_block.dart';
|
||||||
import 'package:PiliPlus/models/common/super_resolution_type.dart';
|
import 'package:PiliPlus/models/common/super_resolution_type.dart';
|
||||||
import 'package:PiliPlus/models/common/video/audio_quality.dart';
|
import 'package:PiliPlus/models/common/video/audio_quality.dart';
|
||||||
import 'package:PiliPlus/models/common/video/cdn_type.dart';
|
import 'package:PiliPlus/models/common/video/cdn_type.dart';
|
||||||
@@ -13,6 +17,7 @@ import 'package:PiliPlus/models/common/video/video_decode_type.dart';
|
|||||||
import 'package:PiliPlus/models/common/video/video_quality.dart';
|
import 'package:PiliPlus/models/common/video/video_quality.dart';
|
||||||
import 'package:PiliPlus/models/video/play/url.dart';
|
import 'package:PiliPlus/models/video/play/url.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_intro_controller.dart';
|
import 'package:PiliPlus/pages/common/common_intro_controller.dart';
|
||||||
|
import 'package:PiliPlus/pages/danmaku/dnamaku_model.dart';
|
||||||
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
||||||
import 'package:PiliPlus/pages/setting/widgets/switch_item.dart';
|
import 'package:PiliPlus/pages/setting/widgets/switch_item.dart';
|
||||||
import 'package:PiliPlus/pages/video/controller.dart';
|
import 'package:PiliPlus/pages/video/controller.dart';
|
||||||
@@ -407,6 +412,15 @@ class HeaderControlState extends State<HeaderControl> {
|
|||||||
style: subTitleStyle,
|
style: subTitleStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
showDanmakuPool();
|
||||||
|
},
|
||||||
|
leading: const Icon(CustomIcons.dm_on, size: 20),
|
||||||
|
title: const Text('弹幕列表', style: titleStyle),
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -1337,7 +1351,7 @@ class HeaderControlState extends State<HeaderControl> {
|
|||||||
int danmakuFontWeight = plPlayerController.danmakuFontWeight;
|
int danmakuFontWeight = plPlayerController.danmakuFontWeight;
|
||||||
bool massiveMode = plPlayerController.massiveMode;
|
bool massiveMode = plPlayerController.massiveMode;
|
||||||
|
|
||||||
final DanmakuController? danmakuController =
|
final DanmakuController<DanmakuExtra>? danmakuController =
|
||||||
plPlayerController.danmakuController;
|
plPlayerController.danmakuController;
|
||||||
|
|
||||||
showBottomSheet(
|
showBottomSheet(
|
||||||
@@ -1843,6 +1857,146 @@ class HeaderControlState extends State<HeaderControl> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showDanmakuPool() {
|
||||||
|
final ctr = plPlayerController.danmakuController;
|
||||||
|
if (ctr == null) return;
|
||||||
|
showBottomSheet((context, setState) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Material(
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
color: theme.colorScheme.surface,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||||
|
child: CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverPersistentHeader(
|
||||||
|
pinned: true,
|
||||||
|
delegate: CustomSliverPersistentHeaderDelegate(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(6),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
const Text('弹幕列表'),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => setState(() {}),
|
||||||
|
icon: const Icon(Icons.refresh),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
bgColor: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
?_buildDanmakuList(ctr.staticDanmaku),
|
||||||
|
?_buildDanmakuList(ctr.scrollDanmaku),
|
||||||
|
?_buildDanmakuList(ctr.specialDanmaku),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget? _buildDanmakuList(List<DanmakuItem<DanmakuExtra>> list) {
|
||||||
|
if (list.isEmpty) return null;
|
||||||
|
list = List.of(list);
|
||||||
|
|
||||||
|
return SliverList.builder(
|
||||||
|
itemCount: list.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
final item = list[index];
|
||||||
|
final extra = item.content.extra! as VideoDanmaku;
|
||||||
|
return ListTile(
|
||||||
|
onLongPress: () => Utils.copyText(item.content.text),
|
||||||
|
subtitle: Text(item.content.text),
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Builder(
|
||||||
|
builder: (context) => IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (!Accounts.main.isLogin) {
|
||||||
|
SmartDialog.showToast('请先登录');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final res = await DanmakuHttp.danmakuLike(
|
||||||
|
isLike: extra.isLike,
|
||||||
|
cid: plPlayerController.cid!,
|
||||||
|
id: extra.id,
|
||||||
|
);
|
||||||
|
if (res.isSuccess) {
|
||||||
|
extra.isLike = !extra.isLike;
|
||||||
|
if (context.mounted) {
|
||||||
|
(context as Element).markNeedsBuild();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.toast();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: extra.isLike
|
||||||
|
? const Icon(Icons.thumb_up)
|
||||||
|
: const Icon(Icons.thumb_up_outlined),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (item.content.selfSend)
|
||||||
|
IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final res = await DanmakuHttp.danmakuRecall(
|
||||||
|
cid: plPlayerController.cid!,
|
||||||
|
id: extra.id,
|
||||||
|
);
|
||||||
|
if (res.isSuccess) {
|
||||||
|
SmartDialog.showToast('删除成功');
|
||||||
|
} else {
|
||||||
|
res.toast();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.delete_outline),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
autoWrapReportDialog(
|
||||||
|
context,
|
||||||
|
ReportOptions.danmakuReport,
|
||||||
|
(reasonType, reasonDesc, banUid) {
|
||||||
|
if (banUid) {
|
||||||
|
final filter = plPlayerController.filters;
|
||||||
|
if (filter.dmUid.add(extra.mid)) {
|
||||||
|
filter.count++;
|
||||||
|
GStorage.localCache.put(
|
||||||
|
LocalCacheKey.danmakuFilterRules,
|
||||||
|
filter,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
DanmakuFilterHttp.danmakuFilterAdd(
|
||||||
|
filter: extra.mid,
|
||||||
|
type: 2,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return DanmakuHttp.danmakuReport(
|
||||||
|
reason: reasonType == 0 ? 11 : reasonType,
|
||||||
|
cid: plPlayerController.cid!,
|
||||||
|
id: extra.id,
|
||||||
|
content: reasonDesc,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.report_problem_outlined),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// 播放顺序
|
/// 播放顺序
|
||||||
void showSetRepeat() {
|
void showSetRepeat() {
|
||||||
showBottomSheet(
|
showBottomSheet(
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import 'package:PiliPlus/models/common/video/video_type.dart';
|
|||||||
import 'package:PiliPlus/models/user/danmaku_rule.dart';
|
import 'package:PiliPlus/models/user/danmaku_rule.dart';
|
||||||
import 'package:PiliPlus/models/video/play/url.dart';
|
import 'package:PiliPlus/models/video/play/url.dart';
|
||||||
import 'package:PiliPlus/models_new/video/video_shot/data.dart';
|
import 'package:PiliPlus/models_new/video/video_shot/data.dart';
|
||||||
|
import 'package:PiliPlus/pages/danmaku/dnamaku_model.dart';
|
||||||
import 'package:PiliPlus/pages/mine/controller.dart';
|
import 'package:PiliPlus/pages/mine/controller.dart';
|
||||||
import 'package:PiliPlus/plugin/pl_player/models/bottom_progress_behavior.dart';
|
import 'package:PiliPlus/plugin/pl_player/models/bottom_progress_behavior.dart';
|
||||||
import 'package:PiliPlus/plugin/pl_player/models/data_source.dart';
|
import 'package:PiliPlus/plugin/pl_player/models/data_source.dart';
|
||||||
@@ -326,7 +327,7 @@ class PlPlayerController {
|
|||||||
late int danmakuWeight = Pref.danmakuWeight;
|
late int danmakuWeight = Pref.danmakuWeight;
|
||||||
late RuleFilter filters = Pref.danmakuFilterRule;
|
late RuleFilter filters = Pref.danmakuFilterRule;
|
||||||
// 关联弹幕控制器
|
// 关联弹幕控制器
|
||||||
DanmakuController? danmakuController;
|
DanmakuController<DanmakuExtra>? danmakuController;
|
||||||
bool showDanmaku = true;
|
bool showDanmaku = true;
|
||||||
Set<int> dmState = <int>{};
|
Set<int> dmState = <int>{};
|
||||||
late final mergeDanmaku = Pref.mergeDanmaku;
|
late final mergeDanmaku = Pref.mergeDanmaku;
|
||||||
|
|||||||
Reference in New Issue
Block a user