Merge branch 'main' into design

This commit is contained in:
guozhigq
2024-11-26 00:02:44 +08:00
20 changed files with 496 additions and 98 deletions

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart';
@ -98,7 +99,8 @@ class _PagesBottomSheetState extends State<PagesBottomSheet>
with TickerProviderStateMixin {
final ScrollController _listScrollController = ScrollController();
late ListObserverController _listObserverController;
final ScrollController _scrollController = ScrollController();
late GridObserverController _gridObserverController;
final ScrollController _gridScrollController = ScrollController();
late int currentIndex;
TabController? tabController;
List<ListObserverController>? _listObserverControllerList;
@ -163,6 +165,9 @@ class _PagesBottomSheetState extends State<PagesBottomSheet>
);
},
);
} else {
_gridObserverController =
GridObserverController(controller: _gridScrollController);
}
}
@ -185,18 +190,12 @@ class _PagesBottomSheetState extends State<PagesBottomSheet>
);
}
}
} else {
_gridObserverController.initialIndexModel = ObserverIndexPositionModel(
index: currentIndex,
isFixedHeight: false,
);
}
WidgetsBinding.instance.addPostFrameCallback((_) {
if (widget.dataType != VideoEpidoesType.videoEpisode) {
double itemHeight = (widget.isFullScreen
? 400
: Get.size.width - 3 * StyleString.safeSpace) /
5.2;
double offset = ((currentIndex - 1) / 2).ceil() * itemHeight;
_scrollController.jumpTo(offset);
}
});
}
// 获取订阅状态
@ -236,7 +235,9 @@ class _PagesBottomSheetState extends State<PagesBottomSheet>
void dispose() {
try {
_listObserverController.controller?.dispose();
_gridObserverController.controller?.dispose();
_listScrollController.dispose();
_gridScrollController.dispose();
for (var element in _listObserverControllerList!) {
element.controller?.dispose();
}
@ -303,24 +304,27 @@ class _PagesBottomSheetState extends State<PagesBottomSheet>
: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12.0), // 设置左右间距为12
child: GridView.count(
controller: _scrollController,
crossAxisCount: 2,
crossAxisSpacing: StyleString.safeSpace,
childAspectRatio: 2.6,
children: List.generate(
widget.episodes.length,
(index) {
bool isCurrentIndex = currentIndex == index;
return EpisodeGridItem(
episode: widget.episodes[index],
index: index,
isCurrentIndex: isCurrentIndex,
dataType: widget.dataType,
changeFucCall: widget.changeFucCall,
isFullScreen: widget.isFullScreen,
);
},
child: GridViewObserver(
controller: _gridObserverController,
child: GridView.count(
controller: _gridScrollController,
crossAxisCount: 2,
crossAxisSpacing: StyleString.safeSpace,
childAspectRatio: 2.6,
children: List.generate(
widget.episodes.length,
(index) {
bool isCurrentIndex = currentIndex == index;
return EpisodeGridItem(
episode: widget.episodes[index],
index: index,
isCurrentIndex: isCurrentIndex,
dataType: widget.dataType,
changeFucCall: widget.changeFucCall,
isFullScreen: widget.isFullScreen,
);
},
),
),
),
),

View File

@ -622,4 +622,8 @@ class Api {
/// 视频标签
static const String videoTag = '/x/tag/archive/tags';
/// 修复标题和海报
// /api/view?id=${aid} /all/video/av${aid} /video/av${aid}/
static const String fixTitleAndPic = '${HttpString.biliplusBaseUrl}/api/view';
}

View File

@ -1,3 +1,4 @@
import 'package:pilipala/models/common/invalid_video.dart';
import 'dart:convert';
import 'dart:math';
import 'package:dio/dio.dart';
@ -50,6 +51,32 @@ class CommonHttp {
}
}
static Future fixVideoPicAndTitle({required int aid}) async {
var res = await Request().getWithoutCookie(Api.fixTitleAndPic, data: {
'id': aid,
});
if (res != null) {
if (res.data['code'] == -404) {
return {
'status': false,
'data': null,
'msg': '没有相关信息',
};
} else {
return {
'status': true,
'data': InvalidVideoModel.fromJson(res.data),
};
}
} else {
return {
'status': false,
'data': null,
'msg': '没有相关信息',
};
}
}
static Future buvidActivate() async {
try {
// 获取 HTML 数据

View File

@ -8,6 +8,8 @@ class HttpString {
static const String messageBaseUrl = 'https://message.bilibili.com';
static const String bangumiBaseUrl = 'https://bili.meark.me';
static const String sponsorBlockBaseUrl = 'https://www.bsbsb.top';
static const String biliplusBaseUrl = 'https://www.biliplus.com';
static const List<int> validateStatusCodes = [
302,
304,

View File

@ -68,7 +68,7 @@ class Request {
// 从cookie中获取 csrf token
static Future<String> getCsrf() async {
List<Cookie> cookies = await cookieManager.cookieJar
.loadForRequest(Uri.parse(HttpString.apiBaseUrl));
.loadForRequest(Uri.parse(HttpString.baseUrl));
String token = '';
if (cookies.where((e) => e.name == 'bili_jct').isNotEmpty) {
token = cookies.firstWhere((e) => e.name == 'bili_jct').value;
@ -82,9 +82,12 @@ class Request {
}
final List<Cookie> cookies = await cookieManager.cookieJar
.loadForRequest(Uri.parse(HttpString.baseUrl));
buvid = cookies.firstWhere((cookie) => cookie.name == 'buvid3').value;
if (buvid == null) {
.loadForRequest(Uri.parse(HttpString.apiBaseUrl));
buvid = cookies
.firstWhere((cookie) => cookie.name == 'buvid3',
orElse: () => Cookie('buvid3', ''))
.value;
if (buvid == null || buvid!.isEmpty) {
try {
var result = await Request().get(
"${HttpString.apiBaseUrl}/x/frontend/finger/spi",

View File

@ -0,0 +1,18 @@
enum CommentRangeType {
video,
bangumi,
// dynamic,
}
extension ActionTypeExtension on CommentRangeType {
String get value => [
'video',
'bangumi',
// 'dynamic',
][index];
String get label => [
'视频',
'番剧',
// '动态',
][index];
}

View File

@ -0,0 +1,73 @@
class InvalidVideoModel {
final int? id;
final int? ver;
final int? aid;
final String? lastupdate;
final int? lastupdatets;
final String? title;
final String? description;
final String? pic;
final int? tid;
final String? typename;
final int? created;
final String? createdAt;
final String? author;
final int? mid;
final String? play;
final String? coins;
final String? review;
final String? videoReview;
final String? favorites;
final String? tag;
final List<String>? tagList;
InvalidVideoModel({
this.id,
this.ver,
this.aid,
this.lastupdate,
this.lastupdatets,
this.title,
this.description,
this.pic,
this.tid,
this.typename,
this.created,
this.createdAt,
this.author,
this.mid,
this.play,
this.coins,
this.review,
this.videoReview,
this.favorites,
this.tag,
this.tagList,
});
factory InvalidVideoModel.fromJson(Map<String, dynamic> json) {
return InvalidVideoModel(
id: json['id'],
ver: json['ver'],
aid: json['aid'],
lastupdate: json['lastupdate'],
lastupdatets: json['lastupdatets'],
title: json['title'],
description: json['description'],
pic: json['pic'],
tid: json['tid'],
typename: json['typename'],
created: json['created'],
createdAt: json['created_at'],
author: json['author'],
mid: json['mid'],
play: json['play'],
coins: json['coins'],
review: json['review'],
videoReview: json['video_review'],
favorites: json['favorites'],
tag: json['tag'],
tagList: json['tag'].toString().split(',').toList(),
);
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:pilipala/http/common.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/user/fav_detail.dart';
@ -8,6 +9,8 @@ import 'package:pilipala/models/user/fav_folder.dart';
import 'package:pilipala/pages/fav/index.dart';
import 'package:pilipala/utils/utils.dart';
import 'widget/invalid_video_card.dart';
class FavDetailController extends GetxController {
FavFolderItemData? item;
RxString title = ''.obs;
@ -152,4 +155,22 @@ class FavDetailController extends GetxController {
},
);
}
// 查看无效视频信息
Future toViewInvalidVideo(FavDetailItemData item) async {
SmartDialog.showLoading(msg: '加载中...');
var res = await CommonHttp.fixVideoPicAndTitle(aid: item.id!);
SmartDialog.dismiss();
if (res['status']) {
showModalBottomSheet(
context: Get.context!,
isScrollControlled: true,
builder: (context) {
return InvalidVideoCard(videoInfo: res['data']);
},
);
} else {
SmartDialog.showToast(res['msg']);
}
}
}

View File

@ -226,6 +226,8 @@ class _FavDetailPageState extends State<FavDetailPage> {
isOwner: _favDetailController.isOwner,
callFn: () => _favDetailController
.onCancelFav(favList[index].id),
viewInvalidVideoCb: () => _favDetailController
.toViewInvalidVideo(favList[index]),
);
}, childCount: favList.length),
),

View File

@ -19,6 +19,7 @@ class FavVideoCardH extends StatelessWidget {
final Function? callFn;
final int? searchType;
final String isOwner;
final Function? viewInvalidVideoCb;
const FavVideoCardH({
Key? key,
@ -26,6 +27,7 @@ class FavVideoCardH extends StatelessWidget {
this.callFn,
this.searchType,
required this.isOwner,
this.viewInvalidVideoCb,
}) : super(key: key);
@override
@ -36,6 +38,10 @@ class FavVideoCardH extends StatelessWidget {
return InkWell(
onTap: () async {
// int? seasonId;
if (videoItem.title == '已失效视频') {
viewInvalidVideoCb?.call();
return;
}
String? epId;
if (videoItem.ogv != null &&
(videoItem.ogv['type_name'] == '番剧' ||
@ -65,11 +71,17 @@ class FavVideoCardH extends StatelessWidget {
epId != null ? SearchType.media_bangumi : SearchType.video,
});
},
onLongPress: () => imageSaveDialog(
context,
videoItem,
SmartDialog.dismiss,
),
onLongPress: () {
if (videoItem.title == '已失效视频') {
SmartDialog.showToast('视频已失效');
return;
}
imageSaveDialog(
context,
videoItem,
SmartDialog.dismiss,
);
},
child: Column(
children: [
Padding(

View File

@ -0,0 +1,97 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/common/invalid_video.dart';
class InvalidVideoCard extends StatelessWidget {
const InvalidVideoCard({required this.videoInfo, Key? key}) : super(key: key);
final InvalidVideoModel videoInfo;
@override
Widget build(BuildContext context) {
const TextStyle textStyle = TextStyle(fontSize: 14.0);
return Padding(
padding: EdgeInsets.fromLTRB(
12,
14,
12,
MediaQuery.of(context).padding.bottom + 20,
),
child: LayoutBuilder(
builder: (context, constraints) {
double maxWidth = constraints.maxWidth;
double maxHeight = maxWidth * 9 / 16;
return SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
NetworkImgLayer(
width: maxWidth,
height: maxHeight,
src: videoInfo.pic,
radius: 20,
),
const SizedBox(height: 10),
SelectableText(
videoInfo.title!,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 2),
SelectableText(videoInfo.author!, style: textStyle),
const SizedBox(height: 2),
SelectableText('创建时间:${videoInfo.createdAt}', style: textStyle),
SelectableText('更新时间:${videoInfo.lastupdate}',
style: textStyle),
SelectableText('分类:${videoInfo.typename}', style: textStyle),
SelectableText(
'投币:${videoInfo.coins} 收藏:${videoInfo.favorites}',
style: textStyle),
if (videoInfo.tagList != null &&
videoInfo.tagList!.isNotEmpty) ...[
const SizedBox(height: 6),
_buildTags(context, videoInfo.tagList),
],
],
),
);
},
),
);
}
Widget _buildTags(BuildContext context, List<String>? videoTags) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
return Wrap(
spacing: 6,
runSpacing: 6,
direction: Axis.horizontal,
textDirection: TextDirection.ltr,
children: videoTags!.map((tag) {
return InkWell(
onTap: () {
Get.toNamed('/searchResult', parameters: {'keyword': tag});
},
borderRadius: BorderRadius.circular(6),
child: Container(
decoration: BoxDecoration(
color: colorScheme.surfaceVariant.withOpacity(0.5),
borderRadius: BorderRadius.circular(6),
),
padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 10),
child: Text(
tag,
style: TextStyle(
fontSize: 12,
color: colorScheme.onSurfaceVariant,
),
),
),
);
}).toList(),
);
}
}

View File

@ -312,25 +312,28 @@ class _LiveRoomPageState extends State<LiveRoomPage>
),
),
// 消息列表
Obx(
() => Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.only(
bottom: 90 + padding.bottom,
),
height: Get.size.height -
(padding.top +
kToolbarHeight +
(_liveRoomController.isPortrait.value
? Get.size.width
: Get.size.width * 9 / 16) +
100 +
padding.bottom),
child: buildMessageListUI(
context,
_liveRoomController,
_scrollController,
Visibility(
visible: !isLandscape,
child: Obx(
() => Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.only(
bottom: 90 + padding.bottom,
),
height: Get.size.height -
(padding.top +
kToolbarHeight +
(_liveRoomController.isPortrait.value
? Get.size.width
: Get.size.width * 9 / 16) +
100 +
padding.bottom),
child: buildMessageListUI(
context,
_liveRoomController,
_scrollController,
),
),
),
),

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/models/common/comment_range_type.dart';
import 'package:pilipala/models/common/dynamics_type.dart';
import 'package:pilipala/models/common/reply_sort_type.dart';
import 'package:pilipala/pages/setting/widgets/select_dialog.dart';
@ -27,6 +28,8 @@ class _ExtraSettingState extends State<ExtraSetting> {
late String defaultSystemProxyHost;
late String defaultSystemProxyPort;
bool userLogin = false;
// 记录每个选项是否被选中的状态
late List<String> enableComment;
@override
void initState() {
@ -47,6 +50,8 @@ class _ExtraSettingState extends State<ExtraSetting> {
localCache.get(LocalCacheKey.systemProxyHost, defaultValue: '');
defaultSystemProxyPort =
localCache.get(LocalCacheKey.systemProxyPort, defaultValue: '');
enableComment = setting
.get(SettingBoxKey.enableComment, defaultValue: ['video', 'bangumi']);
}
// 设置代理
@ -199,9 +204,94 @@ class _ExtraSettingState extends State<ExtraSetting> {
GlobalDataCache.enableDlna = val;
},
),
SetSwitchItem(
title: 'Sponsor Block',
subTitle: '自动跳过视频中赞助片段',
setKey: SettingBoxKey.enableSponsorBlock,
defaultVal: false,
callFn: (bool val) {
GlobalDataCache.enableSponsorBlock = val;
},
),
ListTile(
dense: false,
title: Text('评论展示', style: titleStyle),
onTap: () async {
List<String> tempEnableComment = List.from(enableComment);
int? result = await showDialog(
context: context,
builder: (context) {
// 带多选框的list
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return AlertDialog(
title: const Text('评论展示'),
contentPadding: const EdgeInsets.fromLTRB(0, 24, 0, 24),
content: SizedBox(
width: double.maxFinite,
child: ListView.builder(
itemCount: CommentRangeType.values.length,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int index) {
return CheckboxListTile(
contentPadding: const EdgeInsets.symmetric(
horizontal: 24, vertical: 0),
title: Text(
'${CommentRangeType.values[index].label}评论'),
value: tempEnableComment.contains(
CommentRangeType.values[index].value),
onChanged: (bool? value) {
setState(() {
if (value == true) {
tempEnableComment.add(
CommentRangeType.values[index].value);
} else {
tempEnableComment.remove(
CommentRangeType.values[index].value);
}
});
},
);
},
),
),
actions: [
TextButton(
onPressed: Navigator.of(context).pop,
child: Text(
'取消',
style: TextStyle(
color: Theme.of(context).colorScheme.outline),
),
),
TextButton(
onPressed: () async {
enableComment = tempEnableComment;
setting.put(
SettingBoxKey.enableComment, enableComment);
GlobalDataCache.enableComment = enableComment;
SmartDialog.showToast('操作成功');
Navigator.of(context).pop();
},
child: const Text('确认'),
)
],
);
},
);
},
);
if (result != null) {
defaultReplySort = result;
setting.put(SettingBoxKey.replySortType, result);
setState(() {});
}
},
),
ListTile(
dense: false,
title: Text('评论排序', style: titleStyle),
subtitle: Text(
'当前优先展示「${ReplySortType.values[defaultReplySort].titles}',
style: subTitleStyle,
@ -211,7 +301,7 @@ class _ExtraSettingState extends State<ExtraSetting> {
context: context,
builder: (context) {
return SelectDialog<int>(
title: '评论展示',
title: '评论排序',
value: defaultReplySort,
values: ReplySortType.values.map((e) {
return {'title': e.titles, 'value': e.index};

View File

@ -21,6 +21,7 @@ import 'package:pilipala/models/video/play/url.dart';
import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/pages/video/detail/reply_reply/index.dart';
import 'package:pilipala/plugin/pl_player/index.dart';
import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/utils.dart';
import 'package:pilipala/utils/video_utils.dart';
@ -140,8 +141,16 @@ class VideoDetailController extends GetxController
} else if (argMap.containsKey('pic')) {
updateCover(argMap['pic']);
}
tabCtr = TabController(length: 2, vsync: this);
tabs.value = <String>[
'简介',
if (videoType == SearchType.video &&
GlobalDataCache.enableComment.contains('video'))
'评论',
if (videoType == SearchType.media_bangumi &&
GlobalDataCache.enableComment.contains('bangumi'))
'评论'
];
tabCtr = TabController(length: tabs.length, vsync: this);
autoPlay.value =
setting.get(SettingBoxKey.autoPlayEnable, defaultValue: true);
enableHA.value = setting.get(SettingBoxKey.enableHA, defaultValue: false);
@ -198,7 +207,7 @@ class VideoDetailController extends GetxController
});
/// 仅投稿视频skip
if (videoType == SearchType.video) {
if (videoType == SearchType.video && GlobalDataCache.enableSponsorBlock) {
querySkipSegments();
}
}

View File

@ -17,6 +17,7 @@ import 'package:pilipala/pages/video/detail/controller.dart';
import 'package:pilipala/pages/video/detail/reply/index.dart';
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/id_utils.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:share_plus/share_plus.dart';
@ -87,19 +88,22 @@ class VideoIntroController extends GetxController {
}
// 获取视频简介&分p
Future queryVideoIntro({cover}) async {
Future queryVideoIntro({String? cover, String? type, int? cid}) async {
var result = await VideoHttp.videoIntro(bvid: bvid);
if (result['status']) {
videoDetail.value = result['data']!;
ugcSeason = result['data']!.ugcSeason;
pages.value = result['data']!.pages!;
lastPlayCid.value = videoDetail.value.cid!;
if (pages.isNotEmpty) {
lastPlayCid.value = pages.first.cid!;
if (type == null) {
lastPlayCid.value = cid ?? videoDetail.value.cid!;
}
final VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: heroTag);
videoDetailCtr.tabs.value = ['简介', '评论 ${result['data']?.stat?.reply}'];
videoDetailCtr.tabs.value = [
'简介',
if (GlobalDataCache.enableComment.contains('video'))
'评论 ${result['data']?.stat?.reply}'
];
videoDetailCtr.cover.value = cover ?? result['data'].pic ?? '';
// 获取到粉丝数再返回
await queryUserStat();
@ -469,13 +473,16 @@ class VideoIntroController extends GetxController {
// 重新请求评论
try {
/// 未渲染回复组件时可能异常
final VideoReplyController videoReplyCtr =
Get.find<VideoReplyController>(tag: heroTag);
videoReplyCtr.aid = aid;
videoReplyCtr.queryReplyList(type: 'init');
if (GlobalDataCache.enableComment.contains('video')) {
final VideoReplyController videoReplyCtr =
Get.find<VideoReplyController>(tag: heroTag);
videoReplyCtr.aid = aid;
videoReplyCtr.queryReplyList(type: 'init');
}
} catch (_) {}
this.bvid = bvid;
await queryVideoIntro(cover: cover);
// 点击切换时优先取当前cid
await queryVideoIntro(cover: cover, cid: cid);
}
void startTimer() {

View File

@ -57,7 +57,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
heroTag = Get.arguments['heroTag'];
videoIntroController =
Get.put(VideoIntroController(bvid: widget.bvid), tag: heroTag);
_futureBuilderFuture = videoIntroController.queryVideoIntro();
_futureBuilderFuture = videoIntroController.queryVideoIntro(type: 'init');
videoIntroController.videoDetail.listen((value) {
videoDetail = value;
});

View File

@ -27,7 +27,7 @@ class SeasonPanel extends StatefulWidget {
}
class _SeasonPanelState extends State<SeasonPanel> {
late List<EpisodeItem> episodes;
List<EpisodeItem>? episodes;
late int cid;
late RxInt currentIndex = (-1).obs;
final String heroTag = Get.arguments['heroTag'];
@ -75,7 +75,10 @@ class _SeasonPanelState extends State<SeasonPanel> {
// 获取currentIndex
void getCurrentIndex() {
currentIndex.value = episodes.indexWhere((EpisodeItem e) => e.cid == cid);
if (episodes != null) {
currentIndex.value =
episodes!.indexWhere((EpisodeItem e) => e.cid == cid);
}
final List<SectionItem> sections = widget.ugcSeason.sections!;
if (sections.length == 1 && sections.first.type == 1) {
final List<EpisodeItem> episodesList = sections.first.episodes!;
@ -83,6 +86,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
for (int j = 0; j < episodesList[i].pages!.length; j++) {
if (episodesList[i].pages![j].cid == cid) {
currentIndex.value = i;
episodes = episodesList;
continue;
}
}
@ -137,7 +141,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
widget.videoIntroCtr.bottomSheetController =
_bottomSheetController = EpisodeBottomSheet(
currentCid: cid,
episodes: episodes,
episodes: episodes!,
changeFucCall: changeFucCall,
sheetHeight: widget.sheetHeight,
dataType: VideoEpidoesType.videoEpisode,
@ -165,7 +169,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
),
const SizedBox(width: 10),
Obx(() => Text(
'${currentIndex.value + 1}/${episodes.length}',
'${currentIndex.value + 1}/${episodes!.length}',
style: Theme.of(context).textTheme.labelMedium,
)),
const SizedBox(width: 6),

View File

@ -24,6 +24,7 @@ import 'package:pilipala/pages/video/detail/related/index.dart';
import 'package:pilipala/plugin/pl_player/index.dart';
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
import 'package:pilipala/services/service_locator.dart';
import 'package:pilipala/utils/global_data_cache.dart';
import 'package:pilipala/utils/storage.dart';
import 'package:status_bar_control/status_bar_control.dart';
@ -779,13 +780,20 @@ class _VideoDetailPageState extends State<VideoDetailPage>
);
},
),
Obx(
() => VideoReplyPanel(
bvid: vdCtr.bvid,
oid: vdCtr.oid.value,
onControllerCreated: vdCtr.onControllerCreated,
),
)
if ((vdCtr.videoType == SearchType.media_bangumi &&
GlobalDataCache.enableComment
.contains('bangumi')) ||
(vdCtr.videoType == SearchType.video &&
GlobalDataCache.enableComment
.contains('video'))) ...[
Obx(
() => VideoReplyPanel(
bvid: vdCtr.bvid,
oid: vdCtr.oid.value,
onControllerCreated: vdCtr.onControllerCreated,
),
)
],
],
),
),

View File

@ -6,7 +6,7 @@ import 'package:pilipala/plugin/pl_player/models/play_speed.dart';
import 'package:pilipala/utils/storage.dart';
import '../models/common/index.dart';
Box setting = GStorage.setting;
Box settingBox = GStorage.setting;
Box localCache = GStorage.localCache;
Box videoStorage = GStorage.video;
Box userInfoCache = GStorage.userInfo;
@ -58,6 +58,10 @@ class GlobalDataCache {
static bool enableDlna = false;
// 硬件解码格式
static late String hardwareDecodeFormat;
// sponsorBlock开关
static bool enableSponsorBlock = false;
// 视频评论开关
static List<String> enableComment = ['video', 'bangumi'];
// 私有构造函数
GlobalDataCache._();
@ -70,18 +74,18 @@ class GlobalDataCache {
// 异步初始化方法
static Future<void> initialize() async {
imgQuality = await setting.get(SettingBoxKey.defaultPicQa,
imgQuality = await settingBox.get(SettingBoxKey.defaultPicQa,
defaultValue: 10); // 设置全局变量
fullScreenGestureMode = FullScreenGestureMode.values[setting.get(
fullScreenGestureMode = FullScreenGestureMode.values[settingBox.get(
SettingBoxKey.fullScreenGestureMode,
defaultValue: FullScreenGestureMode.fromBottomtoTop.index)];
enablePlayerControlAnimation = setting
enablePlayerControlAnimation = settingBox
.get(SettingBoxKey.enablePlayerControlAnimation, defaultValue: true);
actionTypeSort = await setting.get(SettingBoxKey.actionTypeSort,
actionTypeSort = await settingBox.get(SettingBoxKey.actionTypeSort,
defaultValue: ['like', 'coin', 'collect', 'watchLater', 'share']);
isOpenDanmu =
await setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
isOpenDanmu = await settingBox.get(SettingBoxKey.enableShowDanmaku,
defaultValue: false);
blockTypes =
await localCache.get(LocalCacheKey.danmakuBlockType, defaultValue: []);
showArea =
@ -102,7 +106,7 @@ class GlobalDataCache {
.firstWhere((e) => e.value == defaultPlayRepeat);
playbackSpeed =
await videoStorage.get(VideoBoxKey.playSpeedDefault, defaultValue: 1.0);
enableAutoLongPressSpeed = await setting
enableAutoLongPressSpeed = await settingBox
.get(SettingBoxKey.enableAutoLongPressSpeed, defaultValue: false);
if (!enableAutoLongPressSpeed) {
longPressSpeed = await videoStorage.get(VideoBoxKey.longPressSpeedDefault,
@ -120,13 +124,21 @@ class GlobalDataCache {
sheetHeight = localCache.get('sheetHeight', defaultValue: 0.0);
historyCacheList = localCache.get('cacheList', defaultValue: []);
enableSearchSuggest =
setting.get(SettingBoxKey.enableSearchSuggest, defaultValue: true);
settingBox.get(SettingBoxKey.enableSearchSuggest, defaultValue: true);
enableAutoExpand =
setting.get(SettingBoxKey.enableAutoExpand, defaultValue: false);
settingBox.get(SettingBoxKey.enableAutoExpand, defaultValue: false);
enableDynamicSwitch =
setting.get(SettingBoxKey.enableDynamicSwitch, defaultValue: true);
enableDlna = setting.get(SettingBoxKey.enableDlna, defaultValue: false);
hardwareDecodeFormat = setting.get(SettingBoxKey.hardwareDecodeFormat,
settingBox.get(SettingBoxKey.enableDynamicSwitch, defaultValue: true);
enableDlna = settingBox.get(SettingBoxKey.enableDlna, defaultValue: false);
hardwareDecodeFormat = settingBox.get(SettingBoxKey.hardwareDecodeFormat,
defaultValue: Platform.isAndroid ? 'auto-safe' : 'auto');
settingBox.get(SettingBoxKey.enableDynamicSwitch, defaultValue: true);
enableDlna = settingBox.get(SettingBoxKey.enableDlna, defaultValue: false);
enableSponsorBlock =
settingBox.get(SettingBoxKey.enableSponsorBlock, defaultValue: false);
settingBox.get(SettingBoxKey.enableDynamicSwitch, defaultValue: true);
enableDlna = settingBox.get(SettingBoxKey.enableDlna, defaultValue: false);
enableComment = settingBox
.get(SettingBoxKey.enableComment, defaultValue: ['video', 'bangumi']);
}
}

View File

@ -117,7 +117,9 @@ class SettingBoxKey {
defaultHomePage = 'defaultHomePage',
enableRelatedVideo = 'enableRelatedVideo',
enableDlna = 'enableDlna',
hardwareDecodeFormat = 'hardwareDecodeFormat';
hardwareDecodeFormat = 'hardwareDecodeFormat',
enableSponsorBlock = 'enableSponsorBlock',
enableComment = 'enableComment';
/// 外观
static const String themeMode = 'themeMode',