From 08cb807f39d4983743fda5e8359ef1655cbf9714 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 11 Nov 2024 23:46:08 +0800 Subject: [PATCH 01/39] fix: history cid --- lib/pages/video/detail/introduction/controller.dart | 10 +++++----- lib/pages/video/detail/introduction/view.dart | 2 +- .../detail/introduction/widgets/season_panel.dart | 12 ++++++++---- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 2671f4d8..eafedd08 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -85,15 +85,14 @@ 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(tag: heroTag); @@ -473,7 +472,8 @@ class VideoIntroController extends GetxController { videoReplyCtr.queryReplyList(type: 'init'); } catch (_) {} this.bvid = bvid; - await queryVideoIntro(cover: cover); + // 点击切换时,优先取当前cid + await queryVideoIntro(cover: cover, cid: cid); } void startTimer() { diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index a02ed530..9ceb35e0 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -57,7 +57,7 @@ class _VideoIntroPanelState extends State 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; }); diff --git a/lib/pages/video/detail/introduction/widgets/season_panel.dart b/lib/pages/video/detail/introduction/widgets/season_panel.dart index e5a9ea84..291f1622 100644 --- a/lib/pages/video/detail/introduction/widgets/season_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/season_panel.dart @@ -27,7 +27,7 @@ class SeasonPanel extends StatefulWidget { } class _SeasonPanelState extends State { - late List episodes; + List? episodes; late int cid; late RxInt currentIndex = (-1).obs; final String heroTag = Get.arguments['heroTag']; @@ -75,7 +75,10 @@ class _SeasonPanelState extends State { // 获取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 sections = widget.ugcSeason.sections!; if (sections.length == 1 && sections.first.type == 1) { final List episodesList = sections.first.episodes!; @@ -83,6 +86,7 @@ class _SeasonPanelState extends State { 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 { 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 { ), 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), From f44b5793c21e0d951e0d9a3cab0f7c8e0ebf1de3 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 17 Nov 2024 20:40:17 +0800 Subject: [PATCH 02/39] fix: repeated reply --- lib/pages/video/detail/reply/controller.dart | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index 4af59b9d..38d59617 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -70,6 +70,13 @@ class VideoReplyController extends GetxController { isEnd = res['data'].cursor.isEnd ?? false; nextOffset = res['data'].cursor.paginationReply.nextOffset ?? ""; if (replies.isNotEmpty) { + /// 临时修复 + final bool flag = replyList + .any((ReplyItemModel reply) => reply.rpid == replies.first.rpid); + if (replies.length == 1 && flag) { + replies.clear(); + isEnd = true; + } noMore.value = isEnd ? '没有更多了' : '加载中...'; } else { noMore.value = From b8affcef050ecc4529a06e390468d693e8247e10 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 18 Nov 2024 00:27:58 +0800 Subject: [PATCH 03/39] feat: view invalid fav video --- lib/http/api.dart | 4 ++ lib/http/common.dart | 29 ++++++++ lib/http/constants.dart | 2 + lib/models/common/invalid_video.dart | 70 +++++++++++++++++++ lib/pages/fav_detail/controller.dart | 21 ++++++ lib/pages/fav_detail/view.dart | 2 + .../fav_detail/widget/fav_video_card.dart | 22 ++++-- .../fav_detail/widget/invalid_video_card.dart | 51 ++++++++++++++ 8 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 lib/models/common/invalid_video.dart create mode 100644 lib/pages/fav_detail/widget/invalid_video_card.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index 5b2cdf58..379540a5 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -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'; } diff --git a/lib/http/common.dart b/lib/http/common.dart index 2f5f0e84..87d5e2a2 100644 --- a/lib/http/common.dart +++ b/lib/http/common.dart @@ -1,3 +1,6 @@ +import 'dart:developer'; + +import 'package:pilipala/models/common/invalid_video.dart'; import 'package:pilipala/models/sponsor_block/segment.dart'; import 'index.dart'; @@ -43,4 +46,30 @@ 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': '没有相关信息', + }; + } + } } diff --git a/lib/http/constants.dart b/lib/http/constants.dart index 07d06958..e7e031bb 100644 --- a/lib/http/constants.dart +++ b/lib/http/constants.dart @@ -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 validateStatusCodes = [ 302, 304, diff --git a/lib/models/common/invalid_video.dart b/lib/models/common/invalid_video.dart new file mode 100644 index 00000000..c4813872 --- /dev/null +++ b/lib/models/common/invalid_video.dart @@ -0,0 +1,70 @@ +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; + + 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, + }); + + factory InvalidVideoModel.fromJson(Map 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'], + ); + } +} diff --git a/lib/pages/fav_detail/controller.dart b/lib/pages/fav_detail/controller.dart index 93efd3aa..022e0103 100644 --- a/lib/pages/fav_detail/controller.dart +++ b/lib/pages/fav_detail/controller.dart @@ -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']); + } + } } diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index 462c7df3..30a15bf4 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -226,6 +226,8 @@ class _FavDetailPageState extends State { isOwner: _favDetailController.isOwner, callFn: () => _favDetailController .onCancelFav(favList[index].id), + viewInvalidVideoCb: () => _favDetailController + .toViewInvalidVideo(favList[index]), ); }, childCount: favList.length), ), diff --git a/lib/pages/fav_detail/widget/fav_video_card.dart b/lib/pages/fav_detail/widget/fav_video_card.dart index ecb4dd4a..ec2a7755 100644 --- a/lib/pages/fav_detail/widget/fav_video_card.dart +++ b/lib/pages/fav_detail/widget/fav_video_card.dart @@ -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( diff --git a/lib/pages/fav_detail/widget/invalid_video_card.dart b/lib/pages/fav_detail/widget/invalid_video_card.dart new file mode 100644 index 00000000..e8e82d0e --- /dev/null +++ b/lib/pages/fav_detail/widget/invalid_video_card.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.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: textStyle), + SelectableText('作者:${videoInfo.author}', style: textStyle), + SelectableText('创建时间:${videoInfo.createdAt}', style: textStyle), + SelectableText('上次更新时间:${videoInfo.lastupdate}', + style: textStyle), + SelectableText('分类:${videoInfo.typename}', style: textStyle), + SelectableText('投币:${videoInfo.coins}', style: textStyle), + SelectableText('收藏:${videoInfo.favorites}', style: textStyle), + SelectableText('标签:${videoInfo.tag}', style: textStyle), + ], + ), + ); + }, + ), + ); + } +} From 85ace29282303ea5f52f1ee0887fa0e91e6fcfa5 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 19 Nov 2024 23:22:33 +0800 Subject: [PATCH 04/39] mod: invalid video style --- lib/http/common.dart | 2 - lib/models/common/invalid_video.dart | 3 + .../fav_detail/widget/invalid_video_card.dart | 58 +++++++++++++++++-- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/lib/http/common.dart b/lib/http/common.dart index 87d5e2a2..c6354900 100644 --- a/lib/http/common.dart +++ b/lib/http/common.dart @@ -1,5 +1,3 @@ -import 'dart:developer'; - import 'package:pilipala/models/common/invalid_video.dart'; import 'package:pilipala/models/sponsor_block/segment.dart'; diff --git a/lib/models/common/invalid_video.dart b/lib/models/common/invalid_video.dart index c4813872..e1541f9c 100644 --- a/lib/models/common/invalid_video.dart +++ b/lib/models/common/invalid_video.dart @@ -19,6 +19,7 @@ class InvalidVideoModel { final String? videoReview; final String? favorites; final String? tag; + final List? tagList; InvalidVideoModel({ this.id, @@ -41,6 +42,7 @@ class InvalidVideoModel { this.videoReview, this.favorites, this.tag, + this.tagList, }); factory InvalidVideoModel.fromJson(Map json) { @@ -65,6 +67,7 @@ class InvalidVideoModel { videoReview: json['video_review'], favorites: json['favorites'], tag: json['tag'], + tagList: json['tag'].toString().split(',').toList(), ); } } diff --git a/lib/pages/fav_detail/widget/invalid_video_card.dart b/lib/pages/fav_detail/widget/invalid_video_card.dart index e8e82d0e..78e9ab0a 100644 --- a/lib/pages/fav_detail/widget/invalid_video_card.dart +++ b/lib/pages/fav_detail/widget/invalid_video_card.dart @@ -1,4 +1,5 @@ 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'; @@ -32,15 +33,28 @@ class InvalidVideoCard extends StatelessWidget { radius: 20, ), const SizedBox(height: 10), - SelectableText('标题:${videoInfo.title}', style: textStyle), - SelectableText('作者:${videoInfo.author}', style: textStyle), + 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}', + SelectableText('更新时间:${videoInfo.lastupdate}', style: textStyle), SelectableText('分类:${videoInfo.typename}', style: textStyle), - SelectableText('投币:${videoInfo.coins}', style: textStyle), - SelectableText('收藏:${videoInfo.favorites}', style: textStyle), - SelectableText('标签:${videoInfo.tag}', style: textStyle), + SelectableText( + '投币:${videoInfo.coins} 收藏:${videoInfo.favorites}', + style: textStyle), + if (videoInfo.tagList != null && + videoInfo.tagList!.isNotEmpty) ...[ + const SizedBox(height: 6), + _buildTags(context, videoInfo.tagList), + ], ], ), ); @@ -48,4 +62,36 @@ class InvalidVideoCard extends StatelessWidget { ), ); } + + Widget _buildTags(BuildContext context, List? 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(), + ); + } } From 16fa4677423b95dd829b087b6c0104c92afa6d87 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 19 Nov 2024 23:50:45 +0800 Subject: [PATCH 05/39] refactor: GlobalDataCache --- lib/common/widgets/network_img_layer.dart | 2 +- lib/http/member.dart | 8 +-- lib/main.dart | 2 +- lib/pages/dynamics/widgets/up_panel.dart | 2 +- lib/pages/main/view.dart | 2 +- lib/pages/member_archive/controller.dart | 5 +- lib/pages/member_article/controller.dart | 5 +- lib/pages/member_dynamics/controller.dart | 5 +- lib/pages/member_seasons/controller.dart | 2 +- lib/pages/search/controller.dart | 8 +-- lib/pages/setting/extra_setting.dart | 4 +- lib/pages/setting/pages/action_menu_set.dart | 2 +- lib/pages/setting/pages/play_gesture_set.dart | 4 +- lib/pages/setting/play_setting.dart | 2 +- lib/pages/setting/style_setting.dart | 2 +- lib/pages/video/detail/introduction/view.dart | 6 +-- .../detail/reply/widgets/reply_item.dart | 4 +- lib/pages/video/detail/widgets/ai_detail.dart | 2 +- lib/plugin/pl_player/controller.dart | 38 +++++++------- lib/plugin/pl_player/view.dart | 4 +- lib/utils/global_data_cache.dart | 52 +++++++++---------- lib/utils/login.dart | 2 +- 22 files changed, 79 insertions(+), 84 deletions(-) diff --git a/lib/common/widgets/network_img_layer.dart b/lib/common/widgets/network_img_layer.dart index 4980e2fc..b7b5de7e 100644 --- a/lib/common/widgets/network_img_layer.dart +++ b/lib/common/widgets/network_img_layer.dart @@ -48,7 +48,7 @@ class NetworkImgLayer extends StatelessWidget { Widget build(BuildContext context) { int defaultImgQuality = 10; try { - defaultImgQuality = GlobalDataCache().imgQuality; + defaultImgQuality = GlobalDataCache.imgQuality; } catch (_) {} if (src == '' || src == null) { diff --git a/lib/http/member.dart b/lib/http/member.dart index 66d0ff47..107a9379 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -26,7 +26,7 @@ class MemberHttp { }) async { String? wWebid; if ((await getWWebid(mid: mid))['status']) { - wWebid = GlobalDataCache().wWebid; + wWebid = GlobalDataCache.wWebid; } Map params = await WbiSign().makSign({ @@ -574,7 +574,7 @@ class MemberHttp { } static Future getWWebid({required int mid}) async { - String? wWebid = GlobalDataCache().wWebid; + String? wWebid = GlobalDataCache.wWebid; if (wWebid != null) { return {'status': true, 'data': wWebid}; } @@ -588,7 +588,7 @@ class MemberHttp { final content = match.group(1); String decodedString = Uri.decodeComponent(content!); Map map = jsonDecode(decodedString); - GlobalDataCache().wWebid = map['access_id']; + GlobalDataCache.wWebid = map['access_id']; return {'status': true, 'data': map['access_id']}; } else { return {'status': false, 'data': '请检查登录状态'}; @@ -605,7 +605,7 @@ class MemberHttp { }) async { String? wWebid; if ((await getWWebid(mid: mid))['status']) { - wWebid = GlobalDataCache().wWebid; + wWebid = GlobalDataCache.wWebid; } Map params = await WbiSign().makSign({ 'host_mid': mid, diff --git a/lib/main.dart b/lib/main.dart index 1ec86c8e..5a163f49 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -65,7 +65,7 @@ void main() async { } PiliSchame.init(); - await GlobalDataCache().initialize(); + await GlobalDataCache.initialize(); } class MyApp extends StatelessWidget { diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart index d5d7958e..607b6af7 100644 --- a/lib/pages/dynamics/widgets/up_panel.dart +++ b/lib/pages/dynamics/widgets/up_panel.dart @@ -173,7 +173,7 @@ class _UpPanelState extends State { if (data.type == 'up') { EasyThrottle.throttle('follow', const Duration(milliseconds: 300), () { - if (GlobalDataCache().enableDynamicSwitch) { + if (GlobalDataCache.enableDynamicSwitch) { onClickUp(data, i); } else { onClickUpAni(data, i); diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index 01fae4bf..1c4dbf62 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -125,7 +125,7 @@ class _MainAppState extends State with SingleTickerProviderStateMixin { double sheetHeight = MediaQuery.sizeOf(context).height - MediaQuery.of(context).padding.top - MediaQuery.sizeOf(context).width * 9 / 16; - GlobalDataCache().sheetHeight = sheetHeight; + GlobalDataCache.sheetHeight = sheetHeight; localCache.put('sheetHeight', sheetHeight); localCache.put('statusBarHeight', statusBarHeight); diff --git a/lib/pages/member_archive/controller.dart b/lib/pages/member_archive/controller.dart index 61816ed5..3fdcbedc 100644 --- a/lib/pages/member_archive/controller.dart +++ b/lib/pages/member_archive/controller.dart @@ -28,9 +28,8 @@ class MemberArchiveController extends GetxController { super.onInit(); mid = int.parse(Get.parameters['mid']!); currentOrder.value = orderList.first; - ownerMid = GlobalDataCache().userInfo != null - ? GlobalDataCache().userInfo!.mid! - : -1; + ownerMid = + GlobalDataCache.userInfo != null ? GlobalDataCache.userInfo!.mid! : -1; isOwner.value = mid == -1 || mid == ownerMid; } diff --git a/lib/pages/member_article/controller.dart b/lib/pages/member_article/controller.dart index 9c67f679..542fbc4f 100644 --- a/lib/pages/member_article/controller.dart +++ b/lib/pages/member_article/controller.dart @@ -20,9 +20,8 @@ class MemberArticleController extends GetxController { void onInit() { super.onInit(); mid = int.parse(Get.parameters['mid']!); - ownerMid = GlobalDataCache().userInfo != null - ? GlobalDataCache().userInfo!.mid! - : -1; + ownerMid = + GlobalDataCache.userInfo != null ? GlobalDataCache.userInfo!.mid! : -1; isOwner.value = mid == -1 || mid == ownerMid; } diff --git a/lib/pages/member_dynamics/controller.dart b/lib/pages/member_dynamics/controller.dart index 8fdf55b7..be5b2454 100644 --- a/lib/pages/member_dynamics/controller.dart +++ b/lib/pages/member_dynamics/controller.dart @@ -18,9 +18,8 @@ class MemberDynamicsController extends GetxController { void onInit() { super.onInit(); mid = int.parse(Get.parameters['mid']!); - ownerMid = GlobalDataCache().userInfo != null - ? GlobalDataCache().userInfo!.mid! - : -1; + ownerMid = + GlobalDataCache.userInfo != null ? GlobalDataCache.userInfo!.mid! : -1; isOwner.value = mid == -1 || mid == ownerMid; } diff --git a/lib/pages/member_seasons/controller.dart b/lib/pages/member_seasons/controller.dart index 07532787..e3f2c409 100644 --- a/lib/pages/member_seasons/controller.dart +++ b/lib/pages/member_seasons/controller.dart @@ -59,7 +59,7 @@ class MemberSeasonsController extends GetxController { mid: mid, seriesId: seriesId!, pn: pn, - currentMid: GlobalDataCache().userInfo?.mid ?? -1, + currentMid: GlobalDataCache.userInfo?.mid ?? -1, ); if (res['status']) { seasonsList.addAll(res['data'].seriesList); diff --git a/lib/pages/search/controller.dart b/lib/pages/search/controller.dart index 2da2acff..8d24f167 100644 --- a/lib/pages/search/controller.dart +++ b/lib/pages/search/controller.dart @@ -43,10 +43,10 @@ class SSearchController extends GetxController { hintText = hint; } } - historyCacheList = GlobalDataCache().historyCacheList; + historyCacheList = GlobalDataCache.historyCacheList; historyList.value = historyCacheList; enableHotKey = setting.get(SettingBoxKey.enableHotKey, defaultValue: true); - enableSearchSuggest = GlobalDataCache().enableSearchSuggest; + enableSearchSuggest = GlobalDataCache.enableSearchSuggest; } void onChange(value) { @@ -128,7 +128,7 @@ class SSearchController extends GetxController { historyCacheList = []; historyList.refresh(); localCache.put('cacheList', []); - GlobalDataCache().historyCacheList = []; + GlobalDataCache.historyCacheList = []; SmartDialog.showToast('搜索历史已清空'); } @@ -139,7 +139,7 @@ class SSearchController extends GetxController { historyList.value = historyCacheList; historyList.refresh(); localCache.put('cacheList', historyCacheList); - GlobalDataCache().historyCacheList = historyCacheList; + GlobalDataCache.historyCacheList = historyCacheList; searchFocusNode.unfocus(); } } diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index 07cd585a..fdc62f13 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -146,7 +146,7 @@ class _ExtraSettingState extends State { setKey: SettingBoxKey.enableSearchSuggest, defaultVal: true, callFn: (val) { - GlobalDataCache().enableSearchSuggest = val; + GlobalDataCache.enableSearchSuggest = val; }, ), SetSwitchItem( @@ -181,7 +181,7 @@ class _ExtraSettingState extends State { setKey: SettingBoxKey.enableAutoExpand, defaultVal: false, callFn: (val) { - GlobalDataCache().enableAutoExpand = val; + GlobalDataCache.enableAutoExpand = val; }, ), const SetSwitchItem( diff --git a/lib/pages/setting/pages/action_menu_set.dart b/lib/pages/setting/pages/action_menu_set.dart index cbbd0e84..3b211bae 100644 --- a/lib/pages/setting/pages/action_menu_set.dart +++ b/lib/pages/setting/pages/action_menu_set.dart @@ -38,7 +38,7 @@ class _ActionMenuSetPageState extends State { .map((i) => (i['value'] as ActionType).value) .toList(); setting.put(SettingBoxKey.actionTypeSort, sortedTabbar); - GlobalDataCache().actionTypeSort = sortedTabbar; + GlobalDataCache.actionTypeSort = sortedTabbar; SmartDialog.showToast('操作成功'); } diff --git a/lib/pages/setting/pages/play_gesture_set.dart b/lib/pages/setting/pages/play_gesture_set.dart index bad115a5..dc11cd6f 100644 --- a/lib/pages/setting/pages/play_gesture_set.dart +++ b/lib/pages/setting/pages/play_gesture_set.dart @@ -58,11 +58,11 @@ class _PlayGesturePageState extends State { }, ); if (result != null) { - GlobalDataCache().fullScreenGestureMode = FullScreenGestureMode + GlobalDataCache.fullScreenGestureMode = FullScreenGestureMode .values .firstWhere((element) => element.values == result); fullScreenGestureMode = - GlobalDataCache().fullScreenGestureMode.index; + GlobalDataCache.fullScreenGestureMode.index; setting.put( SettingBoxKey.fullScreenGestureMode, fullScreenGestureMode); SmartDialog.showToast('设置成功'); diff --git a/lib/pages/setting/play_setting.dart b/lib/pages/setting/play_setting.dart index e191d8fd..7090bfaf 100644 --- a/lib/pages/setting/play_setting.dart +++ b/lib/pages/setting/play_setting.dart @@ -155,7 +155,7 @@ class _PlaySettingState extends State { setKey: SettingBoxKey.enablePlayerControlAnimation, defaultVal: true, callFn: (bool val) { - GlobalDataCache().enablePlayerControlAnimation = val; + GlobalDataCache.enablePlayerControlAnimation = val; }), SetSwitchItem( title: '港澳台模式', diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart index 5b59397e..54b97ea5 100644 --- a/lib/pages/setting/style_setting.dart +++ b/lib/pages/setting/style_setting.dart @@ -175,7 +175,7 @@ class _StyleSettingState extends State { SettingBoxKey.defaultPicQa, picQuality); Get.back(); settingController.picQuality.value = picQuality; - GlobalDataCache().imgQuality = picQuality; + GlobalDataCache.imgQuality = picQuality; SmartDialog.showToast('设置成功'); }, child: const Text('确定'), diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 451173dd..417548d5 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -169,8 +169,8 @@ class _VideoInfoState extends State with TickerProviderStateMixin { owner = widget.videoDetail!.owner; enableAi = setting.get(SettingBoxKey.enableAi, defaultValue: true); - _expandableCtr = ExpandableController( - initialExpanded: GlobalDataCache().enableAutoExpand); + _expandableCtr = + ExpandableController(initialExpanded: GlobalDataCache.enableAutoExpand); } // 收藏 @@ -556,7 +556,7 @@ class _VideoInfoState extends State with TickerProviderStateMixin { } Widget actionGrid(BuildContext context, videoIntroController) { - final actionTypeSort = GlobalDataCache().actionTypeSort; + final actionTypeSort = GlobalDataCache.actionTypeSort; Map menuListWidgets = { 'like': Obx( diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index 5d31858f..e0a6d07f 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -52,7 +52,7 @@ class ReplyItem extends StatelessWidget { @override Widget build(BuildContext context) { final bool isOwner = int.parse(replyItem!.member!.mid!) == - (GlobalDataCache().userInfo?.mid ?? -1); + (GlobalDataCache.userInfo?.mid ?? -1); return Material( child: InkWell( // 点击整个评论区 评论详情/回复 @@ -415,7 +415,7 @@ class ReplyItemRow extends StatelessWidget { onLongPress: () { feedBack(); final bool isOwner = int.parse(replyItem!.member!.mid!) == - (GlobalDataCache().userInfo?.mid ?? -1); + (GlobalDataCache.userInfo?.mid ?? -1); showModalBottomSheet( context: context, useRootNavigator: true, diff --git a/lib/pages/video/detail/widgets/ai_detail.dart b/lib/pages/video/detail/widgets/ai_detail.dart index 64327553..c17591fb 100644 --- a/lib/pages/video/detail/widgets/ai_detail.dart +++ b/lib/pages/video/detail/widgets/ai_detail.dart @@ -18,7 +18,7 @@ class AiDetail extends StatelessWidget { Widget build(BuildContext context) { return Container( padding: const EdgeInsets.only(left: 16, right: 16), - height: GlobalDataCache().sheetHeight, + height: GlobalDataCache.sheetHeight, child: Column( children: [ _buildHeader(context), diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index de4cd9df..b69d96bb 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -278,19 +278,18 @@ class PlPlayerController { // 添加一个私有构造函数 PlPlayerController._internal(this.videoType) { - final cache = GlobalDataCache(); - isOpenDanmu.value = cache.isOpenDanmu; - blockTypes = cache.blockTypes; - showArea = cache.showArea; - opacityVal = cache.opacityVal; - fontSizeVal = cache.fontSizeVal; - danmakuDurationVal = cache.danmakuDurationVal; - strokeWidth = cache.strokeWidth; - playRepeat = cache.playRepeat; - _playbackSpeed.value = cache.playbackSpeed; - enableAutoLongPressSpeed = cache.enableAutoLongPressSpeed; - _longPressSpeed.value = cache.longPressSpeed; - speedsList = cache.speedsList; + isOpenDanmu.value = GlobalDataCache.isOpenDanmu; + blockTypes = GlobalDataCache.blockTypes; + showArea = GlobalDataCache.showArea; + opacityVal = GlobalDataCache.opacityVal; + fontSizeVal = GlobalDataCache.fontSizeVal; + danmakuDurationVal = GlobalDataCache.danmakuDurationVal; + strokeWidth = GlobalDataCache.strokeWidth; + playRepeat = GlobalDataCache.playRepeat; + _playbackSpeed.value = GlobalDataCache.playbackSpeed; + enableAutoLongPressSpeed = GlobalDataCache.enableAutoLongPressSpeed; + _longPressSpeed.value = GlobalDataCache.longPressSpeed; + speedsList = GlobalDataCache.speedsList; // _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) { // if (status == PlayerStatus.playing) { // WakelockPlus.enable(); @@ -1047,13 +1046,12 @@ class PlPlayerController { /// 缓存本次弹幕选项 cacheDanmakuOption() { - final cache = GlobalDataCache(); - cache.blockTypes = blockTypes; - cache.showArea = showArea; - cache.opacityVal = opacityVal; - cache.fontSizeVal = fontSizeVal; - cache.danmakuDurationVal = danmakuDurationVal; - cache.strokeWidth = strokeWidth; + GlobalDataCache.blockTypes = blockTypes; + GlobalDataCache.showArea = showArea; + GlobalDataCache.opacityVal = opacityVal; + GlobalDataCache.fontSizeVal = fontSizeVal; + GlobalDataCache.danmakuDurationVal = danmakuDurationVal; + GlobalDataCache.strokeWidth = strokeWidth; localCache.put(LocalCacheKey.danmakuBlockType, blockTypes); localCache.put(LocalCacheKey.danmakuShowArea, showArea); diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 990661bc..c73bc55f 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -89,7 +89,7 @@ class _PLVideoPlayerState extends State late bool enableBackgroundPlay; late double screenWidth; final FullScreenGestureMode fullScreenGestureMode = - GlobalDataCache().fullScreenGestureMode; + GlobalDataCache.fullScreenGestureMode; // 用于记录上一次全屏切换手势触发时间,避免误触 DateTime? lastFullScreenToggleTime; @@ -136,7 +136,7 @@ class _PLVideoPlayerState extends State screenWidth = Get.size.width; animationController = AnimationController( vsync: this, - duration: GlobalDataCache().enablePlayerControlAnimation + duration: GlobalDataCache.enablePlayerControlAnimation ? const Duration(milliseconds: 150) : const Duration(milliseconds: 10), ); diff --git a/lib/utils/global_data_cache.dart b/lib/utils/global_data_cache.dart index 3321c660..ea673859 100644 --- a/lib/utils/global_data_cache.dart +++ b/lib/utils/global_data_cache.dart @@ -11,48 +11,48 @@ Box videoStorage = GStorage.video; Box userInfoCache = GStorage.userInfo; class GlobalDataCache { - late int imgQuality; - late FullScreenGestureMode fullScreenGestureMode; - late bool enablePlayerControlAnimation; - late List actionTypeSort; - late double sheetHeight; - String? wWebid; + static late int imgQuality; + static late FullScreenGestureMode fullScreenGestureMode; + static late bool enablePlayerControlAnimation; + static late List actionTypeSort; + static late double sheetHeight; + static String? wWebid; /// 播放器相关 // 弹幕开关 - late bool isOpenDanmu; + static late bool isOpenDanmu; // 弹幕屏蔽类型 - late List blockTypes; + static late List blockTypes; // 弹幕展示区域 - late double showArea; + static late double showArea; // 弹幕透明度 - late double opacityVal; + static late double opacityVal; // 弹幕字体大小 - late double fontSizeVal; + static late double fontSizeVal; // 弹幕显示时间 - late double danmakuDurationVal; + static late double danmakuDurationVal; // 弹幕描边宽度 - late double strokeWidth; + static late double strokeWidth; // 播放器循环模式 - late PlayRepeat playRepeat; + static late PlayRepeat playRepeat; // 播放器默认播放速度 - late double playbackSpeed; + static late double playbackSpeed; // 播放器自动长按速度 - late bool enableAutoLongPressSpeed; + static late bool enableAutoLongPressSpeed; // 播放器长按速度 - late double longPressSpeed; + static late double longPressSpeed; // 播放器速度列表 - late List speedsList; + static late List speedsList; // 用户信息 - UserInfoData? userInfo; + static UserInfoData? userInfo; // 搜索历史 - late List historyCacheList; - // - late bool enableSearchSuggest = true; + static late List historyCacheList; + // 搜索建议 + static late bool enableSearchSuggest; // 简介默认展开 - late bool enableAutoExpand = false; - // - late bool enableDynamicSwitch = true; + static late bool enableAutoExpand; + // 动态切换 + static late bool enableDynamicSwitch; // 私有构造函数 GlobalDataCache._(); @@ -64,7 +64,7 @@ class GlobalDataCache { factory GlobalDataCache() => _instance; // 异步初始化方法 - Future initialize() async { + static Future initialize() async { imgQuality = await setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10); // 设置全局变量 fullScreenGestureMode = FullScreenGestureMode.values[setting.get( diff --git a/lib/utils/login.dart b/lib/utils/login.dart index 9dde1cb1..159de81d 100644 --- a/lib/utils/login.dart +++ b/lib/utils/login.dart @@ -118,7 +118,7 @@ class LoginUtils { Request.dio.options.headers['cookie'] = ''; userInfoCache.put('userInfoCache', null); localCache.put(LocalCacheKey.accessKey, {'mid': -1, 'value': ''}); - GlobalDataCache().userInfo = null; + GlobalDataCache.userInfo = null; await refreshLoginStatus(false); } } From 65bb5d7e3d762f8700101e4546f6d3058ec66b34 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 20 Nov 2024 00:02:12 +0800 Subject: [PATCH 06/39] refactor: buvidActivate call --- lib/http/common.dart | 44 ++++++++++++++++++++++++++++++++++++++++++++ lib/http/init.dart | 34 ---------------------------------- lib/main.dart | 2 ++ 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/lib/http/common.dart b/lib/http/common.dart index 2f5f0e84..9644d142 100644 --- a/lib/http/common.dart +++ b/lib/http/common.dart @@ -1,8 +1,14 @@ +import 'dart:convert'; +import 'dart:math'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; import 'package:pilipala/models/sponsor_block/segment.dart'; import 'index.dart'; class CommonHttp { + static final RegExp spmPrefixExp = + RegExp(r''); static Future unReadDynamic() async { var res = await Request().get(Api.getUnreadDynamic, data: {'alltype_offset': 0, 'video_offset': '', 'article_offset': 0}); @@ -43,4 +49,42 @@ class CommonHttp { }; } } + + static Future buvidActivate() async { + try { + // 获取 HTML 数据 + var html = await Request().get(Api.dynamicSpmPrefix); + + // 提取 spmPrefix + String spmPrefix = spmPrefixExp.firstMatch(html.data)?.group(1) ?? ''; + + // 生成随机 PNG 结束部分 + Random rand = Random(); + String randPngEnd = base64.encode( + List.generate(32, (_) => rand.nextInt(256)) + ..addAll(List.filled(4, 0)) + ..addAll([73, 69, 78, 68]) + ..addAll(List.generate(4, (_) => rand.nextInt(256))), + ); + + // 构建 JSON 数据 + String jsonData = json.encode({ + '3064': 1, + '39c8': '$spmPrefix.fp.risk', + '3c43': { + 'adca': 'Linux', + 'bfe9': randPngEnd.substring(randPngEnd.length - 50), + }, + }); + + // 发送 POST 请求 + await Request().post( + Api.activateBuvidApi, + data: {'payload': jsonData}, + options: Options(contentType: 'application/json'), + ); + } catch (err) { + debugPrint('buvidActivate error: $err'); + } + } } diff --git a/lib/http/init.dart b/lib/http/init.dart index 8a11034c..03de43b7 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -1,9 +1,7 @@ // ignore_for_file: avoid_print import 'dart:async'; -import 'dart:convert'; import 'dart:developer'; import 'dart:io'; -import 'dart:math' show Random; import 'package:cookie_jar/cookie_jar.dart'; import 'package:dio/dio.dart'; import 'package:dio/io.dart'; @@ -13,7 +11,6 @@ import 'package:pilipala/models/user/info.dart'; import 'package:pilipala/utils/id_utils.dart'; import '../utils/storage.dart'; import '../utils/utils.dart'; -import 'api.dart'; import 'constants.dart'; import 'interceptor.dart'; @@ -27,8 +24,6 @@ class Request { late bool enableSystemProxy; late String systemProxyHost; late String systemProxyPort; - static final RegExp spmPrefixExp = - RegExp(r''); static String? buvid; /// 设置cookie @@ -62,11 +57,6 @@ class Request { baseUrlType = 'bangumi'; } setBaseUrl(type: baseUrlType); - try { - await buvidActivate(); - } catch (e) { - log("setCookie, ${e.toString()}"); - } final String cookieString = cookie .map((Cookie cookie) => '${cookie.name}=${cookie.value}') @@ -122,30 +112,6 @@ class Request { dio.options.headers['referer'] = 'https://www.bilibili.com/'; } - static Future buvidActivate() async { - var html = await Request().get(Api.dynamicSpmPrefix); - String spmPrefix = spmPrefixExp.firstMatch(html.data)!.group(1)!; - Random rand = Random(); - String rand_png_end = base64.encode( - List.generate(32, (_) => rand.nextInt(256)) + - List.filled(4, 0) + - [73, 69, 78, 68] + - List.generate(4, (_) => rand.nextInt(256))); - - String jsonData = json.encode({ - '3064': 1, - '39c8': '${spmPrefix}.fp.risk', - '3c43': { - 'adca': 'Linux', - 'bfe9': rand_png_end.substring(rand_png_end.length - 50), - }, - }); - - await Request().post(Api.activateBuvidApi, - data: {'payload': jsonData}, - options: Options(contentType: 'application/json')); - } - /* * config it and create */ diff --git a/lib/main.dart b/lib/main.dart index 1ec86c8e..fcb29fad 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'package:flutter/material.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/widgets/custom_toast.dart'; +import 'package:pilipala/http/common.dart'; import 'package:pilipala/http/init.dart'; import 'package:pilipala/models/common/color_type.dart'; import 'package:pilipala/models/common/theme_type.dart'; @@ -66,6 +67,7 @@ void main() async { PiliSchame.init(); await GlobalDataCache().initialize(); + CommonHttp.buvidActivate(); } class MyApp extends StatelessWidget { From 4008b8caef561575f447d57c74d804fc731c3de1 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 20 Nov 2024 09:46:05 +0800 Subject: [PATCH 07/39] fix: controlsLock exit fullscreen --- lib/pages/video/detail/view.dart | 5 +++++ lib/plugin/pl_player/controller.dart | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 0fb97066..d357d3ea 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -684,6 +684,11 @@ class _VideoDetailPageState extends State canPop: plPlayerController?.isFullScreen.value != true, onPopInvoked: (bool didPop) { + if (plPlayerController?.controlsLock.value == + true) { + plPlayerController?.onLockControl(false); + return; + } if (plPlayerController?.isFullScreen.value == true) { plPlayerController! diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index de4cd9df..61711bf3 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -909,7 +909,7 @@ class PlPlayerController { if (videoType == 'live') { return; } - if (controlsLock.value) { + if (_controlsLock.value) { return; } _doubleSpeedStatus.value = val; @@ -1081,6 +1081,7 @@ class PlPlayerController { videoFitChangedTimer?.cancel(); // _position.close(); _playerEventSubs?.cancel(); + _controlsLock.value = false; // _sliderPosition.close(); // _sliderTempPosition.close(); // _isSliderMoving.close(); From 121d32e40324d2f178493c07d0213f68bb02f5b8 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 20 Nov 2024 09:50:34 +0800 Subject: [PATCH 08/39] mod: reply appbar title spacing --- lib/pages/video/detail/reply_reply/view.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/pages/video/detail/reply_reply/view.dart b/lib/pages/video/detail/reply_reply/view.dart index c697349d..cf72c3a4 100644 --- a/lib/pages/video/detail/reply_reply/view.dart +++ b/lib/pages/video/detail/reply_reply/view.dart @@ -89,9 +89,12 @@ class _VideoReplyReplyPanelState extends State { return AppBar( toolbarHeight: 45, automaticallyImplyLeading: false, - title: Text( - '评论详情', - style: Theme.of(context).textTheme.titleSmall, + title: Padding( + padding: const EdgeInsets.only(left: 14), + child: Text( + '评论详情', + style: Theme.of(context).textTheme.titleSmall, + ), ), actions: [ IconButton( @@ -102,7 +105,7 @@ class _VideoReplyReplyPanelState extends State { Navigator.pop(context); }, ), - const SizedBox(width: 14), + const SizedBox(width: 12), ], ); } From 1ac152bb49ed159cd7366a20f23227accd882a75 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 20 Nov 2024 22:45:25 +0800 Subject: [PATCH 09/39] feat: dlna switch --- lib/pages/setting/extra_setting.dart | 6 ++++ .../video/detail/widgets/header_control.dart | 33 ++++++++++--------- lib/utils/global_data_cache.dart | 3 ++ lib/utils/storage.dart | 3 +- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index fdc62f13..3e82f2bd 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -190,6 +190,12 @@ class _ExtraSettingState extends State { setKey: SettingBoxKey.enableRelatedVideo, defaultVal: true, ), + const SetSwitchItem( + title: '视频投屏开关', + subTitle: '打开后将在播放器右上角显示投屏入口', + setKey: SettingBoxKey.enableDlna, + defaultVal: false, + ), ListTile( dense: false, title: Text('评论展示', style: titleStyle), diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index f22bf846..bc9167d5 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -16,6 +16,7 @@ import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/introduction/widgets/menu_row.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; +import 'package:pilipala/utils/global_data_cache.dart'; import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/services/shutdown_timer_service.dart'; import '../../../../http/danmaku.dart'; @@ -1237,22 +1238,24 @@ class _HeaderControlState extends State { // ), // fuc: () => _.screenshot(), // ), - ComBtn( - icon: const Icon( - Icons.cast, - size: 19, - color: Colors.white, + if (GlobalDataCache.enableDlna) ...[ + ComBtn( + icon: const Icon( + Icons.cast, + size: 19, + color: Colors.white, + ), + fuc: () async { + showDialog( + context: context, + builder: (BuildContext context) { + return LiveDlnaPage( + datasource: widget.videoDetailCtr!.videoUrl); + }, + ); + }, ), - fuc: () async { - showDialog( - context: context, - builder: (BuildContext context) { - return LiveDlnaPage( - datasource: widget.videoDetailCtr!.videoUrl); - }, - ); - }, - ), + ], if (isFullScreen.value) ...[ SizedBox( width: 56, diff --git a/lib/utils/global_data_cache.dart b/lib/utils/global_data_cache.dart index ea673859..a421f829 100644 --- a/lib/utils/global_data_cache.dart +++ b/lib/utils/global_data_cache.dart @@ -53,6 +53,8 @@ class GlobalDataCache { static late bool enableAutoExpand; // 动态切换 static late bool enableDynamicSwitch; + // 投屏开关 + static bool enableDlna = false; // 私有构造函数 GlobalDataCache._(); @@ -120,5 +122,6 @@ class GlobalDataCache { setting.get(SettingBoxKey.enableAutoExpand, defaultValue: false); enableDynamicSwitch = setting.get(SettingBoxKey.enableDynamicSwitch, defaultValue: true); + enableDlna = setting.get(SettingBoxKey.enableDlna, defaultValue: false); } } diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index a5b36768..49a5c734 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -115,7 +115,8 @@ class SettingBoxKey { enableAi = 'enableAi', enableAutoExpand = 'enableAutoExpand', defaultHomePage = 'defaultHomePage', - enableRelatedVideo = 'enableRelatedVideo'; + enableRelatedVideo = 'enableRelatedVideo', + enableDlna = 'enableDlna'; /// 外观 static const String themeMode = 'themeMode', From 14640f338ca4068f29214ea707c362083a775428 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 21 Nov 2024 23:43:55 +0800 Subject: [PATCH 10/39] opt: hide live users by default --- lib/pages/dynamics/widgets/up_panel.dart | 239 +++++++++++++++-------- 1 file changed, 156 insertions(+), 83 deletions(-) diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart index d5d7958e..35dc5cd8 100644 --- a/lib/pages/dynamics/widgets/up_panel.dart +++ b/lib/pages/dynamics/widgets/up_panel.dart @@ -34,6 +34,7 @@ class _UpPanelState extends State { List liveList = []; static const itemPadding = EdgeInsets.symmetric(horizontal: 5, vertical: 0); late MyInfo userInfo; + RxBool showLiveUser = false.obs; void listFormat() { userInfo = widget.upData.myInfo!; @@ -131,21 +132,70 @@ class _UpPanelState extends State { children: [ const SizedBox(width: 10), if (liveList.isNotEmpty) ...[ - for (int i = 0; i < liveList.length; i++) ...[ - upItemBuild(liveList[i], i) - ], - VerticalDivider( - indent: 20, - endIndent: 40, - width: 26, - color: Theme.of(context) - .colorScheme - .primary - .withOpacity(0.5), + Obx( + () => AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + transitionBuilder: (Widget child, + Animation animation) { + return FadeTransition( + opacity: animation, child: child); + }, + child: showLiveUser.value + ? Row( + key: ValueKey(showLiveUser.value), + children: [ + for (int i = 0; + i < liveList.length; + i++) + UpItemWidget( + data: liveList[i], + index: i, + currentMid: currentMid, + onClickUp: onClickUp, + onClickUpAni: onClickUpAni, + itemPadding: itemPadding, + contentWidth: contentWidth, + ) + ], + ) + : SizedBox.shrink( + key: ValueKey(showLiveUser.value), + ), + ), + ), + Obx( + () => IconButton( + onPressed: () { + showLiveUser.value = !showLiveUser.value; + }, + icon: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + transitionBuilder: (Widget child, + Animation animation) { + return ScaleTransition( + scale: animation, child: child); + }, + child: Icon( + !showLiveUser.value + ? Icons.arrow_forward_ios_rounded + : Icons.arrow_back_ios_rounded, + key: ValueKey(showLiveUser.value), + size: 18, + ), + ), + ), ), ], for (int i = 0; i < upList.length; i++) ...[ - upItemBuild(upList[i], i) + UpItemWidget( + data: upList[i], + index: i, + currentMid: currentMid, + onClickUp: onClickUp, + onClickUpAni: onClickUpAni, + itemPadding: itemPadding, + contentWidth: contentWidth, + ) ], const SizedBox(width: 10), ], @@ -165,8 +215,93 @@ class _UpPanelState extends State { )), ); } +} - Widget upItemBuild(data, i) { +class _SliverHeaderDelegate extends SliverPersistentHeaderDelegate { + _SliverHeaderDelegate({required this.height, required this.child}); + + final double height; + final Widget child; + + @override + Widget build( + BuildContext context, double shrinkOffset, bool overlapsContent) { + return child; + } + + @override + double get maxExtent => height; + + @override + double get minExtent => height; + + @override + bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => + true; +} + +class UpPanelSkeleton extends StatelessWidget { + const UpPanelSkeleton({super.key}); + + @override + Widget build(BuildContext context) { + return ListView.builder( + scrollDirection: Axis.horizontal, + physics: const NeverScrollableScrollPhysics(), + itemCount: 10, + itemBuilder: ((context, index) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.onInverseSurface, + borderRadius: BorderRadius.circular(50), + ), + ), + Container( + margin: const EdgeInsets.only(top: 6), + width: 45, + height: 12, + color: Theme.of(context).colorScheme.onInverseSurface, + ), + ], + ), + ); + }), + ); + } +} + +class UpItemWidget extends StatelessWidget { + final dynamic data; + final int index; + final RxInt currentMid; + final Function(dynamic, int) onClickUp; + final Function(dynamic, int) onClickUpAni; + // final Function() feedBack; + final EdgeInsets itemPadding; + final double contentWidth; + + const UpItemWidget({ + Key? key, + required this.data, + required this.index, + required this.currentMid, + required this.onClickUp, + required this.onClickUpAni, + // required this.feedBack, + required this.itemPadding, + required this.contentWidth, + }) : super(key: key); + + @override + Widget build(BuildContext context) { return InkWell( onTap: () { feedBack(); @@ -174,9 +309,9 @@ class _UpPanelState extends State { EasyThrottle.throttle('follow', const Duration(milliseconds: 300), () { if (GlobalDataCache().enableDynamicSwitch) { - onClickUp(data, i); + onClickUp(data, index); } else { - onClickUpAni(data, i); + onClickUpAni(data, index); } }); } else if (data.type == 'live') { @@ -251,13 +386,12 @@ class _UpPanelState extends State { softWrap: false, textAlign: TextAlign.center, style: TextStyle( - color: currentMid.value == data.mid - ? Theme.of(context).colorScheme.primary - : Theme.of(context).colorScheme.outline, - fontSize: Theme.of(context) - .textTheme - .labelMedium! - .fontSize), + color: currentMid.value == data.mid + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.outline, + fontSize: + Theme.of(context).textTheme.labelMedium!.fontSize, + ), ), ), ), @@ -269,64 +403,3 @@ class _UpPanelState extends State { ); } } - -class _SliverHeaderDelegate extends SliverPersistentHeaderDelegate { - _SliverHeaderDelegate({required this.height, required this.child}); - - final double height; - final Widget child; - - @override - Widget build( - BuildContext context, double shrinkOffset, bool overlapsContent) { - return child; - } - - @override - double get maxExtent => height; - - @override - double get minExtent => height; - - @override - bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) => - true; -} - -class UpPanelSkeleton extends StatelessWidget { - const UpPanelSkeleton({super.key}); - - @override - Widget build(BuildContext context) { - return ListView.builder( - scrollDirection: Axis.horizontal, - physics: const NeverScrollableScrollPhysics(), - itemCount: 10, - itemBuilder: ((context, index) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 50, - height: 50, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.onInverseSurface, - borderRadius: BorderRadius.circular(50), - ), - ), - Container( - margin: const EdgeInsets.only(top: 6), - width: 45, - height: 12, - color: Theme.of(context).colorScheme.onInverseSurface, - ), - ], - ), - ); - }), - ); - } -} From b824b75bc64f5b45a784965a99424282c3b69bc9 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 23 Nov 2024 00:01:16 +0800 Subject: [PATCH 11/39] opt: enableDlna switch callFn --- lib/pages/setting/extra_setting.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index 3e82f2bd..004f3e9c 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -190,11 +190,14 @@ class _ExtraSettingState extends State { setKey: SettingBoxKey.enableRelatedVideo, defaultVal: true, ), - const SetSwitchItem( + SetSwitchItem( title: '视频投屏开关', subTitle: '打开后将在播放器右上角显示投屏入口', setKey: SettingBoxKey.enableDlna, defaultVal: false, + callFn: (bool val) { + GlobalDataCache.enableDlna = val; + }, ), ListTile( dense: false, From e1c7a74e1be2226527f5b1eafd7ffec07a59ed88 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 23 Nov 2024 01:15:32 +0800 Subject: [PATCH 12/39] feat: SponsorBlock switch --- lib/pages/setting/extra_setting.dart | 9 +++++++++ lib/pages/video/detail/controller.dart | 3 ++- lib/utils/global_data_cache.dart | 4 ++++ lib/utils/storage.dart | 3 ++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index 004f3e9c..f4b56508 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -199,6 +199,15 @@ class _ExtraSettingState extends State { 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), diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index da3b0cbc..cb2e324c 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -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'; @@ -198,7 +199,7 @@ class VideoDetailController extends GetxController }); /// 仅投稿视频skip - if (videoType == SearchType.video) { + if (videoType == SearchType.video && GlobalDataCache.enableSponsorBlock) { querySkipSegments(); } } diff --git a/lib/utils/global_data_cache.dart b/lib/utils/global_data_cache.dart index a421f829..90b42795 100644 --- a/lib/utils/global_data_cache.dart +++ b/lib/utils/global_data_cache.dart @@ -55,6 +55,8 @@ class GlobalDataCache { static late bool enableDynamicSwitch; // 投屏开关 static bool enableDlna = false; + // sponsorBlock开关 + static bool enableSponsorBlock = false; // 私有构造函数 GlobalDataCache._(); @@ -123,5 +125,7 @@ class GlobalDataCache { enableDynamicSwitch = setting.get(SettingBoxKey.enableDynamicSwitch, defaultValue: true); enableDlna = setting.get(SettingBoxKey.enableDlna, defaultValue: false); + enableSponsorBlock = + setting.get(SettingBoxKey.enableSponsorBlock, defaultValue: false); } } diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 49a5c734..9133314c 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -116,7 +116,8 @@ class SettingBoxKey { enableAutoExpand = 'enableAutoExpand', defaultHomePage = 'defaultHomePage', enableRelatedVideo = 'enableRelatedVideo', - enableDlna = 'enableDlna'; + enableDlna = 'enableDlna', + enableSponsorBlock = 'enableSponsorBlock'; /// 外观 static const String themeMode = 'themeMode', From 2db409b44909f2ce06a485248846e8ba67f12071 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 23 Nov 2024 15:15:58 +0800 Subject: [PATCH 13/39] opt: video intro skeleton --- lib/common/skeleton/video_intro.dart | 126 ++++++++++++++++++ lib/pages/video/detail/introduction/view.dart | 25 +--- 2 files changed, 133 insertions(+), 18 deletions(-) create mode 100644 lib/common/skeleton/video_intro.dart diff --git a/lib/common/skeleton/video_intro.dart b/lib/common/skeleton/video_intro.dart new file mode 100644 index 00000000..b7a5ec74 --- /dev/null +++ b/lib/common/skeleton/video_intro.dart @@ -0,0 +1,126 @@ +import 'package:flutter/material.dart'; +import '../constants.dart'; +import 'skeleton.dart'; + +class VideoIntroSkeleton extends StatelessWidget { + const VideoIntroSkeleton({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + Color bgColor = Theme.of(context).colorScheme.onInverseSurface; + return Skeleton( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 18), + Container( + width: double.infinity, + height: 20, + margin: const EdgeInsets.only(bottom: 6), + color: bgColor, + ), + Container( + width: 220, + height: 20, + margin: const EdgeInsets.only(bottom: 12), + color: bgColor, + ), + Row( + children: [ + Container( + width: 45, + height: 14, + color: bgColor, + ), + const SizedBox(width: 8), + Container( + width: 45, + height: 14, + color: bgColor, + ), + const SizedBox(width: 8), + Container( + width: 45, + height: 14, + color: bgColor, + ), + const Spacer(), + Container( + width: 35, + height: 14, + color: bgColor, + ), + const SizedBox(width: 4), + ], + ), + const SizedBox(height: 30), + LayoutBuilder(builder: (context, constraints) { + // 并列5个正方形 + double width = (constraints.maxWidth - 30) / 5; + return Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: List.generate(5, (index) { + return Container( + width: width - 24, + height: width - 24, + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.circular(16), + ), + ); + }), + ); + }), + const SizedBox(height: 20), + Container( + width: double.infinity, + height: 30, + margin: const EdgeInsets.symmetric(horizontal: 6), + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.circular(8), + ), + ), + const SizedBox(height: 20), + Row( + children: [ + ClipOval( + child: Container( + width: 44, + height: 44, + color: bgColor, + ), + ), + const SizedBox(width: 12), + Container( + width: 50, + height: 14, + color: bgColor, + ), + const SizedBox(width: 8), + Container( + width: 35, + height: 14, + color: bgColor, + ), + const Spacer(), + Container( + width: 55, + height: 30, + decoration: BoxDecoration( + color: bgColor, + borderRadius: BorderRadius.circular(16), + ), + ), + const SizedBox(width: 2) + ], + ), + const SizedBox(height: 10), + ], + ), + ), + ); + } +} diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 451173dd..d283d086 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -6,8 +6,8 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; -import 'package:lottie/lottie.dart'; import 'package:pilipala/common/constants.dart'; +import 'package:pilipala/common/skeleton/video_intro.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; @@ -76,10 +76,8 @@ class _VideoIntroPanelState extends State future: _futureBuilderFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { - if (snapshot.data == null) { - return const SliverToBoxAdapter(child: SizedBox()); - } - if (snapshot.data['status']) { + Map? data = snapshot.data; + if (data != null && data['status']) { // 请求成功 return Obx( () => VideoInfo( @@ -91,25 +89,16 @@ class _VideoIntroPanelState extends State } else { // 请求错误 return HttpError( - errMsg: snapshot.data['msg'], - btnText: snapshot.data['code'] == -404 || - snapshot.data['code'] == 62002 + errMsg: data?['msg'] ?? '请求异常', + btnText: (data?['code'] == -404 || data?['code'] == 62002) ? '返回上一页' : null, fn: () => Get.back(), ); } } else { - return SliverToBoxAdapter( - child: SizedBox( - height: 100, - child: Center( - child: Lottie.asset( - 'assets/loading.json', - width: 200, - ), - ), - ), + return const SliverToBoxAdapter( + child: VideoIntroSkeleton(), ); } }, From 79cd211976e05bc027e1951e71af632e2cedc110 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 23 Nov 2024 15:28:26 +0800 Subject: [PATCH 14/39] feat: back home when autoplay is off --- lib/pages/video/detail/view.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 0fb97066..488ed14d 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -909,6 +909,21 @@ class _VideoDetailPageState extends State icon: const Icon(FontAwesomeIcons.arrowLeft, size: 15), fuc: () => Get.back(), ), + const SizedBox(width: 8), + ComBtn( + icon: const Icon( + FontAwesomeIcons.house, + size: 15, + color: Colors.white, + ), + fuc: () async { + await vdCtr.plPlayerController.dispose(type: 'all'); + if (mounted) { + Navigator.popUntil( + context, (Route route) => route.isFirst); + } + }, + ), const Spacer(), ComBtn( icon: const Icon(Icons.history_outlined, size: 22), From e8166c9f829e9887fef01680ebbea0f90eaf8f16 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 23 Nov 2024 22:48:09 +0800 Subject: [PATCH 15/39] opt: toggle showSubtitleBtn --- lib/pages/video/detail/controller.dart | 9 +++++++++ lib/pages/video/detail/widgets/header_control.dart | 6 +++--- lib/plugin/pl_player/controller.dart | 5 +++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index da3b0cbc..ca5a73be 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -480,6 +480,15 @@ class VideoDetailController extends GetxController getDanmaku(subtitles); } } + headerControl = HeaderControl( + controller: plPlayerController, + videoDetailCtr: this, + floating: floating, + bvid: bvid, + videoType: videoType, + showSubtitleBtn: result['status'] && result['data'].subtitles.isNotEmpty, + ); + plPlayerController.setHeaderControl(headerControl); } // 获取弹幕 diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index f22bf846..d563396d 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -30,7 +30,7 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget { this.floating, this.bvid, this.videoType, - this.showSubtitleBtn, + this.showSubtitleBtn = true, super.key, }); final PlPlayerController? controller; @@ -38,7 +38,7 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget { final Floating? floating; final String? bvid; final SearchType? videoType; - final bool? showSubtitleBtn; + final bool showSubtitleBtn; @override State createState() => _HeaderControlState(); @@ -1326,7 +1326,7 @@ class _HeaderControlState extends State { ], /// 字幕 - if (widget.showSubtitleBtn ?? true) + if (widget.showSubtitleBtn) ComBtn( icon: const Icon( Icons.closed_caption_off, diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index de4cd9df..d1305aa7 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -929,6 +929,11 @@ class PlPlayerController { showControls.value = !val; } + /// 设置/更新顶部控制栏 + void setHeaderControl(PreferredSizeWidget? widget) { + headerControl = widget; + } + void toggleFullScreen(bool val) { _isFullScreen.value = val; } From e1948b159b0b6e129d993c1093f639d5a53cf7a4 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Nov 2024 01:16:33 +0800 Subject: [PATCH 16/39] feat: comment can be closed --- lib/models/common/comment_range_type.dart | 18 ++++ lib/pages/setting/extra_setting.dart | 83 ++++++++++++++++++- lib/pages/video/detail/controller.dart | 13 ++- .../video/detail/introduction/controller.dart | 17 ++-- lib/pages/video/detail/view.dart | 22 +++-- lib/utils/global_data_cache.dart | 28 ++++--- lib/utils/storage.dart | 3 +- 7 files changed, 156 insertions(+), 28 deletions(-) create mode 100644 lib/models/common/comment_range_type.dart diff --git a/lib/models/common/comment_range_type.dart b/lib/models/common/comment_range_type.dart new file mode 100644 index 00000000..979c84d8 --- /dev/null +++ b/lib/models/common/comment_range_type.dart @@ -0,0 +1,18 @@ +enum CommentRangeType { + video, + bangumi, + // dynamic, +} + +extension ActionTypeExtension on CommentRangeType { + String get value => [ + 'video', + 'bangumi', + // 'dynamic', + ][index]; + String get label => [ + '视频', + '番剧', + // '动态', + ][index]; +} diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index 004f3e9c..299f9094 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -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 { late String defaultSystemProxyHost; late String defaultSystemProxyPort; bool userLogin = false; + // 记录每个选项是否被选中的状态 + late List enableComment; @override void initState() { @@ -47,6 +50,8 @@ class _ExtraSettingState extends State { localCache.get(LocalCacheKey.systemProxyHost, defaultValue: ''); defaultSystemProxyPort = localCache.get(LocalCacheKey.systemProxyPort, defaultValue: ''); + enableComment = setting + .get(SettingBoxKey.enableComment, defaultValue: ['video', 'bangumi']); } // 设置代理 @@ -202,6 +207,82 @@ class _ExtraSettingState extends State { ListTile( dense: false, title: Text('评论展示', style: titleStyle), + onTap: () async { + List 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 +292,7 @@ class _ExtraSettingState extends State { context: context, builder: (context) { return SelectDialog( - title: '评论展示', + title: '评论排序', value: defaultReplySort, values: ReplySortType.values.map((e) { return {'title': e.titles, 'value': e.index}; diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index ca5a73be..3755233c 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -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 = [ + '简介', + 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); diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 24bd7db0..5af5d57a 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -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'; @@ -99,7 +100,11 @@ class VideoIntroController extends GetxController { } final VideoDetailController videoDetailCtr = Get.find(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,10 +474,12 @@ class VideoIntroController extends GetxController { // 重新请求评论 try { /// 未渲染回复组件时可能异常 - final VideoReplyController videoReplyCtr = - Get.find(tag: heroTag); - videoReplyCtr.aid = aid; - videoReplyCtr.queryReplyList(type: 'init'); + if (GlobalDataCache.enableComment.contains('video')) { + final VideoReplyController videoReplyCtr = + Get.find(tag: heroTag); + videoReplyCtr.aid = aid; + videoReplyCtr.queryReplyList(type: 'init'); + } } catch (_) {} this.bvid = bvid; await queryVideoIntro(cover: cover); diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 488ed14d..564ab65a 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -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 ); }, ), - 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, + ), + ) + ], ], ), ), diff --git a/lib/utils/global_data_cache.dart b/lib/utils/global_data_cache.dart index a421f829..01b68dc6 100644 --- a/lib/utils/global_data_cache.dart +++ b/lib/utils/global_data_cache.dart @@ -5,7 +5,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; @@ -55,6 +55,8 @@ class GlobalDataCache { static late bool enableDynamicSwitch; // 投屏开关 static bool enableDlna = false; + // 视频评论开关 + static List enableComment = ['video', 'bangumi']; // 私有构造函数 GlobalDataCache._(); @@ -67,18 +69,18 @@ class GlobalDataCache { // 异步初始化方法 static Future 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 = @@ -99,7 +101,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, @@ -117,11 +119,13 @@ 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); + settingBox.get(SettingBoxKey.enableDynamicSwitch, defaultValue: true); + enableDlna = settingBox.get(SettingBoxKey.enableDlna, defaultValue: false); + enableComment = settingBox + .get(SettingBoxKey.enableComment, defaultValue: ['video', 'bangumi']); } } diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 49a5c734..8fb00cb5 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -116,7 +116,8 @@ class SettingBoxKey { enableAutoExpand = 'enableAutoExpand', defaultHomePage = 'defaultHomePage', enableRelatedVideo = 'enableRelatedVideo', - enableDlna = 'enableDlna'; + enableDlna = 'enableDlna', + enableComment = 'enableComment'; /// 外观 static const String themeMode = 'themeMode', From 796db85b21125af56e51c50d65e14945e409815a Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Nov 2024 16:29:53 +0800 Subject: [PATCH 17/39] opt: videoPlayer control --- assets/images/video/dlna.png | Bin 0 -> 1372 bytes assets/images/video/fullscreen.png | Bin 0 -> 274 bytes assets/images/video/fullscreen_exit.png | Bin 0 -> 246 bytes assets/images/video/pip.png | Bin 0 -> 1072 bytes lib/pages/video/detail/controller.dart | 1 + .../video/detail/widgets/header_control.dart | 123 +++--------------- lib/plugin/pl_player/controller.dart | 72 +++++----- lib/plugin/pl_player/view.dart | 59 ++++++--- 8 files changed, 105 insertions(+), 150 deletions(-) create mode 100755 assets/images/video/dlna.png create mode 100755 assets/images/video/fullscreen.png create mode 100755 assets/images/video/fullscreen_exit.png create mode 100755 assets/images/video/pip.png diff --git a/assets/images/video/dlna.png b/assets/images/video/dlna.png new file mode 100755 index 0000000000000000000000000000000000000000..a5d658721fd044c54976a607a9a1cbaab4e73ded GIT binary patch literal 1372 zcmV-i1*7_jP)oQ2-H@gh1wrRq{RA*Ql!`y?JuzSq=-V1h@vD&g82vRLwyo` zl{RTXS`aCu&8b7rkeyCjWL^Kckj0knapmI-FxrK&C-XQhs)fVIX~`q z&YU@OE-cUjEzkmalasGgE2-qUdC>L`!_J`ZEN#_gjc7h;M3=R-umKy?qf$|iHsmwm zn9?dGrFCq!35|AeOmSuAO?5_bjoG)x9LLlizB1N~QNhn#<`#qV;Fv3UiFbLEF)B>Y z`_9)>C@fRI`Sy%@w0XWaq&BO^>g(6Csm>#ImAdqFDdK{jR+sg_BU4?SN=cH&wWd_z zNozDNNlK{`P`O+K&4p4%NnJ2Y;;KACjft8Ou9h@bUnOF;Moon3oS<4t%4(~QP-b5; zB{d?ett|3?I7Q2R+~*ly&wtWdiaRk-JyGXcK`C3vIM<)h2(92RmihYm_YCs^sLlB( z@A#K|2x{YFM}7NoU!@{cE=5p<>^>Ne+(tMxhk>&=mnQnw<7rG*kF9GBAuQ@eNf*cB3B-;UWR;^qHXbmdO|T{Ba1`2*>4w*&&#nal#*mu#tc^`g7j; zX$!&>vJn;wg5wZA5^&L8AP2b^jHMVO9@|#h6N~ArqA3^-#TjwaWET(U@m!MgTmw3s z^T89{>{ms7);q%vtz$L6IS+kiZdHvF_tBiymM&u;dkG2PcrjwL@`4w@xie>8+*edq z+dzakGQqaK==vBbbV=ob`Og?W*OZJ@tx=O9O8WzeSfNg9_?WFhx$4x4 zK>Yg+M@plb_6;>#k=P9MtJDuElEW}x>%T;r>aJGaWsN*SHJiEeo z^v=9(S|P7+g(@?5h$>D4EeufwK#C!DI)CKMUq_97d6{?EX|E6|eqo0*o}F5)yP7C? z)$5pcI&IOgoj0VE4glzYQW`S76B^bQ>%1KWWlrd>W(NgT>$;?e1z6StXt&0#3HLRs zU6y;7Ms?qcAJ=Yk@5oONC0$p(xTM8u)+4z}C^4hHozy)o0v%GuZ058^G@wm0xHoA) zBgR)ImC+&4BHdGRMqN9hgj_vRvlbV2n^kJkjahd0sSeaC85Kz-71P=|ylWLx(kM+! zY6aD)Zw%i2#qN;3n_o`(>b&e9H#LSPr;E*za7>BHmy+ ze*8_plgx7%1d9vw<5CU`Q^}uvnscnrq@{e$^9)l7Ob~Zo46o+6QOb!VLCMvm0)1q# ze4>X*5=GlSLT|wW(Gy|OBB{?KlFTh4#U*_bZV@=D7PCEro6!(BJubqK3SMPN(8>P! e*8(k2Vfqj3bVE?>l~cn20000YP);M1& literal 0 HcmV?d00001 diff --git a/assets/images/video/fullscreen_exit.png b/assets/images/video/fullscreen_exit.png new file mode 100755 index 0000000000000000000000000000000000000000..9881ed1d91ae66a4ad74165ab928112e15400f41 GIT binary patch literal 246 zcmVbFY}^EsZi+BEQ6T=DZ}v434nEY=mNk_kRU;V1o<5`V$UJ79!3ytUi^*$)WIhU zi`Gp!lH}HwhE^Ko`{~q(ak;f*U;)J*!;sP{4sE>Vu2&p#06e*6)|t6Q>pnNShkp!$ w1PK!K56}vLYj|h^fGguO?=z;ZrKUQ01L+?Gh~%R}YXATM07*qoM6N<$f*=oM!~g&Q literal 0 HcmV?d00001 diff --git a/assets/images/video/pip.png b/assets/images/video/pip.png new file mode 100755 index 0000000000000000000000000000000000000000..1b7421256a1088dc5a8ccb7718564f9218a9fda0 GIT binary patch literal 1072 zcmV-01kd}4P)7%g6otPRrzV7&pOh-0rBrQ_1yU+NWI;D5i;|-9Cl+a?5|vF6f-OHwBowI|V2M<* ziV#&1e*$IEw2e}cuxUX`i;xJhi_{R3Hfn-WO6oYV4+}p}oQXa5%-HV6cQt-*X5N`I z=iPhe8tPGxdep-^OyObepo4~rt~A4SbGyuQ)vGU+RCVHt-qF@l0CwxFq>QQ=3wq59 z!am*5nraarsjv*RUGolv#fra>w4{Hv;{5)wpfL3VFJXWcA|yG@7&8@=WrR+8c@aZn zb~z52VK)y?ScFMsbY891*^27WxLqfsDMj4VgI12q8rPQUWdv=}h|(6w5%=W0BxzPD zbyPPosa4BXCEstHc-YxK-&H?9>ZIl3PHvB6vtmvIEu5=CmL9XKHnArkM2mC6)f#}f z;T%1d4`N-Xt1jve>l5{P$ZWrM_y&?y(M_}acnE;kc{1Gl@dh#CWYoh9=|0zNv{EAR1YthsvpiNt)KVR#mNG7H z@wIbiH)Gm)7eJT{{hYVTXrz;$)LDBbFezT;lHFEOS{c_*bn*0P{D!+~T%P^0)X_$7&7&Oq}OQvt$e2EQ7pVa}Z!Ac!ekn zw)7v2~SA33;8v^p^pT? zZQwWw+Q|^HoO**$jA;s&=@3rTWOR_TbTDe-dj`|Sjm^?=}%^vehTrrujd7`moDZk{yJ+`x}tP}q- zSIaiKK9=96VWoV0r7!7(Vig6U{efBu3GK}nW~lCzwsB!|DlQ{-b0*71gX@zg65wX1 z0zt^y#rM~rWtT(IQQtf?_|k&Ae>JCu91}CF+05tPxV00!pV3Sk?G}U)7wvGr?=DT4 zu1-_-`kW*`wUxe!FMM`t8pCI*9Eh)Mn=HZsMyuVeDe@d9tv5Jh$DZML4RMZmk&pO0 zOqf))+BgGwy7gB4yq+$Q=z>Mh#x(T-AA|km^VY?7h7_&bP8yFm z4l_&{U(R0dO4#NUdw7?NmXD&vm1*LeI#B*&E_;2k|2wwQ#-ko~?iaI~%b5Jb{Q*H- zrj4E9{Rp5F0VO%5v<51*t71xMH2{R0nsj-JP%!rD4`sAarmI+1LK8}BGUq2M$Hsu> qeDE-*fpr#4MWKZ8nDwYfUi=T2nexsIOUV5I0000 { final Box localCache = GStorage.localCache; final Box videoStorage = GStorage.video; late List speedsList; - double buttonSpace = 8; + double buttonSpace = 4; RxBool isFullScreen = false.obs; late String heroTag; late VideoIntroController videoIntroController; @@ -486,65 +486,6 @@ class _HeaderControlState extends State { }); } - /// 选择倍速 - void showSetSpeedSheet() { - final double currentSpeed = widget.controller!.playbackSpeed; - showDialog( - context: Get.context!, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('播放速度'), - content: StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return Wrap( - spacing: 8, - runSpacing: 2, - children: [ - for (final double i in speedsList) ...[ - if (i == currentSpeed) ...[ - FilledButton( - onPressed: () async { - // setState(() => currentSpeed = i), - await widget.controller!.setPlaybackSpeed(i); - Get.back(); - }, - child: Text(i.toString()), - ), - ] else ...[ - FilledButton.tonal( - onPressed: () async { - // setState(() => currentSpeed = i), - await widget.controller!.setPlaybackSpeed(i); - Get.back(); - }, - child: Text(i.toString()), - ), - ] - ] - ], - ); - }), - actions: [ - TextButton( - onPressed: () => Get.back(), - child: Text( - '取消', - style: TextStyle(color: Theme.of(context).colorScheme.outline), - ), - ), - TextButton( - onPressed: () async { - await widget.controller!.setDefaultSpeed(); - Get.back(); - }, - child: const Text('默认速度'), - ), - ], - ); - }, - ); - } - /// 选择画质 void showSetVideoQa() { final List videoFormat = videoInfo.supportFormats!; @@ -1222,7 +1163,7 @@ class _HeaderControlState extends State { fuc: () async { // 销毁播放器实例 await widget.controller!.dispose(type: 'all'); - if (mounted) { + if (context.mounted) { Navigator.popUntil( context, (Route route) => route.isFirst); } @@ -1230,21 +1171,9 @@ class _HeaderControlState extends State { ), ], const Spacer(), - // ComBtn( - // icon: const Icon( - // FontAwesomeIcons.cropSimple, - // size: 15, - // color: Colors.white, - // ), - // fuc: () => _.screenshot(), - // ), if (GlobalDataCache.enableDlna) ...[ ComBtn( - icon: const Icon( - Icons.cast, - size: 19, - color: Colors.white, - ), + icon: Image.asset('assets/images/video/dlna.png', width: 19), fuc: () async { showDialog( context: context, @@ -1255,7 +1184,10 @@ class _HeaderControlState extends State { ); }, ), + SizedBox(width: buttonSpace), ], + + /// 弹幕开关(全屏时) if (isFullScreen.value) ...[ SizedBox( width: 56, @@ -1271,6 +1203,7 @@ class _HeaderControlState extends State { ), ), ), + SizedBox(width: buttonSpace), SizedBox( width: 34, height: 34, @@ -1292,8 +1225,10 @@ class _HeaderControlState extends State { ), ), ), + SizedBox(width: buttonSpace), ], - SizedBox(width: buttonSpace), + + /// pip if (Platform.isAndroid) ...[ SizedBox( width: 34, @@ -1318,9 +1253,9 @@ class _HeaderControlState extends State { await widget.floating!.enable(aspectRatio: aspectRatio); } else {} }, - icon: const Icon( - Icons.picture_in_picture_outlined, - size: 19, + icon: Image.asset( + 'assets/images/video/pip.png', + width: 19, color: Colors.white, ), ), @@ -1329,37 +1264,21 @@ class _HeaderControlState extends State { ], /// 字幕 - if (widget.showSubtitleBtn) + if (widget.showSubtitleBtn) ...[ ComBtn( - icon: const Icon( - Icons.closed_caption_off, - size: 22, - color: Colors.white, + icon: Icon( + FontAwesomeIcons.closedCaptioning, + size: 16, + color: Colors.white.withOpacity(0.9), ), fuc: () => showSubtitleDialog(), ), - SizedBox(width: buttonSpace), - Obx( - () => SizedBox( - width: 45, - height: 34, - child: TextButton( - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - ), - onPressed: () => showSetSpeedSheet(), - child: Text( - '${_.playbackSpeed}X', - style: textStyle, - ), - ), - ), - ), - SizedBox(width: buttonSpace), + SizedBox(width: buttonSpace), + ], ComBtn( icon: const Icon( Icons.more_vert_outlined, - size: 18, + size: 19, color: Colors.white, ), fuc: () => showSettingSheet(), diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 2013d5b2..7291cc98 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -6,6 +6,7 @@ import 'dart:typed_data'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_volume_controller/flutter_volume_controller.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; @@ -113,12 +114,13 @@ class PlPlayerController { // final Durations durations; List> videoFitType = [ - {'attr': BoxFit.contain, 'desc': '包含'}, - {'attr': BoxFit.cover, 'desc': '覆盖'}, - {'attr': BoxFit.fill, 'desc': '填充'}, - {'attr': BoxFit.fitHeight, 'desc': '高度适应'}, - {'attr': BoxFit.fitWidth, 'desc': '宽度适应'}, - {'attr': BoxFit.scaleDown, 'desc': '缩小适应'}, + {'attr': BoxFit.contain, 'desc': '自动'}, + {'attr': BoxFit.cover, 'desc': '铺满'}, + {'attr': BoxFit.fill, 'desc': '填满'}, + {'attr': BoxFit.fitHeight, 'desc': '等高'}, + {'attr': BoxFit.fitWidth, 'desc': '等宽'}, + {'attr': BoxFit.scaleDown, 'desc': '缩放'}, + {'attr': BoxFit.none, 'desc': '原始'}, ]; PreferredSizeWidget? headerControl; @@ -827,47 +829,53 @@ class PlPlayerController { } /// Toggle Change the videofit accordingly - void toggleVideoFit() { - showDialog( - context: Get.context!, - builder: (context) { - return AlertDialog( - title: const Text('画面比例'), - content: StatefulBuilder(builder: (context, StateSetter setState) { - return Wrap( - alignment: WrapAlignment.start, + void toggleVideoFit(String toggleType) { + if (toggleType == 'press') { + final String videoFitDEsc = _videoFitDesc.value; + final int index = videoFitType.indexWhere( + (element) => element['desc'] == videoFitDEsc, + ); + final int newIndex = index + 1 >= videoFitType.length ? 0 : index + 1; + _videoFit.value = videoFitType[newIndex]['attr']; + _videoFitDesc.value = videoFitType[newIndex]['desc']; + setVideoFit(); + SmartDialog.showToast('画面比例:${videoFitType[newIndex]['desc']}'); + } else { + void onPressed(item) { + _videoFit.value = item['attr']; + _videoFitDesc.value = item['desc']; + setVideoFit(); + Navigator.of(Get.context!).pop(); + } + + showDialog( + context: Get.context!, + builder: (context) { + return AlertDialog( + title: const Text('画面比例'), + content: Wrap( spacing: 8, runSpacing: 2, children: [ for (var i in videoFitType) ...[ if (_videoFit.value == i['attr']) ...[ FilledButton( - onPressed: () async { - _videoFit.value = i['attr']; - _videoFitDesc.value = i['desc']; - setVideoFit(); - Get.back(); - }, + onPressed: () => onPressed(i), child: Text(i['desc']), ), ] else ...[ FilledButton.tonal( - onPressed: () async { - _videoFit.value = i['attr']; - _videoFitDesc.value = i['desc']; - setVideoFit(); - Get.back(); - }, + onPressed: () => onPressed(i), child: Text(i['desc']), ), ] ] ], - ); - }), - ); - }, - ); + ), + ); + }, + ); + } } /// 缓存fit diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index c73bc55f..415830e0 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -301,16 +301,22 @@ class _PLVideoPlayerState extends State /// 画面比例 BottomControlType.fit: SizedBox( + width: 45, height: 30, child: TextButton( - onPressed: () => _.toggleVideoFit(), + onPressed: () => _.toggleVideoFit('press'), + onLongPress: () => _.toggleVideoFit('longPress'), style: ButtonStyle( padding: MaterialStateProperty.all(EdgeInsets.zero), ), child: Obx( () => Text( _.videoFitDEsc.value, - style: const TextStyle(color: Colors.white, fontSize: 13), + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), ), ), ), @@ -320,29 +326,49 @@ class _PLVideoPlayerState extends State BottomControlType.speed: SizedBox( width: 45, height: 34, - child: TextButton( - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - ), - onPressed: () {}, - child: Obx( - () => Text( - '${_.playbackSpeed.toString()}X', - style: textStyle, + child: PopupMenuButton( + tooltip: '更改播放速度', + onSelected: (double value) { + _.setPlaybackSpeed(value); + }, + initialValue: _.playbackSpeed, + color: Colors.black.withOpacity(0.8), + itemBuilder: (BuildContext context) { + return _.speedsList.map((double speed) { + return PopupMenuItem( + height: 40, + padding: const EdgeInsets.only(left: 20), + value: speed, + child: Text( + '${speed}x', + style: textStyle.copyWith(fontWeight: FontWeight.bold), + ), + ); + }).toList(); + }, + child: Container( + width: 45, + height: 34, + alignment: Alignment.center, + margin: const EdgeInsets.only(right: 4), + child: Obx( + () => Text( + '${_.playbackSpeed.toString()}x', + style: textStyle.copyWith(fontWeight: FontWeight.bold), + ), ), ), ), ), - /// 字幕 /// 全屏 BottomControlType.fullscreen: ComBtn( icon: Obx( - () => Icon( + () => Image.asset( _.isFullScreen.value - ? FontAwesomeIcons.compress - : FontAwesomeIcons.expand, - size: 15, + ? 'assets/images/video/fullscreen_exit.png' + : 'assets/images/video/fullscreen.png', + width: 19, color: Colors.white, ), ), @@ -359,6 +385,7 @@ class _PLVideoPlayerState extends State BottomControlType.time, BottomControlType.space, BottomControlType.fit, + BottomControlType.speed, BottomControlType.fullscreen, ]; for (var i = 0; i < userSpecifyItem.length; i++) { From 5201c66ac163af98fa1ad0047a2b240857b4015e Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Nov 2024 17:38:35 +0800 Subject: [PATCH 18/39] feat: hardwareDecodeFormat --- lib/pages/setting/play_setting.dart | 31 ++++++++++++++++++++++++++++ lib/plugin/pl_player/controller.dart | 1 + lib/utils/global_data_cache.dart | 5 +++++ lib/utils/storage.dart | 3 ++- 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/pages/setting/play_setting.dart b/lib/pages/setting/play_setting.dart index 7090bfaf..c6d7fe0b 100644 --- a/lib/pages/setting/play_setting.dart +++ b/lib/pages/setting/play_setting.dart @@ -31,6 +31,7 @@ class _PlaySettingState extends State { late int defaultFullScreenMode; late int defaultBtmProgressBehavior; late String defaultAoOutput; + late String hardwareDecodeFormat; @override void initState() { @@ -49,6 +50,8 @@ class _PlaySettingState extends State { defaultValue: BtmProgresBehavior.values.first.code); defaultAoOutput = setting.get(SettingBoxKey.defaultAoOutput, defaultValue: '0'); + hardwareDecodeFormat = setting.get(SettingBoxKey.hardwareDecodeFormat, + defaultValue: Platform.isAndroid ? 'auto-safe' : 'auto'); } @override @@ -294,6 +297,34 @@ class _PlaySettingState extends State { } }, ), + ListTile( + dense: false, + title: Text('硬解方式', style: titleStyle), + subtitle: Text( + '当前硬解方式(--hwdec):$hardwareDecodeFormat', + style: subTitleStyle, + ), + onTap: () async { + String? result = await showDialog( + context: context, + builder: (context) { + return SelectDialog( + title: '硬解方式', + value: hardwareDecodeFormat, + values: ['no', 'auto-safe', 'auto', 'yes', 'auto-copy'] + .map((e) { + return {'title': e, 'value': e}; + }).toList()); + }, + ); + if (result != null) { + setting.put(SettingBoxKey.hardwareDecodeFormat, result); + hardwareDecodeFormat = result; + GlobalDataCache.hardwareDecodeFormat = result; + setState(() {}); + } + }, + ), ListTile( dense: false, title: Text('默认全屏方式', style: titleStyle), diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 2013d5b2..075a2e91 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -470,6 +470,7 @@ class PlPlayerController { configuration: VideoControllerConfiguration( enableHardwareAcceleration: enableHA, androidAttachSurfaceAfterVideoParameters: false, + hwdec: enableHA ? GlobalDataCache.hardwareDecodeFormat : null, ), ); diff --git a/lib/utils/global_data_cache.dart b/lib/utils/global_data_cache.dart index a421f829..911a4285 100644 --- a/lib/utils/global_data_cache.dart +++ b/lib/utils/global_data_cache.dart @@ -1,3 +1,4 @@ +import 'dart:io'; import 'package:hive/hive.dart'; import 'package:pilipala/models/user/info.dart'; import 'package:pilipala/plugin/pl_player/models/play_repeat.dart'; @@ -55,6 +56,8 @@ class GlobalDataCache { static late bool enableDynamicSwitch; // 投屏开关 static bool enableDlna = false; + // 硬件解码格式 + static late String hardwareDecodeFormat; // 私有构造函数 GlobalDataCache._(); @@ -123,5 +126,7 @@ class GlobalDataCache { enableDynamicSwitch = setting.get(SettingBoxKey.enableDynamicSwitch, defaultValue: true); enableDlna = setting.get(SettingBoxKey.enableDlna, defaultValue: false); + hardwareDecodeFormat = setting.get(SettingBoxKey.hardwareDecodeFormat, + defaultValue: Platform.isAndroid ? 'auto-safe' : 'auto'); } } diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 49a5c734..04896341 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -116,7 +116,8 @@ class SettingBoxKey { enableAutoExpand = 'enableAutoExpand', defaultHomePage = 'defaultHomePage', enableRelatedVideo = 'enableRelatedVideo', - enableDlna = 'enableDlna'; + enableDlna = 'enableDlna', + hardwareDecodeFormat = 'hardwareDecodeFormat'; /// 外观 static const String themeMode = 'themeMode', From 747ed377b510a66d98cd4559cd83f0cd2ee805b4 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Nov 2024 17:46:20 +0800 Subject: [PATCH 19/39] mod --- lib/pages/whisper_detail/view.dart | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart index 3c3d9f18..e70c6f3c 100644 --- a/lib/pages/whisper_detail/view.dart +++ b/lib/pages/whisper_detail/view.dart @@ -101,25 +101,11 @@ class _WhisperDetailPageState extends State Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - automaticallyImplyLeading: false, title: SizedBox( - width: double.infinity, + width: double.maxFinite, height: 50, child: Row( children: [ - SizedBox( - width: 34, - height: 34, - child: IconButton( - onPressed: () => Get.back(), - icon: Icon( - Icons.arrow_back_ios, - size: 18, - color: Theme.of(context).colorScheme.onPrimaryContainer, - ), - ), - ), - const SizedBox(width: 10), GestureDetector( onTap: () { feedBack(); From 17a87d23366419ff1ea7ccb226ce18ad6adc9395 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Nov 2024 22:08:45 +0800 Subject: [PATCH 20/39] fix: liveRoom layout error --- lib/http/init.dart | 11 ++++++---- lib/pages/live_room/view.dart | 41 +++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/lib/http/init.dart b/lib/http/init.dart index 03de43b7..9c0f368c 100644 --- a/lib/http/init.dart +++ b/lib/http/init.dart @@ -68,7 +68,7 @@ class Request { // 从cookie中获取 csrf token static Future getCsrf() async { List 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 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", diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 11864391..ced55e37 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -312,25 +312,28 @@ class _LiveRoomPageState extends State ), ), // 消息列表 - 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, + ), ), ), ), From ea900ffe4eaf3f4ceef1d3b57064b845a5045844 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 24 Nov 2024 22:53:48 +0800 Subject: [PATCH 21/39] opt: jumpTo rebound --- lib/common/pages_bottom_sheet.dart | 64 ++++++++++++++++-------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/lib/common/pages_bottom_sheet.dart b/lib/common/pages_bottom_sheet.dart index dd8c5490..fa6f61c7 100644 --- a/lib/common/pages_bottom_sheet.dart +++ b/lib/common/pages_bottom_sheet.dart @@ -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 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? _listObserverControllerList; @@ -163,6 +165,9 @@ class _PagesBottomSheetState extends State ); }, ); + } else { + _gridObserverController = + GridObserverController(controller: _gridScrollController); } } @@ -185,18 +190,12 @@ class _PagesBottomSheetState extends State ); } } + } 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 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 : 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, + ); + }, + ), ), ), ), From 0ae6238d0e4bb39152ad0ff249fc465d39950bc3 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 25 Nov 2024 22:39:04 +0800 Subject: [PATCH 22/39] opt: pl_gallery layout --- .../pl_gallery/interactiveviewer_gallery.dart | 109 +++++++++--------- 1 file changed, 53 insertions(+), 56 deletions(-) diff --git a/lib/plugin/pl_gallery/interactiveviewer_gallery.dart b/lib/plugin/pl_gallery/interactiveviewer_gallery.dart index f0b11619..88c9129c 100644 --- a/lib/plugin/pl_gallery/interactiveviewer_gallery.dart +++ b/lib/plugin/pl_gallery/interactiveviewer_gallery.dart @@ -234,17 +234,17 @@ class _InteractiveviewerGalleryState extends State @override Widget build(BuildContext context) { - return InteractiveViewerBoundary( - controller: _transformationController, - boundaryWidth: MediaQuery.of(context).size.width, - onScaleChanged: _onScaleChanged, - onLeftBoundaryHit: _onLeftBoundaryHit, - onRightBoundaryHit: _onRightBoundaryHit, - onNoBoundaryHit: _onNoBoundaryHit, - maxScale: widget.maxScale, - minScale: widget.minScale, - child: Stack(children: [ - CustomDismissible( + return Stack(children: [ + InteractiveViewerBoundary( + controller: _transformationController, + boundaryWidth: MediaQuery.of(context).size.width, + onScaleChanged: _onScaleChanged, + onLeftBoundaryHit: _onLeftBoundaryHit, + onRightBoundaryHit: _onRightBoundaryHit, + onNoBoundaryHit: _onNoBoundaryHit, + maxScale: widget.maxScale, + minScale: widget.minScale, + child: CustomDismissible( onDismissed: () { Navigator.of(context).pop(); widget.onDismissed?.call(_pageController!.page!.floor()); @@ -275,53 +275,50 @@ class _InteractiveviewerGalleryState extends State }, ), ), - Positioned( - bottom: 0, - left: 0, - right: 0, - child: Container( - padding: EdgeInsets.fromLTRB( - 12, 8, 20, MediaQuery.of(context).padding.bottom + 8), - decoration: _enablePageView - ? BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.transparent, - Colors.black.withOpacity(0.3) - ], - ), - ) - : null, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - IconButton( - icon: const Icon(Icons.close, color: Colors.white), - onPressed: () { - Navigator.of(context).pop(); - widget.onDismissed?.call(_pageController!.page!.floor()); - }, - ), - widget.sources.length > 1 - ? Text( - "${currentIndex! + 1}/${widget.sources.length}", - style: const TextStyle(color: Colors.white), - ) - : const SizedBox(), - PopupMenuButton( - itemBuilder: (context) { - return _buildPopupMenuList(); - }, - child: const Icon(Icons.more_horiz, color: Colors.white), - ), - ], - ), + ), + Positioned( + bottom: 0, + left: 0, + right: 0, + child: Container( + padding: EdgeInsets.fromLTRB( + 12, 8, 20, MediaQuery.of(context).padding.bottom + 8), + decoration: _enablePageView + ? BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [Colors.transparent, Colors.black.withOpacity(0.3)], + ), + ) + : null, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + IconButton( + icon: const Icon(Icons.close, color: Colors.white), + onPressed: () { + Navigator.of(context).pop(); + widget.onDismissed?.call(_pageController!.page!.floor()); + }, + ), + widget.sources.length > 1 + ? Text( + "${currentIndex! + 1}/${widget.sources.length}", + style: const TextStyle(color: Colors.white), + ) + : const SizedBox(), + PopupMenuButton( + itemBuilder: (context) { + return _buildPopupMenuList(); + }, + child: const Icon(Icons.more_horiz, color: Colors.white), + ), + ], ), ), - ]), - ); + ), + ]); } // 图片分享 From 859ee82367162c82a92d1cd7bd0f15fa8122d18a Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 25 Nov 2024 23:40:48 +0800 Subject: [PATCH 23/39] opt: bottomSheet DragHandle --- lib/common/widgets/drag_handle.dart | 25 +++ lib/common/widgets/video_card_h.dart | 20 +-- lib/common/widgets/video_card_v.dart | 20 +-- lib/pages/bangumi/introduction/view.dart | 20 +-- .../introduction/widgets/intro_detail.dart | 154 ++++++++---------- lib/pages/dynamics/widgets/author_panel.dart | 21 +-- .../detail/reply/widgets/reply_item.dart | 20 +-- lib/pages/video/detail/widgets/ai_detail.dart | 36 ++-- .../video/detail/widgets/header_control.dart | 18 +- .../pl_gallery/interactiveviewer_gallery.dart | 22 +-- 10 files changed, 129 insertions(+), 227 deletions(-) create mode 100644 lib/common/widgets/drag_handle.dart diff --git a/lib/common/widgets/drag_handle.dart b/lib/common/widgets/drag_handle.dart new file mode 100644 index 00000000..1143a732 --- /dev/null +++ b/lib/common/widgets/drag_handle.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; + +class DragHandle extends StatelessWidget { + const DragHandle({super.key}); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: Navigator.of(context).pop, + child: SizedBox( + height: 36, + child: Center( + child: Container( + width: 32, + height: 4, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.outline, + borderRadius: BorderRadius.circular(4), + ), + ), + ), + ), + ); + } +} diff --git a/lib/common/widgets/video_card_h.dart b/lib/common/widgets/video_card_h.dart index 78c4ba87..b662a3b0 100644 --- a/lib/common/widgets/video_card_h.dart +++ b/lib/common/widgets/video_card_h.dart @@ -12,6 +12,7 @@ import '../../http/video.dart'; import '../../utils/utils.dart'; import '../constants.dart'; import 'badge.dart'; +import 'drag_handle.dart'; import 'network_img_layer.dart'; import 'stat/danmu.dart'; import 'stat/view.dart'; @@ -373,27 +374,12 @@ class MorePanel extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return Padding( padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), child: Column( mainAxisSize: MainAxisSize.min, children: [ - InkWell( - onTap: () => Get.back(), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.outline, - borderRadius: const BorderRadius.all(Radius.circular(3))), - ), - ), - ), - ), + const DragHandle(), ListTile( onTap: () async => await menuActionHandler('block'), minLeadingWidth: 0, diff --git a/lib/common/widgets/video_card_v.dart b/lib/common/widgets/video_card_v.dart index 8cec3523..72cfb998 100644 --- a/lib/common/widgets/video_card_v.dart +++ b/lib/common/widgets/video_card_v.dart @@ -5,6 +5,7 @@ import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/image_save.dart'; import 'package:pilipala/utils/route_push.dart'; import '../../models/model_rec_video_item.dart'; +import 'drag_handle.dart'; import 'stat/danmu.dart'; import 'stat/view.dart'; import '../../http/dynamics.dart'; @@ -368,27 +369,12 @@ class MorePanel extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return Padding( padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), child: Column( mainAxisSize: MainAxisSize.min, children: [ - InkWell( - onTap: () => Get.back(), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.outline, - borderRadius: const BorderRadius.all(Radius.circular(3))), - ), - ), - ), - ), + const DragHandle(), ListTile( onTap: () async => await menuActionHandler('block'), minLeadingWidth: 0, diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index 75e293c4..4fc6a1b1 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -5,6 +5,7 @@ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/widgets/badge.dart'; +import 'package:pilipala/common/widgets/drag_handle.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/stat/danmu.dart'; import 'package:pilipala/common/widgets/stat/view.dart'; @@ -445,27 +446,12 @@ class BangumiStatusWidget extends StatelessWidget { } Widget morePanel(BuildContext context, BangumiIntroController ctr) { - return Container( + return Padding( padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), child: Column( mainAxisSize: MainAxisSize.min, children: [ - InkWell( - onTap: () => Get.back(), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.outline, - borderRadius: const BorderRadius.all(Radius.circular(3))), - ), - ), - ), - ), + const DragHandle(), ...ctr.followStatusList .map( (e) => ListTile( diff --git a/lib/pages/bangumi/introduction/widgets/intro_detail.dart b/lib/pages/bangumi/introduction/widgets/intro_detail.dart index a4c469de..04c035ed 100644 --- a/lib/pages/bangumi/introduction/widgets/intro_detail.dart +++ b/lib/pages/bangumi/introduction/widgets/intro_detail.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; +import 'package:pilipala/common/widgets/drag_handle.dart'; import 'package:pilipala/common/widgets/stat/danmu.dart'; import 'package:pilipala/common/widgets/stat/view.dart'; import 'package:pilipala/utils/storage.dart'; @@ -23,94 +24,81 @@ class IntroDetail extends StatelessWidget { color: Theme.of(context).colorScheme.onSurface, ); return Container( - color: Theme.of(context).colorScheme.surface, - padding: const EdgeInsets.only(left: 14, right: 14), + padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), height: sheetHeight, child: Column( children: [ - Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .onSecondaryContainer - .withOpacity(0.5), - borderRadius: const BorderRadius.all(Radius.circular(3))), - ), - ), - ), + const DragHandle(), Expanded( - child: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - bangumiDetail!.title, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, + child: Padding( + padding: const EdgeInsets.only(left: 16, right: 16), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + bangumiDetail!.title, + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + ), ), - ), - const SizedBox(height: 4), - Row( - children: [ - StatView( - view: bangumiDetail!.stat!['views'], - size: 'medium', - ), - const SizedBox(width: 6), - StatDanMu( - danmu: bangumiDetail!.stat!['danmakus'], - size: 'medium', - ), - ], - ), - const SizedBox(height: 4), - Row( - children: [ - Text( - bangumiDetail!.areas!.first['name'], - style: smallTitle, - ), - const SizedBox(width: 6), - Text( - bangumiDetail!.publish!['pub_time_show'], - style: smallTitle, - ), - const SizedBox(width: 6), - Text( - bangumiDetail!.newEp!['desc'], - style: smallTitle, - ), - ], - ), - const SizedBox(height: 20), - Text( - '简介:', - style: Theme.of(context).textTheme.titleMedium, - ), - const SizedBox(height: 4), - Text( - '${bangumiDetail!.evaluate!}', - style: smallTitle.copyWith(fontSize: 13), - ), - const SizedBox(height: 20), - Text( - '声优:', - style: Theme.of(context).textTheme.titleMedium, - ), - const SizedBox(height: 4), - Text( - bangumiDetail.actors, - style: smallTitle.copyWith(fontSize: 13), - ), - SizedBox(height: MediaQuery.of(context).padding.bottom + 20) - ], + const SizedBox(height: 4), + Row( + children: [ + StatView( + view: bangumiDetail!.stat!['views'], + size: 'medium', + ), + const SizedBox(width: 6), + StatDanMu( + danmu: bangumiDetail!.stat!['danmakus'], + size: 'medium', + ), + ], + ), + const SizedBox(height: 4), + Row( + children: [ + Text( + bangumiDetail!.areas!.first['name'], + style: smallTitle, + ), + const SizedBox(width: 6), + Text( + bangumiDetail!.publish!['pub_time_show'], + style: smallTitle, + ), + const SizedBox(width: 6), + Text( + bangumiDetail!.newEp!['desc'], + style: smallTitle, + ), + ], + ), + const SizedBox(height: 20), + Text( + '简介:', + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(height: 4), + Text( + '${bangumiDetail!.evaluate!}', + style: smallTitle.copyWith(fontSize: 13), + ), + const SizedBox(height: 20), + Text( + '声优:', + style: Theme.of(context).textTheme.titleMedium, + ), + const SizedBox(height: 4), + Text( + bangumiDetail.actors, + style: smallTitle.copyWith(fontSize: 13), + ), + SizedBox(height: MediaQuery.of(context).padding.bottom + 20) + ], + ), ), ), ) diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index 8acdc26a..64068b0a 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -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/common/widgets/drag_handle.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/http/user.dart'; import 'package:pilipala/utils/feed_back.dart'; @@ -108,28 +109,12 @@ class MorePanel extends StatelessWidget { @override Widget build(BuildContext context) { - return Container( + return Padding( padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), - // clipBehavior: Clip.hardEdge, child: Column( mainAxisSize: MainAxisSize.min, children: [ - InkWell( - onTap: () => Get.back(), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.outline, - borderRadius: const BorderRadius.all(Radius.circular(3))), - ), - ), - ), - ), + const DragHandle(), ListTile( onTap: () async { try { diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index e0a6d07f..a453a0fb 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -7,6 +7,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/widgets/badge.dart'; +import 'package:pilipala/common/widgets/drag_handle.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/http/reply.dart'; import 'package:pilipala/models/common/reply_type.dart'; @@ -1117,27 +1118,12 @@ class MorePanel extends StatelessWidget { ColorScheme colorScheme = Theme.of(context).colorScheme; TextTheme textTheme = Theme.of(context).textTheme; Color errorColor = colorScheme.error; - return Container( + return Padding( padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), child: Column( mainAxisSize: MainAxisSize.min, children: [ - InkWell( - onTap: () => Get.back(), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: colorScheme.outline, - borderRadius: const BorderRadius.all(Radius.circular(3))), - ), - ), - ), - ), + const DragHandle(), ListTile( onTap: () async => await menuActionHandler('copyAll'), minLeadingWidth: 0, diff --git a/lib/pages/video/detail/widgets/ai_detail.dart b/lib/pages/video/detail/widgets/ai_detail.dart index c17591fb..a82e3506 100644 --- a/lib/pages/video/detail/widgets/ai_detail.dart +++ b/lib/pages/video/detail/widgets/ai_detail.dart @@ -1,6 +1,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:pilipala/common/widgets/drag_handle.dart'; import 'package:pilipala/models/video/ai.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/utils/global_data_cache.dart'; @@ -17,21 +18,24 @@ class AiDetail extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - padding: const EdgeInsets.only(left: 16, right: 16), + padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), height: GlobalDataCache.sheetHeight, child: Column( children: [ - _buildHeader(context), + const DragHandle(), Expanded( child: SingleChildScrollView( - child: Column( - children: [ - if (modelResult!.summary != '') ...[ - _buildSummaryText(modelResult!.summary!), - const SizedBox(height: 20), + child: Padding( + padding: const EdgeInsets.only(left: 16, right: 16), + child: Column( + children: [ + if (modelResult!.summary != '') ...[ + _buildSummaryText(modelResult!.summary!), + const SizedBox(height: 20), + ], + _buildOutlineList(context), ], - _buildOutlineList(context), - ], + ), ), ), ), @@ -40,20 +44,6 @@ class AiDetail extends StatelessWidget { ); } - Widget _buildHeader(BuildContext context) { - return Center( - child: Container( - decoration: BoxDecoration( - color: Theme.of(context).hintColor, - borderRadius: const BorderRadius.all(Radius.circular(10)), - ), - height: 4, - width: 40, - margin: const EdgeInsets.symmetric(vertical: 16), - ), - ); - } - Widget _buildSummaryText(String summary) { return SelectableText( summary, diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 5b2c51ae..0fbdc493 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -8,6 +8,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:ns_danmaku/ns_danmaku.dart'; +import 'package:pilipala/common/widgets/drag_handle.dart'; import 'package:pilipala/http/user.dart'; import 'package:pilipala/models/video/play/quality.dart'; import 'package:pilipala/models/video/play/url.dart'; @@ -102,22 +103,7 @@ class _HeaderControlState extends State { margin: const EdgeInsets.all(12), child: Column( children: [ - SizedBox( - height: 35, - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .onSecondaryContainer - .withOpacity(0.5), - borderRadius: - const BorderRadius.all(Radius.circular(3))), - ), - ), - ), + const DragHandle(), Expanded( child: Material( child: ListView( diff --git a/lib/plugin/pl_gallery/interactiveviewer_gallery.dart b/lib/plugin/pl_gallery/interactiveviewer_gallery.dart index 88c9129c..6776b10c 100644 --- a/lib/plugin/pl_gallery/interactiveviewer_gallery.dart +++ b/lib/plugin/pl_gallery/interactiveviewer_gallery.dart @@ -7,8 +7,8 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; -import 'package:get/get.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:pilipala/common/widgets/drag_handle.dart'; import 'package:pilipala/utils/download.dart'; import 'package:share_plus/share_plus.dart'; import 'package:status_bar_control/status_bar_control.dart'; @@ -423,29 +423,13 @@ class _InteractiveviewerGalleryState extends State useRootNavigator: true, isScrollControlled: true, builder: (context) { - return Container( + return Padding( padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), child: Column( mainAxisSize: MainAxisSize.min, children: [ - InkWell( - onTap: () => Get.back(), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( - child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.outline, - borderRadius: - const BorderRadius.all(Radius.circular(3))), - ), - ), - ), - ), + const DragHandle(), ..._buildListTitles(), ], ), From 6ba022828c8ba4aa4fdd92f9bb3d01bb21ffae23 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 26 Nov 2024 23:31:20 +0800 Subject: [PATCH 24/39] opt: videoDetail SliverAppBar height change --- lib/pages/video/detail/view.dart | 4 +-- lib/plugin/pl_player/view.dart | 42 +++++++++++++++++++------------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 564ab65a..55aafeb5 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -680,8 +680,8 @@ class _VideoDetailPageState extends State forceElevated: innerBoxIsScrolled, expandedHeight: expandedHeight, backgroundColor: Colors.black, - flexibleSpace: FlexibleSpaceBar( - background: PopScope( + flexibleSpace: SizedBox.expand( + child: PopScope( canPop: plPlayerController?.isFullScreen.value != true, onPopInvoked: (bool didPop) { diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index c73bc55f..4c405cc0 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -739,29 +739,37 @@ class _PLVideoPlayerState extends State // 头部、底部控制条 Obx( () => Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (widget.headerControl != null || _.headerControl != null) - ClipRect( + if (widget.headerControl != null || _.headerControl != null) ...[ + Flexible( + child: ClipRect( + child: AppBarAni( + controller: animationController, + visible: !_.controlsLock.value && _.showControls.value, + position: 'top', + child: widget.headerControl ?? _.headerControl!, + ), + ), + ), + ] else ...[ + const SizedBox.shrink() + ], + Flexible( + flex: _.videoType == 'live' ? 0 : 1, + child: ClipRect( child: AppBarAni( controller: animationController, visible: !_.controlsLock.value && _.showControls.value, - position: 'top', - child: widget.headerControl ?? _.headerControl!, + position: 'bottom', + child: widget.bottomControl ?? + BottomControl( + controller: widget.controller, + triggerFullScreen: _.triggerFullScreen, + buildBottomControl: buildBottomControl(), + ), ), ), - const Spacer(), - ClipRect( - child: AppBarAni( - controller: animationController, - visible: !_.controlsLock.value && _.showControls.value, - position: 'bottom', - child: widget.bottomControl ?? - BottomControl( - controller: widget.controller, - triggerFullScreen: _.triggerFullScreen, - buildBottomControl: buildBottomControl(), - ), - ), ), ], ), From bae15505938b5ac49560bf1531bf07852311925f Mon Sep 17 00:00:00 2001 From: guozhigq Date: Tue, 26 Nov 2024 23:35:48 +0800 Subject: [PATCH 25/39] mod: enableCDN default false --- lib/pages/live_room/controller.dart | 2 +- lib/pages/setting/play_setting.dart | 2 +- lib/pages/video/detail/controller.dart | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index a918ec7b..28f92005 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -69,7 +69,7 @@ class LiveRoomController extends GetxController { Request.getBuvid().then((value) => buvid = value); } // CDN优化 - enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true); + enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: false); final userInfo = userInfoCache.get('userInfoCache'); if (userInfo != null && userInfo.mid != null) { userId = userInfo.mid; diff --git a/lib/pages/setting/play_setting.dart b/lib/pages/setting/play_setting.dart index c6d7fe0b..1151775e 100644 --- a/lib/pages/setting/play_setting.dart +++ b/lib/pages/setting/play_setting.dart @@ -95,7 +95,7 @@ class _PlaySettingState extends State { title: 'CDN优化', subTitle: '使用优质CDN线路', setKey: SettingBoxKey.enableCDN, - defaultVal: true, + defaultVal: false, ), const SetSwitchItem( title: '自动播放', diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 78028904..cc2cbffc 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -169,7 +169,7 @@ class VideoDetailController extends GetxController } // CDN优化 - enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true); + enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: false); // 预设的画质 cacheVideoQa = setting.get(SettingBoxKey.defaultVideoQa); // 预设的解码格式 From 518f49973c967f026f90393d49ead3cdff9bd1b1 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 27 Nov 2024 00:05:10 +0800 Subject: [PATCH 26/39] mod: fav folder edit --- lib/pages/fav_detail/controller.dart | 5 ++-- lib/pages/fav_edit/controller.dart | 11 +++++++++ lib/pages/fav_edit/view.dart | 35 +++++++++++----------------- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/lib/pages/fav_detail/controller.dart b/lib/pages/fav_detail/controller.dart index 022e0103..32bad5c9 100644 --- a/lib/pages/fav_detail/controller.dart +++ b/lib/pages/fav_detail/controller.dart @@ -134,8 +134,9 @@ class FavDetailController extends GetxController { 'privacy': [22, 0].contains(item!.attr) ? 0 : 1, }, ); - title.value = res['title']; - print(title); + if (res != null) { + title.value = res['title']; + } } Future toViewPlayAll() async { diff --git a/lib/pages/fav_edit/controller.dart b/lib/pages/fav_edit/controller.dart index bf310389..18e88a03 100644 --- a/lib/pages/fav_edit/controller.dart +++ b/lib/pages/fav_edit/controller.dart @@ -53,6 +53,7 @@ class FavEditController extends GetxController { intro: intro, mediaId: mediaId!, cover: cover, + privacy: privacy.value, ); if (res['status']) { SmartDialog.showToast('编辑成功'); @@ -74,4 +75,14 @@ class FavEditController extends GetxController { SmartDialog.showToast(res['msg']); } } + + void togglePrivacy() { + if (privacy.value == 0) { + privacy.value = 1; + SmartDialog.showToast('设置为私密后,只有自己可见'); + } else { + privacy.value = 0; + SmartDialog.showToast('设置为公开后,所有人可见'); + } + } } diff --git a/lib/pages/fav_edit/view.dart b/lib/pages/fav_edit/view.dart index 2fecf070..4b5db10c 100644 --- a/lib/pages/fav_edit/view.dart +++ b/lib/pages/fav_edit/view.dart @@ -21,31 +21,22 @@ class _FavEditPageState extends State { appBar: AppBar( title: Obx( () => _favEditController.type.value == 'add' - ? Text( - '新建收藏夹', - style: Theme.of(context).textTheme.titleMedium, - ) - : Text( - '编辑收藏夹', - style: Theme.of(context).textTheme.titleMedium, - ), + ? const Text('新建收藏夹') + : const Text('编辑收藏夹'), ), actions: [ Obx( - () => _favEditController.privacy.value == 0 - ? IconButton( - onPressed: () { - _favEditController.privacy.value = 1; - }, - icon: const Icon(Icons.lock_open_outlined)) - : IconButton( - onPressed: () { - _favEditController.privacy.value = 0; - }, - icon: Icon( - Icons.lock_outlined, - color: Theme.of(context).colorScheme.error, - )), + () => IconButton( + onPressed: _favEditController.togglePrivacy, + icon: Icon( + _favEditController.privacy.value == 0 + ? Icons.lock_open_outlined + : Icons.lock_outlined, + color: _favEditController.privacy.value == 0 + ? null + : Theme.of(context).colorScheme.error, + ), + ), ), TextButton( onPressed: _favEditController.onSubmit, child: const Text('保存')), From 9f16296b0a9f0752b24f577593337887837fd8df Mon Sep 17 00:00:00 2001 From: guozhigq Date: Wed, 27 Nov 2024 23:55:13 +0800 Subject: [PATCH 27/39] =?UTF-8?q?fix=EF=BC=9AcurrentEpisodeIndex=20null?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/common/pages_bottom_sheet.dart | 3 +-- lib/pages/video/detail/introduction/controller.dart | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/common/pages_bottom_sheet.dart b/lib/common/pages_bottom_sheet.dart index fa6f61c7..434b73c4 100644 --- a/lib/common/pages_bottom_sheet.dart +++ b/lib/common/pages_bottom_sheet.dart @@ -1,5 +1,4 @@ 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'; @@ -183,7 +182,7 @@ class _PagesBottomSheetState extends State isFixedHeight: true, ); } else { - _listObserverControllerList![widget.currentEpisodeIndex!] + _listObserverControllerList![widget.currentEpisodeIndex ?? 0] .initialIndexModel = ObserverIndexPositionModel( index: currentIndex, isFixedHeight: true, diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index eafedd08..6578a882 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -608,6 +608,7 @@ class VideoIntroController extends GetxController { // 播放器底栏 选集 回调 void showEposideHandler() { late List episodes; + int currentEpisodeIndex = 0; VideoEpidoesType dataType = VideoEpidoesType.videoEpisode; if (videoDetail.value.ugcSeason != null) { dataType = VideoEpidoesType.videoEpisode; @@ -616,6 +617,7 @@ class VideoIntroController extends GetxController { final List episodesList = sections[i].episodes!; for (int j = 0; j < episodesList.length; j++) { if (episodesList[j].cid == lastPlayCid.value) { + currentEpisodeIndex = i; episodes = episodesList; continue; } @@ -635,6 +637,7 @@ class VideoIntroController extends GetxController { sheetHeight: Get.size.height, isFullScreen: true, ugcSeason: ugcSeason, + currentEpisodeIndex: currentEpisodeIndex, changeFucCall: (item, index) { if (dataType == VideoEpidoesType.videoEpisode) { changeSeasonOrbangu( From 973a61c54a6a7e3b991aead0bc2dda27e29a1be4 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 28 Nov 2024 00:07:18 +0800 Subject: [PATCH 28/39] refactor: currentEpisodeIndex calc --- .../introduction/widgets/season_panel.dart | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/pages/video/detail/introduction/widgets/season_panel.dart b/lib/pages/video/detail/introduction/widgets/season_panel.dart index 291f1622..4a35f45b 100644 --- a/lib/pages/video/detail/introduction/widgets/season_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/season_panel.dart @@ -42,23 +42,14 @@ class _SeasonPanelState extends State { _videoDetailController = Get.find(tag: heroTag); /// 根据 cid 找到对应集,找到对应 episodes - final List sections = widget.ugcSeason.sections!; - for (int i = 0; i < sections.length; i++) { - final List episodesList = sections[i].episodes!; - for (int j = 0; j < episodesList.length; j++) { - if (episodesList[j].cid == cid) { - currentEpisodeIndex = i; - episodes = episodesList; - continue; - } - } - } + getCurrentEpisodeIndex(); /// 取对应 season_id 的 episodes getCurrentIndex(); _videoDetailController.cid.listen((int p0) { cid = p0; getCurrentIndex(); + getCurrentEpisodeIndex(); }); } @@ -94,6 +85,21 @@ class _SeasonPanelState extends State { } } + // 获取currentEpisodeIndex + void getCurrentEpisodeIndex() { + final List sections = widget.ugcSeason.sections!; + for (int i = 0; i < sections.length; i++) { + final List episodesList = sections[i].episodes!; + for (int j = 0; j < episodesList.length; j++) { + if (episodesList[j].cid == cid) { + currentEpisodeIndex = i; + episodes = episodesList; + continue; + } + } + } + } + Widget buildEpisodeListItem( EpisodeItem episode, int index, From 65c9027ef390422939a7b676b4b0768e9f37602b Mon Sep 17 00:00:00 2001 From: guozhigq Date: Thu, 28 Nov 2024 23:05:02 +0800 Subject: [PATCH 29/39] feat: marquee title --- .../video/detail/widgets/header_control.dart | 417 ++++++++++-------- pubspec.lock | 16 + pubspec.yaml | 2 + 3 files changed, 246 insertions(+), 189 deletions(-) diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 5412d326..28448f51 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -7,6 +7,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:hive/hive.dart'; +import 'package:marquee/marquee.dart'; import 'package:ns_danmaku/ns_danmaku.dart'; import 'package:pilipala/common/widgets/drag_handle.dart'; import 'package:pilipala/http/user.dart'; @@ -62,6 +63,7 @@ class _HeaderControlState extends State { late String heroTag; late VideoIntroController videoIntroController; late VideoDetailData videoDetail; + DateTime initialTime = DateTime.now(); @override void initState() { @@ -108,30 +110,6 @@ class _HeaderControlState extends State { child: Material( child: ListView( children: [ - // ListTile( - // onTap: () {}, - // dense: true, - // enabled: false, - // leading: - // const Icon(Icons.network_cell_outlined, size: 20), - // title: Text('省流模式', style: titleStyle), - // subtitle: Text('低画质 | 减少视频缓存', style: subTitleStyle), - // trailing: Transform.scale( - // scale: 0.75, - // child: Switch( - // thumbIcon: MaterialStateProperty.resolveWith( - // (Set states) { - // if (states.isNotEmpty && - // states.first == MaterialState.selected) { - // return const Icon(Icons.done); - // } - // return null; // All other states will use the default thumbIcon. - // }), - // value: false, - // onChanged: (value) => {}, - // ), - // ), - // ), ListTile( onTap: () async { final res = await UserHttp.toViewLater( @@ -1071,6 +1049,16 @@ class _HeaderControlState extends State { ); } + Stream _getTimeStream() { + return Stream.periodic(const Duration(seconds: 60), (count) { + return DateTime.now(); + }); + } + + String _formatTime(DateTime dateTime) { + return '${dateTime.hour}:${dateTime.minute < 10 ? '0${dateTime.minute}' : dateTime.minute}'; + } + @override Widget build(BuildContext context) { final _ = widget.controller!; @@ -1086,49 +1074,12 @@ class _HeaderControlState extends State { primary: false, automaticallyImplyLeading: false, titleSpacing: 14, - title: Row( + title: Column( children: [ - ComBtn( - icon: const Icon( - FontAwesomeIcons.arrowLeft, - size: 15, - color: Colors.white, - ), - fuc: () => >{ - if (widget.controller!.isFullScreen.value) - {widget.controller!.triggerFullScreen(status: false)} - else - { - if (MediaQuery.of(context).orientation == - Orientation.landscape) - { - SystemChrome.setPreferredOrientations([ - DeviceOrientation.portraitUp, - ]) - }, - Get.back() - } - }, - ), - SizedBox(width: buttonSpace), - if (isFullScreen.value && - isLandscape && - widget.videoType == SearchType.video) ...[ - Column( - crossAxisAlignment: CrossAxisAlignment.start, + if (isFullScreen.value && isLandscape) ...[ + Row( children: [ - ConstrainedBox( - constraints: const BoxConstraints(maxWidth: 200), - child: Obx( - () => Text( - videoIntroController.videoDetail.value.title ?? '', - style: const TextStyle( - color: Colors.white, - fontSize: 16, - ), - ), - ), - ), + const SizedBox(width: 40), if (videoIntroController.isShowOnlineTotal) Text( '${videoIntroController.total.value}人正在看', @@ -1136,138 +1087,226 @@ class _HeaderControlState extends State { color: Colors.white, fontSize: 12, ), - ) + ), + const Spacer(), + Expanded( + child: Align( + alignment: Alignment.center, + child: StreamBuilder( + stream: _getTimeStream(), + builder: (context, snapshot) { + if (snapshot.hasData) { + String currentTime = _formatTime(snapshot.data!); + return Text( + currentTime, + style: const TextStyle(fontSize: 12), + ); + } else if (snapshot.connectionState == + ConnectionState.waiting) { + // 如果Stream还未发出数据,先显示初始获取的时间 + String currentTime = _formatTime(initialTime); + return Text( + currentTime, + style: const TextStyle(fontSize: 12), + ); + } else { + return const SizedBox(); + } + }, + ), + ), + ), + const Spacer(), + + /// TODO 网络&电量 ], - ) - ] else ...[ - ComBtn( - icon: const Icon( - FontAwesomeIcons.house, - size: 15, - color: Colors.white, - ), - fuc: () async { - // 销毁播放器实例 - await widget.controller!.dispose(type: 'all'); - if (context.mounted) { - Navigator.popUntil( - context, (Route route) => route.isFirst); - } - }, ), ], - const Spacer(), - if (GlobalDataCache.enableDlna) ...[ - ComBtn( - icon: Image.asset('assets/images/video/dlna.png', width: 19), - fuc: () async { - showDialog( - context: context, - builder: (BuildContext context) { - return LiveDlnaPage( - datasource: widget.videoDetailCtr!.videoUrl); - }, - ); - }, - ), - SizedBox(width: buttonSpace), - ], - - /// 弹幕开关(全屏时) - if (isFullScreen.value) ...[ - SizedBox( - width: 56, - height: 34, - child: TextButton( - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - ), - onPressed: () => showShootDanmakuSheet(), - child: const Text( - '发弹幕', - style: textStyle, - ), - ), - ), - SizedBox(width: buttonSpace), - SizedBox( - width: 34, - height: 34, - child: Obx( - () => IconButton( - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - ), - onPressed: () { - _.isOpenDanmu.value = !_.isOpenDanmu.value; - }, - icon: Icon( - _.isOpenDanmu.value - ? Icons.subtitles_outlined - : Icons.subtitles_off_outlined, - size: 19, - color: Colors.white, - ), - ), - ), - ), - SizedBox(width: buttonSpace), - ], - - /// pip - if (Platform.isAndroid) ...[ - SizedBox( - width: 34, - height: 34, - child: IconButton( - style: ButtonStyle( - padding: MaterialStateProperty.all(EdgeInsets.zero), - ), - onPressed: () async { - bool canUsePiP = false; - widget.controller!.hiddenControls(false); - try { - canUsePiP = await widget.floating!.isPipAvailable; - } on PlatformException catch (_) { - canUsePiP = false; - } - if (canUsePiP) { - final Rational aspectRatio = Rational( - widget.videoDetailCtr!.data.dash!.video!.first.width!, - widget.videoDetailCtr!.data.dash!.video!.first.height!, - ); - await widget.floating!.enable(aspectRatio: aspectRatio); - } else {} - }, - icon: Image.asset( - 'assets/images/video/pip.png', - width: 19, + Row( + children: [ + ComBtn( + icon: const Icon( + FontAwesomeIcons.arrowLeft, + size: 15, color: Colors.white, ), + fuc: () => >{ + if (widget.controller!.isFullScreen.value) + {widget.controller!.triggerFullScreen(status: false)} + else + { + if (MediaQuery.of(context).orientation == + Orientation.landscape) + { + SystemChrome.setPreferredOrientations([ + DeviceOrientation.portraitUp, + ]) + }, + Get.back() + } + }, ), - ), - SizedBox(width: buttonSpace), - ], + SizedBox(width: buttonSpace), + if (isFullScreen.value && + isLandscape && + widget.videoType == SearchType.video) ...[ + Expanded( + child: LayoutBuilder(builder: (context, constraints) { + return SizedBox( + width: constraints.maxWidth, + height: 25, + child: Obx( + () => Marquee( + text: videoIntroController.videoDetail.value.title ?? + '', + style: const TextStyle(fontSize: 16), + scrollAxis: Axis.horizontal, + crossAxisAlignment: CrossAxisAlignment.center, + blankSpace: constraints.maxWidth, + velocity: 100, + pauseAfterRound: const Duration(seconds: 1), + startPadding: 0, + accelerationDuration: const Duration(seconds: 1), + accelerationCurve: Curves.linear, + decelerationDuration: const Duration(seconds: 1), + decelerationCurve: Curves.easeOut, + ), + ), + ); + }), + ), + ] else ...[ + ComBtn( + icon: const Icon( + FontAwesomeIcons.house, + size: 15, + color: Colors.white, + ), + fuc: () async { + // 销毁播放器实例 + await widget.controller!.dispose(type: 'all'); + if (context.mounted) { + Navigator.popUntil( + context, (Route route) => route.isFirst); + } + }, + ), + ], + const Spacer(), + if (GlobalDataCache.enableDlna) ...[ + ComBtn( + icon: Image.asset('assets/images/video/dlna.png', width: 19), + fuc: () async { + showDialog( + context: context, + builder: (BuildContext context) { + return LiveDlnaPage( + datasource: widget.videoDetailCtr!.videoUrl); + }, + ); + }, + ), + SizedBox(width: buttonSpace), + ], - /// 字幕 - if (widget.showSubtitleBtn) ...[ - ComBtn( - icon: Icon( - FontAwesomeIcons.closedCaptioning, - size: 16, - color: Colors.white.withOpacity(0.9), + /// 弹幕开关(全屏时) + if (isFullScreen.value) ...[ + SizedBox( + width: 56, + height: 34, + child: TextButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + onPressed: () => showShootDanmakuSheet(), + child: const Text( + '发弹幕', + style: textStyle, + ), + ), + ), + SizedBox(width: buttonSpace), + SizedBox( + width: 34, + height: 34, + child: Obx( + () => IconButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + onPressed: () { + _.isOpenDanmu.value = !_.isOpenDanmu.value; + }, + icon: Icon( + _.isOpenDanmu.value + ? Icons.subtitles_outlined + : Icons.subtitles_off_outlined, + size: 19, + color: Colors.white, + ), + ), + ), + ), + SizedBox(width: buttonSpace), + ], + + /// pip + if (Platform.isAndroid) ...[ + SizedBox( + width: 34, + height: 34, + child: IconButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + onPressed: () async { + bool canUsePiP = false; + widget.controller!.hiddenControls(false); + try { + canUsePiP = await widget.floating!.isPipAvailable; + } on PlatformException catch (_) { + canUsePiP = false; + } + if (canUsePiP) { + final Rational aspectRatio = Rational( + widget.videoDetailCtr!.data.dash!.video!.first.width!, + widget + .videoDetailCtr!.data.dash!.video!.first.height!, + ); + await widget.floating!.enable(aspectRatio: aspectRatio); + } else {} + }, + icon: Image.asset( + 'assets/images/video/pip.png', + width: 19, + color: Colors.white, + ), + ), + ), + SizedBox(width: buttonSpace), + ], + + /// 字幕 + if (widget.showSubtitleBtn) ...[ + ComBtn( + icon: Icon( + FontAwesomeIcons.closedCaptioning, + size: 16, + color: Colors.white.withOpacity(0.9), + ), + fuc: () => showSubtitleDialog(), + ), + SizedBox(width: buttonSpace), + ], + ComBtn( + icon: const Icon( + Icons.more_vert_outlined, + size: 19, + color: Colors.white, + ), + fuc: () => showSettingSheet(), ), - fuc: () => showSubtitleDialog(), - ), - SizedBox(width: buttonSpace), - ], - ComBtn( - icon: const Icon( - Icons.more_vert_outlined, - size: 19, - color: Colors.white, - ), - fuc: () => showSettingSheet(), + ], ), ], ), diff --git a/pubspec.lock b/pubspec.lock index a3dd3af9..715b23a5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -497,6 +497,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "6.2.1" + fading_edge_scrollview: + dependency: transitive + description: + name: fading_edge_scrollview + sha256: c25c2231652ce774cc31824d0112f11f653881f43d7f5302c05af11942052031 + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.0.0" fake_async: dependency: transitive description: @@ -990,6 +998,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "6.1.0" + marquee: + dependency: "direct main" + description: + name: marquee + sha256: "4b5243d2804373bdc25fc93d42c3b402d6ec1f4ee8d0bb72276edd04ae7addb8" + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.2.3" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index b2275398..80a8b067 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -152,6 +152,8 @@ dependencies: re_highlight: ^0.0.3 # 图片选择器 image_picker: ^1.1.2 + # 跑马灯 + marquee: ^2.2.3 dev_dependencies: flutter_test: From b79a664e94e0444d5552475276e358e8cbd87965 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 29 Nov 2024 23:51:58 +0800 Subject: [PATCH 30/39] refactor: progressBar --- lib/plugin/pl_player/view.dart | 3 +- .../pl_player/widgets/bottom_control.dart | 50 +++--------------- .../pl_player/widgets/progress_bar.dart | 52 +++++++++++++++++++ 3 files changed, 59 insertions(+), 46 deletions(-) create mode 100644 lib/plugin/pl_player/widgets/progress_bar.dart diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index c379303e..b47d38de 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -842,8 +842,7 @@ class _PLVideoPlayerState extends State total: Duration(seconds: max), progressBarColor: colorTheme, baseBarColor: Colors.white.withOpacity(0.2), - bufferedBarColor: - Theme.of(context).colorScheme.primary.withOpacity(0.4), + bufferedBarColor: Colors.white.withOpacity(0.6), timeLabelLocation: TimeLabelLocation.none, thumbColor: colorTheme, barHeight: 3, diff --git a/lib/plugin/pl_player/widgets/bottom_control.dart b/lib/plugin/pl_player/widgets/bottom_control.dart index b3ff37db..3c21c2af 100644 --- a/lib/plugin/pl_player/widgets/bottom_control.dart +++ b/lib/plugin/pl_player/widgets/bottom_control.dart @@ -1,8 +1,6 @@ -import 'package:audio_video_progress_bar/audio_video_progress_bar.dart'; import 'package:flutter/material.dart'; -import 'package:get/get.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; -import 'package:pilipala/utils/feed_back.dart'; +import 'progress_bar.dart'; class BottomControl extends StatelessWidget implements PreferredSizeWidget { final PlPlayerController? controller; @@ -20,54 +18,18 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { - Color colorTheme = Theme.of(context).colorScheme.primary; - final _ = controller!; return Container( color: Colors.transparent, height: 90, - padding: const EdgeInsets.only(left: 18, right: 18), + padding: const EdgeInsets.symmetric(horizontal: 18), child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ - Obx( - () { - final int value = _.sliderPositionSeconds.value; - final int max = _.durationSeconds.value; - final int buffer = _.bufferedSeconds.value; - if (value > max || max <= 0) { - return const SizedBox(); - } - return Padding( - padding: const EdgeInsets.only(left: 7, right: 7, bottom: 6), - child: ProgressBar( - progress: Duration(seconds: value), - buffered: Duration(seconds: buffer), - total: Duration(seconds: max), - progressBarColor: colorTheme, - baseBarColor: Colors.white.withOpacity(0.2), - bufferedBarColor: colorTheme.withOpacity(0.4), - timeLabelLocation: TimeLabelLocation.none, - thumbColor: colorTheme, - barHeight: 3.5, - thumbRadius: 7, - onDragStart: (duration) { - feedBack(); - _.onChangedSliderStart(); - }, - onDragUpdate: (duration) { - _.onUpdatedSliderProgress(duration.timeStamp); - }, - onSeek: (duration) { - _.onChangedSliderEnd(); - _.onChangedSlider(duration.inSeconds.toDouble()); - _.seekTo(Duration(seconds: duration.inSeconds), - type: 'slider'); - }, - ), - ); - }, + Padding( + padding: const EdgeInsets.fromLTRB(7, 0, 7, 6), + child: ProgressBarWidget(controller: controller!), ), - Row(children: [...buildBottomControl!]), + Row(children: buildBottomControl!), const SizedBox(height: 10), ], ), diff --git a/lib/plugin/pl_player/widgets/progress_bar.dart b/lib/plugin/pl_player/widgets/progress_bar.dart new file mode 100644 index 00000000..d0ed0a4e --- /dev/null +++ b/lib/plugin/pl_player/widgets/progress_bar.dart @@ -0,0 +1,52 @@ +import 'package:audio_video_progress_bar/audio_video_progress_bar.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/plugin/pl_player/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; + +class ProgressBarWidget extends StatelessWidget { + final PlPlayerController controller; + + const ProgressBarWidget({ + required this.controller, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Obx(() { + Color colorTheme = Theme.of(context).colorScheme.primary; + final _ = controller; + final int value = _.sliderPositionSeconds.value; + final int max = _.durationSeconds.value; + final int buffer = _.bufferedSeconds.value; + if (value > max || max <= 0) { + return const SizedBox(); + } + return ProgressBar( + progress: Duration(seconds: value), + buffered: Duration(seconds: buffer), + total: Duration(seconds: max), + progressBarColor: colorTheme, + baseBarColor: Colors.white.withOpacity(0.2), + bufferedBarColor: Colors.white.withOpacity(0.6), + timeLabelLocation: TimeLabelLocation.none, + thumbColor: colorTheme, + barHeight: 3.5, + thumbRadius: 7, + onDragStart: (duration) { + feedBack(); + _.onChangedSliderStart(); + }, + onDragUpdate: (duration) { + _.onUpdatedSliderProgress(duration.timeStamp); + }, + onSeek: (duration) { + _.onChangedSliderEnd(); + _.onChangedSlider(duration.inSeconds.toDouble()); + _.seekTo(Duration(seconds: duration.inSeconds), type: 'slider'); + }, + ); + }); + } +} From 1127ef74370d7f5faef07ffb03718a9b585f94f6 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sat, 30 Nov 2024 14:18:26 +0800 Subject: [PATCH 31/39] fix: _futureBuilderFuture init --- lib/pages/dynamics/detail/view.dart | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index b1f9bea8..186a9e9a 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -20,7 +20,6 @@ import '../../../models/video/reply/item.dart'; import '../widgets/dynamic_panel.dart'; class DynamicDetailPage extends StatefulWidget { - // const DynamicDetailPage({super.key}); const DynamicDetailPage({Key? key}) : super(key: key); @override @@ -90,19 +89,22 @@ class _DynamicDetailPageState extends State _dynamicDetailController = Get.put( DynamicDetailController(oid, replyType), tag: opusId.toString()); + _futureBuilderFuture = _dynamicDetailController.queryReplyList(); await _dynamicDetailController.reqHtmlByOpusId(opusId!); setState(() {}); } } else { oid = moduleDynamic.major!.draw!.id!; } - } catch (_) {} + } catch (err) { + print('err:${err.toString()}'); + } } if (!isOpusId) { _dynamicDetailController = Get.put(DynamicDetailController(oid, replyType), tag: oid.toString()); + _futureBuilderFuture ??= _dynamicDetailController.queryReplyList(); } - _futureBuilderFuture = _dynamicDetailController.queryReplyList(); } // 查看二级评论 @@ -132,7 +134,7 @@ class _DynamicDetailPageState extends State // 分页加载 if (scrollController.position.pixels >= scrollController.position.maxScrollExtent - 300) { - EasyThrottle.throttle('replylist', const Duration(seconds: 2), () { + EasyThrottle.throttle('replyList', const Duration(seconds: 2), () { _dynamicDetailController.onLoad(); }); } From 038f6c00d7a2da3cb39d45a5667208da96e4f108 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 1 Dec 2024 00:30:56 +0800 Subject: [PATCH 32/39] opt: article render --- lib/common/widgets/html_render.dart | 24 ++++++++++++++++++------ lib/pages/opus/view.dart | 21 ++++++++++++--------- lib/pages/read/view.dart | 21 ++++++++++++--------- 3 files changed, 42 insertions(+), 24 deletions(-) diff --git a/lib/common/widgets/html_render.dart b/lib/common/widgets/html_render.dart index b2aa75ff..e4e3ef77 100644 --- a/lib/common/widgets/html_render.dart +++ b/lib/common/widgets/html_render.dart @@ -5,6 +5,8 @@ import 'package:pilipala/plugin/pl_gallery/hero_dialog_route.dart'; import 'package:pilipala/plugin/pl_gallery/interactiveviewer_gallery.dart'; import 'package:pilipala/utils/highlight.dart'; +import '../../utils/global_data_cache.dart'; + // ignore: must_be_immutable class HtmlRender extends StatelessWidget { const HtmlRender({ @@ -41,6 +43,8 @@ class HtmlRender extends StatelessWidget { TagExtension( tagsToExtend: {'img'}, builder: (ExtensionContext extensionContext) { + int defaultImgQuality = 10; + defaultImgQuality = GlobalDataCache.imgQuality; try { final Map attributes = extensionContext.attributes; @@ -99,13 +103,13 @@ class HtmlRender extends StatelessWidget { ), ); }, - child: CachedNetworkImage(imageUrl: imgUrl), + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: CachedNetworkImage( + imageUrl: '$imgUrl@${defaultImgQuality}q.webp', + ), + ), ); - // return NetworkImgLayer( - // width: isEmote ? 22 : Get.size.width - 24, - // height: isEmote ? 22 : 200, - // src: imgUrl, - // ); } catch (err) { return const SizedBox(); } @@ -138,6 +142,14 @@ class HtmlRender extends StatelessWidget { textAlign: TextAlign.justify, ), 'img': Style(margin: Margins.only(top: 4, bottom: 4)), + 'figcaption': Style( + textAlign: TextAlign.center, + margin: Margins.only(top: 8, bottom: 20), + color: Theme.of(context).colorScheme.secondary, + ), + 'figure': Style( + margin: Margins.zero, + ), }, ); } diff --git a/lib/pages/opus/view.dart b/lib/pages/opus/view.dart index 42c0c419..971bb678 100644 --- a/lib/pages/opus/view.dart +++ b/lib/pages/opus/view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/models/read/opus.dart'; + import 'controller.dart'; import 'text_helper.dart'; @@ -26,16 +27,18 @@ class _OpusPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: _buildAppBar(), - body: SingleChildScrollView( + body: CustomScrollView( controller: controller.scrollController, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildTitle(), - _buildFutureContent(), - ], - ), + slivers: [ + SliverList( + delegate: SliverChildListDelegate( + [ + _buildTitle(), + _buildFutureContent(), + ], + ), + ), + ], ), ); } diff --git a/lib/pages/read/view.dart b/lib/pages/read/view.dart index 710934eb..4bc93326 100644 --- a/lib/pages/read/view.dart +++ b/lib/pages/read/view.dart @@ -6,6 +6,7 @@ import 'package:pilipala/models/read/opus.dart'; import 'package:pilipala/models/read/read.dart'; import 'package:pilipala/pages/opus/text_helper.dart'; import 'package:pilipala/utils/utils.dart'; + import 'controller.dart'; class ReadPage extends StatefulWidget { @@ -38,16 +39,18 @@ class _ReadPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: _buildAppBar(), - body: SingleChildScrollView( + body: CustomScrollView( controller: controller.scrollController, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildTitle(), - _buildFutureContent(), - ], - ), + slivers: [ + SliverList( + delegate: SliverChildListDelegate( + [ + _buildTitle(), + _buildFutureContent(), + ], + ), + ), + ], ), ); } From fc921cdcb5d1b7ffa318b2ca1e96d9d5d5cb522e Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 1 Dec 2024 20:14:22 +0800 Subject: [PATCH 33/39] fix: vertical video fullScreen --- lib/pages/video/detail/view.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index c7896480..72af55db 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -554,6 +554,11 @@ class _VideoDetailPageState extends State playerController: plPlayerController!, ), bottomList: vdCtr.bottomList, + fullScreenCb: (bool status) { + if (vdCtr.videoDirection.value == 'vertical') { + videoHeight.value = status ? Get.size.height : verticalHeight; + } + }, showEposideCb: () => vdCtr.videoType == SearchType.video ? videoIntroController.showEposideHandler() : bangumiIntroController.showEposideHandler(), From a84efecb3aa8a513f0b734257ec28ccc7657c6bd Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 1 Dec 2024 22:49:38 +0800 Subject: [PATCH 34/39] fix: PlPlayerController videoType --- lib/plugin/pl_player/controller.dart | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index dab32b5c..e95fe647 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -81,7 +81,7 @@ class PlPlayerController { final Rx _subTitleOpen = false.obs; final Rx _subTitleCode = (-1).obs; // 默认投稿视频格式 - static Rx _videoType = 'archive'.obs; + static String _videoType = 'archive'; final Rx _direction = 'horizontal'.obs; @@ -127,7 +127,6 @@ class PlPlayerController { PreferredSizeWidget? bottomControl; Widget? danmuWidget; RxList subtitles = [].obs; - String videoType = 'archive'; /// 数据加载监听 Stream get onDataStatusChanged => dataStatus.status.stream; @@ -225,7 +224,7 @@ class PlPlayerController { Rx get playerCount => _playerCount; /// - // Rx get videoType => _videoType; + String get videoType => _videoType; /// 弹幕开关 Rx isOpenDanmu = false.obs; @@ -279,7 +278,7 @@ class PlPlayerController { } // 添加一个私有构造函数 - PlPlayerController._internal(this.videoType) { + PlPlayerController._internal() { isOpenDanmu.value = GlobalDataCache.isOpenDanmu; blockTypes = GlobalDataCache.blockTypes; showArea = GlobalDataCache.showArea; @@ -306,11 +305,11 @@ class PlPlayerController { String videoType = 'archive', }) { // 如果实例尚未创建,则创建一个新实例 - _instance ??= PlPlayerController._internal(videoType); + _instance ??= PlPlayerController._internal(); if (videoType != 'none') { _instance!._playerCount.value += 1; - _videoType.value = videoType; } + _videoType = videoType; return _instance!; } From fbd0dd1d8f0cd4da38b260b4525b77f8c5a773c8 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 1 Dec 2024 23:21:33 +0800 Subject: [PATCH 35/39] mod: _futureBuilderFuture init --- lib/pages/dynamics/detail/view.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index 186a9e9a..5c8f85e3 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -103,7 +103,7 @@ class _DynamicDetailPageState extends State if (!isOpusId) { _dynamicDetailController = Get.put(DynamicDetailController(oid, replyType), tag: oid.toString()); - _futureBuilderFuture ??= _dynamicDetailController.queryReplyList(); + _futureBuilderFuture = _dynamicDetailController.queryReplyList(); } } From 3d3a306e199cb7a81d3ff4030dbe218fb8e50bfe Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 1 Dec 2024 23:26:09 +0800 Subject: [PATCH 36/39] typo: getSubtitleContent --- lib/pages/video/detail/controller.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index cc2cbffc..4fdf8420 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -487,7 +487,7 @@ class VideoDetailController extends GetxController if (result['status']) { if (result['data'].subtitles.isNotEmpty) { subtitles = result['data'].subtitles; - getDanmaku(subtitles); + getSubtitleContent(subtitles); } } headerControl = HeaderControl( @@ -501,8 +501,8 @@ class VideoDetailController extends GetxController plPlayerController.setHeaderControl(headerControl); } - // 获取弹幕 - Future getDanmaku(List subtitles) async { + // 获取字幕 + Future getSubtitleContent(List subtitles) async { if (subtitles.isNotEmpty) { for (var i in subtitles) { final Map res = await VideoHttp.getSubtitleContent( From 97d20b1145930a4043833f48d98c4c940ecd0ed6 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 2 Dec 2024 00:04:04 +0800 Subject: [PATCH 37/39] opt: nextPlay logic & style --- lib/pages/later/controller.dart | 1 + lib/pages/video/detail/introduction/controller.dart | 2 +- lib/pages/video/detail/widgets/watch_later_list.dart | 9 ++++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/pages/later/controller.dart b/lib/pages/later/controller.dart index 6cb8a3c0..cf408d97 100644 --- a/lib/pages/later/controller.dart +++ b/lib/pages/later/controller.dart @@ -122,6 +122,7 @@ class LaterController extends GetxController { 'heroTag': heroTag, 'sourceType': 'watchLater', 'count': laterList.length, + 'mediaId': userInfo!.mid, }, ); } diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index c30a4dbd..d16d85a8 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -523,7 +523,7 @@ class VideoIntroController extends GetxController { Get.find(tag: heroTag); /// 优先稍后再看、收藏夹 - if (videoDetailCtr.isWatchLaterVisible.value) { + if (videoDetailCtr.sourceType.value != 'normal') { episodes.addAll(videoDetailCtr.mediaList); } else if (videoDetail.value.ugcSeason != null) { final UgcSeason ugcSeason = videoDetail.value.ugcSeason!; diff --git a/lib/pages/video/detail/widgets/watch_later_list.dart b/lib/pages/video/detail/widgets/watch_later_list.dart index 93326ec3..6d675dd8 100644 --- a/lib/pages/video/detail/widgets/watch_later_list.dart +++ b/lib/pages/video/detail/widgets/watch_later_list.dart @@ -85,9 +85,12 @@ class _MediaListPanelState extends State { AppBar( toolbarHeight: 45, automaticallyImplyLeading: false, - title: Text( - widget.panelTitle ?? '稍后再看', - style: Theme.of(context).textTheme.titleSmall, + title: Padding( + padding: const EdgeInsets.only(left: 12), + child: Text( + widget.panelTitle ?? '稍后再看', + style: Theme.of(context).textTheme.titleSmall, + ), ), actions: [ IconButton( From 1395f7ebf3e36659e3cb40e039d67007a7806f78 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 2 Dec 2024 21:01:33 +0800 Subject: [PATCH 38/39] opt: watchLater visible logic --- lib/pages/video/detail/controller.dart | 6 ++---- lib/pages/video/detail/view.dart | 7 +++---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index cc2cbffc..3d0d68e9 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -624,10 +624,8 @@ class VideoDetailController extends GetxController } void toggeleWatchLaterVisible(bool val) { - if (sourceType.value == 'watchLater' || - sourceType.value == 'fav' || - sourceType.value == 'up_archive') { - isWatchLaterVisible.value = !isWatchLaterVisible.value; + if (['watchLater', 'fav', 'up_archive'].contains(sourceType.value)) { + isWatchLaterVisible.value = val; } } diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index c7896480..cad795fc 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -206,12 +206,12 @@ class _VideoDetailPageState extends State vdCtr.bottomList.insert(3, BottomControlType.episode); } } + vdCtr.toggeleWatchLaterVisible(false); } else { if (vdCtr.bottomList.contains(BottomControlType.episode)) { vdCtr.bottomList.removeAt(3); } } - vdCtr.toggeleWatchLaterVisible(!isFullScreen); }); } @@ -825,9 +825,8 @@ class _VideoDetailPageState extends State /// 稍后再看列表 Obx( () => Visibility( - visible: vdCtr.sourceType.value == 'watchLater' || - vdCtr.sourceType.value == 'fav' || - vdCtr.sourceType.value == 'up_archive', + visible: ['watchLater', 'fav', 'up_archive'] + .contains(vdCtr.sourceType.value), child: AnimatedPositioned( duration: const Duration(milliseconds: 400), curve: Curves.easeInOut, From 15e5eec5b100d5beda6b92339beadcb9d3bfc1cb Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 2 Dec 2024 22:35:53 +0800 Subject: [PATCH 39/39] upgrade: AGP from 7.2.0 to 8.7.2 and Gradle from 7.5 to 8.10.2 --- android/app/build.gradle | 19 +++++------- android/app/proguard-rules.pro | 4 +++ android/build.gradle | 21 ++++++------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- android/settings.gradle | 30 ++++++++++++++----- pubspec.lock | 12 ++++---- pubspec.yaml | 4 +-- 7 files changed, 52 insertions(+), 40 deletions(-) create mode 100644 android/app/proguard-rules.pro diff --git a/android/app/build.gradle b/android/app/build.gradle index 3dc4f82a..0e6ecb11 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -1,3 +1,9 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { @@ -6,10 +12,6 @@ if (localPropertiesFile.exists()) { } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { @@ -21,9 +23,6 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" def keystorePropertiesFile = rootProject.file('key.properties') def keystoreProperties = new Properties() @@ -37,8 +36,9 @@ def _keyAlias = System.getenv("KEY_ALIAS") ?: keystoreProperties["keyAlias"] def _keyPassword = System.getenv("KEY_PASSWORD") ?: keystoreProperties["keyPassword"] android { + namespace "com.guozhigq.pilipala" compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion + ndkVersion "27.0.12077973" compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -91,9 +91,6 @@ flutter { source '../..' } -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" -} ext.abiCodes = ["x86_64": 1, "armeabi-v7a": 2, "arm64-v8a": 3] import com.android.build.OutputFile diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 00000000..2bcd166d --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,4 @@ +# missing R8 error +-dontwarn javax.annotation.Nullable +-dontwarn org.conscrypt.Conscrypt +-dontwarn org.conscrypt.OpenSSLProvider \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 674e96f4..a7b975c2 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,15 +1,3 @@ -buildscript { - ext.kotlin_version = '1.9.0' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} allprojects { repositories { @@ -20,6 +8,15 @@ allprojects { rootProject.buildDir = '../build' subprojects { + afterEvaluate { project -> + if (project.hasProperty('android')) { + project.android { + if (namespace == null) { + namespace project.group + } + } + } + } project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 3c472b99..afa1e8eb 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index 44e62bcf..f2420f21 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -1,11 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "8.7.2" apply false + id "org.jetbrains.kotlin.android" version "1.9.0" apply false +} + +include ":app" \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 715b23a5..d29eb4f3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -85,10 +85,10 @@ packages: dependency: "direct main" description: name: audio_service - sha256: "4547c312a94f9cb2c48b60823fb190767cbd63454a83c73049384d5d3cba4650" + sha256: "9dd5ba7e77567b290c35908b1950d61485b4dfdd3a0ac398e98cfeec04651b75" url: "https://pub.flutter-io.cn" source: hosted - version: "0.18.13" + version: "0.18.15" audio_service_platform_interface: dependency: transitive description: @@ -101,18 +101,18 @@ packages: dependency: transitive description: name: audio_service_web - sha256: "9d7d5ae5f98a5727f2580fad73062f2484f400eef6cef42919413268e62a363e" + sha256: "4cdc2127cd4562b957fb49227dc58e3303fafb09bde2573bc8241b938cf759d9" url: "https://pub.flutter-io.cn" source: hosted - version: "0.1.2" + version: "0.1.3" audio_session: dependency: "direct main" description: name: audio_session - sha256: "6fdf255ed3af86535c96452c33ecff1245990bb25a605bfb1958661ccc3d467f" + sha256: "343e83bc7809fbda2591a49e525d6b63213ade10c76f15813be9aed6657b3261" url: "https://pub.flutter-io.cn" source: hosted - version: "0.1.18" + version: "0.1.21" audio_video_progress_bar: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 80a8b067..6ee98cc3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -89,8 +89,8 @@ dependencies: media_kit_libs_video: ^1.0.4 # 媒体通知 - audio_service: ^0.18.13 - audio_session: ^0.1.18 + audio_service: ^0.18.15 + audio_session: ^0.1.21 # 音量、亮度、屏幕控制 flutter_volume_controller: ^1.3.2