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
@@ -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) ...[
|
||||
|
||||
@@ -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) ...[
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(),
|
||||
],
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -132,8 +132,6 @@ class _SearchPanelState extends State<SearchPanel>
|
||||
_searchPanelController,
|
||||
loadingState,
|
||||
);
|
||||
default:
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = '没有更多了';
|
||||
|
||||
@@ -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(),
|
||||
],
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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 (_) {}
|
||||
},
|
||||
),
|
||||
|
||||
@@ -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']!),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user