mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
refa: video model (#523)
This commit is contained in:
committed by
GitHub
parent
bf464994df
commit
7a6085e923
@@ -1,5 +1,6 @@
|
|||||||
import 'package:PiliPlus/common/widgets/no_splash_factory.dart';
|
import 'package:PiliPlus/common/widgets/no_splash_factory.dart';
|
||||||
import 'package:PiliPlus/common/widgets/overlay_pop.dart';
|
import 'package:PiliPlus/common/widgets/overlay_pop.dart';
|
||||||
|
import 'package:PiliPlus/models/model_video.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AnimatedDialog extends StatefulWidget {
|
class AnimatedDialog extends StatefulWidget {
|
||||||
@@ -9,7 +10,7 @@ class AnimatedDialog extends StatefulWidget {
|
|||||||
required this.closeFn,
|
required this.closeFn,
|
||||||
});
|
});
|
||||||
|
|
||||||
final dynamic videoItem;
|
final BaseVideoItemModel videoItem;
|
||||||
final Function closeFn;
|
final Function closeFn;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -42,13 +42,10 @@ abstract class _StatItemBase extends StatelessWidget {
|
|||||||
const SizedBox(width: 2),
|
const SizedBox(width: 2),
|
||||||
Text(
|
Text(
|
||||||
Utils.numFormat(value),
|
Utils.numFormat(value),
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: size == 'medium' ? 12 : 11, color: color),
|
||||||
fontSize: size == 'medium' ? 12 : 11,
|
|
||||||
color: color,
|
|
||||||
),
|
|
||||||
overflow: TextOverflow.clip,
|
overflow: TextOverflow.clip,
|
||||||
semanticsLabel: semanticsLabel,
|
semanticsLabel: semanticsLabel,
|
||||||
),
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import 'package:PiliPlus/common/widgets/image_save.dart';
|
import 'package:PiliPlus/common/widgets/image_save.dart';
|
||||||
import 'package:PiliPlus/models/model_hot_video_item.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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import '../../http/search.dart';
|
import '../../http/search.dart';
|
||||||
@@ -24,7 +26,7 @@ class VideoCardH extends StatelessWidget {
|
|||||||
this.onLongPress,
|
this.onLongPress,
|
||||||
this.onViewLater,
|
this.onViewLater,
|
||||||
});
|
});
|
||||||
final dynamic videoItem;
|
final BaseVideoItemModel videoItem;
|
||||||
final String source;
|
final String source;
|
||||||
final bool showOwner;
|
final bool showOwner;
|
||||||
final bool showView;
|
final bool showView;
|
||||||
@@ -36,12 +38,18 @@ class VideoCardH extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final int aid = videoItem.aid;
|
final int aid = videoItem.aid!;
|
||||||
final String bvid = videoItem.bvid;
|
final String bvid = videoItem.bvid!;
|
||||||
String type = 'video';
|
String type = 'video';
|
||||||
try {
|
// try {
|
||||||
type = videoItem.type;
|
// type = videoItem.type;
|
||||||
} catch (_) {}
|
// } catch (_) {}
|
||||||
|
if (videoItem is SearchVideoItemModel) {
|
||||||
|
var typeOrNull = (videoItem as SearchVideoItemModel).type;
|
||||||
|
if (typeOrNull?.isNotEmpty == true) {
|
||||||
|
type = typeOrNull!;
|
||||||
|
}
|
||||||
|
}
|
||||||
return Material(
|
return Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
child: Stack(
|
child: Stack(
|
||||||
@@ -61,13 +69,7 @@ class VideoCardH extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
imageSaveDialog(
|
imageSaveDialog(
|
||||||
context: context,
|
context: context,
|
||||||
title: videoItem.title is String
|
title: videoItem.title,
|
||||||
? videoItem.title
|
|
||||||
: videoItem.title is List
|
|
||||||
? (videoItem.title as List)
|
|
||||||
.map((item) => item['text'])
|
|
||||||
.join()
|
|
||||||
: '',
|
|
||||||
cover: videoItem.pic,
|
cover: videoItem.pic,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -81,9 +83,11 @@ class VideoCardH extends StatelessWidget {
|
|||||||
SmartDialog.showToast('课堂视频暂不支持播放');
|
SmartDialog.showToast('课堂视频暂不支持播放');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (videoItem is HotVideoItemModel &&
|
if ((videoItem is HotVideoItemModel) &&
|
||||||
videoItem.redirectUrl?.isNotEmpty == true) {
|
(videoItem as HotVideoItemModel).redirectUrl?.isNotEmpty ==
|
||||||
if (Utils.viewPgcFromUri(videoItem.redirectUrl!)) {
|
true) {
|
||||||
|
if (Utils.viewPgcFromUri(
|
||||||
|
(videoItem as HotVideoItemModel).redirectUrl!)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,20 +128,24 @@ class VideoCardH extends StatelessWidget {
|
|||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
NetworkImgLayer(
|
NetworkImgLayer(
|
||||||
src: videoItem.pic as String,
|
src: videoItem.pic,
|
||||||
width: maxWidth,
|
width: maxWidth,
|
||||||
height: maxHeight,
|
height: maxHeight,
|
||||||
),
|
),
|
||||||
if (videoItem is HotVideoItemModel &&
|
if (videoItem is HotVideoItemModel &&
|
||||||
videoItem.pgcLabel?.isNotEmpty == true)
|
(videoItem as HotVideoItemModel)
|
||||||
|
.pgcLabel
|
||||||
|
?.isNotEmpty ==
|
||||||
|
true)
|
||||||
PBadge(
|
PBadge(
|
||||||
text: videoItem.pgcLabel,
|
text:
|
||||||
|
(videoItem as HotVideoItemModel).pgcLabel,
|
||||||
top: 6.0,
|
top: 6.0,
|
||||||
right: 6.0,
|
right: 6.0,
|
||||||
),
|
),
|
||||||
if (videoItem.duration != 0)
|
if (videoItem.duration > 0)
|
||||||
PBadge(
|
PBadge(
|
||||||
text: Utils.timeFormat(videoItem.duration!),
|
text: Utils.timeFormat(videoItem.duration),
|
||||||
right: 6.0,
|
right: 6.0,
|
||||||
bottom: 6.0,
|
bottom: 6.0,
|
||||||
type: 'gray',
|
type: 'gray',
|
||||||
@@ -180,7 +188,7 @@ class VideoCardH extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget videoContent(context) {
|
Widget videoContent(BuildContext context) {
|
||||||
String pubdate = showPubdate
|
String pubdate = showPubdate
|
||||||
? Utils.dateFormat(videoItem.pubdate!, formatType: 'day')
|
? Utils.dateFormat(videoItem.pubdate!, formatType: 'day')
|
||||||
: '';
|
: '';
|
||||||
@@ -189,7 +197,33 @@ class VideoCardH extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (videoItem.title is String)
|
if ((videoItem is SearchVideoItemModel) &&
|
||||||
|
(videoItem as SearchVideoItemModel).titleList?.isNotEmpty == true)
|
||||||
|
Expanded(
|
||||||
|
child: Text.rich(
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
maxLines: 2,
|
||||||
|
TextSpan(
|
||||||
|
children: [
|
||||||
|
for (var i
|
||||||
|
in (videoItem as SearchVideoItemModel).titleList!)
|
||||||
|
TextSpan(
|
||||||
|
text: i['text'],
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize:
|
||||||
|
Theme.of(context).textTheme.bodyMedium!.fontSize,
|
||||||
|
height: 1.42,
|
||||||
|
letterSpacing: 0.3,
|
||||||
|
color: i['type'] == 'em'
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Theme.of(context).colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
else
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
videoItem.title,
|
videoItem.title,
|
||||||
@@ -202,31 +236,6 @@ class VideoCardH extends StatelessWidget {
|
|||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
)
|
|
||||||
else
|
|
||||||
Expanded(
|
|
||||||
child: Text.rich(
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
maxLines: 2,
|
|
||||||
TextSpan(
|
|
||||||
children: [
|
|
||||||
for (final i in videoItem.title) ...[
|
|
||||||
TextSpan(
|
|
||||||
text: i['text'] as String,
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize:
|
|
||||||
Theme.of(context).textTheme.bodyMedium!.fontSize,
|
|
||||||
height: 1.42,
|
|
||||||
letterSpacing: 0.3,
|
|
||||||
color: i['type'] == 'em'
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Theme.of(context).colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
// const Spacer(),
|
// const Spacer(),
|
||||||
// if (videoItem.rcmdReason != null &&
|
// if (videoItem.rcmdReason != null &&
|
||||||
@@ -267,7 +276,7 @@ class VideoCardH extends StatelessWidget {
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoItem.stat.view!,
|
value: videoItem.stat.viewStr,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
],
|
],
|
||||||
@@ -275,7 +284,7 @@ class VideoCardH extends StatelessWidget {
|
|||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoItem.stat.danmu!,
|
value: videoItem.stat.danmuStr,
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
if (source == 'normal') const SizedBox(width: 24),
|
if (source == 'normal') const SizedBox(width: 24),
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ class VideoCardHMemberVideo extends StatelessWidget {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (videoItem.bvid == null || videoItem.firstCid == null) {
|
if (videoItem.bvid == null || videoItem.cid == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Utils.toViewPage(
|
Utils.toViewPage(
|
||||||
'bvid=${videoItem.bvid}&cid=${videoItem.firstCid}',
|
'bvid=${videoItem.bvid}&cid=${videoItem.cid}',
|
||||||
arguments: {
|
arguments: {
|
||||||
'heroTag': Utils.makeHeroTag(videoItem.bvid),
|
'heroTag': Utils.makeHeroTag(videoItem.bvid),
|
||||||
},
|
},
|
||||||
@@ -90,7 +90,7 @@ class VideoCardHMemberVideo extends StatelessWidget {
|
|||||||
right: 6.0,
|
right: 6.0,
|
||||||
top: 6.0,
|
top: 6.0,
|
||||||
),
|
),
|
||||||
if (videoItem.duration != null)
|
if (videoItem.duration > 0)
|
||||||
PBadge(
|
PBadge(
|
||||||
text: Utils.timeFormat(videoItem.duration),
|
text: Utils.timeFormat(videoItem.duration),
|
||||||
right: 6.0,
|
right: 6.0,
|
||||||
@@ -147,7 +147,7 @@ class VideoCardHMemberVideo extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
// videoItem.season?['title'] ?? videoItem.title ?? '',
|
// videoItem.season?['title'] ?? videoItem.title ?? '',
|
||||||
videoItem.title ?? '',
|
videoItem.title,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: videoItem.bvid != null && videoItem.bvid == bvid
|
fontWeight: videoItem.bvid != null && videoItem.bvid == bvid
|
||||||
@@ -184,14 +184,14 @@ class VideoCardHMemberVideo extends StatelessWidget {
|
|||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
// view: videoItem.season?['view_content'] ??
|
// view: videoItem.season?['view_content'] ??
|
||||||
// videoItem.viewContent,
|
// videoItem.viewContent,
|
||||||
value: videoItem.viewContent!,
|
value: videoItem.stat.viewStr,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
// danmu: videoItem.season?['danmaku'] ?? videoItem.danmaku,
|
// danmu: videoItem.season?['danmaku'] ?? videoItem.danmaku,
|
||||||
value: videoItem.danmaku!,
|
value: videoItem.stat.danmuStr,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import 'video_popup_menu.dart';
|
|||||||
|
|
||||||
// 视频卡片 - 垂直布局
|
// 视频卡片 - 垂直布局
|
||||||
class VideoCardV extends StatelessWidget {
|
class VideoCardV extends StatelessWidget {
|
||||||
final dynamic videoItem;
|
final BaseRecVideoItemModel videoItem;
|
||||||
final VoidCallback? onRemove;
|
final VoidCallback? onRemove;
|
||||||
|
|
||||||
const VideoCardV({
|
const VideoCardV({
|
||||||
@@ -31,14 +31,14 @@ class VideoCardV extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void onPushDetail(heroTag) async {
|
void onPushDetail(heroTag) async {
|
||||||
String goto = videoItem.goto;
|
String goto = videoItem.goto!;
|
||||||
switch (goto) {
|
switch (goto) {
|
||||||
case 'bangumi':
|
case 'bangumi':
|
||||||
Utils.viewBangumi(epId: videoItem.param);
|
Utils.viewBangumi(epId: videoItem.param!);
|
||||||
break;
|
break;
|
||||||
case 'av':
|
case 'av':
|
||||||
String bvid = videoItem.bvid ?? IdUtils.av2bv(videoItem.aid);
|
String bvid = videoItem.bvid ?? IdUtils.av2bv(videoItem.aid!);
|
||||||
int cid = videoItem.cid;
|
int cid = videoItem.cid!;
|
||||||
if (cid == -1) {
|
if (cid == -1) {
|
||||||
cid = await SearchHttp.ab2c(aid: videoItem.aid, bvid: bvid);
|
cid = await SearchHttp.ab2c(aid: videoItem.aid, bvid: bvid);
|
||||||
}
|
}
|
||||||
@@ -55,13 +55,13 @@ class VideoCardV extends StatelessWidget {
|
|||||||
case 'picture':
|
case 'picture':
|
||||||
try {
|
try {
|
||||||
String dynamicType = 'picture';
|
String dynamicType = 'picture';
|
||||||
String uri = videoItem.uri;
|
String uri = videoItem.uri!;
|
||||||
String id = '';
|
String id = '';
|
||||||
if (videoItem.uri.startsWith('bilibili://article/')) {
|
if (uri.startsWith('bilibili://article/')) {
|
||||||
// https://www.bilibili.com/read/cv27063554
|
// https://www.bilibili.com/read/cv27063554
|
||||||
dynamicType = 'read';
|
dynamicType = 'read';
|
||||||
RegExp regex = RegExp(r'\d+');
|
RegExp regex = RegExp(r'\d+');
|
||||||
Match match = regex.firstMatch(videoItem.uri)!;
|
Match match = regex.firstMatch(uri)!;
|
||||||
String matchedNumber = match.group(0)!;
|
String matchedNumber = match.group(0)!;
|
||||||
videoItem.param = int.parse(matchedNumber);
|
videoItem.param = int.parse(matchedNumber);
|
||||||
id = 'cv${videoItem.param}';
|
id = 'cv${videoItem.param}';
|
||||||
@@ -95,8 +95,8 @@ class VideoCardV extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SmartDialog.showToast(videoItem.goto);
|
SmartDialog.showToast(goto);
|
||||||
Utils.handleWebview(videoItem.uri);
|
Utils.handleWebview(videoItem.uri!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,7 +114,7 @@ class VideoCardV extends StatelessWidget {
|
|||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.id)),
|
onTap: () => onPushDetail(Utils.makeHeroTag(videoItem.aid)),
|
||||||
onLongPress: () => imageSaveDialog(
|
onLongPress: () => imageSaveDialog(
|
||||||
context: context,
|
context: context,
|
||||||
title: videoItem.title,
|
title: videoItem.title,
|
||||||
@@ -179,7 +179,7 @@ class VideoCardV extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(videoItem.title + "\n",
|
child: Text("${videoItem.title}\n",
|
||||||
// semanticsLabel: "${videoItem.title}",
|
// semanticsLabel: "${videoItem.title}",
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
@@ -223,7 +223,7 @@ class VideoCardV extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const SizedBox(width: 2),
|
const SizedBox(width: 2),
|
||||||
],
|
],
|
||||||
if (videoItem.isFollowed == 1) ...[
|
if (videoItem.isFollowed) ...[
|
||||||
const PBadge(
|
const PBadge(
|
||||||
text: '已关注',
|
text: '已关注',
|
||||||
stack: 'normal',
|
stack: 'normal',
|
||||||
@@ -262,7 +262,7 @@ class VideoCardV extends StatelessWidget {
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoItem.stat.view!,
|
value: videoItem.stat.viewStr,
|
||||||
goto: videoItem.goto,
|
goto: videoItem.goto,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
@@ -270,7 +270,7 @@ class VideoCardV extends StatelessWidget {
|
|||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoItem.stat.danmu!,
|
value: videoItem.stat.danmuStr,
|
||||||
),
|
),
|
||||||
if (videoItem is RecVideoItemModel) ...<Widget>[
|
if (videoItem is RecVideoItemModel) ...<Widget>[
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
@@ -294,7 +294,7 @@ class VideoCardV extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
if (videoItem is RecVideoItemAppModel &&
|
if (videoItem is RecVideoItemAppModel &&
|
||||||
videoItem.desc != null &&
|
videoItem.desc != null &&
|
||||||
videoItem.desc.contains(' · ')) ...<Widget>[
|
videoItem.desc!.contains(' · ')) ...<Widget>[
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Expanded(
|
Expanded(
|
||||||
flex: 0,
|
flex: 0,
|
||||||
@@ -310,7 +310,7 @@ class VideoCardV extends StatelessWidget {
|
|||||||
.withOpacity(0.8),
|
.withOpacity(0.8),
|
||||||
),
|
),
|
||||||
text: Utils.shortenChineseDateString(
|
text: Utils.shortenChineseDateString(
|
||||||
videoItem.desc.split(' · ').last)),
|
videoItem.desc!.split(' · ').last)),
|
||||||
)),
|
)),
|
||||||
const SizedBox(width: 2),
|
const SizedBox(width: 2),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:PiliPlus/models/model_video.dart';
|
||||||
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
|
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -21,16 +22,16 @@ class VideoCustomAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class VideoCustomActions {
|
class VideoCustomActions {
|
||||||
dynamic videoItem;
|
BaseSimpleVideoItemModel videoItem;
|
||||||
BuildContext context;
|
BuildContext context;
|
||||||
late List<VideoCustomAction> actions;
|
late List<VideoCustomAction> actions;
|
||||||
VoidCallback? onRemove;
|
VoidCallback? onRemove;
|
||||||
|
|
||||||
VideoCustomActions(this.videoItem, this.context, [this.onRemove]) {
|
VideoCustomActions(this.videoItem, this.context, [this.onRemove]) {
|
||||||
actions = [
|
actions = [
|
||||||
if ((videoItem.bvid as String?)?.isNotEmpty == true) ...[
|
if (videoItem.bvid?.isNotEmpty == true) ...[
|
||||||
VideoCustomAction(
|
VideoCustomAction(
|
||||||
videoItem.bvid,
|
videoItem.bvid!,
|
||||||
'copy',
|
'copy',
|
||||||
Stack(
|
Stack(
|
||||||
children: [
|
children: [
|
||||||
@@ -39,7 +40,7 @@ class VideoCustomActions {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
() {
|
() {
|
||||||
Utils.copyText(videoItem.bvid);
|
Utils.copyText(videoItem.bvid!);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
VideoCustomAction(
|
VideoCustomAction(
|
||||||
@@ -84,7 +85,7 @@ class VideoCustomActions {
|
|||||||
SmartDialog.showToast("未能获取dislikeReasons或feedbacks");
|
SmartDialog.showToast("未能获取dislikeReasons或feedbacks");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Widget actionButton(DislikeReason? r, FeedbackReason? f) {
|
Widget actionButton(Reason? r, Reason? f) {
|
||||||
return SearchText(
|
return SearchText(
|
||||||
text: r?.name ?? f?.name ?? '未知',
|
text: r?.name ?? f?.name ?? '未知',
|
||||||
onTap: (_) async {
|
onTap: (_) async {
|
||||||
@@ -258,11 +259,11 @@ class VideoCustomActions {
|
|||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var res = await VideoHttp.relationMod(
|
var res = await VideoHttp.relationMod(
|
||||||
mid: videoItem.owner.mid,
|
mid: videoItem.owner.mid!,
|
||||||
act: 5,
|
act: 5,
|
||||||
reSrc: 11,
|
reSrc: 11,
|
||||||
);
|
);
|
||||||
GStorage.setBlackMid(videoItem.owner.mid);
|
GStorage.setBlackMid(videoItem.owner.mid!);
|
||||||
Get.back();
|
Get.back();
|
||||||
SmartDialog.showToast(res['msg'] ?? '成功');
|
SmartDialog.showToast(res['msg'] ?? '成功');
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -19,22 +19,19 @@ import 'constants.dart';
|
|||||||
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
|
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
|
||||||
|
|
||||||
class Request {
|
class Request {
|
||||||
static const gzipDecoder = GZipDecoder();
|
static const _gzipDecoder = GZipDecoder();
|
||||||
static const brotilDecoder = BrotliDecoder();
|
static const _brotilDecoder = BrotliDecoder();
|
||||||
|
|
||||||
static final Request _instance = Request._internal();
|
static final Request _instance = Request._internal();
|
||||||
static late AccountManager accountManager;
|
static late AccountManager accountManager;
|
||||||
static late final Dio dio;
|
static late final Dio dio;
|
||||||
factory Request() => _instance;
|
factory Request() => _instance;
|
||||||
late bool enableSystemProxy;
|
|
||||||
late String systemProxyHost;
|
|
||||||
late String systemProxyPort;
|
|
||||||
static final _rand = Random();
|
static final _rand = Random();
|
||||||
static final RegExp spmPrefixExp =
|
static final RegExp _spmPrefixExp =
|
||||||
RegExp(r'<meta name="spm_prefix" content="([^"]+?)">');
|
RegExp(r'<meta name="spm_prefix" content="([^"]+?)">');
|
||||||
|
|
||||||
/// 设置cookie
|
/// 设置cookie
|
||||||
static setCookie() async {
|
static Future<void> setCookie() async {
|
||||||
accountManager = AccountManager();
|
accountManager = AccountManager();
|
||||||
dio.interceptors.add(accountManager);
|
dio.interceptors.add(accountManager);
|
||||||
await Accounts.refresh();
|
await Accounts.refresh();
|
||||||
@@ -63,7 +60,7 @@ class Request {
|
|||||||
try {
|
try {
|
||||||
final html = await Request().get(Api.dynamicSpmPrefix,
|
final html = await Request().get(Api.dynamicSpmPrefix,
|
||||||
options: Options(extra: {'account': account}));
|
options: Options(extra: {'account': account}));
|
||||||
final String spmPrefix = spmPrefixExp.firstMatch(html.data)!.group(1)!;
|
final String spmPrefix = _spmPrefixExp.firstMatch(html.data)!.group(1)!;
|
||||||
final String randPngEnd = base64.encode(
|
final String randPngEnd = base64.encode(
|
||||||
List<int>.generate(32, (_) => _rand.nextInt(256)) +
|
List<int>.generate(32, (_) => _rand.nextInt(256)) +
|
||||||
List<int>.filled(4, 0) +
|
List<int>.filled(4, 0) +
|
||||||
@@ -112,12 +109,10 @@ class Request {
|
|||||||
responseDecoder: responseDecoder, // Http2Adapter没有自动解压
|
responseDecoder: responseDecoder, // Http2Adapter没有自动解压
|
||||||
persistentConnection: true);
|
persistentConnection: true);
|
||||||
|
|
||||||
enableSystemProxy = GStorage.setting
|
final bool enableSystemProxy = GStorage.setting
|
||||||
.get(SettingBoxKey.enableSystemProxy, defaultValue: false) as bool;
|
.get(SettingBoxKey.enableSystemProxy, defaultValue: false);
|
||||||
systemProxyHost =
|
final String systemProxyHost = GStorage.defaultSystemProxyHost;
|
||||||
GStorage.setting.get(SettingBoxKey.systemProxyHost, defaultValue: '');
|
final String systemProxyPort = GStorage.defaultSystemProxyPort;
|
||||||
systemProxyPort =
|
|
||||||
GStorage.setting.get(SettingBoxKey.systemProxyPort, defaultValue: '');
|
|
||||||
|
|
||||||
final http11Adapter = IOHttpClientAdapter(createHttpClient: () {
|
final http11Adapter = IOHttpClientAdapter(createHttpClient: () {
|
||||||
final client = HttpClient()
|
final client = HttpClient()
|
||||||
@@ -286,10 +281,10 @@ class Request {
|
|||||||
ResponseBody responseBody) {
|
ResponseBody responseBody) {
|
||||||
switch (responseBody.headers['content-encoding']?.firstOrNull) {
|
switch (responseBody.headers['content-encoding']?.firstOrNull) {
|
||||||
case 'gzip':
|
case 'gzip':
|
||||||
return utf8.decode(gzipDecoder.decodeBytes(responseBytes),
|
return utf8.decode(_gzipDecoder.decodeBytes(responseBytes),
|
||||||
allowMalformed: true);
|
allowMalformed: true);
|
||||||
case 'br':
|
case 'br':
|
||||||
return utf8.decode(brotilDecoder.convert(responseBytes),
|
return utf8.decode(_brotilDecoder.convert(responseBytes),
|
||||||
allowMalformed: true);
|
allowMalformed: true);
|
||||||
default:
|
default:
|
||||||
return utf8.decode(responseBytes, allowMalformed: true);
|
return utf8.decode(responseBytes, allowMalformed: true);
|
||||||
|
|||||||
@@ -148,8 +148,7 @@ class SearchHttp {
|
|||||||
} else if (bvid != null) {
|
} else if (bvid != null) {
|
||||||
data['bvid'] = bvid;
|
data['bvid'] = bvid;
|
||||||
}
|
}
|
||||||
final dynamic res = await Request()
|
final dynamic res = await Request().get(Api.ab2c, queryParameters: data);
|
||||||
.get(Api.ab2c, queryParameters: <String, dynamic>{...data});
|
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return part != null
|
return part != null
|
||||||
? ((res.data['data'] as List).getOrNull(part - 1)?['cid'] ??
|
? ((res.data['data'] as List).getOrNull(part - 1)?['cid'] ??
|
||||||
@@ -201,8 +200,8 @@ class SearchHttp {
|
|||||||
} else if (epId != null) {
|
} else if (epId != null) {
|
||||||
data['ep_id'] = epId;
|
data['ep_id'] = epId;
|
||||||
}
|
}
|
||||||
final dynamic res = await Request()
|
final dynamic res =
|
||||||
.get(Api.bangumiInfo, queryParameters: <String, dynamic>{...data});
|
await Request().get(Api.bangumiInfo, queryParameters: data);
|
||||||
|
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -349,13 +349,11 @@ class VideoHttp {
|
|||||||
var res =
|
var res =
|
||||||
await Request().get(Api.relatedList, queryParameters: {'bvid': bvid});
|
await Request().get(Api.relatedList, queryParameters: {'bvid': bvid});
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
List<HotVideoItemModel> list = [];
|
final items =
|
||||||
for (var i in res.data['data']) {
|
(res.data['data'] as List).map((i) => HotVideoItemModel.fromJson(i));
|
||||||
HotVideoItemModel videoItem = HotVideoItemModel.fromJson(i);
|
final list = RecommendFilter.applyFilterToRelatedVideos
|
||||||
if (!RecommendFilter.filter(videoItem, relatedVideos: true)) {
|
? items.where((i) => !RecommendFilter.filterAll(i)).toList()
|
||||||
list.add(videoItem);
|
: items.toList();
|
||||||
}
|
|
||||||
}
|
|
||||||
return LoadingState.success(list);
|
return LoadingState.success(list);
|
||||||
} else {
|
} else {
|
||||||
return LoadingState.error(res.data['message']);
|
return LoadingState.error(res.data['message']);
|
||||||
@@ -390,7 +388,6 @@ class VideoHttp {
|
|||||||
static Future hasCoinVideo({required String bvid}) async {
|
static Future hasCoinVideo({required String bvid}) async {
|
||||||
var res =
|
var res =
|
||||||
await Request().get(Api.hasCoinVideo, queryParameters: {'bvid': bvid});
|
await Request().get(Api.hasCoinVideo, queryParameters: {'bvid': bvid});
|
||||||
debugPrint('res: $res');
|
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {'status': true, 'data': res.data['data']};
|
return {'status': true, 'data': res.data['data']};
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class BangumiListDataModel {
|
|||||||
});
|
});
|
||||||
|
|
||||||
int? hasNext;
|
int? hasNext;
|
||||||
List? list;
|
List<BangumiListItemModel>? list;
|
||||||
int? num;
|
int? num;
|
||||||
int? size;
|
int? size;
|
||||||
int? total;
|
int? total;
|
||||||
|
|||||||
@@ -1,60 +1,20 @@
|
|||||||
|
import 'package:PiliPlus/models/model_rec_video_item.dart';
|
||||||
|
import 'package:PiliPlus/models/model_video.dart';
|
||||||
import 'package:PiliPlus/utils/id_utils.dart';
|
import 'package:PiliPlus/utils/id_utils.dart';
|
||||||
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
|
|
||||||
class RecVideoItemAppModel {
|
class RecVideoItemAppModel extends BaseRecVideoItemModel {
|
||||||
RecVideoItemAppModel({
|
|
||||||
this.id,
|
|
||||||
this.aid,
|
|
||||||
this.bvid,
|
|
||||||
this.cid,
|
|
||||||
this.pic,
|
|
||||||
this.stat,
|
|
||||||
this.duration,
|
|
||||||
this.title,
|
|
||||||
this.isFollowed,
|
|
||||||
this.owner,
|
|
||||||
this.rcmdReason,
|
|
||||||
this.goto,
|
|
||||||
this.param,
|
|
||||||
this.uri,
|
|
||||||
this.talkBack,
|
|
||||||
this.bangumiView,
|
|
||||||
this.bangumiFollow,
|
|
||||||
this.bangumiBadge,
|
|
||||||
this.cardType,
|
|
||||||
this.adInfo,
|
|
||||||
this.threePoint,
|
|
||||||
this.desc,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? id;
|
int? id;
|
||||||
int? aid;
|
|
||||||
String? bvid;
|
|
||||||
int? cid;
|
|
||||||
String? pic;
|
|
||||||
RcmdStat? stat;
|
|
||||||
int? duration;
|
|
||||||
String? title;
|
|
||||||
int? isFollowed;
|
|
||||||
RcmdOwner? owner;
|
|
||||||
String? rcmdReason;
|
|
||||||
String? goto;
|
|
||||||
int? param;
|
|
||||||
String? uri;
|
|
||||||
String? talkBack;
|
String? talkBack;
|
||||||
// 番剧
|
|
||||||
String? bangumiView;
|
|
||||||
String? bangumiFollow;
|
|
||||||
String? bangumiBadge;
|
|
||||||
|
|
||||||
String? cardType;
|
String? cardType;
|
||||||
Map? adInfo;
|
Map? adInfo;
|
||||||
ThreePoint? threePoint;
|
ThreePoint? threePoint;
|
||||||
String? desc;
|
|
||||||
|
|
||||||
RecVideoItemAppModel.fromJson(Map<String, dynamic> json) {
|
RecVideoItemAppModel.fromJson(Map<String, dynamic> json) {
|
||||||
id = json['player_args'] != null
|
id = json['player_args'] != null
|
||||||
? json['player_args']['aid']
|
? json['player_args']['aid']
|
||||||
: int.parse(json['param'] ?? '-1');
|
: int.tryParse(json['param'] ?? '-1');
|
||||||
aid = id;
|
aid = id;
|
||||||
bvid = json['bvid'] ??
|
bvid = json['bvid'] ??
|
||||||
(json['player_args'] != null
|
(json['player_args'] != null
|
||||||
@@ -70,21 +30,22 @@ class RecVideoItemAppModel {
|
|||||||
title = json['title'];
|
title = json['title'];
|
||||||
owner = RcmdOwner.fromJson(json);
|
owner = RcmdOwner.fromJson(json);
|
||||||
rcmdReason = json['bottom_rcmd_reason'] ?? json['top_rcmd_reason'];
|
rcmdReason = json['bottom_rcmd_reason'] ?? json['top_rcmd_reason'];
|
||||||
|
if (rcmdReason != null && rcmdReason!.contains('赞')) {
|
||||||
|
// 有时能在推荐原因里获得点赞数
|
||||||
|
(stat as RcmdStat).like = Utils.parseNum(rcmdReason!);
|
||||||
|
}
|
||||||
// 由于app端api并不会直接返回与owner的关注状态
|
// 由于app端api并不会直接返回与owner的关注状态
|
||||||
// 所以借用推荐原因是否为“已关注”、“新关注”判别关注状态,从而与web端接口等效
|
// 所以借用推荐原因是否为“已关注”、“新关注”判别关注状态,从而与web端接口等效
|
||||||
isFollowed = (rcmdReason == '已关注') || (rcmdReason == '新关注') ? 1 : 0;
|
isFollowed = const {'已关注', '新关注'}.contains(rcmdReason);
|
||||||
// 如果是,就无需再显示推荐原因,交由view统一处理即可
|
// 如果是,就无需再显示推荐原因,交由view统一处理即可
|
||||||
if (isFollowed == 1) {
|
if (isFollowed) rcmdReason = null;
|
||||||
rcmdReason = null;
|
|
||||||
}
|
|
||||||
goto = json['goto'];
|
goto = json['goto'];
|
||||||
param = int.parse(json['param']);
|
param = int.parse(json['param']);
|
||||||
uri = json['uri'];
|
uri = json['uri'];
|
||||||
talkBack = json['talk_back'];
|
talkBack = json['talk_back'];
|
||||||
|
|
||||||
if (json['goto'] == 'bangumi') {
|
if (json['goto'] == 'bangumi') {
|
||||||
bangumiView = json['cover_left_text_1'];
|
|
||||||
bangumiFollow = json['cover_left_text_2'];
|
|
||||||
bangumiBadge = json['cover_right_text'];
|
bangumiBadge = json['cover_right_text'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,30 +56,37 @@ class RecVideoItemAppModel {
|
|||||||
: null;
|
: null;
|
||||||
desc = json['desc'];
|
desc = json['desc'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// int? get pubdate => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
class RcmdStat {
|
class RcmdStat implements BaseStat {
|
||||||
RcmdStat({
|
@override
|
||||||
this.view,
|
int? like;
|
||||||
this.like,
|
|
||||||
this.danmu,
|
@override
|
||||||
});
|
int? get view => Utils.parseNum(viewStr);
|
||||||
String? view;
|
@override
|
||||||
String? like;
|
int? get danmu => Utils.parseNum(danmuStr);
|
||||||
String? danmu;
|
|
||||||
|
@override
|
||||||
|
late String viewStr;
|
||||||
|
@override
|
||||||
|
late String danmuStr;
|
||||||
|
|
||||||
RcmdStat.fromJson(Map<String, dynamic> json) {
|
RcmdStat.fromJson(Map<String, dynamic> json) {
|
||||||
view = json["cover_left_text_1"];
|
viewStr = json["cover_left_text_1"];
|
||||||
danmu = json['cover_left_text_2'] ?? '-';
|
danmuStr = json['cover_left_text_2'];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class RcmdOwner {
|
@override
|
||||||
RcmdOwner({this.name, this.mid});
|
set danmu(_) {}
|
||||||
|
@override
|
||||||
String? name;
|
set view(_) {}
|
||||||
int? mid;
|
}
|
||||||
|
|
||||||
|
class RcmdOwner extends BaseOwner {
|
||||||
RcmdOwner.fromJson(Map<String, dynamic> json) {
|
RcmdOwner.fromJson(Map<String, dynamic> json) {
|
||||||
name = json['goto'] == 'av'
|
name = json['goto'] == 'av'
|
||||||
? json['args']['up_name']
|
? json['args']['up_name']
|
||||||
@@ -130,63 +98,26 @@ class RcmdOwner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThreePoint {
|
class ThreePoint {
|
||||||
ThreePoint({
|
List<Reason>? dislikeReasons;
|
||||||
this.dislikeReasons,
|
List<Reason>? feedbacks;
|
||||||
this.feedbacks,
|
|
||||||
this.watchLater,
|
|
||||||
});
|
|
||||||
|
|
||||||
List<DislikeReason>? dislikeReasons;
|
|
||||||
List<FeedbackReason>? feedbacks;
|
|
||||||
int? watchLater;
|
int? watchLater;
|
||||||
|
|
||||||
ThreePoint.fromJson(Map<String, dynamic> json) {
|
ThreePoint.fromJson(Map<String, dynamic> json) {
|
||||||
if (json['dislike_reasons'] != null) {
|
dislikeReasons = (json['dislike_reasons'] as List?)
|
||||||
dislikeReasons = [];
|
?.map((v) => Reason.fromJson(v))
|
||||||
json['dislike_reasons'].forEach((v) {
|
.toList();
|
||||||
dislikeReasons!.add(DislikeReason.fromJson(v));
|
feedbacks =
|
||||||
});
|
(json['feedbacks'] as List?)?.map((v) => Reason.fromJson(v)).toList();
|
||||||
}
|
|
||||||
if (json['feedbacks'] != null) {
|
|
||||||
feedbacks = [];
|
|
||||||
json['feedbacks'].forEach((v) {
|
|
||||||
feedbacks!.add(FeedbackReason.fromJson(v));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
watchLater = json['watch_later'];
|
watchLater = json['watch_later'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DislikeReason {
|
class Reason {
|
||||||
DislikeReason({
|
|
||||||
this.id,
|
|
||||||
this.name,
|
|
||||||
this.toast,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? id;
|
int? id;
|
||||||
String? name;
|
String? name;
|
||||||
String? toast;
|
String? toast;
|
||||||
|
|
||||||
DislikeReason.fromJson(Map<String, dynamic> json) {
|
Reason.fromJson(Map<String, dynamic> json) {
|
||||||
id = json['id'];
|
|
||||||
name = json['name'];
|
|
||||||
toast = json['toast'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FeedbackReason {
|
|
||||||
FeedbackReason({
|
|
||||||
this.id,
|
|
||||||
this.name,
|
|
||||||
this.toast,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? id;
|
|
||||||
String? name;
|
|
||||||
String? toast;
|
|
||||||
|
|
||||||
FeedbackReason.fromJson(Map<String, dynamic> json) {
|
|
||||||
id = json['id'];
|
id = json['id'];
|
||||||
name = json['name'];
|
name = json['name'];
|
||||||
toast = json['toast'];
|
toast = json['toast'];
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
|
|
||||||
|
import '../model_video.dart';
|
||||||
|
|
||||||
class MemberArchiveDataModel {
|
class MemberArchiveDataModel {
|
||||||
MemberArchiveDataModel({
|
MemberArchiveDataModel({
|
||||||
this.list,
|
this.list,
|
||||||
@@ -51,114 +55,60 @@ class TListItemModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class VListItemModel {
|
class VListItemModel extends BaseVideoItemModel {
|
||||||
VListItemModel({
|
|
||||||
this.comment,
|
|
||||||
this.typeid,
|
|
||||||
this.play,
|
|
||||||
this.pic,
|
|
||||||
this.subtitle,
|
|
||||||
this.description,
|
|
||||||
this.copyright,
|
|
||||||
this.title,
|
|
||||||
this.review,
|
|
||||||
this.author,
|
|
||||||
this.mid,
|
|
||||||
this.created,
|
|
||||||
this.pubdate,
|
|
||||||
this.length,
|
|
||||||
this.duration,
|
|
||||||
this.videoReview,
|
|
||||||
this.aid,
|
|
||||||
this.bvid,
|
|
||||||
this.cid,
|
|
||||||
this.hideClick,
|
|
||||||
this.isChargingSrc,
|
|
||||||
this.rcmdReason,
|
|
||||||
this.owner,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? comment;
|
int? comment;
|
||||||
int? typeid;
|
int? typeid;
|
||||||
int? play;
|
|
||||||
String? pic;
|
|
||||||
String? subtitle;
|
String? subtitle;
|
||||||
String? description;
|
|
||||||
String? copyright;
|
String? copyright;
|
||||||
String? title;
|
|
||||||
int? review;
|
int? review;
|
||||||
String? author;
|
|
||||||
int? mid;
|
|
||||||
int? created;
|
|
||||||
int? pubdate;
|
|
||||||
String? length;
|
|
||||||
String? duration;
|
|
||||||
int? videoReview;
|
|
||||||
int? aid;
|
|
||||||
String? bvid;
|
|
||||||
int? cid;
|
|
||||||
bool? hideClick;
|
bool? hideClick;
|
||||||
bool? isChargingSrc;
|
bool? isChargingSrc;
|
||||||
Stat? stat;
|
|
||||||
String? rcmdReason;
|
|
||||||
Owner? owner;
|
|
||||||
|
|
||||||
VListItemModel.fromJson(Map<String, dynamic> json) {
|
VListItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
comment = json['comment'];
|
comment = json['comment'];
|
||||||
typeid = json['typeid'];
|
typeid = json['typeid'];
|
||||||
play = json['play'];
|
|
||||||
pic = json['pic'];
|
pic = json['pic'];
|
||||||
subtitle = json['subtitle'];
|
subtitle = json['subtitle'];
|
||||||
description = json['description'];
|
desc = json['description'];
|
||||||
copyright = json['copyright'];
|
copyright = json['copyright'];
|
||||||
title = json['title'];
|
title = json['title'];
|
||||||
review = json['review'];
|
review = json['review'];
|
||||||
author = json['author'];
|
|
||||||
mid = json['mid'];
|
|
||||||
created = json['created'];
|
|
||||||
pubdate = json['created'];
|
pubdate = json['created'];
|
||||||
length = json['length'];
|
if (json['length'] != null) duration = Utils.duration(json['length']);
|
||||||
duration = json['length'];
|
|
||||||
videoReview = json['video_review'];
|
|
||||||
aid = json['aid'];
|
aid = json['aid'];
|
||||||
bvid = json['bvid'];
|
bvid = json['bvid'];
|
||||||
cid = null;
|
|
||||||
hideClick = json['hide_click'];
|
hideClick = json['hide_click'];
|
||||||
isChargingSrc = json['is_charging_arc'];
|
isChargingSrc = json['is_charging_arc'];
|
||||||
stat = Stat.fromJson(json);
|
stat = VListStat.fromJson(json);
|
||||||
rcmdReason = null;
|
owner = VListOwner.fromJson(json);
|
||||||
owner = Owner.fromJson(json);
|
}
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// int? cid = null;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// String? rcmdReason = null;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// String? goto;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// bool isFollowed;
|
||||||
|
|
||||||
|
// @override
|
||||||
|
// String? uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
class VListOwner extends BaseOwner {
|
||||||
|
VListOwner.fromJson(Map<String, dynamic> json) {
|
||||||
|
mid = json["mid"];
|
||||||
|
name = json["author"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Stat {
|
class VListStat extends BaseStat {
|
||||||
Stat({
|
VListStat.fromJson(Map<String, dynamic> json) {
|
||||||
this.view,
|
|
||||||
this.danmu,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? view;
|
|
||||||
int? danmu;
|
|
||||||
|
|
||||||
Stat.fromJson(Map<String, dynamic> json) {
|
|
||||||
view = json["play"];
|
view = json["play"];
|
||||||
danmu = json['video_review'];
|
danmu = json['video_review'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Owner {
|
|
||||||
Owner({
|
|
||||||
this.mid,
|
|
||||||
this.name,
|
|
||||||
this.face,
|
|
||||||
});
|
|
||||||
int? mid;
|
|
||||||
String? name;
|
|
||||||
String? face;
|
|
||||||
|
|
||||||
Owner.fromJson(Map<String, dynamic> json) {
|
|
||||||
mid = json["mid"];
|
|
||||||
name = json["author"];
|
|
||||||
face = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,89 +1,26 @@
|
|||||||
class MemberCoinsDataModel {
|
import '../model_hot_video_item.dart';
|
||||||
MemberCoinsDataModel({
|
|
||||||
this.aid,
|
|
||||||
this.bvid,
|
|
||||||
this.cid,
|
|
||||||
this.coins,
|
|
||||||
this.copyright,
|
|
||||||
this.ctime,
|
|
||||||
this.desc,
|
|
||||||
this.duration,
|
|
||||||
this.owner,
|
|
||||||
this.pic,
|
|
||||||
this.pubLocation,
|
|
||||||
this.pubdate,
|
|
||||||
this.resourceType,
|
|
||||||
this.state,
|
|
||||||
this.subtitle,
|
|
||||||
this.time,
|
|
||||||
this.title,
|
|
||||||
this.tname,
|
|
||||||
this.videos,
|
|
||||||
this.view,
|
|
||||||
this.danmaku,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? aid;
|
class MemberCoinsDataModel extends HotVideoItemModel {
|
||||||
String? bvid;
|
|
||||||
int? cid;
|
|
||||||
int? coins;
|
|
||||||
int? copyright;
|
|
||||||
int? ctime;
|
|
||||||
String? desc;
|
|
||||||
int? duration;
|
|
||||||
Owner? owner;
|
|
||||||
String? pic;
|
|
||||||
String? pubLocation;
|
|
||||||
int? pubdate;
|
|
||||||
String? resourceType;
|
|
||||||
int? state;
|
|
||||||
String? subtitle;
|
String? subtitle;
|
||||||
|
int? coins;
|
||||||
int? time;
|
int? time;
|
||||||
String? title;
|
// int? get view => stat.view;
|
||||||
String? tname;
|
// int? get danmaku => stat.danmu;
|
||||||
int? videos;
|
|
||||||
int? view;
|
|
||||||
int? danmaku;
|
|
||||||
|
|
||||||
MemberCoinsDataModel.fromJson(Map<String, dynamic> json) {
|
MemberCoinsDataModel.fromJson(Map<String, dynamic> json)
|
||||||
aid = json['aid'];
|
: super.fromJson(json) {
|
||||||
bvid = json['bvid'];
|
|
||||||
cid = json['cid'];
|
|
||||||
coins = json['coins'];
|
coins = json['coins'];
|
||||||
copyright = json['copyright'];
|
|
||||||
ctime = json['ctime'];
|
|
||||||
desc = json['desc'];
|
|
||||||
duration = json['duration'];
|
|
||||||
owner = Owner.fromJson(json['owner']);
|
|
||||||
pic = json['pic'];
|
|
||||||
pubLocation = json['pub_location'];
|
|
||||||
pubdate = json['pubdate'];
|
|
||||||
resourceType = json['resource_type'];
|
|
||||||
state = json['state'];
|
|
||||||
subtitle = json['subtitle'];
|
subtitle = json['subtitle'];
|
||||||
time = json['time'];
|
time = json['time'];
|
||||||
title = json['title'];
|
// view = json['stat']['view'];
|
||||||
tname = json['tname'];
|
// danmaku = json['stat']['danmaku'];
|
||||||
videos = json['videos'];
|
|
||||||
view = json['stat']['view'];
|
|
||||||
danmaku = json['stat']['danmaku'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Owner {
|
|
||||||
Owner({
|
|
||||||
this.mid,
|
|
||||||
this.name,
|
|
||||||
this.face,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? mid;
|
|
||||||
String? name;
|
|
||||||
String? face;
|
|
||||||
|
|
||||||
Owner.fromJson(Map<String, dynamic> json) {
|
|
||||||
mid = json['mid'];
|
|
||||||
name = json['name'];
|
|
||||||
face = json['face'];
|
|
||||||
}
|
}
|
||||||
|
// @override
|
||||||
|
// String? goto;
|
||||||
|
// @override
|
||||||
|
// bool isFollowed;
|
||||||
|
// @override
|
||||||
|
// String? rcmdReason;
|
||||||
|
// @override
|
||||||
|
// String? uri;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,23 @@
|
|||||||
import './model_owner.dart';
|
import 'model_owner.dart';
|
||||||
|
import 'model_rec_video_item.dart';
|
||||||
|
import 'model_video.dart';
|
||||||
|
|
||||||
class HotVideoItemModel {
|
// 稍后再看, 排行榜等网页返回也使用该类
|
||||||
HotVideoItemModel({
|
class HotVideoItemModel extends BaseRecVideoItemModel {
|
||||||
this.aid,
|
|
||||||
this.cid,
|
|
||||||
this.bvid,
|
|
||||||
this.videos,
|
|
||||||
this.tid,
|
|
||||||
this.tname,
|
|
||||||
this.copyright,
|
|
||||||
this.pic,
|
|
||||||
this.title,
|
|
||||||
this.pubdate,
|
|
||||||
this.ctime,
|
|
||||||
this.desc,
|
|
||||||
this.state,
|
|
||||||
this.duration,
|
|
||||||
this.middionId,
|
|
||||||
this.owner,
|
|
||||||
this.stat,
|
|
||||||
this.vDynamic,
|
|
||||||
this.dimension,
|
|
||||||
this.shortLinkV2,
|
|
||||||
this.firstFrame,
|
|
||||||
this.pubLocation,
|
|
||||||
this.seasontype,
|
|
||||||
this.isOgv,
|
|
||||||
this.rcmdReason,
|
|
||||||
this.checked,
|
|
||||||
this.pgcLabel,
|
|
||||||
this.redirectUrl,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? aid;
|
|
||||||
int? cid;
|
|
||||||
String? bvid;
|
|
||||||
int? videos;
|
int? videos;
|
||||||
int? tid;
|
int? tid;
|
||||||
String? tname;
|
String? tname;
|
||||||
int? copyright;
|
int? copyright;
|
||||||
String? pic;
|
|
||||||
String? title;
|
|
||||||
int? pubdate;
|
|
||||||
int? ctime;
|
int? ctime;
|
||||||
String? desc;
|
|
||||||
int? state;
|
int? state;
|
||||||
int? duration;
|
|
||||||
int? middionId;
|
|
||||||
Owner? owner;
|
|
||||||
Stat? stat;
|
|
||||||
String? vDynamic;
|
|
||||||
Dimension? dimension;
|
Dimension? dimension;
|
||||||
String? shortLinkV2;
|
|
||||||
String? firstFrame;
|
String? firstFrame;
|
||||||
String? pubLocation;
|
String? pubLocation;
|
||||||
int? seasontype;
|
|
||||||
bool? isOgv;
|
|
||||||
RcmdReason? rcmdReason;
|
|
||||||
bool? checked;
|
|
||||||
String? pgcLabel;
|
String? pgcLabel;
|
||||||
String? redirectUrl;
|
String? redirectUrl;
|
||||||
|
|
||||||
|
bool? checked; // 手动设置的
|
||||||
|
|
||||||
HotVideoItemModel.fromJson(Map<String, dynamic> json) {
|
HotVideoItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
aid = json["aid"];
|
aid = json["aid"];
|
||||||
cid = json["cid"];
|
cid = json["cid"];
|
||||||
@@ -76,97 +33,62 @@ class HotVideoItemModel {
|
|||||||
desc = json["desc"];
|
desc = json["desc"];
|
||||||
state = json["state"];
|
state = json["state"];
|
||||||
duration = json["duration"];
|
duration = json["duration"];
|
||||||
middionId = json["middion_id"];
|
|
||||||
owner = Owner.fromJson(json["owner"]);
|
owner = Owner.fromJson(json["owner"]);
|
||||||
stat = Stat.fromJson(json['stat']);
|
stat = HotStat.fromJson(json['stat']);
|
||||||
vDynamic = json["vDynamic"];
|
dimension = Dimension.fromJson(json['dimension']);
|
||||||
dimension = Dimension.fromMap(json['dimension']);
|
|
||||||
shortLinkV2 = json["short_link_v2"];
|
|
||||||
firstFrame = json["first_frame"];
|
firstFrame = json["first_frame"];
|
||||||
pubLocation = json["pub_location"];
|
pubLocation = json["pub_location"];
|
||||||
seasontype = json["seasontype"];
|
dynamic rcmd = json['rcmd_reason'];
|
||||||
isOgv = json["isOgv"];
|
rcmdReason = rcmd is Map ? rcmd['content'] : rcmd; // 相关视频里rcmd为String,
|
||||||
rcmdReason = json['rcmd_reason'] != '' && json['rcmd_reason'] != null
|
if (rcmdReason?.isEmpty == true) rcmdReason = null;
|
||||||
? RcmdReason.fromJson(json['rcmd_reason'])
|
|
||||||
: null;
|
|
||||||
pgcLabel = json['pgc_label'];
|
pgcLabel = json['pgc_label'];
|
||||||
redirectUrl = json['redirect_url'];
|
redirectUrl = json['redirect_url'];
|
||||||
}
|
// uri = json['uri']; // 仅在稍后再看存在
|
||||||
}
|
}
|
||||||
|
|
||||||
class Stat {
|
// @override
|
||||||
Stat({
|
// get isFollowed => false;
|
||||||
this.aid,
|
// @override
|
||||||
this.view,
|
// get goto => 'av';
|
||||||
this.danmu,
|
// @override
|
||||||
this.reply,
|
// get uri => 'bilibili://video/$aid';
|
||||||
this.favorite,
|
}
|
||||||
this.coin,
|
|
||||||
this.share,
|
|
||||||
this.nowRank,
|
|
||||||
this.hisRank,
|
|
||||||
this.like,
|
|
||||||
this.dislike,
|
|
||||||
this.vt,
|
|
||||||
this.vv,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? aid;
|
class HotStat extends Stat {
|
||||||
int? view;
|
|
||||||
int? danmu;
|
|
||||||
int? reply;
|
int? reply;
|
||||||
int? favorite;
|
int? favorite;
|
||||||
int? coin;
|
int? coin;
|
||||||
int? share;
|
int? share;
|
||||||
int? nowRank;
|
int? nowRank;
|
||||||
int? hisRank;
|
int? hisRank;
|
||||||
int? like;
|
|
||||||
int? dislike;
|
int? dislike;
|
||||||
int? vt;
|
int? vt;
|
||||||
int? vv;
|
int? vv;
|
||||||
|
|
||||||
Stat.fromJson(Map<String, dynamic> json) {
|
HotStat.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
|
||||||
aid = json["aid"];
|
|
||||||
view = json["view"];
|
|
||||||
danmu = json['danmaku'];
|
|
||||||
reply = json["reply"];
|
reply = json["reply"];
|
||||||
favorite = json["favorite"];
|
favorite = json["favorite"];
|
||||||
coin = json['coin'];
|
coin = json['coin'];
|
||||||
share = json["share"];
|
share = json["share"];
|
||||||
nowRank = json["now_rank"];
|
nowRank = json["now_rank"];
|
||||||
hisRank = json['his_rank'];
|
hisRank = json['his_rank'];
|
||||||
like = json["like"];
|
|
||||||
dislike = json["dislike"];
|
dislike = json["dislike"];
|
||||||
vt = json['vt'];
|
vt = json['vt'];
|
||||||
vv = json["vv"];
|
vv = json["vv"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Dimension {
|
// class RcmdReason {
|
||||||
Dimension({this.width, this.height, this.rotate});
|
// RcmdReason({
|
||||||
|
// this.rcornerMark,
|
||||||
|
// this.content,
|
||||||
|
// });
|
||||||
|
|
||||||
int? width;
|
// int? rcornerMark;
|
||||||
int? height;
|
// String? content = '';
|
||||||
int? rotate;
|
|
||||||
|
|
||||||
Dimension.fromMap(Map<String, dynamic> json) {
|
// RcmdReason.fromJson(Map<String, dynamic> json) {
|
||||||
width = json["width"];
|
// rcornerMark = json["corner_mark"];
|
||||||
height = json["height"];
|
// content = json["content"] ?? '';
|
||||||
rotate = json["rotate"];
|
// }
|
||||||
}
|
// }
|
||||||
}
|
|
||||||
|
|
||||||
class RcmdReason {
|
|
||||||
RcmdReason({
|
|
||||||
this.rcornerMark,
|
|
||||||
this.content,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? rcornerMark;
|
|
||||||
String? content = '';
|
|
||||||
|
|
||||||
RcmdReason.fromJson(Map<String, dynamic> json) {
|
|
||||||
rcornerMark = json["corner_mark"];
|
|
||||||
content = json["content"] ?? '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
|
import 'model_video.dart';
|
||||||
|
|
||||||
part 'model_owner.g.dart';
|
part 'model_owner.g.dart';
|
||||||
|
|
||||||
@HiveType(typeId: 3)
|
@HiveType(typeId: 3)
|
||||||
class Owner {
|
class Owner implements BaseOwner {
|
||||||
Owner({
|
Owner({
|
||||||
this.mid,
|
this.mid,
|
||||||
this.name,
|
this.name,
|
||||||
this.face,
|
this.face,
|
||||||
});
|
});
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
|
@override
|
||||||
int? mid;
|
int? mid;
|
||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
|
@override
|
||||||
String? name;
|
String? name;
|
||||||
@HiveField(2)
|
@HiveField(2)
|
||||||
String? face;
|
String? face;
|
||||||
|
|||||||
@@ -1,55 +1,19 @@
|
|||||||
import './model_owner.dart';
|
import './model_owner.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'model_video.dart';
|
||||||
|
|
||||||
part 'model_rec_video_item.g.dart';
|
abstract class BaseRecVideoItemModel extends BaseVideoItemModel {
|
||||||
|
String? goto;
|
||||||
@HiveType(typeId: 0)
|
String? uri;
|
||||||
class RecVideoItemModel {
|
|
||||||
RecVideoItemModel({
|
|
||||||
this.id,
|
|
||||||
this.bvid,
|
|
||||||
this.cid,
|
|
||||||
this.goto,
|
|
||||||
this.uri,
|
|
||||||
this.pic,
|
|
||||||
this.title,
|
|
||||||
this.duration,
|
|
||||||
this.pubdate,
|
|
||||||
this.owner,
|
|
||||||
this.stat,
|
|
||||||
this.isFollowed,
|
|
||||||
this.rcmdReason,
|
|
||||||
});
|
|
||||||
|
|
||||||
@HiveField(0)
|
|
||||||
int? id = -1;
|
|
||||||
@HiveField(1)
|
|
||||||
String? bvid = '';
|
|
||||||
@HiveField(2)
|
|
||||||
int? cid = -1;
|
|
||||||
@HiveField(3)
|
|
||||||
String? goto = '';
|
|
||||||
@HiveField(4)
|
|
||||||
String? uri = '';
|
|
||||||
@HiveField(5)
|
|
||||||
String? pic = '';
|
|
||||||
@HiveField(6)
|
|
||||||
String? title = '';
|
|
||||||
@HiveField(7)
|
|
||||||
int? duration = -1;
|
|
||||||
@HiveField(8)
|
|
||||||
int? pubdate = -1;
|
|
||||||
@HiveField(9)
|
|
||||||
Owner? owner;
|
|
||||||
@HiveField(10)
|
|
||||||
Stat? stat;
|
|
||||||
@HiveField(11)
|
|
||||||
int? isFollowed;
|
|
||||||
@HiveField(12)
|
|
||||||
String? rcmdReason;
|
String? rcmdReason;
|
||||||
|
|
||||||
|
// app推荐专属
|
||||||
|
int? param;
|
||||||
|
String? bangumiBadge;
|
||||||
|
}
|
||||||
|
|
||||||
|
class RecVideoItemModel extends BaseRecVideoItemModel {
|
||||||
RecVideoItemModel.fromJson(Map<String, dynamic> json) {
|
RecVideoItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
id = json["id"];
|
aid = json["id"];
|
||||||
bvid = json["bvid"];
|
bvid = json["bvid"];
|
||||||
cid = json["cid"];
|
cid = json["cid"];
|
||||||
goto = json["goto"];
|
goto = json["goto"];
|
||||||
@@ -60,34 +24,15 @@ class RecVideoItemModel {
|
|||||||
pubdate = json["pubdate"];
|
pubdate = json["pubdate"];
|
||||||
owner = Owner.fromJson(json["owner"]);
|
owner = Owner.fromJson(json["owner"]);
|
||||||
stat = Stat.fromJson(json["stat"]);
|
stat = Stat.fromJson(json["stat"]);
|
||||||
isFollowed = json["is_followed"] ?? 0;
|
isFollowed = json["is_followed"] == 1;
|
||||||
// rcmdReason = json["rcmd_reason"] != null
|
// rcmdReason = json["rcmd_reason"] != null
|
||||||
// ? RcmdReason.fromJson(json["rcmd_reason"])
|
// ? RcmdReason.fromJson(json["rcmd_reason"])
|
||||||
// : RcmdReason(content: '');
|
// : RcmdReason(content: '');
|
||||||
rcmdReason = json["rcmd_reason"]?['content'];
|
rcmdReason = json["rcmd_reason"]?['content'];
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@HiveType(typeId: 1)
|
// @override
|
||||||
class Stat {
|
// String? get desc => null;
|
||||||
Stat({
|
|
||||||
this.view,
|
|
||||||
this.like,
|
|
||||||
this.danmu,
|
|
||||||
});
|
|
||||||
@HiveField(0)
|
|
||||||
int? view;
|
|
||||||
@HiveField(1)
|
|
||||||
int? like;
|
|
||||||
@HiveField(2)
|
|
||||||
int? danmu;
|
|
||||||
|
|
||||||
Stat.fromJson(Map<String, dynamic> json) {
|
|
||||||
// 无需在model中转换以保留原始数据,在view层处理即可
|
|
||||||
view = json["view"];
|
|
||||||
like = json["like"];
|
|
||||||
danmu = json['danmaku'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @HiveType(typeId: 2)
|
// @HiveType(typeId: 2)
|
||||||
@@ -96,10 +41,8 @@ class Stat {
|
|||||||
// this.reasonType,
|
// this.reasonType,
|
||||||
// this.content,
|
// this.content,
|
||||||
// });
|
// });
|
||||||
// @HiveField(0)
|
// // int? reasonType;
|
||||||
// int? reasonType;
|
// // String? content;
|
||||||
// @HiveField(1)
|
|
||||||
// String? content = '';
|
|
||||||
//
|
//
|
||||||
// RcmdReason.fromJson(Map<String, dynamic> json) {
|
// RcmdReason.fromJson(Map<String, dynamic> json) {
|
||||||
// reasonType = json["reason_type"];
|
// reasonType = json["reason_type"];
|
||||||
|
|||||||
@@ -1,154 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'model_rec_video_item.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// TypeAdapterGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
class RecVideoItemModelAdapter extends TypeAdapter<RecVideoItemModel> {
|
|
||||||
@override
|
|
||||||
final int typeId = 0;
|
|
||||||
|
|
||||||
@override
|
|
||||||
RecVideoItemModel read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return RecVideoItemModel(
|
|
||||||
id: fields[0] as int?,
|
|
||||||
bvid: fields[1] as String?,
|
|
||||||
cid: fields[2] as int?,
|
|
||||||
goto: fields[3] as String?,
|
|
||||||
uri: fields[4] as String?,
|
|
||||||
pic: fields[5] as String?,
|
|
||||||
title: fields[6] as String?,
|
|
||||||
duration: fields[7] as int?,
|
|
||||||
pubdate: fields[8] as int?,
|
|
||||||
owner: fields[9] as Owner?,
|
|
||||||
stat: fields[10] as Stat?,
|
|
||||||
isFollowed: fields[11] as int?,
|
|
||||||
rcmdReason: fields[12] as String?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, RecVideoItemModel obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(13)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.id)
|
|
||||||
..writeByte(1)
|
|
||||||
..write(obj.bvid)
|
|
||||||
..writeByte(2)
|
|
||||||
..write(obj.cid)
|
|
||||||
..writeByte(3)
|
|
||||||
..write(obj.goto)
|
|
||||||
..writeByte(4)
|
|
||||||
..write(obj.uri)
|
|
||||||
..writeByte(5)
|
|
||||||
..write(obj.pic)
|
|
||||||
..writeByte(6)
|
|
||||||
..write(obj.title)
|
|
||||||
..writeByte(7)
|
|
||||||
..write(obj.duration)
|
|
||||||
..writeByte(8)
|
|
||||||
..write(obj.pubdate)
|
|
||||||
..writeByte(9)
|
|
||||||
..write(obj.owner)
|
|
||||||
..writeByte(10)
|
|
||||||
..write(obj.stat)
|
|
||||||
..writeByte(11)
|
|
||||||
..write(obj.isFollowed)
|
|
||||||
..writeByte(12)
|
|
||||||
..write(obj.rcmdReason);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is RecVideoItemModelAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
class StatAdapter extends TypeAdapter<Stat> {
|
|
||||||
@override
|
|
||||||
final int typeId = 1;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stat read(BinaryReader reader) {
|
|
||||||
final numOfFields = reader.readByte();
|
|
||||||
final fields = <int, dynamic>{
|
|
||||||
for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
};
|
|
||||||
return Stat(
|
|
||||||
view: fields[0] as int?,
|
|
||||||
like: fields[1] as int?,
|
|
||||||
danmu: fields[2] as int?,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void write(BinaryWriter writer, Stat obj) {
|
|
||||||
writer
|
|
||||||
..writeByte(3)
|
|
||||||
..writeByte(0)
|
|
||||||
..write(obj.view)
|
|
||||||
..writeByte(1)
|
|
||||||
..write(obj.like)
|
|
||||||
..writeByte(2)
|
|
||||||
..write(obj.danmu);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => typeId.hashCode;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
other is StatAdapter &&
|
|
||||||
runtimeType == other.runtimeType &&
|
|
||||||
typeId == other.typeId;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// class RcmdReasonAdapter extends TypeAdapter<RcmdReason> {
|
|
||||||
// @override
|
|
||||||
// final int typeId = 2;
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// RcmdReason read(BinaryReader reader) {
|
|
||||||
// final numOfFields = reader.readByte();
|
|
||||||
// final fields = <int, dynamic>{
|
|
||||||
// for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(),
|
|
||||||
// };
|
|
||||||
// return RcmdReason(
|
|
||||||
// reasonType: fields[0] as int?,
|
|
||||||
// content: fields[1] as String?,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// void write(BinaryWriter writer, RcmdReason obj) {
|
|
||||||
// writer
|
|
||||||
// ..writeByte(2)
|
|
||||||
// ..writeByte(0)
|
|
||||||
// ..write(obj.reasonType)
|
|
||||||
// ..writeByte(1)
|
|
||||||
// ..write(obj.content);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// int get hashCode => typeId.hashCode;
|
|
||||||
//
|
|
||||||
// @override
|
|
||||||
// bool operator ==(Object other) =>
|
|
||||||
// identical(this, other) ||
|
|
||||||
// other is RcmdReasonAdapter &&
|
|
||||||
// runtimeType == other.runtimeType &&
|
|
||||||
// typeId == other.typeId;
|
|
||||||
// }
|
|
||||||
59
lib/models/model_video.dart
Normal file
59
lib/models/model_video.dart
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
|
|
||||||
|
abstract class BaseSimpleVideoItemModel {
|
||||||
|
late String title;
|
||||||
|
String? bvid;
|
||||||
|
int? cid;
|
||||||
|
String? pic;
|
||||||
|
int duration = -1;
|
||||||
|
late BaseOwner owner;
|
||||||
|
late BaseStat stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BaseVideoItemModel extends BaseSimpleVideoItemModel {
|
||||||
|
int? aid;
|
||||||
|
String? desc;
|
||||||
|
int? pubdate;
|
||||||
|
bool isFollowed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BaseOwner {
|
||||||
|
int? mid;
|
||||||
|
String? name;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BaseStat {
|
||||||
|
int? view;
|
||||||
|
int? like;
|
||||||
|
int? danmu;
|
||||||
|
|
||||||
|
String get viewStr => Utils.numFormat(view);
|
||||||
|
String get danmuStr => Utils.numFormat(danmu);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Stat extends BaseStat {
|
||||||
|
Stat.fromJson(Map<String, dynamic> json) {
|
||||||
|
view = json["view"];
|
||||||
|
like = json["like"];
|
||||||
|
danmu = json['danmaku'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PlayStat extends BaseStat {
|
||||||
|
PlayStat.fromJson(Map<String, dynamic> json) {
|
||||||
|
view = json['play'];
|
||||||
|
danmu = json['danmaku'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Dimension {
|
||||||
|
int? width;
|
||||||
|
int? height;
|
||||||
|
int? rotate;
|
||||||
|
|
||||||
|
Dimension.fromJson(Map<String, dynamic> json) {
|
||||||
|
width = json["width"];
|
||||||
|
height = json["height"];
|
||||||
|
rotate = json["rotate"];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
import 'package:PiliPlus/utils/em.dart';
|
import 'package:PiliPlus/utils/em.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
|
|
||||||
class SearchVideoModel {
|
import '../model_owner.dart';
|
||||||
SearchVideoModel({
|
import '../model_video.dart';
|
||||||
this.numResults,
|
|
||||||
this.list,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
class SearchVideoModel {
|
||||||
int? numResults;
|
int? numResults;
|
||||||
List<SearchVideoItemModel>? list;
|
List<SearchVideoItemModel>? list;
|
||||||
|
|
||||||
@@ -19,68 +17,25 @@ class SearchVideoModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SearchVideoItemModel {
|
class SearchVideoItemModel extends BaseVideoItemModel {
|
||||||
SearchVideoItemModel({
|
|
||||||
this.type,
|
|
||||||
this.id,
|
|
||||||
this.cid,
|
|
||||||
// this.author,
|
|
||||||
this.mid,
|
|
||||||
// this.typeid,
|
|
||||||
// this.typename,
|
|
||||||
this.arcurl,
|
|
||||||
this.aid,
|
|
||||||
this.bvid,
|
|
||||||
this.title,
|
|
||||||
this.description,
|
|
||||||
this.pic,
|
|
||||||
// this.play,
|
|
||||||
this.videoReview,
|
|
||||||
// this.favorites,
|
|
||||||
this.tag,
|
|
||||||
// this.review,
|
|
||||||
this.pubdate,
|
|
||||||
this.senddate,
|
|
||||||
this.duration,
|
|
||||||
// this.viewType,
|
|
||||||
// this.like,
|
|
||||||
// this.upic,
|
|
||||||
// this.danmaku,
|
|
||||||
this.owner,
|
|
||||||
this.stat,
|
|
||||||
this.rcmdReason,
|
|
||||||
});
|
|
||||||
|
|
||||||
String? type;
|
String? type;
|
||||||
int? id;
|
int? id;
|
||||||
int? cid;
|
|
||||||
// String? author;
|
// String? author;
|
||||||
int? mid;
|
|
||||||
// String? typeid;
|
// String? typeid;
|
||||||
// String? typename;
|
// String? typename;
|
||||||
String? arcurl;
|
String? arcurl;
|
||||||
int? aid;
|
|
||||||
String? bvid;
|
|
||||||
List? title;
|
|
||||||
// List? titleList;
|
|
||||||
String? description;
|
|
||||||
String? pic;
|
|
||||||
// String? play;
|
// String? play;
|
||||||
int? videoReview;
|
// int? videoReview;
|
||||||
// String? favorites;
|
// String? favorites;
|
||||||
String? tag;
|
String? tag;
|
||||||
// String? review;
|
// String? review;
|
||||||
int? pubdate;
|
int? ctime;
|
||||||
int? senddate;
|
|
||||||
int? duration;
|
|
||||||
// String? duration;
|
// String? duration;
|
||||||
// String? viewType;
|
// String? viewType;
|
||||||
// String? like;
|
// String? like;
|
||||||
// String? upic;
|
// String? upic;
|
||||||
// String? danmaku;
|
// String? danmaku;
|
||||||
Owner? owner;
|
List<Map<String, String>>? titleList;
|
||||||
Stat? stat;
|
|
||||||
String? rcmdReason;
|
|
||||||
|
|
||||||
SearchVideoItemModel.fromJson(Map<String, dynamic> json) {
|
SearchVideoItemModel.fromJson(Map<String, dynamic> json) {
|
||||||
type = json['type'];
|
type = json['type'];
|
||||||
@@ -88,43 +43,35 @@ class SearchVideoItemModel {
|
|||||||
arcurl = json['arcurl'];
|
arcurl = json['arcurl'];
|
||||||
aid = json['aid'];
|
aid = json['aid'];
|
||||||
bvid = json['bvid'];
|
bvid = json['bvid'];
|
||||||
mid = json['mid'];
|
|
||||||
// title = json['title'].replaceAll(RegExp(r'<.*?>'), '');
|
// title = json['title'].replaceAll(RegExp(r'<.*?>'), '');
|
||||||
title = Em.regTitle(json['title']);
|
titleList = Em.regTitle(json['title']);
|
||||||
description = json['description'];
|
title = titleList!.map((i) => i['text']!).join();
|
||||||
|
desc = json['description'];
|
||||||
pic = json['pic'] != null && json['pic'].startsWith('//')
|
pic = json['pic'] != null && json['pic'].startsWith('//')
|
||||||
? 'https:${json['pic']}'
|
? 'https:${json['pic']}'
|
||||||
: json['pic'] ?? '';
|
: json['pic'] ?? '';
|
||||||
videoReview = json['video_review'];
|
|
||||||
pubdate = json['pubdate'];
|
pubdate = json['pubdate'];
|
||||||
senddate = json['senddate'];
|
ctime = json['senddate'];
|
||||||
duration = Utils.duration(json['duration']);
|
duration = Utils.duration(json['duration']);
|
||||||
owner = Owner.fromJson(json);
|
owner = SearchOwner.fromJson(json);
|
||||||
stat = Stat.fromJson(json);
|
stat = SearchStat.fromJson(json);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Stat {
|
// @override
|
||||||
Stat({
|
// String? goto;
|
||||||
this.view,
|
// @override
|
||||||
this.danmu,
|
// bool isFollowed;
|
||||||
this.favorite,
|
// @override
|
||||||
this.reply,
|
// String? uri;
|
||||||
this.like,
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// 播放量
|
class SearchStat extends BaseStat {
|
||||||
int? view;
|
|
||||||
// 弹幕数
|
|
||||||
int? danmu;
|
|
||||||
// 收藏数
|
// 收藏数
|
||||||
int? favorite;
|
int? favorite;
|
||||||
// 评论数
|
// 评论数
|
||||||
int? reply;
|
int? reply;
|
||||||
// 喜欢
|
|
||||||
int? like;
|
|
||||||
|
|
||||||
Stat.fromJson(Map<String, dynamic> json) {
|
SearchStat.fromJson(Map<String, dynamic> json) {
|
||||||
view = json['play'];
|
view = json['play'];
|
||||||
danmu = json['danmaku'];
|
danmu = json['danmaku'];
|
||||||
favorite = json['favorite'];
|
favorite = json['favorite'];
|
||||||
@@ -133,17 +80,8 @@ class Stat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Owner {
|
class SearchOwner extends Owner {
|
||||||
Owner({
|
SearchOwner.fromJson(Map<String, dynamic> json) {
|
||||||
this.mid,
|
|
||||||
this.name,
|
|
||||||
this.face,
|
|
||||||
});
|
|
||||||
int? mid;
|
|
||||||
String? name;
|
|
||||||
String? face;
|
|
||||||
|
|
||||||
Owner.fromJson(Map<String, dynamic> json) {
|
|
||||||
mid = json["mid"];
|
mid = json["mid"];
|
||||||
name = json["author"];
|
name = json["author"];
|
||||||
face = json['upic'];
|
face = json['upic'];
|
||||||
@@ -301,7 +239,7 @@ class SearchLiveItemModel {
|
|||||||
rankScore = json['rank_score'];
|
rankScore = json['rank_score'];
|
||||||
roomid = json['roomid'];
|
roomid = json['roomid'];
|
||||||
attentions = json['attentions'];
|
attentions = json['attentions'];
|
||||||
cateName = Em.regCate(json['cate_name']) ?? '';
|
cateName = Em.regCate(json['cate_name']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,107 +1,90 @@
|
|||||||
import 'package:json_annotation/json_annotation.dart';
|
import '../model_owner.dart';
|
||||||
|
import '../model_video.dart';
|
||||||
import 'badge.dart';
|
import 'badge.dart';
|
||||||
import 'cursor_attr.dart';
|
import 'cursor_attr.dart';
|
||||||
import 'three_point.dart';
|
import 'three_point.dart';
|
||||||
|
|
||||||
part 'item.g.dart';
|
class Item extends BaseSimpleVideoItemModel {
|
||||||
|
|
||||||
@JsonSerializable()
|
|
||||||
class Item {
|
|
||||||
String? title;
|
|
||||||
String? subtitle;
|
String? subtitle;
|
||||||
String? tname;
|
String? tname;
|
||||||
String? cover;
|
String? get cover => pic; // 不知道哪里使用了cover
|
||||||
@JsonKey(name: 'cover_icon')
|
|
||||||
String? coverIcon;
|
String? coverIcon;
|
||||||
String? uri;
|
String? uri;
|
||||||
String? param;
|
String? param;
|
||||||
String? goto;
|
String? goto;
|
||||||
String? length;
|
String? length;
|
||||||
int? duration;
|
|
||||||
@JsonKey(name: 'is_popular')
|
|
||||||
bool? isPopular;
|
bool? isPopular;
|
||||||
@JsonKey(name: 'is_steins')
|
|
||||||
bool? isSteins;
|
bool? isSteins;
|
||||||
@JsonKey(name: 'is_ugcpay')
|
|
||||||
bool? isUgcpay;
|
bool? isUgcpay;
|
||||||
@JsonKey(name: 'is_cooperation')
|
|
||||||
bool? isCooperation;
|
bool? isCooperation;
|
||||||
@JsonKey(name: 'is_pgc')
|
|
||||||
bool? isPgc;
|
bool? isPgc;
|
||||||
@JsonKey(name: 'is_live_playback')
|
|
||||||
bool? isLivePlayback;
|
bool? isLivePlayback;
|
||||||
@JsonKey(name: 'is_pugv')
|
|
||||||
bool? isPugv;
|
bool? isPugv;
|
||||||
@JsonKey(name: 'is_fold')
|
|
||||||
bool? isFold;
|
bool? isFold;
|
||||||
@JsonKey(name: 'is_oneself')
|
|
||||||
bool? isOneself;
|
bool? isOneself;
|
||||||
int? play;
|
|
||||||
int? danmaku;
|
|
||||||
int? ctime;
|
int? ctime;
|
||||||
@JsonKey(name: 'ugc_pay')
|
|
||||||
int? ugcPay;
|
int? ugcPay;
|
||||||
String? author;
|
|
||||||
bool? state;
|
bool? state;
|
||||||
String? bvid;
|
|
||||||
int? videos;
|
int? videos;
|
||||||
@JsonKey(name: 'three_point')
|
|
||||||
List<ThreePoint>? threePoint;
|
List<ThreePoint>? threePoint;
|
||||||
@JsonKey(name: 'first_cid')
|
|
||||||
int? firstCid;
|
|
||||||
@JsonKey(name: 'cursor_attr')
|
|
||||||
CursorAttr? cursorAttr;
|
CursorAttr? cursorAttr;
|
||||||
@JsonKey(name: 'view_content')
|
|
||||||
String? viewContent;
|
|
||||||
@JsonKey(name: 'icon_type')
|
|
||||||
int? iconType;
|
int? iconType;
|
||||||
@JsonKey(name: 'publish_time_text')
|
|
||||||
String? publishTimeText;
|
String? publishTimeText;
|
||||||
List<Badge>? badges;
|
List<Badge>? badges;
|
||||||
Map? season;
|
Map? season;
|
||||||
Map? history;
|
Map? history;
|
||||||
|
|
||||||
Item({
|
Item.fromJson(Map<String, dynamic> json) {
|
||||||
this.title,
|
title = json['title'];
|
||||||
this.subtitle,
|
subtitle = json['subtitle'];
|
||||||
this.tname,
|
tname = json['tname'];
|
||||||
this.cover,
|
pic = json['cover'];
|
||||||
this.coverIcon,
|
coverIcon = json['cover_icon'];
|
||||||
this.uri,
|
uri = json['uri'];
|
||||||
this.param,
|
param = json['param'];
|
||||||
this.goto,
|
goto = json['goto'];
|
||||||
this.length,
|
length = json['length'];
|
||||||
this.duration,
|
duration = json['duration'] ?? -1;
|
||||||
this.isPopular,
|
isPopular = json['is_popular'];
|
||||||
this.isSteins,
|
isSteins = json['is_steins'];
|
||||||
this.isUgcpay,
|
isUgcpay = json['is_ugcpay'];
|
||||||
this.isCooperation,
|
isCooperation = json['is_cooperation'];
|
||||||
this.isPgc,
|
isPgc = json['is_pgc'];
|
||||||
this.isLivePlayback,
|
isLivePlayback = json['is_live_playback'];
|
||||||
this.isPugv,
|
isPugv = json['is_pugv'];
|
||||||
this.isFold,
|
isFold = json['is_fold'];
|
||||||
this.isOneself,
|
isOneself = json['is_oneself'];
|
||||||
this.play,
|
ctime = json['ctime'];
|
||||||
this.danmaku,
|
ugcPay = json['ugc_pay'];
|
||||||
this.ctime,
|
state = json['state'];
|
||||||
this.ugcPay,
|
bvid = json['bvid'];
|
||||||
this.author,
|
videos = json['videos'];
|
||||||
this.state,
|
threePoint = (json['three_point'] as List<dynamic>?)
|
||||||
this.bvid,
|
?.map((e) => ThreePoint.fromJson(e as Map<String, dynamic>))
|
||||||
this.videos,
|
.toList();
|
||||||
this.threePoint,
|
cid = json['first_cid'];
|
||||||
this.firstCid,
|
cursorAttr = json['cursor_attr'] == null
|
||||||
this.cursorAttr,
|
? null
|
||||||
this.viewContent,
|
: CursorAttr.fromJson(json['cursor_attr'] as Map<String, dynamic>);
|
||||||
this.iconType,
|
iconType = json['icon_type'];
|
||||||
this.publishTimeText,
|
publishTimeText = json['publish_time_text'];
|
||||||
this.badges,
|
badges = (json['badges'] as List<dynamic>?)
|
||||||
this.season,
|
?.map((e) => Badge.fromJson(e as Map<String, dynamic>))
|
||||||
this.history,
|
.toList();
|
||||||
});
|
season = json['season'];
|
||||||
|
history = json['history'];
|
||||||
factory Item.fromJson(Map<String, dynamic> json) => _$ItemFromJson(json);
|
stat = PlayStat.fromJson(json);
|
||||||
|
owner = Owner(mid: 0, name: json['author']);
|
||||||
Map<String, dynamic> toJson() => _$ItemToJson(this);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserStat extends PlayStat {
|
||||||
|
String? _viewStr;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get viewStr => _viewStr ?? super.viewStr;
|
||||||
|
|
||||||
|
UserStat.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
|
||||||
|
_viewStr = json['view_content'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'item.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// JsonSerializableGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
Item _$ItemFromJson(Map<String, dynamic> json) => Item(
|
|
||||||
title: json['title'] as String?,
|
|
||||||
subtitle: json['subtitle'] as String?,
|
|
||||||
tname: json['tname'] as String?,
|
|
||||||
cover: json['cover'] as String?,
|
|
||||||
coverIcon: json['cover_icon'] as String?,
|
|
||||||
uri: json['uri'] as String?,
|
|
||||||
param: json['param'] as String?,
|
|
||||||
goto: json['goto'] as String?,
|
|
||||||
length: json['length'] as String?,
|
|
||||||
duration: (json['duration'] as num?)?.toInt(),
|
|
||||||
isPopular: json['is_popular'] as bool?,
|
|
||||||
isSteins: json['is_steins'] as bool?,
|
|
||||||
isUgcpay: json['is_ugcpay'] as bool?,
|
|
||||||
isCooperation: json['is_cooperation'] as bool?,
|
|
||||||
isPgc: json['is_pgc'] as bool?,
|
|
||||||
isLivePlayback: json['is_live_playback'] as bool?,
|
|
||||||
isPugv: json['is_pugv'] as bool?,
|
|
||||||
isFold: json['is_fold'] as bool?,
|
|
||||||
isOneself: json['is_oneself'] as bool?,
|
|
||||||
play: (json['play'] as num?)?.toInt(),
|
|
||||||
danmaku: (json['danmaku'] as num?)?.toInt(),
|
|
||||||
ctime: (json['ctime'] as num?)?.toInt(),
|
|
||||||
ugcPay: (json['ugc_pay'] as num?)?.toInt(),
|
|
||||||
author: json['author'] as String?,
|
|
||||||
state: json['state'] as bool?,
|
|
||||||
bvid: json['bvid'] as String?,
|
|
||||||
videos: (json['videos'] as num?)?.toInt(),
|
|
||||||
threePoint: (json['three_point'] as List<dynamic>?)
|
|
||||||
?.map((e) => ThreePoint.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
firstCid: (json['first_cid'] as num?)?.toInt(),
|
|
||||||
cursorAttr: json['cursor_attr'] == null
|
|
||||||
? null
|
|
||||||
: CursorAttr.fromJson(json['cursor_attr'] as Map<String, dynamic>),
|
|
||||||
viewContent: json['view_content'] as String?,
|
|
||||||
iconType: (json['icon_type'] as num?)?.toInt(),
|
|
||||||
publishTimeText: json['publish_time_text'] as String?,
|
|
||||||
badges: (json['badges'] as List<dynamic>?)
|
|
||||||
?.map((e) => Badge.fromJson(e as Map<String, dynamic>))
|
|
||||||
.toList(),
|
|
||||||
season: json['season'],
|
|
||||||
history: json['history'],
|
|
||||||
);
|
|
||||||
|
|
||||||
Map<String, dynamic> _$ItemToJson(Item instance) => <String, dynamic>{
|
|
||||||
'title': instance.title,
|
|
||||||
'subtitle': instance.subtitle,
|
|
||||||
'tname': instance.tname,
|
|
||||||
'cover': instance.cover,
|
|
||||||
'cover_icon': instance.coverIcon,
|
|
||||||
'uri': instance.uri,
|
|
||||||
'param': instance.param,
|
|
||||||
'goto': instance.goto,
|
|
||||||
'length': instance.length,
|
|
||||||
'duration': instance.duration,
|
|
||||||
'is_popular': instance.isPopular,
|
|
||||||
'is_steins': instance.isSteins,
|
|
||||||
'is_ugcpay': instance.isUgcpay,
|
|
||||||
'is_cooperation': instance.isCooperation,
|
|
||||||
'is_pgc': instance.isPgc,
|
|
||||||
'is_live_playback': instance.isLivePlayback,
|
|
||||||
'is_pugv': instance.isPugv,
|
|
||||||
'is_fold': instance.isFold,
|
|
||||||
'is_oneself': instance.isOneself,
|
|
||||||
'play': instance.play,
|
|
||||||
'danmaku': instance.danmaku,
|
|
||||||
'ctime': instance.ctime,
|
|
||||||
'ugc_pay': instance.ugcPay,
|
|
||||||
'author': instance.author,
|
|
||||||
'state': instance.state,
|
|
||||||
'bvid': instance.bvid,
|
|
||||||
'videos': instance.videos,
|
|
||||||
'three_point': instance.threePoint,
|
|
||||||
'first_cid': instance.firstCid,
|
|
||||||
'cursor_attr': instance.cursorAttr,
|
|
||||||
'view_content': instance.viewContent,
|
|
||||||
'icon_type': instance.iconType,
|
|
||||||
'publish_time_text': instance.publishTimeText,
|
|
||||||
'badges': instance.badges,
|
|
||||||
'season': instance.season,
|
|
||||||
};
|
|
||||||
@@ -1,83 +1,45 @@
|
|||||||
import 'package:PiliPlus/models/model_owner.dart';
|
import '../model_owner.dart';
|
||||||
import 'package:PiliPlus/models/user/fav_folder.dart';
|
import '../model_video.dart';
|
||||||
|
import 'fav_folder.dart';
|
||||||
|
|
||||||
class FavDetailData {
|
class FavDetailData {
|
||||||
FavDetailData({
|
|
||||||
this.info,
|
|
||||||
this.medias,
|
|
||||||
this.hasMore,
|
|
||||||
});
|
|
||||||
|
|
||||||
FavFolderItemData? info;
|
FavFolderItemData? info;
|
||||||
List<FavDetailItemData>? medias;
|
List<FavDetailItemData>? list;
|
||||||
|
List<FavDetailItemData>? get medias => list;
|
||||||
bool? hasMore;
|
bool? hasMore;
|
||||||
|
|
||||||
FavDetailData.fromJson(Map<String, dynamic> json) {
|
FavDetailData.fromJson(Map<String, dynamic> json) {
|
||||||
info =
|
info =
|
||||||
json['info'] == null ? null : FavFolderItemData.fromJson(json['info']);
|
json['info'] == null ? null : FavFolderItemData.fromJson(json['info']);
|
||||||
medias = (json['medias'] as List?)
|
list = (json['medias'] as List?)
|
||||||
?.map<FavDetailItemData>((e) => FavDetailItemData.fromJson(e))
|
?.map<FavDetailItemData>((e) => FavDetailItemData.fromJson(e))
|
||||||
.toList();
|
.toList();
|
||||||
hasMore = json['has_more'];
|
hasMore = json['has_more'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FavDetailItemData {
|
class FavDetailItemData extends BaseVideoItemModel {
|
||||||
FavDetailItemData({
|
|
||||||
this.id,
|
|
||||||
this.type,
|
|
||||||
this.title,
|
|
||||||
this.pic,
|
|
||||||
this.intro,
|
|
||||||
this.page,
|
|
||||||
this.duration,
|
|
||||||
this.owner,
|
|
||||||
this.attr,
|
|
||||||
this.cntInfo,
|
|
||||||
this.link,
|
|
||||||
this.ctime,
|
|
||||||
this.pubdate,
|
|
||||||
this.favTime,
|
|
||||||
this.bvId,
|
|
||||||
this.bvid,
|
|
||||||
// this.season,
|
|
||||||
this.ogv,
|
|
||||||
this.stat,
|
|
||||||
this.cid,
|
|
||||||
this.epId,
|
|
||||||
this.checked,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? id;
|
int? id;
|
||||||
int? type;
|
int? type;
|
||||||
String? title;
|
|
||||||
String? pic;
|
|
||||||
String? intro;
|
|
||||||
int? page;
|
int? page;
|
||||||
int? duration;
|
|
||||||
Owner? owner;
|
|
||||||
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/fav/list.md
|
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/fav/list.md
|
||||||
// | attr | num | 失效 | 0: 正常;9: up自己删除;1: 其他原因删除 |
|
// | attr | num | 失效 | 0: 正常;9: up自己删除;1: 其他原因删除 |
|
||||||
int? attr;
|
int? attr;
|
||||||
Map? cntInfo;
|
Map? cntInfo;
|
||||||
String? link;
|
String? link;
|
||||||
int? ctime;
|
int? ctime;
|
||||||
int? pubdate;
|
|
||||||
int? favTime;
|
int? favTime;
|
||||||
String? bvId;
|
|
||||||
String? bvid;
|
|
||||||
Map? ogv;
|
Map? ogv;
|
||||||
Stat? stat;
|
|
||||||
int? cid;
|
|
||||||
String? epId;
|
String? epId;
|
||||||
bool? checked;
|
bool? checked;
|
||||||
|
|
||||||
FavDetailItemData.fromJson(Map<String, dynamic> json) {
|
FavDetailItemData.fromJson(Map<String, dynamic> json) {
|
||||||
id = json['id'];
|
id = json['id'];
|
||||||
|
aid = id;
|
||||||
type = json['type'];
|
type = json['type'];
|
||||||
title = json['title'];
|
title = json['title'];
|
||||||
pic = json['cover'];
|
pic = json['cover'];
|
||||||
intro = json['intro'];
|
desc = json['intro'];
|
||||||
page = json['page'];
|
page = json['page'];
|
||||||
duration = json['duration'];
|
duration = json['duration'];
|
||||||
owner = Owner.fromJson(json['upper']);
|
owner = Owner.fromJson(json['upper']);
|
||||||
@@ -87,38 +49,18 @@ class FavDetailItemData {
|
|||||||
ctime = json['ctime'];
|
ctime = json['ctime'];
|
||||||
pubdate = json['pubtime'];
|
pubdate = json['pubtime'];
|
||||||
favTime = json['fav_time'];
|
favTime = json['fav_time'];
|
||||||
bvId = json['bv_id'];
|
|
||||||
bvid = json['bvid'];
|
bvid = json['bvid'];
|
||||||
ogv = json['ogv'];
|
ogv = json['ogv'];
|
||||||
stat = Stat.fromJson(json['cnt_info']);
|
stat = PlayStat.fromJson(json['cnt_info']);
|
||||||
cid = json['ugc'] != null ? json['ugc']['first_cid'] : null;
|
cid = json['ugc']?['first_cid'];
|
||||||
if (json['link'] != null && json['link'].contains('/bangumi')) {
|
if (json['link'] != null && json['link'].contains('/bangumi')) {
|
||||||
epId = resolveEpId(json['link']);
|
epId = resolveEpId(json['link']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String resolveEpId(url) {
|
static final _digitRegExp = RegExp(r'\d+');
|
||||||
RegExp regex = RegExp(r'\d+');
|
String resolveEpId(String url) => _digitRegExp.firstMatch(url)!.group(0)!;
|
||||||
Iterable<Match> matches = regex.allMatches(url);
|
|
||||||
List<String> numbers = [];
|
|
||||||
for (Match match in matches) {
|
|
||||||
numbers.add(match.group(0)!);
|
|
||||||
}
|
|
||||||
return numbers[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Stat {
|
// @override
|
||||||
Stat({
|
// bool isFollowed;
|
||||||
this.view,
|
|
||||||
this.danmu,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? view;
|
|
||||||
int? danmu;
|
|
||||||
|
|
||||||
Stat.fromJson(Map<String, dynamic> json) {
|
|
||||||
view = json['play'];
|
|
||||||
danmu = json['danmaku'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,47 +60,19 @@ class HisTabItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class HisListItem {
|
class HisListItem {
|
||||||
HisListItem({
|
late String title;
|
||||||
this.title,
|
|
||||||
this.longTitle,
|
|
||||||
this.cover,
|
|
||||||
this.pic,
|
|
||||||
this.covers,
|
|
||||||
this.uri,
|
|
||||||
this.history,
|
|
||||||
this.videos,
|
|
||||||
this.authorName,
|
|
||||||
this.authorFace,
|
|
||||||
this.authorMid,
|
|
||||||
this.viewAt,
|
|
||||||
this.progress,
|
|
||||||
this.badge,
|
|
||||||
this.showTitle,
|
|
||||||
this.duration,
|
|
||||||
this.current,
|
|
||||||
this.total,
|
|
||||||
this.newDesc,
|
|
||||||
this.isFinish,
|
|
||||||
this.isFav,
|
|
||||||
this.kid,
|
|
||||||
this.tagName,
|
|
||||||
this.liveStatus,
|
|
||||||
this.checked,
|
|
||||||
});
|
|
||||||
|
|
||||||
String? title;
|
|
||||||
String? longTitle;
|
String? longTitle;
|
||||||
String? cover;
|
String? cover;
|
||||||
String? pic;
|
String? pic;
|
||||||
List? covers;
|
List? covers;
|
||||||
String? uri;
|
String? uri;
|
||||||
History? history;
|
late History history;
|
||||||
int? videos;
|
int? videos;
|
||||||
String? authorName;
|
String? authorName;
|
||||||
String? authorFace;
|
String? authorFace;
|
||||||
int? authorMid;
|
int? authorMid;
|
||||||
int? viewAt;
|
int? viewAt;
|
||||||
int? progress;
|
int progress = 0;
|
||||||
String? badge;
|
String? badge;
|
||||||
String? showTitle;
|
String? showTitle;
|
||||||
int? duration;
|
int? duration;
|
||||||
@@ -113,7 +85,7 @@ class HisListItem {
|
|||||||
String? tagName;
|
String? tagName;
|
||||||
int? liveStatus;
|
int? liveStatus;
|
||||||
bool? checked;
|
bool? checked;
|
||||||
void isFullScreen;
|
dynamic isFullScreen;
|
||||||
|
|
||||||
HisListItem.fromJson(Map<String, dynamic> json) {
|
HisListItem.fromJson(Map<String, dynamic> json) {
|
||||||
title = json['title'];
|
title = json['title'];
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
class SubDetailModelData {
|
class SubDetailModelData {
|
||||||
DetailInfo? info;
|
DetailInfo? info;
|
||||||
List<SubDetailMediaItem>? medias;
|
List<SubDetailMediaItem>? list;
|
||||||
|
|
||||||
SubDetailModelData({this.info, this.medias});
|
List<SubDetailMediaItem>? get medias => list; // 不知道哪里使用了这个
|
||||||
|
|
||||||
|
SubDetailModelData({this.info, this.list});
|
||||||
|
|
||||||
SubDetailModelData.fromJson(Map<String, dynamic> json) {
|
SubDetailModelData.fromJson(Map<String, dynamic> json) {
|
||||||
info = DetailInfo.fromJson(json['info']);
|
info = DetailInfo.fromJson(json['info']);
|
||||||
if (json['medias'] != null) {
|
list = (json['medias'] as List?)
|
||||||
medias = <SubDetailMediaItem>[];
|
?.map((i) => SubDetailMediaItem.fromJson(i))
|
||||||
json['medias'].forEach((v) {
|
.toList();
|
||||||
medias!.add(SubDetailMediaItem.fromJson(v));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,8 +22,8 @@ class SubDetailMediaItem {
|
|||||||
int? duration;
|
int? duration;
|
||||||
int? pubtime;
|
int? pubtime;
|
||||||
String? bvid;
|
String? bvid;
|
||||||
Map? upper;
|
Map<String, dynamic>? upper;
|
||||||
Map? cntInfo;
|
Map<String, dynamic>? cntInfo;
|
||||||
int? enableVt;
|
int? enableVt;
|
||||||
String? vtDisplay;
|
String? vtDisplay;
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
import '../model_owner.dart';
|
||||||
|
import '../model_video.dart';
|
||||||
|
|
||||||
class MediaVideoItemModel {
|
class MediaVideoItemModel {
|
||||||
MediaVideoItemModel({
|
MediaVideoItemModel({
|
||||||
this.id,
|
this.id,
|
||||||
@@ -43,7 +46,7 @@ class MediaVideoItemModel {
|
|||||||
int? attr;
|
int? attr;
|
||||||
int? tid;
|
int? tid;
|
||||||
int? copyRight;
|
int? copyRight;
|
||||||
Map? cntInfo;
|
Map<String, dynamic>? cntInfo;
|
||||||
String? cover;
|
String? cover;
|
||||||
int? duration;
|
int? duration;
|
||||||
int? pubtime;
|
int? pubtime;
|
||||||
@@ -152,24 +155,6 @@ class Page {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Dimension {
|
|
||||||
Dimension({
|
|
||||||
this.width,
|
|
||||||
this.height,
|
|
||||||
this.rotate,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? width;
|
|
||||||
int? height;
|
|
||||||
int? rotate;
|
|
||||||
|
|
||||||
factory Dimension.fromJson(Map<String, dynamic> json) => Dimension(
|
|
||||||
width: json["width"],
|
|
||||||
height: json["height"],
|
|
||||||
rotate: json["rotate"],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Meta {
|
class Meta {
|
||||||
Meta({
|
Meta({
|
||||||
this.quality,
|
this.quality,
|
||||||
@@ -224,26 +209,7 @@ class Rights {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Upper {
|
class Upper extends Owner {
|
||||||
Upper({
|
|
||||||
this.mid,
|
|
||||||
this.name,
|
|
||||||
this.face,
|
|
||||||
this.followed,
|
|
||||||
this.fans,
|
|
||||||
this.vipType,
|
|
||||||
this.vipStatue,
|
|
||||||
this.vipDueDate,
|
|
||||||
this.vipPayType,
|
|
||||||
this.officialRole,
|
|
||||||
this.officialTitle,
|
|
||||||
this.officialDesc,
|
|
||||||
this.displayName,
|
|
||||||
});
|
|
||||||
|
|
||||||
int? mid;
|
|
||||||
String? name;
|
|
||||||
String? face;
|
|
||||||
int? followed;
|
int? followed;
|
||||||
int? fans;
|
int? fans;
|
||||||
int? vipType;
|
int? vipType;
|
||||||
@@ -255,19 +221,16 @@ class Upper {
|
|||||||
String? officialDesc;
|
String? officialDesc;
|
||||||
String? displayName;
|
String? displayName;
|
||||||
|
|
||||||
factory Upper.fromJson(Map<String, dynamic> json) => Upper(
|
Upper.fromJson(Map<String, dynamic> json) : super.fromJson(json) {
|
||||||
mid: json["mid"],
|
followed = json["followed"];
|
||||||
name: json["name"],
|
fans = json["fans"];
|
||||||
face: json["face"],
|
vipType = json["vip_type"];
|
||||||
followed: json["followed"],
|
vipStatue = json["vip_statue"];
|
||||||
fans: json["fans"],
|
vipDueDate = json["vip_due_date"];
|
||||||
vipType: json["vip_type"],
|
vipPayType = json["vip_pay_type"];
|
||||||
vipStatue: json["vip_statue"],
|
officialRole = json["official_role"];
|
||||||
vipDueDate: json["vip_due_date"],
|
officialTitle = json["official_title"];
|
||||||
vipPayType: json["vip_pay_type"],
|
officialDesc = json["official_desc"];
|
||||||
officialRole: json["official_role"],
|
displayName = json["display_name"];
|
||||||
officialTitle: json["official_title"],
|
}
|
||||||
officialDesc: json["official_desc"],
|
|
||||||
displayName: json["display_name"],
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -324,19 +324,19 @@ class _BangumiInfoState extends State<BangumiInfo>
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: !widget.isLoading
|
value: Utils.numFormat(!widget.isLoading
|
||||||
? widget.bangumiDetail!.stat!['views']
|
? widget.bangumiDetail!.stat!['views']
|
||||||
: bangumiItem!.stat!['views'],
|
: bangumiItem!.stat!['views']),
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: !widget.isLoading
|
value: Utils.numFormat(!widget.isLoading
|
||||||
? widget
|
? widget
|
||||||
.bangumiDetail!.stat!['danmakus']
|
.bangumiDetail!.stat!['danmakus']
|
||||||
: bangumiItem!.stat!['danmakus'],
|
: bangumiItem!.stat!['danmakus']),
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
),
|
),
|
||||||
if (isLandscape) ...[
|
if (isLandscape) ...[
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
|
import 'package:PiliPlus/common/widgets/stat/stat.dart';
|
||||||
|
import 'package:PiliPlus/models/bangumi/info.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_collapse_slide_page.dart';
|
import 'package:PiliPlus/pages/common/common_collapse_slide_page.dart';
|
||||||
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
|
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:PiliPlus/common/widgets/stat/stat.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
import '../../../../utils/utils.dart';
|
import '../../../../utils/utils.dart';
|
||||||
|
|
||||||
class IntroDetail extends CommonCollapseSlidePage {
|
class IntroDetail extends CommonCollapseSlidePage {
|
||||||
final dynamic bangumiDetail;
|
final BangumiInfoModel bangumiDetail;
|
||||||
final dynamic videoTags;
|
final dynamic videoTags;
|
||||||
|
|
||||||
const IntroDetail({
|
const IntroDetail({
|
||||||
super.key,
|
super.key,
|
||||||
this.bangumiDetail,
|
required this.bangumiDetail,
|
||||||
this.videoTags,
|
this.videoTags,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
|
|||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
SelectableText(
|
SelectableText(
|
||||||
widget.bangumiDetail!.title,
|
widget.bangumiDetail.title!,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
@@ -81,14 +82,14 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: widget.bangumiDetail!.stat!['views'],
|
value: Utils.numFormat(widget.bangumiDetail.stat!['views']),
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: widget.bangumiDetail!.stat!['danmakus'],
|
value: Utils.numFormat(widget.bangumiDetail.stat!['danmakus']),
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -97,17 +98,17 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
widget.bangumiDetail!.areas!.first['name'],
|
widget.bangumiDetail.areas!.first['name'],
|
||||||
style: smallTitle,
|
style: smallTitle,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
widget.bangumiDetail!.publish!['pub_time_show'],
|
widget.bangumiDetail.publish!['pub_time_show'],
|
||||||
style: smallTitle,
|
style: smallTitle,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
widget.bangumiDetail!.newEp!['desc'],
|
widget.bangumiDetail.newEp!['desc'],
|
||||||
style: smallTitle,
|
style: smallTitle,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -119,7 +120,7 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
SelectableText(
|
SelectableText(
|
||||||
'${widget.bangumiDetail!.evaluate!}',
|
widget.bangumiDetail.evaluate!,
|
||||||
style: smallTitle.copyWith(fontSize: 14),
|
style: smallTitle.copyWith(fontSize: 14),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
@@ -129,7 +130,7 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
SelectableText(
|
SelectableText(
|
||||||
widget.bangumiDetail.actors,
|
widget.bangumiDetail.actors!,
|
||||||
style: smallTitle.copyWith(fontSize: 14),
|
style: smallTitle.copyWith(fontSize: 14),
|
||||||
),
|
),
|
||||||
if (widget.videoTags is List && widget.videoTags.isNotEmpty) ...[
|
if (widget.videoTags is List && widget.videoTags.isNotEmpty) ...[
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ Widget bangumiContent(Item bangumiItem) {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
bangumiItem.title ?? '',
|
bangumiItem.title,
|
||||||
textAlign: TextAlign.start,
|
textAlign: TextAlign.start,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
letterSpacing: 0.3,
|
letterSpacing: 0.3,
|
||||||
|
|||||||
@@ -41,21 +41,20 @@ class FavDetailController extends MultiSelectController {
|
|||||||
item.value = data.info ?? FavFolderItemData();
|
item.value = data.info ?? FavFolderItemData();
|
||||||
isOwner.value = data.info?.mid == mid;
|
isOwner.value = data.info?.mid == mid;
|
||||||
}
|
}
|
||||||
if (data.medias.isNullOrEmpty) {
|
if (data.list.isNullOrEmpty) {
|
||||||
isEnd = true;
|
isEnd = true;
|
||||||
}
|
}
|
||||||
if (currentPage != 1 && loadingState.value is Success) {
|
if (currentPage != 1 && loadingState.value is Success) {
|
||||||
data.medias ??= <FavDetailItemData>[];
|
data.list ??= <FavDetailItemData>[];
|
||||||
data.medias!.insertAll(
|
data.list!.insertAll(
|
||||||
0,
|
0,
|
||||||
List<FavDetailItemData>.from((loadingState.value as Success).response),
|
(loadingState.value as Success).response,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (isEnd.not &&
|
if (isEnd.not && (data.list?.length ?? 0) >= (data.info?.mediaCount ?? 0)) {
|
||||||
(data.medias?.length ?? 0) >= (data.info?.mediaCount ?? 0)) {
|
|
||||||
isEnd = true;
|
isEnd = true;
|
||||||
}
|
}
|
||||||
loadingState.value = LoadingState.success(data.medias);
|
loadingState.value = LoadingState.success(data.list);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,8 +137,7 @@ class FavDetailController extends MultiSelectController {
|
|||||||
|
|
||||||
void toViewPlayAll() {
|
void toViewPlayAll() {
|
||||||
if (loadingState.value is Success) {
|
if (loadingState.value is Success) {
|
||||||
List<FavDetailItemData> list = List<FavDetailItemData>.from(
|
List<FavDetailItemData> list = (loadingState.value as Success).response;
|
||||||
(loadingState.value as Success).response);
|
|
||||||
for (FavDetailItemData element in list) {
|
for (FavDetailItemData element in list) {
|
||||||
if (element.cid == null) {
|
if (element.cid == null) {
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:PiliPlus/common/widgets/dialog.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/user.dart';
|
import 'package:PiliPlus/http/user.dart';
|
||||||
|
import 'package:PiliPlus/models/user/fav_detail.dart';
|
||||||
import 'package:PiliPlus/models/user/fav_folder.dart';
|
import 'package:PiliPlus/models/user/fav_folder.dart';
|
||||||
import 'package:PiliPlus/pages/fav_search/view.dart' show SearchType;
|
import 'package:PiliPlus/pages/fav_search/view.dart' show SearchType;
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
@@ -429,15 +430,15 @@ class _FavDetailPageState extends State<FavDetailPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
final element = loadingState.response[index];
|
FavDetailItemData element = loadingState.response[index];
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: FavVideoCardH(
|
child: FavVideoCardH(
|
||||||
videoItem: element,
|
videoItem: element,
|
||||||
callFn: () => _favDetailController.onCancelFav(
|
callFn: () => _favDetailController.onCancelFav(
|
||||||
element.id,
|
element.id!,
|
||||||
element.type,
|
element.type!,
|
||||||
),
|
),
|
||||||
onViewFav: () {
|
onViewFav: () {
|
||||||
Utils.toViewPage(
|
Utils.toViewPage(
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
import 'package:PiliPlus/common/widgets/icon_button.dart';
|
||||||
import 'package:PiliPlus/common/widgets/image_save.dart';
|
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/models/user/fav_detail.dart';
|
||||||
import 'package:PiliPlus/utils/extension.dart';
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/common/widgets/stat/stat.dart';
|
|
||||||
import 'package:PiliPlus/http/search.dart';
|
import 'package:PiliPlus/http/search.dart';
|
||||||
import 'package:PiliPlus/http/video.dart';
|
import 'package:PiliPlus/http/video.dart';
|
||||||
import 'package:PiliPlus/utils/id_utils.dart';
|
import 'package:PiliPlus/utils/id_utils.dart';
|
||||||
@@ -16,7 +16,7 @@ import '../../../common/widgets/badge.dart';
|
|||||||
|
|
||||||
// 收藏视频卡片 - 水平布局
|
// 收藏视频卡片 - 水平布局
|
||||||
class FavVideoCardH extends StatelessWidget {
|
class FavVideoCardH extends StatelessWidget {
|
||||||
final dynamic videoItem;
|
final FavDetailItemData videoItem;
|
||||||
final Function? callFn;
|
final Function? callFn;
|
||||||
final int? searchType;
|
final int? searchType;
|
||||||
final GestureTapCallback? onTap;
|
final GestureTapCallback? onTap;
|
||||||
@@ -37,7 +37,7 @@ class FavVideoCardH extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
int id = videoItem.id;
|
int id = videoItem.id!;
|
||||||
String bvid = videoItem.bvid ?? IdUtils.av2bv(id);
|
String bvid = videoItem.bvid ?? IdUtils.av2bv(id);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@@ -48,11 +48,11 @@ class FavVideoCardH extends StatelessWidget {
|
|||||||
String? epId;
|
String? epId;
|
||||||
if (videoItem.type == 24) {
|
if (videoItem.type == 24) {
|
||||||
videoItem.cid = await SearchHttp.ab2c(bvid: bvid);
|
videoItem.cid = await SearchHttp.ab2c(bvid: bvid);
|
||||||
dynamic seasonId = videoItem.ogv['season_id'];
|
dynamic seasonId = videoItem.ogv!['season_id'];
|
||||||
epId = videoItem.epId;
|
epId = videoItem.epId;
|
||||||
Utils.viewBangumi(seasonId: seasonId, epId: epId);
|
Utils.viewBangumi(seasonId: seasonId, epId: epId);
|
||||||
return;
|
return;
|
||||||
} else if (videoItem.page == 0 || videoItem.page > 1) {
|
} else if (videoItem.page == 0 || videoItem.page! > 1) {
|
||||||
var result = await VideoHttp.videoIntro(bvid: bvid);
|
var result = await VideoHttp.videoIntro(bvid: bvid);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
epId = result['data'].epId;
|
epId = result['data'].epId;
|
||||||
@@ -61,9 +61,8 @@ class FavVideoCardH extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoItem is FavDetailItemData &&
|
if ([0, 16].contains(videoItem.attr).not) {
|
||||||
[0, 16].contains(videoItem.attr).not) {
|
Get.toNamed('/member?mid=${videoItem.owner.mid}');
|
||||||
Get.toNamed('/member?mid=${videoItem.owner?.mid}');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onViewFav();
|
onViewFav();
|
||||||
@@ -117,21 +116,20 @@ class FavVideoCardH extends StatelessWidget {
|
|||||||
height: maxHeight,
|
height: maxHeight,
|
||||||
),
|
),
|
||||||
PBadge(
|
PBadge(
|
||||||
text: Utils.timeFormat(videoItem.duration!),
|
text: Utils.timeFormat(videoItem.duration),
|
||||||
right: 6.0,
|
right: 6.0,
|
||||||
bottom: 6.0,
|
bottom: 6.0,
|
||||||
type: 'gray',
|
type: 'gray',
|
||||||
),
|
),
|
||||||
if (videoItem.ogv != null) ...[
|
if (videoItem.ogv != null)
|
||||||
PBadge(
|
PBadge(
|
||||||
text: videoItem.ogv['type_name'],
|
text: videoItem.ogv!['type_name'],
|
||||||
top: 6.0,
|
top: 6.0,
|
||||||
right: 6.0,
|
right: 6.0,
|
||||||
bottom: null,
|
bottom: null,
|
||||||
left: null,
|
left: null,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -163,30 +161,28 @@ class FavVideoCardH extends StatelessWidget {
|
|||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
if (videoItem.ogv != null) ...[
|
if (videoItem.ogv != null)
|
||||||
Text(
|
Text(
|
||||||
videoItem.intro,
|
videoItem.desc!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Text(
|
Text(
|
||||||
Utils.dateFormat(videoItem.favTime),
|
Utils.dateFormat(videoItem.favTime),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11, color: Theme.of(context).colorScheme.outline),
|
fontSize: 11, color: Theme.of(context).colorScheme.outline),
|
||||||
),
|
),
|
||||||
if (videoItem.owner.name != '') ...[
|
if (!videoItem.owner.name.isNullOrEmpty)
|
||||||
Text(
|
Text(
|
||||||
videoItem.owner.name,
|
videoItem.owner.name!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 2),
|
padding: const EdgeInsets.only(top: 2),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -194,13 +190,13 @@ class FavVideoCardH extends StatelessWidget {
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoItem.cntInfo['play'],
|
value: videoItem.stat.viewStr,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoItem.cntInfo['danmaku'],
|
value: videoItem.stat.danmuStr,
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -49,17 +49,11 @@ class FavSearchController extends CommonController {
|
|||||||
late List currentList = loadingState.value is Success
|
late List currentList = loadingState.value is Success
|
||||||
? (loadingState.value as Success).response
|
? (loadingState.value as Success).response
|
||||||
: [];
|
: [];
|
||||||
List? dataList = searchType == SearchType.fav
|
List? dataList = currentPage == 1
|
||||||
? (currentPage == 1
|
|
||||||
? response.response.medias
|
|
||||||
: response.response.medias != null
|
|
||||||
? currentList + response.response.medias
|
|
||||||
: currentList)
|
|
||||||
: (currentPage == 1
|
|
||||||
? response.response.list
|
? response.response.list
|
||||||
: response.response.list != null
|
: response.response.list != null
|
||||||
? currentList + response.response.list
|
? currentList + response.response.list
|
||||||
: currentList);
|
: currentList;
|
||||||
isEnd = searchType == SearchType.fav
|
isEnd = searchType == SearchType.fav
|
||||||
? response.response.hasMore == false
|
? response.response.hasMore == false
|
||||||
: response.response.list == null || response.response.list.isEmpty;
|
: response.response.list == null || response.response.list.isEmpty;
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
|||||||
return switch (loadingState) {
|
return switch (loadingState) {
|
||||||
Loading() => errorWidget(),
|
Loading() => errorWidget(),
|
||||||
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
Success() => (loadingState.response as List?)?.isNotEmpty == true
|
||||||
? _favSearchCtr.searchType == SearchType.fav
|
? switch (_favSearchCtr.searchType) {
|
||||||
? CustomScrollView(
|
SearchType.fav => CustomScrollView(
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
controller: _favSearchCtr.scrollController,
|
controller: _favSearchCtr.scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
@@ -120,9 +120,8 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
: _favSearchCtr.searchType == SearchType.follow
|
SearchType.follow => ListView.builder(
|
||||||
? ListView.builder(
|
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||||
),
|
),
|
||||||
@@ -136,8 +135,8 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
|||||||
item: loadingState.response[index],
|
item: loadingState.response[index],
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
)
|
),
|
||||||
: CustomScrollView(
|
SearchType.history => CustomScrollView(
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
controller: _favSearchCtr.scrollController,
|
controller: _favSearchCtr.scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
@@ -167,7 +166,8 @@ class _FavSearchPageState extends State<FavSearchPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
|
}
|
||||||
: errorWidget(
|
: errorWidget(
|
||||||
callback: _favSearchCtr.onReload,
|
callback: _favSearchCtr.onReload,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ class HistoryController extends MultiSelectController
|
|||||||
bool customHandleResponse(Success response) {
|
bool customHandleResponse(Success response) {
|
||||||
HistoryData data = response.response;
|
HistoryData data = response.response;
|
||||||
isEnd = data.list.isNullOrEmpty || data.list!.length < 20;
|
isEnd = data.list.isNullOrEmpty || data.list!.length < 20;
|
||||||
max = data.list?.lastOrNull?.history?.oid;
|
max = data.list?.lastOrNull?.history.oid;
|
||||||
viewAt = data.list?.lastOrNull?.viewAt;
|
viewAt = data.list?.lastOrNull?.viewAt;
|
||||||
if (currentPage == 1) {
|
if (currentPage == 1) {
|
||||||
if (type == null && tabs.isEmpty && data.tab?.isNotEmpty == true) {
|
if (type == null && tabs.isEmpty && data.tab?.isNotEmpty == true) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:PiliPlus/models/user/history.dart';
|
|||||||
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
|
||||||
import 'package:PiliPlus/pages/fav_search/controller.dart';
|
import 'package:PiliPlus/pages/fav_search/controller.dart';
|
||||||
import 'package:PiliPlus/pages/history/base_controller.dart';
|
import 'package:PiliPlus/pages/history/base_controller.dart';
|
||||||
|
import 'package:PiliPlus/utils/extension.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -20,7 +21,7 @@ import 'package:PiliPlus/utils/utils.dart';
|
|||||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||||
|
|
||||||
class HistoryItem extends StatelessWidget {
|
class HistoryItem extends StatelessWidget {
|
||||||
final dynamic videoItem;
|
final HisListItem videoItem;
|
||||||
final dynamic ctr;
|
final dynamic ctr;
|
||||||
final Function? onChoose;
|
final Function? onChoose;
|
||||||
final Function? onDelete;
|
final Function? onDelete;
|
||||||
@@ -35,7 +36,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
int aid = videoItem.history.oid;
|
int aid = videoItem.history.oid!;
|
||||||
String bvid = videoItem.history.bvid ?? IdUtils.av2bv(aid);
|
String bvid = videoItem.history.bvid ?? IdUtils.av2bv(aid);
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
@@ -45,7 +46,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
onChoose?.call();
|
onChoose?.call();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (videoItem.history.business.contains('article')) {
|
if (videoItem.history.business?.contains('article') == true) {
|
||||||
// int cid = videoItem.history.cid ??
|
// int cid = videoItem.history.cid ??
|
||||||
// // videoItem.history.oid ??
|
// // videoItem.history.oid ??
|
||||||
// await SearchHttp.ab2c(aid: aid, bvid: bvid);
|
// await SearchHttp.ab2c(aid: aid, bvid: bvid);
|
||||||
@@ -80,8 +81,8 @@ class HistoryItem extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast('直播未开播');
|
SmartDialog.showToast('直播未开播');
|
||||||
}
|
}
|
||||||
} else if (videoItem.history?.business == 'pgc' ||
|
} else if (videoItem.history.business == 'pgc' ||
|
||||||
videoItem.tagName.contains('动画')) {
|
videoItem.tagName?.contains('动画') == true) {
|
||||||
/// hack
|
/// hack
|
||||||
var bvid = videoItem.history.bvid;
|
var bvid = videoItem.history.bvid;
|
||||||
if (bvid != null && bvid != '') {
|
if (bvid != null && bvid != '') {
|
||||||
@@ -106,7 +107,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
SmartDialog.showToast(result['msg']);
|
SmartDialog.showToast(result['msg']);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (videoItem.history.epid != '') {
|
if (videoItem.history.epid != null && videoItem.history.epid != 0) {
|
||||||
Utils.viewBangumi(epId: videoItem.history.epid);
|
Utils.viewBangumi(epId: videoItem.history.epid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -164,9 +165,9 @@ class HistoryItem extends StatelessWidget {
|
|||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
NetworkImgLayer(
|
NetworkImgLayer(
|
||||||
src: (videoItem.cover != ''
|
src: (videoItem.cover.isNullOrEmpty
|
||||||
? videoItem.cover
|
? videoItem.covers?.first ?? ''
|
||||||
: videoItem.covers.first),
|
: videoItem.cover),
|
||||||
width: maxWidth,
|
width: maxWidth,
|
||||||
height: maxHeight,
|
height: maxHeight,
|
||||||
),
|
),
|
||||||
@@ -176,7 +177,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
PBadge(
|
PBadge(
|
||||||
text: videoItem.progress == -1
|
text: videoItem.progress == -1
|
||||||
? '已看完'
|
? '已看完'
|
||||||
: '${Utils.timeFormat(videoItem.progress!)}/${Utils.timeFormat(videoItem.duration!)}',
|
: '${Utils.timeFormat(videoItem.progress)}/${Utils.timeFormat(videoItem.duration!)}',
|
||||||
right: 6.0,
|
right: 6.0,
|
||||||
bottom: 8.0,
|
bottom: 8.0,
|
||||||
type: 'gray',
|
type: 'gray',
|
||||||
@@ -254,7 +255,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
child: videoProgressIndicator(
|
child: videoProgressIndicator(
|
||||||
videoItem.progress == -1
|
videoItem.progress == -1
|
||||||
? 1
|
? 1
|
||||||
: videoItem.progress / videoItem.duration,
|
: videoItem.progress / videoItem.duration!,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -281,7 +282,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
letterSpacing: 0.3,
|
letterSpacing: 0.3,
|
||||||
),
|
),
|
||||||
maxLines: videoItem.videos > 1 ? 1 : 2,
|
maxLines: videoItem.videos! > 1 ? 1 : 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
if (videoItem.isFullScreen != null) ...[
|
if (videoItem.isFullScreen != null) ...[
|
||||||
@@ -301,7 +302,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
videoItem.authorName,
|
videoItem.authorName!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
@@ -318,7 +319,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||||
color: Theme.of(context).colorScheme.outline),
|
color: Theme.of(context).colorScheme.outline),
|
||||||
),
|
),
|
||||||
if (videoItem is HisListItem)
|
// if (videoItem is HisListItem)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 29,
|
width: 29,
|
||||||
height: 29,
|
height: 29,
|
||||||
@@ -356,11 +357,11 @@ class HistoryItem extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (videoItem.history?.business != 'pgc' &&
|
if (videoItem.history.business != 'pgc' &&
|
||||||
videoItem.badge != '番剧' &&
|
videoItem.badge != '番剧' &&
|
||||||
!videoItem.tagName.contains('动画') &&
|
videoItem.tagName?.contains('动画') != true &&
|
||||||
videoItem.history.business != 'live' &&
|
videoItem.history.business != 'live' &&
|
||||||
!videoItem.history.business.contains('article'))
|
videoItem.history.business?.contains('article') != true)
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
var res = await UserHttp.toViewLater(
|
var res = await UserHttp.toViewLater(
|
||||||
@@ -377,10 +378,7 @@ class HistoryItem extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
PopupMenuItem<String>(
|
PopupMenuItem<String>(
|
||||||
onTap: () => ctr is HistoryBaseController
|
onTap: () => ctr!.delHistory(
|
||||||
? onDelete?.call(
|
|
||||||
videoItem.kid, videoItem.history.business)
|
|
||||||
: ctr!.delHistory(
|
|
||||||
videoItem.kid, videoItem.history.business),
|
videoItem.kid, videoItem.history.business),
|
||||||
height: 35,
|
height: 35,
|
||||||
child: const Row(
|
child: const Row(
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:get/get.dart';
|
|||||||
import 'package:PiliPlus/http/member.dart';
|
import 'package:PiliPlus/http/member.dart';
|
||||||
import 'package:PiliPlus/http/user.dart';
|
import 'package:PiliPlus/http/user.dart';
|
||||||
import 'package:PiliPlus/http/video.dart';
|
import 'package:PiliPlus/http/video.dart';
|
||||||
import 'package:PiliPlus/models/member/archive.dart';
|
|
||||||
import 'package:PiliPlus/models/member/coin.dart';
|
import 'package:PiliPlus/models/member/coin.dart';
|
||||||
import 'package:PiliPlus/models/member/info.dart';
|
import 'package:PiliPlus/models/member/info.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
@@ -22,7 +21,6 @@ class MemberController extends GetxController {
|
|||||||
late int ownerMid;
|
late int ownerMid;
|
||||||
bool specialFollowed = false;
|
bool specialFollowed = false;
|
||||||
// 投稿列表
|
// 投稿列表
|
||||||
RxList<VListItemModel>? archiveList = <VListItemModel>[].obs;
|
|
||||||
dynamic userInfo;
|
dynamic userInfo;
|
||||||
RxInt attribute = (-1).obs;
|
RxInt attribute = (-1).obs;
|
||||||
RxString attributeText = '关注'.obs;
|
RxString attributeText = '关注'.obs;
|
||||||
@@ -43,7 +41,12 @@ class MemberController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
Future<Map<String, dynamic>> getInfo() async {
|
Future<Map<String, dynamic>> getInfo() {
|
||||||
|
return Future.wait([getMemberInfo(), getMemberStat(), getMemberView()])
|
||||||
|
.then((res) => res[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> getMemberInfo() async {
|
||||||
wwebid = await Utils.getWwebid(mid);
|
wwebid = await Utils.getWwebid(mid);
|
||||||
await getMemberStat();
|
await getMemberStat();
|
||||||
await getMemberView();
|
await getMemberView();
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ class MemberVideoCtr extends CommonController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Item element in list) {
|
for (Item element in list) {
|
||||||
if (element.firstCid == null) {
|
if (element.cid == null) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
if (element.bvid != list.first.bvid) {
|
if (element.bvid != list.first.bvid) {
|
||||||
@@ -150,7 +150,7 @@ class MemberVideoCtr extends CommonController {
|
|||||||
? desc.not
|
? desc.not
|
||||||
: desc;
|
: desc;
|
||||||
Utils.toViewPage(
|
Utils.toViewPage(
|
||||||
'bvid=${element.bvid}&cid=${element.firstCid}',
|
'bvid=${element.bvid}&cid=${element.cid}',
|
||||||
arguments: {
|
arguments: {
|
||||||
'videoItem': element,
|
'videoItem': element,
|
||||||
'heroTag': Utils.makeHeroTag(element.bvid),
|
'heroTag': Utils.makeHeroTag(element.bvid),
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class MemberArchiveController extends GetxController {
|
|||||||
int pn = 1;
|
int pn = 1;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
RxMap<String, String> currentOrder = <String, String>{}.obs;
|
RxMap<String, String> currentOrder = <String, String>{}.obs;
|
||||||
List<Map<String, String>> orderList = [
|
static const List<Map<String, String>> orderList = [
|
||||||
{'type': 'pubdate', 'label': '最新发布'},
|
{'type': 'pubdate', 'label': '最新发布'},
|
||||||
{'type': 'click', 'label': '最多播放'},
|
{'type': 'click', 'label': '最多播放'},
|
||||||
{'type': 'stow', 'label': '最多收藏'},
|
{'type': 'stow', 'label': '最多收藏'},
|
||||||
@@ -37,8 +37,7 @@ class MemberArchiveController extends GetxController {
|
|||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
if (type == 'init') {
|
if (type == 'init') {
|
||||||
archivesList.value = res['data'].list.vlist;
|
archivesList.value = res['data'].list.vlist;
|
||||||
}
|
} else if (type == 'onLoad') {
|
||||||
if (type == 'onLoad') {
|
|
||||||
archivesList.addAll(res['data'].list.vlist);
|
archivesList.addAll(res['data'].list.vlist);
|
||||||
}
|
}
|
||||||
count = res['data'].page['count'];
|
count = res['data'].page['count'];
|
||||||
@@ -49,7 +48,7 @@ class MemberArchiveController extends GetxController {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSort() async {
|
toggleSort() {
|
||||||
List<String> typeList = orderList.map((e) => e['type']!).toList();
|
List<String> typeList = orderList.map((e) => e['type']!).toList();
|
||||||
int index = typeList.indexOf(currentOrder['type']!);
|
int index = typeList.indexOf(currentOrder['type']!);
|
||||||
if (index == orderList.length - 1) {
|
if (index == orderList.length - 1) {
|
||||||
@@ -61,9 +60,7 @@ class MemberArchiveController extends GetxController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 上拉加载
|
// 上拉加载
|
||||||
Future onLoad() async {
|
Future onLoad() => getMemberArchive('onLoad');
|
||||||
getMemberArchive('onLoad');
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onClose() {
|
void onClose() {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class _MemberArchivePageState extends State<MemberArchivePage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Map data = snapshot.data as Map;
|
Map data = snapshot.data as Map;
|
||||||
List list = _memberArchivesController.archivesList;
|
final list = _memberArchivesController.archivesList;
|
||||||
if (data['status']) {
|
if (data['status']) {
|
||||||
return Obx(
|
return Obx(
|
||||||
() => list.isNotEmpty
|
() => list.isNotEmpty
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import 'package:PiliPlus/common/widgets/image_save.dart';
|
import 'package:PiliPlus/common/widgets/image_save.dart';
|
||||||
|
import 'package:PiliPlus/common/widgets/stat/stat.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/common/widgets/badge.dart';
|
import 'package:PiliPlus/common/widgets/badge.dart';
|
||||||
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
||||||
import 'package:PiliPlus/common/widgets/stat/stat.dart';
|
|
||||||
import 'package:PiliPlus/http/search.dart';
|
import 'package:PiliPlus/http/search.dart';
|
||||||
import 'package:PiliPlus/models/member/coin.dart';
|
import 'package:PiliPlus/models/member/coin.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
@@ -53,7 +53,7 @@ class MemberCoinsItem extends StatelessWidget {
|
|||||||
width: maxWidth,
|
width: maxWidth,
|
||||||
height: maxHeight,
|
height: maxHeight,
|
||||||
),
|
),
|
||||||
if (coinItem.duration != null)
|
if (coinItem.duration > 0)
|
||||||
PBadge(
|
PBadge(
|
||||||
bottom: 6,
|
bottom: 6,
|
||||||
right: 6,
|
right: 6,
|
||||||
@@ -80,9 +80,15 @@ class MemberCoinsItem extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
value: coinItem.view!,
|
value: coinItem.stat.viewStr,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
StatDanMu(
|
||||||
|
context: context,
|
||||||
|
theme: 'gray',
|
||||||
|
value: coinItem.stat.danmuStr,
|
||||||
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Text(
|
Text(
|
||||||
Utils.customStampStr(
|
Utils.customStampStr(
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
import 'package:PiliPlus/common/widgets/stat/stat.dart';
|
||||||
|
import 'package:PiliPlus/models/member/seasons.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:PiliPlus/common/constants.dart';
|
import 'package:PiliPlus/common/constants.dart';
|
||||||
import 'package:PiliPlus/common/widgets/badge.dart';
|
import 'package:PiliPlus/common/widgets/badge.dart';
|
||||||
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
|
||||||
import 'package:PiliPlus/common/widgets/stat/stat.dart';
|
|
||||||
import 'package:PiliPlus/http/search.dart';
|
import 'package:PiliPlus/http/search.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
|
|
||||||
class MemberSeasonsItem extends StatelessWidget {
|
class MemberSeasonsItem extends StatelessWidget {
|
||||||
final dynamic seasonItem;
|
final MemberArchiveItem seasonItem;
|
||||||
|
|
||||||
const MemberSeasonsItem({
|
const MemberSeasonsItem({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -65,7 +66,7 @@ class MemberSeasonsItem extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
seasonItem.title,
|
seasonItem.title!,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@@ -74,7 +75,7 @@ class MemberSeasonsItem extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
value: seasonItem.view,
|
value: Utils.numFormat(seasonItem.view!),
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
|
|||||||
@@ -132,8 +132,6 @@ class _SearchPanelState extends State<SearchPanel>
|
|||||||
_searchPanelController,
|
_searchPanelController,
|
||||||
loadingState,
|
loadingState,
|
||||||
);
|
);
|
||||||
default:
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,15 +50,16 @@ class SubDetailController extends GetxController {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
subInfo.value = res['data'].info;
|
SubDetailModelData data = res['data'];
|
||||||
|
subInfo.value = data.info!;
|
||||||
if (currentPage == 1 && type == 'init') {
|
if (currentPage == 1 && type == 'init') {
|
||||||
subList.value = res['data'].medias;
|
subList.value = data.list!;
|
||||||
mediaCount = res['data'].info.mediaCount;
|
mediaCount = data.info!.mediaCount!;
|
||||||
if (item.type == 11) {
|
if (item.type == 11) {
|
||||||
playCount.value = res['data'].info.cntInfo!['play'];
|
playCount.value = data.info!.cntInfo!['play'];
|
||||||
}
|
}
|
||||||
} else if (type == 'onLoad') {
|
} else if (type == 'onLoad') {
|
||||||
subList.addAll(res['data'].medias);
|
subList.addAll(data.list!);
|
||||||
}
|
}
|
||||||
if (subList.length >= mediaCount) {
|
if (subList.length >= mediaCount) {
|
||||||
loadingText.value = '没有更多了';
|
loadingText.value = '没有更多了';
|
||||||
|
|||||||
@@ -129,13 +129,13 @@ class SubVideoCardH extends StatelessWidget {
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoItem.cntInfo?['play'],
|
value: Utils.numFormat(videoItem.cntInfo?['play']),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoItem.cntInfo?['danmaku'],
|
value: Utils.numFormat(videoItem.cntInfo?['danmaku']),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -616,9 +616,9 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: !widget.loadingStatus
|
value: Utils.numFormat(!widget.loadingStatus
|
||||||
? videoDetail.stat?.view ?? '-'
|
? videoDetail.stat?.view ?? '-'
|
||||||
: videoItem['stat']?.view ?? '-',
|
: videoItem['stat']?.view ?? '-'),
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
textColor: t.colorScheme.outline,
|
textColor: t.colorScheme.outline,
|
||||||
),
|
),
|
||||||
@@ -626,9 +626,9 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: !widget.loadingStatus
|
value: Utils.numFormat(!widget.loadingStatus
|
||||||
? videoDetail.stat?.danmu ?? '-'
|
? videoDetail.stat?.danmu ?? '-'
|
||||||
: videoItem['stat']?.danmu ?? '-',
|
: videoItem['stat']?.danmu ?? '-'),
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
textColor: t.colorScheme.outline,
|
textColor: t.colorScheme.outline,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -57,14 +57,14 @@ class IntroDetail extends StatelessWidget {
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoDetail!.stat!.view,
|
value: Utils.numFormat(videoDetail!.stat!.view),
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: videoDetail!.stat!.danmu,
|
value: Utils.numFormat(videoDetail!.stat!.danmu),
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
|||||||
widget.videoIntroController.changeSeasonOrbangu(
|
widget.videoIntroController.changeSeasonOrbangu(
|
||||||
null,
|
null,
|
||||||
videoItem.bvid,
|
videoItem.bvid,
|
||||||
videoItem.firstCid,
|
videoItem.cid,
|
||||||
IdUtils.bv2av(videoItem.bvid!),
|
IdUtils.bv2av(videoItem.bvid!),
|
||||||
videoItem.cover,
|
videoItem.cover,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ class _AiDetailState extends CommonCollapseSlidePageState<AiDetail> {
|
|||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text:
|
text:
|
||||||
Utils.tampToSeektime(item.timestamp!),
|
Utils.formatDuration(item.timestamp!),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
@@ -198,15 +198,8 @@ class _AiDetailState extends CommonCollapseSlidePageState<AiDetail> {
|
|||||||
tag: Get
|
tag: Get
|
||||||
.arguments['heroTag'])
|
.arguments['heroTag'])
|
||||||
.plPlayerController
|
.plPlayerController
|
||||||
.seekTo(
|
.seekTo(Duration(
|
||||||
Duration(
|
seconds: item.timestamp!));
|
||||||
seconds: Utils.duration(
|
|
||||||
Utils.tampToSeektime(
|
|
||||||
item.timestamp!)
|
|
||||||
.toString(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -234,14 +234,15 @@ class _MediaListPanelState extends CommonSlidePageState<MediaListPanel> {
|
|||||||
StatView(
|
StatView(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value: item.cntInfo!['play'] as int,
|
value: Utils.numFormat(
|
||||||
|
item.cntInfo!['play']!),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
StatDanMu(
|
StatDanMu(
|
||||||
context: context,
|
context: context,
|
||||||
theme: 'gray',
|
theme: 'gray',
|
||||||
value:
|
value: Utils.numFormat(
|
||||||
item.cntInfo!['danmaku'] as int,
|
item.cntInfo!['danmaku']!),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,31 +1,27 @@
|
|||||||
import 'package:html/parser.dart' show parse;
|
import 'package:html/parser.dart' show parse;
|
||||||
|
|
||||||
class Em {
|
class Em {
|
||||||
static regCate(String origin) {
|
static final _exp = RegExp('<[^>]*>([^<]*)</[^>]*>');
|
||||||
String str = origin;
|
|
||||||
RegExp exp = RegExp('<[^>]*>([^<]*)</[^>]*>');
|
static String regCate(String origin) {
|
||||||
Iterable<Match> matches = exp.allMatches(origin);
|
Iterable<Match> matches = _exp.allMatches(origin);
|
||||||
for (Match match in matches) {
|
return matches.lastOrNull?.group(1) ?? origin;
|
||||||
str = match.group(1)!;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static regTitle(String origin) {
|
static List<Map<String, String>> regTitle(String origin) {
|
||||||
RegExp exp = RegExp('<[^>]*>([^<]*)</[^>]*>');
|
List<Map<String, String>> res = [];
|
||||||
List res = [];
|
|
||||||
origin.splitMapJoin(
|
origin.splitMapJoin(
|
||||||
exp,
|
_exp,
|
||||||
onMatch: (Match match) {
|
onMatch: (Match match) {
|
||||||
String matchStr = match[0]!;
|
String matchStr = match[0]!;
|
||||||
Map map = {'type': 'em', 'text': regCate(matchStr)};
|
var map = {'type': 'em', 'text': regCate(matchStr)};
|
||||||
res.add(map);
|
res.add(map);
|
||||||
return regCate(matchStr);
|
return matchStr;
|
||||||
},
|
},
|
||||||
onNonMatch: (String str) {
|
onNonMatch: (String str) {
|
||||||
if (str != '') {
|
if (str != '') {
|
||||||
str = parse(str).body?.text ?? str;
|
str = parse(str).body?.text ?? str;
|
||||||
Map map = {'type': 'text', 'text': str};
|
var map = {'type': 'text', 'text': str};
|
||||||
res.add(map);
|
res.add(map);
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import 'package:PiliPlus/models/model_video.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
import 'storage.dart';
|
import 'storage.dart';
|
||||||
@@ -30,46 +31,30 @@ class RecommendFilter {
|
|||||||
.get(SettingBoxKey.applyFilterToRelatedVideos, defaultValue: true);
|
.get(SettingBoxKey.applyFilterToRelatedVideos, defaultValue: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool filter(dynamic videoItem, {bool relatedVideos = false}) {
|
static bool filter(BaseVideoItemModel videoItem) {
|
||||||
if (relatedVideos && !applyFilterToRelatedVideos) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
//由于相关视频中没有已关注标签,只能视为非关注视频
|
//由于相关视频中没有已关注标签,只能视为非关注视频
|
||||||
if (!relatedVideos &&
|
if (videoItem.isFollowed && exemptFilterForFollowed) {
|
||||||
videoItem.isFollowed == 1 &&
|
|
||||||
exemptFilterForFollowed) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (videoItem.duration > 0 && videoItem.duration < minDurationForRcmd) {
|
return filterAll(videoItem);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (filterLikeRatio(videoItem.stat.like, videoItem.stat.view)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (filterTitle(videoItem.title)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool filterLikeRatio(like, view) {
|
static bool filterLikeRatio(int? like, int? view) {
|
||||||
if (view is int &&
|
return (view != null &&
|
||||||
view > -1 &&
|
view > -1 &&
|
||||||
like is int &&
|
like != null &&
|
||||||
like > -1 &&
|
like > -1 &&
|
||||||
like * 100 < minLikeRatioForRecommend * view) {
|
like * 100 < minLikeRatioForRecommend * view);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool filterTitle(String title, {bool? isFollowed}) {
|
static bool filterTitle(String title) {
|
||||||
if (exemptFilterForFollowed && isFollowed == true) {
|
return (rcmdRegExp.pattern.isNotEmpty && rcmdRegExp.hasMatch(title));
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (rcmdRegExp.pattern.isNotEmpty && rcmdRegExp.hasMatch(title)) {
|
|
||||||
return true;
|
static bool filterAll(BaseVideoItemModel videoItem) {
|
||||||
}
|
return (videoItem.duration > 0 &&
|
||||||
return false;
|
videoItem.duration < minDurationForRcmd) ||
|
||||||
|
filterLikeRatio(videoItem.stat.like, videoItem.stat.view) ||
|
||||||
|
filterTitle(videoItem.title);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,11 +47,17 @@ import 'package:html/dom.dart' as dom;
|
|||||||
import 'package:html/parser.dart' as html_parser;
|
import 'package:html/parser.dart' as html_parser;
|
||||||
import 'package:path/path.dart' as path;
|
import 'package:path/path.dart' as path;
|
||||||
|
|
||||||
|
import '../models/home/rcmd/result.dart';
|
||||||
|
import '../models/model_rec_video_item.dart';
|
||||||
|
import '../models/model_video.dart';
|
||||||
|
|
||||||
class Utils {
|
class Utils {
|
||||||
static final Random random = Random();
|
static final Random random = Random();
|
||||||
|
|
||||||
static const channel = MethodChannel("PiliPlus");
|
static const channel = MethodChannel("PiliPlus");
|
||||||
|
|
||||||
|
static final _numRegExp = RegExp(r'([\d\.]+)([千万亿])?');
|
||||||
|
|
||||||
static ThemeData getThemeData({
|
static ThemeData getThemeData({
|
||||||
required ColorScheme colorScheme,
|
required ColorScheme colorScheme,
|
||||||
required bool isDynamic,
|
required bool isDynamic,
|
||||||
@@ -1149,6 +1155,32 @@ class Utils {
|
|||||||
// return tempPath;
|
// return tempPath;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
static int getUnit(String? unit) {
|
||||||
|
switch (unit) {
|
||||||
|
case '千':
|
||||||
|
return 1000;
|
||||||
|
case '万':
|
||||||
|
return 10000;
|
||||||
|
case '亿':
|
||||||
|
return 100000000;
|
||||||
|
default:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseNum(String numberStr) {
|
||||||
|
if (numberStr == '-') return 0;
|
||||||
|
try {
|
||||||
|
final match = _numRegExp.firstMatch(numberStr)!;
|
||||||
|
var number = double.parse(match.group(1)!);
|
||||||
|
number *= getUnit(match.group(2));
|
||||||
|
return number.toInt();
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('parse failed: "$numberStr" : $e');
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static String numFormat(dynamic number) {
|
static String numFormat(dynamic number) {
|
||||||
if (number == null) {
|
if (number == null) {
|
||||||
return '00:00';
|
return '00:00';
|
||||||
@@ -1197,63 +1229,49 @@ class Utils {
|
|||||||
return '${int.parse(durationParts[0])}秒';
|
return '${int.parse(durationParts[0])}秒';
|
||||||
}
|
}
|
||||||
|
|
||||||
static String videoItemSemantics(dynamic videoItem) {
|
static String videoItemSemantics(BaseVideoItemModel videoItem) {
|
||||||
String semanticsLabel = "";
|
StringBuffer semanticsLabel = StringBuffer();
|
||||||
bool emptyStatCheck(dynamic stat) {
|
bool emptyStatCheck(int? stat) {
|
||||||
return stat == null ||
|
return stat == null || stat <= 0;
|
||||||
stat == '' ||
|
|
||||||
stat == 0 ||
|
|
||||||
stat == '0' ||
|
|
||||||
stat == '-';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (videoItem.runtimeType.toString() == "RecVideoItemAppModel") {
|
if (videoItem is RecVideoItemAppModel) {
|
||||||
if (videoItem.goto == 'picture') {
|
if (videoItem.goto == 'picture') {
|
||||||
semanticsLabel += '动态,';
|
semanticsLabel.write('动态,');
|
||||||
} else if (videoItem.goto == 'bangumi') {
|
} else if (videoItem.goto == 'bangumi') {
|
||||||
semanticsLabel += '番剧,';
|
semanticsLabel.write('番剧,');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (videoItem.title is String) {
|
semanticsLabel.write(videoItem.title);
|
||||||
semanticsLabel += videoItem.title;
|
|
||||||
} else {
|
|
||||||
semanticsLabel +=
|
|
||||||
videoItem.title.map((e) => e['text'] as String).join('');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!emptyStatCheck(videoItem.stat.view)) {
|
if (!emptyStatCheck(videoItem.stat.view)) {
|
||||||
semanticsLabel += ',${Utils.numFormat(videoItem.stat.view)}';
|
semanticsLabel.write(',${Utils.numFormat(videoItem.stat.view)}');
|
||||||
semanticsLabel +=
|
semanticsLabel.write(
|
||||||
(videoItem.runtimeType.toString() == "RecVideoItemAppModel" &&
|
(videoItem is RecVideoItemAppModel && videoItem.goto == 'picture')
|
||||||
videoItem.goto == 'picture')
|
|
||||||
? '浏览'
|
? '浏览'
|
||||||
: '播放';
|
: '播放');
|
||||||
}
|
}
|
||||||
if (!emptyStatCheck(videoItem.stat.danmu)) {
|
if (!emptyStatCheck(videoItem.stat.danmu)) {
|
||||||
semanticsLabel += ',${Utils.numFormat(videoItem.stat.danmu)}弹幕';
|
semanticsLabel.write(',${Utils.numFormat(videoItem.stat.danmu)}弹幕');
|
||||||
}
|
}
|
||||||
if (videoItem.rcmdReason != null) {
|
if ((videoItem is BaseRecVideoItemModel) && videoItem.rcmdReason != null) {
|
||||||
semanticsLabel += ',${videoItem.rcmdReason}';
|
semanticsLabel.write(',${videoItem.rcmdReason}');
|
||||||
}
|
}
|
||||||
if (!emptyStatCheck(videoItem.duration) &&
|
if (!emptyStatCheck(videoItem.duration) && videoItem.duration > 0) {
|
||||||
(videoItem.duration is! int || videoItem.duration > 0)) {
|
semanticsLabel.write(
|
||||||
semanticsLabel +=
|
',时长${Utils.durationReadFormat(Utils.timeFormat(videoItem.duration))}');
|
||||||
',时长${Utils.durationReadFormat(Utils.timeFormat(videoItem.duration))}';
|
|
||||||
}
|
}
|
||||||
if (videoItem.runtimeType.toString() != "RecVideoItemAppModel" &&
|
if (videoItem.pubdate != null) {
|
||||||
videoItem.pubdate != null) {
|
semanticsLabel
|
||||||
semanticsLabel +=
|
.write(',${Utils.dateFormat(videoItem.pubdate!, formatType: 'day')}');
|
||||||
',${Utils.dateFormat(videoItem.pubdate!, formatType: 'day')}';
|
|
||||||
}
|
}
|
||||||
if (videoItem.owner.name != '') {
|
if (videoItem.owner.name != '') {
|
||||||
semanticsLabel += ',Up主:${videoItem.owner.name}';
|
semanticsLabel.write(',Up主:${videoItem.owner.name}');
|
||||||
}
|
}
|
||||||
if ((videoItem.runtimeType.toString() == "RecVideoItemAppModel" ||
|
if (videoItem is BaseRecVideoItemModel && videoItem.isFollowed) {
|
||||||
videoItem.runtimeType.toString() == "RecVideoItemModel") &&
|
semanticsLabel.write(',已关注');
|
||||||
videoItem.isFollowed == 1) {
|
|
||||||
semanticsLabel += ',已关注';
|
|
||||||
}
|
}
|
||||||
return semanticsLabel;
|
return semanticsLabel.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
static String timeFormat(dynamic time) {
|
static String timeFormat(dynamic time) {
|
||||||
@@ -1263,14 +1281,7 @@ class Utils {
|
|||||||
if (time == null || time == 0) {
|
if (time == null || time == 0) {
|
||||||
return '00:00';
|
return '00:00';
|
||||||
}
|
}
|
||||||
int hour = time ~/ 3600;
|
return formatDuration(time);
|
||||||
int minute = (time % 3600) ~/ 60;
|
|
||||||
int second = time % 60;
|
|
||||||
String paddingStr(int number) {
|
|
||||||
return number.toString().padLeft(2, '0');
|
|
||||||
}
|
|
||||||
|
|
||||||
return '${hour > 0 ? "${paddingStr(hour)}:" : ""}${paddingStr(minute)}:${paddingStr(second)}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static String shortenChineseDateString(String date) {
|
static String shortenChineseDateString(String date) {
|
||||||
@@ -1570,17 +1581,6 @@ class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 时间戳转时间
|
|
||||||
static tampToSeektime(number) {
|
|
||||||
int hours = number ~/ 60;
|
|
||||||
int minutes = number % 60;
|
|
||||||
|
|
||||||
String formattedHours = hours.toString().padLeft(2, '0');
|
|
||||||
String formattedMinutes = minutes.toString().padLeft(2, '0');
|
|
||||||
|
|
||||||
return '$formattedHours:$formattedMinutes';
|
|
||||||
}
|
|
||||||
|
|
||||||
static double getSheetHeight(BuildContext context) {
|
static double getSheetHeight(BuildContext context) {
|
||||||
double height = context.height.abs();
|
double height = context.height.abs();
|
||||||
double width = context.width.abs();
|
double width = context.width.abs();
|
||||||
|
|||||||
Reference in New Issue
Block a user