diff --git a/lib/common/skeleton/video_card_h.dart b/lib/common/skeleton/video_card_h.dart index ca508c7f8..27e8811e7 100644 --- a/lib/common/skeleton/video_card_h.dart +++ b/lib/common/skeleton/video_card_h.dart @@ -13,85 +13,67 @@ class VideoCardHSkeleton extends StatelessWidget { horizontal: StyleString.safeSpace, vertical: 5, ), - child: LayoutBuilder( - builder: (context, boxConstraints) { - double width = - (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; - return SizedBox( - height: width / StyleString.aspectRatio, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (context, boxConstraints) { - return Container( - decoration: BoxDecoration( - color: - Theme.of(context).colorScheme.onInverseSurface, - borderRadius: StyleString.mdRadius, - ), - ); - }, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + return Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.onInverseSurface, + borderRadius: StyleString.mdRadius, ), - ), - // VideoContent(videoItem: videoItem) - Expanded( - child: Padding( - padding: const EdgeInsets.fromLTRB(10, 4, 6, 4), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - color: - Theme.of(context).colorScheme.onInverseSurface, - width: 200, - height: 11, - margin: const EdgeInsets.only(bottom: 5), - ), - Container( - color: - Theme.of(context).colorScheme.onInverseSurface, - width: 150, - height: 13, - ), - const Spacer(), - Container( - color: - Theme.of(context).colorScheme.onInverseSurface, - width: 100, - height: 13, - margin: const EdgeInsets.only(bottom: 5), - ), - Row( - children: [ - Container( - color: Theme.of(context) - .colorScheme - .onInverseSurface, - width: 40, - height: 13, - margin: const EdgeInsets.only(right: 8), - ), - Container( - color: Theme.of(context) - .colorScheme - .onInverseSurface, - width: 40, - height: 13, - ), - ], - ) - ], - ), - ), - ), - ], + ); + }, ), - ); - }, + ), + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(10, 4, 6, 4), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + color: Theme.of(context).colorScheme.onInverseSurface, + width: 200, + height: 11, + margin: const EdgeInsets.only(bottom: 5), + ), + Container( + color: Theme.of(context).colorScheme.onInverseSurface, + width: 150, + height: 13, + ), + const Spacer(), + Container( + color: Theme.of(context).colorScheme.onInverseSurface, + width: 100, + height: 13, + margin: const EdgeInsets.only(bottom: 5), + ), + Row( + children: [ + Container( + color: Theme.of(context).colorScheme.onInverseSurface, + width: 40, + height: 13, + margin: const EdgeInsets.only(right: 8), + ), + Container( + color: Theme.of(context).colorScheme.onInverseSurface, + width: 40, + height: 13, + ), + ], + ) + ], + ), + ), + ), + ], ), ), ); diff --git a/lib/common/widgets/video_card_h.dart b/lib/common/widgets/video_card_h.dart index c19e0d2c8..795ba21cf 100644 --- a/lib/common/widgets/video_card_h.dart +++ b/lib/common/widgets/video_card_h.dart @@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/video_progress_indicator.dart'; import 'package:PiliPlus/models/model_hot_video_item.dart'; import 'package:PiliPlus/models/model_video.dart'; import 'package:PiliPlus/models/search/result.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import '../../http/search.dart'; @@ -80,7 +81,7 @@ class VideoCardH extends StatelessWidget { if ((videoItem is HotVideoItemModel) && (videoItem as HotVideoItemModel).redirectUrl?.isNotEmpty == true) { - if (Utils.viewPgcFromUri( + if (PageUtils.viewPgcFromUri( (videoItem as HotVideoItemModel).redirectUrl!)) { return; } @@ -91,7 +92,7 @@ class VideoCardH extends StatelessWidget { if (source == 'later') { onViewLater!(cid); } else { - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'videoItem': videoItem, @@ -115,8 +116,7 @@ class VideoCardH extends StatelessWidget { AspectRatio( aspectRatio: StyleString.aspectRatio, child: LayoutBuilder( - builder: (BuildContext context, - BoxConstraints boxConstraints) { + builder: (context, boxConstraints) { final double maxWidth = boxConstraints.maxWidth; final double maxHeight = boxConstraints.maxHeight; num? progress; diff --git a/lib/common/widgets/video_card_h_member_video.dart b/lib/common/widgets/video_card_h_member_video.dart index eb0f59540..7d7a6d4fa 100644 --- a/lib/common/widgets/video_card_h_member_video.dart +++ b/lib/common/widgets/video_card_h_member_video.dart @@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/stat/stat.dart'; import 'package:PiliPlus/common/widgets/video_popup_menu.dart'; import 'package:PiliPlus/common/widgets/video_progress_indicator.dart'; import 'package:PiliPlus/models/space_archive/item.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import '../../utils/utils.dart'; @@ -40,7 +41,7 @@ class VideoCardHMemberVideo extends StatelessWidget { return; } if (videoItem.isPgc == true && videoItem.uri?.isNotEmpty == true) { - if (Utils.viewPgcFromUri(videoItem.uri!)) { + if (PageUtils.viewPgcFromUri(videoItem.uri!)) { return; } } @@ -48,7 +49,7 @@ class VideoCardHMemberVideo extends StatelessWidget { return; } try { - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${videoItem.bvid}&cid=${videoItem.cid}', arguments: { 'heroTag': Utils.makeHeroTag(videoItem.bvid), diff --git a/lib/common/widgets/video_card_v.dart b/lib/common/widgets/video_card_v.dart index d2c51547e..077cd0370 100644 --- a/lib/common/widgets/video_card_v.dart +++ b/lib/common/widgets/video_card_v.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/http/search.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -33,7 +34,7 @@ class VideoCardV extends StatelessWidget { String goto = videoItem.goto!; switch (goto) { case 'bangumi': - Utils.viewBangumi(epId: videoItem.param!); + PageUtils.viewBangumi(epId: videoItem.param!); break; case 'av': String bvid = videoItem.bvid ?? IdUtils.av2bv(videoItem.aid!); @@ -41,7 +42,7 @@ class VideoCardV extends StatelessWidget { if (cid == -1) { cid = await SearchHttp.ab2c(aid: videoItem.aid, bvid: bvid); } - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { // 'videoItem': videoItem, @@ -68,7 +69,7 @@ class VideoCardV extends StatelessWidget { if (uri.startsWith('http')) { String id = Uri.parse(uri).path.split('/')[1]; if (isStringNumeric(id)) { - Utils.pushDynFromId(id); + PageUtils.pushDynFromId(id); return; } } @@ -84,7 +85,7 @@ class VideoCardV extends StatelessWidget { break; default: SmartDialog.showToast(goto); - Utils.handleWebview(videoItem.uri!); + PageUtils.handleWebview(videoItem.uri!); } } diff --git a/lib/common/widgets/video_card_v_member_home.dart b/lib/common/widgets/video_card_v_member_home.dart index 7fcac04cb..ad8c323b4 100644 --- a/lib/common/widgets/video_card_v_member_home.dart +++ b/lib/common/widgets/video_card_v_member_home.dart @@ -2,6 +2,7 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/http/search.dart'; import 'package:PiliPlus/models/space/item.dart'; import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import '../../utils/utils.dart'; @@ -22,11 +23,11 @@ class VideoCardVMemberHome extends StatelessWidget { String goto = videoItem.goto ?? ''; switch (goto) { case 'bangumi': - Utils.viewBangumi(epId: videoItem.param); + PageUtils.viewBangumi(epId: videoItem.param); break; case 'av': if (videoItem.isPgc == true && videoItem.uri?.isNotEmpty == true) { - if (Utils.viewPgcFromUri(videoItem.uri!)) { + if (PageUtils.viewPgcFromUri(videoItem.uri!)) { return; } } @@ -37,7 +38,7 @@ class VideoCardVMemberHome extends StatelessWidget { } int? cid = videoItem.firstCid; cid ??= await SearchHttp.ab2c(aid: aid, bvid: bvid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${bvid ?? IdUtils.av2bv(int.parse(aid!))}&cid=$cid', arguments: { 'pic': videoItem.cover, @@ -47,7 +48,7 @@ class VideoCardVMemberHome extends StatelessWidget { break; default: SmartDialog.showToast(goto); - Utils.handleWebview(videoItem.uri ?? ''); + PageUtils.handleWebview(videoItem.uri ?? ''); } } diff --git a/lib/grpc/grpc_repo.dart b/lib/grpc/grpc_repo.dart index 683549088..886f1d244 100644 --- a/lib/grpc/grpc_repo.dart +++ b/lib/grpc/grpc_repo.dart @@ -16,7 +16,7 @@ import 'package:PiliPlus/grpc/network/network.pb.dart' as network; import 'package:PiliPlus/grpc/restriction/restriction.pb.dart'; import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/constants.dart'; -import 'package:PiliPlus/utils/login.dart'; +import 'package:PiliPlus/utils/login_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:archive/archive.dart'; diff --git a/lib/http/login.dart b/lib/http/login.dart index 2700080a5..072072a31 100644 --- a/lib/http/login.dart +++ b/lib/http/login.dart @@ -5,7 +5,7 @@ import 'package:dio/dio.dart'; import 'package:encrypt/encrypt.dart'; import '../common/constants.dart'; import '../models/login/index.dart'; -import '../utils/login.dart'; +import '../utils/login_utils.dart'; import '../utils/utils.dart'; import 'index.dart'; diff --git a/lib/main.dart b/lib/main.dart index 155df5d5b..651c31bc0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:PiliPlus/build_config.dart'; import 'package:PiliPlus/pages/video/detail/view_v.dart'; import 'package:PiliPlus/utils/cache_manage.dart'; -import 'package:PiliPlus/utils/utils.dart'; +import 'package:PiliPlus/utils/theme_utils.dart'; import 'package:flex_seed_scheme/flex_seed_scheme.dart'; import 'package:flutter/services.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; @@ -182,12 +182,12 @@ class MyApp extends StatelessWidget { return GetMaterialApp( // showSemanticsDebugger: true, title: 'PiliPlus', - theme: Utils.getThemeData( + theme: ThemeUtils.getThemeData( colorScheme: lightColorScheme, isDynamic: lightDynamic != null && isDynamicColor, variant: variant, ), - darkTheme: Utils.getThemeData( + darkTheme: ThemeUtils.getThemeData( colorScheme: darkColorScheme, isDynamic: darkDynamic != null && isDynamicColor, isDark: true, diff --git a/lib/pages/about/index.dart b/lib/pages/about/index.dart index 9ffba5e8d..71de44a50 100644 --- a/lib/pages/about/index.dart +++ b/lib/pages/about/index.dart @@ -4,7 +4,8 @@ import 'dart:io'; import 'package:PiliPlus/build_config.dart'; import 'package:PiliPlus/services/loggeer.dart'; import 'package:PiliPlus/utils/accounts/account.dart'; -import 'package:PiliPlus/utils/login.dart'; +import 'package:PiliPlus/utils/login_utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -70,7 +71,7 @@ class _AboutPageState extends State { onSubmitted: (value) { Get.back(); if (value.isNotEmpty) { - Utils.handleWebview(value, inApp: true); + PageUtils.handleWebview(value, inApp: true); } }, ), @@ -132,7 +133,7 @@ Commit Hash: ${BuildConfig.commitHash}''', style: TextStyle(fontSize: 14), ), leading: const Icon(Icons.info_outline), - onTap: () => Utils.launchURL( + onTap: () => PageUtils.launchURL( 'https://github.com/bggRGjQaUbCoE/PiliPlus/commit/${BuildConfig.commitHash}'), onLongPress: () => Utils.copyText(BuildConfig.commitHash), ), @@ -165,13 +166,13 @@ Commit Hash: ${BuildConfig.commitHash}''', color: Theme.of(context).colorScheme.outlineVariant, ), ListTile( - onTap: () => Utils.launchURL(_sourceCodeUrl), + onTap: () => PageUtils.launchURL(_sourceCodeUrl), leading: const Icon(Icons.code), title: const Text('Source Code'), subtitle: Text(_sourceCodeUrl, style: subTitleStyle), ), ListTile( - onTap: () => Utils.launchURL(_originSourceCodeUrl), + onTap: () => PageUtils.launchURL(_originSourceCodeUrl), leading: const Icon(Icons.code), title: const Text('Origin'), subtitle: Text( @@ -180,7 +181,7 @@ Commit Hash: ${BuildConfig.commitHash}''', ), ), ListTile( - onTap: () => Utils.launchURL(_upstreamUrl), + onTap: () => PageUtils.launchURL(_upstreamUrl), leading: const Icon(Icons.code), title: const Text('Upstream'), subtitle: Text( @@ -212,7 +213,8 @@ Commit Hash: ${BuildConfig.commitHash}''', children: [ ListTile( title: const Text('GitHub Issue'), - onTap: () => Utils.launchURL('$_sourceCodeUrl/issues'), + onTap: () => + PageUtils.launchURL('$_sourceCodeUrl/issues'), ), ], ); diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index a0b102a87..be172827b 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -9,6 +9,7 @@ import 'package:PiliPlus/pages/video/detail/introduction/controller.dart'; import 'package:PiliPlus/pages/video/detail/introduction/pay_coins_page.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -281,7 +282,7 @@ class BangumiIntroController ), onTap: () { Get.back(); - Utils.launchURL(videoUrl); + PageUtils.launchURL(videoUrl); }, ), ListTile( @@ -582,10 +583,10 @@ class BangumiIntroController if (type == 'tap') { actionFavVideo(type: 'default'); } else { - Utils.showFavBottomSheet(context: context, ctr: this); + PageUtils.showFavBottomSheet(context: context, ctr: this); } } else if (type != 'longPress') { - Utils.showFavBottomSheet(context: context, ctr: this); + PageUtils.showFavBottomSheet(context: context, ctr: this); } } } diff --git a/lib/pages/bangumi/widgets/bangumi_card_v.dart b/lib/pages/bangumi/widgets/bangumi_card_v.dart index 27a144133..c139f445f 100644 --- a/lib/pages/bangumi/widgets/bangumi_card_v.dart +++ b/lib/pages/bangumi/widgets/bangumi_card_v.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; @@ -28,7 +29,7 @@ class BangumiCardV extends StatelessWidget { ), onTap: () async { final int seasonId = bangumiItem.seasonId; - Utils.viewBangumi(seasonId: seasonId); + PageUtils.viewBangumi(seasonId: seasonId); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/bangumi/widgets/bangumi_card_v_member_home.dart b/lib/pages/bangumi/widgets/bangumi_card_v_member_home.dart index 48ee4f826..1d36a6da1 100644 --- a/lib/pages/bangumi/widgets/bangumi_card_v_member_home.dart +++ b/lib/pages/bangumi/widgets/bangumi_card_v_member_home.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/models/space_archive/item.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/utils/utils.dart'; @@ -23,7 +24,7 @@ class BangumiCardVMemberHome extends StatelessWidget { child: InkWell( onTap: () async { final int seasonId = int.tryParse(bangumiItem.param ?? '') ?? -1; - Utils.viewBangumi(seasonId: seasonId); + PageUtils.viewBangumi(seasonId: seasonId); }, onLongPress: () => imageSaveDialog( context: context, diff --git a/lib/pages/bangumi/widgets/bangumi_card_v_pgc_index.dart b/lib/pages/bangumi/widgets/bangumi_card_v_pgc_index.dart index 9b6767c29..dcfbb613a 100644 --- a/lib/pages/bangumi/widgets/bangumi_card_v_pgc_index.dart +++ b/lib/pages/bangumi/widgets/bangumi_card_v_pgc_index.dart @@ -1,8 +1,8 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; -import 'package:PiliPlus/utils/utils.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; // 视频卡片 - 垂直布局 @@ -26,7 +26,7 @@ class BangumiCardVPgcIndex extends StatelessWidget { cover: bangumiItem['cover'], ), onTap: () { - Utils.viewBangumi(seasonId: bangumiItem['season_id']); + PageUtils.viewBangumi(seasonId: bangumiItem['season_id']); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/bangumi/widgets/bangumi_card_v_timeline.dart b/lib/pages/bangumi/widgets/bangumi_card_v_timeline.dart index 339e70c8c..8d1f338a0 100644 --- a/lib/pages/bangumi/widgets/bangumi_card_v_timeline.dart +++ b/lib/pages/bangumi/widgets/bangumi_card_v_timeline.dart @@ -1,9 +1,9 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/models/bangumi/pgc_timeline/episode.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; -import 'package:PiliPlus/utils/utils.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; // 视频卡片 - 垂直布局 @@ -27,10 +27,7 @@ class BangumiCardVTimeline extends StatelessWidget { cover: item.cover, ), onTap: () async { - Utils.viewBangumi( - seasonId: item.seasonId, - epId: item.episodeId, - ); + PageUtils.viewBangumi(seasonId: item.seasonId, epId: item.episodeId); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/pages/common/reply_controller.dart b/lib/pages/common/reply_controller.dart index 1f5f51811..7a916d2bf 100644 --- a/lib/pages/common/reply_controller.dart +++ b/lib/pages/common/reply_controller.dart @@ -10,6 +10,7 @@ import 'package:PiliPlus/pages/common/common_list_controller.dart'; import 'package:PiliPlus/pages/video/detail/reply_new/reply_page.dart'; import 'package:PiliPlus/utils/accounts/account.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; @@ -170,7 +171,7 @@ abstract class ReplyController extends CommonListController { (res) { if (res != null) { savedReplies[key] = null; - ReplyInfo replyInfo = Utils.replyCast(res); + ReplyInfo replyInfo = RequestUtils.replyCast(res); if (loadingState.value is Success) { List? list = (loadingState.value as Success).response; if (list == null) { diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart index ccafab49a..5ea632db8 100644 --- a/lib/pages/danmaku/view.dart +++ b/lib/pages/danmaku/view.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/pages/danmaku/index.dart'; import 'package:PiliPlus/plugin/pl_player/index.dart'; -import 'package:PiliPlus/utils/danmaku.dart'; +import 'package:PiliPlus/utils/danmaku_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; /// 传入播放器控制器,监听播放进度,加载对应弹幕 diff --git a/lib/pages/dynamics/create_dyn_panel.dart b/lib/pages/dynamics/create_dyn_panel.dart index e07180277..0d24326ed 100644 --- a/lib/pages/dynamics/create_dyn_panel.dart +++ b/lib/pages/dynamics/create_dyn_panel.dart @@ -4,8 +4,8 @@ import 'package:PiliPlus/pages/dynamics/view.dart'; import 'package:PiliPlus/pages/emote/controller.dart'; import 'package:PiliPlus/pages/emote/view.dart'; import 'package:PiliPlus/pages/video/detail/reply_new/toolbar_icon_button.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; -import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -488,8 +488,8 @@ class _CreateDynPanelState extends CommonPublishPageState { if (result['status']) { Get.back(); SmartDialog.showToast('发布成功'); - Utils.insertCreatedDyn(result); - Utils.checkCreatedDyn( + RequestUtils.insertCreatedDyn(result); + RequestUtils.checkCreatedDyn( id: result['data']?['dyn_id'], dynText: editController.text, ); diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index d8684d1ba..5a8d18320 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -9,6 +9,8 @@ import 'package:PiliPlus/models/common/reply_sort_type.dart'; import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart'; import 'package:PiliPlus/pages/video/detail/reply/widgets/reply_item_grpc.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:easy_debounce/easy_throttle.dart'; @@ -69,7 +71,7 @@ class _DynamicDetailPageState extends State vsync: this, duration: const Duration(milliseconds: 200), )..forward(); - Utils.onHorizontalPreview( + PageUtils.onHorizontalPreview( _key, AnimationController( vsync: this, @@ -618,7 +620,8 @@ class _DynamicDetailPageState extends State Expanded( child: Builder( builder: (context) => TextButton.icon( - onPressed: () => Utils.onLikeDynamic( + onPressed: () => + RequestUtils.onLikeDynamic( _dynamicDetailController.item, () { if (context.mounted) { diff --git a/lib/pages/dynamics/repost_dyn_panel.dart b/lib/pages/dynamics/repost_dyn_panel.dart index 8d000c2c3..346860fcc 100644 --- a/lib/pages/dynamics/repost_dyn_panel.dart +++ b/lib/pages/dynamics/repost_dyn_panel.dart @@ -6,8 +6,8 @@ import 'package:PiliPlus/pages/emote/controller.dart'; import 'package:PiliPlus/pages/emote/view.dart'; import 'package:PiliPlus/pages/video/detail/reply_new/toolbar_icon_button.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; -import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -386,8 +386,8 @@ class _RepostPanelState extends CommonPublishPageState { Get.back(); SmartDialog.showToast('转发成功'); widget.callback?.call(); - Utils.insertCreatedDyn(result); - Utils.checkCreatedDyn( + RequestUtils.insertCreatedDyn(result); + RequestUtils.checkCreatedDyn( id: result['data']?['dyn_id'], dynText: editController.text, ); diff --git a/lib/pages/dynamics/widgets/action_panel.dart b/lib/pages/dynamics/widgets/action_panel.dart index d7b6b50d1..e19ea19c3 100644 --- a/lib/pages/dynamics/widgets/action_panel.dart +++ b/lib/pages/dynamics/widgets/action_panel.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -110,7 +111,7 @@ class _ActionPanelState extends State { flex: 1, child: TextButton.icon( onPressed: () => - Utils.pushDynDetail(widget.item, 1, action: 'comment'), + PageUtils.pushDynDetail(widget.item, 1, action: 'comment'), icon: Icon( FontAwesomeIcons.comment, size: 16, diff --git a/lib/pages/dynamics/widgets/additional_panel.dart b/lib/pages/dynamics/widgets/additional_panel.dart index 318941d4d..9c7147b8c 100644 --- a/lib/pages/dynamics/widgets/additional_panel.dart +++ b/lib/pages/dynamics/widgets/additional_panel.dart @@ -1,3 +1,4 @@ +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -34,7 +35,7 @@ Widget addWidget(item, context, type, {floor = 1}) { String cover = dynamicProperty[type].cover; try { int cid = await SearchHttp.ab2c(bvid: bvid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'pic': cover, diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index 9643a3b3b..c7abac6aa 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -5,6 +5,7 @@ import 'package:PiliPlus/common/widgets/save_panel.dart'; import 'package:PiliPlus/http/index.dart'; import 'package:PiliPlus/http/video.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:dio/dio.dart'; @@ -343,7 +344,7 @@ class AuthorPanel extends StatelessWidget { ListTile( onTap: () { Get.back(); - Utils.checkCreatedDyn(id: item.idStr, isManual: true); + RequestUtils.checkCreatedDyn(id: item.idStr, isManual: true); }, minLeadingWidth: 0, leading: Stack( diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index a4b594047..cf82019f1 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -1,6 +1,6 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/utils/extension.dart'; -import 'package:PiliPlus/utils/utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -64,7 +64,7 @@ class DynamicPanel extends StatelessWidget { 'DYNAMIC_TYPE_MEDIALIST', ].contains(item.type).not ? null - : () => Utils.pushDynDetail(item, 1), + : () => PageUtils.pushDynDetail(item, 1), onLongPress: () { if (item.type == 'DYNAMIC_TYPE_AV') { imageSaveDialog( diff --git a/lib/pages/dynamics/widgets/forward_panel.dart b/lib/pages/dynamics/widgets/forward_panel.dart index 9431a3c8c..6756f88ae 100644 --- a/lib/pages/dynamics/widgets/forward_panel.dart +++ b/lib/pages/dynamics/widgets/forward_panel.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/common/widgets/image_view.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; @@ -218,7 +219,7 @@ Widget forWard(bool isSave, item, BuildContext context, source, callback, 'MAJOR_TYPE_NONE') { return; } - Utils.pushDynDetail(item.orig, floor + 1); + PageUtils.pushDynDetail(item.orig, floor + 1); }, onLongPress: () { if (item.orig.modules.moduleDynamic.major?.type == @@ -365,10 +366,10 @@ Widget forWard(bool isSave, item, BuildContext context, source, callback, onTap: () { try { String url = item.modules.moduleDynamic.major.common['jump_url']; - if (url.contains('bangumi/play') && Utils.viewPgcFromUri(url)) { + if (url.contains('bangumi/play') && PageUtils.viewPgcFromUri(url)) { return; } - Utils.handleWebview(url, inApp: true); + PageUtils.handleWebview(url, inApp: true); } catch (_) {} }, child: Container( @@ -420,7 +421,7 @@ Widget forWard(bool isSave, item, BuildContext context, source, callback, final Map music = item.modules.moduleDynamic.major.music; return InkWell( onTap: () { - Utils.handleWebview("https:${music['jump_url']}"); + PageUtils.handleWebview("https:${music['jump_url']}"); }, child: Container( width: double.infinity, diff --git a/lib/pages/dynamics/widgets/live_rcmd_panel.dart b/lib/pages/dynamics/widgets/live_rcmd_panel.dart index 9d57b0488..2de870b71 100644 --- a/lib/pages/dynamics/widgets/live_rcmd_panel.dart +++ b/lib/pages/dynamics/widgets/live_rcmd_panel.dart @@ -1,3 +1,4 @@ +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/common/constants.dart'; @@ -63,7 +64,7 @@ Widget liveRcmdPanel(source, item, context, {floor = 1}) { const EdgeInsets.symmetric(horizontal: StyleString.safeSpace), child: GestureDetector( onTap: () { - Utils.pushDynDetail(item, floor); + PageUtils.pushDynDetail(item, floor); }, child: LayoutBuilder(builder: (context, box) { double width = box.maxWidth; diff --git a/lib/pages/dynamics/widgets/rich_node_panel.dart b/lib/pages/dynamics/widgets/rich_node_panel.dart index fbd956d5d..ef6acd2c8 100644 --- a/lib/pages/dynamics/widgets/rich_node_panel.dart +++ b/lib/pages/dynamics/widgets/rich_node_panel.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/image_view.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -108,7 +109,7 @@ InlineSpan? richNode(item, BuildContext context) { PiliScheme.routePushFromUrl('https:$url'); return; } - Utils.handleWebview( + PageUtils.handleWebview( url.startsWith('//') ? "https://$url" : url, ); }, @@ -239,7 +240,7 @@ InlineSpan? richNode(item, BuildContext context) { onTap: () async { try { int cid = await SearchHttp.ab2c(bvid: i.rid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${i.rid}&cid=$cid', arguments: { 'pic': null, diff --git a/lib/pages/fav/article/widget/item.dart b/lib/pages/fav/article/widget/item.dart index 932e0bde1..6626ef6ff 100644 --- a/lib/pages/fav/article/widget/item.dart +++ b/lib/pages/fav/article/widget/item.dart @@ -114,11 +114,11 @@ class FavArticleItem extends StatelessWidget { right: 12, bottom: 0, child: iconButton( - iconSize: 22, + iconSize: 18, context: context, onPressed: onDelete, icon: Icons.clear, - iconColor: Theme.of(context).colorScheme.onSurfaceVariant, + iconColor: Theme.of(context).colorScheme.outline, bgColor: Colors.transparent, ), ), diff --git a/lib/pages/fav/note/widget/item.dart b/lib/pages/fav/note/widget/item.dart index 956f8ce56..848572b47 100644 --- a/lib/pages/fav/note/widget/item.dart +++ b/lib/pages/fav/note/widget/item.dart @@ -2,7 +2,7 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; import 'package:PiliPlus/models/member/article.dart'; import 'package:PiliPlus/pages/fav/note/controller.dart'; -import 'package:PiliPlus/utils/utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; class FavNoteItem extends StatelessWidget { @@ -28,7 +28,7 @@ class FavNoteItem extends StatelessWidget { return; } if (item.webUrl?.isNotEmpty == true) { - Utils.handleWebview( + PageUtils.handleWebview( item.webUrl!, inApp: true, ); diff --git a/lib/pages/fav/pgc/widget/item.dart b/lib/pages/fav/pgc/widget/item.dart index 0acbc1a6f..b3a4434b8 100644 --- a/lib/pages/fav/pgc/widget/item.dart +++ b/lib/pages/fav/pgc/widget/item.dart @@ -4,7 +4,7 @@ import 'package:PiliPlus/common/widgets/icon_button.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; import 'package:PiliPlus/models/bangumi/list.dart'; import 'package:PiliPlus/pages/common/multi_select_controller.dart'; -import 'package:PiliPlus/utils/utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; class FavPgcItem extends StatelessWidget { @@ -34,7 +34,7 @@ class FavPgcItem extends StatelessWidget { onSelect(); return; } - Utils.viewBangumi(seasonId: item.seasonId); + PageUtils.viewBangumi(seasonId: item.seasonId); }, onLongPress: () { if (!ctr.enableMultiSelect.value) { @@ -179,11 +179,11 @@ class FavPgcItem extends StatelessWidget { right: 12, bottom: 0, child: iconButton( - iconSize: 20, + iconSize: 18, context: context, onPressed: onUpdateStatus, icon: Icons.more_vert, - iconColor: Theme.of(context).colorScheme.onSurfaceVariant, + iconColor: Theme.of(context).colorScheme.outline, bgColor: Colors.transparent, ), ), diff --git a/lib/pages/fav/video/widgets/item.dart b/lib/pages/fav/video/widgets/item.dart index a093792a7..977f53ea0 100644 --- a/lib/pages/fav/video/widgets/item.dart +++ b/lib/pages/fav/video/widgets/item.dart @@ -32,39 +32,30 @@ class FavItem extends StatelessWidget { )), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), - child: LayoutBuilder( - builder: (context, boxConstraints) { - double width = - (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; - return SizedBox( - height: width / StyleString.aspectRatio, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Hero( - tag: heroTag, - child: NetworkImgLayer( - src: favFolderItem.cover, - width: maxWidth, - height: maxHeight, - ), - ); - }, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Hero( + tag: heroTag, + child: NetworkImgLayer( + src: favFolderItem.cover, + width: maxWidth, + height: maxHeight, ), - ), - const SizedBox(width: 10), - videoContent(context), - ], + ); + }, ), - ); - }, + ), + const SizedBox(width: 10), + videoContent(context), + ], ), ), ); @@ -99,7 +90,7 @@ class FavItem extends StatelessWidget { ), const Spacer(), Text( - Utils.isPublicText(favFolderItem.attr ?? 0), + Utils.isPublicFavText(favFolderItem.attr ?? 0), style: TextStyle( fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, color: Theme.of(context).colorScheme.outline, diff --git a/lib/pages/fav_detail/controller.dart b/lib/pages/fav_detail/controller.dart index 5f39d31e0..3447468f4 100644 --- a/lib/pages/fav_detail/controller.dart +++ b/lib/pages/fav_detail/controller.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/models/user/fav_detail.dart'; import 'package:PiliPlus/models/user/fav_folder.dart'; import 'package:PiliPlus/pages/common/multi_select_controller.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -153,7 +154,7 @@ class FavDetailController if (element.bvid != list.first.bvid) { SmartDialog.showToast('已跳过不支持播放的视频'); } - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${element.bvid}&cid=${element.cid}', arguments: { 'videoItem': element, diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index 6d25ce825..f42e746f0 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -7,6 +7,8 @@ import 'package:PiliPlus/models/user/fav_folder.dart'; import 'package:PiliPlus/pages/fav_detail/fav_sort_page.dart'; import 'package:PiliPlus/pages/fav_search/view.dart' show SearchType; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -136,7 +138,7 @@ class _FavDetailPageState extends State { VisualDensity(horizontal: -2, vertical: -2), ), onPressed: () { - Utils.onCopyOrMove( context: context, isCopy: true, @@ -160,7 +162,7 @@ class _FavDetailPageState extends State { VisualDensity(horizontal: -2, vertical: -2), ), onPressed: () { - Utils.onCopyOrMove( context: context, isCopy: false, @@ -279,9 +281,10 @@ class _FavDetailPageState extends State { }, child: Text('排序'), ), - if (!Utils.isDefault(_favDetailController - .item.value.attr ?? - 0)) + if (!Utils.isDefaultFav( + _favDetailController + .item.value.attr ?? + 0)) PopupMenuItem( onTap: () { showConfirmDialog( @@ -397,7 +400,7 @@ class _FavDetailPageState extends State { .item.value.attr != null) Text( - '共${_favDetailController.item.value.mediaCount}条视频 · ${Utils.isPublicText(_favDetailController.item.value.attr ?? 0)}', + '共${_favDetailController.item.value.mediaCount}条视频 · ${Utils.isPublicFavText(_favDetailController.item.value.attr ?? 0)}', style: TextStyle( fontSize: Theme.of(context) .textTheme @@ -430,7 +433,7 @@ class _FavDetailPageState extends State { Widget _buildBody(LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { return const VideoCardHSkeleton(); @@ -444,7 +447,7 @@ class _FavDetailPageState extends State { bottom: MediaQuery.of(context).padding.bottom + 85, ), sliver: SliverGrid( - gridDelegate: Grid.videoCardHDelegate(context, minHeight: 110), + gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate( (context, index) { if (index == loadingState.response!.length) { @@ -475,7 +478,7 @@ class _FavDetailPageState extends State { ) : null, onViewFav: () { - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${item.bvid}&cid=${item.cid}', arguments: { 'videoItem': item, diff --git a/lib/pages/fav_detail/widget/fav_video_card.dart b/lib/pages/fav_detail/widget/fav_video_card.dart index 8ac32369c..e28b59d84 100644 --- a/lib/pages/fav_detail/widget/fav_video_card.dart +++ b/lib/pages/fav_detail/widget/fav_video_card.dart @@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/common/widgets/stat/stat.dart'; import 'package:PiliPlus/models/user/fav_detail.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; @@ -50,7 +51,7 @@ class FavVideoCardH extends StatelessWidget { videoItem.cid = await SearchHttp.ab2c(bvid: bvid); dynamic seasonId = videoItem.ogv!['season_id']; epId = videoItem.epId; - Utils.viewBangumi(seasonId: seasonId, epId: epId); + PageUtils.viewBangumi(seasonId: seasonId, epId: epId); return; } else if (videoItem.page == 0 || videoItem.page! > 1) { var result = await VideoHttp.videoIntro(bvid: bvid); @@ -85,53 +86,44 @@ class FavVideoCardH extends StatelessWidget { horizontal: StyleString.safeSpace, vertical: 5, ), - child: LayoutBuilder( - builder: (context, boxConstraints) { - double width = - (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; - return SizedBox( - height: width / StyleString.aspectRatio, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Stack( - children: [ - NetworkImgLayer( - src: videoItem.pic, - width: maxWidth, - height: maxHeight, - ), - PBadge( - text: Utils.timeFormat(videoItem.duration), - right: 6.0, - bottom: 6.0, - type: 'gray', - ), - PBadge( - text: videoItem.ogv?['type_name'], - top: 6.0, - right: 6.0, - bottom: null, - left: null, - ), - ], - ); - }, - ), - ), - const SizedBox(width: 10), - videoContent(context), - ], + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Stack( + children: [ + NetworkImgLayer( + src: videoItem.pic, + width: maxWidth, + height: maxHeight, + ), + PBadge( + text: Utils.timeFormat(videoItem.duration), + right: 6.0, + bottom: 6.0, + type: 'gray', + ), + PBadge( + text: videoItem.ogv?['type_name'], + top: 6.0, + right: 6.0, + bottom: null, + left: null, + ), + ], + ); + }, ), - ); - }, + ), + const SizedBox(width: 10), + videoContent(context), + ], ), ), ); @@ -144,55 +136,43 @@ class FavVideoCardH extends StatelessWidget { Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - videoItem.title, - textAlign: TextAlign.start, - style: const TextStyle( - letterSpacing: 0.3, + Expanded( + child: Text( + videoItem.title, + textAlign: TextAlign.start, + style: const TextStyle( + letterSpacing: 0.3, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - maxLines: 2, + ), + Text( + '${Utils.dateFormat(videoItem.favTime)} ${videoItem.owner.name}', + maxLines: 1, overflow: TextOverflow.ellipsis, - ), - if (videoItem.ogv != null) - Text( - videoItem.desc!, - style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - color: Theme.of(context).colorScheme.outline, - ), - ), - const Spacer(), - Text( - Utils.dateFormat(videoItem.favTime), style: TextStyle( - fontSize: 11, color: Theme.of(context).colorScheme.outline), + height: 1, + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), ), - if (!videoItem.owner.name.isNullOrEmpty) - Text( - videoItem.owner.name!, - style: TextStyle( - fontSize: 12, - color: Theme.of(context).colorScheme.outline, + const SizedBox(height: 3), + Row( + children: [ + StatView( + context: context, + theme: 'gray', + value: videoItem.stat.viewStr, ), - ), - Padding( - padding: const EdgeInsets.only(top: 2), - child: Row( - children: [ - StatView( - context: context, - theme: 'gray', - value: videoItem.stat.viewStr, - ), - const SizedBox(width: 8), - StatDanMu( - context: context, - theme: 'gray', - value: videoItem.stat.danmuStr, - ), - const Spacer(), - ], - ), + const SizedBox(width: 8), + StatDanMu( + context: context, + theme: 'gray', + value: videoItem.stat.danmuStr, + ), + const Spacer(), + ], ), ], ), @@ -204,7 +184,7 @@ class FavVideoCardH extends StatelessWidget { context: context, icon: Icons.clear, tooltip: '取消收藏', - iconColor: Theme.of(context).colorScheme.onSurfaceVariant, + iconColor: Theme.of(context).colorScheme.outline, bgColor: Colors.transparent, onPressed: () { showDialog( diff --git a/lib/pages/fav_search/view.dart b/lib/pages/fav_search/view.dart index f91e91cb1..9cd89a099 100644 --- a/lib/pages/fav_search/view.dart +++ b/lib/pages/fav_search/view.dart @@ -6,6 +6,7 @@ import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/pages/follow/widgets/follow_item.dart'; import 'package:PiliPlus/pages/history/widgets/item.dart'; import 'package:PiliPlus/utils/grid.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -107,7 +108,7 @@ class _FavSearchPageState extends State { } : null, onViewFav: () { - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${item.bvid}&cid=${item.cid}', arguments: { 'videoItem': item, @@ -144,7 +145,7 @@ class _FavSearchPageState extends State { videoItem: item, source: 'later', onViewLater: (cid) { - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${item.bvid}&cid=$cid', arguments: { 'videoItem': item, diff --git a/lib/pages/follow/widgets/follow_item.dart b/lib/pages/follow/widgets/follow_item.dart index defacd831..a5beca124 100644 --- a/lib/pages/follow/widgets/follow_item.dart +++ b/lib/pages/follow/widgets/follow_item.dart @@ -1,3 +1,4 @@ +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; @@ -77,7 +78,7 @@ class FollowItem extends StatelessWidget { height: 34, child: FilledButton.tonal( onPressed: () { - Utils.actionRelationMod( + RequestUtils.actionRelationMod( context: context, mid: item.mid, isFollow: item.attribute != -1, diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index 9988cf287..08644cc32 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -5,6 +5,7 @@ import 'package:PiliPlus/pages/common/multi_select_controller.dart'; import 'package:PiliPlus/pages/fav_search/controller.dart'; import 'package:PiliPlus/pages/history/base_controller.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -47,7 +48,7 @@ class HistoryItem extends StatelessWidget { return; } if (videoItem.history.business?.contains('article') == true) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/htmlRender', parameters: { 'url': 'https://www.bilibili.com/read/cv${videoItem.history.oid}', @@ -71,11 +72,11 @@ class HistoryItem extends StatelessWidget { String bvid = result['data'].bvid!; var epid = result['data'].epId; if (epid != null) { - Utils.viewBangumi(epId: epid); + PageUtils.viewBangumi(epId: epid); } else { int cid = videoItem.history.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'heroTag': Utils.makeHeroTag(cid), @@ -88,13 +89,13 @@ class HistoryItem extends StatelessWidget { } } else { if (videoItem.history.epid != null && videoItem.history.epid != 0) { - Utils.viewBangumi(epId: videoItem.history.epid); + PageUtils.viewBangumi(epId: videoItem.history.epid); } } } else { int cid = videoItem.history.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'heroTag': Utils.makeHeroTag(aid), @@ -124,132 +125,121 @@ class HistoryItem extends StatelessWidget { horizontal: StyleString.safeSpace, vertical: 5, ), - child: LayoutBuilder( - builder: (context, boxConstraints) { - double width = - (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; - return SizedBox( - height: width / StyleString.aspectRatio, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack( - clipBehavior: Clip.none, - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - src: (videoItem.cover.isNullOrEmpty - ? videoItem.covers?.firstOrNull ?? '' - : videoItem.cover), - width: maxWidth, - height: maxHeight, - ), - if (!BusinessType - .hiddenDurationType.hiddenDurationType - .contains(videoItem.history.business)) - PBadge( - text: videoItem.progress == -1 - ? '已看完' - : '${Utils.timeFormat(videoItem.progress)}/${Utils.timeFormat(videoItem.duration!)}', - right: 6.0, - bottom: 8.0, - type: 'gray', - ), - // 右上角 - if (BusinessType.showBadge.showBadge - .contains( - videoItem.history.business) || - videoItem.history.business == - BusinessType.live.type) - PBadge( - text: videoItem.badge, - top: 6.0, - right: 6.0, - bottom: null, - left: null, - ), - ], - ); - }, - ), - ), - Positioned.fill( - child: AnimatedOpacity( - opacity: videoItem.checked == true ? 1 : 0, - duration: const Duration(milliseconds: 200), - child: Container( - alignment: Alignment.center, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.black.withOpacity(0.6), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + clipBehavior: Clip.none, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + src: (videoItem.cover.isNullOrEmpty + ? videoItem.covers?.firstOrNull ?? '' + : videoItem.cover), + width: maxWidth, + height: maxHeight, + ), + if (!BusinessType + .hiddenDurationType.hiddenDurationType + .contains(videoItem.history.business)) + PBadge( + text: videoItem.progress == -1 + ? '已看完' + : '${Utils.timeFormat(videoItem.progress)}/${Utils.timeFormat(videoItem.duration!)}', + right: 6.0, + bottom: 8.0, + type: 'gray', ), - child: SizedBox( - width: 34, - height: 34, - child: AnimatedScale( - scale: videoItem.checked == true ? 1 : 0, - duration: const Duration(milliseconds: 250), - curve: Curves.easeInOut, - child: IconButton( - tooltip: '取消选择', - style: ButtonStyle( - padding: WidgetStateProperty.all( - EdgeInsets.zero), - backgroundColor: - WidgetStateProperty.resolveWith( - (states) { - return Theme.of(context) - .colorScheme - .surface - .withOpacity(0.8); - }, - ), - ), - onPressed: () { - feedBack(); - onChoose?.call(); - }, - icon: Icon(Icons.done_all_outlined, - color: Theme.of(context) - .colorScheme - .primary), - ), + // 右上角 + if (BusinessType.showBadge.showBadge + .contains(videoItem.history.business) || + videoItem.history.business == + BusinessType.live.type) + PBadge( + text: videoItem.badge, + top: 6.0, + right: 6.0, + bottom: null, + left: null, + ), + ], + ); + }, + ), + ), + Positioned.fill( + child: AnimatedOpacity( + opacity: videoItem.checked == true ? 1 : 0, + duration: const Duration(milliseconds: 200), + child: Container( + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + color: Colors.black.withOpacity(0.6), + ), + child: SizedBox( + width: 34, + height: 34, + child: AnimatedScale( + scale: videoItem.checked == true ? 1 : 0, + duration: const Duration(milliseconds: 250), + curve: Curves.easeInOut, + child: IconButton( + tooltip: '取消选择', + style: ButtonStyle( + padding: + WidgetStateProperty.all(EdgeInsets.zero), + backgroundColor: + WidgetStateProperty.resolveWith( + (states) { + return Theme.of(context) + .colorScheme + .surface + .withOpacity(0.8); + }, ), ), + onPressed: () { + feedBack(); + onChoose?.call(); + }, + icon: Icon(Icons.done_all_outlined, + color: + Theme.of(context).colorScheme.primary), ), ), ), - if (videoItem.duration != null && - videoItem.duration != 0 && - videoItem.progress != null && - videoItem.progress != 0) - Positioned( - left: 0, - right: 0, - bottom: 0, - child: videoProgressIndicator( - videoItem.progress == -1 - ? 1 - : videoItem.progress! / videoItem.duration!, - ), - ), - ], + ), ), - const SizedBox(width: 10), - videoContent(context), - ], - ), - ); - }, + ), + if (videoItem.duration != null && + videoItem.duration != 0 && + videoItem.progress != null && + videoItem.progress != 0) + Positioned( + left: 0, + right: 0, + bottom: 0, + child: videoProgressIndicator( + videoItem.progress == -1 + ? 1 + : videoItem.progress! / videoItem.duration!, + ), + ), + ], + ), + const SizedBox(width: 10), + videoContent(context), + ], ), ), Positioned( diff --git a/lib/pages/html/view.dart b/lib/pages/html/view.dart index 4773aab1a..0baf5234c 100644 --- a/lib/pages/html/view.dart +++ b/lib/pages/html/view.dart @@ -10,6 +10,8 @@ import 'package:PiliPlus/models/common/reply_sort_type.dart'; import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart'; import 'package:PiliPlus/pages/video/detail/reply/widgets/reply_item_grpc.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:easy_debounce/easy_throttle.dart'; @@ -68,7 +70,7 @@ class _HtmlRenderPageState extends State vsync: this, duration: const Duration(milliseconds: 200), )..forward(); - Utils.onHorizontalPreview( + PageUtils.onHorizontalPreview( _key, AnimationController( vsync: this, @@ -283,7 +285,8 @@ class _HtmlRenderPageState extends State IconButton( tooltip: '浏览器打开', onPressed: () { - Utils.inAppWebview(url.startsWith('http') ? url : 'https:$url'); + PageUtils.inAppWebview( + url.startsWith('http') ? url : 'https:$url'); }, icon: const Icon(Icons.open_in_browser_outlined, size: 19), ), @@ -305,7 +308,7 @@ class _HtmlRenderPageState extends State ), PopupMenuItem( onTap: () { - Utils.inAppWebview( + PageUtils.inAppWebview( url.startsWith('http') ? url : 'https:$url'); }, child: const Row( @@ -640,7 +643,7 @@ class _HtmlRenderPageState extends State builder: (context) => TextButton.icon( onPressed: () => - Utils.onLikeDynamic( + RequestUtils.onLikeDynamic( _htmlRenderCtr.item.value, () { if (context.mounted) { diff --git a/lib/pages/later/child_view.dart b/lib/pages/later/child_view.dart index bb8964a35..9c1f3197d 100644 --- a/lib/pages/later/child_view.dart +++ b/lib/pages/later/child_view.dart @@ -11,6 +11,7 @@ import 'package:PiliPlus/pages/later/view.dart' show LaterViewType, LaterViewTypeExt; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/grid.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -85,7 +86,7 @@ class _LaterViewChildPageState extends State videoItem: videoItem, source: 'later', onViewLater: (cid) { - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${videoItem.bvid}&cid=$cid', arguments: { 'videoItem': videoItem, @@ -185,8 +186,7 @@ class _LaterViewChildPageState extends State ); }, icon: Icons.clear, - iconColor: - Theme.of(context).colorScheme.onSurfaceVariant, + iconColor: Theme.of(context).colorScheme.outline, bgColor: Colors.transparent, ), ), diff --git a/lib/pages/later/controller.dart b/lib/pages/later/controller.dart index 487eda33c..ef64b8e2d 100644 --- a/lib/pages/later/controller.dart +++ b/lib/pages/later/controller.dart @@ -6,6 +6,7 @@ import 'package:PiliPlus/pages/later/base_controller.dart'; import 'package:PiliPlus/pages/later/view.dart' show LaterViewType, LaterViewTypeExt; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -216,7 +217,7 @@ class LaterController extends MultiSelectController { if (item.bvid != list.first.bvid) { SmartDialog.showToast('已跳过不支持播放的视频'); } - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${item.bvid}&cid=${item.cid}', arguments: { 'videoItem': item, diff --git a/lib/pages/later/view.dart b/lib/pages/later/view.dart index 3f95dd4fd..9dfecd6d2 100644 --- a/lib/pages/later/view.dart +++ b/lib/pages/later/view.dart @@ -7,8 +7,8 @@ import 'package:PiliPlus/pages/later/base_controller.dart'; import 'package:PiliPlus/pages/later/child_view.dart'; import 'package:PiliPlus/pages/later/controller.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; -import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; @@ -271,7 +271,7 @@ class _LaterPageState extends State ), onPressed: () { final ctr = currCtr(); - Utils.onCopyOrMove( + RequestUtils.onCopyOrMove( context: context, isCopy: true, ctr: ctr, @@ -292,7 +292,7 @@ class _LaterPageState extends State ), onPressed: () { final ctr = currCtr(); - Utils.onCopyOrMove( + RequestUtils.onCopyOrMove( context: context, isCopy: false, ctr: ctr, diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index 3882db716..8282d6f76 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -6,7 +6,7 @@ import 'package:PiliPlus/models/live/quality.dart'; import 'package:PiliPlus/pages/mine/controller.dart'; import 'package:PiliPlus/services/service_locator.dart'; import 'package:PiliPlus/tcp/live.dart'; -import 'package:PiliPlus/utils/danmaku.dart'; +import 'package:PiliPlus/utils/danmaku_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index 73d90691d..70c8e8b33 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -7,6 +7,7 @@ import 'package:PiliPlus/pages/live_room/widgets/chat.dart'; import 'package:PiliPlus/pages/live_room/widgets/header_control.dart'; import 'package:PiliPlus/services/service_locator.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; @@ -436,7 +437,7 @@ class _LiveRoomPageState extends State IconButton( tooltip: '浏览器打开', onPressed: () { - Utils.inAppWebview( + PageUtils.inAppWebview( 'https://live.bilibili.com/h5/${_liveRoomController.roomId}', off: true, ); diff --git a/lib/pages/live_room/widgets/header_control.dart b/lib/pages/live_room/widgets/header_control.dart index 8158b5cbc..af22a4fcb 100644 --- a/lib/pages/live_room/widgets/header_control.dart +++ b/lib/pages/live_room/widgets/header_control.dart @@ -1,6 +1,6 @@ import 'dart:io'; -import 'package:PiliPlus/utils/utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; import 'package:PiliPlus/plugin/pl_player/index.dart'; @@ -89,7 +89,7 @@ class LiveHeaderControl extends StatelessWidget implements PreferredSizeWidget { const SizedBox(width: 10), ], IconButton( - onPressed: () => Utils.scheduleExit( + onPressed: () => PageUtils.scheduleExit( context, plPlayerController.isFullScreen.value, true, diff --git a/lib/pages/media/view.dart b/lib/pages/media/view.dart index 04c2c27c1..6b2f8f34b 100644 --- a/lib/pages/media/view.dart +++ b/lib/pages/media/view.dart @@ -322,7 +322,7 @@ class FavFolderItem extends StatelessWidget { maxLines: 1, ), Text( - ' 共${item!.mediaCount}条视频 · ${Utils.isPublicText(item?.attr ?? 0)}', + ' 共${item!.mediaCount}条视频 · ${Utils.isPublicFavText(item?.attr ?? 0)}', style: Theme.of(context) .textTheme .labelSmall! diff --git a/lib/pages/member/content/member_contribute/content/favorite/widget/item.dart b/lib/pages/member/content/member_contribute/content/favorite/widget/item.dart index 28eb6e8ca..177e18375 100644 --- a/lib/pages/member/content/member_contribute/content/favorite/widget/item.dart +++ b/lib/pages/member/content/member_contribute/content/favorite/widget/item.dart @@ -128,7 +128,7 @@ class MemberFavItem extends StatelessWidget { const Spacer(), Text( item.type == 0 - ? '${item.mediaCount}个内容 · ${Utils.isPublicText(item.attr ?? 0)}' + ? '${item.mediaCount}个内容 · ${Utils.isPublicFavText(item.attr ?? 0)}' : item.type == 11 ? '${item.mediaCount}个内容 · ${item.upper?.name}' : item.type == 21 diff --git a/lib/pages/member/content/member_contribute/content/video/member_video_ctr.dart b/lib/pages/member/content/member_contribute/content/video/member_video_ctr.dart index 931c29bf8..f688e08ea 100644 --- a/lib/pages/member/content/member_contribute/content/video/member_video_ctr.dart +++ b/lib/pages/member/content/member_contribute/content/video/member_video_ctr.dart @@ -9,6 +9,7 @@ import 'package:PiliPlus/pages/member/content/member_contribute/member_contribut show ContributeType; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -148,7 +149,7 @@ class MemberVideoCtr extends CommonListController { ?.group(1); dynamic bvid = IdUtils.av2bv(int.tryParse(oid) ?? 0); dynamic cid = await SearchHttp.ab2c(aid: oid, bvid: bvid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'heroTag': Utils.makeHeroTag(oid), @@ -189,7 +190,7 @@ class MemberVideoCtr extends CommonListController { : sort.value == 'asc') ? desc.not : desc; - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${element.bvid}&cid=${element.cid}', arguments: { 'videoItem': element, diff --git a/lib/pages/member/controller.dart b/lib/pages/member/controller.dart index 6e95bbda8..0f38aa265 100644 --- a/lib/pages/member/controller.dart +++ b/lib/pages/member/controller.dart @@ -7,6 +7,7 @@ import 'package:PiliPlus/models/space/data.dart'; import 'package:PiliPlus/models/space/item.dart'; import 'package:PiliPlus/models/space/tab2.dart'; import 'package:PiliPlus/pages/common/common_data_controller.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -204,7 +205,7 @@ class MemberControllerNew extends CommonDataController SmartDialog.showToast('账号未登录'); return; } - Utils.actionRelationMod( + RequestUtils.actionRelationMod( context: context, mid: mid, isFollow: isFollow, diff --git a/lib/pages/member/widget/edit_profile_page.dart b/lib/pages/member/widget/edit_profile_page.dart index 30f0ad9f6..d1e300d2b 100644 --- a/lib/pages/member/widget/edit_profile_page.dart +++ b/lib/pages/member/widget/edit_profile_page.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/http/constants.dart'; import 'package:PiliPlus/http/index.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -177,7 +178,7 @@ class _EditProfilePageState extends State { _divider1, _item( title: '头像挂件', - onTap: () => Utils.launchURL( + onTap: () => PageUtils.launchURL( 'https://www.bilibili.com/h5/mall/pendant/home'), ), _divider1, @@ -200,7 +201,7 @@ class _EditProfilePageState extends State { _divider1, _item( title: '哔哩哔哩认证', - onTap: () => Utils.launchURL( + onTap: () => PageUtils.launchURL( 'https://account.bilibili.com/official/mobile/home'), ), _divider, diff --git a/lib/pages/member/widget/user_info_card.dart b/lib/pages/member/widget/user_info_card.dart index 0a0ea9ed5..1ebcfa242 100644 --- a/lib/pages/member/widget/user_info_card.dart +++ b/lib/pages/member/widget/user_info_card.dart @@ -5,6 +5,7 @@ import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/models/space/card.dart' as space; import 'package:PiliPlus/models/space/images.dart' as space; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -549,7 +550,7 @@ class UserInfoCard extends StatelessWidget { return GestureDetector( onTap: () { if (card.prInfo?.url?.isNotEmpty == true) { - Utils.handleWebview(card.prInfo!.url!); + PageUtils.handleWebview(card.prInfo!.url!); } }, child: Container( diff --git a/lib/pages/member_coin/widgets/item.dart b/lib/pages/member_coin/widgets/item.dart index 5b3f19eec..3555b188e 100644 --- a/lib/pages/member_coin/widgets/item.dart +++ b/lib/pages/member_coin/widgets/item.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/common/widgets/stat/stat.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; @@ -25,7 +26,7 @@ class MemberCoinsItem extends StatelessWidget { onTap: () async { int cid = await SearchHttp.ab2c(aid: coinItem.aid, bvid: coinItem.bvid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=${coinItem.bvid}&cid=$cid', arguments: { 'videoItem': coinItem, diff --git a/lib/pages/member_search/controller.dart b/lib/pages/member_search/controller.dart index e6ecc941e..cb530b03f 100644 --- a/lib/pages/member_search/controller.dart +++ b/lib/pages/member_search/controller.dart @@ -2,7 +2,7 @@ import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/models/member/archive.dart'; import 'package:PiliPlus/utils/extension.dart'; -import 'package:PiliPlus/utils/utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/http/member.dart'; @@ -39,7 +39,7 @@ class MemberSearchController extends GetxController super.onInit(); mid = int.parse(Get.parameters['mid']!); uname.value = Get.parameters['uname']!; - Utils.getWwebid(mid).then((res) { + RequestUtils.getWwebid(mid).then((res) { wwebid = res; }); } diff --git a/lib/pages/mine/controller.dart b/lib/pages/mine/controller.dart index 9254cf898..2d6d9334f 100644 --- a/lib/pages/mine/controller.dart +++ b/lib/pages/mine/controller.dart @@ -1,5 +1,5 @@ import 'package:PiliPlus/utils/accounts/account.dart'; -import 'package:PiliPlus/utils/login.dart'; +import 'package:PiliPlus/utils/login_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; diff --git a/lib/pages/msg_feed_top/sys_msg/view.dart b/lib/pages/msg_feed_top/sys_msg/view.dart index 62c580331..15342166d 100644 --- a/lib/pages/msg_feed_top/sys_msg/view.dart +++ b/lib/pages/msg_feed_top/sys_msg/view.dart @@ -7,6 +7,7 @@ import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/msg/msgfeed_sys_msg.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -197,7 +198,7 @@ class _SysMsgPageState extends State { recognizer: TapGestureRecognizer() ..onTap = () { try { - Utils.pushDynFromId(match[4]); + PageUtils.pushDynFromId(match[4]); } catch (err) { SmartDialog.showToast(err.toString()); } diff --git a/lib/pages/search_panel/widgets/media_bangumi_panel.dart b/lib/pages/search_panel/widgets/media_bangumi_panel.dart index 72d1ee577..4313316cf 100644 --- a/lib/pages/search_panel/widgets/media_bangumi_panel.dart +++ b/lib/pages/search_panel/widgets/media_bangumi_panel.dart @@ -1,6 +1,7 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; @@ -35,7 +36,7 @@ Widget searchBangumiPanel( var i = loadingState.response![index]; return InkWell( onTap: () { - Utils.viewBangumi(seasonId: i.seasonId); + PageUtils.viewBangumi(seasonId: i.seasonId); }, onLongPress: () => imageSaveDialog( context: context, diff --git a/lib/pages/setting/pages/logs.dart b/lib/pages/setting/pages/logs.dart index 0256cd1d6..5674a47f2 100644 --- a/lib/pages/setting/pages/logs.dart +++ b/lib/pages/setting/pages/logs.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import '../../../services/loggeer.dart'; @@ -116,7 +117,7 @@ class _LogsPageState extends State { copyLogs(); break; case 'feedback': - Utils.launchURL( + PageUtils.launchURL( 'https://github.com/bggRGjQaUbCoE/PiliPlus/issues'); break; case 'clear': diff --git a/lib/pages/setting/sponsor_block_page.dart b/lib/pages/setting/sponsor_block_page.dart index 047876a05..192b13584 100644 --- a/lib/pages/setting/sponsor_block_page.dart +++ b/lib/pages/setting/sponsor_block_page.dart @@ -6,6 +6,7 @@ import 'package:PiliPlus/http/index.dart'; import 'package:PiliPlus/models/common/sponsor_block/segment_type.dart'; import 'package:PiliPlus/models/common/sponsor_block/skip_type.dart'; import 'package:PiliPlus/pages/setting/slide_color_picker.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -135,7 +136,7 @@ class _SponsorBlockPageState extends State { dense: true, title: Text('关于空降助手', style: _titleStyle), subtitle: Text(_url, style: _subTitleStyle), - onTap: () => Utils.launchURL(_url), + onTap: () => PageUtils.launchURL(_url), ); Widget get _userIdItem => ListTile( diff --git a/lib/pages/setting/widgets/model.dart b/lib/pages/setting/widgets/model.dart index a58b78330..a7b3ce904 100644 --- a/lib/pages/setting/widgets/model.dart +++ b/lib/pages/setting/widgets/model.dart @@ -539,6 +539,7 @@ List get styleSettings => [ GStorage.setting.put(SettingBoxKey.themeMode, result.index); Get.put(ColorSelectController()).themeType.value = result; Get.changeThemeMode(result.toThemeMode); + setState(); } }, leading: const Icon(Icons.flashlight_on_outlined), diff --git a/lib/pages/subscription/widgets/item.dart b/lib/pages/subscription/widgets/item.dart index bbe69d889..8272f4036 100644 --- a/lib/pages/subscription/widgets/item.dart +++ b/lib/pages/subscription/widgets/item.dart @@ -35,39 +35,30 @@ class SubItem extends StatelessWidget { ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), - child: LayoutBuilder( - builder: (context, boxConstraints) { - double width = - (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; - return SizedBox( - height: width / StyleString.aspectRatio, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Hero( - tag: heroTag, - child: NetworkImgLayer( - src: subFolderItem.cover, - width: maxWidth, - height: maxHeight, - ), - ); - }, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Hero( + tag: heroTag, + child: NetworkImgLayer( + src: subFolderItem.cover, + width: maxWidth, + height: maxHeight, ), - ), - const SizedBox(width: 10), - videoContent(context), - ], + ); + }, ), - ); - }, + ), + const SizedBox(width: 10), + videoContent(context), + ], ), ), ); diff --git a/lib/pages/subscription_detail/widget/sub_video_card.dart b/lib/pages/subscription_detail/widget/sub_video_card.dart index c7f3b655a..2e1880a89 100644 --- a/lib/pages/subscription_detail/widget/sub_video_card.dart +++ b/lib/pages/subscription_detail/widget/sub_video_card.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/stat/stat.dart'; @@ -27,7 +28,7 @@ class SubVideoCardH extends StatelessWidget { return InkWell( onTap: () async { int cid = await SearchHttp.ab2c(bvid: bvid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'videoItem': videoItem, @@ -46,46 +47,37 @@ class SubVideoCardH extends StatelessWidget { horizontal: StyleString.safeSpace, vertical: 5, ), - child: LayoutBuilder( - builder: (context, boxConstraints) { - double width = - (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; - return SizedBox( - height: width / StyleString.aspectRatio, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (context, boxConstraints) { - double maxWidth = boxConstraints.maxWidth; - double maxHeight = boxConstraints.maxHeight; - return Stack( - children: [ - NetworkImgLayer( - src: videoItem.cover, - width: maxWidth, - height: maxHeight, - ), - PBadge( - text: Utils.timeFormat(videoItem.duration!), - right: 6.0, - bottom: 6.0, - type: 'gray', - ), - ], - ); - }, - ), - ), - const SizedBox(width: 10), - videoContent(context), - ], + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + return Stack( + children: [ + NetworkImgLayer( + src: videoItem.cover, + width: maxWidth, + height: maxHeight, + ), + PBadge( + text: Utils.timeFormat(videoItem.duration!), + right: 6.0, + bottom: 6.0, + type: 'gray', + ), + ], + ); + }, ), - ); - }, + ), + const SizedBox(width: 10), + videoContent(context), + ], ), ), ); @@ -116,24 +108,22 @@ class SubVideoCardH extends StatelessWidget { color: Theme.of(context).colorScheme.outline, ), ), - Padding( - padding: const EdgeInsets.only(top: 2), - child: Row( - children: [ - StatView( - context: context, - theme: 'gray', - value: Utils.numFormat(videoItem.cntInfo?['play']), - ), - const SizedBox(width: 8), - StatDanMu( - context: context, - theme: 'gray', - value: Utils.numFormat(videoItem.cntInfo?['danmaku']), - ), - const Spacer(), - ], - ), + const SizedBox(height: 3), + Row( + children: [ + StatView( + context: context, + theme: 'gray', + value: Utils.numFormat(videoItem.cntInfo?['play']), + ), + const SizedBox(width: 8), + StatDanMu( + context: context, + theme: 'gray', + value: Utils.numFormat(videoItem.cntInfo?['danmaku']), + ), + const Spacer(), + ], ), ], ), diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 57cdb1530..a2353d84a 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -22,6 +22,7 @@ import 'package:PiliPlus/pages/video/detail/post_panel/post_panel.dart'; import 'package:PiliPlus/pages/video/detail/widgets/send_danmaku_panel.dart'; import 'package:PiliPlus/pages/video/detail/widgets/media_list_panel.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'; @@ -428,7 +429,7 @@ class VideoDetailController extends GetxController : null, ); if (plPlayerController.isFullScreen.value) { - Utils.showFSSheet( + PageUtils.showVideoBottomSheet( context, child: plPlayerController.darkVideoPage && MyApp.darkThemeData != null ? Theme( @@ -1368,7 +1369,7 @@ class VideoDetailController extends GetxController ); } if (plPlayerController.isFullScreen.value) { - Utils.showFSSheet( + PageUtils.showVideoBottomSheet( context, child: plPlayerController.darkVideoPage && MyApp.darkThemeData != null ? Theme( @@ -1664,7 +1665,7 @@ class VideoDetailController extends GetxController Get.find(tag: heroTag).videoDetail.value.title; } catch (_) {} if (plPlayerController.isFullScreen.value) { - Utils.showFSSheet( + PageUtils.showVideoBottomSheet( context, child: plPlayerController.darkVideoPage && MyApp.darkThemeData != null ? Theme( diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index d1b936650..bc31764ad 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -8,6 +8,8 @@ import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart'; import 'package:PiliPlus/pages/video/detail/introduction/pay_coins_page.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:expandable/expandable.dart'; import 'package:flutter/material.dart'; @@ -471,7 +473,7 @@ class VideoIntroController extends GetxController ), onTap: () { Get.back(); - Utils.launchURL(videoUrl); + PageUtils.launchURL(videoUrl); }, ), ListTile( @@ -570,7 +572,7 @@ class VideoIntroController extends GetxController } return; } else { - Utils.actionRelationMod( + RequestUtils.actionRelationMod( context: context, mid: videoDetail.value.owner?.mid, isFollow: attr != 0, @@ -598,7 +600,7 @@ class VideoIntroController extends GetxController if (videoDetailCtr.isPlayAll) { if (videoDetailCtr.mediaList.indexWhere((item) => item.bvid == bvid) == -1) { - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { if (cover != null) 'pic': cover, @@ -866,7 +868,7 @@ class VideoIntroController extends GetxController ); } else { SearchHttp.ab2c(aid: videoItem.aid, bvid: videoItem.bvid).then( - (cid) => Utils.toViewPage( + (cid) => PageUtils.toVideoPage( 'bvid=${videoItem.bvid}&cid=${videoItem.cid}', arguments: { 'videoItem': videoItem, @@ -912,10 +914,10 @@ class VideoIntroController extends GetxController if (type == 'tap') { actionFavVideo(type: 'default'); } else { - Utils.showFavBottomSheet(context: context, ctr: this); + PageUtils.showFavBottomSheet(context: context, ctr: this); } } else if (type != 'longPress') { - Utils.showFavBottomSheet(context: context, ctr: this); + PageUtils.showFavBottomSheet(context: context, ctr: this); } } } diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 465291ffa..099f35c5a 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -5,6 +5,8 @@ import 'package:PiliPlus/pages/search/widgets/search_text.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:expandable/expandable.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/rendering.dart'; @@ -296,112 +298,125 @@ class _VideoInfoState extends State { children: [ Expanded( child: videoItem['staff'] == null - ? GestureDetector( - onTap: onPushMember, - behavior: HitTestBehavior.opaque, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - Obx( - () => Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - type: 'avatar', - src: videoIntroController.userStat - .value['card']?['face'] ?? - '', - width: 35, - height: 35, - fadeInDuration: Duration.zero, - fadeOutDuration: Duration.zero, - ), - if ((videoIntroController.userStat - .value['card'] - ?['official_verify'] - ?['type'] ?? - -1) != - -1) - Positioned( - right: -2, - bottom: -2, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context) - .colorScheme - .surface, + ? Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + GestureDetector( + onTap: onPushMember, + behavior: HitTestBehavior.opaque, + child: Row( + mainAxisAlignment: + MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Obx( + () => Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + type: 'avatar', + src: videoIntroController + .userStat + .value['card'] + ?['face'] ?? + '', + width: 35, + height: 35, + fadeInDuration: Duration.zero, + fadeOutDuration: + Duration.zero, + ), + if ((videoIntroController + .userStat + .value['card'] + ?[ + 'official_verify'] + ?['type'] ?? + -1) != + -1) + Positioned( + right: -2, + bottom: -2, + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context) + .colorScheme + .surface, + ), + child: Icon( + Icons.offline_bolt, + color: videoIntroController + .userStat + .value['card'] + ?[ + 'official_verify'] + ?['type'] == + 0 + ? Colors.yellow + : Colors + .lightBlueAccent, + size: 14, + ), + ), ), - child: Icon( - Icons.offline_bolt, - color: videoIntroController + ], + ), + ), + const SizedBox(width: 10), + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Obx( + () => Text( + videoIntroController.userStat + .value['card'] + ?['name'] ?? + "", + maxLines: 1, + overflow: + TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, + color: (videoIntroController + .userStat + .value['card']?['vip'] + ?[ + 'status'] ?? + -1) > + 0 && + videoIntroController .userStat .value['card'] ?[ - 'official_verify'] - ?['type'] == - 0 - ? Colors.yellow - : Colors - .lightBlueAccent, - size: 14, + 'vip']?['type'] == + 2 + ? context.vipColor + : null, ), ), ), - ], - ), - ), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Obx( - () => Text( - videoIntroController.userStat - .value['card'] - ?['name'] ?? - "", - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 13, - color: (videoIntroController - .userStat - .value['card']?['vip'] - ?[ - 'status'] ?? - -1) > - 0 && - videoIntroController - .userStat - .value['card'] - ?[ - 'vip']?['type'] == - 2 - ? context.vipColor - : null, + const SizedBox(height: 0), + Obx( + () => Text( + '${Utils.numFormat(videoIntroController.userStat.value['follower'])}粉丝 ${videoIntroController.userStat.value['archive_count'] != null ? '${Utils.numFormat(videoIntroController.userStat.value['archive_count'])}视频' : ''}', + style: TextStyle( + fontSize: 12, + color: + t.colorScheme.outline, + ), ), ), - ), - const SizedBox(height: 0), - Obx( - () => Text( - '${Utils.numFormat(videoIntroController.userStat.value['follower'])}粉丝 ${videoIntroController.userStat.value['archive_count'] != null ? '${Utils.numFormat(videoIntroController.userStat.value['archive_count'])}视频' : ''}', - style: TextStyle( - fontSize: 12, - color: t.colorScheme.outline, - ), - ), - ), - ], - ), + ], + ), + ], ), - followButton(context, t), - ], - ), + ), + const Spacer(), + followButton(context, t), + ], ) : SelfSizedHorizontalList( gapSize: 25, @@ -489,7 +504,7 @@ class _VideoInfoState extends State { customBorder: const CircleBorder(), onTap: () { - Utils + RequestUtils .actionRelationMod( context: context, mid: videoItem[ @@ -1140,7 +1155,7 @@ class _VideoInfoState extends State { recognizer: TapGestureRecognizer() ..onTap = () { try { - Utils.handleWebview(matchStr); + PageUtils.handleWebview(matchStr); } catch (err) { SmartDialog.showToast(err.toString()); } diff --git a/lib/pages/video/detail/introduction/widgets/create_fav_page.dart b/lib/pages/video/detail/introduction/widgets/create_fav_page.dart index 8712118d9..670c3005c 100644 --- a/lib/pages/video/detail/introduction/widgets/create_fav_page.dart +++ b/lib/pages/video/detail/introduction/widgets/create_fav_page.dart @@ -43,7 +43,7 @@ class _CreateFavPageState extends State { if (data['status']) { _titleController.text = data['data']['title']; _introController.text = data['data']['intro']; - _isPublic = Utils.isPublic(data['data']['attr']); + _isPublic = Utils.isPublicFav(data['data']['attr']); _cover = data['data']['cover']; _attr = data['data']['attr']; } else { @@ -171,7 +171,7 @@ class _CreateFavPageState extends State { Widget get _buildBody => SingleChildScrollView( child: Column( children: [ - if (_attr == null || !Utils.isDefault(_attr!)) ...[ + if (_attr == null || !Utils.isDefaultFav(_attr!)) ...[ ListTile( tileColor: Theme.of(context).colorScheme.onInverseSurface, onTap: () { @@ -285,11 +285,11 @@ class _CreateFavPageState extends State { ), title: TextField( autofocus: true, - readOnly: _attr != null && Utils.isDefault(_attr!), + readOnly: _attr != null && Utils.isDefaultFav(_attr!), controller: _titleController, style: TextStyle( fontSize: 14, - color: _attr != null && Utils.isDefault(_attr!) + color: _attr != null && Utils.isDefaultFav(_attr!) ? Theme.of(context).colorScheme.outline : null, ), @@ -312,7 +312,7 @@ class _CreateFavPageState extends State { ), ), const SizedBox(height: 16), - if (_attr == null || !Utils.isDefault(_attr!)) ...[ + if (_attr == null || !Utils.isDefaultFav(_attr!)) ...[ ListTile( tileColor: Theme.of(context).colorScheme.onInverseSurface, title: Row( diff --git a/lib/pages/video/detail/introduction/widgets/fav_panel.dart b/lib/pages/video/detail/introduction/widgets/fav_panel.dart index bfabc4ef9..9e12ad575 100644 --- a/lib/pages/video/detail/introduction/widgets/fav_panel.dart +++ b/lib/pages/video/detail/introduction/widgets/fav_panel.dart @@ -107,7 +107,7 @@ class _FavPanelState extends State { 1, index), dense: true, - leading: Utils.isPublic(widget + leading: Utils.isPublicFav(widget .ctr.favFolderData.value.list[index].attr) ? const Icon(Icons.folder_outlined) : const Icon(Icons.lock_outline), @@ -115,7 +115,7 @@ class _FavPanelState extends State { title: Text(widget .ctr.favFolderData.value.list[index].title!), subtitle: Text( - '${widget.ctr.favFolderData.value.list[index].mediaCount}个内容 . ${Utils.isPublicText(widget.ctr.favFolderData.value.list[index].attr)}', + '${widget.ctr.favFolderData.value.list[index].mediaCount}个内容 . ${Utils.isPublicFavText(widget.ctr.favFolderData.value.list[index].attr)}', ), trailing: Transform.scale( scale: 0.9, diff --git a/lib/pages/video/detail/member/controller.dart b/lib/pages/video/detail/member/controller.dart index 1426d9fa3..db799078d 100644 --- a/lib/pages/video/detail/member/controller.dart +++ b/lib/pages/video/detail/member/controller.dart @@ -6,7 +6,7 @@ import 'package:PiliPlus/models/space_archive/item.dart'; import 'package:PiliPlus/pages/common/common_data_controller.dart'; import 'package:PiliPlus/pages/member/content/member_contribute/member_contribute.dart' show ContributeType; -import 'package:PiliPlus/utils/utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:get/get.dart'; class HorizontalMemberPageController extends CommonDataController { @@ -28,7 +28,7 @@ class HorizontalMemberPageController extends CommonDataController { } Future getUserInfo() async { - wwebid ??= await Utils.getWwebid(mid); + wwebid ??= await RequestUtils.getWwebid(mid); dynamic res = await MemberHttp.memberInfo(mid: mid, wwebid: wwebid); if (res['status']) { userState.value = LoadingState.success(res['data']); diff --git a/lib/pages/video/detail/member/horizontal_member_page.dart b/lib/pages/video/detail/member/horizontal_member_page.dart index 830f49e69..3cff46056 100644 --- a/lib/pages/video/detail/member/horizontal_member_page.dart +++ b/lib/pages/video/detail/member/horizontal_member_page.dart @@ -14,6 +14,7 @@ import 'package:PiliPlus/pages/video/detail/member/controller.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/grid.dart'; import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -338,7 +339,7 @@ class _HorizontalMemberPageState extends State { SmartDialog.showToast('账号未登录'); return; } - Utils.actionRelationMod( + RequestUtils.actionRelationMod( context: context, mid: widget.mid, isFollow: memberInfoModel.isFollowed ?? false, diff --git a/lib/pages/video/detail/related/view.dart b/lib/pages/video/detail/related/view.dart index ecf73f8e6..4dd712124 100644 --- a/lib/pages/video/detail/related/view.dart +++ b/lib/pages/video/detail/related/view.dart @@ -46,9 +46,7 @@ class _RelatedVideoPanelState extends State ), Success() => loadingState.response?.isNotEmpty == true ? SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context).padding.bottom, - ), + padding: const EdgeInsets.only(bottom: 80), sliver: SliverGrid( gridDelegate: Grid.videoCardHDelegate(context), delegate: SliverChildBuilderDelegate((context, index) { diff --git a/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart b/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart index 4612ca709..49c67e419 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart @@ -12,6 +12,7 @@ import 'package:PiliPlus/common/widgets/save_panel.dart'; import 'package:PiliPlus/pages/video/detail/reply/widgets/zan_grpc.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:dio/dio.dart'; import 'package:flutter/gestures.dart'; @@ -917,14 +918,14 @@ class ReplyItemGrpc extends StatelessWidget { }); return; } - Utils.handleWebview(matchStr); + PageUtils.handleWebview(matchStr); } } else { if (appUrlSchema.startsWith('bilibili://search')) { Get.toNamed('/searchResult', parameters: {'keyword': title}); } else { - Utils.handleWebview(matchStr); + PageUtils.handleWebview(matchStr); } } }, @@ -960,7 +961,7 @@ class ReplyItemGrpc extends StatelessWidget { ), recognizer: TapGestureRecognizer() ..onTap = () { - Utils.handleWebview(matchStr); + PageUtils.handleWebview(matchStr); }, ), ); @@ -1019,7 +1020,7 @@ class ReplyItemGrpc extends StatelessWidget { return; } - Utils.handleWebview(patternStr); + PageUtils.handleWebview(patternStr); }, ) ], @@ -1074,7 +1075,8 @@ class ReplyItemGrpc extends StatelessWidget { color: Theme.of(context).colorScheme.primary, ), recognizer: TapGestureRecognizer() - ..onTap = () => Utils.handleWebview(content.richText.note.clickUrl), + ..onTap = + () => PageUtils.handleWebview(content.richText.note.clickUrl), ), ); } diff --git a/lib/pages/video/detail/reply_reply/view.dart b/lib/pages/video/detail/reply_reply/view.dart index f847d3dc0..8ad8ea539 100644 --- a/lib/pages/video/detail/reply_reply/view.dart +++ b/lib/pages/video/detail/reply_reply/view.dart @@ -6,6 +6,8 @@ import 'package:PiliPlus/pages/common/common_slide_page.dart'; import 'package:PiliPlus/pages/video/detail/reply/widgets/reply_item_grpc.dart'; import 'package:PiliPlus/pages/video/detail/reply_new/reply_page.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -287,7 +289,7 @@ class _VideoReplyReplyPanelState vsync: this, duration: const Duration(milliseconds: 200), )..forward(); - Utils.onHorizontalPreview( + PageUtils.onHorizontalPreview( _key, AnimationController( vsync: this, @@ -351,7 +353,7 @@ class _VideoReplyReplyPanelState .then((res) { if (res != null) { _savedReplies[key] = null; - ReplyInfo replyInfo = Utils.replyCast(res); + ReplyInfo replyInfo = RequestUtils.replyCast(res); List list = _videoReplyReplyController.loadingState.value is Success ? (_videoReplyReplyController.loadingState.value as Success) diff --git a/lib/pages/video/detail/view_v.dart b/lib/pages/video/detail/view_v.dart index 2d0e76894..bcb6ac99c 100644 --- a/lib/pages/video/detail/view_v.dart +++ b/lib/pages/video/detail/view_v.dart @@ -22,6 +22,7 @@ import 'package:PiliPlus/pages/video/detail/widgets/ai_detail.dart'; import 'package:PiliPlus/utils/download.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:auto_orientation/auto_orientation.dart'; import 'package:cached_network_image/cached_network_image.dart'; @@ -557,7 +558,7 @@ class _VideoDetailPageVState extends State void enterPip() { if (Get.currentRoute.startsWith('/video') && videoDetailController.floating != null) { - Utils.enterPip( + PageUtils.enterPip( videoDetailController.floating!, videoDetailController.data.dash!.video!.first.width!, videoDetailController.data.dash!.video!.first.height!, @@ -875,7 +876,7 @@ class _VideoDetailPageVState extends State SmartDialog.showToast( '账号未登录'); } else { - Utils.reportVideo( + PageUtils.reportVideo( videoDetailController .oid.value); } @@ -1462,7 +1463,7 @@ class _VideoDetailPageVState extends State if (!Accounts.main.isLogin) { SmartDialog.showToast('账号未登录'); } else { - Utils.reportVideo( + PageUtils.reportVideo( videoDetailController.oid.value); } break; @@ -2195,7 +2196,7 @@ class _VideoDetailPageVState extends State vsync: this, duration: const Duration(milliseconds: 200), )..forward(); - Utils.onHorizontalPreview( + PageUtils.onHorizontalPreview( videoDetailController.childKey, AnimationController( vsync: this, @@ -2309,7 +2310,7 @@ class _VideoDetailPageVState extends State }, ); if (isFullScreen) { - Utils.showFSSheet( + PageUtils.showVideoBottomSheet( context, isFullScreen: () => isFullScreen, child: videoDetailController.plPlayerController.darkVideoPage @@ -2407,7 +2408,7 @@ class _VideoDetailPageVState extends State void showViewPoints() { if (isFullScreen) { - Utils.showFSSheet( + PageUtils.showVideoBottomSheet( context, isFullScreen: () => isFullScreen, child: videoDetailController.plPlayerController.darkVideoPage diff --git a/lib/pages/video/detail/widgets/ai_detail.dart b/lib/pages/video/detail/widgets/ai_detail.dart index eee2578a9..8551f90b2 100644 --- a/lib/pages/video/detail/widgets/ai_detail.dart +++ b/lib/pages/video/detail/widgets/ai_detail.dart @@ -1,6 +1,7 @@ import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/pages/common/common_collapse_slide_page.dart'; import 'package:PiliPlus/pages/video/detail/controller.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -50,7 +51,7 @@ class _AiDetailState extends CommonCollapseSlidePageState { ..onTap = () { // 处理点击事件 try { - Utils.handleWebview(match.group(0)!); + PageUtils.handleWebview(match.group(0)!); } catch (err) { SmartDialog.showToast(err.toString()); } diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index e7c804bcf..d46fe29b0 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -11,6 +11,7 @@ import 'package:PiliPlus/pages/setting/widgets/switch_item.dart'; import 'package:PiliPlus/pages/video/detail/introduction/widgets/action_item.dart'; import 'package:PiliPlus/utils/download.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:canvas_danmaku/canvas_danmaku.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; @@ -99,7 +100,7 @@ class HeaderControlState extends State { } void showBottomSheet(StatefulWidgetBuilder builder, {double? padding}) { - Utils.showFSSheet( + PageUtils.showVideoBottomSheet( context, isFullScreen: () => isFullScreen, padding: padding, @@ -191,7 +192,7 @@ class HeaderControlState extends State { dense: true, onTap: () => { Get.back(), - Utils.scheduleExit(this.context, isFullScreen) + PageUtils.scheduleExit(this.context, isFullScreen) }, leading: const Icon(Icons.hourglass_top_outlined, size: 20), title: const Text('定时关闭', style: titleStyle), @@ -582,7 +583,7 @@ class HeaderControlState extends State { return; } Get.back(); - Utils.reportVideo(videoDetailCtr.oid.value); + PageUtils.reportVideo(videoDetailCtr.oid.value); }, leading: const Icon(Icons.error_outline, size: 20), title: const Text('举报', style: titleStyle), @@ -2237,7 +2238,7 @@ class HeaderControlState extends State { const Duration(seconds: 3), () {}); } if (!context.mounted) return; - Utils.enterPip( + PageUtils.enterPip( widget.floating!, widget .videoDetailCtr.data.dash!.video!.first.width!, diff --git a/lib/pages/video/detail/widgets/media_list_panel.dart b/lib/pages/video/detail/widgets/media_list_panel.dart index 731d7af02..fa7083647 100644 --- a/lib/pages/video/detail/widgets/media_list_panel.dart +++ b/lib/pages/video/detail/widgets/media_list_panel.dart @@ -240,7 +240,7 @@ class _MediaListPanelState Theme.of(context).colorScheme.outline, ), ), - const SizedBox(height: 2), + const SizedBox(height: 3), Row( children: [ StatView( diff --git a/lib/pages/webview/webview_page.dart b/lib/pages/webview/webview_page.dart index 7f106b141..ebb0973fd 100644 --- a/lib/pages/webview/webview_page.dart +++ b/lib/pages/webview/webview_page.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/utils/accounts/account.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/cache_manage.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -108,7 +109,7 @@ class _WebviewPageNewState extends State { case _WebviewMenuItem.openInBrowser: WebUri? uri = await _webViewController?.getUrl(); if (uri != null) { - Utils.launchURL(uri.toString()); + PageUtils.launchURL(uri.toString()); } break; case _WebviewMenuItem.clearCache: @@ -261,7 +262,7 @@ class _WebviewPageNewState extends State { TextButton( onPressed: () async { Get.back(); - Utils.launchURL(request.url.toString()); + PageUtils.launchURL(request.url.toString()); }, child: Text('确定 ($fileSize)')), ], @@ -312,7 +313,7 @@ class _WebviewPageNewState extends State { showCloseIcon: true, action: SnackBarAction( label: '打开', - onPressed: () => Utils.launchURL(url), + onPressed: () => PageUtils.launchURL(url), ), ); ScaffoldMessenger.of(context).showSnackBar(snackBar); diff --git a/lib/pages/whisper_detail/widget/chat_item.dart b/lib/pages/whisper_detail/widget/chat_item.dart index 3e8576062..131983443 100644 --- a/lib/pages/whisper_detail/widget/chat_item.dart +++ b/lib/pages/whisper_detail/widget/chat_item.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; @@ -192,7 +193,7 @@ class ChatItem extends StatelessWidget { SmartDialog.showLoading(); final int cid = await SearchHttp.ab2c(bvid: bvid); SmartDialog.dismiss().then( - (e) => Utils.toViewPage( + (e) => PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'pic': content['thumb'], @@ -240,7 +241,7 @@ class ChatItem extends StatelessWidget { var bvid = content["bvid"]; final int cid = await SearchHttp.ab2c(bvid: bvid); SmartDialog.dismiss().then( - (_) => Utils.toViewPage( + (_) => PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'pic': content['thumb'], @@ -327,7 +328,8 @@ class ChatItem extends StatelessWidget { SmartDialog.showLoading(); final int cid = await SearchHttp.ab2c(bvid: bvid); SmartDialog.dismiss().then( - (e) => Utils.toViewPage('bvid=$bvid&cid=$cid', + (e) => PageUtils.toVideoPage( + 'bvid=$bvid&cid=$cid', arguments: { 'pic': i['cover_url'], 'heroTag': Utils.makeHeroTag(bvid), @@ -339,7 +341,7 @@ class ChatItem extends StatelessWidget { } } else { SmartDialog.showToast('未匹配到 BV 号'); - Utils.handleWebview(i['jump_url']); + PageUtils.handleWebview(i['jump_url']); } }, child: Row( diff --git a/lib/utils/app_scheme.dart b/lib/utils/app_scheme.dart index 63551afdd..13eab0ef5 100644 --- a/lib/utils/app_scheme.dart +++ b/lib/utils/app_scheme.dart @@ -3,6 +3,7 @@ import 'dart:async'; import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/models/common/reply_type.dart'; import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:app_links/app_links.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -84,7 +85,7 @@ class PiliScheme { String? id = uriDigitRegExp.firstMatch(path)?.group(1); if (id != null) { bool isEp = path.contains('/ep/'); - Utils.viewBangumi( + PageUtils.viewBangumi( seasonId: isEp ? null : id, epId: isEp ? id : null, progress: uri.queryParameters['start_progress']); @@ -95,7 +96,7 @@ class PiliScheme { // bilibili://space/12345678?frommodule=XX&h5awaken=random String? mid = uriDigitRegExp.firstMatch(path)?.group(1); if (mid != null) { - Utils.toDupNamed('/member?mid=$mid', off: off); + PageUtils.toDupNamed('/member?mid=$mid', off: off); return true; } return false; @@ -159,7 +160,7 @@ class PiliScheme { if (aid != null || bvid != null) { if (queryParameters['cid'] != null) { bvid ??= IdUtils.av2bv(int.parse(aid!)); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=${queryParameters['cid']}', arguments: { 'pic': null, @@ -185,7 +186,7 @@ class PiliScheme { // bilibili://live/12345678?extra_jump_from=1&from=1&is_room_feed=1&h5awaken=random String? roomId = uriDigitRegExp.firstMatch(path)?.group(1); if (roomId != null) { - Utils.toDupNamed('/liveRoom?roomid=$roomId', off: off); + PageUtils.toDupNamed('/liveRoom?roomid=$roomId', off: off); return true; } return false; @@ -194,7 +195,7 @@ class PiliScheme { if (path.startsWith('/season')) { String? seasonId = uriDigitRegExp.firstMatch(path)?.group(1); if (seasonId != null) { - Utils.viewBangumi(seasonId: seasonId, epId: null); + PageUtils.viewBangumi(seasonId: seasonId, epId: null); return true; } } @@ -203,7 +204,7 @@ class PiliScheme { // bilibili://opus/detail/12345678?h5awaken=random // String? id = uriDigitRegExp.firstMatch(path)?.group(1); // if (id != null) { - // Utils.toDupNamed( + // PageUtils.toDupNamed( // '/htmlRender', // parameters: { // 'url': 'https://www.bilibili.com/opus/$id', @@ -219,7 +220,7 @@ class PiliScheme { bool hasMatch = await _onPushDynDetail(path, off); return hasMatch; case 'search': - Utils.toDupNamed( + PageUtils.toDupNamed( '/searchResult', parameters: {'keyword': ''}, off: off, @@ -229,7 +230,7 @@ class PiliScheme { // bilibili://article/40679479?jump_opus=1&jump_opus_type=1&opus_type=article&h5awaken=random String? id = uriDigitRegExp.firstMatch(path)?.group(1); if (id != null) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/htmlRender', parameters: { 'url': 'www.bilibili.com/read/cv$id', @@ -351,7 +352,7 @@ class PiliScheme { .firstMatch(path) ?.group(1); if (cvid != null) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/htmlRender', parameters: { 'url': 'https://www.bilibili.com/read/cv$cvid', @@ -424,7 +425,7 @@ class PiliScheme { dynamic res = await DynamicsHttp.dynamicDetail(rid: rid, type: 2); SmartDialog.dismiss(); if (res['status']) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/dynamicDetail', arguments: { 'item': res['data'], @@ -442,7 +443,7 @@ class PiliScheme { case 'medialist': String? mediaId = uriDigitRegExp.firstMatch(path)?.group(1); if (mediaId != null) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/favDetail', parameters: { 'mediaId': mediaId, @@ -546,7 +547,7 @@ class PiliScheme { if (host.contains('live.bilibili.com')) { String? roomId = uriDigitRegExp.firstMatch(path)?.group(1); if (roomId != null) { - Utils.toDupNamed('/liveRoom?roomid=$roomId', off: off); + PageUtils.toDupNamed('/liveRoom?roomid=$roomId', off: off); return true; } launchURL(); @@ -556,7 +557,7 @@ class PiliScheme { if (host.contains('space.bilibili.com')) { String? mid = uriDigitRegExp.firstMatch(path)?.group(1); if (mid != null) { - Utils.toDupNamed('/member?mid=$mid', off: off); + PageUtils.toDupNamed('/member?mid=$mid', off: off); return true; } launchURL(); @@ -579,7 +580,7 @@ class PiliScheme { .firstMatch(uri.query) ?.group(1); if (id != null) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/htmlRender', parameters: { 'url': 'https://www.bilibili.com/read/cv$id', @@ -597,7 +598,7 @@ class PiliScheme { // case 'opus': // String? id = uriDigitRegExp.firstMatch(path)?.group(1); // if (id != null) { - // Utils.toDupNamed( + // PageUtils.toDupNamed( // '/htmlRender', // parameters: { // 'url': 'https://www.bilibili.com/opus/$id', @@ -635,7 +636,7 @@ class PiliScheme { if (id != null) { bool isSeason = id.startsWith('ss'); id = id.substring(2); - Utils.viewBangumi( + PageUtils.viewBangumi( seasonId: isSeason ? id : null, epId: isSeason ? null : id, progress: uri.queryParameters['start_progress']); @@ -664,7 +665,7 @@ class PiliScheme { String? id = RegExp(r'cv(\d+)', caseSensitive: false).firstMatch(path)?.group(1); if (id != null) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/htmlRender', parameters: { 'url': 'https://www.bilibili.com/read/cv$id', @@ -682,7 +683,7 @@ class PiliScheme { debugPrint('个人空间'); String? mid = uriDigitRegExp.firstMatch(path)?.group(1); if (mid != null) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/member?mid=$mid', off: off, ); @@ -708,7 +709,7 @@ class PiliScheme { static Future _onPushDynDetail(path, off) async { String? id = uriDigitRegExp.firstMatch(path)?.group(1); if (id != null) { - Utils.pushDynFromId(id, off: off); + PageUtils.pushDynFromId(id, off: off); return true; } return false; @@ -719,7 +720,7 @@ class PiliScheme { bool off, Map? parameters, ) { - Utils.toDupNamed( + PageUtils.toDupNamed( '/webview', parameters: { 'url': url, @@ -752,7 +753,7 @@ class PiliScheme { if (showDialog) { SmartDialog.dismiss(); } - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'pic': null, diff --git a/lib/utils/danmaku.dart b/lib/utils/danmaku_utils.dart similarity index 100% rename from lib/utils/danmaku.dart rename to lib/utils/danmaku_utils.dart diff --git a/lib/utils/grid.dart b/lib/utils/grid.dart index 4a135b24a..159e24f7d 100644 --- a/lib/utils/grid.dart +++ b/lib/utils/grid.dart @@ -12,7 +12,7 @@ class Grid { SliverGridDelegateWithExtentAndRatio( mainAxisSpacing: 2, maxCrossAxisExtent: Grid.smallCardWidth * 2, - childAspectRatio: StyleString.aspectRatio * 2.4, + childAspectRatio: StyleString.aspectRatio * 2.2, minHeight: MediaQuery.textScalerOf(context).scale(minHeight), ); } diff --git a/lib/utils/login.dart b/lib/utils/login_utils.dart similarity index 100% rename from lib/utils/login.dart rename to lib/utils/login_utils.dart diff --git a/lib/utils/page_utils.dart b/lib/utils/page_utils.dart new file mode 100644 index 000000000..fda9be077 --- /dev/null +++ b/lib/utils/page_utils.dart @@ -0,0 +1,747 @@ +import 'dart:math'; + +import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'; +import 'package:PiliPlus/http/dynamics.dart'; +import 'package:PiliPlus/http/search.dart'; +import 'package:PiliPlus/models/bangumi/info.dart'; +import 'package:PiliPlus/models/common/search_type.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; +import 'package:PiliPlus/models/live/item.dart'; +import 'package:PiliPlus/pages/video/detail/introduction/widgets/fav_panel.dart'; +import 'package:PiliPlus/pages/video/detail/introduction/widgets/menu_row.dart'; +import 'package:PiliPlus/services/shutdown_timer_service.dart'; +import 'package:PiliPlus/utils/app_scheme.dart'; +import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/feed_back.dart'; +import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/storage.dart'; +import 'package:PiliPlus/utils/url_utils.dart'; +import 'package:PiliPlus/utils/utils.dart'; +import 'package:floating/floating.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class PageUtils { + static void scheduleExit(BuildContext context, isFullScreen, + [bool isLive = false]) { + if (!context.mounted) { + return; + } + const List scheduleTimeChoices = [0, 15, 30, 45, 60]; + const TextStyle titleStyle = TextStyle(fontSize: 14); + if (isLive) { + shutdownTimerService.waitForPlayingCompleted = false; + } + PageUtils.showVideoBottomSheet( + context, + isFullScreen: () => isFullScreen, + child: StatefulBuilder( + builder: (_, setState) { + return Theme( + data: Theme.of(context), + child: Material( + color: Colors.transparent, + child: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(12), + padding: const EdgeInsets.only(left: 14, right: 14), + child: ListView( + padding: + const EdgeInsets.symmetric(vertical: 0, horizontal: 20), + children: [ + const SizedBox(height: 10), + const Center(child: Text('定时关闭', style: titleStyle)), + const SizedBox(height: 10), + ...[ + ...[ + ...scheduleTimeChoices, + if (scheduleTimeChoices + .contains( + shutdownTimerService.scheduledExitInMinutes) + .not) + shutdownTimerService.scheduledExitInMinutes, + ]..sort(), + -1, + ].map( + (choice) => ListTile( + dense: true, + onTap: () { + if (choice == -1) { + showDialog( + context: context, + builder: (context) { + String duration = ''; + return AlertDialog( + title: const Text('自定义时长'), + content: TextField( + autofocus: true, + onChanged: (value) => duration = value, + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.allow( + RegExp(r'\d+')), + ], + decoration: const InputDecoration( + suffixText: 'min'), + ), + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: TextStyle( + color: Theme.of(context) + .colorScheme + .outline), + ), + ), + TextButton( + onPressed: () { + Get.back(); + int choice = + int.tryParse(duration) ?? 0; + shutdownTimerService + .scheduledExitInMinutes = choice; + shutdownTimerService + .startShutdownTimer(); + setState(() {}); + }, + child: Text('确定'), + ), + ], + ); + }, + ); + } else { + Get.back(); + shutdownTimerService.scheduledExitInMinutes = + choice; + shutdownTimerService.startShutdownTimer(); + } + }, + contentPadding: const EdgeInsets.only(), + title: Text(choice == -1 + ? '自定义' + : choice == 0 + ? "禁用" + : "$choice分钟后"), + trailing: shutdownTimerService.scheduledExitInMinutes == + choice + ? Icon( + Icons.done, + color: Theme.of(context).colorScheme.primary, + ) + : null, + ), + ), + const SizedBox(height: 6), + const Center( + child: SizedBox( + width: 125, + child: Divider(height: 1), + ), + ), + if (isLive.not) ...[ + const SizedBox(height: 10), + ListTile( + dense: true, + onTap: () { + shutdownTimerService.waitForPlayingCompleted = + !shutdownTimerService.waitForPlayingCompleted; + setState(() {}); + }, + contentPadding: const EdgeInsets.only(), + title: const Text("额外等待视频播放完毕", style: titleStyle), + 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; + }), + value: shutdownTimerService.waitForPlayingCompleted, + onChanged: (value) => setState(() => + shutdownTimerService.waitForPlayingCompleted = + value), + ), + ), + ), + ], + const SizedBox(height: 10), + Row( + children: [ + const Text('倒计时结束:', style: titleStyle), + const Spacer(), + ActionRowLineItem( + onTap: () { + shutdownTimerService.exitApp = false; + setState(() {}); + // Get.back(); + }, + text: " 暂停视频 ", + selectStatus: !shutdownTimerService.exitApp, + ), + const Spacer(), + // const SizedBox(width: 10), + ActionRowLineItem( + onTap: () { + shutdownTimerService.exitApp = true; + setState(() {}); + // Get.back(); + }, + text: " 退出APP ", + selectStatus: shutdownTimerService.exitApp, + ) + ], + ), + const SizedBox(height: 10), + ], + ), + ), + ), + ); + }, + ), + ); + } + + static Future pushDynFromId(id, {bool off = false}) async { + SmartDialog.showLoading(); + dynamic res = await DynamicsHttp.dynamicDetail(id: id); + SmartDialog.dismiss(); + if (res['status']) { + DynamicItemModel data = res['data']; + if (data.basic?['comment_type'] == 12) { + toDupNamed( + '/htmlRender', + parameters: { + 'url': 'www.bilibili.com/opus/$id', + 'title': '', + 'id': id, + 'dynamicType': 'opus' + }, + off: off, + ); + } else { + toDupNamed( + '/dynamicDetail', + arguments: { + 'item': res['data'], + 'floor': 1, + 'action': 'detail', + }, + off: off, + ); + } + } else { + SmartDialog.showToast(res['msg']); + } + } + + static void showFavBottomSheet({ + required BuildContext context, + required dynamic ctr, + }) { + showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Theme.of(context).colorScheme.surface, + sheetAnimationStyle: AnimationStyle(curve: Curves.ease), + constraints: BoxConstraints( + maxWidth: min(640, min(Get.width, Get.height)), + ), + builder: (BuildContext context) { + return DraggableScrollableSheet( + minChildSize: 0, + maxChildSize: 1, + initialChildSize: 0.7, + snap: true, + expand: false, + snapSizes: const [0.7], + builder: (BuildContext context, ScrollController scrollController) { + return FavPanel( + ctr: ctr, + scrollController: scrollController, + ); + }, + ); + }, + ); + } + + static void reportVideo(int aid) { + Get.toNamed( + '/webview', + parameters: {'url': 'https://www.bilibili.com/appeal/?avid=$aid'}, + ); + } + + static void enterPip(Floating floating, int width, int height) { + Rational aspectRatio = Rational(width, height); + floating.enable( + EnableManual( + aspectRatio: aspectRatio.fitsInAndroidRequirements + ? aspectRatio + : height > width + ? const Rational.vertical() + : const Rational.landscape(), + ), + ); + } + + static void pushDynDetail(item, floor, {action = 'all'}) async { + feedBack(); + + /// 点击评论action 直接查看评论 + if (action == 'comment') { + toDupNamed( + '/dynamicDetail', + arguments: { + 'item': item, + 'floor': floor, + 'action': action, + }, + ); + return; + } + + debugPrint('pushDynDetail: ${item.type}'); + + switch (item.type) { + case 'DYNAMIC_TYPE_AV': + if (item.modules.moduleDynamic.major.archive?.type == 2) { + if (item.modules.moduleDynamic.major.archive.jumpUrl + .startsWith('//')) { + item.modules.moduleDynamic.major.archive.jumpUrl = + 'https:${item.modules.moduleDynamic.major.archive.jumpUrl}'; + } + String? redirectUrl = await UrlUtils.parseRedirectUrl( + item.modules.moduleDynamic.major.archive.jumpUrl, false); + if (redirectUrl != null) { + viewPgcFromUri(redirectUrl); + return; + } + } + + try { + String bvid = item.modules.moduleDynamic.major.archive.bvid; + String cover = item.modules.moduleDynamic.major.archive.cover; + int cid = await SearchHttp.ab2c(bvid: bvid); + toVideoPage( + 'bvid=$bvid&cid=$cid', + arguments: { + 'pic': cover, + 'heroTag': Utils.makeHeroTag(bvid), + }, + preventDuplicates: false, + ); + } catch (err) { + SmartDialog.showToast(err.toString()); + } + break; + + /// 专栏文章查看 + case 'DYNAMIC_TYPE_ARTICLE': + String? url = item?.modules?.moduleDynamic?.major?.opus?.jumpUrl; + if (url != null) { + String? title = item?.modules?.moduleDynamic?.major?.opus?.title; + if (url.contains('opus') || url.contains('read')) { + RegExp digitRegExp = RegExp(r'\d+'); + Iterable matches = digitRegExp.allMatches(url); + String number = matches.first.group(0)!; + if (url.contains('read')) { + number = 'cv$number'; + } + toDupNamed('/htmlRender', parameters: { + 'url': url.startsWith('//') ? url.split('//').last : url, + 'title': title ?? '', + 'id': number, + 'dynamicType': url.split('//').last.split('/')[1] + }); + } else { + handleWebview('https:$url'); + } + } + + break; + case 'DYNAMIC_TYPE_PGC': + debugPrint('番剧'); + SmartDialog.showToast('暂未支持的类型,请联系开发者'); + break; + + case 'DYNAMIC_TYPE_LIVE_RCMD': + DynamicLiveModel liveRcmd = item.modules.moduleDynamic.major.liveRcmd; + ModuleAuthorModel author = item.modules.moduleAuthor; + LiveItemModel liveItem = LiveItemModel.fromJson({ + 'title': liveRcmd.title, + 'uname': author.name, + 'cover': liveRcmd.cover, + 'mid': author.mid, + 'face': author.face, + 'roomid': liveRcmd.roomId, + 'watched_show': liveRcmd.watchedShow, + }); + toDupNamed('/liveRoom?roomid=${liveItem.roomId}'); + break; + + /// 合集查看 + case 'DYNAMIC_TYPE_UGC_SEASON': + DynamicArchiveModel ugcSeason = + item.modules.moduleDynamic.major.ugcSeason; + int aid = ugcSeason.aid!; + String bvid = IdUtils.av2bv(aid); + String cover = ugcSeason.cover!; + int cid = await SearchHttp.ab2c(bvid: bvid); + toVideoPage( + 'bvid=$bvid&cid=$cid', + arguments: { + 'pic': cover, + 'heroTag': Utils.makeHeroTag(bvid), + }, + preventDuplicates: false, + ); + break; + + /// 番剧查看 + case 'DYNAMIC_TYPE_PGC_UNION': + debugPrint('DYNAMIC_TYPE_PGC_UNION 番剧'); + DynamicArchiveModel pgc = item.modules.moduleDynamic.major.pgc; + if (pgc.epid != null) { + viewBangumi(epId: pgc.epid); + } + break; + case 'DYNAMIC_TYPE_MEDIALIST': + if (item.modules?.moduleDynamic?.major?.medialist != null) { + final String? url = + item.modules.moduleDynamic.major.medialist['jump_url']; + if (url?.contains('medialist/detail/ml') == true) { + Get.toNamed( + '/favDetail', + parameters: { + 'heroTag': + '${item.modules.moduleDynamic.major.medialist['cover']}', + 'mediaId': + '${item.modules.moduleDynamic.major.medialist['id']}', + }, + ); + } else if (url != null) { + handleWebview(url.http2https); + } + } + break; + + // 纯文字动态查看 + // case 'DYNAMIC_TYPE_WORD': + // # 装扮/剧集点评/普通分享 + // case 'DYNAMIC_TYPE_COMMON_SQUARE': + // 转发的动态 + // case 'DYNAMIC_TYPE_FORWARD': + // 图文动态查看 + // case 'DYNAMIC_TYPE_DRAW': + default: + toDupNamed( + '/dynamicDetail', + arguments: { + 'item': item, + 'floor': floor, + }, + ); + break; + } + } + + static void onHorizontalPreview( + GlobalKey key, + transitionAnimationController, + ctr, + List imgList, + index, + onClose, + ) { + key.currentState?.showBottomSheet( + (context) { + return FadeTransition( + opacity: Tween(begin: 0, end: 1).animate(ctr), + child: InteractiveviewerGallery( + sources: imgList.map((url) => SourceModel(url: url)).toList(), + initIndex: index, + setStatusBar: false, + onClose: onClose, + ), + ); + }, + enableDrag: false, + elevation: 0, + backgroundColor: Colors.transparent, + transitionAnimationController: transitionAnimationController, + sheetAnimationStyle: AnimationStyle(duration: Duration.zero), + ); + } + + static void inAppWebview( + String url, { + bool off = false, + }) { + if (GStorage.openInBrowser) { + launchURL(url); + } else { + if (off) { + Get.offNamed( + '/webview', + parameters: {'url': url}, + arguments: {'inApp': true}, + ); + } else { + Get.toNamed( + '/webview', + parameters: {'url': url}, + arguments: {'inApp': true}, + ); + } + } + } + + static launchURL(String url) async { + try { + final Uri uri = Uri.parse(url); + if (!await launchUrl( + uri, + mode: LaunchMode.externalApplication, + )) { + SmartDialog.showToast('Could not launch $url'); + } + } catch (e) { + SmartDialog.showToast(e.toString()); + } + } + + static void handleWebview( + String url, { + bool off = false, + bool inApp = false, + Map? parameters, + }) async { + if (inApp.not && GStorage.openInBrowser) { + if ((await PiliScheme.routePushFromUrl(url, selfHandle: true)).not) { + launchURL(url); + } + } else { + if (off) { + Get.offNamed( + '/webview', + parameters: { + 'url': url, + if (parameters != null) ...parameters, + }, + ); + } else { + PiliScheme.routePushFromUrl(url, parameters: parameters); + } + } + } + + static void showVideoBottomSheet( + BuildContext context, { + required Widget child, + required Function isFullScreen, + double? padding, + }) { + if (!context.mounted) { + return; + } + Get.generalDialog( + barrierLabel: '', + barrierDismissible: true, + pageBuilder: (buildContext, animation, secondaryAnimation) { + return MediaQuery.orientationOf(Get.context!) == Orientation.portrait + ? SafeArea( + child: Column( + children: [ + const Spacer(flex: 3), + Expanded(flex: 7, child: child), + if (isFullScreen() && padding != null) + SizedBox(height: padding), + ], + ), + ) + : SafeArea( + child: Row( + children: [ + const Spacer(), + Expanded(child: child), + ], + ), + ); + }, + transitionDuration: const Duration(milliseconds: 350), + transitionBuilder: (context, animation, secondaryAnimation, child) { + Offset begin = + MediaQuery.orientationOf(Get.context!) == Orientation.portrait + ? Offset(0.0, 1.0) + : Offset(1.0, 0.0); + var tween = Tween(begin: begin, end: Offset.zero) + .chain(CurveTween(curve: Curves.easeInOut)); + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + routeSettings: RouteSettings(arguments: Get.arguments), + ); + } + + static void toVideoPage( + String page, { + dynamic arguments, + int? id, + bool preventDuplicates = true, + Map? parameters, + bool off = false, + }) { + if (off) { + Get.offNamed( + '/videoV?$page', + arguments: arguments, + id: id, + preventDuplicates: preventDuplicates, + parameters: parameters, + ); + } else { + Get.toNamed( + '/videoV?$page', + arguments: arguments, + id: id, + preventDuplicates: preventDuplicates, + parameters: parameters, + ); + } + } + + static bool viewPgcFromUri(String uri) { + String? id = RegExp(r'(ep|ss)\d+').firstMatch(uri)?.group(0); + if (id != null) { + bool isSeason = id.startsWith('ss'); + id = id.substring(2); + viewBangumi( + seasonId: isSeason ? id : null, + epId: isSeason ? null : id, + ); + return true; + } + return false; + } + + static void viewBangumi( + {dynamic seasonId, dynamic epId, dynamic progress}) async { + try { + SmartDialog.showLoading(msg: '资源获取中'); + var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId); + SmartDialog.dismiss(); + if (result['status']) { + BangumiInfoModel data = result['data']; + + // epId episode -> progress episode -> first episode + EpisodeItem? episode; + + if (epId != null) { + if (data.episodes?.isNotEmpty == true) { + episode = data.episodes!.firstWhereOrNull( + (item) { + return item.epId.toString() == epId.toString(); + }, + ); + } + if (episode == null && data.section?.isNotEmpty == true) { + for (Section item in data.section!) { + if (item.episodes?.isNotEmpty == true) { + for (EpisodeItem item in item.episodes!) { + if (item.epId.toString() == epId.toString()) { + // view as normal video + toVideoPage( + 'bvid=${item.bvid}&cid=${item.cid}&seasonId=${data.seasonId}&epId=${item.epId}', + arguments: { + 'pgcApi': true, + 'pic': item.cover, + 'heroTag': Utils.makeHeroTag(item.cid), + 'videoType': SearchType.video, + if (progress != null) 'progress': int.tryParse(progress) + }, + preventDuplicates: false, + ); + return; + } + } + } + } + } + } + + if (data.episodes.isNullOrEmpty) { + SmartDialog.showToast('资源加载失败'); + return; + } + + episode ??= data.userStatus?.progress?.lastEpId != null + ? data.episodes!.firstWhereOrNull( + (item) => item.epId == data.userStatus?.progress?.lastEpId, + ) ?? + data.episodes!.first + : data.episodes!.first; + toVideoPage( + 'bvid=${episode.bvid}&cid=${episode.cid}&seasonId=${data.seasonId}&epId=${episode.epId}&type=${data.type}', + arguments: { + 'pic': episode.cover, + 'heroTag': Utils.makeHeroTag(episode.cid), + 'videoType': SearchType.media_bangumi, + 'bangumiItem': data, + if (progress != null) 'progress': int.tryParse(progress) + }, + preventDuplicates: false, + ); + } else { + SmartDialog.showToast(result['msg']); + } + } catch (e) { + SmartDialog.dismiss(); + SmartDialog.showToast('$e'); + debugPrint('$e'); + } + } + + static void toDupNamed( + String page, { + dynamic arguments, + Map? parameters, + bool off = false, + }) { + if (off) { + Get.offNamed( + page, + arguments: arguments, + parameters: parameters, + preventDuplicates: false, + ); + } else { + Get.toNamed( + page, + arguments: arguments, + parameters: parameters, + preventDuplicates: false, + ); + } + } +} diff --git a/lib/utils/request_utils.dart b/lib/utils/request_utils.dart new file mode 100644 index 000000000..799edf17b --- /dev/null +++ b/lib/utils/request_utils.dart @@ -0,0 +1,386 @@ +import 'dart:convert'; +import 'dart:math'; + +import 'package:PiliPlus/common/widgets/radio_widget.dart'; +import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart'; +import 'package:PiliPlus/http/constants.dart'; +import 'package:PiliPlus/http/dynamics.dart'; +import 'package:PiliPlus/http/init.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/http/member.dart'; +import 'package:PiliPlus/http/user.dart'; +import 'package:PiliPlus/http/video.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; +import 'package:PiliPlus/models/user/fav_folder.dart'; +import 'package:PiliPlus/pages/common/multi_select_controller.dart'; +import 'package:PiliPlus/pages/dynamics/tab/controller.dart'; +import 'package:PiliPlus/pages/later/controller.dart'; +import 'package:PiliPlus/pages/video/detail/introduction/widgets/group_panel.dart'; +import 'package:PiliPlus/utils/accounts/account.dart'; +import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/feed_back.dart'; +import 'package:PiliPlus/utils/storage.dart'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; +import 'package:html/dom.dart' as dom; +import 'package:html/parser.dart' as html_parser; + +class RequestUtils { + static Future actionRelationMod({ + required BuildContext context, + required dynamic mid, + required bool isFollow, + required ValueChanged? callback, + Map? followStatus, + }) async { + if (mid == null) { + return; + } + feedBack(); + if (!isFollow) { + var res = await VideoHttp.relationMod( + mid: mid, + act: 1, + reSrc: 11, + ); + SmartDialog.showToast(res['status'] ? "关注成功" : res['msg']); + if (res['status']) { + callback?.call(2); + } + } else { + if (followStatus == null) { + Map result = await UserHttp.hasFollow(mid); + if (result['status']) { + followStatus = result['data']; + } else { + SmartDialog.showToast(result['msg']); + return; + } + } + if (context.mounted) { + showDialog( + context: context, + builder: (context) { + bool isSpecialFollowed = followStatus!['special'] == 1; + String text = isSpecialFollowed ? '移除特别关注' : '加入特别关注'; + return AlertDialog( + clipBehavior: Clip.hardEdge, + contentPadding: const EdgeInsets.symmetric(vertical: 12), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + dense: true, + onTap: () async { + Get.back(); + final res = await MemberHttp.specialAction( + fid: mid, + isAdd: !isSpecialFollowed, + ); + if (res['status']) { + SmartDialog.showToast('$text成功'); + callback?.call(-10); + } else { + SmartDialog.showToast(res['msg']); + } + }, + title: Text( + text, + style: const TextStyle(fontSize: 14), + ), + ), + ListTile( + dense: true, + onTap: () async { + Get.back(); + var result = await showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + backgroundColor: Theme.of(context).colorScheme.surface, + sheetAnimationStyle: AnimationStyle(curve: Curves.ease), + constraints: BoxConstraints( + maxWidth: min(640, min(Get.width, Get.height)), + ), + builder: (BuildContext context) { + return DraggableScrollableSheet( + minChildSize: 0, + maxChildSize: 1, + initialChildSize: 0.7, + snap: true, + expand: false, + snapSizes: const [0.7], + builder: (BuildContext context, + ScrollController scrollController) { + return GroupPanel( + mid: mid, + tags: followStatus!['tag'], + scrollController: scrollController, + ); + }, + ); + }, + ); + followStatus!['tag'] = result; + if (result != null) { + callback?.call(2); + } + }, + title: const Text( + '设置分组', + style: TextStyle(fontSize: 14), + ), + ), + ListTile( + dense: true, + onTap: () async { + Get.back(); + var res = await VideoHttp.relationMod( + mid: mid, + act: 2, + reSrc: 11, + ); + SmartDialog.showToast( + res['status'] ? "取消关注成功" : res['msg']); + if (res['status']) { + callback?.call(0); + } + }, + title: const Text( + '取消关注', + style: TextStyle(fontSize: 14), + ), + ), + ], + ), + ); + }, + ); + } + } + } + + static ReplyInfo replyCast(res) { + Map? emote = res['content']['emote']; + emote?.forEach((key, value) { + value['size'] = value['meta']['size']; + }); + return ReplyInfo.create() + ..mergeFromProto3Json( + res + ..['id'] = res['rpid'] + ..['member']['name'] = res['member']['uname'] + ..['member']['face'] = res['member']['avatar'] + ..['member']['level'] = res['member']['level_info']['current_level'] + ..['member']['vipStatus'] = res['member']['vip']['vipStatus'] + ..['member']['vipType'] = res['member']['vip']['vipType'] + ..['member']['officialVerifyType'] = + res['member']['official_verify']['type'] + ..['content']['emote'] = emote, + ignoreUnknownFields: true, + ); + } + + static Future getWwebid(mid) async { + try { + dynamic response = await Request().get( + '${HttpString.spaceBaseUrl}/$mid/dynamic', + options: Options( + extra: {'account': AnonymousAccount()}, + ), + ); + dom.Document document = html_parser.parse(response.data); + dom.Element? scriptElement = + document.querySelector('script#__RENDER_DATA__'); + return jsonDecode( + Uri.decodeComponent(scriptElement?.text ?? ''))['access_id']; + } catch (e) { + debugPrint('failed to get wwebid: $e'); + return null; + } + } + + static Future insertCreatedDyn(result) async { + try { + dynamic id = result['data']['dyn_id']; + if (id != null) { + await Future.delayed(const Duration(milliseconds: 200)); + dynamic res = await DynamicsHttp.dynamicDetail(id: id); + if (res['status']) { + final ctr = Get.find(tag: 'all'); + if (ctr.loadingState.value is Success) { + List? list = + (ctr.loadingState.value as Success).response; + if (list != null) { + list.insert(0, res['data']); + ctr.loadingState.refresh(); + return; + } + } + ctr.loadingState.value = LoadingState.success([res['data']]); + } + } + } catch (e) { + debugPrint('create dyn $e'); + } + } + + static Future checkCreatedDyn({id, dynText, isManual}) async { + if (isManual == true || GStorage.enableCreateDynAntifraud) { + try { + if (id != null) { + if (isManual != true) { + await Future.delayed(const Duration(seconds: 5)); + } + dynamic res = + await DynamicsHttp.dynamicDetail(id: id, clearCookie: true); + showDialog( + context: Get.context!, + builder: (context) => AlertDialog( + title: Text('动态检查结果'), + content: SelectableText( + '${res['status'] ? '无账号状态下找到了你的动态,动态正常!' : '你的动态被shadow ban(仅自己可见)!'}${dynText != null ? ' \n\n动态内容: $dynText' : ''}'), + ), + ); + } + } catch (e) { + debugPrint('check dyn error: $e'); + } + } + } + + // 动态点赞 + static Future onLikeDynamic(item, VoidCallback callback) async { + feedBack(); + String dynamicId = item.idStr!; + // 1 已点赞 2 不喜欢 0 未操作 + item.modules?.moduleStat ??= ModuleStatModel(); + item.modules?.moduleStat.like ??= Like(); + Like like = item.modules.moduleStat.like; + int count = like.count == '点赞' ? 0 : int.parse(like.count ?? '0'); + bool status = like.status ?? false; + int up = status ? 2 : 1; + var res = await DynamicsHttp.likeDynamic(dynamicId: dynamicId, up: up); + if (res['status']) { + SmartDialog.showToast(!status ? '点赞成功' : '取消赞'); + if (up == 1) { + item.modules.moduleStat.like.count = (count + 1).toString(); + item.modules.moduleStat.like.status = true; + } else { + if (count == 1) { + item.modules.moduleStat.like.count = '点赞'; + } else { + item.modules.moduleStat.like.count = (count - 1).toString(); + } + item.modules.moduleStat.like.status = false; + } + callback(); + } else { + SmartDialog.showToast(res['msg']); + } + } + + static void onCopyOrMove({ + required BuildContext context, + required bool isCopy, + required MultiSelectController ctr, + required dynamic mediaId, + required dynamic mid, + }) { + VideoHttp.allFavFolders(mid).then((res) { + if (context.mounted && + res['status'] && + (res['data'].list as List?)?.isNotEmpty == true) { + List list = res['data'].list; + dynamic checkedId; + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text('${isCopy ? '复制' : '移动'}到'), + contentPadding: const EdgeInsets.only(top: 5), + content: SingleChildScrollView( + child: Builder( + builder: (context) => Column( + children: List.generate(list.length, (index) { + return RadioWidget( + padding: const EdgeInsets.only(left: 14), + title: list[index].title ?? '', + groupValue: checkedId, + value: list[index].id, + onChanged: (value) { + checkedId = value; + if (context.mounted) { + (context as Element).markNeedsBuild(); + } + }, + ); + }), + ), + ), + ), + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: + TextStyle(color: Theme.of(context).colorScheme.outline), + ), + ), + TextButton( + onPressed: () { + if (checkedId != null) { + List resources = ((ctr.loadingState.value as Success) + .response as List) + .where((e) => e.checked == true) + .toList(); + SmartDialog.showLoading(); + VideoHttp.copyOrMoveFav( + isCopy: isCopy, + isFav: ctr is! LaterController, + srcMediaId: mediaId, + tarMediaId: checkedId, + resources: resources + .map((item) => ctr is LaterController + ? item.aid + : '${item.id}:${item.type}') + .toList(), + mid: isCopy ? mid : null, + ).then((res) { + if (res['status']) { + ctr.handleSelect(false); + if (isCopy.not) { + List dataList = + (ctr.loadingState.value as Success).response; + List remainList = dataList + .toSet() + .difference(resources.toSet()) + .toList(); + ctr.loadingState.value = + LoadingState.success(remainList); + } + SmartDialog.dismiss(); + SmartDialog.showToast('${isCopy ? '复制' : '移动'}成功'); + Get.back(); + } else { + SmartDialog.dismiss(); + SmartDialog.showToast('${res['msg']}'); + } + }); + } + }, + child: Text('确认'), + ), + ], + ); + }, + ); + } else { + SmartDialog.showToast('${res['msg']}'); + } + }); + } +} diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 2f5337f20..1f186b1ed 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -25,7 +25,7 @@ import 'package:PiliPlus/utils/accounts/account.dart'; import 'package:PiliPlus/utils/accounts/account_adapter.dart'; import 'package:PiliPlus/utils/accounts/cookie_jar_adapter.dart'; import 'package:PiliPlus/utils/accounts/account_type_adapter.dart'; -import 'package:PiliPlus/utils/login.dart'; +import 'package:PiliPlus/utils/login_utils.dart'; import 'package:PiliPlus/utils/set_int_adapter.dart'; import 'package:cookie_jar/cookie_jar.dart'; import 'package:flutter/material.dart'; diff --git a/lib/utils/theme_utils.dart b/lib/utils/theme_utils.dart new file mode 100644 index 000000000..b4f28c76c --- /dev/null +++ b/lib/utils/theme_utils.dart @@ -0,0 +1,155 @@ +import 'package:PiliPlus/main.dart'; +import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/storage.dart'; +import 'package:flex_seed_scheme/flex_seed_scheme.dart'; +import 'package:flutter/material.dart'; + +class ThemeUtils { + static ThemeData getThemeData({ + required ColorScheme colorScheme, + required bool isDynamic, + bool isDark = false, + required FlexSchemeVariant variant, + }) { + final appFontWeight = + GStorage.appFontWeight.clamp(-1, FontWeight.values.length - 1); + final fontWeight = + appFontWeight == -1 ? null : FontWeight.values[appFontWeight]; + late final textStyle = TextStyle(fontWeight: fontWeight); + ThemeData themeData = ThemeData( + colorScheme: colorScheme, + useMaterial3: true, + textTheme: fontWeight == null + ? null + : TextTheme( + displayLarge: textStyle, + displayMedium: textStyle, + displaySmall: textStyle, + headlineLarge: textStyle, + headlineMedium: textStyle, + headlineSmall: textStyle, + titleLarge: textStyle, + titleMedium: textStyle, + titleSmall: textStyle, + bodyLarge: textStyle, + bodyMedium: textStyle, + bodySmall: textStyle, + labelLarge: textStyle, + labelMedium: textStyle, + labelSmall: textStyle, + ), + tabBarTheme: + fontWeight == null ? null : TabBarTheme(labelStyle: textStyle), + appBarTheme: AppBarTheme( + elevation: 0, + titleSpacing: 0, + centerTitle: false, + scrolledUnderElevation: 0, + backgroundColor: isDynamic ? null : colorScheme.surface, + titleTextStyle: TextStyle( + fontSize: 16, + color: colorScheme.onSurface, + fontWeight: fontWeight, + ), + ), + navigationBarTheme: NavigationBarThemeData( + surfaceTintColor: isDynamic ? colorScheme.onSurfaceVariant : null, + ), + snackBarTheme: SnackBarThemeData( + actionTextColor: colorScheme.primary, + backgroundColor: colorScheme.secondaryContainer, + closeIconColor: colorScheme.secondary, + contentTextStyle: TextStyle(color: colorScheme.secondary), + elevation: 20, + ), + pageTransitionsTheme: const PageTransitionsTheme( + builders: { + TargetPlatform.android: ZoomPageTransitionsBuilder( + allowEnterRouteSnapshotting: false, + ), + }, + ), + popupMenuTheme: PopupMenuThemeData( + surfaceTintColor: isDynamic ? colorScheme.onSurfaceVariant : null, + ), + cardTheme: CardTheme( + elevation: 1, + surfaceTintColor: isDynamic + ? colorScheme.onSurfaceVariant + : isDark + ? colorScheme.onSurfaceVariant + : null, + shadowColor: Colors.transparent, + ), + // dialogTheme: DialogTheme( + // surfaceTintColor: isDark ? colorScheme.onSurfaceVariant : null, + // ), + progressIndicatorTheme: ProgressIndicatorThemeData( + refreshBackgroundColor: colorScheme.onSecondary, + ), + dialogTheme: DialogTheme( + titleTextStyle: TextStyle( + fontSize: 18, + color: colorScheme.onSurface, + fontWeight: fontWeight, + ), + ), + ); + if (isDark && GStorage.isPureBlackTheme) { + themeData = darkenTheme(themeData); + } + if (isDark && GStorage.darkVideoPage) { + MyApp.darkThemeData = themeData; + } + return themeData; + } + + static darkenTheme(ThemeData themeData) { + Color color = themeData.colorScheme.surfaceContainerHighest.darken(0.7); + return themeData.copyWith( + scaffoldBackgroundColor: Colors.black, + appBarTheme: themeData.appBarTheme.copyWith( + backgroundColor: Colors.black, + ), + cardTheme: themeData.cardTheme.copyWith( + color: Colors.black, + ), + dialogTheme: themeData.dialogTheme.copyWith( + backgroundColor: color, + ), + bottomSheetTheme: + themeData.bottomSheetTheme.copyWith(backgroundColor: color), + bottomNavigationBarTheme: + themeData.bottomNavigationBarTheme.copyWith(backgroundColor: color), + navigationBarTheme: + themeData.navigationBarTheme.copyWith(backgroundColor: color), + navigationRailTheme: + themeData.navigationRailTheme.copyWith(backgroundColor: Colors.black), + colorScheme: themeData.colorScheme.copyWith( + primary: themeData.colorScheme.primary.darken(0.1), + onPrimary: themeData.colorScheme.onPrimary.darken(0.1), + primaryContainer: themeData.colorScheme.primaryContainer.darken(0.1), + onPrimaryContainer: + themeData.colorScheme.onPrimaryContainer.darken(0.1), + inversePrimary: themeData.colorScheme.inversePrimary.darken(0.1), + secondary: themeData.colorScheme.secondary.darken(0.1), + onSecondary: themeData.colorScheme.onSecondary.darken(0.1), + secondaryContainer: + themeData.colorScheme.secondaryContainer.darken(0.1), + onSecondaryContainer: + themeData.colorScheme.onSecondaryContainer.darken(0.1), + error: themeData.colorScheme.error.darken(0.1), + surface: Colors.black, + onSurface: themeData.colorScheme.onSurface.darken(0.15), + surfaceTint: themeData.colorScheme.surfaceTint.darken(), + inverseSurface: themeData.colorScheme.inverseSurface.darken(), + onInverseSurface: themeData.colorScheme.onInverseSurface.darken(), + surfaceContainer: themeData.colorScheme.surfaceContainer.darken(), + surfaceContainerHigh: + themeData.colorScheme.surfaceContainerHigh.darken(), + surfaceContainerHighest: + themeData.colorScheme.surfaceContainerHighest.darken(0.4), + ), + ); + } +} diff --git a/lib/utils/url_utils.dart b/lib/utils/url_utils.dart index 451d2ef79..104f8a3d1 100644 --- a/lib/utils/url_utils.dart +++ b/lib/utils/url_utils.dart @@ -1,3 +1,4 @@ +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -65,7 +66,7 @@ class UrlUtils { String? bvid = matchRes['BV']; bvid ??= IdUtils.av2bv(aid!); final int cid = await SearchHttp.ab2c(aid: aid, bvid: bvid); - Utils.toViewPage( + PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { 'pic': '', @@ -75,7 +76,7 @@ class UrlUtils { ); } else { if (redirectUrl.isNotEmpty) { - Utils.handleWebview(redirectUrl); + PageUtils.handleWebview(redirectUrl); } else { SmartDialog.showToast('matchUrlPush: $pathSegment'); } diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index d60b3393b..098f60f92 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -4,52 +4,19 @@ import 'dart:io'; import 'dart:math'; import 'package:PiliPlus/build_config.dart'; import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'; -import 'package:PiliPlus/common/widgets/radio_widget.dart'; -import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart'; import 'package:PiliPlus/http/api.dart'; -import 'package:PiliPlus/http/constants.dart'; -import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/init.dart'; -import 'package:PiliPlus/http/loading_state.dart'; -import 'package:PiliPlus/http/member.dart'; -import 'package:PiliPlus/http/search.dart'; -import 'package:PiliPlus/http/user.dart'; -import 'package:PiliPlus/http/video.dart'; -import 'package:PiliPlus/main.dart'; -import 'package:PiliPlus/models/bangumi/info.dart'; -import 'package:PiliPlus/models/common/search_type.dart'; -import 'package:PiliPlus/models/dynamics/result.dart'; -import 'package:PiliPlus/models/live/item.dart'; -import 'package:PiliPlus/models/user/fav_folder.dart'; -import 'package:PiliPlus/pages/common/multi_select_controller.dart'; -import 'package:PiliPlus/pages/dynamics/tab/controller.dart'; -import 'package:PiliPlus/pages/later/controller.dart'; -import 'package:PiliPlus/pages/video/detail/introduction/widgets/fav_panel.dart'; -import 'package:PiliPlus/pages/video/detail/introduction/widgets/group_panel.dart'; -import 'package:PiliPlus/pages/video/detail/introduction/widgets/menu_row.dart'; -import 'package:PiliPlus/services/shutdown_timer_service.dart'; -import 'package:PiliPlus/utils/accounts/account.dart'; -import 'package:PiliPlus/utils/app_scheme.dart'; import 'package:PiliPlus/utils/extension.dart'; -import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/global_data.dart'; -import 'package:PiliPlus/utils/id_utils.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; -import 'package:PiliPlus/utils/url_utils.dart'; import 'package:crypto/crypto.dart'; import 'package:device_info_plus/device_info_plus.dart'; -import 'package:dio/dio.dart'; -import 'package:flex_seed_scheme/flex_seed_scheme.dart'; -import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:share_plus/share_plus.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'package:html/dom.dart' as dom; -import 'package:html/parser.dart' as html_parser; import 'package:path/path.dart' as path; import 'package:uuid/v4.dart'; @@ -64,352 +31,6 @@ class Utils { static final _numRegExp = RegExp(r'([\d\.]+)([千万亿])?'); - static Future pushDynFromId(id, {bool off = false}) async { - SmartDialog.showLoading(); - dynamic res = await DynamicsHttp.dynamicDetail(id: id); - SmartDialog.dismiss(); - if (res['status']) { - DynamicItemModel data = res['data']; - if (data.basic?['comment_type'] == 12) { - Utils.toDupNamed( - '/htmlRender', - parameters: { - 'url': 'www.bilibili.com/opus/$id', - 'title': '', - 'id': id, - 'dynamicType': 'opus' - }, - off: off, - ); - } else { - Utils.toDupNamed( - '/dynamicDetail', - arguments: { - 'item': res['data'], - 'floor': 1, - 'action': 'detail', - }, - off: off, - ); - } - } else { - SmartDialog.showToast(res['msg']); - } - } - - static void reportVideo(int aid) { - Get.toNamed( - '/webview', - parameters: {'url': 'https://www.bilibili.com/appeal/?avid=$aid'}, - ); - } - - /// 定时关闭 - static void scheduleExit(BuildContext context, isFullScreen, - [bool isLive = false]) { - if (!context.mounted) { - return; - } - const List scheduleTimeChoices = [0, 15, 30, 45, 60]; - const TextStyle titleStyle = TextStyle(fontSize: 14); - if (isLive) { - shutdownTimerService.waitForPlayingCompleted = false; - } - Utils.showFSSheet( - context, - isFullScreen: () => isFullScreen, - child: StatefulBuilder( - builder: (_, setState) { - return Theme( - data: Theme.of(context), - child: Material( - color: Colors.transparent, - child: Container( - clipBehavior: Clip.hardEdge, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: const BorderRadius.all(Radius.circular(12)), - ), - margin: const EdgeInsets.all(12), - padding: const EdgeInsets.only(left: 14, right: 14), - child: ListView( - padding: - const EdgeInsets.symmetric(vertical: 0, horizontal: 20), - children: [ - const SizedBox(height: 10), - const Center(child: Text('定时关闭', style: titleStyle)), - const SizedBox(height: 10), - ...[ - ...[ - ...scheduleTimeChoices, - if (scheduleTimeChoices - .contains( - shutdownTimerService.scheduledExitInMinutes) - .not) - shutdownTimerService.scheduledExitInMinutes, - ]..sort(), - -1, - ].map( - (choice) => ListTile( - dense: true, - onTap: () { - if (choice == -1) { - showDialog( - context: context, - builder: (context) { - String duration = ''; - return AlertDialog( - title: const Text('自定义时长'), - content: TextField( - autofocus: true, - onChanged: (value) => duration = value, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.allow( - RegExp(r'\d+')), - ], - decoration: const InputDecoration( - suffixText: 'min'), - ), - actions: [ - TextButton( - onPressed: Get.back, - child: Text( - '取消', - style: TextStyle( - color: Theme.of(context) - .colorScheme - .outline), - ), - ), - TextButton( - onPressed: () { - Get.back(); - int choice = - int.tryParse(duration) ?? 0; - shutdownTimerService - .scheduledExitInMinutes = choice; - shutdownTimerService - .startShutdownTimer(); - setState(() {}); - }, - child: Text('确定'), - ), - ], - ); - }, - ); - } else { - Get.back(); - shutdownTimerService.scheduledExitInMinutes = - choice; - shutdownTimerService.startShutdownTimer(); - } - }, - contentPadding: const EdgeInsets.only(), - title: Text(choice == -1 - ? '自定义' - : choice == 0 - ? "禁用" - : "$choice分钟后"), - trailing: shutdownTimerService.scheduledExitInMinutes == - choice - ? Icon( - Icons.done, - color: Theme.of(context).colorScheme.primary, - ) - : null, - ), - ), - const SizedBox(height: 6), - const Center( - child: SizedBox( - width: 125, - child: Divider(height: 1), - ), - ), - if (isLive.not) ...[ - const SizedBox(height: 10), - ListTile( - dense: true, - onTap: () { - shutdownTimerService.waitForPlayingCompleted = - !shutdownTimerService.waitForPlayingCompleted; - setState(() {}); - }, - contentPadding: const EdgeInsets.only(), - title: const Text("额外等待视频播放完毕", style: titleStyle), - 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; - }), - value: shutdownTimerService.waitForPlayingCompleted, - onChanged: (value) => setState(() => - shutdownTimerService.waitForPlayingCompleted = - value), - ), - ), - ), - ], - const SizedBox(height: 10), - Row( - children: [ - const Text('倒计时结束:', style: titleStyle), - const Spacer(), - ActionRowLineItem( - onTap: () { - shutdownTimerService.exitApp = false; - setState(() {}); - // Get.back(); - }, - text: " 暂停视频 ", - selectStatus: !shutdownTimerService.exitApp, - ), - const Spacer(), - // const SizedBox(width: 10), - ActionRowLineItem( - onTap: () { - shutdownTimerService.exitApp = true; - setState(() {}); - // Get.back(); - }, - text: " 退出APP ", - selectStatus: shutdownTimerService.exitApp, - ) - ], - ), - const SizedBox(height: 10), - ], - ), - ), - ), - ); - }, - ), - ); - } - - static void enterPip(Floating floating, int width, int height) { - Rational aspectRatio = Rational(width, height); - floating.enable( - EnableManual( - aspectRatio: aspectRatio.fitsInAndroidRequirements - ? aspectRatio - : height > width - ? const Rational.vertical() - : const Rational.landscape(), - ), - ); - } - - static ThemeData getThemeData({ - required ColorScheme colorScheme, - required bool isDynamic, - bool isDark = false, - required FlexSchemeVariant variant, - }) { - final appFontWeight = - GStorage.appFontWeight.clamp(-1, FontWeight.values.length - 1); - final fontWeight = - appFontWeight == -1 ? null : FontWeight.values[appFontWeight]; - late final textStyle = TextStyle(fontWeight: fontWeight); - ThemeData themeData = ThemeData( - colorScheme: colorScheme, - useMaterial3: true, - textTheme: fontWeight == null - ? null - : TextTheme( - displayLarge: textStyle, - displayMedium: textStyle, - displaySmall: textStyle, - headlineLarge: textStyle, - headlineMedium: textStyle, - headlineSmall: textStyle, - titleLarge: textStyle, - titleMedium: textStyle, - titleSmall: textStyle, - bodyLarge: textStyle, - bodyMedium: textStyle, - bodySmall: textStyle, - labelLarge: textStyle, - labelMedium: textStyle, - labelSmall: textStyle, - ), - tabBarTheme: - fontWeight == null ? null : TabBarTheme(labelStyle: textStyle), - appBarTheme: AppBarTheme( - elevation: 0, - titleSpacing: 0, - centerTitle: false, - scrolledUnderElevation: 0, - backgroundColor: isDynamic ? null : colorScheme.surface, - titleTextStyle: TextStyle( - fontSize: 16, - color: colorScheme.onSurface, - fontWeight: fontWeight, - ), - ), - navigationBarTheme: NavigationBarThemeData( - surfaceTintColor: isDynamic ? colorScheme.onSurfaceVariant : null, - ), - snackBarTheme: SnackBarThemeData( - actionTextColor: colorScheme.primary, - backgroundColor: colorScheme.secondaryContainer, - closeIconColor: colorScheme.secondary, - contentTextStyle: TextStyle(color: colorScheme.secondary), - elevation: 20, - ), - pageTransitionsTheme: const PageTransitionsTheme( - builders: { - TargetPlatform.android: ZoomPageTransitionsBuilder( - allowEnterRouteSnapshotting: false, - ), - }, - ), - popupMenuTheme: PopupMenuThemeData( - surfaceTintColor: isDynamic ? colorScheme.onSurfaceVariant : null, - ), - cardTheme: CardTheme( - elevation: 1, - surfaceTintColor: isDynamic - ? colorScheme.onSurfaceVariant - : isDark - ? colorScheme.onSurfaceVariant - : null, - shadowColor: Colors.transparent, - ), - // dialogTheme: DialogTheme( - // surfaceTintColor: isDark ? colorScheme.onSurfaceVariant : null, - // ), - progressIndicatorTheme: ProgressIndicatorThemeData( - refreshBackgroundColor: colorScheme.onSecondary, - ), - dialogTheme: DialogTheme( - titleTextStyle: TextStyle( - fontSize: 18, - color: colorScheme.onSurface, - fontWeight: fontWeight, - ), - ), - ); - if (isDark && GStorage.isPureBlackTheme) { - themeData = Utils.darkenTheme(themeData); - } - if (isDark && GStorage.darkVideoPage) { - MyApp.darkThemeData = themeData; - } - return themeData; - } - static final regExp = RegExp(r'(@(\d+[a-z]_?)*)(\..*)?$', caseSensitive: false); @@ -464,347 +85,6 @@ class Utils { } } - static void toViewPage( - String page, { - dynamic arguments, - int? id, - bool preventDuplicates = true, - Map? parameters, - bool off = false, - }) { - if (off) { - Get.offNamed( - '/videoV?$page', - arguments: arguments, - id: id, - preventDuplicates: preventDuplicates, - parameters: parameters, - ); - } else { - Get.toNamed( - '/videoV?$page', - arguments: arguments, - id: id, - preventDuplicates: preventDuplicates, - parameters: parameters, - ); - } - } - - static Future insertCreatedDyn(result) async { - try { - dynamic id = result['data']['dyn_id']; - if (id != null) { - await Future.delayed(const Duration(milliseconds: 200)); - dynamic res = await DynamicsHttp.dynamicDetail(id: id); - if (res['status']) { - final ctr = Get.find(tag: 'all'); - if (ctr.loadingState.value is Success) { - List? list = - (ctr.loadingState.value as Success).response; - if (list != null) { - list.insert(0, res['data']); - ctr.loadingState.refresh(); - return; - } - } - ctr.loadingState.value = LoadingState.success([res['data']]); - } - } - } catch (e) { - debugPrint('create dyn $e'); - } - } - - static Future checkCreatedDyn({id, dynText, isManual}) async { - if (isManual == true || GStorage.enableCreateDynAntifraud) { - try { - if (id != null) { - if (isManual != true) { - await Future.delayed(const Duration(seconds: 5)); - } - dynamic res = - await DynamicsHttp.dynamicDetail(id: id, clearCookie: true); - showDialog( - context: Get.context!, - builder: (context) => AlertDialog( - title: Text('动态检查结果'), - content: SelectableText( - '${res['status'] ? '无账号状态下找到了你的动态,动态正常!' : '你的动态被shadow ban(仅自己可见)!'}${dynText != null ? ' \n\n动态内容: $dynText' : ''}'), - ), - ); - } - } catch (e) { - debugPrint('check dyn error: $e'); - } - } - } - - // 动态点赞 - static Future onLikeDynamic(item, VoidCallback callback) async { - feedBack(); - String dynamicId = item.idStr!; - // 1 已点赞 2 不喜欢 0 未操作 - item.modules?.moduleStat ??= ModuleStatModel(); - item.modules?.moduleStat.like ??= Like(); - Like like = item.modules.moduleStat.like; - int count = like.count == '点赞' ? 0 : int.parse(like.count ?? '0'); - bool status = like.status ?? false; - int up = status ? 2 : 1; - var res = await DynamicsHttp.likeDynamic(dynamicId: dynamicId, up: up); - if (res['status']) { - SmartDialog.showToast(!status ? '点赞成功' : '取消赞'); - if (up == 1) { - item.modules.moduleStat.like.count = (count + 1).toString(); - item.modules.moduleStat.like.status = true; - } else { - if (count == 1) { - item.modules.moduleStat.like.count = '点赞'; - } else { - item.modules.moduleStat.like.count = (count - 1).toString(); - } - item.modules.moduleStat.like.status = false; - } - callback(); - } else { - SmartDialog.showToast(res['msg']); - } - } - - static void showFSSheet( - BuildContext context, { - required Widget child, - required Function isFullScreen, - double? padding, - }) { - if (!context.mounted) { - return; - } - Get.generalDialog( - barrierLabel: '', - barrierDismissible: true, - pageBuilder: (buildContext, animation, secondaryAnimation) { - return MediaQuery.orientationOf(Get.context!) == Orientation.portrait - ? SafeArea( - child: Column( - children: [ - const Spacer(flex: 3), - Expanded(flex: 7, child: child), - if (isFullScreen() && padding != null) - SizedBox(height: padding), - ], - ), - ) - : SafeArea( - child: Row( - children: [ - const Spacer(), - Expanded(child: child), - ], - ), - ); - }, - transitionDuration: const Duration(milliseconds: 350), - transitionBuilder: (context, animation, secondaryAnimation, child) { - Offset begin = - MediaQuery.orientationOf(Get.context!) == Orientation.portrait - ? Offset(0.0, 1.0) - : Offset(1.0, 0.0); - var tween = Tween(begin: begin, end: Offset.zero) - .chain(CurveTween(curve: Curves.easeInOut)); - return SlideTransition( - position: animation.drive(tween), - child: child, - ); - }, - routeSettings: RouteSettings(arguments: Get.arguments), - ); - } - - static darkenTheme(ThemeData themeData) { - // return themeData; - Color color = themeData.colorScheme.surfaceContainerHighest.darken(0.7); - return themeData.copyWith( - scaffoldBackgroundColor: Colors.black, - appBarTheme: themeData.appBarTheme.copyWith( - backgroundColor: Colors.black, - ), - cardTheme: themeData.cardTheme.copyWith( - color: Colors.black, - ), - dialogTheme: themeData.dialogTheme.copyWith( - backgroundColor: color, - ), - bottomSheetTheme: - themeData.bottomSheetTheme.copyWith(backgroundColor: color), - bottomNavigationBarTheme: - themeData.bottomNavigationBarTheme.copyWith(backgroundColor: color), - navigationBarTheme: - themeData.navigationBarTheme.copyWith(backgroundColor: color), - navigationRailTheme: - themeData.navigationRailTheme.copyWith(backgroundColor: Colors.black), - colorScheme: themeData.colorScheme.copyWith( - primary: themeData.colorScheme.primary.darken(0.1), - onPrimary: themeData.colorScheme.onPrimary.darken(0.1), - primaryContainer: themeData.colorScheme.primaryContainer.darken(0.1), - onPrimaryContainer: - themeData.colorScheme.onPrimaryContainer.darken(0.1), - inversePrimary: themeData.colorScheme.inversePrimary.darken(0.1), - secondary: themeData.colorScheme.secondary.darken(0.1), - onSecondary: themeData.colorScheme.onSecondary.darken(0.1), - secondaryContainer: - themeData.colorScheme.secondaryContainer.darken(0.1), - onSecondaryContainer: - themeData.colorScheme.onSecondaryContainer.darken(0.1), - error: themeData.colorScheme.error.darken(0.1), - surface: Colors.black, - onSurface: themeData.colorScheme.onSurface.darken(0.15), - surfaceTint: themeData.colorScheme.surfaceTint.darken(), - inverseSurface: themeData.colorScheme.inverseSurface.darken(), - onInverseSurface: themeData.colorScheme.onInverseSurface.darken(), - surfaceContainer: themeData.colorScheme.surfaceContainer.darken(), - surfaceContainerHigh: - themeData.colorScheme.surfaceContainerHigh.darken(), - surfaceContainerHighest: - themeData.colorScheme.surfaceContainerHighest.darken(0.4), - ), - ); - } - - static void onCopyOrMove({ - required BuildContext context, - required bool isCopy, - required MultiSelectController ctr, - required dynamic mediaId, - required dynamic mid, - }) { - VideoHttp.allFavFolders(mid).then((res) { - if (context.mounted && - res['status'] && - (res['data'].list as List?)?.isNotEmpty == true) { - List list = res['data'].list; - dynamic checkedId; - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: Text('${isCopy ? '复制' : '移动'}到'), - contentPadding: const EdgeInsets.only(top: 5), - content: SingleChildScrollView( - child: Builder( - builder: (context) => Column( - children: List.generate(list.length, (index) { - return RadioWidget( - padding: const EdgeInsets.only(left: 14), - title: list[index].title ?? '', - groupValue: checkedId, - value: list[index].id, - onChanged: (value) { - checkedId = value; - if (context.mounted) { - (context as Element).markNeedsBuild(); - } - }, - ); - }), - ), - ), - ), - actions: [ - TextButton( - onPressed: Get.back, - child: Text( - '取消', - style: - TextStyle(color: Theme.of(context).colorScheme.outline), - ), - ), - TextButton( - onPressed: () { - if (checkedId != null) { - List resources = ((ctr.loadingState.value as Success) - .response as List) - .where((e) => e.checked == true) - .toList(); - SmartDialog.showLoading(); - VideoHttp.copyOrMoveFav( - isCopy: isCopy, - isFav: ctr is! LaterController, - srcMediaId: mediaId, - tarMediaId: checkedId, - resources: resources - .map((item) => ctr is LaterController - ? item.aid - : '${item.id}:${item.type}') - .toList(), - mid: isCopy ? mid : null, - ).then((res) { - if (res['status']) { - ctr.handleSelect(false); - if (isCopy.not) { - List dataList = - (ctr.loadingState.value as Success).response; - List remainList = dataList - .toSet() - .difference(resources.toSet()) - .toList(); - ctr.loadingState.value = - LoadingState.success(remainList); - } - SmartDialog.dismiss(); - SmartDialog.showToast('${isCopy ? '复制' : '移动'}成功'); - Get.back(); - } else { - SmartDialog.dismiss(); - SmartDialog.showToast('${res['msg']}'); - } - }); - } - }, - child: Text('确认'), - ), - ], - ); - }, - ); - } else { - SmartDialog.showToast('${res['msg']}'); - } - }); - } - - static void showFavBottomSheet({ - required BuildContext context, - required dynamic ctr, - }) { - showModalBottomSheet( - context: context, - useSafeArea: true, - isScrollControlled: true, - backgroundColor: Theme.of(context).colorScheme.surface, - sheetAnimationStyle: AnimationStyle(curve: Curves.ease), - constraints: BoxConstraints( - maxWidth: min(640, min(Get.width, Get.height)), - ), - builder: (BuildContext context) { - return DraggableScrollableSheet( - minChildSize: 0, - maxChildSize: 1, - initialChildSize: 0.7, - snap: true, - expand: false, - snapSizes: const [0.7], - builder: (BuildContext context, ScrollController scrollController) { - return FavPanel( - ctr: ctr, - scrollController: scrollController, - ); - }, - ); - }, - ); - } - static String buildShadersAbsolutePath( String baseDirectory, List shaders) { List absolutePaths = shaders.map((shader) { @@ -813,257 +93,6 @@ class Utils { return absolutePaths.join(':'); } - static void pushDynDetail(item, floor, {action = 'all'}) async { - feedBack(); - - /// 点击评论action 直接查看评论 - if (action == 'comment') { - Utils.toDupNamed( - '/dynamicDetail', - arguments: { - 'item': item, - 'floor': floor, - 'action': action, - }, - ); - return; - } - - debugPrint('pushDynDetail: ${item.type}'); - - switch (item.type) { - case 'DYNAMIC_TYPE_AV': - if (item.modules.moduleDynamic.major.archive?.type == 2) { - if (item.modules.moduleDynamic.major.archive.jumpUrl - .startsWith('//')) { - item.modules.moduleDynamic.major.archive.jumpUrl = - 'https:${item.modules.moduleDynamic.major.archive.jumpUrl}'; - } - String? redirectUrl = await UrlUtils.parseRedirectUrl( - item.modules.moduleDynamic.major.archive.jumpUrl, false); - if (redirectUrl != null) { - Utils.viewPgcFromUri(redirectUrl); - return; - } - } - - try { - String bvid = item.modules.moduleDynamic.major.archive.bvid; - String cover = item.modules.moduleDynamic.major.archive.cover; - int cid = await SearchHttp.ab2c(bvid: bvid); - Utils.toViewPage( - 'bvid=$bvid&cid=$cid', - arguments: { - 'pic': cover, - 'heroTag': Utils.makeHeroTag(bvid), - }, - preventDuplicates: false, - ); - } catch (err) { - SmartDialog.showToast(err.toString()); - } - break; - - /// 专栏文章查看 - case 'DYNAMIC_TYPE_ARTICLE': - String? url = item?.modules?.moduleDynamic?.major?.opus?.jumpUrl; - if (url != null) { - String? title = item?.modules?.moduleDynamic?.major?.opus?.title; - if (url.contains('opus') || url.contains('read')) { - RegExp digitRegExp = RegExp(r'\d+'); - Iterable matches = digitRegExp.allMatches(url); - String number = matches.first.group(0)!; - if (url.contains('read')) { - number = 'cv$number'; - } - Utils.toDupNamed('/htmlRender', parameters: { - 'url': url.startsWith('//') ? url.split('//').last : url, - 'title': title ?? '', - 'id': number, - 'dynamicType': url.split('//').last.split('/')[1] - }); - } else { - Utils.handleWebview('https:$url'); - } - } - - break; - case 'DYNAMIC_TYPE_PGC': - debugPrint('番剧'); - SmartDialog.showToast('暂未支持的类型,请联系开发者'); - break; - - case 'DYNAMIC_TYPE_LIVE_RCMD': - DynamicLiveModel liveRcmd = item.modules.moduleDynamic.major.liveRcmd; - ModuleAuthorModel author = item.modules.moduleAuthor; - LiveItemModel liveItem = LiveItemModel.fromJson({ - 'title': liveRcmd.title, - 'uname': author.name, - 'cover': liveRcmd.cover, - 'mid': author.mid, - 'face': author.face, - 'roomid': liveRcmd.roomId, - 'watched_show': liveRcmd.watchedShow, - }); - Utils.toDupNamed('/liveRoom?roomid=${liveItem.roomId}'); - break; - - /// 合集查看 - case 'DYNAMIC_TYPE_UGC_SEASON': - DynamicArchiveModel ugcSeason = - item.modules.moduleDynamic.major.ugcSeason; - int aid = ugcSeason.aid!; - String bvid = IdUtils.av2bv(aid); - String cover = ugcSeason.cover!; - int cid = await SearchHttp.ab2c(bvid: bvid); - Utils.toViewPage( - 'bvid=$bvid&cid=$cid', - arguments: { - 'pic': cover, - 'heroTag': Utils.makeHeroTag(bvid), - }, - preventDuplicates: false, - ); - break; - - /// 番剧查看 - case 'DYNAMIC_TYPE_PGC_UNION': - debugPrint('DYNAMIC_TYPE_PGC_UNION 番剧'); - DynamicArchiveModel pgc = item.modules.moduleDynamic.major.pgc; - if (pgc.epid != null) { - Utils.viewBangumi(epId: pgc.epid); - } - break; - case 'DYNAMIC_TYPE_MEDIALIST': - if (item.modules?.moduleDynamic?.major?.medialist != null) { - final String? url = - item.modules.moduleDynamic.major.medialist['jump_url']; - if (url?.contains('medialist/detail/ml') == true) { - Get.toNamed( - '/favDetail', - parameters: { - 'heroTag': - '${item.modules.moduleDynamic.major.medialist['cover']}', - 'mediaId': - '${item.modules.moduleDynamic.major.medialist['id']}', - }, - ); - } else if (url != null) { - handleWebview(url.http2https); - } - } - break; - - // 纯文字动态查看 - // case 'DYNAMIC_TYPE_WORD': - // # 装扮/剧集点评/普通分享 - // case 'DYNAMIC_TYPE_COMMON_SQUARE': - // 转发的动态 - // case 'DYNAMIC_TYPE_FORWARD': - // 图文动态查看 - // case 'DYNAMIC_TYPE_DRAW': - default: - Utils.toDupNamed( - '/dynamicDetail', - arguments: { - 'item': item, - 'floor': floor, - }, - ); - break; - } - } - - static void onHorizontalPreview( - GlobalKey key, - transitionAnimationController, - ctr, - List imgList, - index, - onClose, - ) { - key.currentState?.showBottomSheet( - (context) { - return FadeTransition( - opacity: Tween(begin: 0, end: 1).animate(ctr), - child: InteractiveviewerGallery( - sources: imgList.map((url) => SourceModel(url: url)).toList(), - initIndex: index, - setStatusBar: false, - onClose: onClose, - ), - ); - }, - enableDrag: false, - elevation: 0, - backgroundColor: Colors.transparent, - transitionAnimationController: transitionAnimationController, - sheetAnimationStyle: AnimationStyle(duration: Duration.zero), - ); - } - - static void inAppWebview( - String url, { - bool off = false, - }) { - if (GStorage.openInBrowser) { - launchURL(url); - } else { - if (off) { - Get.offNamed( - '/webview', - parameters: {'url': url}, - arguments: {'inApp': true}, - ); - } else { - Get.toNamed( - '/webview', - parameters: {'url': url}, - arguments: {'inApp': true}, - ); - } - } - } - - static void handleWebview( - String url, { - bool off = false, - bool inApp = false, - Map? parameters, - }) async { - if (inApp.not && GStorage.openInBrowser) { - if ((await PiliScheme.routePushFromUrl(url, selfHandle: true)).not) { - launchURL(url); - } - } else { - if (off) { - Get.offNamed( - '/webview', - parameters: { - 'url': url, - if (parameters != null) ...parameters, - }, - ); - } else { - PiliScheme.routePushFromUrl(url, parameters: parameters); - } - } - } - - static bool viewPgcFromUri(String uri) { - String? id = RegExp(r'(ep|ss)\d+').firstMatch(uri)?.group(0); - if (id != null) { - bool isSeason = id.startsWith('ss'); - id = id.substring(2); - Utils.viewBangumi( - seasonId: isSeason ? id : null, - epId: isSeason ? null : id, - ); - return true; - } - return false; - } - static void showCopyTextDialog(text) { Get.dialog( AlertDialog( @@ -1072,197 +101,23 @@ class Utils { ); } - static Future getWwebid(mid) async { - try { - dynamic response = await Request().get( - '${HttpString.spaceBaseUrl}/$mid/dynamic', - options: Options( - extra: {'account': AnonymousAccount()}, - ), - ); - dom.Document document = html_parser.parse(response.data); - dom.Element? scriptElement = - document.querySelector('script#__RENDER_DATA__'); - return jsonDecode( - Uri.decodeComponent(scriptElement?.text ?? ''))['access_id']; - } catch (e) { - debugPrint('failed to get wwebid: $e'); - return null; - } - } - static bool isStringNumeric(str) { RegExp numericRegex = RegExp(r'^[\d\.]+$'); return numericRegex.hasMatch(str.toString()); } - static ReplyInfo replyCast(res) { - Map? emote = res['content']['emote']; - emote?.forEach((key, value) { - value['size'] = value['meta']['size']; - }); - return ReplyInfo.create() - ..mergeFromProto3Json( - res - ..['id'] = res['rpid'] - ..['member']['name'] = res['member']['uname'] - ..['member']['face'] = res['member']['avatar'] - ..['member']['level'] = res['member']['level_info']['current_level'] - ..['member']['vipStatus'] = res['member']['vip']['vipStatus'] - ..['member']['vipType'] = res['member']['vip']['vipType'] - ..['member']['officialVerifyType'] = - res['member']['official_verify']['type'] - ..['content']['emote'] = emote, - ignoreUnknownFields: true, - ); - } - - static bool isDefault(int attr) { + static bool isDefaultFav(int attr) { return (attr & 2) == 0; } - static String isPublicText(int attr) { - return isPublic(attr) ? '公开' : '私密'; + static String isPublicFavText(int attr) { + return isPublicFav(attr) ? '公开' : '私密'; } - static bool isPublic(int attr) { + static bool isPublicFav(int attr) { return (attr & 1) == 0; } - static Future actionRelationMod({ - required BuildContext context, - required dynamic mid, - required bool isFollow, - required ValueChanged? callback, - Map? followStatus, - }) async { - if (mid == null) { - return; - } - feedBack(); - if (!isFollow) { - var res = await VideoHttp.relationMod( - mid: mid, - act: 1, - reSrc: 11, - ); - SmartDialog.showToast(res['status'] ? "关注成功" : res['msg']); - if (res['status']) { - callback?.call(2); - } - } else { - if (followStatus == null) { - Map result = await UserHttp.hasFollow(mid); - if (result['status']) { - followStatus = result['data']; - } else { - SmartDialog.showToast(result['msg']); - return; - } - } - if (context.mounted) { - showDialog( - context: context, - builder: (context) { - bool isSpecialFollowed = followStatus!['special'] == 1; - String text = isSpecialFollowed ? '移除特别关注' : '加入特别关注'; - return AlertDialog( - clipBehavior: Clip.hardEdge, - contentPadding: const EdgeInsets.symmetric(vertical: 12), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - ListTile( - dense: true, - onTap: () async { - Get.back(); - final res = await MemberHttp.specialAction( - fid: mid, - isAdd: !isSpecialFollowed, - ); - if (res['status']) { - SmartDialog.showToast('$text成功'); - callback?.call(-10); - } else { - SmartDialog.showToast(res['msg']); - } - }, - title: Text( - text, - style: const TextStyle(fontSize: 14), - ), - ), - ListTile( - dense: true, - onTap: () async { - Get.back(); - var result = await showModalBottomSheet( - context: context, - useSafeArea: true, - isScrollControlled: true, - backgroundColor: Theme.of(context).colorScheme.surface, - sheetAnimationStyle: AnimationStyle(curve: Curves.ease), - constraints: BoxConstraints( - maxWidth: min(640, min(Get.width, Get.height)), - ), - builder: (BuildContext context) { - return DraggableScrollableSheet( - minChildSize: 0, - maxChildSize: 1, - initialChildSize: 0.7, - snap: true, - expand: false, - snapSizes: const [0.7], - builder: (BuildContext context, - ScrollController scrollController) { - return GroupPanel( - mid: mid, - tags: followStatus!['tag'], - scrollController: scrollController, - ); - }, - ); - }, - ); - followStatus!['tag'] = result; - if (result != null) { - callback?.call(2); - } - }, - title: const Text( - '设置分组', - style: TextStyle(fontSize: 14), - ), - ), - ListTile( - dense: true, - onTap: () async { - Get.back(); - var res = await VideoHttp.relationMod( - mid: mid, - act: 2, - reSrc: 11, - ); - SmartDialog.showToast( - res['status'] ? "取消关注成功" : res['msg']); - if (res['status']) { - callback?.call(0); - } - }, - title: const Text( - '取消关注', - style: TextStyle(fontSize: 14), - ), - ), - ], - ), - ); - }, - ); - } - } - } - static String generateRandomString(int length) { const characters = '0123456789abcdefghijklmnopqrstuvwxyz'; @@ -1317,106 +172,6 @@ class Utils { return '${randomTraceId.toString()}:${randomTraceId.toString().substring(16, 32)}:0:0'; } - static void viewBangumi( - {dynamic seasonId, dynamic epId, dynamic progress}) async { - try { - SmartDialog.showLoading(msg: '资源获取中'); - var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId); - SmartDialog.dismiss(); - if (result['status']) { - BangumiInfoModel data = result['data']; - - // epId episode -> progress episode -> first episode - EpisodeItem? episode; - - if (epId != null) { - if (data.episodes?.isNotEmpty == true) { - episode = data.episodes!.firstWhereOrNull( - (item) { - return item.epId.toString() == epId.toString(); - }, - ); - } - if (episode == null && data.section?.isNotEmpty == true) { - for (Section item in data.section!) { - if (item.episodes?.isNotEmpty == true) { - for (EpisodeItem item in item.episodes!) { - if (item.epId.toString() == epId.toString()) { - // view as normal video - Utils.toViewPage( - 'bvid=${item.bvid}&cid=${item.cid}&seasonId=${data.seasonId}&epId=${item.epId}', - arguments: { - 'pgcApi': true, - 'pic': item.cover, - 'heroTag': Utils.makeHeroTag(item.cid), - 'videoType': SearchType.video, - if (progress != null) 'progress': int.tryParse(progress) - }, - preventDuplicates: false, - ); - return; - } - } - } - } - } - } - - if (data.episodes.isNullOrEmpty) { - SmartDialog.showToast('资源加载失败'); - return; - } - - episode ??= data.userStatus?.progress?.lastEpId != null - ? data.episodes!.firstWhereOrNull( - (item) => item.epId == data.userStatus?.progress?.lastEpId, - ) ?? - data.episodes!.first - : data.episodes!.first; - Utils.toViewPage( - 'bvid=${episode.bvid}&cid=${episode.cid}&seasonId=${data.seasonId}&epId=${episode.epId}&type=${data.type}', - arguments: { - 'pic': episode.cover, - 'heroTag': Utils.makeHeroTag(episode.cid), - 'videoType': SearchType.media_bangumi, - 'bangumiItem': data, - if (progress != null) 'progress': int.tryParse(progress) - }, - preventDuplicates: false, - ); - } else { - SmartDialog.showToast(result['msg']); - } - } catch (e) { - SmartDialog.dismiss(); - SmartDialog.showToast('$e'); - debugPrint('$e'); - } - } - - static void toDupNamed( - String page, { - dynamic arguments, - Map? parameters, - bool off = false, - }) { - if (off) { - Get.offNamed( - page, - arguments: arguments, - parameters: parameters, - preventDuplicates: false, - ); - } else { - Get.toNamed( - page, - arguments: arguments, - parameters: parameters, - preventDuplicates: false, - ); - } - } - static Future copyText( String text, { bool needToast = true, @@ -1428,20 +183,6 @@ class Utils { } } - static launchURL(String url) async { - try { - final Uri uri = Uri.parse(url); - if (!await launchUrl( - uri, - mode: LaunchMode.externalApplication, - )) { - SmartDialog.showToast('Could not launch $url'); - } - } catch (e) { - SmartDialog.showToast(e.toString()); - } - } - // static Future getCookiePath() async { // final Directory tempDir = await getApplicationSupportDirectory(); // final String tempPath = "${tempDir.path}/.plpl/"; @@ -1802,7 +543,7 @@ class Utils { Text('${res.data[0]['body']}'), TextButton( onPressed: () { - launchURL( + PageUtils.launchURL( 'https://github.com/bggRGjQaUbCoE/PiliPlus/commits/main'); }, child: Text( @@ -1862,7 +603,7 @@ class Utils { if (data['assets'].isNotEmpty) { for (dynamic i in data['assets']) { if (i['name'].contains(plat)) { - launchURL(i['browser_download_url']); + PageUtils.launchURL(i['browser_download_url']); break; } } @@ -1878,7 +619,8 @@ class Utils { download('ios'); } } catch (_) { - launchURL('https://github.com/bggRGjQaUbCoE/PiliPlus/releases/latest'); + PageUtils.launchURL( + 'https://github.com/bggRGjQaUbCoE/PiliPlus/releases/latest'); } }