Compare commits

...

10 Commits

Author SHA1 Message Date
dom
3b9403a329 fix #2305
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-06 12:03:12 +08:00
dom
c44e92dcc8 update patch
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-06 09:41:52 +08:00
dom
14d1c37df5 flutter 3.44.1
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-06 09:37:11 +08:00
dom
78b3df4019 validate cookie on login
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-06 08:55:38 +08:00
dom
9acb32aaeb opt logout main
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-06 08:54:38 +08:00
dom
50070997de fix #2308
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-05 20:36:39 +08:00
dom
88f0ab1dea opt chat item
Closes #2292

Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-05 10:45:32 +08:00
dom
038285cbe6 fix parse opus
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-05 10:44:32 +08:00
dom
295a587df5 lint
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-04 19:17:59 +08:00
dom
73d7d78080 fix #2295
Signed-off-by: dom <githubaccount56556@proton.me>
2026-06-04 19:17:59 +08:00
17 changed files with 161 additions and 115 deletions

2
.fvmrc
View File

@@ -1,3 +1,3 @@
{ {
"flutter": "3.44.0" "flutter": "3.44.1"
} }

View File

@@ -57,7 +57,7 @@ abstract final class DynamicsHttp {
tempBannedList: tempBannedList, tempBannedList: tempBannedList,
); );
if (data.loadNext == true) { if (data.loadNext == true) {
return followDynamic( return await followDynamic(
type: type, type: type,
offset: data.offset, offset: data.offset,
mid: mid, mid: mid,

View File

@@ -471,7 +471,7 @@ abstract final class MemberHttp {
try { try {
DynamicsDataModel data = DynamicsDataModel.fromJson(res.data['data']); DynamicsDataModel data = DynamicsDataModel.fromJson(res.data['data']);
if (data.loadNext == true) { if (data.loadNext == true) {
return memberDynamic(offset: data.offset, mid: mid); return await memberDynamic(offset: data.offset, mid: mid);
} }
return Success(data); return Success(data);
} catch (e, s) { } catch (e, s) {

View File

@@ -260,7 +260,7 @@ abstract final class VideoHttp {
} }
return Success(data); return Success(data);
} else if (epid != null && videoType == VideoType.ugc) { } else if (epid != null && videoType == VideoType.ugc) {
return videoUrl( return await videoUrl(
avid: avid, avid: avid,
bvid: bvid, bvid: bvid,
cid: cid, cid: cid,

View File

@@ -1,6 +1,8 @@
import 'package:PiliPlus/common/style.dart' as common_style; import 'package:PiliPlus/common/style.dart' as common_style;
import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/models/dynamics/vote_model.dart'; import 'package:PiliPlus/models/dynamics/vote_model.dart';
import 'package:PiliPlus/utils/color_utils.dart';
import 'package:PiliPlus/utils/parse_int.dart';
class ArticleContentModel { class ArticleContentModel {
int? align; int? align;
@@ -124,14 +126,14 @@ class Word {
Word.fromJson(Map<String, dynamic> json) { Word.fromJson(Map<String, dynamic> json) {
words = json['words']; words = json['words'];
fontSize = (json['font_size'] as num?)?.toDouble(); if (json['font_size'] case final num rawSize when rawSize != 0) {
fontSize = rawSize.toDouble();
}
style = json['style'] == null ? null : Style.fromJson(json['style']); style = json['style'] == null ? null : Style.fromJson(json['style']);
color = json['color'] == null if (json['color'] case final String rawColor
? null when rawColor.startsWith('#')) {
: int.tryParse( color = ColourUtils.parse2Int(json['color']);
'FF${(json['color'] as String).substring(1)}', }
radix: 16,
);
fontLevel = json['font_level']; fontLevel = json['font_level'];
} }
@@ -275,7 +277,7 @@ class Music {
Music.fromJson(Map<String, dynamic> json) { Music.fromJson(Map<String, dynamic> json) {
cover = json['cover']; cover = json['cover'];
id = json['id']; id = safeToInt(json['id']);
jumpUrl = json['jump_url']; jumpUrl = json['jump_url'];
label = json['label']; label = json['label'];
title = json['title']; title = json['title'];
@@ -291,12 +293,12 @@ class Opus {
int? statView; int? statView;
Opus.fromJson(Map<String, dynamic> json) { Opus.fromJson(Map<String, dynamic> json) {
authorMid = json['author']?['mid']; authorMid = safeToInt(json['author']?['mid']);
authorName = json['author']?['name']; authorName = json['author']?['name'];
cover = json['cover']; cover = json['cover'];
jumpUrl = json['jump_url']; jumpUrl = json['jump_url'];
title = json['title']; title = json['title'];
statView = json['stat']?['view']; statView = safeToInt(json['stat']?['view']);
} }
} }
@@ -317,9 +319,9 @@ class Live {
descSecond = json['desc_second']; descSecond = json['desc_second'];
title = json['title']; title = json['title'];
jumpUrl = json['jump_url']; jumpUrl = json['jump_url'];
id = json['id']; id = safeToInt(json['id']);
liveState = json['live_state']; liveState = safeToInt(json['live_state']);
reserveType = json['reserve_type']; reserveType = safeToInt(json['reserve_type']);
badgeText = json['badge']?['text']; badgeText = json['badge']?['text'];
} }
} }

View File

@@ -1,4 +1,5 @@
import 'package:PiliPlus/utils/extension/iterable_ext.dart'; import 'package:PiliPlus/utils/extension/iterable_ext.dart';
import 'package:PiliPlus/utils/parse_int.dart';
class SimpleVoteInfo { class SimpleVoteInfo {
int? choiceCnt; int? choiceCnt;
@@ -22,14 +23,14 @@ class SimpleVoteInfo {
}); });
SimpleVoteInfo.fromJson(Map<String, dynamic> json) { SimpleVoteInfo.fromJson(Map<String, dynamic> json) {
choiceCnt = json['choice_cnt']; choiceCnt = safeToInt(json['choice_cnt']);
defaultShare = json['default_share']; defaultShare = safeToInt(json['default_share']);
desc = json['desc']; desc = json['desc'];
endTime = json['end_time']; endTime = safeToInt(json['end_time']);
status = json['status']; status = safeToInt(json['status']);
uid = json['uid']; uid = safeToInt(json['uid']);
voteId = json['vote_id']; voteId = safeToInt(json['vote_id']);
joinNum = json['join_num'] ?? 0; joinNum = safeToInt(json['join_num']) ?? 0;
} }
} }

View File

@@ -260,7 +260,7 @@ class OpusContent extends StatelessWidget {
.toList(), .toList(),
); );
} }
case 3 when (element.line != null): case 3 when (element.line?.pic != null):
final height = element.line!.pic!.height?.toDouble(); final height = element.line!.pic!.height?.toDouble();
return CachedNetworkImage( return CachedNetworkImage(
fit: .contain, fit: .contain,
@@ -336,6 +336,8 @@ class OpusContent extends StatelessWidget {
Text(ugc.title!), Text(ugc.title!),
Text( Text(
ugc.descSecond!, ugc.descSecond!,
maxLines: 2,
overflow: .ellipsis,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: colorScheme.outline, color: colorScheme.outline,
@@ -378,6 +380,8 @@ class OpusContent extends StatelessWidget {
if (common.desc2 != null) if (common.desc2 != null)
Text( Text(
common.desc2!, common.desc2!,
maxLines: 2,
overflow: .ellipsis,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: colorScheme.outline, color: colorScheme.outline,
@@ -415,6 +419,8 @@ class OpusContent extends StatelessWidget {
if (live.descSecond != null) if (live.descSecond != null)
Text( Text(
live.descSecond!, live.descSecond!,
maxLines: 2,
overflow: .ellipsis,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: colorScheme.outline, color: colorScheme.outline,
@@ -507,6 +513,8 @@ class OpusContent extends StatelessWidget {
if (music.label != null) if (music.label != null)
Text( Text(
music.label!, music.label!,
maxLines: 2,
overflow: .ellipsis,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: colorScheme.outline, color: colorScheme.outline,
@@ -693,9 +701,9 @@ class OpusContent extends StatelessWidget {
), ),
); );
} }
} catch (e) { } catch (e, s) {
return SelectableText( return SelectableText(
'错误的类型 $e', '错误的类型 $e${kDebugMode ? '\n$s' : ''}',
style: const TextStyle( style: const TextStyle(
fontWeight: .bold, fontWeight: .bold,
color: Colors.red, color: Colors.red,

View File

@@ -236,6 +236,20 @@ class LoginPageController extends GetxController
} }
} }
static String validateCookie(String cookie) {
return cookie
.split(';')
.where((e) {
try {
Cookie.fromSetCookieValue(e.trim());
} catch (_) {
return false;
}
return true;
})
.join(';');
}
// cookie登录 // cookie登录
Future<void> loginByCookie() async { Future<void> loginByCookie() async {
if (cookieTextController.text.isEmpty) { if (cookieTextController.text.isEmpty) {
@@ -247,7 +261,7 @@ class LoginPageController extends GetxController
"/x/member/web/account", "/x/member/web/account",
options: Options( options: Options(
headers: { headers: {
"cookie": cookieTextController.text, "cookie": validateCookie(cookieTextController.text),
}, },
extra: {'account': AnonymousAccount()}, extra: {'account': AnonymousAccount()},
), ),

View File

@@ -11,7 +11,6 @@ import 'package:PiliPlus/services/account_service.dart';
import 'package:PiliPlus/utils/accounts.dart'; import 'package:PiliPlus/utils/accounts.dart';
import 'package:PiliPlus/utils/accounts/account.dart'; import 'package:PiliPlus/utils/accounts/account.dart';
import 'package:PiliPlus/utils/extension/scroll_controller_ext.dart'; import 'package:PiliPlus/utils/extension/scroll_controller_ext.dart';
import 'package:PiliPlus/utils/login_utils.dart';
import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/storage_key.dart'; import 'package:PiliPlus/utils/storage_key.dart';
import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/storage_pref.dart';
@@ -112,20 +111,22 @@ class MineController extends CommonDataController<FavFolderData, FavFolderData>
..face.value = response.face! ..face.value = response.face!
..isLogin.value = true; ..isLogin.value = true;
} else { } else {
LoginUtils.onLogoutMain(); _onLogoutMain();
return; return;
} }
} else { } else {
final errMsg = res.toString(); final errMsg = res.toString();
SmartDialog.showToast(errMsg); SmartDialog.showToast(errMsg);
if (errMsg == '账号未登录') { if (errMsg == '账号未登录') {
LoginUtils.onLogoutMain(); _onLogoutMain();
return; return;
} }
} }
queryUserStatOwner(); queryUserStatOwner();
} }
void _onLogoutMain() => Accounts.deleteAll({Accounts.main});
Future<void> queryUserStatOwner() async { Future<void> queryUserStatOwner() async {
final res = await UserHttp.userStatOwner(); final res = await UserHttp.userStatOwner();
if (res case Success(:final response)) { if (res case Success(:final response)) {

View File

@@ -387,8 +387,13 @@ class _PayCoinsPageState extends State<PayCoinsPage>
], ],
) )
else else
SizedBox(height: 100, child: _buildCoinWidget(0, 1)), Center(
SizedBox(height: isV ? 25 : 10), child: SizedBox(height: 100, child: _buildCoinWidget(0, 1)),
),
if (isV)
const SizedBox(height: 25)
else
const SizedBox(height: 10),
if (_hasCopyright) if (_hasCopyright)
GestureDetector( GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,

View File

@@ -200,44 +200,45 @@ class ChatItem extends StatelessWidget {
Widget msgTypeCommonShareCard_14(dynamic content, Color textColor) { Widget msgTypeCommonShareCard_14(dynamic content, Color textColor) {
if (content['source'] == '直播') { if (content['source'] == '直播') {
return Column( return GestureDetector(
crossAxisAlignment: CrossAxisAlignment.start, behavior: .opaque,
children: [ onTap: () {
GestureDetector( dynamic roomId = content['sourceID'];
onTap: () { if (roomId is String) {
dynamic roomId = content['sourceID']; roomId = int.parse(roomId);
if (roomId is String) { }
roomId = int.parse(roomId); PageUtils.toLiveRoom(roomId);
} },
PageUtils.toLiveRoom(roomId); child: Column(
}, crossAxisAlignment: CrossAxisAlignment.start,
child: NetworkImgLayer( children: [
NetworkImgLayer(
width: 220, width: 220,
height: 123.75, height: 123.75,
src: content['cover'], src: content['cover'],
), ),
), const SizedBox(height: 6),
const SizedBox(height: 6), Text(
Text( content['title'] ?? "",
content['title'] ?? "", style: TextStyle(
style: TextStyle( letterSpacing: 0.6,
letterSpacing: 0.6, height: 1.5,
height: 1.5, color: textColor,
color: textColor, fontWeight: FontWeight.bold,
fontWeight: FontWeight.bold, ),
), ),
), const SizedBox(height: 1),
const SizedBox(height: 1), Text(
Text( '${content['author']} · 直播',
'${content['author']} · 直播', style: TextStyle(
style: TextStyle( letterSpacing: 0.6,
letterSpacing: 0.6, height: 1.5,
height: 1.5, color: textColor.withValues(alpha: 0.6),
color: textColor.withValues(alpha: 0.6), fontSize: 12,
fontSize: 12, ),
), ),
), ],
], ),
); );
} else { } else {
return def(textColor); return def(textColor);
@@ -246,6 +247,7 @@ class ChatItem extends StatelessWidget {
Widget msgTypeArticleCard_12(dynamic content, Color textColor) { Widget msgTypeArticleCard_12(dynamic content, Color textColor) {
return GestureDetector( return GestureDetector(
behavior: .opaque,
onTap: () => Get.toNamed( onTap: () => Get.toNamed(
'/articlePage', '/articlePage',
parameters: { parameters: {
@@ -267,7 +269,7 @@ class ChatItem extends StatelessWidget {
], ],
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
SelectableText( Text(
content['title'] ?? "", content['title'] ?? "",
style: TextStyle( style: TextStyle(
letterSpacing: 0.6, letterSpacing: 0.6,
@@ -278,8 +280,7 @@ class ChatItem extends StatelessWidget {
), ),
if (content['summary'] != null && content['summary'] != '') ...[ if (content['summary'] != null && content['summary'] != '') ...[
const SizedBox(height: 1), const SizedBox(height: 1),
SelectableText( Text(
scrollPhysics: const NeverScrollableScrollPhysics(),
content['summary'], content['summary'],
style: TextStyle( style: TextStyle(
letterSpacing: 0.6, letterSpacing: 0.6,
@@ -570,32 +571,20 @@ class ChatItem extends StatelessWidget {
'unsupported source type: ${content['source']}', 'unsupported source type: ${content['source']}',
); );
} }
return Column( return GestureDetector(
crossAxisAlignment: CrossAxisAlignment.start, onTap: onTap,
children: [ behavior: .opaque,
GestureDetector( child: Column(
onTap: onTap, crossAxisAlignment: CrossAxisAlignment.start,
child: NetworkImgLayer( children: [
NetworkImgLayer(
width: 220, width: 220,
height: 123.75, height: 123.75,
src: content['thumb'], src: content['thumb'],
), ),
), const SizedBox(height: 6),
const SizedBox(height: 6),
Text(
content['title'] ?? "",
style: TextStyle(
letterSpacing: 0.6,
height: 1.5,
color: textColor,
fontWeight: FontWeight.bold,
),
),
if (content['source'] == 6 &&
(content['headline'] as String?)?.isNotEmpty == true) ...[
const SizedBox(height: 1),
Text( Text(
content['headline'], content['title'] ?? "",
style: TextStyle( style: TextStyle(
letterSpacing: 0.6, letterSpacing: 0.6,
height: 1.5, height: 1.5,
@@ -603,20 +592,33 @@ class ChatItem extends StatelessWidget {
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
], if (content['source'] == 6 &&
if (content['author'] != null) ...[ (content['headline'] as String?)?.isNotEmpty == true) ...[
const SizedBox(height: 1), const SizedBox(height: 1),
Text( Text(
'${content['author']}${type != null ? ' · $type' : ''}', content['headline'],
style: TextStyle( style: TextStyle(
letterSpacing: 0.6, letterSpacing: 0.6,
height: 1.5, height: 1.5,
color: textColor.withValues(alpha: 0.6), color: textColor,
fontSize: 12, fontWeight: FontWeight.bold,
),
), ),
), ],
if (content['author'] != null) ...[
const SizedBox(height: 1),
Text(
'${content['author']}${type != null ? ' · $type' : ''}',
style: TextStyle(
letterSpacing: 0.6,
height: 1.5,
color: textColor.withValues(alpha: 0.6),
fontSize: 12,
),
),
],
], ],
], ),
); );
} }
@@ -749,7 +751,7 @@ class ChatItem extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
SelectableText( Text(
content['title'], content['title'],
style: theme.textTheme.titleMedium!.copyWith( style: theme.textTheme.titleMedium!.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,

View File

@@ -160,7 +160,7 @@ Future<ui.Image?> _getImg(String url) async {
key: cacheKey, key: cacheKey,
headers: Constants.baseHeaders, headers: Constants.baseHeaders,
); );
return _loadImg(fileInfo.path); return await _loadImg(fileInfo.path);
} catch (_) { } catch (_) {
return null; return null;
} }

View File

@@ -0,0 +1,13 @@
diff --git a/packages/flutter/lib/src/material/navigation_drawer.dart b/packages/flutter/lib/src/material/navigation_drawer.dart
index 8a16764cb0c..6b8545c3781 100644
--- a/packages/flutter/lib/src/material/navigation_drawer.dart
+++ b/packages/flutter/lib/src/material/navigation_drawer.dart
@@ -410,7 +410,7 @@ class _NavigationDestinationBuilder extends StatelessWidget {
child: _NavigationDestinationSemantics(
child: SizedBox(
height: navigationDrawerTheme.tileHeight ?? defaults.tileHeight,
- child: inkWell,
+ child: Material(type: MaterialType.transparency, child: inkWell),
),
),
);

View File

@@ -26,6 +26,9 @@ $ImageAnimPatch = "lib/scripts/image_anim.patch"
$LayoutBuilderPatch = "lib/scripts/layout_builder.patch" $LayoutBuilderPatch = "lib/scripts/layout_builder.patch"
# https://github.com/bggRGjQaUbCoE/PiliPlus/issues/2308
$NavigationDrawerPatch = "lib/scripts/navigation_drawer.patch"
# TODO: remove # TODO: remove
# https://github.com/flutter/flutter/issues/90223 # https://github.com/flutter/flutter/issues/90223
$ModalBarrierPatch = "lib/scripts/modal_barrier.patch" $ModalBarrierPatch = "lib/scripts/modal_barrier.patch"
@@ -46,7 +49,7 @@ Set-Location $env:FLUTTER_ROOT
$picks = @() $picks = @()
$reverts = @() $reverts = @()
$patches = @($ModalBarrierPatch, $TextSelectionPatch, $MouseCursorPatch, $patches = @($ModalBarrierPatch, $TextSelectionPatch, $MouseCursorPatch,
$ImageAnimPatch, $LayoutBuilderPatch) $ImageAnimPatch, $LayoutBuilderPatch, $NavigationDrawerPatch)
switch ($platform.ToLower()) { switch ($platform.ToLower()) {
"android" { "android" {
@@ -103,12 +106,7 @@ foreach ($patch in $patches) {
# TODO: remove # TODO: remove
if ($platform.ToLower() -eq "android") { if ($platform.ToLower() -eq "android") {
git stash "df67bb3b55323961184ae7117cc91c054f36a42c" | Set-Content -Path .\bin\internal\engine.version
git cherry-pick 625275cfae17b27c9049b0740a9ef67d626b3b1c -X ours
git reset --soft HEAD~1
git stash pop
git restore DEPS
"f84bd039a0692e5cab5383a8de29bc41151a4dfd" | Set-Content -Path .\bin\internal\engine.version
Remove-Item -Path ".\bin\cache" -Recurse -Force Remove-Item -Path ".\bin\cache" -Recurse -Force
flutter --version flutter --version
} }

View File

@@ -1,8 +1,10 @@
import 'package:flutter/rendering.dart' show Color; import 'package:flutter/rendering.dart' show Color;
abstract final class ColourUtils { abstract final class ColourUtils {
static Color parseColor(String color) => static int parse2Int(String color) =>
Color(0xFF000000 | int.parse(color.substring(1), radix: 16)); 0xFF000000 | int.parse(color.substring(1), radix: 16);
static Color parseColor(String color) => Color(parse2Int(color));
static Color parseMedalColor(String color) { static Color parseMedalColor(String color) {
final rgba = int.parse(color.substring(1), radix: 16); final rgba = int.parse(color.substring(1), radix: 16);

View File

@@ -234,7 +234,7 @@ packages:
description: description:
path: "." path: "."
ref: main ref: main
resolved-ref: b442c6c8309a17d8b9d395d08eadc401b42f4f8f resolved-ref: "697d4516df2fc3ba7417c7ce9aba079d34ba13e5"
url: "https://github.com/bggRGjQaUbCoE/canvas_danmaku.git" url: "https://github.com/bggRGjQaUbCoE/canvas_danmaku.git"
source: git source: git
version: "0.2.6" version: "0.2.6"
@@ -2001,4 +2001,4 @@ packages:
version: "3.1.3" version: "3.1.3"
sdks: sdks:
dart: ">=3.12.0 <4.0.0" dart: ">=3.12.0 <4.0.0"
flutter: "3.44.0" flutter: "3.44.1"

View File

@@ -21,7 +21,7 @@ version: 2.0.8+1
environment: environment:
sdk: ">=3.12.0" sdk: ">=3.12.0"
flutter: 3.44.0 flutter: 3.44.1
# Dependencies specify other packages that your package needs in order to work. # Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions # To automatically upgrade your package dependencies to the latest versions