diff --git a/lib/http/interceptor.dart b/lib/http/interceptor.dart index 3ea3e15f3..26bc4968e 100644 --- a/lib/http/interceptor.dart +++ b/lib/http/interceptor.dart @@ -1,6 +1,6 @@ // ignore_for_file: avoid_print -import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:PiliPalaX/utils/utils.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -77,29 +77,8 @@ class ApiInterceptor extends Interceptor { case DioExceptionType.sendTimeout: return '发送请求超时,请检查网络设置'; case DioExceptionType.unknown: - final String res = await checkConnect(); + final String res = (await Utils.checkConnectivity()).title; return '$res网络异常 ${error.error}'; } } - - static Future checkConnect() async { - final List connectivityResult = - await Connectivity().checkConnectivity(); - switch (connectivityResult.first) { - case ConnectivityResult.mobile: - return '流量'; - case ConnectivityResult.wifi: - return 'Wi-Fi'; - case ConnectivityResult.ethernet: - return '局域'; - case ConnectivityResult.vpn: - return '代理'; - case ConnectivityResult.other: - return '其他'; - case ConnectivityResult.none: - return '无'; - default: - return ''; - } - } } diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index 813d2fa0a..8d55a37e5 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -68,12 +68,13 @@ class _MainAppState extends State } void _checkDefaultSearch([bool shouldCheck = false]) { - if (shouldCheck && - _mainController.pages[_mainController.pageController.page?.round() ?? 0] - is! HomePage) { - return; - } if (_homeController.enableSearchWord) { + if (shouldCheck && + _mainController + .pages[_mainController.pageController.page?.round() ?? 0] + is! HomePage) { + return; + } int now = DateTime.now().millisecondsSinceEpoch; if (now - _homeController.lateCheckAt >= 5 * 60 * 1000) { _homeController.lateCheckAt = now; diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index 33be1b1e7..849dae289 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -148,11 +148,10 @@ class _ExtraSettingState extends State { leading: Stack( alignment: Alignment.center, children: [ - const Icon(Icons.shield), + const Icon(Icons.shield_outlined), Icon( Icons.play_arrow_rounded, - size: 18, - color: Theme.of(context).colorScheme.surface, + size: 15, ), ], ), diff --git a/lib/pages/setting/video_setting.dart b/lib/pages/setting/video_setting.dart index 448ddaadc..7592044bc 100644 --- a/lib/pages/setting/video_setting.dart +++ b/lib/pages/setting/video_setting.dart @@ -20,7 +20,9 @@ class VideoSetting extends StatefulWidget { class _VideoSettingState extends State { Box setting = GStorage.setting; late dynamic defaultVideoQa; + late dynamic defaultVideoQaCellular; late dynamic defaultAudioQa; + late dynamic defaultAudioQaCellular; late dynamic defaultDecode; late dynamic secondDecode; late dynamic hardwareDecoding; @@ -30,20 +32,42 @@ class _VideoSettingState extends State { @override void initState() { super.initState(); - defaultVideoQa = setting.get(SettingBoxKey.defaultVideoQa, - defaultValue: VideoQuality.values.last.code); - defaultAudioQa = setting.get(SettingBoxKey.defaultAudioQa, - defaultValue: AudioQuality.values.last.code); - defaultDecode = setting.get(SettingBoxKey.defaultDecode, - defaultValue: VideoDecodeFormats.values.last.code); - secondDecode = setting.get(SettingBoxKey.secondDecode, - defaultValue: VideoDecodeFormats.values[1].code); - hardwareDecoding = setting.get(SettingBoxKey.hardwareDecoding, - defaultValue: Platform.isAndroid ? 'auto-safe' : 'auto'); - videoSync = - setting.get(SettingBoxKey.videoSync, defaultValue: 'display-resample'); - defaultCDNService = setting.get(SettingBoxKey.CDNService, - defaultValue: CDNService.backupUrl.code); + defaultVideoQa = setting.get( + SettingBoxKey.defaultVideoQa, + defaultValue: VideoQuality.values.last.code, + ); + defaultVideoQaCellular = setting.get( + SettingBoxKey.defaultVideoQaCellular, + defaultValue: VideoQuality.high1080.code, + ); + defaultAudioQa = setting.get( + SettingBoxKey.defaultAudioQa, + defaultValue: AudioQuality.values.last.code, + ); + defaultAudioQaCellular = setting.get( + SettingBoxKey.defaultAudioQaCellular, + defaultValue: AudioQuality.k192.code, + ); + defaultDecode = setting.get( + SettingBoxKey.defaultDecode, + defaultValue: VideoDecodeFormats.values.last.code, + ); + secondDecode = setting.get( + SettingBoxKey.secondDecode, + defaultValue: VideoDecodeFormats.values[1].code, + ); + hardwareDecoding = setting.get( + SettingBoxKey.hardwareDecoding, + defaultValue: Platform.isAndroid ? 'auto-safe' : 'auto', + ); + videoSync = setting.get( + SettingBoxKey.videoSync, + defaultValue: 'display-resample', + ); + defaultCDNService = setting.get( + SettingBoxKey.CDNService, + defaultValue: CDNService.backupUrl.code, + ); } @override @@ -79,26 +103,25 @@ class _VideoSettingState extends State { defaultVal: true, ), ListTile( - enabled: false, - onTap: null, - title: Text("b站定向流量支持", style: titleStyle), + title: Text("B站定向流量支持", style: titleStyle), subtitle: - Text("若套餐含b站定向流量,则会自动使用。可查阅运营商的流量记录确认。", style: subTitleStyle), + Text("若套餐含B站定向流量,则会自动使用。可查阅运营商的流量记录确认。", style: subTitleStyle), leading: const Icon(Icons.perm_data_setting_outlined), trailing: Transform.scale( alignment: Alignment.centerRight, // 缩放Switch的大小后保持右侧对齐, 避免右侧空隙过大 scale: 0.8, child: Switch( - thumbIcon: WidgetStateProperty.resolveWith( - (Set states) { - if (states.isNotEmpty && - states.first == WidgetState.selected) { - return const Icon(Icons.done); - } - return null; // All other states will use the default thumbIcon. - }), - value: true, - onChanged: null), + thumbIcon: WidgetStateProperty.resolveWith( + (Set states) { + if (states.isNotEmpty && + states.first == WidgetState.selected) { + return const Icon(Icons.lock_outline_rounded); + } + return null; // All other states will use the default thumbIcon. + }), + value: true, + onChanged: (_) {}, + ), ), ), ListTile( @@ -147,11 +170,12 @@ class _VideoSettingState extends State { context: context, builder: (context) { return SelectDialog( - title: '默认画质', - value: defaultVideoQa, - values: VideoQuality.values.reversed.map((e) { - return {'title': e.description, 'value': e.code}; - }).toList()); + title: '默认画质', + value: defaultVideoQa, + values: VideoQuality.values.reversed.map((e) { + return {'title': e.description, 'value': e.code}; + }).toList(), + ); }, ); if (result != null) { @@ -161,6 +185,34 @@ class _VideoSettingState extends State { } }, ), + ListTile( + dense: false, + title: Text('蜂窝网络画质', style: titleStyle), + leading: const Icon(Icons.video_settings_outlined), + subtitle: Text( + '当前画质:${VideoQualityCode.fromCode(defaultVideoQaCellular)!.description!}', + style: subTitleStyle, + ), + onTap: () async { + int? result = await showDialog( + context: context, + builder: (context) { + return SelectDialog( + title: '蜂窝网络画质', + value: defaultVideoQaCellular, + values: VideoQuality.values.reversed.map((e) { + return {'title': e.description, 'value': e.code}; + }).toList(), + ); + }, + ); + if (result != null) { + defaultVideoQaCellular = result; + setting.put(SettingBoxKey.defaultVideoQaCellular, result); + setState(() {}); + } + }, + ), ListTile( dense: false, title: Text('默认音质', style: titleStyle), @@ -174,11 +226,12 @@ class _VideoSettingState extends State { context: context, builder: (context) { return SelectDialog( - title: '默认音质', - value: defaultAudioQa, - values: AudioQuality.values.reversed.map((e) { - return {'title': e.description, 'value': e.code}; - }).toList()); + title: '默认音质', + value: defaultAudioQa, + values: AudioQuality.values.reversed.map((e) { + return {'title': e.description, 'value': e.code}; + }).toList(), + ); }, ); if (result != null) { @@ -188,6 +241,34 @@ class _VideoSettingState extends State { } }, ), + ListTile( + dense: false, + title: Text('蜂窝网络音质', style: titleStyle), + leading: const Icon(Icons.music_video_outlined), + subtitle: Text( + '当前音质:${AudioQualityCode.fromCode(defaultAudioQaCellular)!.description!}', + style: subTitleStyle, + ), + onTap: () async { + int? result = await showDialog( + context: context, + builder: (context) { + return SelectDialog( + title: '蜂窝网络音质', + value: defaultAudioQaCellular, + values: AudioQuality.values.reversed.map((e) { + return {'title': e.description, 'value': e.code}; + }).toList(), + ); + }, + ); + if (result != null) { + defaultAudioQaCellular = result; + setting.put(SettingBoxKey.defaultAudioQaCellular, result); + setState(() {}); + } + }, + ), ListTile( dense: false, title: Text('首选解码格式', style: titleStyle), diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index e3ffa5eec..ec2181dca 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -18,6 +18,7 @@ import 'package:PiliPalaX/pages/video/detail/related/controller.dart'; import 'package:PiliPalaX/pages/video/detail/reply/controller.dart'; import 'package:PiliPalaX/utils/extension.dart'; import 'package:canvas_danmaku/models/danmaku_content_item.dart'; +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:dio/dio.dart'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; @@ -206,7 +207,7 @@ class VideoDetailController extends GetxController late PreferredSizeWidget headerControl; // late bool enableCDN; - late int? cacheVideoQa; + int? cacheVideoQa; late String cacheDecode; late String cacheSecondDecode; late int cacheAudioQa; @@ -303,16 +304,11 @@ class VideoDetailController extends GetxController // CDN优化 // enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true); - // 预设的画质 - cacheVideoQa = setting.get(SettingBoxKey.defaultVideoQa, - defaultValue: VideoQuality.values.last.code); // 预设的解码格式 cacheDecode = setting.get(SettingBoxKey.defaultDecode, defaultValue: VideoDecodeFormats.values.last.code); cacheSecondDecode = setting.get(SettingBoxKey.secondDecode, defaultValue: VideoDecodeFormats.values[1].code); - cacheAudioQa = setting.get(SettingBoxKey.defaultAudioQa, - defaultValue: AudioQuality.hiRes.code); oid.value = IdUtils.bv2av(Get.parameters['bvid']!); enableSponsorBlock = setting.get(SettingBoxKey.enableSponsorBlock, defaultValue: false); @@ -1013,6 +1009,21 @@ class VideoDetailController extends GetxController // 视频链接 Future queryVideoUrl() async { + if (cacheVideoQa == null) { + await Utils.checkConnectivity().then((res) { + cacheVideoQa = res == ConnectivityResult.mobile + ? setting.get(SettingBoxKey.defaultVideoQaCellular, + defaultValue: VideoQuality.high1080.code) + : setting.get(SettingBoxKey.defaultVideoQa, + defaultValue: VideoQuality.values.last.code); + + cacheAudioQa = res == ConnectivityResult.mobile + ? setting.get(SettingBoxKey.defaultAudioQaCellular, + defaultValue: AudioQuality.k192.code) + : setting.get(SettingBoxKey.defaultAudioQa, + defaultValue: AudioQuality.hiRes.code); + }); + } var result = await VideoHttp.videoUrl(cid: cid.value, bvid: bvid); if (result['status']) { data = result['data']; diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 859217a2a..e89df009e 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -808,21 +808,21 @@ class _HeaderControlState extends State { videoFormat[i].quality) { return; } + Get.back(); final int quality = videoFormat[i].quality!; widget.videoDetailCtr!.currentVideoQa = VideoQualityCode.fromCode(quality)!; - String oldQualityDesc = - VideoQualityCode.fromCode(setting.get( - SettingBoxKey.defaultVideoQa, - defaultValue: - VideoQuality.values.last.code))! - .description; - setting.put( - SettingBoxKey.defaultVideoQa, quality); - SmartDialog.showToast( - "默认画质由:$oldQualityDesc 变为:${VideoQualityCode.fromCode(quality)!.description}"); widget.videoDetailCtr!.updatePlayer(); - Get.back(); + // String oldQualityDesc = + // VideoQualityCode.fromCode(setting.get( + // SettingBoxKey.defaultVideoQa, + // defaultValue: + // VideoQuality.values.last.code))! + // .description; + // setting.put( + // SettingBoxKey.defaultVideoQa, quality); + // SmartDialog.showToast( + // "默认画质由:$oldQualityDesc 变为:${VideoQualityCode.fromCode(quality)!.description}"); }, // 可能包含会员解锁画质 enabled: i >= totalQaSam - userfulQaSam, @@ -897,20 +897,20 @@ class _HeaderControlState extends State { if (currentAudioQa.code == i.id) { return; } + Get.back(); final int quality = i.id!; widget.videoDetailCtr!.currentAudioQa = AudioQualityCode.fromCode(quality)!; - String oldQualityDesc = AudioQualityCode.fromCode( - setting.get(SettingBoxKey.defaultAudioQa, - defaultValue: - AudioQuality.values.last.code))! - .description; - setting.put( - SettingBoxKey.defaultAudioQa, quality); - SmartDialog.showToast( - "默认音质由:$oldQualityDesc 变为:${AudioQualityCode.fromCode(quality)!.description}"); widget.videoDetailCtr!.updatePlayer(); - Get.back(); + // String oldQualityDesc = AudioQualityCode.fromCode( + // setting.get(SettingBoxKey.defaultAudioQa, + // defaultValue: + // AudioQuality.values.last.code))! + // .description; + // setting.put( + // SettingBoxKey.defaultAudioQa, quality); + // SmartDialog.showToast( + // "默认音质由:$oldQualityDesc 变为:${AudioQualityCode.fromCode(quality)!.description}"); }, contentPadding: const EdgeInsets.only(left: 20, right: 20), @@ -1763,11 +1763,15 @@ class _HeaderControlState extends State { icon: Stack( alignment: Alignment.center, children: [ - Icon(Icons.shield, size: 18), + Icon( + Icons.shield_outlined, + size: 19, + color: Colors.white, + ), Icon( Icons.play_arrow_rounded, - size: 17, - color: Colors.black87, + size: 13, + color: Colors.white, ), ], ), diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index ef45c1a48..0fe4e0baf 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -257,7 +257,9 @@ class SettingBoxKey { autoUpgradeEnable = 'autoUpgradeEnable', feedBackEnable = 'feedBackEnable', defaultVideoQa = 'defaultVideoQa', + defaultVideoQaCellular = 'defaultVideoQaCellular', defaultAudioQa = 'defaultAudioQa', + defaultAudioQaCellular = 'defaultAudioQaCellular', autoPlayEnable = 'autoPlayEnable', fullScreenMode = 'fullScreenMode', defaultDecode = 'defaultDecode', diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index eed1504b5..a5898d2ca 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -17,6 +17,7 @@ import 'package:PiliPalaX/pages/video/detail/introduction/widgets/group_panel.da import 'package:PiliPalaX/utils/feed_back.dart'; import 'package:PiliPalaX/utils/login.dart'; import 'package:PiliPalaX/utils/storage.dart'; +import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:crypto/crypto.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; @@ -30,9 +31,17 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web; import 'package:html/dom.dart' as dom; import 'package:html/parser.dart' as html_parser; +extension ConnectivityResultExt on ConnectivityResult { + String get title => ['蓝牙', 'Wi-Fi', '局域', '流量', '无', '代理', '其他'][index]; +} + class Utils { static final Random random = Random(); + static Future checkConnectivity() async { + return (await Connectivity().checkConnectivity()).first; + } + static Future getWwebid(mid) async { try { dynamic response =