Merge branch 'main' into feature-login

This commit is contained in:
guozhigq
2024-06-06 23:36:53 +08:00
74 changed files with 1079 additions and 740 deletions

View File

@ -94,7 +94,7 @@ QQ频道: https://pd.qq.com/s/365esodk3
- [x] 音质选择(视视频而定) - [x] 音质选择(视视频而定)
- [x] 解码格式选择(视视频而定) - [x] 解码格式选择(视视频而定)
- [x] 弹幕 - [x] 弹幕
- [ ] 字幕 - [x] 字幕
- [x] 记忆播放 - [x] 记忆播放
- [x] 视频比例:高度/宽度适应、填充、包含等 - [x] 视频比例:高度/宽度适应、填充、包含等

View File

@ -1,5 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.7.10' ext.kotlin_version = '1.9.0'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()

1
assets/loading.json Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

14
change_log/1.0.23.0504.md Normal file
View File

@ -0,0 +1,14 @@
## 1.0.23
### 功能
+ 封面下载
### 修复
+ 全屏问题
+ 视频播放器灰屏问题
+ 评论区点击区域问题
更多更新日志可在Github上查看
问题反馈、功能建议请查看「关于」页面。

View File

@ -21,6 +21,6 @@
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key> <key>MinimumOSVersion</key>
<string>11.0</string> <string>12.0</string>
</dict> </dict>
</plist> </plist>

View File

@ -10,7 +10,6 @@ PODS:
- connectivity_plus (0.0.1): - connectivity_plus (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- ReachabilitySwift
- device_info_plus (0.0.1): - device_info_plus (0.0.1):
- Flutter - Flutter
- Flutter (1.0.0) - Flutter (1.0.0)
@ -41,7 +40,6 @@ PODS:
- FlutterMacOS - FlutterMacOS
- permission_handler_apple (9.3.0): - permission_handler_apple (9.3.0):
- Flutter - Flutter
- ReachabilitySwift (5.0.0)
- saver_gallery (0.0.1): - saver_gallery (0.0.1):
- Flutter - Flutter
- screen_brightness_ios (0.1.0): - screen_brightness_ios (0.1.0):
@ -101,7 +99,6 @@ SPEC REPOS:
trunk: trunk:
- FMDB - FMDB
- GT3Captcha-iOS - GT3Captcha-iOS
- ReachabilitySwift
- Toast - Toast
EXTERNAL SOURCES: EXTERNAL SOURCES:
@ -167,9 +164,9 @@ SPEC CHECKSUMS:
audio_service: f509d65da41b9521a61f1c404dd58651f265a567 audio_service: f509d65da41b9521a61f1c404dd58651f265a567
audio_session: 4f3e461722055d21515cf3261b64c973c062f345 audio_session: 4f3e461722055d21515cf3261b64c973c062f345
auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d
connectivity_plus: e2dad488011aeb593e219360e804c43cc1af5770 connectivity_plus: ddd7f30999e1faaef5967c23d5b6d503d10434db
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529 flutter_volume_controller: e4d5832f08008180f76e30faf671ffd5a425e529
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265 fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
@ -182,7 +179,6 @@ SPEC CHECKSUMS:
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85 package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
saver_gallery: 2b4e584106fde2407ab51560f3851564963e6b78 saver_gallery: 2b4e584106fde2407ab51560f3851564963e6b78
screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625 screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5 share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
@ -190,11 +186,11 @@ SPEC CHECKSUMS:
status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446 status_bar_control: 7c84146799e6a076315cc1550f78ef53aae3e446
system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44 system_proxy: bec1a5c5af67dd3e3ebf43979400a8756c04cc44
Toast: ec33c32b8688982cecc6348adeae667c1b9938da Toast: ec33c32b8688982cecc6348adeae667c1b9938da
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7 webview_cookie_manager: eaf920722b493bd0f7611b5484771ca53fed03f7
webview_flutter_wkwebview: 4f3e50f7273d31e5500066ed267e3ae4309c5ae4 webview_flutter_wkwebview: be0f0d33777f1bfd0c9fdcb594786704dbf65f36
PODFILE CHECKSUM: 637cd290bed23275b5f5ffcc7eb1e73d0a5fb2be PODFILE CHECKSUM: 637cd290bed23275b5f5ffcc7eb1e73d0a5fb2be

View File

@ -156,7 +156,7 @@
97C146E61CF9000F007C117D /* Project object */ = { 97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 1430; LastUpgradeCheck = 1510;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1430" LastUpgradeVersion = "1510"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -34,6 +34,9 @@ class NetworkImgLayer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final int defaultImgQuality = GlobalData().imgQuality; final int defaultImgQuality = GlobalData().imgQuality;
if (src == '' || src == null) {
return placeholder(context);
}
final String imageUrl = final String imageUrl =
'${src!.startsWith('//') ? 'https:${src!}' : src!}@${quality ?? defaultImgQuality}q.webp'; '${src!.startsWith('//') ? 'https:${src!}' : src!}@${quality ?? defaultImgQuality}q.webp';
int? memCacheWidth, memCacheHeight; int? memCacheWidth, memCacheHeight;

View File

@ -20,11 +20,13 @@ import 'network_img_layer.dart';
class VideoCardV extends StatelessWidget { class VideoCardV extends StatelessWidget {
final dynamic videoItem; final dynamic videoItem;
final int crossAxisCount; final int crossAxisCount;
final Function? blockUserCb;
const VideoCardV({ const VideoCardV({
Key? key, Key? key,
required this.videoItem, required this.videoItem,
required this.crossAxisCount, required this.crossAxisCount,
this.blockUserCb,
}) : super(key: key); }) : super(key: key);
bool isStringNumeric(String str) { bool isStringNumeric(String str) {
@ -157,7 +159,11 @@ class VideoCardV extends StatelessWidget {
); );
}), }),
), ),
VideoContent(videoItem: videoItem, crossAxisCount: crossAxisCount) VideoContent(
videoItem: videoItem,
crossAxisCount: crossAxisCount,
blockUserCb: blockUserCb,
)
], ],
), ),
); );
@ -167,9 +173,14 @@ class VideoCardV extends StatelessWidget {
class VideoContent extends StatelessWidget { class VideoContent extends StatelessWidget {
final dynamic videoItem; final dynamic videoItem;
final int crossAxisCount; final int crossAxisCount;
const VideoContent( final Function? blockUserCb;
{Key? key, required this.videoItem, required this.crossAxisCount})
: super(key: key); const VideoContent({
Key? key,
required this.videoItem,
required this.crossAxisCount,
this.blockUserCb,
}) : super(key: key);
Widget _buildBadge(String text, String type, [double fs = 12]) { Widget _buildBadge(String text, String type, [double fs = 12]) {
return PBadge( return PBadge(
@ -241,7 +252,10 @@ class VideoContent extends StatelessWidget {
useRootNavigator: true, useRootNavigator: true,
isScrollControlled: true, isScrollControlled: true,
builder: (context) { builder: (context) {
return MorePanel(videoItem: videoItem); return MorePanel(
videoItem: videoItem,
blockUserCb: blockUserCb,
);
}, },
); );
}, },
@ -297,11 +311,17 @@ class VideoStat extends StatelessWidget {
class MorePanel extends StatelessWidget { class MorePanel extends StatelessWidget {
final dynamic videoItem; final dynamic videoItem;
const MorePanel({super.key, required this.videoItem}); final Function? blockUserCb;
const MorePanel({
super.key,
required this.videoItem,
this.blockUserCb,
});
Future<dynamic> menuActionHandler(String type) async { Future<dynamic> menuActionHandler(String type) async {
switch (type) { switch (type) {
case 'block': case 'block':
Get.back();
blockUser(); blockUser();
break; break;
case 'watchLater': case 'watchLater':
@ -338,7 +358,10 @@ class MorePanel extends StatelessWidget {
reSrc: 11, reSrc: 11,
); );
SmartDialog.dismiss(); SmartDialog.dismiss();
SmartDialog.showToast(res['msg'] ?? '成功'); if (res['status']) {
blockUserCb?.call(videoItem.owner.mid);
}
SmartDialog.showToast(res['msg']);
}, },
child: const Text('确认'), child: const Text('确认'),
) )

View File

@ -520,4 +520,7 @@ class Api {
/// 删除收藏夹 /// 删除收藏夹
static const String delFavFolder = '/x/v3/fav/folder/del'; static const String delFavFolder = '/x/v3/fav/folder/del';
/// 搜索结果计数
static const String searchCount = '/x/web-interface/wbi/search/all/v2';
} }

View File

@ -41,6 +41,7 @@ class DynamicsHttp {
'status': false, 'status': false,
'data': [], 'data': [],
'msg': res.data['message'], 'msg': res.data['message'],
'code': res.data['code'],
}; };
} }
} }

View File

@ -46,7 +46,7 @@ class ApiInterceptor extends Interceptor {
// 处理网络请求错误 // 处理网络请求错误
// handler.next(err); // handler.next(err);
String url = err.requestOptions.uri.toString(); String url = err.requestOptions.uri.toString();
if (!url.contains('heartBeat')) { if (!url.contains('heartbeat')) {
SmartDialog.showToast( SmartDialog.showToast(
await dioError(err), await dioError(err),
displayType: SmartToastType.onlyRefresh, displayType: SmartToastType.onlyRefresh,

View File

@ -1,5 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/models/search/all.dart';
import 'package:pilipala/utils/wbi_sign.dart';
import '../models/bangumi/info.dart'; import '../models/bangumi/info.dart';
import '../models/common/search_type.dart'; import '../models/common/search_type.dart';
import '../models/search/hot.dart'; import '../models/search/hot.dart';
@ -179,4 +181,26 @@ class SearchHttp {
'pic': res.data['data'].first['first_frame'], 'pic': res.data['data'].first['first_frame'],
}; };
} }
static Future<Map<String, dynamic>> searchCount(
{required String keyword}) async {
Map<String, dynamic> data = {
'keyword': keyword,
'web_location': 333.999,
};
Map params = await WbiSign().makSign(data);
final dynamic res = await Request().get(Api.searchCount, data: params);
if (res.data['code'] == 0) {
return {
'status': true,
'data': SearchAllModel.fromJson(res.data['data']),
};
} else {
return {
'status': false,
'data': [],
'msg': '请求错误 🙅',
};
}
}
} }

View File

@ -62,7 +62,8 @@ class UserHttp {
return { return {
'status': false, 'status': false,
'data': [], 'data': [],
'msg': res.data['message'] ?? '账号未登录' 'msg': res.data['message'],
'code': res.data['code'],
}; };
} }
} }
@ -111,7 +112,12 @@ class UserHttp {
'data': {'list': list, 'count': res.data['data']['count']} 'data': {'list': list, 'count': res.data['data']['count']}
}; };
} else { } else {
return {'status': false, 'data': [], 'msg': res.data['message']}; return {
'status': false,
'data': [],
'msg': res.data['message'],
'code': res.data['code'],
};
} }
} }
@ -126,7 +132,12 @@ class UserHttp {
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return {'status': true, 'data': HistoryData.fromJson(res.data['data'])}; return {'status': true, 'data': HistoryData.fromJson(res.data['data'])};
} else { } else {
return {'status': false, 'data': [], 'msg': res.data['message']}; return {
'status': false,
'data': [],
'msg': res.data['message'],
'code': res.data['code'],
};
} }
} }
@ -326,7 +337,12 @@ class UserHttp {
'data': SubFolderModelData.fromJson(res.data['data']) 'data': SubFolderModelData.fromJson(res.data['data'])
}; };
} else { } else {
return {'status': false, 'msg': res.data['message']}; return {
'status': false,
'data': [],
'msg': res.data['message'],
'code': res.data['code'],
};
} }
} }

View File

@ -387,9 +387,15 @@ class VideoHttp {
'csrf': await Request.getCsrf(), 'csrf': await Request.getCsrf(),
}); });
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
return {'status': true, 'data': res.data['data']}; if (act == 5) {
List<int> blackMidsList =
setting.get(SettingBoxKey.blackMidsList, defaultValue: [-1]);
blackMidsList.add(mid);
setting.put(SettingBoxKey.blackMidsList, blackMidsList);
}
return {'status': true, 'data': res.data['data'], 'msg': '成功'};
} else { } else {
return {'status': false, 'data': []}; return {'status': false, 'data': [], 'msg': res.data['message']};
} }
} }

View File

