mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt: item
opt: util Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
747
lib/utils/page_utils.dart
Normal file
747
lib/utils/page_utils.dart
Normal file
@@ -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<int> 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<Icon?>(
|
||||
(Set<WidgetState> 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<Match> 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<ScaffoldState> key,
|
||||
transitionAnimationController,
|
||||
ctr,
|
||||
List<String> imgList,
|
||||
index,
|
||||
onClose,
|
||||
) {
|
||||
key.currentState?.showBottomSheet(
|
||||
(context) {
|
||||
return FadeTransition(
|
||||
opacity: Tween<double>(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<String, String>? 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<String, String>? 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user