Merge branch 'main' into fix

This commit is contained in:
guozhigq
2024-10-10 23:57:03 +08:00
18 changed files with 178 additions and 78 deletions

View File

@ -12,7 +12,6 @@ on:
- ".idea/**"
- "!.github/workflows/**"
jobs:
update_version:
name: Read and update version
@ -96,7 +95,7 @@ jobs:
if: steps.cache-flutter.outputs.cache-hit != 'true'
uses: subosito/flutter-action@v2
with:
flutter-version: 3.16.5
flutter-version: 3.19.6
channel: any
- name: 下载项目依赖

View File

@ -36,7 +36,7 @@ jobs:
if: steps.cache-flutter.outputs.cache-hit != 'true'
uses: subosito/flutter-action@v2
with:
flutter-version: 3.16.5
flutter-version: 3.19.6
channel: any
- name: 下载项目依赖
@ -98,7 +98,7 @@ jobs:
uses: subosito/flutter-action@v2.10.0
with:
cache: true
flutter-version: 3.16.5
flutter-version: 3.19.6
- name: flutter build ipa
run: |

39
change_log/1.0.25.1010.md Normal file
View File

@ -0,0 +1,39 @@
## 1.0.25
### 功能
+ 直播弹幕
+ 稍后再看、收藏夹播放全部
+ 收藏夹新建、编辑
+ 评论删除
+ 评论保存为图片
+ 动态页滑动切换up
+ up投稿筛选充电视频
+ 直播tab展示关注up
+ up主页专栏展示
### 优化
+ 视频详情页一键三连
+ 动态页标识充电视频
+ 播放器亮度、音量调整百分比展示
+ 封面预览时视频标题可复制
+ 竖屏直播布局
+ 图片预览
+ 专栏渲染优化
+ 私信图片查看
### 修复
+ 收藏夹点击异常
+ 搜索up异常
+ 系统通知已读异常
+ [赞了我的]展示错误
+ 部分up合集无法打开
+ 切换合集视频投币个数未重置
+ 搜索条件筛选面板无法滚动
+ 部分机型导航条未沉浸
+ 专栏图片渲染问题
+ 专栏浏览历史记录
+ 直播间历史记录
更多更新日志可在Github上查看
问题反馈、功能建议请查看「关于」页面。

View File