@ -23,7 +23,7 @@ import 'package:pilipala/utils/app_scheme.dart';
import 'package:pilipala/utils/data.dart'; import 'package:pilipala/utils/data.dart';
import 'package:pilipala/utils/global_data.dart'; import 'package:pilipala/utils/global_data.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:media_kit/media_kit.dart'; // Provides [Player], [Media], [Playlist] etc. import 'package:media_kit/media_kit.dart';
import 'package:pilipala/utils/recommend_filter.dart'; import 'package:pilipala/utils/recommend_filter.dart';
import 'package:catcher_2/catcher_2.dart'; import 'package:catcher_2/catcher_2.dart';
import './services/loggeer.dart'; import './services/loggeer.dart';
@ -31,35 +31,21 @@ import './services/loggeer.dart';
void main() async { void main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
MediaKit.ensureInitialized(); MediaKit.ensureInitialized();
SystemChrome.setPreferredOrientations( await SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]) [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
.then((_) async {
await GStrorage.init(); await GStrorage.init();
await setupServiceLocator(); await setupServiceLocator();
clearLogs(); clearLogs();
Request(); Request();
await Request.setCookie(); await Request.setCookie();
RecommendFilter();
// 异常捕获 logo记录 // 异常捕获 logo记录
final Catcher2Options debugConfig = Catcher2Options(
SilentReportMode(),
[
FileHandler(await getLogsPath()),
ConsoleHandler(
enableDeviceParameters: false,
enableApplicationParameters: false,
)
],
);
final Catcher2Options releaseConfig = Catcher2Options( final Catcher2Options releaseConfig = Catcher2Options(
SilentReportMode(), SilentReportMode(),
[FileHandler(await getLogsPath())], [FileHandler(await getLogsPath())],
); );
Catcher2( Catcher2(
debugConfig: debugConfig,
releaseConfig: releaseConfig, releaseConfig: releaseConfig,
runAppFunction: () { runAppFunction: () {
runApp(const MyApp()); runApp(const MyApp());
@ -79,11 +65,8 @@ void main() async {
)); ));
} }
Data.init();
GlobalData();
PiliSchame.init(); PiliSchame.init();
DisableBatteryOpt(); DisableBatteryOpt();
});
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
@ -124,6 +107,39 @@ class MyApp extends StatelessWidget {
} catch (_) {} } catch (_) {}
} }
if (Platform.isAndroid) {
return AndroidApp(
brandColor: brandColor,
isDynamicColor: isDynamicColor,
currentThemeValue: currentThemeValue,
textScale: textScale,
);
} else {
return OtherApp(
brandColor: brandColor,
currentThemeValue: currentThemeValue,
textScale: textScale,
);
}
}
}
class AndroidApp extends StatelessWidget {
const AndroidApp({
super.key,
required this.brandColor,
required this.isDynamicColor,
required this.currentThemeValue,
required this.textScale,
});
final Color brandColor;
final bool isDynamicColor;
final ThemeType currentThemeValue;
final double textScale;
@override
Widget build(BuildContext context) {
return DynamicColorBuilder( return DynamicColorBuilder(
builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) { builder: ((ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
ColorScheme? lightColorScheme; ColorScheme? lightColorScheme;
@ -143,50 +159,77 @@ class MyApp extends StatelessWidget {
brightness: Brightness.dark, brightness: Brightness.dark,
); );
} }
return BuildMainApp(
lightColorScheme: lightColorScheme,
darkColorScheme: darkColorScheme,
currentThemeValue: currentThemeValue,
textScale: textScale,
);
}),
);
}
}
// ThemeData themeData = ThemeData( class OtherApp extends StatelessWidget {
// colorScheme: currentThemeValue == ThemeType.dark const OtherApp({
// ? darkColorScheme super.key,
// : lightColorScheme, required this.brandColor,
// ); required this.currentThemeValue,
required this.textScale,
});
// // 小白条、导航栏沉浸 final Color brandColor;
// if (Platform.isAndroid) { final ThemeType currentThemeValue;
// List<String> versionParts = Platform.version.split('.'); final double textScale;
// int androidVersion = int.parse(versionParts[0]);
// if (androidVersion >= 29) { @override
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); Widget build(BuildContext context) {
// } return BuildMainApp(
// SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( lightColorScheme: ColorScheme.fromSeed(
// systemNavigationBarColor: GlobalData().enableMYBar seedColor: brandColor,
// ? const Color(0x00010000) brightness: Brightness.light,
// : themeData.canvasColor, ),
// systemNavigationBarDividerColor: GlobalData().enableMYBar darkColorScheme: ColorScheme.fromSeed(
// ? const Color(0x00010000) seedColor: brandColor,
// : themeData.canvasColor, brightness: Brightness.dark,
// systemNavigationBarIconBrightness: ),
// currentThemeValue == ThemeType.dark currentThemeValue: currentThemeValue,
// ? Brightness.light textScale: textScale,
// : Brightness.dark, );
// statusBarColor: Colors.transparent, }
// )); }
// }
class BuildMainApp extends StatelessWidget {
const BuildMainApp({
super.key,
required this.lightColorScheme,
required this.darkColorScheme,
required this.currentThemeValue,
required this.textScale,
});
final ColorScheme lightColorScheme;
final ColorScheme darkColorScheme;
final ThemeType currentThemeValue;
final double textScale;
@override
Widget build(BuildContext context) {
final SnackBarThemeData snackBarTheme = SnackBarThemeData(
actionTextColor: lightColorScheme.primary,
backgroundColor: lightColorScheme.secondaryContainer,
closeIconColor: lightColorScheme.secondary,
contentTextStyle: TextStyle(color: lightColorScheme.secondary),
elevation: 20,
);
// 图片缓存
// PaintingBinding.instance.imageCache.maximumSizeBytes = 1000 << 20;
return GetMaterialApp( return GetMaterialApp(
title: 'PiliPala', title: 'PiliPala',
theme: ThemeData( theme: ThemeData(
colorScheme: currentThemeValue == ThemeType.dark colorScheme: currentThemeValue == ThemeType.dark
? darkColorScheme ? darkColorScheme
: lightColorScheme, : lightColorScheme,
snackBarTheme: SnackBarThemeData( snackBarTheme: snackBarTheme,
actionTextColor: lightColorScheme.primary,
backgroundColor: lightColorScheme.secondaryContainer,
closeIconColor: lightColorScheme.secondary,
contentTextStyle: TextStyle(color: lightColorScheme.secondary),
elevation: 20,
),
pageTransitionsTheme: const PageTransitionsTheme( pageTransitionsTheme: const PageTransitionsTheme(
builders: <TargetPlatform, PageTransitionsBuilder>{ builders: <TargetPlatform, PageTransitionsBuilder>{
TargetPlatform.android: ZoomPageTransitionsBuilder( TargetPlatform.android: ZoomPageTransitionsBuilder(
@ -199,13 +242,7 @@ class MyApp extends StatelessWidget {
colorScheme: currentThemeValue == ThemeType.light colorScheme: currentThemeValue == ThemeType.light
? lightColorScheme ? lightColorScheme
: darkColorScheme, : darkColorScheme,
snackBarTheme: SnackBarThemeData( snackBarTheme: snackBarTheme,
actionTextColor: darkColorScheme.primary,
backgroundColor: darkColorScheme.secondaryContainer,
closeIconColor: darkColorScheme.secondary,
contentTextStyle: TextStyle(color: darkColorScheme.secondary),
elevation: 20,
),
), ),
localizationsDelegates: const [ localizationsDelegates: const [
GlobalCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
@ -231,8 +268,11 @@ class MyApp extends StatelessWidget {
VideoDetailPage.routeObserver, VideoDetailPage.routeObserver,
SearchPage.routeObserver, SearchPage.routeObserver,
], ],
); onInit: () {
}), RecommendFilter();
Data.init();
GlobalData();
},
); );
} }
} }

View File

@ -415,6 +415,7 @@ class DynamicMajorModel {
this.type, this.type,
this.courses, this.courses,
this.common, this.common,
this.music,
}); });
DynamicArchiveModel? archive; DynamicArchiveModel? archive;
@ -431,6 +432,7 @@ class DynamicMajorModel {
String? type; String? type;
Map? courses; Map? courses;
Map? common; Map? common;
Map? music;
DynamicMajorModel.fromJson(Map<String, dynamic> json) { DynamicMajorModel.fromJson(Map<String, dynamic> json) {
archive = json['archive'] != null archive = json['archive'] != null
@ -455,6 +457,7 @@ class DynamicMajorModel {
type = json['type']; type = json['type'];
courses = json['courses'] ?? {}; courses = json['courses'] ?? {};
common = json['common'] ?? {}; common = json['common'] ?? {};
music = json['music'] ?? {};
} }
} }

View File

@ -0,0 +1,9 @@
class SearchAllModel {
SearchAllModel({this.topTList});
Map? topTList;
SearchAllModel.fromJson(Map<String, dynamic> json) {
topTList = json['top_tlist'];
}
}

View File

@ -218,7 +218,7 @@ class AboutController extends GetxController {
RxString currentVersion = ''.obs; RxString currentVersion = ''.obs;
RxString remoteVersion = ''.obs; RxString remoteVersion = ''.obs;
late LatestDataModel remoteAppInfo; late LatestDataModel remoteAppInfo;
RxBool isUpdate = true.obs; RxBool isUpdate = false.obs;
RxBool isLoading = true.obs; RxBool isLoading = true.obs;
late LatestDataModel data; late LatestDataModel data;

View File

@ -194,7 +194,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
src: widget.bangumiDetail!.cover!, src: widget.bangumiDetail!.cover!,
), ),
PBadge( PBadge(
text: '评分 ${widget.bangumiDetail!.rating!['score']!}', text:
'评分 ${widget.bangumiDetail?.rating?['score']! ?? '暂无'}',
top: null, top: null,
right: 6, right: 6,
bottom: 6, bottom: 6,

View File

@ -3,7 +3,6 @@ import 'dart:async';
import 'package:easy_debounce/easy_throttle.dart'; import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:nil/nil.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/utils/main_stream.dart'; import 'package:pilipala/utils/main_stream.dart';
@ -142,10 +141,10 @@ class _BangumiPageState extends State<BangumiPage>
), ),
); );
} else { } else {
return nil; return const SizedBox();
} }
} else { } else {
return nil; return const SizedBox();
} }
}, },
), ),
@ -216,7 +215,7 @@ class _BangumiPageState extends State<BangumiPage>
(BuildContext context, int index) { (BuildContext context, int index) {
return bangumiList!.isNotEmpty return bangumiList!.isNotEmpty
? BangumiCardV(bangumiItem: bangumiList[index]) ? BangumiCardV(bangumiItem: bangumiList[index])
: nil; : const SizedBox();
}, },
childCount: bangumiList!.isNotEmpty ? bangumiList!.length : 10, childCount: bangumiList!.isNotEmpty ? bangumiList!.length : 10,
), ),

View File

