diff --git a/lib/common/widgets/stat/stat.dart b/lib/common/widgets/stat/stat.dart index 65fa2216b..ce30c734b 100644 --- a/lib/common/widgets/stat/stat.dart +++ b/lib/common/widgets/stat/stat.dart @@ -18,23 +18,13 @@ class StatWidget extends StatelessWidget { @override Widget build(BuildContext context) { - IconData iconData = switch (type) { - StatType.view => Icons.remove_red_eye_outlined, - StatType.danmaku => Icons.subtitles_outlined, - StatType.like => Icons.thumb_up_outlined, - StatType.reply => Icons.comment_outlined, - StatType.follow => Icons.favorite_border, - StatType.play => Icons.play_circle_outlined, - }; - Color color = this.color ?? Theme.of(context).colorScheme.outline.withValues(alpha: 0.8); - return Row( spacing: 2, children: [ Icon( - iconData, + type.iconData, size: iconSize, color: color, ), diff --git a/lib/http/api.dart b/lib/http/api.dart index 25c689104..16fb3f3d5 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -911,4 +911,8 @@ class Api { static const String liveShieldUser = '${HttpString.liveBaseUrl}/liveact/shield_user'; + + static const String spaceComic = '${HttpString.appBaseUrl}/x/v2/space/comic'; + + static const String spaceAudio = '/audio/music-service/web/song/upper'; } diff --git a/lib/http/member.dart b/lib/http/member.dart index a9689da2b..2f53466bc 100644 --- a/lib/http/member.dart +++ b/lib/http/member.dart @@ -17,6 +17,7 @@ import 'package:PiliPlus/models_new/member/search_archive/data.dart'; import 'package:PiliPlus/models_new/space/space/data.dart'; import 'package:PiliPlus/models_new/space/space_archive/data.dart'; import 'package:PiliPlus/models_new/space/space_article/data.dart'; +import 'package:PiliPlus/models_new/space/space_audio/data.dart'; import 'package:PiliPlus/models_new/space/space_opus/data.dart'; import 'package:PiliPlus/models_new/space/space_season_series/item.dart'; import 'package:PiliPlus/models_new/upower_rank/data.dart'; @@ -142,6 +143,7 @@ class MemberHttp { ContributeType.season => Api.spaceSeason, ContributeType.series => Api.spaceSeries, ContributeType.bangumi => Api.spaceBangumi, + ContributeType.comic => Api.spaceComic, }, queryParameters: data, options: Options( @@ -158,6 +160,27 @@ class MemberHttp { } } + static Future> spaceAudio({ + required int page, + required mid, + }) async { + var res = await Request().get( + Api.spaceAudio, + queryParameters: { + 'pn': page, + 'ps': 20, + 'order': 1, + 'uid': mid, + 'web_location': 333.1387 + }, + ); + if (res.data['code'] == 0) { + return Success(SpaceAudioData.fromJson(res.data['data'])); + } else { + return Error(res.data['message']); + } + } + static Future spaceStory({ required mid, required aid, diff --git a/lib/models/common/member/contribute_type.dart b/lib/models/common/member/contribute_type.dart index 4023ee1ad..a3b08a8f4 100644 --- a/lib/models/common/member/contribute_type.dart +++ b/lib/models/common/member/contribute_type.dart @@ -1 +1,8 @@ -enum ContributeType { video, charging, season, series, bangumi } +enum ContributeType { + video, + charging, + season, + series, + bangumi, + comic, +} diff --git a/lib/models/common/stat_type.dart b/lib/models/common/stat_type.dart index bf38a5190..cc3943a4d 100644 --- a/lib/models/common/stat_type.dart +++ b/lib/models/common/stat_type.dart @@ -1 +1,15 @@ -enum StatType { view, danmaku, like, reply, follow, play } +import 'package:flutter/material.dart' show IconData, Icons; + +enum StatType { + view(Icons.remove_red_eye_outlined), + danmaku(Icons.subtitles_outlined), + like(Icons.thumb_up_outlined), + reply(Icons.comment_outlined), + follow(Icons.favorite_border), + play(Icons.play_circle_outlined), + listen(Icons.headset_outlined), + ; + + final IconData iconData; + const StatType(this.iconData); +} diff --git a/lib/models_new/space/space/audios.dart b/lib/models_new/space/space/audios.dart index d0a846dbc..61b0d794d 100644 --- a/lib/models_new/space/space/audios.dart +++ b/lib/models_new/space/space/audios.dart @@ -1,15 +1,15 @@ -import 'package:PiliPlus/models_new/space/space/item.dart'; +import 'package:PiliPlus/models_new/space/space_audio/item.dart'; class Audios { int? count; - List? item; + List? item; Audios({this.count, this.item}); factory Audios.fromJson(Map json) => Audios( count: json['count'] as int?, item: (json['item'] as List?) - ?.map((e) => Item.fromJson(e as Map)) + ?.map((e) => SpaceAudioItem.fromJson(e as Map)) .toList(), ); } diff --git a/lib/models_new/space/space/comic.dart b/lib/models_new/space/space/comic.dart index e6119949f..cdd5ede33 100644 --- a/lib/models_new/space/space/comic.dart +++ b/lib/models_new/space/space/comic.dart @@ -1,11 +1,15 @@ +import 'package:PiliPlus/models_new/space/space_archive/item.dart'; + class Comic { int? count; - List? item; + List? item; Comic({this.count, this.item}); factory Comic.fromJson(Map json) => Comic( count: json['count'] as int?, - item: json['item'] as List?, + item: (json['item'] as List?) + ?.map((e) => SpaceArchiveItem.fromJson(e)) + .toList(), ); } diff --git a/lib/models_new/space/space_archive/item.dart b/lib/models_new/space/space_archive/item.dart index d52079092..8940f2069 100644 --- a/lib/models_new/space/space_archive/item.dart +++ b/lib/models_new/space/space_archive/item.dart @@ -32,6 +32,8 @@ class SpaceArchiveItem extends BaseSimpleVideoItemModel { List? badges; SpaceArchiveSeason? season; History? history; + String? styles; + String? label; SpaceArchiveItem.fromJson(Map json) { title = json['title']; @@ -75,5 +77,7 @@ class SpaceArchiveItem extends BaseSimpleVideoItemModel { : SpaceArchiveSeason.fromJson(json['season'] as Map); stat = PlayStat.fromJson(json); owner = Owner(mid: 0, name: json['author']); + styles = json['styles']; + label = json['label']; } } diff --git a/lib/models_new/space/space_audio/data.dart b/lib/models_new/space/space_audio/data.dart new file mode 100644 index 000000000..5cd91cd5f --- /dev/null +++ b/lib/models_new/space/space_audio/data.dart @@ -0,0 +1,27 @@ +import 'package:PiliPlus/models_new/space/space_audio/item.dart'; + +class SpaceAudioData { + int? curPage; + int? pageCount; + int? totalSize; + int? pageSize; + List? items; + + SpaceAudioData({ + this.curPage, + this.pageCount, + this.totalSize, + this.pageSize, + this.items, + }); + + factory SpaceAudioData.fromJson(Map json) => SpaceAudioData( + curPage: json['curPage'] as int?, + pageCount: json['pageCount'] as int?, + totalSize: json['totalSize'] as int?, + pageSize: json['pageSize'] as int?, + items: (json['data'] as List?) + ?.map((e) => SpaceAudioItem.fromJson(e as Map)) + .toList(), + ); +} diff --git a/lib/models_new/space/space_audio/item.dart b/lib/models_new/space/space_audio/item.dart new file mode 100644 index 000000000..6220d894f --- /dev/null +++ b/lib/models_new/space/space_audio/item.dart @@ -0,0 +1,90 @@ +import 'package:PiliPlus/models_new/space/space_audio/statistic.dart'; + +class SpaceAudioItem { + int? id; + int? uid; + String? uname; + String? author; + String? title; + String? cover; + String? intro; + String? lyric; + int? crtype; + int? duration; + int? passtime; + int? curtime; + int? aid; + String? bvid; + int? cid; + int? msid; + int? attr; + int? limit; + int? activityId; + String? limitdesc; + int? coinNum; + int? ctime; + Statistic? statistic; + dynamic vipInfo; + dynamic collectIds; + int? isCooper; + + SpaceAudioItem({ + this.id, + this.uid, + this.uname, + this.author, + this.title, + this.cover, + this.intro, + this.lyric, + this.crtype, + this.duration, + this.passtime, + this.curtime, + this.aid, + this.bvid, + this.cid, + this.msid, + this.attr, + this.limit, + this.activityId, + this.limitdesc, + this.coinNum, + this.ctime, + this.statistic, + this.vipInfo, + this.collectIds, + this.isCooper, + }); + + factory SpaceAudioItem.fromJson(Map json) => SpaceAudioItem( + id: json['id'] as int?, + uid: json['uid'] as int?, + uname: json['uname'] as String?, + author: json['author'] as String?, + title: json['title'] as String?, + cover: json['cover'] as String?, + intro: json['intro'] as String?, + lyric: json['lyric'] as String?, + crtype: json['crtype'] as int?, + duration: json['duration'] as int?, + passtime: json['passtime'] as int?, + curtime: json['curtime'] as int?, + aid: json['aid'] as int?, + bvid: json['bvid'] as String?, + cid: json['cid'] as int?, + msid: json['msid'] as int?, + attr: json['attr'] as int?, + limit: json['limit'] as int?, + activityId: json['activityId'] as int?, + limitdesc: json['limitdesc'] as String?, + coinNum: json['coin_num'] as int?, + ctime: json['ctime'] as int?, + statistic: json['statistic'] == null + ? null + : Statistic.fromJson(json['statistic'] as Map), + vipInfo: json['vipInfo'] as dynamic, + collectIds: json['collectIds'] as dynamic, + isCooper: json['is_cooper'] as int?, + ); +} diff --git a/lib/models_new/space/space_audio/statistic.dart b/lib/models_new/space/space_audio/statistic.dart new file mode 100644 index 000000000..5c7635ebc --- /dev/null +++ b/lib/models_new/space/space_audio/statistic.dart @@ -0,0 +1,17 @@ +class Statistic { + int? sid; + int? play; + int? collect; + int? comment; + int? share; + + Statistic({this.sid, this.play, this.collect, this.comment, this.share}); + + factory Statistic.fromJson(Map json) => Statistic( + sid: json['sid'] as int?, + play: json['play'] as int?, + collect: json['collect'] as int?, + comment: json['comment'] as int?, + share: json['share'] as int?, + ); +} diff --git a/lib/pages/member_audio/controller.dart b/lib/pages/member_audio/controller.dart new file mode 100644 index 000000000..3e0a0c34d --- /dev/null +++ b/lib/pages/member_audio/controller.dart @@ -0,0 +1,38 @@ +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/http/member.dart'; +import 'package:PiliPlus/models_new/space/space_audio/data.dart'; +import 'package:PiliPlus/models_new/space/space_audio/item.dart'; +import 'package:PiliPlus/pages/common/common_list_controller.dart'; + +class MemberAudioController + extends CommonListController { + MemberAudioController(this.mid); + + final int mid; + int? totalSize; + + @override + void onInit() { + super.onInit(); + queryData(); + } + + @override + void checkIsEnd(int length) { + if (totalSize != null && length >= totalSize!) { + isEnd = true; + } + } + + @override + List? getDataList(SpaceAudioData response) { + totalSize = response.totalSize; + return response.items; + } + + @override + Future> customGetData() => MemberHttp.spaceAudio( + page: page, + mid: mid, + ); +} diff --git a/lib/pages/member_audio/view.dart b/lib/pages/member_audio/view.dart index 8c0e4cb3b..88e8a0bd6 100644 --- a/lib/pages/member_audio/view.dart +++ b/lib/pages/member_audio/view.dart @@ -1,12 +1,24 @@ +import 'package:PiliPlus/common/constants.dart'; +import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; +import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; +import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models_new/space/space_audio/item.dart'; +import 'package:PiliPlus/pages/member_audio/controller.dart'; +import 'package:PiliPlus/pages/member_audio/widgets/item.dart'; +import 'package:PiliPlus/utils/grid.dart'; import 'package:flutter/material.dart'; +import 'package:get/get.dart'; class MemberAudio extends StatefulWidget { const MemberAudio({ super.key, required this.heroTag, + required this.mid, }); final String? heroTag; + final int mid; @override State createState() => _MemberAudioState(); @@ -14,14 +26,58 @@ class MemberAudio extends StatefulWidget { class _MemberAudioState extends State with AutomaticKeepAliveClientMixin { - @override - bool get wantKeepAlive => true; + late final _controller = + Get.put(MemberAudioController(widget.mid), tag: widget.heroTag); @override Widget build(BuildContext context) { super.build(context); - return const Center( - child: Text('Audio'), + return refreshIndicator( + onRefresh: _controller.onRefresh, + child: CustomScrollView( + slivers: [ + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80, + ), + sliver: Obx(() => _buildBody(_controller.loadingState.value)), + ), + ], + ), ); } + + @override + bool get wantKeepAlive => true; + + Widget _buildBody(LoadingState?> loadingState) { + return switch (loadingState) { + Loading() => linearLoading, + Success(:var response) => response?.isNotEmpty == true + ? SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: 2, + maxCrossAxisExtent: Grid.smallCardWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.6, + minHeight: MediaQuery.textScalerOf(context).scale(90), + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == response.length - 1) { + _controller.onLoadMore(); + } + return MemberAudioItem( + item: response[index], + ); + }, + childCount: response!.length, + ), + ) + : HttpError(onReload: _controller.onReload), + Error(:var errMsg) => HttpError( + errMsg: errMsg, + onReload: _controller.onReload, + ), + }; + } } diff --git a/lib/pages/member_audio/widgets/item.dart b/lib/pages/member_audio/widgets/item.dart new file mode 100644 index 000000000..4ceb793c8 --- /dev/null +++ b/lib/pages/member_audio/widgets/item.dart @@ -0,0 +1,89 @@ +import 'package:PiliPlus/common/constants.dart'; +import 'package:PiliPlus/common/widgets/image/image_save.dart'; +import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; +import 'package:PiliPlus/common/widgets/stat/stat.dart'; +import 'package:PiliPlus/models/common/stat_type.dart'; +import 'package:PiliPlus/models_new/space/space_audio/item.dart'; +import 'package:PiliPlus/utils/date_util.dart'; +import 'package:flutter/material.dart'; + +class MemberAudioItem extends StatelessWidget { + const MemberAudioItem({super.key, required this.item}); + + final SpaceAudioItem item; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + return Material( + type: MaterialType.transparency, + child: InkWell( + onTap: () { + // TODO + }, + onLongPress: () => + imageSaveDialog(title: item.title, cover: item.cover), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: StyleString.safeSpace, + vertical: 5, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 1, + child: LayoutBuilder( + builder: + (BuildContext context, BoxConstraints boxConstraints) { + return NetworkImgLayer( + radius: 4, + src: item.cover, + width: boxConstraints.maxWidth, + height: boxConstraints.maxHeight, + ); + }, + ), + ), + const SizedBox(width: 10), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item.title!, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 6), + Text( + DateUtil.dateFormat(item.ctime! ~/ 1000), + style: TextStyle( + fontSize: 13, + color: theme.colorScheme.onSurfaceVariant, + ), + ), + Row( + spacing: 16, + children: [ + StatWidget( + type: StatType.listen, + value: item.statistic?.play, + ), + StatWidget( + type: StatType.reply, + value: item.statistic?.comment, + ), + ], + ) + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/member_comic/controller.dart b/lib/pages/member_comic/controller.dart new file mode 100644 index 000000000..90920953a --- /dev/null +++ b/lib/pages/member_comic/controller.dart @@ -0,0 +1,41 @@ +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/http/member.dart'; +import 'package:PiliPlus/models/common/member/contribute_type.dart'; +import 'package:PiliPlus/models_new/space/space_archive/data.dart'; +import 'package:PiliPlus/models_new/space/space_archive/item.dart'; +import 'package:PiliPlus/pages/common/common_list_controller.dart'; + +class MemberComicController + extends CommonListController { + MemberComicController(this.mid); + + final int mid; + + int? count; + + @override + void onInit() { + super.onInit(); + queryData(); + } + + @override + void checkIsEnd(int length) { + if (count != null && length >= count!) { + isEnd = true; + } + } + + @override + List? getDataList(SpaceArchiveData response) { + count = response.count; + return response.item; + } + + @override + Future> customGetData() => + MemberHttp.spaceArchive( + type: ContributeType.comic, + mid: mid, + ); +} diff --git a/lib/pages/member_comic/view.dart b/lib/pages/member_comic/view.dart new file mode 100644 index 000000000..d8e02845c --- /dev/null +++ b/lib/pages/member_comic/view.dart @@ -0,0 +1,75 @@ +import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; +import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; +import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; +import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models_new/space/space_archive/item.dart'; +import 'package:PiliPlus/pages/member_comic/controller.dart'; +import 'package:PiliPlus/pages/member_comic/widgets/item.dart'; +import 'package:PiliPlus/utils/grid.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class MemberComic extends StatefulWidget { + const MemberComic({ + super.key, + required this.heroTag, + required this.mid, + }); + + final String? heroTag; + final int mid; + + @override + State createState() => _MemberComicState(); +} + +class _MemberComicState extends State + with AutomaticKeepAliveClientMixin { + late final _controller = + Get.put(MemberComicController(widget.mid), tag: widget.heroTag); + + @override + Widget build(BuildContext context) { + super.build(context); + return refreshIndicator( + onRefresh: _controller.onRefresh, + child: CustomScrollView( + slivers: [ + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 80, + ), + sliver: Obx(() => _buildBody(_controller.loadingState.value)), + ), + ], + ), + ); + } + + Widget _buildBody(LoadingState?> loadingState) { + return switch (loadingState) { + Loading() => linearLoading, + Success(:var response) => response?.isNotEmpty == true + ? SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context), + delegate: SliverChildBuilderDelegate( + (context, index) { + if (index == response.length - 1) { + _controller.onLoadMore(); + } + return MemberComicItem(item: response[index]); + }, + childCount: response!.length, + ), + ) + : HttpError(onReload: _controller.onReload), + Error(:var errMsg) => HttpError( + errMsg: errMsg, + onReload: _controller.onReload, + ), + }; + } + + @override + bool get wantKeepAlive => true; +} diff --git a/lib/pages/member_comic/widgets/item.dart b/lib/pages/member_comic/widgets/item.dart new file mode 100644 index 000000000..d38c856c5 --- /dev/null +++ b/lib/pages/member_comic/widgets/item.dart @@ -0,0 +1,84 @@ +import 'package:PiliPlus/common/constants.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_archive/item.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +class MemberComicItem extends StatelessWidget { + const MemberComicItem({super.key, required this.item}); + + final SpaceArchiveItem item; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + late final style = TextStyle( + fontSize: 13, + color: theme.colorScheme.onSurfaceVariant, + ); + return Material( + type: MaterialType.transparency, + child: InkWell( + onTap: () { + Get.toNamed( + '/webview', + parameters: { + 'url': 'https://manga.bilibili.com/detail/mc${item.param}' + }, + ); + }, + onLongPress: () => + imageSaveDialog(title: item.title, cover: item.cover), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: StyleString.safeSpace, + vertical: 5, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: 3 / 4, + child: LayoutBuilder( + builder: + (BuildContext context, BoxConstraints boxConstraints) { + return NetworkImgLayer( + radius: 4, + src: item.cover, + width: boxConstraints.maxWidth, + height: boxConstraints.maxHeight, + ); + }, + ), + ), + const SizedBox(width: 10), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(item.title), + if (item.styles != null) ...[ + const SizedBox(height: 6), + Text( + item.styles!, + style: style, + ), + ], + if (item.label != null) ...[ + Text( + item.label!, + style: style, + ), + ], + ], + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/member_contribute/view.dart b/lib/pages/member_contribute/view.dart index 109fcc383..2320105b7 100644 --- a/lib/pages/member_contribute/view.dart +++ b/lib/pages/member_contribute/view.dart @@ -2,6 +2,7 @@ import 'package:PiliPlus/models/common/member/contribute_type.dart'; import 'package:PiliPlus/models_new/space/space/tab2.dart'; import 'package:PiliPlus/pages/member_article/view.dart'; import 'package:PiliPlus/pages/member_audio/view.dart'; +import 'package:PiliPlus/pages/member_comic/view.dart'; import 'package:PiliPlus/pages/member_contribute/controller.dart'; import 'package:PiliPlus/pages/member_opus/view.dart'; import 'package:PiliPlus/pages/member_season_series/view.dart'; @@ -110,7 +111,14 @@ class _MemberContributeState extends State heroTag: widget.heroTag, mid: widget.mid, ), - 'audio' => MemberAudio(heroTag: widget.heroTag), + 'audio' => MemberAudio( + heroTag: widget.heroTag, + mid: widget.mid, + ), + 'comic' => MemberComic( + heroTag: widget.heroTag, + mid: widget.mid, + ), 'season_video' => MemberVideo( type: ContributeType.season, heroTag: widget.heroTag, diff --git a/lib/pages/member_home/view.dart b/lib/pages/member_home/view.dart index 5c5174586..3482482c0 100644 --- a/lib/pages/member_home/view.dart +++ b/lib/pages/member_home/view.dart @@ -7,7 +7,9 @@ import 'package:PiliPlus/models_new/space/space/data.dart'; import 'package:PiliPlus/models_new/space/space/tab2.dart'; import 'package:PiliPlus/pages/member/controller.dart'; import 'package:PiliPlus/pages/member_article/widget/item.dart'; +import 'package:PiliPlus/pages/member_audio/widgets/item.dart'; import 'package:PiliPlus/pages/member_coin_arc/view.dart'; +import 'package:PiliPlus/pages/member_comic/widgets/item.dart'; import 'package:PiliPlus/pages/member_contribute/controller.dart'; import 'package:PiliPlus/pages/member_home/widgets/fav_item.dart'; import 'package:PiliPlus/pages/member_home/widgets/video_card_v_member_home.dart'; @@ -52,7 +54,7 @@ class _MemberHomeState extends State ? CustomScrollView( slivers: [ if (res.archive?.item?.isNotEmpty == true) ...[ - _videoHeader( + _header( color, title: '视频', param: 'contribute', @@ -85,7 +87,7 @@ class _MemberHomeState extends State ), ], if (res.favourite2?.item?.isNotEmpty == true) ...[ - _videoHeader( + _header( color, title: '收藏', param: 'favorite', @@ -102,7 +104,7 @@ class _MemberHomeState extends State ), ], if (res.coinArchive?.item?.isNotEmpty == true) ...[ - _videoHeader( + _header( color, title: '最近投币的视频', param: 'coinArchive', @@ -135,7 +137,7 @@ class _MemberHomeState extends State ), ], if (res.likeArchive?.item?.isNotEmpty == true) ...[ - _videoHeader( + _header( color, title: '最近点赞的视频', param: 'likeArchive', @@ -168,7 +170,7 @@ class _MemberHomeState extends State ), ], if (res.article?.item?.isNotEmpty == true) ...[ - _videoHeader( + _header( color, title: '图文', param: 'contribute', @@ -188,17 +190,50 @@ class _MemberHomeState extends State ), ], if (res.audios?.item?.isNotEmpty == true) ...[ - _videoHeader( + _header( color, title: '音频', param: 'contribute', param1: 'audio', count: res.audios!.count!, ), - // TODO + SliverGrid( + gridDelegate: SliverGridDelegateWithExtentAndRatio( + mainAxisSpacing: 2, + maxCrossAxisExtent: Grid.smallCardWidth * 2, + childAspectRatio: StyleString.aspectRatio * 2.6, + minHeight: MediaQuery.textScalerOf(context).scale(90), + ), + delegate: SliverChildBuilderDelegate( + (context, index) { + return MemberAudioItem( + item: res.audios!.item![index], + ); + }, + childCount: isVertical ? 1 : min(2, res.audios!.count!), + ), + ) + ], + if (res.comic?.item?.isNotEmpty == true) ...[ + _header( + color, + title: '漫画', + param: 'contribute', + param1: 'comic', + count: res.comic!.count!, + ), + SliverGrid( + gridDelegate: Grid.videoCardHDelegate(context), + delegate: SliverChildBuilderDelegate( + (context, index) { + return MemberComicItem(item: res.comic!.item![index]); + }, + childCount: isVertical ? 1 : min(2, res.comic!.count!), + ), + ), ], if (res.season?.item?.isNotEmpty == true) ...[ - _videoHeader( + _header( color, title: '追番', param: 'bangumi', @@ -242,7 +277,7 @@ class _MemberHomeState extends State }; } - Widget _videoHeader( + Widget _header( Color color, { required String title, required String param, @@ -286,7 +321,8 @@ class _MemberHomeState extends State int index = _ctr.tab2!.indexWhere((item) => item.param == param); if (index != -1) { - if (const ['video', 'opus', 'audio'].contains(param1)) { + if (const ['video', 'opus', 'audio', 'comic'] + .contains(param1)) { List items = _ctr.tab2! .firstWhere((item) => item.param == param) .items!;