diff --git a/lib/models_new/space/space_fav/list.dart b/lib/models_new/space/space_fav/list.dart index 631bd033..df53dfba 100644 --- a/lib/models_new/space/space_fav/list.dart +++ b/lib/models_new/space/space_fav/list.dart @@ -1,60 +1,38 @@ import 'package:PiliPlus/models/model_owner.dart'; +import 'package:PiliPlus/models_new/sub/sub/list.dart'; -class SpaceFavItemModel { - int? id; +class SpaceFavItemModel extends SubItemModel { int? mediaId; int? count; int? isPublic; - int? fid; - int? mid; - int? attr; - String? attrDesc; - String? title; - String? cover; - Owner? upper; - int? coverType; - String? intro; - int? ctime; - int? mtime; - int? state; - int? favState; - int? mediaCount; - int? viewCount; - int? vt; - bool? isTop; - dynamic recentFav; - int? playSwitch; - int? type; - String? link; - String? bvid; SpaceFavItemModel({ - this.id, + super.id, this.mediaId, this.count, this.isPublic, - this.fid, - this.mid, - this.attr, - this.attrDesc, - this.title, - this.cover, - this.upper, - this.coverType, - this.intro, - this.ctime, - this.mtime, - this.state, - this.favState, - this.mediaCount, - this.viewCount, - this.vt, - this.isTop, - this.recentFav, - this.playSwitch, - this.type, - this.link, - this.bvid, + super.fid, + super.mid, + super.attr, + super.attrDesc, + super.title, + super.cover, + super.upper, + super.coverType, + super.intro, + super.ctime, + super.mtime, + super.state, + super.favState, + super.mediaCount, + super.viewCount, + super.vt, + super.isTop, + super.recentFav, + super.playSwitch, + super.type, + super.link, + super.bvid, }); factory SpaceFavItemModel.fromJson(Map json) => diff --git a/lib/models_new/sub/sub/list.dart b/lib/models_new/sub/sub/list.dart index 8cb56b23..4d3a5860 100644 --- a/lib/models_new/sub/sub/list.dart +++ b/lib/models_new/sub/sub/list.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/models/model_owner.dart'; +import 'package:PiliPlus/models_new/fav/fav_detail/cnt_info.dart'; class SubItemModel { int? id; @@ -24,6 +25,7 @@ class SubItemModel { int? type; String? link; String? bvid; + CntInfo? cntInfo; SubItemModel({ this.id, @@ -49,6 +51,7 @@ class SubItemModel { this.type, this.link, this.bvid, + this.cntInfo, }); factory SubItemModel.fromJson(Map json) => SubItemModel( @@ -77,5 +80,8 @@ class SubItemModel { type: json['type'] as int?, link: json['link'] as String?, bvid: json['bvid'] as String?, + cntInfo: json['cnt_info'] == null + ? null + : CntInfo.fromJson(json['cnt_info']), ); } diff --git a/lib/models_new/sub/sub_detail/data.dart b/lib/models_new/sub/sub_detail/data.dart index d4d52c3f..63c78dd7 100644 --- a/lib/models_new/sub/sub_detail/data.dart +++ b/lib/models_new/sub/sub_detail/data.dart @@ -1,8 +1,8 @@ -import "package:PiliPlus/models_new/sub/sub_detail/info.dart"; +import 'package:PiliPlus/models_new/sub/sub/list.dart'; import 'package:PiliPlus/models_new/sub/sub_detail/media.dart'; class SubDetailData { - Info? info; + SubItemModel? info; List? medias; SubDetailData({this.info, this.medias}); @@ -10,7 +10,7 @@ class SubDetailData { factory SubDetailData.fromJson(Map json) => SubDetailData( info: json['info'] == null ? null - : Info.fromJson(json['info'] as Map), + : SubItemModel.fromJson(json['info'] as Map), medias: (json['medias'] as List?) ?.map((e) => SubDetailItemModel.fromJson(e as Map)) .toList(), diff --git a/lib/models_new/sub/sub_detail/info.dart b/lib/models_new/sub/sub_detail/info.dart deleted file mode 100644 index c3ce52b4..00000000 --- a/lib/models_new/sub/sub_detail/info.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:PiliPlus/models/model_owner.dart'; -import 'package:PiliPlus/models_new/fav/fav_detail/cnt_info.dart'; - -class Info { - int? id; - int? seasonType; - String? title; - String? cover; - Owner? upper; - CntInfo? cntInfo; - int? mediaCount; - String? intro; - int? enableVt; - - Info({ - this.id, - this.seasonType, - this.title, - this.cover, - this.upper, - this.cntInfo, - this.mediaCount, - this.intro, - this.enableVt, - }); - - factory Info.fromJson(Map json) => Info( - id: json['id'] as int?, - seasonType: json['season_type'] as int?, - title: json['title'] as String?, - cover: json['cover'] as String?, - upper: json['upper'] == null - ? null - : Owner.fromJson(json['upper'] as Map), - cntInfo: json['cnt_info'] == null - ? null - : CntInfo.fromJson(json['cnt_info'] as Map), - mediaCount: json['media_count'] as int?, - intro: json['intro'] as String?, - enableVt: json['enable_vt'] as int?, - ); -} diff --git a/lib/pages/member_favorite/widget/item.dart b/lib/pages/member_favorite/widget/item.dart index 7513d45e..a2ee5f1d 100644 --- a/lib/pages/member_favorite/widget/item.dart +++ b/lib/pages/member_favorite/widget/item.dart @@ -3,7 +3,7 @@ import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models_new/space/space_fav/list.dart'; -import 'package:PiliPlus/models_new/sub/sub/list.dart'; +import 'package:PiliPlus/pages/subscription_detail/view.dart'; import 'package:PiliPlus/utils/fav_util.dart'; import 'package:PiliPlus/utils/num_util.dart'; import 'package:PiliPlus/utils/utils.dart'; @@ -38,20 +38,9 @@ class MemberFavItem extends StatelessWidget { ); callback?.call(res); } else { - Get.toNamed( - '/subDetail', - arguments: SubItemModel( - type: item.type, - title: item.title, - cover: item.cover, - upper: item.upper, - mediaCount: item.mediaCount, - viewCount: item.viewCount, - ), - parameters: { - 'id': item.id.toString(), - 'heroTag': Utils.makeHeroTag(item.id), - }, + SubDetailPage.toSubDetailPage( + item.id!, + subInfo: item, ); } }, diff --git a/lib/pages/subscription/widgets/item.dart b/lib/pages/subscription/widgets/item.dart index 41cbcfeb..58111fa2 100644 --- a/lib/pages/subscription/widgets/item.dart +++ b/lib/pages/subscription/widgets/item.dart @@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models_new/sub/sub/list.dart'; +import 'package:PiliPlus/pages/subscription_detail/view.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -42,13 +43,10 @@ class SubItem extends StatelessWidget { }, ); } else { - Get.toNamed( - '/subDetail', - arguments: item, - parameters: { - 'heroTag': heroTag, - 'id': item.id.toString(), - }, + SubDetailPage.toSubDetailPage( + item.id!, + heroTag: heroTag, + subInfo: item, ); } }, diff --git a/lib/pages/subscription_detail/controller.dart b/lib/pages/subscription_detail/controller.dart index eab7c144..b4c15ed0 100644 --- a/lib/pages/subscription_detail/controller.dart +++ b/lib/pages/subscription_detail/controller.dart @@ -8,55 +8,39 @@ import 'package:get/get.dart'; class SubDetailController extends CommonListController { - late SubItemModel subInfo; - late int id; - late String heroTag; - - late final RxInt mediaCount; - late final RxInt playCount; + String? heroTag; + SubItemModel? subInfo; @override void onInit() { super.onInit(); - subInfo = Get.arguments; - mediaCount = (subInfo.mediaCount ?? 0).obs; - playCount = (subInfo.viewCount ?? 0).obs; - id = int.parse(Get.parameters['id']!); - heroTag = Get.parameters['heroTag']!; + final args = Get.arguments; + id = args['id']; + subInfo = args['subInfo']; + heroTag = args['heroTag']; + queryData(); } @override List? getDataList(SubDetailData response) { - mediaCount.value = response.info!.mediaCount!; - if (subInfo.type == 11) { - playCount.value = response.info!.cntInfo!.play!; - } + subInfo = response.info; return response.medias; } @override void checkIsEnd(int length) { - if (length >= mediaCount.value) { + final count = subInfo?.mediaCount; + if (count != null && length >= count) { isEnd = true; } } @override - Future> customGetData() { - if (subInfo.type == 11) { - return FavHttp.favResourceList( - id: id, - ps: 20, - pn: page, - ); - } else { - return FavHttp.favSeasonList( - id: id, - ps: 20, - pn: page, - ); - } - } + Future> customGetData() => FavHttp.favSeasonList( + id: id, + ps: 20, + pn: page, + ); } diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index 2bb03268..09042de7 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -3,6 +3,7 @@ import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models_new/sub/sub/list.dart'; import 'package:PiliPlus/models_new/sub/sub_detail/media.dart'; import 'package:PiliPlus/pages/subscription_detail/controller.dart'; import 'package:PiliPlus/pages/subscription_detail/widget/sub_video_card.dart'; @@ -17,6 +18,21 @@ class SubDetailPage extends StatefulWidget { @override State createState() => _SubDetailPageState(); + + static void toSubDetailPage( + int id, { + String? heroTag, + SubItemModel? subInfo, + }) { + Get.toNamed( + '/subDetail', + arguments: { + 'id': id, + 'subInfo': subInfo, + 'heroTag': heroTag, + }, + ); + } } class _SubDetailPageState extends State { @@ -39,7 +55,7 @@ class _SubDetailPageState extends State { controller: _subDetailController.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ - _buildAppBar(theme, padding), + _appBar(theme, padding), SliverPadding( padding: EdgeInsets.only( top: 7, @@ -91,11 +107,37 @@ class _SubDetailPageState extends State { }; } - Widget _buildAppBar(ThemeData theme, EdgeInsets padding) { + Widget _appBar(ThemeData theme, EdgeInsets padding) { + final info = _subDetailController.subInfo; + if (info != null) return _buildAppBar(theme, padding, info); + return Obx(() { + return switch (_subDetailController.loadingState.value) { + Loading() || Error() => const SliverAppBar(), + Success() => _buildAppBar( + theme, + padding, + _subDetailController.subInfo!, + ), + }; + }); + } + + Widget _buildAppBar(ThemeData theme, EdgeInsets padding, SubItemModel info) { final style = TextStyle( fontSize: 12.5, color: theme.colorScheme.outline, ); + Widget cover = NetworkImgLayer( + width: 176, + height: 110, + src: info.cover, + ); + if (_subDetailController.heroTag != null) { + cover = Hero( + tag: _subDetailController.heroTag!, + child: cover, + ); + } return SliverAppBar.medium( expandedHeight: kToolbarHeight + 132, pinned: true, @@ -103,16 +145,14 @@ class _SubDetailPageState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - _subDetailController.subInfo.title!, + info.title!, maxLines: 1, overflow: TextOverflow.ellipsis, style: theme.textTheme.titleMedium, ), - Obx( - () => Text( - '共${_subDetailController.mediaCount.value}条视频', - style: theme.textTheme.labelMedium, - ), + Text( + '共${info.mediaCount}条视频', + style: theme.textTheme.labelMedium, ), ], ), @@ -135,21 +175,14 @@ class _SubDetailPageState extends State { spacing: 12, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Hero( - tag: _subDetailController.heroTag, - child: NetworkImgLayer( - width: 176, - height: 110, - src: _subDetailController.subInfo.cover, - ), - ), + cover, Expanded( child: Column( spacing: 4, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - _subDetailController.subInfo.title!, + info.title!, style: TextStyle( fontSize: theme.textTheme.titleMedium!.fontSize, fontWeight: FontWeight.bold, @@ -158,32 +191,19 @@ class _SubDetailPageState extends State { GestureDetector( onTap: () { Get.toNamed( - '/member?mid=${_subDetailController.subInfo.upper!.mid}', + '/member?mid=${info.upper!.mid}', ); }, child: Text( - _subDetailController.subInfo.upper!.name!, + info.upper!.name!, style: TextStyle(color: theme.colorScheme.primary), ), ), const Spacer(), - Obx( - () { - final mediaCount = - _subDetailController.mediaCount.value; - return mediaCount == 0 - ? const SizedBox.shrink() - : Text( - '共$mediaCount条视频', - style: style, - ); - }, - ), - Obx( - () => Text( - '${NumUtil.numFormat(_subDetailController.playCount.value)}次播放', - style: style, - ), + Text('共${info.mediaCount}条视频', style: style), + Text( + '${NumUtil.numFormat(info.viewCount ?? info.cntInfo?.play)}次播放', + style: style, ), ], ), diff --git a/lib/utils/app_scheme.dart b/lib/utils/app_scheme.dart index 1d37e7fa..a2467388 100644 --- a/lib/utils/app_scheme.dart +++ b/lib/utils/app_scheme.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:PiliPlus/http/search.dart'; import 'package:PiliPlus/models/common/video/source_type.dart'; +import 'package:PiliPlus/pages/subscription_detail/view.dart'; import 'package:PiliPlus/pages/video/reply_reply/view.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/id_utils.dart'; @@ -568,6 +569,13 @@ class PiliScheme { } if (host.contains('space.bilibili.com')) { + String? sid = + uri.queryParameters['sid'] ?? + RegExp(r'lists/(\d+)').firstMatch(path)?.group(1); + if (sid != null) { + SubDetailPage.toSubDetailPage(int.parse(sid)); + return true; + } String? mid = uriDigitRegExp.firstMatch(path)?.group(1); if (mid != null) { PageUtils.toDupNamed('/member?mid=$mid', off: off);