refa: video model (#523)

This commit is contained in:
My-Responsitories
2025-03-25 10:12:44 +08:00
committed by GitHub
parent bf464994df
commit 7a6085e923
52 changed files with 761 additions and 1494 deletions

View File

@@ -324,19 +324,19 @@ class _BangumiInfoState extends State<BangumiInfo>
StatView(
context: context,
theme: 'gray',
value: !widget.isLoading
value: Utils.numFormat(!widget.isLoading
? widget.bangumiDetail!.stat!['views']
: bangumiItem!.stat!['views'],
: bangumiItem!.stat!['views']),
size: 'medium',
),
const SizedBox(width: 6),
StatDanMu(
context: context,
theme: 'gray',
value: !widget.isLoading
value: Utils.numFormat(!widget.isLoading
? widget
.bangumiDetail!.stat!['danmakus']
: bangumiItem!.stat!['danmakus'],
: bangumiItem!.stat!['danmakus']),
size: 'medium',
),
if (isLandscape) ...[

View File

@@ -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/search/widgets/search_text.dart';
import 'package:flutter/material.dart';
import 'package:PiliPlus/common/widgets/stat/stat.dart';
import 'package:get/get.dart';
import '../../../../utils/utils.dart';
class IntroDetail extends CommonCollapseSlidePage {
final dynamic bangumiDetail;
final BangumiInfoModel bangumiDetail;
final dynamic videoTags;
const IntroDetail({
super.key,
this.bangumiDetail,
required this.bangumiDetail,
this.videoTags,
});
@@ -70,7 +71,7 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
),
children: [
SelectableText(
widget.bangumiDetail!.title,
widget.bangumiDetail.title!,
style: const TextStyle(
fontSize: 16,
),
@@ -81,14 +82,14 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
StatView(
context: context,
theme: 'gray',
value: widget.bangumiDetail!.stat!['views'],
value: Utils.numFormat(widget.bangumiDetail.stat!['views']),
size: 'medium',
),
const SizedBox(width: 6),
StatDanMu(
context: context,
theme: 'gray',
value: widget.bangumiDetail!.stat!['danmakus'],
value: Utils.numFormat(widget.bangumiDetail.stat!['danmakus']),
size: 'medium',
),
],
@@ -97,17 +98,17 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
Row(
children: [
Text(
widget.bangumiDetail!.areas!.first['name'],
widget.bangumiDetail.areas!.first['name'],
style: smallTitle,
),
const SizedBox(width: 6),
Text(
widget.bangumiDetail!.publish!['pub_time_show'],
widget.bangumiDetail.publish!['pub_time_show'],
style: smallTitle,
),
const SizedBox(width: 6),
Text(
widget.bangumiDetail!.newEp!['desc'],
widget.bangumiDetail.newEp!['desc'],
style: smallTitle,
),
],
@@ -119,7 +120,7 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
),
const SizedBox(height: 4),
SelectableText(
'${widget.bangumiDetail!.evaluate!}',
widget.bangumiDetail.evaluate!,
style: smallTitle.copyWith(fontSize: 14),
),
const SizedBox(height: 20),
@@ -129,7 +130,7 @@ class _IntroDetailState extends CommonCollapseSlidePageState<IntroDetail> {
),
const SizedBox(height: 4),
SelectableText(
widget.bangumiDetail.actors,
widget.bangumiDetail.actors!,
style: smallTitle.copyWith(fontSize: 14),
),
if (widget.videoTags is List && widget.videoTags.isNotEmpty) ...[

View File

@@ -98,7 +98,7 @@ Widget bangumiContent(Item bangumiItem) {
children: [
Expanded(
child: Text(
bangumiItem.title ?? '',
bangumiItem.title,
textAlign: TextAlign.start,
style: const TextStyle(
letterSpacing: 0.3,

View File

@@ -41,21 +41,20 @@ class FavDetailController extends MultiSelectController {
item.value = data.info ?? FavFolderItemData();
isOwner.value = data.info?.mid == mid;
}
if (data.medias.isNullOrEmpty) {
if (data.list.isNullOrEmpty) {
isEnd = true;
}
if (currentPage != 1 && loadingState.value is Success) {
data.medias ??= <FavDetailItemData>[];
data.medias!.insertAll(
data.list ??= <FavDetailItemData>[];
data.list!.insertAll(
0,
List<FavDetailItemData>.from((loadingState.value as Success).response),
(loadingState.value as Success).response,
);
}
if (isEnd.not &&
(data.medias?.length ?? 0) >= (data.info?.mediaCount ?? 0)) {
if (isEnd.not && (data.list?.length ?? 0) >= (data.info?.mediaCount ?? 0)) {
isEnd = true;
}
loadingState.value = LoadingState.success(data.medias);
loadingState.value = LoadingState.success(data.list);
return true;
}
@@ -138,8 +137,7 @@ class FavDetailController extends MultiSelectController {
void toViewPlayAll() {
if (loadingState.value is Success) {
List<FavDetailItemData> list = List<FavDetailItemData>.from(
(loadingState.value as Success).response);
List<FavDetailItemData> list = (loadingState.value as Success).response;
for (FavDetailItemData element in list) {
if (element.cid == null) {
continue;

View File

@@ -2,6 +2,7 @@ import 'package:PiliPlus/common/widgets/dialog.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/http/loading_state.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/pages/fav_search/view.dart' show SearchType;
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(
children: [
Positioned.fill(
child: FavVideoCardH(
videoItem: element,
callFn: () => _favDetailController.onCancelFav(
element.id,
element.type,
element.id!,
element.type!,
),
onViewFav: () {
Utils.toViewPage(

View File

@@ -1,12 +1,12 @@
import 'package:PiliPlus/common/widgets/icon_button.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/utils/extension.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:flutter/material.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/video.dart';
import 'package:PiliPlus/utils/id_utils.dart';
@@ -16,7 +16,7 @@ import '../../../common/widgets/badge.dart';
// 收藏视频卡片 - 水平布局
class FavVideoCardH extends StatelessWidget {
final dynamic videoItem;
final FavDetailItemData videoItem;
final Function? callFn;
final int? searchType;
final GestureTapCallback? onTap;
@@ -37,7 +37,7 @@ class FavVideoCardH extends StatelessWidget {
@override
Widget build(BuildContext context) {
int id = videoItem.id;
int id = videoItem.id!;
String bvid = videoItem.bvid ?? IdUtils.av2bv(id);
return InkWell(
onTap: () async {
@@ -48,11 +48,11 @@ class FavVideoCardH extends StatelessWidget {
String? epId;
if (videoItem.type == 24) {
videoItem.cid = await SearchHttp.ab2c(bvid: bvid);
dynamic seasonId = videoItem.ogv['season_id'];
dynamic seasonId = videoItem.ogv!['season_id'];
epId = videoItem.epId;
Utils.viewBangumi(seasonId: seasonId, epId: epId);
return;
} else if (videoItem.page == 0 || videoItem.page > 1) {
} else if (videoItem.page == 0 || videoItem.page! > 1) {
var result = await VideoHttp.videoIntro(bvid: bvid);
if (result['status']) {
epId = result['data'].epId;
@@ -61,9 +61,8 @@ class FavVideoCardH extends StatelessWidget {
}
}
if (videoItem is FavDetailItemData &&
[0, 16].contains(videoItem.attr).not) {
Get.toNamed('/member?mid=${videoItem.owner?.mid}');
if ([0, 16].contains(videoItem.attr).not) {
Get.toNamed('/member?mid=${videoItem.owner.mid}');
return;
}
onViewFav();
@@ -117,20 +116,19 @@ class FavVideoCardH extends StatelessWidget {
height: maxHeight,
),
PBadge(
text: Utils.timeFormat(videoItem.duration!),
text: Utils.timeFormat(videoItem.duration),
right: 6.0,
bottom: 6.0,
type: 'gray',
),
if (videoItem.ogv != null) ...[
if (videoItem.ogv != null)
PBadge(
text: videoItem.ogv['type_name'],
text: videoItem.ogv!['type_name'],
top: 6.0,
right: 6.0,
bottom: null,
left: null,
),
],
],
);
},
@@ -163,30 +161,28 @@ class FavVideoCardH extends StatelessWidget {
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
if (videoItem.ogv != null) ...[
if (videoItem.ogv != null)
Text(
videoItem.intro,
videoItem.desc!,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
color: Theme.of(context).colorScheme.outline,
),
),
],
const Spacer(),
Text(
Utils.dateFormat(videoItem.favTime),
style: TextStyle(
fontSize: 11, color: Theme.of(context).colorScheme.outline),
),
if (videoItem.owner.name != '') ...[
if (!videoItem.owner.name.isNullOrEmpty)
Text(
videoItem.owner.name,
videoItem.owner.name!,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
color: Theme.of(context).colorScheme.outline,
),
),
],
Padding(
padding: const EdgeInsets.only(top: 2),
child: Row(
@@ -194,13 +190,13 @@ class FavVideoCardH extends StatelessWidget {
StatView(
context: context,
theme: 'gray',
value: videoItem.cntInfo['play'],
value: videoItem.stat.viewStr,
),
const SizedBox(width: 8),
StatDanMu(
context: context,
theme: 'gray',
value: videoItem.cntInfo['danmaku'],
value: videoItem.stat.danmuStr,
),
const Spacer(),
],

View File

@@ -49,17 +49,11 @@ class FavSearchController extends CommonController {
late List currentList = loadingState.value is Success
? (loadingState.value as Success).response
: [];
List? dataList = searchType == SearchType.fav
? (currentPage == 1
? response.response.medias
: response.response.medias != null
? currentList + response.response.medias
: currentList)
: (currentPage == 1
? response.response.list
: response.response.list != null
? currentList + response.response.list
: currentList);
List? dataList = currentPage == 1
? response.response.list
: response.response.list != null
? currentList + response.response.list
: currentList;
isEnd = searchType == SearchType.fav
? response.response.hasMore == false
: response.response.list == null || response.response.list.isEmpty;

View File

@@ -65,8 +65,8 @@ class _FavSearchPageState extends State<FavSearchPage> {
return switch (loadingState) {
Loading() => errorWidget(),
Success() => (loadingState.response as List?)?.isNotEmpty == true
? _favSearchCtr.searchType == SearchType.fav
? CustomScrollView(
? switch (_favSearchCtr.searchType) {
SearchType.fav => CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
controller: _favSearchCtr.scrollController,
slivers: [
@@ -120,54 +120,54 @@ class _FavSearchPageState extends State<FavSearchPage> {
),
),
],
)
: _favSearchCtr.searchType == SearchType.follow
? ListView.builder(
),
SearchType.follow => ListView.builder(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom + 80,
),
controller: _favSearchCtr.scrollController,
itemCount: loadingState.response.length,
itemBuilder: ((context, index) {
if (index == loadingState.response.length - 1) {
_favSearchCtr.onLoadMore();
}
return FollowItem(
item: loadingState.response[index],
);
}),
),
SearchType.history => CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
controller: _favSearchCtr.scrollController,
slivers: [
SliverPadding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom + 80,
),
controller: _favSearchCtr.scrollController,
itemCount: loadingState.response.length,
itemBuilder: ((context, index) {
if (index == loadingState.response.length - 1) {
_favSearchCtr.onLoadMore();
}
return FollowItem(
item: loadingState.response[index],
);
}),
)
: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
controller: _favSearchCtr.scrollController,
slivers: [
SliverPadding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).padding.bottom + 80,
),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: 2,
maxCrossAxisExtent: Grid.mediumCardWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.2,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == loadingState.response.length - 1) {
_favSearchCtr.onLoadMore();
}
return HistoryItem(
videoItem: loadingState.response[index],
ctr: _favSearchCtr,
onChoose: null,
);
},
childCount: loadingState.response.length,
),
),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithExtentAndRatio(
mainAxisSpacing: 2,
maxCrossAxisExtent: Grid.mediumCardWidth * 2,
childAspectRatio: StyleString.aspectRatio * 2.2,
),
],
)
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == loadingState.response.length - 1) {
_favSearchCtr.onLoadMore();
}
return HistoryItem(
videoItem: loadingState.response[index],
ctr: _favSearchCtr,
onChoose: null,
);
},
childCount: loadingState.response.length,
),
),
),
],
),
}
: errorWidget(
callback: _favSearchCtr.onReload,
),

View File

@@ -67,7 +67,7 @@ class HistoryController extends MultiSelectController
bool customHandleResponse(Success response) {
HistoryData data = response.response;
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;
if (currentPage == 1) {
if (type == null && tabs.isEmpty && data.tab?.isNotEmpty == true) {

View File

@@ -4,6 +4,7 @@ import 'package:PiliPlus/models/user/history.dart';
import 'package:PiliPlus/pages/common/multi_select_controller.dart';
import 'package:PiliPlus/pages/fav_search/controller.dart';
import 'package:PiliPlus/pages/history/base_controller.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.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';
class HistoryItem extends StatelessWidget {
final dynamic videoItem;
final HisListItem videoItem;
final dynamic ctr;
final Function? onChoose;
final Function? onDelete;
@@ -35,7 +36,7 @@ class HistoryItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
int aid = videoItem.history.oid;
int aid = videoItem.history.oid!;
String bvid = videoItem.history.bvid ?? IdUtils.av2bv(aid);
return InkWell(
onTap: () async {
@@ -45,7 +46,7 @@ class HistoryItem extends StatelessWidget {
onChoose?.call();
return;
}
if (videoItem.history.business.contains('article')) {
if (videoItem.history.business?.contains('article') == true) {
// int cid = videoItem.history.cid ??
// // videoItem.history.oid ??
// await SearchHttp.ab2c(aid: aid, bvid: bvid);
@@ -80,8 +81,8 @@ class HistoryItem extends StatelessWidget {
} else {
SmartDialog.showToast('直播未开播');
}
} else if (videoItem.history?.business == 'pgc' ||
videoItem.tagName.contains('动画')) {
} else if (videoItem.history.business == 'pgc' ||
videoItem.tagName?.contains('动画') == true) {
/// hack
var bvid = videoItem.history.bvid;
if (bvid != null && bvid != '') {
@@ -106,7 +107,7 @@ class HistoryItem extends StatelessWidget {
SmartDialog.showToast(result['msg']);
}
} else {
if (videoItem.history.epid != '') {
if (videoItem.history.epid != null && videoItem.history.epid != 0) {
Utils.viewBangumi(epId: videoItem.history.epid);
}
}
@@ -164,9 +165,9 @@ class HistoryItem extends StatelessWidget {
return Stack(
children: [
NetworkImgLayer(
src: (videoItem.cover != ''
? videoItem.cover
: videoItem.covers.first),
src: (videoItem.cover.isNullOrEmpty
? videoItem.covers?.first ?? ''
: videoItem.cover),
width: maxWidth,
height: maxHeight,
),
@@ -176,7 +177,7 @@ class HistoryItem extends StatelessWidget {
PBadge(
text: videoItem.progress == -1
? '已看完'
: '${Utils.timeFormat(videoItem.progress!)}/${Utils.timeFormat(videoItem.duration!)}',
: '${Utils.timeFormat(videoItem.progress)}/${Utils.timeFormat(videoItem.duration!)}',
right: 6.0,
bottom: 8.0,
type: 'gray',
@@ -254,7 +255,7 @@ class HistoryItem extends StatelessWidget {
child: videoProgressIndicator(
videoItem.progress == -1
? 1
: videoItem.progress / videoItem.duration,
: videoItem.progress / videoItem.duration!,
),
),
],
@@ -281,7 +282,7 @@ class HistoryItem extends StatelessWidget {
style: const TextStyle(
letterSpacing: 0.3,
),
maxLines: videoItem.videos > 1 ? 1 : 2,
maxLines: videoItem.videos! > 1 ? 1 : 2,
overflow: TextOverflow.ellipsis,
),
if (videoItem.isFullScreen != null) ...[
@@ -301,7 +302,7 @@ class HistoryItem extends StatelessWidget {
Row(
children: [
Text(
videoItem.authorName,
videoItem.authorName!,
style: TextStyle(
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
color: Theme.of(context).colorScheme.outline,
@@ -318,82 +319,79 @@ class HistoryItem extends StatelessWidget {
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
color: Theme.of(context).colorScheme.outline),
),
if (videoItem is HisListItem)
SizedBox(
width: 29,
height: 29,
child: PopupMenuButton<String>(
padding: EdgeInsets.zero,
tooltip: '功能菜单',
icon: Icon(
Icons.more_vert_outlined,
color: Theme.of(context).colorScheme.outline,
size: 18,
),
position: PopupMenuPosition.under,
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<String>>[
if (videoItem.authorMid != null &&
videoItem.authorName?.isNotEmpty == true)
PopupMenuItem<String>(
onTap: () {
Get.toNamed(
'/member?mid=${videoItem.authorMid}',
arguments: {
'heroTag': '${videoItem.authorMid}',
},
);
},
height: 35,
child: Row(
children: [
Icon(MdiIcons.accountCircleOutline, size: 16),
SizedBox(width: 6),
Text(
'访问:${videoItem.authorName}',
style: TextStyle(fontSize: 13),
)
],
),
),
if (videoItem.history?.business != 'pgc' &&
videoItem.badge != '番剧' &&
!videoItem.tagName.contains('动画') &&
videoItem.history.business != 'live' &&
!videoItem.history.business.contains('article'))
PopupMenuItem<String>(
onTap: () async {
var res = await UserHttp.toViewLater(
bvid: videoItem.history.bvid);
SmartDialog.showToast(res['msg']);
},
height: 35,
child: const Row(
children: [
Icon(Icons.watch_later_outlined, size: 16),
SizedBox(width: 6),
Text('稍后再看', style: TextStyle(fontSize: 13))
],
),
),
// if (videoItem is HisListItem)
SizedBox(
width: 29,
height: 29,
child: PopupMenuButton<String>(
padding: EdgeInsets.zero,
tooltip: '功能菜单',
icon: Icon(
Icons.more_vert_outlined,
color: Theme.of(context).colorScheme.outline,
size: 18,
),
position: PopupMenuPosition.under,
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<String>>[
if (videoItem.authorMid != null &&
videoItem.authorName?.isNotEmpty == true)
PopupMenuItem<String>(
onTap: () => ctr is HistoryBaseController
? onDelete?.call(
videoItem.kid, videoItem.history.business)
: ctr!.delHistory(
videoItem.kid, videoItem.history.business),
onTap: () {
Get.toNamed(
'/member?mid=${videoItem.authorMid}',
arguments: {
'heroTag': '${videoItem.authorMid}',
},
);
},
height: 35,
child: const Row(
child: Row(
children: [
Icon(Icons.close_outlined, size: 16),
Icon(MdiIcons.accountCircleOutline, size: 16),
SizedBox(width: 6),
Text('删除记录', style: TextStyle(fontSize: 13))
Text(
'访问:${videoItem.authorName}',
style: TextStyle(fontSize: 13),
)
],
),
),
],
),
if (videoItem.history.business != 'pgc' &&
videoItem.badge != '番剧' &&
videoItem.tagName?.contains('动画') != true &&
videoItem.history.business != 'live' &&
videoItem.history.business?.contains('article') != true)
PopupMenuItem<String>(
onTap: () async {
var res = await UserHttp.toViewLater(
bvid: videoItem.history.bvid);
SmartDialog.showToast(res['msg']);
},
height: 35,
child: const Row(
children: [
Icon(Icons.watch_later_outlined, size: 16),
SizedBox(width: 6),
Text('稍后再看', style: TextStyle(fontSize: 13))
],
),
),
PopupMenuItem<String>(
onTap: () => ctr!.delHistory(
videoItem.kid, videoItem.history.business),
height: 35,
child: const Row(
children: [
Icon(Icons.close_outlined, size: 16),
SizedBox(width: 6),
Text('删除记录', style: TextStyle(fontSize: 13))
],
),
),
],
),
),
],
),
],

View File

@@ -5,7 +5,6 @@ import 'package:get/get.dart';
import 'package:PiliPlus/http/member.dart';
import 'package:PiliPlus/http/user.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/info.dart';
import 'package:PiliPlus/utils/storage.dart';
@@ -22,7 +21,6 @@ class MemberController extends GetxController {
late int ownerMid;
bool specialFollowed = false;
// 投稿列表
RxList<VListItemModel>? archiveList = <VListItemModel>[].obs;
dynamic userInfo;
RxInt attribute = (-1).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);
await getMemberStat();
await getMemberView();

View File

@@ -136,7 +136,7 @@ class MemberVideoCtr extends CommonController {
}
for (Item element in list) {
if (element.firstCid == null) {
if (element.cid == null) {
continue;
} else {
if (element.bvid != list.first.bvid) {
@@ -150,7 +150,7 @@ class MemberVideoCtr extends CommonController {
? desc.not
: desc;
Utils.toViewPage(
'bvid=${element.bvid}&cid=${element.firstCid}',
'bvid=${element.bvid}&cid=${element.cid}',
arguments: {
'videoItem': element,
'heroTag': Utils.makeHeroTag(element.bvid),

View File

@@ -10,7 +10,7 @@ class MemberArchiveController extends GetxController {
int pn = 1;
int count = 0;
RxMap<String, String> currentOrder = <String, String>{}.obs;
List<Map<String, String>> orderList = [
static const List<Map<String, String>> orderList = [
{'type': 'pubdate', 'label': '最新发布'},
{'type': 'click', 'label': '最多播放'},
{'type': 'stow', 'label': '最多收藏'},
@@ -37,8 +37,7 @@ class MemberArchiveController extends GetxController {
if (res['status']) {
if (type == 'init') {
archivesList.value = res['data'].list.vlist;
}
if (type == 'onLoad') {
} else if (type == 'onLoad') {
archivesList.addAll(res['data'].list.vlist);
}
count = res['data'].page['count'];
@@ -49,7 +48,7 @@ class MemberArchiveController extends GetxController {
return res;
}
toggleSort() async {
toggleSort() {
List<String> typeList = orderList.map((e) => e['type']!).toList();
int index = typeList.indexOf(currentOrder['type']!);
if (index == orderList.length - 1) {
@@ -61,9 +60,7 @@ class MemberArchiveController extends GetxController {
}
// 上拉加载
Future onLoad() async {
getMemberArchive('onLoad');
}
Future onLoad() => getMemberArchive('onLoad');
@override
void onClose() {

View File

@@ -86,7 +86,7 @@ class _MemberArchivePageState extends State<MemberArchivePage> {
);
}
Map data = snapshot.data as Map;
List list = _memberArchivesController.archivesList;
final list = _memberArchivesController.archivesList;
if (data['status']) {
return Obx(
() => list.isNotEmpty

View File

@@ -1,9 +1,9 @@
import 'package:PiliPlus/common/widgets/image_save.dart';
import 'package:PiliPlus/common/widgets/stat/stat.dart';
import 'package:flutter/material.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.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/models/member/coin.dart';
import 'package:PiliPlus/utils/utils.dart';
@@ -53,7 +53,7 @@ class MemberCoinsItem extends StatelessWidget {
width: maxWidth,
height: maxHeight,
),
if (coinItem.duration != null)
if (coinItem.duration > 0)
PBadge(
bottom: 6,
right: 6,
@@ -80,9 +80,15 @@ class MemberCoinsItem extends StatelessWidget {
children: [
StatView(
context: context,
value: coinItem.view!,
value: coinItem.stat.viewStr,
theme: 'gray',
),
const SizedBox(width: 8),
StatDanMu(
context: context,
theme: 'gray',
value: coinItem.stat.danmuStr,
),
const Spacer(),
Text(
Utils.customStampStr(

View File

@@ -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:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.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/utils/utils.dart';
class MemberSeasonsItem extends StatelessWidget {
final dynamic seasonItem;
final MemberArchiveItem seasonItem;
const MemberSeasonsItem({
super.key,
@@ -65,7 +66,7 @@ class MemberSeasonsItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
seasonItem.title,
seasonItem.title!,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
@@ -74,7 +75,7 @@ class MemberSeasonsItem extends StatelessWidget {
children: [
StatView(
context: context,
value: seasonItem.view,
value: Utils.numFormat(seasonItem.view!),
theme: 'gray',
),
const Spacer(),

View File

@@ -132,8 +132,6 @@ class _SearchPanelState extends State<SearchPanel>
_searchPanelController,
loadingState,
);
default:
return const SizedBox.shrink();
}
}
}

View File

@@ -50,15 +50,16 @@ class SubDetailController extends GetxController {
);
}
if (res['status']) {
subInfo.value = res['data'].info;
SubDetailModelData data = res['data'];
subInfo.value = data.info!;
if (currentPage == 1 && type == 'init') {
subList.value = res['data'].medias;
mediaCount = res['data'].info.mediaCount;
subList.value = data.list!;
mediaCount = data.info!.mediaCount!;
if (item.type == 11) {
playCount.value = res['data'].info.cntInfo!['play'];
playCount.value = data.info!.cntInfo!['play'];
}
} else if (type == 'onLoad') {
subList.addAll(res['data'].medias);
subList.addAll(data.list!);
}
if (subList.length >= mediaCount) {
loadingText.value = '没有更多了';

View File

@@ -129,13 +129,13 @@ class SubVideoCardH extends StatelessWidget {
StatView(
context: context,
theme: 'gray',
value: videoItem.cntInfo?['play'],
value: Utils.numFormat(videoItem.cntInfo?['play']),
),
const SizedBox(width: 8),
StatDanMu(
context: context,
theme: 'gray',
value: videoItem.cntInfo?['danmaku'],
value: Utils.numFormat(videoItem.cntInfo?['danmaku']),
),
const Spacer(),
],

View File

@@ -616,9 +616,9 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
StatView(
context: context,
theme: 'gray',
value: !widget.loadingStatus
value: Utils.numFormat(!widget.loadingStatus
? videoDetail.stat?.view ?? '-'
: videoItem['stat']?.view ?? '-',
: videoItem['stat']?.view ?? '-'),
size: 'medium',
textColor: t.colorScheme.outline,
),
@@ -626,9 +626,9 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
StatDanMu(
context: context,
theme: 'gray',
value: !widget.loadingStatus
value: Utils.numFormat(!widget.loadingStatus
? videoDetail.stat?.danmu ?? '-'
: videoItem['stat']?.danmu ?? '-',
: videoItem['stat']?.danmu ?? '-'),
size: 'medium',
textColor: t.colorScheme.outline,
),

View File

@@ -57,14 +57,14 @@ class IntroDetail extends StatelessWidget {
StatView(
context: context,
theme: 'gray',
value: videoDetail!.stat!.view,
value: Utils.numFormat(videoDetail!.stat!.view),
size: 'medium',
),
const SizedBox(width: 10),
StatDanMu(
context: context,
theme: 'gray',
value: videoDetail!.stat!.danmu,
value: Utils.numFormat(videoDetail!.stat!.danmu),
size: 'medium',
),
const SizedBox(width: 10),

View File

@@ -187,7 +187,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
widget.videoIntroController.changeSeasonOrbangu(
null,
videoItem.bvid,
videoItem.firstCid,
videoItem.cid,
IdUtils.bv2av(videoItem.bvid!),
videoItem.cover,
);

View File

@@ -184,7 +184,7 @@ class _AiDetailState extends CommonCollapseSlidePageState<AiDetail> {
children: [
TextSpan(
text:
Utils.tampToSeektime(item.timestamp!),
Utils.formatDuration(item.timestamp!),
style: TextStyle(
color: Theme.of(context)
.colorScheme
@@ -198,15 +198,8 @@ class _AiDetailState extends CommonCollapseSlidePageState<AiDetail> {
tag: Get
.arguments['heroTag'])
.plPlayerController
.seekTo(
Duration(
seconds: Utils.duration(
Utils.tampToSeektime(
item.timestamp!)
.toString(),
),
),
);
.seekTo(Duration(
seconds: item.timestamp!));
} catch (_) {}
},
),

View File

@@ -234,14 +234,15 @@ class _MediaListPanelState extends CommonSlidePageState<MediaListPanel> {
StatView(
context: context,
theme: 'gray',
value: item.cntInfo!['play'] as int,
value: Utils.numFormat(
item.cntInfo!['play']!),
),
const SizedBox(width: 8),
StatDanMu(
context: context,
theme: 'gray',
value:
item.cntInfo!['danmaku'] as int,
value: Utils.numFormat(
item.cntInfo!['danmaku']!),
),
],
),