diff --git a/lib/pages/video/detail/member/controller.dart b/lib/pages/video/detail/member/controller.dart index 6c4d528c..13ddfa09 100644 --- a/lib/pages/video/detail/member/controller.dart +++ b/lib/pages/video/detail/member/controller.dart @@ -1,12 +1,15 @@ -import 'package:PiliPlus/common/widgets/pair.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/member.dart'; +import 'package:PiliPlus/models/space_archive/data.dart'; +import 'package:PiliPlus/models/space_archive/item.dart'; import 'package:PiliPlus/pages/common/common_controller.dart'; +import 'package:PiliPlus/pages/member/new/content/member_contribute/member_contribute.dart' + show ContributeType; import 'package:PiliPlus/utils/utils.dart'; import 'package:get/get.dart'; class HorizontalMemberPageController extends CommonController { - HorizontalMemberPageController({this.mid, required this.firstParam}); + HorizontalMemberPageController({this.mid, required this.lastAid}); dynamic mid; dynamic wwebid; @@ -17,6 +20,7 @@ class HorizontalMemberPageController extends CommonController { @override void onInit() { super.onInit(); + currentPage = 0; getUserInfo(); queryData(); } @@ -49,72 +53,61 @@ class HorizontalMemberPageController extends CommonController { @override bool customHandleResponse(Success response) { - final data = response.response; - if (currentPage == 0 || isLoadPrevious == true) { - hasPrev = data['page']['has_prev']; + Data data = response.response; + count.value = data.count ?? -1; + if (currentPage == 0 || isLoadPrevious) { + hasPrev = data.hasPrev ?? false; } - if (currentPage == 0 || isLoadPrevious != true) { - hasNext = data['page']['has_next']; + if (currentPage == 0 || !isLoadPrevious) { + hasNext = data.hasNext ?? false; } - if (currentPage != 0 && loadingState.value is Success) { - data['items'] ??= []; + data.item ??= []; if (isLoadPrevious) { - data['items'].addAll((loadingState.value as Success).response); + data.item!.addAll((loadingState.value as Success).response); } else { - data['items'].insertAll(0, (loadingState.value as Success).response); + data.item!.insertAll(0, (loadingState.value as Success).response); } } - - if ((data['items'] as List?)?.isNotEmpty == true) { - final first = data['items'].first; - final last = data['items'].last; - - firstParam = Triple( - first: first['param'], - second: first['player_args']?['cid'], - third: first['index'], - ); - lastParam = Triple( - first: last['param'], - second: last['player_args']?['cid'], - third: last['index'], - ); - } - - loadingState.value = LoadingState.success(data['items']); + firstAid = data.item?.firstOrNull?.param; + lastAid = data.item?.lastOrNull?.param; + loadingState.value = LoadingState.success(data.item); isLoadPrevious = false; return true; } + String? firstAid; + String? lastAid; + RxString order = 'pubdate'.obs; + RxInt count = (-1).obs; bool isLoadPrevious = false; - Triple firstParam; - Triple? lastParam; bool hasPrev = true; bool hasNext = true; @override - Future customGetData() => MemberHttp.spaceStory( + Future customGetData() => MemberHttp.spaceArchive( + type: ContributeType.video, mid: mid, - aid: lastParam == null || isLoadPrevious - ? firstParam.first - : lastParam?.first, - cid: lastParam == null || isLoadPrevious - ? firstParam.second - : lastParam?.second, - index: lastParam == null || isLoadPrevious - ? firstParam.third - : lastParam?.third, - beforeSize: lastParam == null - ? 0 - : isLoadPrevious - ? 20 - : 0, - afterSize: lastParam == null - ? 10 - : isLoadPrevious - ? 0 - : 20, - contain: lastParam == null ? 1 : 0, + aid: isLoadPrevious ? firstAid : lastAid, + order: order.value, + sort: isLoadPrevious ? 'asc' : null, + pn: null, + next: null, + seasonId: null, + seriesId: null, + includeCursor: currentPage == 0 ? true : null, ); + + @override + Future onRefresh() async { + currentPage = 0; + hasPrev = true; + hasNext = true; + await queryData(); + } + + queryBySort() { + order.value = order.value == 'pubdate' ? 'click' : 'pubdate'; + onReload(); + } } diff --git a/lib/pages/video/detail/member/horizontal_member_page.dart b/lib/pages/video/detail/member/horizontal_member_page.dart index 27dd47fa..3c36a834 100644 --- a/lib/pages/video/detail/member/horizontal_member_page.dart +++ b/lib/pages/video/detail/member/horizontal_member_page.dart @@ -1,24 +1,27 @@ import 'package:PiliPlus/common/constants.dart'; +import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart'; import 'package:PiliPlus/common/widgets/icon_button.dart'; import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart' show SourceModel; import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/network_img_layer.dart'; -import 'package:PiliPlus/common/widgets/pair.dart'; +import 'package:PiliPlus/common/widgets/video_card_h_member_video.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/member/info.dart'; import 'package:PiliPlus/pages/video/detail/controller.dart'; import 'package:PiliPlus/pages/video/detail/introduction/controller.dart'; import 'package:PiliPlus/pages/video/detail/member/controller.dart'; -import 'package:PiliPlus/pages/video/detail/member/widget/video_card_h_member_video.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/grid.dart'; +import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import '../../../../models/space_archive/item.dart'; + class HorizontalMemberPage extends StatefulWidget { const HorizontalMemberPage({ super.key, @@ -46,11 +49,7 @@ class _HorizontalMemberPageState extends State { _controller = Get.put( HorizontalMemberPageController( mid: widget.mid, - firstParam: Triple( - first: widget.videoDetailController.oid.value, - second: widget.videoDetailController.cid.value, - third: 0, - ), + lastAid: widget.videoDetailController.oid.value.toString(), ), tag: widget.videoDetailController.heroTag, ); @@ -120,6 +119,59 @@ class _HorizontalMemberPageState extends State { }; } + Widget get _buildSliverHeader { + return SliverPersistentHeader( + pinned: false, + floating: true, + delegate: CustomSliverPersistentHeaderDelegate( + extent: 40, + bgColor: Theme.of(context).colorScheme.surface, + child: Container( + height: 40, + padding: const EdgeInsets.fromLTRB(12, 0, 6, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Obx( + () => Text( + _controller.count.value != -1 + ? '共${_controller.count.value}视频' + : '', + style: const TextStyle(fontSize: 13), + ), + ), + SizedBox( + height: 35, + child: TextButton.icon( + onPressed: () { + _controller + ..lastAid = + widget.videoDetailController.oid.value.toString() + ..queryBySort(); + }, + icon: Icon( + Icons.sort, + size: 16, + color: Theme.of(context).colorScheme.secondary, + ), + label: Obx( + () => Text( + _controller.order.value == 'pubdate' ? '最新发布' : '最多播放', + style: TextStyle( + fontSize: 13, + color: Theme.of(context).colorScheme.secondary, + ), + ), + ), + ), + ) + ], + ), + ), + ), + ); + } + Widget _buildVideoList(LoadingState loadingState) { return switch (loadingState) { Loading() => loadingWidget, @@ -129,6 +181,7 @@ class _HorizontalMemberPageState extends State { controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ + _buildSliverHeader, SliverPadding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).padding.bottom + 80, @@ -149,17 +202,17 @@ class _HorizontalMemberPageState extends State { videoItem: loadingState.response[index], bvid: _bvid, onTap: () { - final videoItem = loadingState.response[index]; + final Item videoItem = loadingState.response[index]; final status = widget.videoIntroController.changeSeasonOrbangu( null, - videoItem['bvid'], - videoItem['player_args']?['cid'], - int.parse(videoItem['param']), - videoItem['cover'], + videoItem.bvid, + videoItem.cid, + IdUtils.bv2av(videoItem.bvid!), + videoItem.cover, ); if (status) { - _bvid = videoItem['bvid']; + _bvid = videoItem.bvid; setState(() {}); } }, diff --git a/lib/pages/video/detail/member/widget/video_card_h_member_video.dart b/lib/pages/video/detail/member/widget/video_card_h_member_video.dart deleted file mode 100644 index a0916ac3..00000000 --- a/lib/pages/video/detail/member/widget/video_card_h_member_video.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/common/widgets/badge.dart'; -import 'package:PiliPlus/common/widgets/image_save.dart'; -import 'package:PiliPlus/common/widgets/network_img_layer.dart'; -import 'package:PiliPlus/common/widgets/stat/stat.dart'; -import 'package:PiliPlus/utils/utils.dart'; -import 'package:flutter/material.dart'; - -// 视频卡片 - 水平布局 -class VideoCardHMemberVideo extends StatelessWidget { - const VideoCardHMemberVideo({ - super.key, - required this.videoItem, - this.onTap, - this.bvid, - }); - final dynamic videoItem; - final VoidCallback? onTap; - final dynamic bvid; - - @override - Widget build(BuildContext context) { - return Stack( - children: [ - InkWell( - onLongPress: () => imageSaveDialog( - context: context, - title: videoItem['title'], - cover: videoItem['cover'], - ), - onTap: onTap, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: StyleString.safeSpace, - vertical: 5, - ), - child: LayoutBuilder( - builder: (BuildContext context, BoxConstraints boxConstraints) { - return Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - AspectRatio( - aspectRatio: StyleString.aspectRatio, - child: LayoutBuilder( - builder: (BuildContext context, - BoxConstraints boxConstraints) { - final double maxWidth = boxConstraints.maxWidth; - final double maxHeight = boxConstraints.maxHeight; - return Stack( - children: [ - NetworkImgLayer( - src: videoItem['cover'], - width: maxWidth, - height: maxHeight, - ), - if (videoItem['duration'] > 0) - PBadge( - text: Utils.timeFormat(videoItem['duration']), - right: 6.0, - bottom: 6.0, - type: 'gray', - ), - ], - ); - }, - ), - ), - const SizedBox(width: 10), - videoContent(context), - ], - ); - }, - ), - ), - ), - // Positioned( - // bottom: 0, - // right: 12, - // child: VideoPopupMenu( - // size: 29, - // iconSize: 17, - // videoItem: videoItem, - // ), - // ), - ], - ); - } - - Widget videoContent(context) { - return Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Text( - videoItem['title'], - textAlign: TextAlign.start, - style: TextStyle( - fontWeight: - videoItem['bvid'] != null && videoItem['bvid'] == bvid - ? FontWeight.bold - : null, - fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize, - height: 1.42, - letterSpacing: 0.3, - color: videoItem['bvid'] != null && videoItem['bvid'] == bvid - ? Theme.of(context).colorScheme.primary - : null, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - Text( - Utils.dateFormat(videoItem['pubdate']), - maxLines: 1, - style: TextStyle( - fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, - height: 1, - color: Theme.of(context).colorScheme.outline, - overflow: TextOverflow.clip, - ), - ), - const SizedBox(height: 3), - Row( - children: [ - StatView( - context: context, - theme: 'gray', - value: videoItem['stat']['view'], - ), - const SizedBox(width: 8), - StatDanMu( - context: context, - theme: 'gray', - value: videoItem['stat']['danmaku'], - ), - ], - ), - ], - ), - ); - } -}