@ -71,7 +71,7 @@ class DynamicsController extends GetxController {
Future queryFollowDynamic({type = 'init'}) async { Future queryFollowDynamic({type = 'init'}) async {
if (!userLogin.value) { if (!userLogin.value) {
return {'status': false, 'msg': '账号未登录'}; return {'status': false, 'msg': '账号未登录', 'code': -101};
} }
if (type == 'init') { if (type == 'init') {
dynamicsList.clear(); dynamicsList.clear();
@ -229,7 +229,7 @@ class DynamicsController extends GetxController {
Future queryFollowUp({type = 'init'}) async { Future queryFollowUp({type = 'init'}) async {
if (!userLogin.value) { if (!userLogin.value) {
return {'status': false, 'msg': '账号未登录'}; return {'status': false, 'msg': '账号未登录', 'code': -101};
} }
if (type == 'init') { if (type == 'init') {
upData.value.upList = <UpItem>[]; upData.value.upList = <UpItem>[];

View File

@ -196,7 +196,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
centerTitle: false, centerTitle: false,
titleSpacing: 0, titleSpacing: 0,
title: StreamBuilder( title: StreamBuilder(
stream: titleStreamC.stream.distinct(), stream: titleStreamC.stream,
initialData: false, initialData: false,
builder: (context, AsyncSnapshot snapshot) { builder: (context, AsyncSnapshot snapshot) {
return AnimatedOpacity( return AnimatedOpacity(

View File

@ -11,6 +11,7 @@ import 'package:pilipala/common/widgets/no_data.dart';
import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/main_stream.dart'; import 'package:pilipala/utils/main_stream.dart';
import 'package:pilipala/utils/route_push.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import '../mine/controller.dart'; import '../mine/controller.dart';
@ -224,8 +225,8 @@ class _DynamicsPageState extends State<DynamicsPage>
if (snapshot.data == null) { if (snapshot.data == null) {
return const SliverToBoxAdapter(child: SizedBox()); return const SliverToBoxAdapter(child: SizedBox());
} }
Map data = snapshot.data; Map? data = snapshot.data;
if (data['status']) { if (data != null && data['status']) {
List<DynamicItemModel> list = List<DynamicItemModel> list =
_dynamicsController.dynamicsList; _dynamicsController.dynamicsList;
return Obx( return Obx(
@ -248,24 +249,21 @@ class _DynamicsPageState extends State<DynamicsPage>
} }
}, },
); );
} else if (data['msg'] == "账号未登录") {
return HttpError(
errMsg: data['msg'],
btnText: "去登录",
fn: () {
mineController.onLogin();
},
);
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data?['msg'] ?? '请求异常',
btnText: data?['code'] == -101 ? '去登录' : null,
fn: () { fn: () {
if (data?['code'] == -101) {
RoutePush.loginRedirectPush();
} else {
setState(() { setState(() {
_futureBuilderFuture = _futureBuilderFuture =
_dynamicsController.queryFollowDynamic(); _dynamicsController.queryFollowDynamic();
_futureBuilderFutureUp = _futureBuilderFutureUp =
_dynamicsController.queryFollowUp(); _dynamicsController.queryFollowUp();
}); });
}
}, },
); );
} }

View File

@ -1,14 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/pages/dynamics/index.dart'; import 'package:pilipala/pages/dynamics/index.dart';
import '../../../models/dynamics/result.dart';
import 'action_panel.dart'; import 'action_panel.dart';
import 'author_panel.dart'; import 'author_panel.dart';
import 'content_panel.dart'; import 'content_panel.dart';
import 'forward_panel.dart'; import 'forward_panel.dart';
class DynamicPanel extends StatelessWidget { class DynamicPanel extends StatelessWidget {
final DynamicItemModel item; final dynamic item;
final String? source; final String? source;
DynamicPanel({required this.item, this.source, Key? key}) : super(key: key); DynamicPanel({required this.item, this.source, Key? key}) : super(key: key);
final DynamicsController _dynamicsController = Get.put(DynamicsController()); final DynamicsController _dynamicsController = Get.put(DynamicsController());

View File

@ -238,6 +238,61 @@ Widget forWard(item, context, ctr, source, {floor = 1}) {
), ),
), ),
); );
case 'DYNAMIC_TYPE_MUSIC':
final Map music = item.modules.moduleDynamic.major.music;
return Padding(
padding: const EdgeInsets.only(top: 8),
child: InkWell(
onTap: () {
Get.toNamed('/webview', parameters: {
'url': "https:${music['jump_url']}",
'type': 'url',
'pageTitle': music['title']
});
},
child: Container(
width: double.infinity,
padding:
const EdgeInsets.only(left: 12, top: 10, right: 12, bottom: 10),
color: Theme.of(context).dividerColor.withOpacity(0.08),
child: Row(
children: [
NetworkImgLayer(
width: 45,
height: 45,
src: music['cover'],
),
const SizedBox(width: 10),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
music['title'],
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 2),
Text(
music['label'],
style: TextStyle(
color: Theme.of(context).colorScheme.outline,
fontSize:
Theme.of(context).textTheme.labelMedium!.fontSize,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
)
],
),
// TextButton(onPressed: () {}, child: Text('123'))
),
),
);
default: default:
return const SizedBox( return const SizedBox(
width: double.infinity, width: double.infinity,

View File

@ -1,3 +1,4 @@
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
@ -30,6 +31,31 @@ class _UpPanelState extends State<UpPanel> {
liveList = widget.upData.liveList!; liveList = widget.upData.liveList!;
} }
void onClickUp(data, i) {
currentMid = data.mid;
Get.find<DynamicsController>().mid.value = data.mid;
Get.find<DynamicsController>().upInfo.value = data;
Get.find<DynamicsController>().onSelectUp(data.mid);
int liveLen = liveList.length;
int upLen = upList.length;
double itemWidth = contentWidth + itemPadding.horizontal;
double screenWidth = MediaQuery.sizeOf(context).width;
double moveDistance = 0.0;
if (itemWidth * (upList.length + liveList.length) <= screenWidth) {
} else if ((upLen - i - 0.5) * itemWidth > screenWidth / 2) {
moveDistance = (i + liveLen + 0.5) * itemWidth + 46 - screenWidth / 2;
} else {
moveDistance = (upLen + liveLen) * itemWidth + 46 - screenWidth;
}
data.hasUpdate = false;
scrollController.animateTo(
moveDistance,
duration: const Duration(milliseconds: 200),
curve: Curves.linear,
);
setState(() {});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
listFormat(); listFormat();
@ -120,30 +146,10 @@ class _UpPanelState extends State<UpPanel> {
onTap: () { onTap: () {
feedBack(); feedBack();
if (data.type == 'up') { if (data.type == 'up') {
currentMid = data.mid; EasyThrottle.throttle('follow', const Duration(milliseconds: 300),
Get.find<DynamicsController>().mid.value = data.mid; () {
Get.find<DynamicsController>().upInfo.value = data; onClickUp(data, i);
Get.find<DynamicsController>().onSelectUp(data.mid); });
int liveLen = liveList.length;
int upLen = upList.length;
double itemWidth = contentWidth + itemPadding.horizontal;
double screenWidth = MediaQuery.sizeOf(context).width;
double moveDistance = 0.0;
if (itemWidth * (upList.length + liveList.length) <= screenWidth) {
} else if ((upLen - i - 0.5) * itemWidth > screenWidth / 2) {
moveDistance =
(i + liveLen + 0.5) * itemWidth + 46 - screenWidth / 2;
} else {
moveDistance = (upLen + liveLen) * itemWidth + 46 - screenWidth;
}
data.hasUpdate = false;
scrollController.animateTo(
moveDistance,
duration: const Duration(milliseconds: 500),
curve: Curves.easeInOut,
);
setState(() {});
} else if (data.type == 'live') { } else if (data.type == 'live') {
LiveItemModel liveItem = LiveItemModel.fromJson({ LiveItemModel liveItem = LiveItemModel.fromJson({
'title': data.title, 'title': data.title,

View File

@ -80,15 +80,12 @@ Widget videoSeasonWidget(item, context, type, {floor = 1}) {
double width = box.maxWidth; double width = box.maxWidth;
return Stack( return Stack(
children: [ children: [
Hero( NetworkImgLayer(
tag: content.bvid,
child: NetworkImgLayer(
type: floor == 1 ? 'emote' : null, type: floor == 1 ? 'emote' : null,
width: width, width: width,
height: width / StyleString.aspectRatio, height: width / StyleString.aspectRatio,
src: content.cover, src: content.cover,
), ),
),
if (content.badge != null && type == 'pgc') if (content.badge != null && type == 'pgc')
PBadge( PBadge(
text: content.badge['text'], text: content.badge['text'],

View File

@ -17,10 +17,15 @@ class FavController extends GetxController {
int pageSize = 60; int pageSize = 60;
RxBool hasMore = true.obs; RxBool hasMore = true.obs;
Future<dynamic> queryFavFolder({type = 'init'}) async { @override
void onInit() {
userInfo = userInfoCache.get('userInfoCache'); userInfo = userInfoCache.get('userInfoCache');
super.onInit();
}
Future<dynamic> queryFavFolder({type = 'init'}) async {
if (userInfo == null) { if (userInfo == null) {
return {'status': false, 'msg': '账号未登录'}; return {'status': false, 'msg': '账号未登录', 'code': -101};
} }
if (!hasMore.value) { if (!hasMore.value) {
return; return;

View File

@ -1,9 +1,11 @@
import 'package:easy_debounce/easy_throttle.dart'; import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/skeleton/video_card_h.dart';
import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/pages/fav/index.dart'; import 'package:pilipala/pages/fav/index.dart';
import 'package:pilipala/pages/fav/widgets/item.dart'; import 'package:pilipala/pages/fav/widgets/item.dart';
import 'package:pilipala/utils/route_push.dart';
class FavPage extends StatefulWidget { class FavPage extends StatefulWidget {
const FavPage({super.key}); const FavPage({super.key});
@ -57,8 +59,8 @@ class _FavPageState extends State<FavPage> {
future: _futureBuilderFuture, future: _futureBuilderFuture,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
Map data = snapshot.data as Map; Map? data = snapshot.data;
if (data['status']) { if (data != null && data['status']) {
return Obx( return Obx(
() => ListView.builder( () => ListView.builder(
controller: scrollController, controller: scrollController,
@ -74,15 +76,30 @@ class _FavPageState extends State<FavPage> {
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
slivers: [ slivers: [
HttpError( HttpError(
errMsg: data['msg'], errMsg: data?['msg'] ?? '请求异常',
fn: () => setState(() {}), btnText: data?['code'] == -101 ? '去登录' : null,
fn: () {
if (data?['code'] == -101) {
RoutePush.loginRedirectPush();
} else {
setState(() {
_futureBuilderFuture =
_favController.queryFavFolder();
});
}
},
), ),
], ],
); );
} }
} else { } else {
// 骨架屏 // 骨架屏
return const Text('请求中'); return ListView.builder(
itemBuilder: (context, index) {
return const VideoCardHSkeleton();
},
itemCount: 10,
);
} }
}, },
), ),

View File

@ -4,6 +4,7 @@ import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/user.dart'; import 'package:pilipala/http/user.dart';
import 'package:pilipala/models/user/history.dart'; import 'package:pilipala/models/user/history.dart';
import 'package:pilipala/models/user/info.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
class HistoryController extends GetxController { class HistoryController extends GetxController {
@ -15,14 +16,20 @@ class HistoryController extends GetxController {
RxBool isLoading = false.obs; RxBool isLoading = false.obs;
RxBool enableMultiple = false.obs; RxBool enableMultiple = false.obs;
RxInt checkedCount = 0.obs; RxInt checkedCount = 0.obs;
Box userInfoCache = GStrorage.userInfo;
UserInfoData? userInfo;
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
historyStatus(); historyStatus();
userInfo = userInfoCache.get('userInfoCache');
} }
Future queryHistoryList({type = 'init'}) async { Future queryHistoryList({type = 'init'}) async {
if (userInfo == null) {
return {'status': false, 'msg': '账号未登录', 'code': -101};
}
int max = 0; int max = 0;
int viewAt = 0; int viewAt = 0;
if (type == 'onload') { if (type == 'onload') {

View File

@ -5,6 +5,7 @@ import 'package:pilipala/common/skeleton/video_card_h.dart';
import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/no_data.dart'; import 'package:pilipala/common/widgets/no_data.dart';
import 'package:pilipala/pages/history/index.dart'; import 'package:pilipala/pages/history/index.dart';
import 'package:pilipala/utils/route_push.dart';
import 'widgets/item.dart'; import 'widgets/item.dart';
@ -183,8 +184,8 @@ class _HistoryPageState extends State<HistoryPage> {
if (snapshot.data == null) { if (snapshot.data == null) {
return const SliverToBoxAdapter(child: SizedBox()); return const SliverToBoxAdapter(child: SizedBox());
} }
Map data = snapshot.data; Map? data = snapshot.data;
if (data['status']) { if (data != null && data['status']) {
return Obx( return Obx(
() => _historyController.historyList.isNotEmpty () => _historyController.historyList.isNotEmpty
? SliverList( ? SliverList(
@ -209,8 +210,18 @@ class _HistoryPageState extends State<HistoryPage> {
); );
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data?['msg'] ?? '请求异常',
fn: () => setState(() {}), btnText: data?['code'] == -101 ? '去登录' : null,
fn: () {
if (data?['code'] == -101) {
RoutePush.loginRedirectPush();
} else {
setState(() {
_futureBuilderFuture =
_historyController.queryHistoryList();
});
}
},
); );
} }
} else { } else {

View File

@ -198,7 +198,8 @@ class HistoryItem extends StatelessWidget {
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(
StyleString.imgRadius.x),
color: Colors.black.withOpacity( color: Colors.black.withOpacity(
ctr!.enableMultiple.value && ctr!.enableMultiple.value &&
videoItem.checked videoItem.checked
@ -243,7 +244,7 @@ class HistoryItem extends StatelessWidget {
), ),
), ),
), ),
videoItem.progress != 0 videoItem.progress != 0 && videoItem.duration != 0
? Positioned( ? Positioned(
left: 3, left: 3,
right: 3, right: 3,

View File

@ -10,9 +10,8 @@ class HistorySearchController extends GetxController {
final FocusNode searchFocusNode = FocusNode(); final FocusNode searchFocusNode = FocusNode();
RxString searchKeyWord = ''.obs; RxString searchKeyWord = ''.obs;
String hintText = '搜索'; String hintText = '搜索';
RxString loadingStatus = 'init'.obs; RxBool loadingStatus = false.obs;
RxString loadingText = '加载中...'.obs; RxString loadingText = '加载中...'.obs;
bool hasRequest = false;
late int mid; late int mid;
RxString uname = ''.obs; RxString uname = ''.obs;
int pn = 1; int pn = 1;
@ -36,8 +35,7 @@ class HistorySearchController extends GetxController {
// 提交搜索内容 // 提交搜索内容
void submit() { void submit() {
loadingStatus.value = 'loading'; if (!loadingStatus.value) {
if (hasRequest) {
pn = 1; pn = 1;
searchHistories(); searchHistories();
} }
@ -48,6 +46,7 @@ class HistorySearchController extends GetxController {
if (type == 'onLoad' && loadingText.value == '没有更多了') { if (type == 'onLoad' && loadingText.value == '没有更多了') {
return; return;
} }
loadingStatus.value = true;
var res = await UserHttp.searchHistory( var res = await UserHttp.searchHistory(
pn: pn, pn: pn,
keyword: controller.value.text, keyword: controller.value.text,
@ -63,9 +62,8 @@ class HistorySearchController extends GetxController {
loadingText.value = '没有更多了'; loadingText.value = '没有更多了';
} }
pn += 1; pn += 1;
hasRequest = true;
} }
loadingStatus.value = 'finish'; loadingStatus.value = false;
return res; return res;
} }
@ -86,6 +84,6 @@ class HistorySearchController extends GetxController {
historyList.removeWhere((e) => e.kid == kid); historyList.removeWhere((e) => e.kid == kid);
SmartDialog.showToast(res['msg']); SmartDialog.showToast(res['msg']);
} }
loadingStatus.value = 'finish'; // loadingStatus.value = fasle;
} }
} }

View File

@ -2,7 +2,6 @@ import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/skeleton/video_card_h.dart'; import 'package:pilipala/common/skeleton/video_card_h.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/no_data.dart'; import 'package:pilipala/common/widgets/no_data.dart';
import 'package:pilipala/pages/history/widgets/item.dart'; import 'package:pilipala/pages/history/widgets/item.dart';
@ -16,20 +15,19 @@ class HistorySearchPage extends StatefulWidget {
} }
class _HistorySearchPageState extends State<HistorySearchPage> { class _HistorySearchPageState extends State<HistorySearchPage> {
final HistorySearchController _historySearchCtr = final HistorySearchController _hisCtr = Get.put(HistorySearchController());
Get.put(HistorySearchController());
late ScrollController scrollController; late ScrollController scrollController;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
scrollController = _historySearchCtr.scrollController; scrollController = _hisCtr.scrollController;
scrollController.addListener( scrollController.addListener(
() { () {
if (scrollController.position.pixels >= if (scrollController.position.pixels >=
scrollController.position.maxScrollExtent - 300) { scrollController.position.maxScrollExtent - 300) {
EasyThrottle.throttle('history', const Duration(seconds: 1), () { EasyThrottle.throttle('history', const Duration(seconds: 1), () {
_historySearchCtr.onLoad(); _hisCtr.onLoad();
}); });
} }
}, },
@ -50,19 +48,19 @@ class _HistorySearchPageState extends State<HistorySearchPage> {
titleSpacing: 0, titleSpacing: 0,
actions: [ actions: [
IconButton( IconButton(
onPressed: () => _historySearchCtr.submit(), onPressed: () => _hisCtr.submit(),
icon: const Icon(Icons.search_outlined, size: 22)), icon: const Icon(Icons.search_outlined, size: 22)),
const SizedBox(width: 10) const SizedBox(width: 10)
], ],
title: Obx( title: Obx(
() => TextField( () => TextField(
autofocus: true, autofocus: true,
focusNode: _historySearchCtr.searchFocusNode, focusNode: _hisCtr.searchFocusNode,
controller: _historySearchCtr.controller.value, controller: _hisCtr.controller.value,
textInputAction: TextInputAction.search, textInputAction: TextInputAction.search,
onChanged: (value) => _historySearchCtr.onChange(value), onChanged: (value) => _hisCtr.onChange(value),
decoration: InputDecoration( decoration: InputDecoration(
hintText: _historySearchCtr.hintText, hintText: _hisCtr.hintText,
border: InputBorder.none, border: InputBorder.none,
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon( icon: Icon(
@ -70,103 +68,61 @@ class _HistorySearchPageState extends State<HistorySearchPage> {
size: 22, size: 22,
color: Theme.of(context).colorScheme.outline, color: Theme.of(context).colorScheme.outline,
), ),
onPressed: () => _historySearchCtr.onClear(), onPressed: () => _hisCtr.onClear(),
), ),
), ),
onSubmitted: (String value) => _historySearchCtr.submit(), onSubmitted: (String value) => _hisCtr.submit(),
), ),
), ),
), ),
body: Obx( body: Obx(
() => Column( () {
children: _historySearchCtr.loadingStatus.value == 'init' return _hisCtr.loadingStatus.value && _hisCtr.historyList.isEmpty
? [const SizedBox()] ? ListView.builder(
: [ itemCount: 10,
Expanded( itemBuilder: (context, index) {
child: FutureBuilder( return const VideoCardHSkeleton();
future: _historySearchCtr.searchHistories(), },
builder: (context, snapshot) { )
if (snapshot.connectionState == ConnectionState.done) { : _hisCtr.historyList.isNotEmpty
Map data = snapshot.data as Map;
if (data['status']) {
return Obx(
() => _historySearchCtr.historyList.isNotEmpty
? ListView.builder( ? ListView.builder(
controller: scrollController, controller: scrollController,
itemCount: itemCount: _hisCtr.historyList.length + 1,
_historySearchCtr.historyList.length +
1,
itemBuilder: (context, index) { itemBuilder: (context, index) {
if (index == if (index == _hisCtr.historyList.length) {
_historySearchCtr
.historyList.length) {
return Container( return Container(
height: MediaQuery.of(context) height: MediaQuery.of(context).padding.bottom + 60,
.padding
.bottom +
60,
padding: EdgeInsets.only( padding: EdgeInsets.only(
bottom: MediaQuery.of(context) bottom: MediaQuery.of(context).padding.bottom),
.padding
.bottom),
child: Center( child: Center(
child: Obx( child: Obx(
() => Text( () => Text(
_historySearchCtr _hisCtr.loadingText.value,
.loadingText.value,
style: TextStyle( style: TextStyle(
color: Theme.of(context) color:
.colorScheme Theme.of(context).colorScheme.outline,
.outline, fontSize: 13,
fontSize: 13), ),
), ),
), ),
), ),
); );
} else { } else {
return HistoryItem( return HistoryItem(
videoItem: _historySearchCtr videoItem: _hisCtr.historyList[index],
.historyList[index], ctr: _hisCtr,
ctr: _historySearchCtr,
onChoose: null, onChoose: null,
onUpdateMultiple: () => null, onUpdateMultiple: () => null,
); );
} }
}, },
) )
: _historySearchCtr.loadingStatus.value ==
'loading'
? const SizedBox(child: Text('加载中...'))
: const CustomScrollView( : const CustomScrollView(
slivers: <Widget>[ slivers: <Widget>[
NoData(), NoData(),
], ],
),
); );
} else {
return CustomScrollView(
slivers: <Widget>[
HttpError(
errMsg: data['msg'],
fn: () => setState(() {}),
)
],
);
}
} else {
// 骨架屏
return ListView.builder(
itemCount: 10,
itemBuilder: (context, index) {
return const VideoCardHSkeleton();
}, },
);
}
},
),
),
],
),
), ),
); );
} }

View File

@ -1,16 +1,30 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/user.dart'; import 'package:pilipala/http/user.dart';
import 'package:pilipala/models/model_hot_video_item.dart'; import 'package:pilipala/models/model_hot_video_item.dart';
import 'package:pilipala/models/user/info.dart';
import 'package:pilipala/utils/storage.dart';
class LaterController extends GetxController { class LaterController extends GetxController {
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
RxList<HotVideoItemModel> laterList = <HotVideoItemModel>[].obs; RxList<HotVideoItemModel> laterList = <HotVideoItemModel>[].obs;
int count = 0; int count = 0;
RxBool isLoading = false.obs; RxBool isLoading = false.obs;
Box userInfoCache = GStrorage.userInfo;
UserInfoData? userInfo;
@override
void onInit() {
super.onInit();
userInfo = userInfoCache.get('userInfoCache');
}
Future queryLaterList() async { Future queryLaterList() async {
if (userInfo == null) {
return {'status': false, 'msg': '账号未登录', 'code': -101};
}
isLoading.value = true; isLoading.value = true;
var res = await UserHttp.seeYouLater(); var res = await UserHttp.seeYouLater();
if (res['status']) { if (res['status']) {

View File

@ -5,6 +5,7 @@ import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/no_data.dart'; import 'package:pilipala/common/widgets/no_data.dart';
import 'package:pilipala/common/widgets/video_card_h.dart'; import 'package:pilipala/common/widgets/video_card_h.dart';
import 'package:pilipala/pages/later/index.dart'; import 'package:pilipala/pages/later/index.dart';
import 'package:pilipala/utils/route_push.dart';
class LaterPage extends StatefulWidget { class LaterPage extends StatefulWidget {
const LaterPage({super.key}); const LaterPage({super.key});
@ -72,8 +73,8 @@ class _LaterPageState extends State<LaterPage> {
future: _futureBuilderFuture, future: _futureBuilderFuture,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
Map data = snapshot.data as Map; Map? data = snapshot.data;
if (data['status']) { if (data != null && data['status']) {
return Obx( return Obx(
() => _laterController.laterList.isNotEmpty && () => _laterController.laterList.isNotEmpty &&
!_laterController.isLoading.value !_laterController.isLoading.value
@ -96,10 +97,18 @@ class _LaterPageState extends State<LaterPage> {
); );
} else { } else {
return HttpError( return HttpError(
errMsg: data['msg'], errMsg: data?['msg'] ?? '请求异常',
fn: () => setState(() { btnText: data?['code'] == -101 ? '去登录' : null,
_futureBuilderFuture = _laterController.queryLaterList(); fn: () {
}), if (data?['code'] == -101) {
RoutePush.loginRedirectPush();
} else {
setState(() {
_futureBuilderFuture =
_laterController.queryLaterList();
});
}
},
); );
} }
} else { } else {

View File

@ -17,8 +17,7 @@ class LiveRoomController extends GetxController {
double volume = 0.0; double volume = 0.0;
// 静音状态 // 静音状态
RxBool volumeOff = false.obs; RxBool volumeOff = false.obs;
PlPlayerController plPlayerController = PlPlayerController plPlayerController = PlPlayerController(videoType: 'live');
PlPlayerController.getInstance(videoType: 'live');
Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs; Rx<RoomInfoH5Model> roomInfoH5 = RoomInfoH5Model().obs;
late bool enableCDN; late bool enableCDN;
late int currentQn; late int currentQn;

View File

@ -153,7 +153,8 @@ class _BottomControlState extends State<BottomControl> {
size: 20, size: 20,
color: Colors.white, color: Colors.white,
), ),
fuc: () => widget.controller!.triggerFullScreen(), fuc: () => widget.controller!.triggerFullScreen(
status: !(widget.controller!.isFullScreen.value)),
), ),
], ],
), ),

View File

@ -40,10 +40,10 @@ class MainController extends GetxController {
dynamicBadgeType.value = DynamicBadgeMode.values[setting.get( dynamicBadgeType.value = DynamicBadgeMode.values[setting.get(
SettingBoxKey.dynamicBadgeMode, SettingBoxKey.dynamicBadgeMode,
defaultValue: DynamicBadgeMode.number.code)]; defaultValue: DynamicBadgeMode.number.code)];
setNavBarConfig();
if (dynamicBadgeType.value != DynamicBadgeMode.hidden) { if (dynamicBadgeType.value != DynamicBadgeMode.hidden) {
getUnreadDynamic(); getUnreadDynamic();
} }
setNavBarConfig();
} }
void onBackPressed(BuildContext context) { void onBackPressed(BuildContext context) {

View File

@ -138,14 +138,14 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 500),
offset: Offset(0, snapshot.data ? 0 : 1), offset: Offset(0, snapshot.data ? 0 : 1),
child: GlobalData().enableMYBar child: GlobalData().enableMYBar
? NavigationBar( ? Obx(
() => NavigationBar(
onDestinationSelected: (value) => setIndex(value), onDestinationSelected: (value) => setIndex(value),
selectedIndex: _mainController.selectedIndex, selectedIndex: _mainController.selectedIndex,
destinations: <Widget>[ destinations: <Widget>[
..._mainController.navigationBars.map((e) { ..._mainController.navigationBars.map((e) {
return NavigationDestination( return NavigationDestination(
icon: Obx( icon: Badge(
() => Badge(
label: _mainController label: _mainController
.dynamicBadgeType.value == .dynamicBadgeType.value ==
DynamicBadgeMode.number DynamicBadgeMode.number
@ -159,14 +159,15 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
e['count'] > 0, e['count'] > 0,
child: e['icon'], child: e['icon'],
), ),
),
selectedIcon: e['selectIcon'], selectedIcon: e['selectIcon'],
label: e['label'], label: e['label'],
); );
}).toList(), }).toList(),
], ],
),
) )
: BottomNavigationBar( : Obx(
() => BottomNavigationBar(
currentIndex: _mainController.selectedIndex, currentIndex: _mainController.selectedIndex,
type: BottomNavigationBarType.fixed, type: BottomNavigationBarType.fixed,
onTap: (value) => setIndex(value), onTap: (value) => setIndex(value),
@ -176,8 +177,7 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
items: [ items: [
..._mainController.navigationBars.map((e) { ..._mainController.navigationBars.map((e) {
return BottomNavigationBarItem( return BottomNavigationBarItem(
icon: Obx( icon: Badge(
() => Badge(
label: _mainController label: _mainController
.dynamicBadgeType.value == .dynamicBadgeType.value ==
DynamicBadgeMode.number DynamicBadgeMode.number
@ -191,13 +191,13 @@ class _MainAppState extends State<MainApp> with SingleTickerProviderStateMixin {
e['count'] > 0, e['count'] > 0,
child: e['icon'], child: e['icon'],
), ),
),
activeIcon: e['selectIcon'], activeIcon: e['selectIcon'],
label: e['label'], label: e['label'],
); );
}).toList(), }).toList(),
], ],
), ),
),
); );
}, },
) )

View File

@ -105,7 +105,7 @@ class _MediaPageState extends State<MediaPage>
color: Theme.of(context).dividerColor.withOpacity(0.1), color: Theme.of(context).dividerColor.withOpacity(0.1),
), ),
ListTile( ListTile(
onTap: () {}, onTap: () => Get.toNamed('/fav'),
leading: null, leading: null,
dense: true, dense: true,
title: Padding( title: Padding(

View File

@ -6,6 +6,7 @@ import 'package:pilipala/http/user.dart';
import 'package:pilipala/models/common/theme_type.dart'; import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/models/user/info.dart'; import 'package:pilipala/models/user/info.dart';
import 'package:pilipala/models/user/stat.dart'; import 'package:pilipala/models/user/stat.dart';
import 'package:pilipala/utils/route_push.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
class MineController extends GetxController { class MineController extends GetxController {
@ -33,14 +34,7 @@ class MineController extends GetxController {
onLogin() async { onLogin() async {
if (!userLogin.value) { if (!userLogin.value) {
Get.toNamed( RoutePush.loginPush();
'/webview',
parameters: {
'url': 'https://passport.bilibili.com/h5-app/passport/login',
'type': 'login',
'pageTitle': '登录bilibili',
},
);
// Get.toNamed('/loginPage'); // Get.toNamed('/loginPage');
} else { } else {
int mid = userInfo.value.mid!; int mid = userInfo.value.mid!;

View File

@ -1,4 +1,5 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
@ -106,4 +107,10 @@ class RcmdController extends GetxController {
duration: const Duration(milliseconds: 500), curve: Curves.easeInOut); duration: const Duration(milliseconds: 500), curve: Curves.easeInOut);
} }
} }
void blockUserCb(mid) {
videoList.removeWhere((e) => e.owner.mid == mid);
videoList.refresh();
SmartDialog.showToast('已移除相关视频');
}
} }

View File

@ -146,6 +146,7 @@ class _RcmdPageState extends State<RcmdPage>
? VideoCardV( ? VideoCardV(
videoItem: videoList[index], videoItem: videoList[index],
crossAxisCount: crossAxisCount, crossAxisCount: crossAxisCount,
blockUserCb: (mid) => ctr.blockUserCb(mid),
) )
: const VideoCardVSkeleton(); : const VideoCardVSkeleton();
}, },

View File

@ -1,8 +1,11 @@
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/http/search.dart';
import 'package:pilipala/models/common/search_type.dart';
class SearchResultController extends GetxController { class SearchResultController extends GetxController {
String? keyword; String? keyword;
int tabIndex = 0; int tabIndex = 0;
RxList searchTabs = [].obs;
@override @override
void onInit() { void onInit() {
@ -10,5 +13,21 @@ class SearchResultController extends GetxController {
if (Get.parameters.keys.isNotEmpty) { if (Get.parameters.keys.isNotEmpty) {
keyword = Get.parameters['keyword']; keyword = Get.parameters['keyword'];
} }
searchTabs.value = SearchType.values
.map((type) => {'label': type.label, 'id': type.type})
.toList();
querySearchCount();
}
Future querySearchCount() async {
var result = await SearchHttp.searchCount(keyword: keyword!);
if (result['status']) {
for (var i in searchTabs) {
final count = result['data'].topTList[i['id']];
i['count'] = count > 99 ? '99+' : count.toString();
}
searchTabs.refresh();
}
return result;
} }
} }

View File

@ -13,7 +13,7 @@ class SearchResultPage extends StatefulWidget {
class _SearchResultPageState extends State<SearchResultPage> class _SearchResultPageState extends State<SearchResultPage>
with TickerProviderStateMixin { with TickerProviderStateMixin {
late SearchResultController? _searchResultController; late SearchResultController _searchResultController;
late TabController? _tabController; late TabController? _tabController;
@override @override
@ -25,7 +25,7 @@ class _SearchResultPageState extends State<SearchResultPage>
_tabController = TabController( _tabController = TabController(
vsync: this, vsync: this,
length: SearchType.values.length, length: SearchType.values.length,
initialIndex: _searchResultController!.tabIndex, initialIndex: _searchResultController.tabIndex,
); );
} }
@ -46,7 +46,7 @@ class _SearchResultPageState extends State<SearchResultPage>
child: SizedBox( child: SizedBox(
width: double.infinity, width: double.infinity,
child: Text( child: Text(
'${_searchResultController!.keyword}', '${_searchResultController.keyword}',
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
), ),
@ -64,10 +64,12 @@ class _SearchResultPageState extends State<SearchResultPage>
splashColor: Colors.transparent, // 点击时的水波纹颜色设置为透明 splashColor: Colors.transparent, // 点击时的水波纹颜色设置为透明
highlightColor: Colors.transparent, // 点击时的背景高亮颜色设置为透明 highlightColor: Colors.transparent, // 点击时的背景高亮颜色设置为透明
), ),
child: TabBar( child: Obx(
() => (TabBar(
controller: _tabController, controller: _tabController,
tabs: [ tabs: [
for (var i in SearchType.values) Tab(text: i.label), for (var i in _searchResultController.searchTabs)
Tab(text: "${i['label']} ${i['count'] ?? ''}")
], ],
isScrollable: true, isScrollable: true,
indicatorWeight: 0, indicatorWeight: 0,
@ -78,21 +80,23 @@ class _SearchResultPageState extends State<SearchResultPage>
borderRadius: const BorderRadius.all(Radius.circular(20)), borderRadius: const BorderRadius.all(Radius.circular(20)),
), ),
indicatorSize: TabBarIndicatorSize.tab, indicatorSize: TabBarIndicatorSize.tab,
labelColor: Theme.of(context).colorScheme.onSecondaryContainer, labelColor:
Theme.of(context).colorScheme.onSecondaryContainer,
labelStyle: const TextStyle(fontSize: 13), labelStyle: const TextStyle(fontSize: 13),
dividerColor: Colors.transparent, dividerColor: Colors.transparent,
unselectedLabelColor: Theme.of(context).colorScheme.outline, unselectedLabelColor: Theme.of(context).colorScheme.outline,
tabAlignment: TabAlignment.start, tabAlignment: TabAlignment.start,
onTap: (index) { onTap: (index) {
if (index == _searchResultController!.tabIndex) { if (index == _searchResultController.tabIndex) {
Get.find<SearchPanelController>( Get.find<SearchPanelController>(
tag: SearchType.values[index].type + tag: SearchType.values[index].type +
_searchResultController!.keyword!) _searchResultController.keyword!)
.animateToTop(); .animateToTop();
} }
_searchResultController!.tabIndex = index; _searchResultController.tabIndex = index;
}, },
)),
), ),
), ),
), ),
@ -102,7 +106,7 @@ class _SearchResultPageState extends State<SearchResultPage>
children: [ children: [
for (var i in SearchType.values) ...{ for (var i in SearchType.values) ...{
SearchPanel( SearchPanel(
keyword: _searchResultController!.keyword, keyword: _searchResultController.keyword,
searchType: i, searchType: i,
tag: DateTime.now().millisecondsSinceEpoch.toString(), tag: DateTime.now().millisecondsSinceEpoch.toString(),
) )

View File

@ -41,7 +41,8 @@ class _LogsPageState extends State<LogsPage> {
.replaceAll('DEVICE INFO', '设备信息') .replaceAll('DEVICE INFO', '设备信息')
.replaceAll('APP INFO', '应用信息') .replaceAll('APP INFO', '应用信息')
.replaceAll('ERROR', '错误信息') .replaceAll('ERROR', '错误信息')
.replaceAll('STACK TRACE', '错误堆栈'); .replaceAll('STACK TRACE', '错误堆栈')
.replaceAll('#', 'Line');
}).toList(); }).toList();
List<Map<String, dynamic>> result = []; List<Map<String, dynamic>> result = [];
for (String i in contentList) { for (String i in contentList) {
@ -50,7 +51,7 @@ class _LogsPageState extends State<LogsPage> {
.split("\n") .split("\n")
.map((l) { .map((l) {
if (l.startsWith("Crash occurred on")) { if (l.startsWith("Crash occurred on")) {
date = DateTime.parse( date = DateTime.tryParse(
l.split("Crash occurred on")[1].trim().split('.')[0], l.split("Crash occurred on")[1].trim().split('.')[0],
); );
return ""; return "";

View File

@ -17,10 +17,15 @@ class SubController extends GetxController {
int pageSize = 20; int pageSize = 20;
RxBool hasMore = true.obs; RxBool hasMore = true.obs;
Future<dynamic> querySubFolder({type = 'init'}) async { @override
void onInit() {
super.onInit();
userInfo = userInfoCache.get('userInfoCache'); userInfo = userInfoCache.get('userInfoCache');
}
Future<dynamic> querySubFolder({type = 'init'}) async {
if (userInfo == null) { if (userInfo == null) {
return {'status': false, 'msg': '账号未登录'}; return {'status': false, 'msg': '账号未登录', 'code': -101};
} }
var res = await UserHttp.userSubFolder( var res = await UserHttp.userSubFolder(
pn: currentPage, pn: currentPage,

View File

@ -1,7 +1,9 @@
import 'package:easy_debounce/easy_throttle.dart'; import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/skeleton/video_card_h.dart';
import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/utils/route_push.dart';
import 'controller.dart'; import 'controller.dart';
import 'widgets/item.dart'; import 'widgets/item.dart';
@ -68,15 +70,30 @@ class _SubPageState extends State<SubPage> {
physics: const NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
slivers: [ slivers: [
HttpError( HttpError(
errMsg: data?['msg'], errMsg: data?['msg'] ?? '请求异常',
fn: () => setState(() {}), btnText: data?['code'] == -101 ? '去登录' : null,
fn: () {
if (data?['code'] == -101) {
RoutePush.loginRedirectPush();
} else {
setState(() {
_futureBuilderFuture =
_subController.querySubFolder();
});
}
},
), ),
], ],
); );
} }
} else { } else {
// 骨架屏 // 骨架屏
return const Text('请求中'); return ListView.builder(
itemBuilder: (context, index) {
return const VideoCardHSkeleton();
},
itemCount: 10,
);
} }
}, },
), ),

View File

@ -74,7 +74,7 @@ class VideoDetailController extends GetxController
final scaffoldKey = GlobalKey<ScaffoldState>(); final scaffoldKey = GlobalKey<ScaffoldState>();
RxString bgCover = ''.obs; RxString bgCover = ''.obs;
RxString cover = ''.obs; RxString cover = ''.obs;
PlPlayerController plPlayerController = PlPlayerController.getInstance(); PlPlayerController plPlayerController = PlPlayerController();
late VideoItem firstVideo; late VideoItem firstVideo;
late AudioItem firstAudio; late AudioItem firstAudio;
@ -233,7 +233,7 @@ class VideoDetailController extends GetxController
audio, audio,
seekToTime, seekToTime,
duration, duration,
bool autoplay = true, bool? autoplay,
}) async { }) async {
/// 设置/恢复 屏幕亮度 /// 设置/恢复 屏幕亮度
if (brightness != null) { if (brightness != null) {
@ -266,7 +266,7 @@ class VideoDetailController extends GetxController
cid: cid.value, cid: cid.value,
enableHeart: enableHeart, enableHeart: enableHeart,
isFirstTime: isFirstTime, isFirstTime: isFirstTime,
autoplay: autoplay, autoplay: autoplay ?? autoPlay.value,
); );
/// 开启自动全屏时在player初始化完成后立即传入headerControl /// 开启自动全屏时在player初始化完成后立即传入headerControl

View File

@ -450,6 +450,7 @@ class VideoIntroController extends GetxController {
videoDetailCtr.danmakuCid.value = cid; videoDetailCtr.danmakuCid.value = cid;
videoDetailCtr.cover.value = cover; videoDetailCtr.cover.value = cover;
videoDetailCtr.queryVideoUrl(); videoDetailCtr.queryVideoUrl();
videoDetailCtr.getSubtitle();
// 重新请求评论 // 重新请求评论
try { try {
/// 未渲染回复组件时可能异常 /// 未渲染回复组件时可能异常

View File

@ -5,6 +5,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:lottie/lottie.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/index.dart';
@ -97,11 +98,14 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
); );
} }
} else { } else {
return const SliverToBoxAdapter( return SliverToBoxAdapter(
child: SizedBox( child: SizedBox(
height: 100, height: 100,
child: Center( child: Center(
child: CircularProgressIndicator(), child: Lottie.asset(
'assets/loading.json',
width: 200,
),
), ),
), ),
); );
@ -595,8 +599,4 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
); );
}); });
} }
// Widget StaffPanel(BuildContext context, videoIntroController) {
// return
// }
} }

View File

@ -1,5 +1,4 @@
import 'package:easy_debounce/easy_throttle.dart'; import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/reply.dart'; import 'package:pilipala/http/reply.dart';
@ -15,7 +14,6 @@ class VideoReplyController extends GetxController {
this.rpid, this.rpid,
this.replyLevel, this.replyLevel,
); );
final ScrollController scrollController = ScrollController();
// 视频aid 请求时使用的oid // 视频aid 请求时使用的oid
int? aid; int? aid;
// 层级 2为楼中楼 // 层级 2为楼中楼

View File

@ -67,13 +67,12 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
vsync: this, duration: const Duration(milliseconds: 300)); vsync: this, duration: const Duration(milliseconds: 300));
_futureBuilderFuture = _videoReplyController.queryReplyList(); _futureBuilderFuture = _videoReplyController.queryReplyList();
scrollController = ScrollController();
fabAnimationCtr.forward(); fabAnimationCtr.forward();
scrollListener(); scrollListener();
} }
void scrollListener() { void scrollListener() {
scrollController = _videoReplyController.scrollController;
scrollController.addListener( scrollController.addListener(
() { () {
if (scrollController.position.pixels >= if (scrollController.position.pixels >=
@ -185,7 +184,8 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
builder: (BuildContext context, snapshot) { builder: (BuildContext context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
var data = snapshot.data; var data = snapshot.data;
if (data['status']) { if (_videoReplyController.replyList.isNotEmpty ||
(data && data['status'])) {
// 请求成功 // 请求成功
return Obx( return Obx(
() => _videoReplyController.isLoadingMore && () => _videoReplyController.isLoadingMore &&

View File

@ -1,3 +1,4 @@
import 'package:appscheme/appscheme.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -11,7 +12,9 @@ import 'package:pilipala/models/video/reply/item.dart';
import 'package:pilipala/pages/preview/index.dart'; import 'package:pilipala/pages/preview/index.dart';
import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/index.dart';
import 'package:pilipala/pages/video/detail/reply_new/index.dart'; import 'package:pilipala/pages/video/detail/reply_new/index.dart';
import 'package:pilipala/utils/app_scheme.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/id_utils.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'package:pilipala/utils/url_utils.dart'; import 'package:pilipala/utils/url_utils.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
@ -642,32 +645,17 @@ InlineSpan buildContent(
'', '',
); );
} else { } else {
final String redirectUrl = Uri uri = Uri.parse(matchStr);
await UrlUtils.parseRedirectUrl(matchStr); SchemeEntity scheme = SchemeEntity(
if (redirectUrl == matchStr) { scheme: uri.scheme,
Clipboard.setData(ClipboardData(text: matchStr)); host: uri.host,
SmartDialog.showToast('地址可能有误'); port: uri.port,
return; path: uri.path,
} query: uri.queryParameters,
final String pathSegment = Uri.parse(redirectUrl).path; source: '',
final String lastPathSegment = dataString: matchStr,
pathSegment.split('/').last;
if (lastPathSegment.startsWith('BV')) {
UrlUtils.matchUrlPush(
lastPathSegment,
title,
redirectUrl,
); );
} else { PiliSchame.fullPathPush(scheme);
Get.toNamed(
'/webview',
parameters: {
'url': redirectUrl,
'type': 'url',
'pageTitle': title
},
);
}
} }
} else { } else {
if (appUrlSchema.startsWith('bilibili://search')) { if (appUrlSchema.startsWith('bilibili://search')) {

View File

@ -99,7 +99,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
fullScreenStatusListener(); fullScreenStatusListener();
if (Platform.isAndroid) { if (Platform.isAndroid) {
floating = vdCtr.floating!; floating = vdCtr.floating!;
autoEnterPip();
} }
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
lifecycleListener(); lifecycleListener();
@ -128,8 +127,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
} }
// 播放器状态监听 // 播放器状态监听
void playerListener(PlayerStatus? status) async { void playerListener(PlayerStatus status) async {
playerStatus.value = status!; playerStatus.value = status;
autoEnterPip(status: status);
if (status == PlayerStatus.completed) { if (status == PlayerStatus.completed) {
// 结束播放退出全屏 // 结束播放退出全屏
if (autoExitFullcreen) { if (autoExitFullcreen) {
@ -176,11 +176,12 @@ class _VideoDetailPageState extends State<VideoDetailPage>
/// 未开启自动播放时触发播放 /// 未开启自动播放时触发播放
Future<void> handlePlay() async { Future<void> handlePlay() async {
await vdCtr.playerInit(); await vdCtr.playerInit(autoplay: true);
plPlayerController = vdCtr.plPlayerController; plPlayerController = vdCtr.plPlayerController;
plPlayerController!.addStatusLister(playerListener); plPlayerController!.addStatusLister(playerListener);
vdCtr.autoPlay.value = true; vdCtr.autoPlay.value = true;
vdCtr.isShowCover.value = false; vdCtr.isShowCover.value = false;
autoEnterPip(status: PlayerStatus.playing);
} }
void fullScreenStatusListener() { void fullScreenStatusListener() {
@ -266,7 +267,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
} }
vdCtr.isFirstTime = false; vdCtr.isFirstTime = false;
final bool autoplay = autoPlayEnable; final bool autoplay = autoPlayEnable;
vdCtr.playerInit(autoplay: autoplay); vdCtr.playerInit();
/// 未开启自动播放时,未播放跳转下一页返回/播放后跳转下一页返回 /// 未开启自动播放时,未播放跳转下一页返回/播放后跳转下一页返回
vdCtr.autoPlay.value = !vdCtr.isShowCover.value; vdCtr.autoPlay.value = !vdCtr.isShowCover.value;
@ -287,10 +288,12 @@ class _VideoDetailPageState extends State<VideoDetailPage>
.subscribe(this, ModalRoute.of(context)! as PageRoute); .subscribe(this, ModalRoute.of(context)! as PageRoute);
} }
void autoEnterPip() { void autoEnterPip({PlayerStatus? status}) {
final String routePath = Get.currentRoute; final String routePath = Get.currentRoute;
if (autoPiP && routePath.startsWith('/video')) { if (autoPiP && routePath.startsWith('/video')) {
floating.toggleAutoPip(autoEnter: autoPiP); floating.toggleAutoPip(
autoEnter: autoPiP && status == PlayerStatus.playing,
);
} }
} }
@ -314,6 +317,15 @@ class _VideoDetailPageState extends State<VideoDetailPage>
case 'show' || 'restart': case 'show' || 'restart':
plPlayerController?.danmakuController?.clear(); plPlayerController?.danmakuController?.clear();
break; break;
case 'pause':
vdCtr.hiddenReplyReplyPanel();
if (vdCtr.videoType == SearchType.video) {
videoIntroController.hiddenEpisodeBottomSheet();
}
if (vdCtr.videoType == SearchType.media_bangumi) {
bangumiIntroController.hiddenEpisodeBottomSheet();
}
break;
} }
} }
@ -323,11 +335,13 @@ class _VideoDetailPageState extends State<VideoDetailPage>
children: [ children: [
GestureDetector( GestureDetector(
onTap: handlePlay, onTap: handlePlay,
child: Image.network( child: Obx(
vdCtr.videoItem['pic'], () => NetworkImgLayer(
src: vdCtr.cover.value,
width: Get.width, width: Get.width,
height: videoHeight, height: videoHeight,
fit: BoxFit.cover, // 适应方式根据需要调整 type: 'emote',
),
), ),
), ),
buildCustomAppBar(), buildCustomAppBar(),
@ -523,11 +537,10 @@ class _VideoDetailPageState extends State<VideoDetailPage>
Scaffold( Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
key: vdCtr.scaffoldKey, key: vdCtr.scaffoldKey,
backgroundColor: Colors.black,
appBar: PreferredSize( appBar: PreferredSize(
preferredSize: const Size.fromHeight(0), preferredSize: const Size.fromHeight(0),
child: AppBar( child: AppBar(
backgroundColor: Colors.transparent, backgroundColor: Colors.black,
elevation: 0, elevation: 0,
), ),
), ),
@ -557,8 +570,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
} }
return SliverAppBar( return SliverAppBar(
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
// 假装使用一个非空变量避免Obx检测不到而罢工 pinned: true,
pinned: vdCtr.autoPlay.value,
elevation: 0, elevation: 0,
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
forceElevated: innerBoxIsScrolled, forceElevated: innerBoxIsScrolled,
@ -566,8 +578,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
backgroundColor: Colors.black, backgroundColor: Colors.black,
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
background: PopScope( background: PopScope(
canPop: plPlayerController?.isFullScreen.value != canPop:
true, plPlayerController?.isFullScreen.value != true,
onPopInvoked: (bool didPop) { onPopInvoked: (bool didPop) {
if (plPlayerController?.isFullScreen.value == if (plPlayerController?.isFullScreen.value ==
true) { true) {
@ -579,16 +591,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
verticalScreen(); verticalScreen();
} }
}, },
child: LayoutBuilder( child: Hero(
builder: (BuildContext context, tag: heroTag,
BoxConstraints boxConstraints) { child: Stack(
return Stack(
children: <Widget>[ children: <Widget>[
if (isShowing) if (isShowing) videoPlayerPanel,
Padding(
padding: EdgeInsets.only(top: 0),
child: videoPlayerPanel,
),
/// 关闭自动播放时 手动播放 /// 关闭自动播放时 手动播放
Obx( Obx(
@ -604,9 +611,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
), ),
), ),
], ],
); ),
}, ),
)), ),
), ),
); );
}, },
@ -625,10 +632,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
: pinnedHeaderHeight; : pinnedHeaderHeight;
}, },
onlyOneScrollInBody: true, onlyOneScrollInBody: true,
body: ColoredBox( body: Column(
key: Key(heroTag),
color: Theme.of(context).colorScheme.background,
child: Column(
children: [ children: [
tabbarBuild(), tabbarBuild(),
Expanded( Expanded(
@ -644,8 +648,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
VideoIntroPanel(bvid: vdCtr.bvid), VideoIntroPanel(bvid: vdCtr.bvid),
] else if (vdCtr.videoType == ] else if (vdCtr.videoType ==
SearchType.media_bangumi) ...[ SearchType.media_bangumi) ...[
Obx(() => BangumiIntroPanel( Obx(() =>
cid: vdCtr.cid.value)), BangumiIntroPanel(cid: vdCtr.cid.value)),
], ],
SliverToBoxAdapter( SliverToBoxAdapter(
child: Divider( child: Divider(
@ -676,7 +680,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
), ),
), ),
), ),
),
/// 重新进入会刷新 /// 重新进入会刷新
// 播放完成/暂停播放 // 播放完成/暂停播放

View File

@ -52,7 +52,10 @@ class WebviewController extends GetxController {
loadProgress.value = progress; loadProgress.value = progress;
}, },
onPageStarted: (String url) { onPageStarted: (String url) {
final String str = Uri.parse(url).pathSegments[0]; final List pathSegments = Uri.parse(url).pathSegments;
if (pathSegments.isNotEmpty &&
url != 'https://passport.bilibili.com/h5-app/passport/login') {
final String str = pathSegments[0];
final Map matchRes = IdUtils.matchAvorBv(input: str); final Map matchRes = IdUtils.matchAvorBv(input: str);
final List matchKeys = matchRes.keys.toList(); final List matchKeys = matchRes.keys.toList();
if (matchKeys.isNotEmpty) { if (matchKeys.isNotEmpty) {
@ -63,6 +66,7 @@ class WebviewController extends GetxController {
); );
} }
} }
}
}, },
// 加载完成 // 加载完成
onUrlChange: (UrlChange urlChange) async { onUrlChange: (UrlChange urlChange) async {
@ -106,6 +110,9 @@ class WebviewController extends GetxController {
SmartDialog.showToast('登录成功'); SmartDialog.showToast('登录成功');
try { try {
Box userInfoCache = GStrorage.userInfo; Box userInfoCache = GStrorage.userInfo;
if (!userInfoCache.isOpen) {
userInfoCache = await Hive.openBox('userInfo');
}
await userInfoCache.put('userInfoCache', result['data']); await userInfoCache.put('userInfoCache', result['data']);
final HomeController homeCtr = Get.find<HomeController>(); final HomeController homeCtr = Get.find<HomeController>();

View File

@ -123,6 +123,7 @@ class PlPlayerController {
PreferredSizeWidget? bottomControl; PreferredSizeWidget? bottomControl;
Widget? danmuWidget; Widget? danmuWidget;
late RxList subtitles; late RxList subtitles;
String videoType = 'archive';
/// 数据加载监听 /// 数据加载监听
Stream<DataStatus> get onDataStatusChanged => dataStatus.status.stream; Stream<DataStatus> get onDataStatusChanged => dataStatus.status.stream;
@ -220,7 +221,7 @@ class PlPlayerController {
Rx<int> get playerCount => _playerCount; Rx<int> get playerCount => _playerCount;
/// ///
Rx<String> get videoType => _videoType; // Rx<String> get videoType => _videoType;
/// 弹幕开关 /// 弹幕开关
Rx<bool> isOpenDanmu = false.obs; Rx<bool> isOpenDanmu = false.obs;
@ -274,8 +275,7 @@ class PlPlayerController {
} }
// 添加一个私有构造函数 // 添加一个私有构造函数
PlPlayerController._() { PlPlayerController._internal(this.videoType) {
_videoType = videoType;
isOpenDanmu.value = isOpenDanmu.value =
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false); setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
blockTypes = blockTypes =
@ -330,11 +330,11 @@ class PlPlayerController {
} }
// 获取实例 传参 // 获取实例 传参
static PlPlayerController getInstance({ factory PlPlayerController({
String videoType = 'archive', String videoType = 'archive',
}) { }) {
// 如果实例尚未创建,则创建一个新实例 // 如果实例尚未创建,则创建一个新实例
_instance ??= PlPlayerController._(); _instance ??= PlPlayerController._internal(videoType);
if (videoType != 'none') { if (videoType != 'none') {
_instance!._playerCount.value += 1; _instance!._playerCount.value += 1;
_videoType.value = videoType; _videoType.value = videoType;
@ -406,7 +406,7 @@ class PlPlayerController {
if (!_listenersInitialized) { if (!_listenersInitialized) {
startListeners(); startListeners();
} }
await _initializePlayer(seekTo: seekTo, duration: _duration.value); await _initializePlayer(duration: _duration.value);
bool autoEnterFullcreen = bool autoEnterFullcreen =
setting.get(SettingBoxKey.enableAutoEnter, defaultValue: false); setting.get(SettingBoxKey.enableAutoEnter, defaultValue: false);
if (autoEnterFullcreen && _isFirstTime) { if (autoEnterFullcreen && _isFirstTime) {
@ -443,7 +443,7 @@ class PlPlayerController {
configuration: PlayerConfiguration( configuration: PlayerConfiguration(
// 默认缓存 5M 大小 // 默认缓存 5M 大小
bufferSize: bufferSize:
videoType.value == 'live' ? 32 * 1024 * 1024 : 5 * 1024 * 1024, videoType == 'live' ? 32 * 1024 * 1024 : 5 * 1024 * 1024,
), ),
); );
@ -523,7 +523,6 @@ class PlPlayerController {
// 开始播放 // 开始播放
Future _initializePlayer({ Future _initializePlayer({
Duration seekTo = Duration.zero,
Duration? duration, Duration? duration,
}) async { }) async {
getVideoFit(); getVideoFit();
@ -542,7 +541,7 @@ class PlPlayerController {
} }
/// 设置倍速 /// 设置倍速
if (videoType.value == 'live') { if (videoType == 'live') {
await setPlaybackSpeed(1.0); await setPlaybackSpeed(1.0);
} else { } else {
if (_playbackSpeed.value != 1.0) { if (_playbackSpeed.value != 1.0) {
@ -934,7 +933,7 @@ class PlPlayerController {
/// 设置长按倍速状态 live模式下禁用 /// 设置长按倍速状态 live模式下禁用
void setDoubleSpeedStatus(bool val) { void setDoubleSpeedStatus(bool val) {
if (videoType.value == 'live') { if (videoType == 'live') {
return; return;
} }
if (controlsLock.value) { if (controlsLock.value) {
@ -1016,7 +1015,7 @@ class PlPlayerController {
if (!_enableHeart) { if (!_enableHeart) {
return false; return false;
} }
if (videoType.value == 'live') { if (videoType == 'live') {
return; return;
} }
// 播放状态变化时,更新 // 播放状态变化时,更新
@ -1115,7 +1114,6 @@ class PlPlayerController {
// _buffered.close(); // _buffered.close();
// _showControls.close(); // _showControls.close();
// _controlsLock.close(); // _controlsLock.close();
// playerStatus.status.close(); // playerStatus.status.close();
// dataStatus.status.close(); // dataStatus.status.close();

View File

@ -7,6 +7,7 @@ import 'package:flutter_volume_controller/flutter_volume_controller.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:lottie/lottie.dart';
import 'package:media_kit/media_kit.dart'; import 'package:media_kit/media_kit.dart';
import 'package:media_kit_video/media_kit_video.dart'; import 'package:media_kit_video/media_kit_video.dart';
import 'package:pilipala/models/common/gesture_mode.dart'; import 'package:pilipala/models/common/gesture_mode.dart';
@ -334,7 +335,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
color: Colors.white, color: Colors.white,
), ),
), ),
fuc: () => _.triggerFullScreen(), fuc: () => _.triggerFullScreen(status: !_.isFullScreen.value),
), ),
}; };
final List<Widget> list = []; final List<Widget> list = [];
@ -652,7 +653,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
}, },
onDoubleTapDown: (TapDownDetails details) { onDoubleTapDown: (TapDownDetails details) {
// live模式下禁用 锁定时🔒禁用 // live模式下禁用 锁定时🔒禁用
if (_.videoType.value == 'live' || _.controlsLock.value) { if (_.videoType == 'live' || _.controlsLock.value) {
return; return;
} }
final double totalWidth = MediaQuery.sizeOf(context).width; final double totalWidth = MediaQuery.sizeOf(context).width;
@ -679,7 +680,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
/// 水平位置 快进 live模式下禁用 /// 水平位置 快进 live模式下禁用
onHorizontalDragUpdate: (DragUpdateDetails details) { onHorizontalDragUpdate: (DragUpdateDetails details) {
// live模式下禁用 锁定时🔒禁用 // live模式下禁用 锁定时🔒禁用
if (_.videoType.value == 'live' || _.controlsLock.value) { if (_.videoType == 'live' || _.controlsLock.value) {
return; return;
} }
// final double tapPosition = details.localPosition.dx; // final double tapPosition = details.localPosition.dx;
@ -695,7 +696,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
_.onChangedSliderStart(); _.onChangedSliderStart();
}, },
onHorizontalDragEnd: (DragEndDetails details) { onHorizontalDragEnd: (DragEndDetails details) {
if (_.videoType.value == 'live' || _.controlsLock.value) { if (_.videoType == 'live' || _.controlsLock.value) {
return; return;
} }
_.onChangedSliderEnd(); _.onChangedSliderEnd();
@ -733,14 +734,18 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
const double threshold = 7.0; // 滑动阈值 const double threshold = 7.0; // 滑动阈值
final bool flag = final bool flag =
fullScreenGestureMode != FullScreenGestureMode.values.last; fullScreenGestureMode != FullScreenGestureMode.values.last;
if (dy > _distance.value && dy > threshold) { if (dy > _distance.value &&
dy > threshold &&
!_.controlsLock.value) {
if (_.isFullScreen.value ^ flag) { if (_.isFullScreen.value ^ flag) {
lastFullScreenToggleTime = DateTime.now(); lastFullScreenToggleTime = DateTime.now();
// 下滑退出全屏 // 下滑退出全屏
await widget.controller.triggerFullScreen(status: flag); await widget.controller.triggerFullScreen(status: flag);
} }
_distance.value = 0.0; _distance.value = 0.0;
} else if (dy < _distance.value && dy < -threshold) { } else if (dy < _distance.value &&
dy < -threshold &&
!_.controlsLock.value) {
if (!_.isFullScreen.value ^ flag) { if (!_.isFullScreen.value ^ flag) {
lastFullScreenToggleTime = DateTime.now(); lastFullScreenToggleTime = DateTime.now();
// 上滑进入全屏 // 上滑进入全屏
@ -768,10 +773,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
), ),
// 头部、底部控制条 // 头部、底部控制条
SafeArea( Obx(
top: false,
bottom: false,
child: Obx(
() => Column( () => Column(
children: [ children: [
if (widget.headerControl != null || _.headerControl != null) if (widget.headerControl != null || _.headerControl != null)
@ -800,7 +802,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
], ],
), ),
), ),
),
/// 进度条 live模式下禁用 /// 进度条 live模式下禁用
@ -826,7 +827,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
return const SizedBox(); return const SizedBox();
} }
if (_.videoType.value == 'live') { if (_.videoType == 'live') {
return const SizedBox(); return const SizedBox();
} }
if (value > max || max <= 0) { if (value > max || max <= 0) {
@ -879,7 +880,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
// 锁 // 锁
Obx( Obx(
() => Visibility( () => Visibility(
visible: _.videoType.value != 'live' && _.isFullScreen.value, visible: _.videoType != 'live' && _.isFullScreen.value,
child: Align( child: Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: FractionalTranslation( child: FractionalTranslation(
@ -913,9 +914,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
colors: [Colors.black26, Colors.transparent], colors: [Colors.black26, Colors.transparent],
), ),
), ),
child: Image.asset( child: Lottie.asset(
'assets/images/loading.gif', 'assets/loading.json',
height: 25, width: 200,
), ),
), ),
); );
@ -939,7 +940,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
begin: 0.0, begin: 0.0,
end: _hideSeekBackwardButton.value ? 0.0 : 1.0, end: _hideSeekBackwardButton.value ? 0.0 : 1.0,
), ),
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 200),
builder: (BuildContext context, double value, builder: (BuildContext context, double value,
Widget? child) => Widget? child) =>
Opacity( Opacity(
@ -982,7 +983,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
begin: 0.0, begin: 0.0,
end: _hideSeekForwardButton.value ? 0.0 : 1.0, end: _hideSeekForwardButton.value ? 0.0 : 1.0,
), ),
duration: const Duration(milliseconds: 500), duration: const Duration(milliseconds: 200),
builder: (BuildContext context, double value, builder: (BuildContext context, double value,
Widget? child) => Widget? child) =>
Opacity( Opacity(

View File

@ -29,6 +29,10 @@ class AppBarAni extends StatelessWidget implements PreferredSizeWidget {
curve: Curves.linear, curve: Curves.linear,
)), )),
child: Container( child: Container(
padding: EdgeInsets.only(
left: MediaQuery.of(context).padding.left,
right: MediaQuery.of(context).padding.right,
),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: position! == 'top' gradient: position! == 'top'
? const LinearGradient( ? const LinearGradient(

View File

@ -20,6 +20,13 @@ class BackwardSeekIndicatorState extends State<BackwardSeekIndicator> {
Timer? timer; Timer? timer;
@override
void setState(VoidCallback fn) {
if (mounted) {
super.setState(fn);
}
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();

View File

@ -1,7 +1,6 @@
import 'package:audio_video_progress_bar/audio_video_progress_bar.dart'; import 'package:audio_video_progress_bar/audio_video_progress_bar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:nil/nil.dart';
import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/plugin/pl_player/index.dart';
import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/feed_back.dart';
@ -36,7 +35,7 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget {
final int max = _.durationSeconds.value; final int max = _.durationSeconds.value;
final int buffer = _.bufferedSeconds.value; final int buffer = _.bufferedSeconds.value;
if (value > max || max <= 0) { if (value > max || max <= 0) {
return nil; return const SizedBox();
} }
return Padding( return Padding(
padding: const EdgeInsets.only(left: 7, right: 7, bottom: 6), padding: const EdgeInsets.only(left: 7, right: 7, bottom: 6),

View File

@ -20,6 +20,13 @@ class ForwardSeekIndicatorState extends State<ForwardSeekIndicator> {
Timer? timer; Timer? timer;
@override
void setState(VoidCallback fn) {
if (mounted) {
super.setState(fn);
}
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();

View File

@ -26,7 +26,7 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler {
static final List<MediaItem> _item = []; static final List<MediaItem> _item = [];
Box setting = GStrorage.setting; Box setting = GStrorage.setting;
bool enableBackgroundPlay = false; bool enableBackgroundPlay = false;
PlPlayerController player = PlPlayerController.getInstance(videoType: 'none'); PlPlayerController player = PlPlayerController();
VideoPlayerServiceHandler() { VideoPlayerServiceHandler() {
revalidateSetting(); revalidateSetting();

View File

@ -18,7 +18,7 @@ class AudioSessionHandler {
session.configure(const AudioSessionConfiguration.music()); session.configure(const AudioSessionConfiguration.music());
session.interruptionEventStream.listen((event) { session.interruptionEventStream.listen((event) {
final player = PlPlayerController.getInstance(videoType: 'none'); final player = PlPlayerController(videoType: 'none');
if (event.begin) { if (event.begin) {
if (!player.playerStatus.playing) return; if (!player.playerStatus.playing) return;
switch (event.type) { switch (event.type) {
@ -51,7 +51,7 @@ class AudioSessionHandler {
// 耳机拔出暂停 // 耳机拔出暂停
session.becomingNoisyEventStream.listen((_) { session.becomingNoisyEventStream.listen((_) {
final player = PlPlayerController.getInstance(videoType: 'none'); final player = PlPlayerController(videoType: 'none');
if (player.playerStatus.playing) { if (player.playerStatus.playing) {
player.pause(); player.pause();
} }

View File

@ -89,7 +89,7 @@ class ShutdownTimerService {
return; return;
} }
PlPlayerController plPlayerController = PlPlayerController plPlayerController =
PlPlayerController.getInstance(videoType: 'none'); PlPlayerController(videoType: 'none');
if (!exitApp && !waitForPlayingCompleted) { if (!exitApp && !waitForPlayingCompleted) {
if (!plPlayerController.playerStatus.playing) { if (!plPlayerController.playerStatus.playing) {
//仅提示用户 //仅提示用户
@ -124,7 +124,7 @@ class ShutdownTimerService {
} else { } else {
//暂停播放 //暂停播放
PlPlayerController plPlayerController = PlPlayerController plPlayerController =
PlPlayerController.getInstance(videoType: 'none'); PlPlayerController(videoType: 'none');
if (plPlayerController.playerStatus.playing) { if (plPlayerController.playerStatus.playing) {
plPlayerController.pause(); plPlayerController.pause();
waitForPlayingCompleted = true; waitForPlayingCompleted = true;

View File

@ -4,7 +4,6 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/utils/route_push.dart'; import 'package:pilipala/utils/route_push.dart';
import '../http/search.dart'; import '../http/search.dart';
import '../models/common/search_type.dart';
import 'id_utils.dart'; import 'id_utils.dart';
import 'url_utils.dart'; import 'url_utils.dart';
import 'utils.dart'; import 'utils.dart';
@ -96,7 +95,7 @@ class PiliSchame {
} }
} }
if (scheme == 'https') { if (scheme == 'https') {
_fullPathPush(value); fullPathPush(value);
} }
} }
@ -127,7 +126,7 @@ class PiliSchame {
} }
} }
static Future<void> _fullPathPush(SchemeEntity value) async { static Future<void> fullPathPush(SchemeEntity value) async {
// https://m.bilibili.com/bangumi/play/ss39708 // https://m.bilibili.com/bangumi/play/ss39708
// https | m.bilibili.com | /bangumi/play/ss39708 // https | m.bilibili.com | /bangumi/play/ss39708
// final String scheme = value.scheme!; // final String scheme = value.scheme!;
@ -136,15 +135,15 @@ class PiliSchame {
Map<String, String>? query = value.query; Map<String, String>? query = value.query;
RegExp regExp = RegExp(r'^((www\.)|(m\.))?bilibili\.com$'); RegExp regExp = RegExp(r'^((www\.)|(m\.))?bilibili\.com$');
if (regExp.hasMatch(host)) { if (regExp.hasMatch(host)) {
print('bilibili.com host: $host');
print('bilibili.com path: $path');
final String lastPathSegment = path!.split('/').last; final String lastPathSegment = path!.split('/').last;
if (path.startsWith('/video')) { if (path.startsWith('/video')) {
if (lastPathSegment.contains('BV')) { Map matchRes = IdUtils.matchAvorBv(input: path);
_videoPush(null, lastPathSegment); if (matchRes.containsKey('AV')) {
} _videoPush(matchRes['AV']! as int, null);
if (lastPathSegment.contains('av')) { } else if (matchRes.containsKey('BV')) {
_videoPush(Utils.matchNum(lastPathSegment)[0], null); _videoPush(null, matchRes['BV'] as String);
} else {
SmartDialog.showToast('投稿匹配失败');
} }
} }
if (path.startsWith('/bangumi')) { if (path.startsWith('/bangumi')) {
@ -235,6 +234,24 @@ class PiliSchame {
print('个人空间'); print('个人空间');
Get.toNamed('/member?mid=$area', arguments: {'face': ''}); Get.toNamed('/member?mid=$area', arguments: {'face': ''});
break; break;
default:
final Map<String, dynamic> map =
IdUtils.matchAvorBv(input: area.split('?').first);
if (map.containsKey('AV')) {
_videoPush(map['AV']! as int, null);
} else if (map.containsKey('BV')) {
_videoPush(null, map['BV'] as String);
} else {
Get.toNamed(
'/webview',
parameters: {
'url': value.dataString ?? "",
'type': 'url',
'pageTitle': ''
},
);
}
break;
} }
} }
} }

View File

@ -41,4 +41,28 @@ class RoutePush {
SmartDialog.showToast('番剧获取失败:$e'); SmartDialog.showToast('番剧获取失败:$e');
} }
} }
// 登录跳转
static Future<void> loginPush() async {
await Get.toNamed(
'/webview',
parameters: {
'url': 'https://passport.bilibili.com/h5-app/passport/login',
'type': 'login',
'pageTitle': '登录bilibili',
},
);
}
// 登录跳转
static Future<void> loginRedirectPush() async {
await Get.offAndToNamed(
'/webview',
parameters: {
'url': 'https://passport.bilibili.com/h5-app/passport/login',
'type': 'login',
'pageTitle': '登录bilibili',
},
);
}
} }

View File

@ -44,7 +44,7 @@ class UrlUtils {
final String bv = matchRes['BV']; final String bv = matchRes['BV'];
final Map res = await SearchHttp.ab2cWithPic(bvid: bv); final Map res = await SearchHttp.ab2cWithPic(bvid: bv);
final int cid = res['cid']; final int cid = res['cid'];
final String pic = res['pic']; final String? pic = res['pic'];
final String heroTag = Utils.makeHeroTag(bv); final String heroTag = Utils.makeHeroTag(bv);
await Get.toNamed( await Get.toNamed(
'/video?bvid=$bv&cid=$cid', '/video?bvid=$bv&cid=$cid',

View File

@ -17,14 +17,6 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "6.2.0" version: "6.2.0"
animations:
dependency: "direct main"
description:
name: animations
sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.0.11"
appscheme: appscheme:
dependency: "direct main" dependency: "direct main"
description: description:
@ -101,10 +93,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: audio_video_progress_bar name: audio_video_progress_bar
sha256: ccc7d7b83d2a16c52d4a7fb332faabd1baa053fb0e4c16815aefd3945ab33b81 sha256: "552b1f73c56c4c88407999e0a8507176f60c56de3e6d63bc20a0eab48467d4c9"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.2" version: "2.0.3"
auto_orientation: auto_orientation:
dependency: "direct main" dependency: "direct main"
description: description:
@ -213,10 +205,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: catcher_2 name: catcher_2
sha256: "9cf33d2befd10058374e5fc6177577fdd938d73d9c06810de81cf91311a7ce98" sha256: "2c2c6f8cf8c817730cd1dbb010d55292396930e7a3d42c04c3039e3fd411a2f8"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.3" version: "1.2.6"
characters: characters:
dependency: transitive dependency: transitive
description: description:
@ -269,10 +261,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: connectivity_plus name: connectivity_plus
sha256: e9feae83b1849f61bad9f6f33ee00646e3410d54ce0821e02f262f9901dad3c9 sha256: db7a4e143dc72cc3cb2044ef9b052a7ebfe729513e6a82943bc3526f784365b8
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "6.0.1" version: "6.0.3"
connectivity_plus_platform_interface: connectivity_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -301,10 +293,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: cross_file name: cross_file
sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.3.3+8" version: "0.3.4+1"
crypto: crypto:
dependency: "direct main" dependency: "direct main"
description: description:
@ -333,10 +325,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: custom_sliding_segmented_control name: custom_sliding_segmented_control
sha256: "05b73fa48d57218bfdf806bad68a859812b216cd81fe81c6cbefde89f39eb257" sha256: "53c3e931c3ae1f696085d1ec70ac8e934da836595a9b7d9b88fdd0fcbf2a5574"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.1" version: "1.8.3"
dart_style: dart_style:
dependency: transitive dependency: transitive
description: description:
@ -461,10 +453,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: extended_image_library name: extended_image_library
sha256: "9b55fc5ebc65fad984de66b8f177a1bef2a84d79203c9c213f75ff83c2c29edd" sha256: c9caee8fe9b6547bd41c960c4f2d1ef8e34321804de6a1777f1d614a24247ad6
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "4.0.1" version: "4.0.4"
extended_list: extended_list:
dependency: transitive dependency: transitive
description: description:
@ -621,10 +613,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_volume_controller name: flutter_volume_controller
sha256: "0f10cc759499cb6c3e152a8f6ff8e5ce385b99db7e1f586d1a29d8e6c11f4082" sha256: fa4c36dfe7ef7f423704f34ab8e64e00b4a30a90aa6e56f251e9dba649efcd7f
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.1" version: "1.3.2"
flutter_web_plugins: flutter_web_plugins:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -722,10 +714,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: http name: http
sha256: d4872660c46d929f6b8a9ef4e7a7eff7e49bbf0c4ec3f385ee32df5119175139 sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.2" version: "1.2.1"
http2: http2:
dependency: transitive dependency: transitive
description: description:
@ -770,10 +762,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
io: io:
dependency: transitive dependency: transitive
description: description:
@ -798,6 +790,30 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "4.8.1" version: "4.8.1"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.flutter-io.cn"
source: hosted
version: "10.0.4"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.3"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@ -834,10 +850,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: logger name: logger
sha256: "6bbb9d6f7056729537a4309bda2e74e18e5d9f14302489cc1e93f33b3fe32cac" sha256: af05cc8714f356fd1f3888fb6741cbe9fbe25cdb6eedbab80e1a6db21047d4a4
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.0.2+1" version: "2.3.0"
logging: logging:
dependency: transitive dependency: transitive
description: description:
@ -846,30 +862,38 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.2.0" version: "1.2.0"
lottie:
dependency: "direct main"
description:
name: lottie
sha256: "6a24ade5d3d918c306bb1c21a6b9a04aab0489d51a2582522eea820b4093b62b"
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.2"
mailer: mailer:
dependency: transitive dependency: transitive
description: description:
name: mailer name: mailer
sha256: "57f6dd1496699999a7bfd0aa6be0645384f477f4823e16d4321c40a434346382" sha256: d25d89555c1031abacb448f07b801d7c01b4c21d4558e944b12b64394c84a3cb
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "6.0.1" version: "6.1.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.12.16" version: "0.12.16+1"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.5.0" version: "0.8.0"
media_kit: media_kit:
dependency: "direct main" dependency: "direct main"
description: description:
@ -949,10 +973,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.10.0" version: "1.12.0"
mime: mime:
dependency: transitive dependency: transitive
description: description:
@ -961,14 +985,6 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
nil:
dependency: "direct main"
description:
name: nil
sha256: ef05770c48942876d843bf6a4822d35e5da0ff893a61f1d5ad96d15c4a659136
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.1"
nm: nm:
dependency: transitive dependency: transitive
description: description:
@ -1022,10 +1038,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: path name: path
sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.8.3" version: "1.9.0"
path_parsing: path_parsing:
dependency: transitive dependency: transitive
description: description:
@ -1435,10 +1451,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.6.1" version: "0.7.0"
timing: timing:
dependency: transitive dependency: transitive
description: description:
@ -1467,10 +1483,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: universal_platform name: universal_platform
sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.0.0+1" version: "1.1.0"
uri_parser: uri_parser:
dependency: transitive dependency: transitive
description: description:
@ -1483,10 +1499,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: e9aa5ea75c84cf46b3db4eea212523591211c3cf2e13099ee4ec147f54201c86 sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "6.2.2" version: "6.2.6"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
@ -1499,10 +1515,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_ios name: url_launcher_ios
sha256: bba3373219b7abb6b5e0d071b0fe66dfbe005d07517a68e38d4fc3638f35c6d3 sha256: "7068716403343f6ba4969b4173cbf3b84fc768042124bc2c011e5d782b24fe89"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "6.2.1" version: "6.3.0"
url_launcher_linux: url_launcher_linux:
dependency: transitive dependency: transitive
description: description:
@ -1531,10 +1547,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "7286aec002c8feecc338cc33269e96b73955ab227456e9fb2a91f7fab8a358e9" sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.2.2" version: "2.3.1"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
@ -1591,6 +1607,14 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.4.0+2" version: "0.4.0+2"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.flutter-io.cn"
source: hosted
version: "14.2.1"
volume_controller: volume_controller:
dependency: transitive dependency: transitive
description: description:
@ -1603,18 +1627,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: wakelock_plus name: wakelock_plus
sha256: f268ca2116db22e57577fb99d52515a24bdc1d570f12ac18bb762361d43b043d sha256: "104d94837bb28c735894dcd592877e990149c380e6358b00c04398ca1426eed4"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.4" version: "1.2.1"
wakelock_plus_platform_interface: wakelock_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: wakelock_plus_platform_interface name: wakelock_plus_platform_interface
sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385" sha256: "582f2f7aecc7376332d961a0dd1efa9378ce117657e0ade55d9ff72699a55e82"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.1.0" version: "1.2.0"
watcher: watcher:
dependency: transitive dependency: transitive
description: description:
@ -1635,10 +1659,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: web name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "0.3.0" version: "0.5.1"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
@ -1659,34 +1683,34 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: webview_flutter name: webview_flutter
sha256: d81b68e88cc353e546afb93fb38958e3717282c5ac6e5d3be4a4aef9fc3c1413 sha256: "6869c8786d179f929144b4a1f86e09ac0eddfe475984951ea6c634774c16b522"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "4.5.0" version: "4.8.0"
webview_flutter_android: webview_flutter_android:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_android name: webview_flutter_android
sha256: e313dcdf45d4c95bcb8960351ef2389b7f0687b90bc92483f7f7983ae5758456 sha256: f42447ca49523f11d8f70abea55ea211b3cafe172dd7a0e7ac007bb35dd356dc
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.13.0" version: "3.16.4"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_platform_interface name: webview_flutter_platform_interface
sha256: "68e86162aa8fc646ae859e1585995c096c95fc2476881fa0c4a8d10f56013a5a" sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "2.8.0" version: "2.10.0"
webview_flutter_wkwebview: webview_flutter_wkwebview:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_wkwebview name: webview_flutter_wkwebview
sha256: "4d062ad505390ecef1c4bfb6001cd857a51e00912cc9dfb66edb1886a9ebd80c" sha256: "7affdf9d680c015b11587181171d3cad8093e449db1f7d9f0f08f4f33d24f9a0"
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.10.2" version: "3.13.1"
win32: win32:
dependency: transitive dependency: transitive
description: description:
@ -1728,5 +1752,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.2.0 <4.0.0" dart: ">=3.4.0 <4.0.0"
flutter: ">=3.16.0" flutter: ">=3.22.0"

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 # 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 # 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. # of the product and file versions while build-number is used as the build suffix.
version: 1.0.22+1022 version: 1.0.23+1023
environment: environment:
sdk: ">=3.0.0 <4.0.0" sdk: ">=3.0.0 <4.0.0"
@ -44,7 +44,7 @@ dependencies:
dio: ^5.4.1 dio: ^5.4.1
cookie_jar: ^4.0.8 cookie_jar: ^4.0.8
dio_cookie_manager: ^3.1.1 dio_cookie_manager: ^3.1.1
connectivity_plus: ^6.0.1 connectivity_plus: ^6.0.3
dio_http2_adapter: ^2.3.1+1 dio_http2_adapter: ^2.3.1+1
# 图片 # 图片
@ -66,7 +66,7 @@ dependencies:
# cookie 管理 # cookie 管理
webview_cookie_manager: ^2.0.6 webview_cookie_manager: ^2.0.6
# 浏览器 # 浏览器
webview_flutter: ^4.5.0 webview_flutter: ^4.8.0
# 解决sliver滑动不同步 # 解决sliver滑动不同步
extended_nested_scroll_view: ^6.2.1 extended_nested_scroll_view: ^6.2.1
# 上拉加载 # 上拉加载
@ -79,7 +79,7 @@ dependencies:
flutter_smart_dialog: ^4.9.4 flutter_smart_dialog: ^4.9.4
# 下滑关闭 # 下滑关闭
dismissible_page: ^1.0.2 dismissible_page: ^1.0.2
custom_sliding_segmented_control: ^1.7.5 custom_sliding_segmented_control: ^1.8.3
# 加密 # 加密
crypto: ^3.0.3 crypto: ^3.0.3
encrypt: ^5.0.3 encrypt: ^5.0.3
@ -94,19 +94,18 @@ dependencies:
audio_session: ^0.1.18 audio_session: ^0.1.18
# 音量、亮度、屏幕控制 # 音量、亮度、屏幕控制
flutter_volume_controller: ^1.3.1 flutter_volume_controller: ^1.3.2
screen_brightness: ^0.2.2+1 screen_brightness: ^0.2.2+1
wakelock_plus: ^1.1.1 wakelock_plus: ^1.1.6
universal_platform: ^1.0.0+1 universal_platform: ^1.1.0
# 进度条 # 进度条
audio_video_progress_bar: ^2.0.2 audio_video_progress_bar: ^2.0.3
auto_orientation: ^2.3.1 auto_orientation: ^2.3.1
protobuf: ^3.0.0 protobuf: ^3.0.0
animations: ^2.0.11
# 获取appx信息 # 获取appx信息
package_info_plus: ^4.1.0 package_info_plus: ^4.2.0
url_launcher: ^6.1.14 url_launcher: ^6.2.6
flutter_svg: ^2.0.10+1 flutter_svg: ^2.0.10+1
# 防抖节流 # 防抖节流
easy_debounce: ^2.0.3 easy_debounce: ^2.0.3
@ -136,16 +135,16 @@ dependencies:
gt3_flutter_plugin: ^0.0.8 gt3_flutter_plugin: ^0.0.8
uuid: ^3.0.7 uuid: ^3.0.7
scrollable_positioned_list: ^0.3.8 scrollable_positioned_list: ^0.3.8
nil: ^1.1.1 catcher_2: ^1.2.6
catcher_2: ^1.2.3 logger: ^2.3.0
logger: ^2.0.2+1 path: ^1.9.0
path: 1.8.3
# 电池优化 # 电池优化
disable_battery_optimization: ^1.1.1 disable_battery_optimization: ^1.1.1
# 展开/收起 # 展开/收起
expandable: ^5.0.1 expandable: ^5.0.1
# 投屏 # 投屏
dlna_dart: ^0.0.8 dlna_dart: ^0.0.8
lottie: ^3.1.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@ -205,6 +204,7 @@ flutter:
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
assets: assets:
- assets/
- assets/images/ - assets/images/
- assets/images/lv/ - assets/images/lv/
- assets/images/logo/ - assets/images/logo/