@ -1,6 +1,7 @@
class MediaVideoItemModel {
MediaVideoItemModel({
this.id,
this.aid,
this.offset,
this.index,
this.intro,
@ -14,12 +15,13 @@ class MediaVideoItemModel {
this.likeState,
this.favState,
this.page,
this.cid,
this.pages,
this.title,
this.type,
this.upper,
this.link,
this.bvId,
this.bvid,
this.shortLink,
this.rights,
this.elecInfo,
@ -32,6 +34,7 @@ class MediaVideoItemModel {
});
int? id;
int? aid;
int? offset;
int? index;
String? intro;
@ -45,12 +48,13 @@ class MediaVideoItemModel {
int? likeState;
int? favState;
int? page;
int? cid;
List<Page>? pages;
String? title;
int? type;
Upper? upper;
String? link;
String? bvId;
String? bvid;
String? shortLink;
Rights? rights;
dynamic elecInfo;
@ -64,6 +68,7 @@ class MediaVideoItemModel {
factory MediaVideoItemModel.fromJson(Map<String, dynamic> json) =>
MediaVideoItemModel(
id: json["id"],
aid: json["id"],
offset: json["offset"],
index: json["index"],
intro: json["intro"],
@ -77,6 +82,7 @@ class MediaVideoItemModel {
likeState: json["like_state"],
favState: json["fav_state"],
page: json["page"],
cid: json["pages"] == null ? -1 : json["pages"].first['id'],
// json["pages"] 可能为null
pages: json["pages"] == null
? []
@ -85,7 +91,7 @@ class MediaVideoItemModel {
type: json["type"],
upper: Upper.fromJson(json["upper"]),
link: json["link"],
bvId: json["bv_id"],
bvid: json["bv_id"],
shortLink: json["short_link"],
rights: Rights.fromJson(json["rights"]),
elecInfo: json["elec_info"],

View File

@ -189,8 +189,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
Stack(
children: [
NetworkImgLayer(
width: 105,
height: 160,
width: 115,
height: 115 / 0.75,
src: widget.bangumiDetail!.cover!,
),
PBadge(
@ -208,7 +208,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
child: InkWell(
onTap: () => showIntroDetail(),
child: SizedBox(
height: 158,
height: 115 / 0.75,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,

View File

@ -96,7 +96,8 @@ class _BangumiPageState extends State<BangumiPage>
),
),
SizedBox(
height: 268,
height: Get.size.width / 3 / 0.75 +
MediaQuery.textScalerOf(context).scale(50.0),
child: FutureBuilder(
future: _futureBuilderFutureFollow,
builder:
@ -117,7 +118,6 @@ class _BangumiPageState extends State<BangumiPage>
itemBuilder: (context, index) {
return Container(
width: Get.size.width / 3,
height: 254,
margin: EdgeInsets.only(
left: StyleString.safeSpace,
right: index ==
@ -208,8 +208,8 @@ class _BangumiPageState extends State<BangumiPage>
crossAxisSpacing: StyleString.cardSpace,
// 列数
crossAxisCount: 3,
mainAxisExtent: Get.size.width / 3 / 0.65 +
MediaQuery.textScalerOf(context).scale(32.0),
mainAxisExtent: Get.size.width / 3 / 0.75 +
MediaQuery.textScalerOf(context).scale(42.0),
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {

View File

@ -86,9 +86,11 @@ class _BangumiPanelState extends State<BangumiPanel> {
item.aid,
item.cover,
);
if (_bottomSheetController != null) {
_bottomSheetController?.close();
}
try {
if (_bottomSheetController != null) {
_bottomSheetController?.close();
}
} catch (_) {}
currentIndex.value = i;
scrollToIndex();
}

View File

@ -37,7 +37,7 @@ class BangumiCardV extends StatelessWidget {
StyleString.imgRadius,
),
child: AspectRatio(
aspectRatio: 0.65,
aspectRatio: 0.75,
child: LayoutBuilder(builder: (context, boxConstraints) {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;

View File

@ -157,7 +157,7 @@ class _OpusPageState extends State<OpusPage> {
Container(
alignment: TextHelper.getAlignment(paragraph.align),
margin: const EdgeInsets.only(bottom: 10),
child: Text.rich(
child: SelectableText.rich(
TextSpan(
children: paragraph.text?.nodes?.map((node) {
return TextHelper.buildTextSpan(

View File

@ -20,7 +20,7 @@ class ReadPageController extends GetxController {
super.onInit();
title.value = Get.parameters['title'] ?? '';
id = Get.parameters['id']!;
articleType = Get.parameters['articleType']!;
articleType = Get.parameters['articleType'] ?? 'read';
url = 'https://www.bilibili.com/read/cv$id';
scrollController.addListener(_scrollListener);
fetchViewInfo();

View File

@ -126,7 +126,6 @@ class _ReadPageState extends State<ReadPage> {
Widget _buildContent(ReadDataModel cvData) {
final List<String> picList = _extractPicList(cvData);
final List<String> imgList = extractDataSrc(cvData.readInfo!.content!);
return Padding(
padding: EdgeInsets.fromLTRB(
16, 0, 16, MediaQuery.of(context).padding.bottom + 40),
@ -163,9 +162,11 @@ class _ReadPageState extends State<ReadPage> {
padding: const EdgeInsets.only(bottom: 20),
child: _buildAuthorWidget(cvData),
),
HtmlRender(
htmlContent: cvData.readInfo!.content!,
imgList: imgList,
SelectionArea(
child: HtmlRender(
htmlContent: cvData.readInfo!.content!,
imgList: imgList,
),
),
],
);
@ -206,7 +207,7 @@ class _ReadPageState extends State<ReadPage> {
return Container(
alignment: TextHelper.getAlignment(paragraph.align),
margin: const EdgeInsets.only(bottom: 10),
child: Text.rich(
child: SelectableText.rich(
TextSpan(
children: paragraph.text?.nodes?.map((node) {
return TextHelper.buildTextSpan(node, paragraph.align, context);

View File

@ -411,7 +411,12 @@ class VideoIntroController extends GetxController {
}
// 修改分P或番剧分集
Future changeSeasonOrbangu(bvid, cid, aid, cover) async {
Future changeSeasonOrbangu(
String bvid,
int cid,
int? aid,
String? cover,
) async {
// 重新获取视频资源
final VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: heroTag);
@ -422,13 +427,14 @@ class VideoIntroController extends GetxController {
releatedCtr.queryRelatedVideo();
}
videoDetailCtr.bvid = bvid;
videoDetailCtr.oid.value = aid ?? IdUtils.bv2av(bvid);
videoDetailCtr.cid.value = cid;
videoDetailCtr.danmakuCid.value = cid;
videoDetailCtr.cover.value = cover;
videoDetailCtr.queryVideoUrl();
videoDetailCtr.clearSubtitleContent();
videoDetailCtr
..bvid = bvid
..oid.value = aid ?? IdUtils.bv2av(bvid)
..cid.value = cid
..danmakuCid.value = cid
..cover.value = cover ?? ''
..queryVideoUrl()
..clearSubtitleContent();
await videoDetailCtr.getSubtitle();
videoDetailCtr.setSubtitleContent();
// 重新请求评论
@ -478,7 +484,13 @@ class VideoIntroController extends GetxController {
final List episodes = [];
bool isPages = false;
late String cover;
if (videoDetail.value.ugcSeason != null) {
final VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: heroTag);
/// 优先稍后再看、收藏夹
if (videoDetailCtr.isWatchLaterVisible.value) {
episodes.addAll(videoDetailCtr.mediaList);
} else if (videoDetail.value.ugcSeason != null) {
final UgcSeason ugcSeason = videoDetail.value.ugcSeason!;
final List<SectionItem> sections = ugcSeason.sections!;
for (int i = 0; i < sections.length; i++) {
@ -495,10 +507,15 @@ class VideoIntroController extends GetxController {
episodes.indexWhere((e) => e.cid == lastPlayCid.value);
int nextIndex = currentIndex + 1;
cover = episodes[nextIndex].cover;
final VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: heroTag);
final PlayRepeat platRepeat = videoDetailCtr.plPlayerController.playRepeat;
int cid = episodes[nextIndex].cid!;
while (cid == -1) {
nextIndex += 1;
SmartDialog.showToast('当前视频暂不支持播放,自动跳过');
cid = episodes[nextIndex].cid!;
}
// 列表循环
if (nextIndex >= episodes.length) {
if (platRepeat == PlayRepeat.listCycle) {
@ -508,7 +525,6 @@ class VideoIntroController extends GetxController {
return;
}
}
final int cid = episodes[nextIndex].cid!;
final String rBvid = isPages ? bvid : episodes[nextIndex].bvid;
final int rAid = isPages ? IdUtils.bv2av(bvid) : episodes[nextIndex].aid!;
changeSeasonOrbangu(rBvid, cid, rAid, cover);

View File

@ -153,7 +153,17 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
child: Container(
height: 40,
padding: const EdgeInsets.fromLTRB(12, 0, 6, 0),
color: Theme.of(context).colorScheme.surface,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
boxShadow: [
BoxShadow(
color: Theme.of(context).colorScheme.surface,
blurRadius: 0.0,
spreadRadius: 0.0,
offset: const Offset(2, 0),
),
],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [

View File

@ -200,25 +200,36 @@ class ReplyItem extends StatelessWidget {
),
],
),
Row(
children: <Widget>[
Text(
Utils.dateFormat(replyItem!.ctime),
style: TextStyle(
fontSize: textTheme.labelSmall!.fontSize,
color: colorScheme.outline,
),
),
if (replyItem!.replyControl != null &&
replyItem!.replyControl!.location != '')
Text(
'${replyItem!.replyControl!.location!}',
RichText(
text: TextSpan(
children: [
TextSpan(
text: Utils.dateFormat(replyItem!.ctime),
style: TextStyle(
fontSize: textTheme.labelSmall!.fontSize,
color: colorScheme.outline),
fontSize: textTheme.labelSmall!.fontSize,
color: colorScheme.outline,
),
),
],
)
if (replyItem!.replyControl != null &&
replyItem!.replyControl!.location != '')
TextSpan(
text: '${replyItem!.replyControl!.location!}',
style: TextStyle(
fontSize: textTheme.labelSmall!.fontSize,
color: colorScheme.outline,
),
),
if (replyItem!.invisible!)
TextSpan(
text: ' • 隐藏的评论',
style: TextStyle(
color: colorScheme.outline,
fontSize: textTheme.labelSmall!.fontSize,
),
),
],
),
),
],
),
],
@ -703,14 +714,11 @@ InlineSpan buildContent(
'',
);
} else if (RegExp(r'^cv\d+$').hasMatch(matchStr)) {
Get.toNamed(
'/webview',
parameters: {
'url': 'https://www.bilibili.com/read/$matchStr',
'type': 'url',
'pageTitle': title
},
);
Get.toNamed('/read', parameters: {
'title': title,
'id': Utils.matchNum(matchStr).first.toString(),
'articleType': 'read',
});
} else {
Uri uri = Uri.parse(matchStr.replaceAll('/?', '?'));
SchemeEntity scheme = SchemeEntity(

View File

@ -3,6 +3,7 @@ import 'dart:io';
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:floating/floating.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:flutter_svg/svg.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
@ -81,14 +82,16 @@ class _VideoDetailPageState extends State<VideoDetailPage>
videoIntroController.videoDetail.listen((value) {
videoPlayerServiceHandler.onVideoDetailChange(value, vdCtr.cid.value);
});
bangumiIntroController = Get.put(BangumiIntroController(), tag: heroTag);
bangumiIntroController.bangumiDetail.listen((value) {
videoPlayerServiceHandler.onVideoDetailChange(value, vdCtr.cid.value);
});
vdCtr.cid.listen((p0) {
videoPlayerServiceHandler.onVideoDetailChange(
bangumiIntroController.bangumiDetail.value, p0);
});
if (vdCtr.videoType == SearchType.media_bangumi) {
bangumiIntroController = Get.put(BangumiIntroController(), tag: heroTag);
bangumiIntroController.bangumiDetail.listen((value) {
videoPlayerServiceHandler.onVideoDetailChange(value, vdCtr.cid.value);
});
vdCtr.cid.listen((p0) {
videoPlayerServiceHandler.onVideoDetailChange(
bangumiIntroController.bangumiDetail.value, p0);
});
}
statusBarHeight = localCache.get('statusBarHeight');
autoExitFullcreen =
setting.get(SettingBoxKey.enableAutoExit, defaultValue: false);
@ -594,10 +597,21 @@ class _VideoDetailPageState extends State<VideoDetailPage>
key: vdCtr.scaffoldKey,
appBar: PreferredSize(
preferredSize: const Size.fromHeight(0),
child: AppBar(
backgroundColor: Colors.black,
elevation: 0,
scrolledUnderElevation: 0,
child: StreamBuilder(
stream: appbarStream.stream.distinct(),
initialData: 0,
builder: ((context, snapshot) {
return AppBar(
backgroundColor: Colors.black,
elevation: 0,
scrolledUnderElevation: 0,
systemOverlayStyle: Get.isDarkMode
? SystemUiOverlayStyle.light
: snapshot.data!.toDouble() > kToolbarHeight
? SystemUiOverlayStyle.dark
: SystemUiOverlayStyle.light,
);
}),
),
),
body: ExtendedNestedScrollView(

View File

@ -109,7 +109,7 @@ class _MediaListPanelState extends State<MediaListPanel> {
var item = mediaList[index];
return InkWell(
onTap: () async {
String bvid = item.bvId!;
String bvid = item.bvid!;
int? aid = item.id;
String cover = item.cover ?? '';
final int cid =
@ -173,7 +173,7 @@ class _MediaListPanelState extends State<MediaListPanel> {
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.w500,
color: item.bvId == widget.bvid
color: item.bvid == widget.bvid
? Theme.of(context)
.colorScheme
.primary

View File

@ -175,6 +175,11 @@ class PiliSchame {
if (lastPathSegment.contains('ep')) {
RoutePush.bangumiPush(null, Utils.matchNum(lastPathSegment).first);
}
} else if (path.startsWith('/BV')) {
final String bvid = path.split('?').first.split('/').last;
_videoPush(null, bvid);
} else if (path.startsWith('/av')) {
_videoPush(Utils.matchNum(path.split('?').first).first, null);
}
} else if (host.contains('live')) {
int roomId = int.parse(path!.split('/').last);

View File

@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.24+1024
version: 1.0.25+1025
environment:
sdk: ">=3.0.0 <4.0.0"