diff --git a/lib/models/common/member/user_info_type.dart b/lib/models/common/member/user_info_type.dart new file mode 100644 index 000000000..426cedbd3 --- /dev/null +++ b/lib/models/common/member/user_info_type.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart' show Alignment; + +enum UserInfoType { + fan('粉丝', .centerLeft), + follow('关注', .center), + like('获赞', .centerRight), + ; + + final String title; + final Alignment alignment; + + const UserInfoType(this.title, this.alignment); +} diff --git a/lib/pages/member/widget/user_info_card.dart b/lib/pages/member/widget/user_info_card.dart index 953c5588a..3acb4884c 100644 --- a/lib/pages/member/widget/user_info_card.dart +++ b/lib/pages/member/widget/user_info_card.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/common/widgets/pendant_avatar.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/models/common/image_type.dart'; +import 'package:PiliPlus/models/common/member/user_info_type.dart'; import 'package:PiliPlus/models_new/space/space/card.dart'; import 'package:PiliPlus/models_new/space/space/followings_followed_upper.dart'; import 'package:PiliPlus/models_new/space/space/images.dart'; @@ -24,17 +25,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart' hide ContextExtensionss; -enum _UserInfoType { - fan('粉丝', .centerLeft), - follow('关注', .center), - like('获赞', .centerRight), - ; - - final String title; - final Alignment alignment; - - const _UserInfoType(this.title, this.alignment); -} class UserInfoCard extends StatelessWidget { const UserInfoCard({ @@ -71,24 +61,24 @@ class UserInfoCard extends StatelessWidget { Widget _countWidget({ required ColorScheme colorScheme, - required _UserInfoType type, + required UserInfoType type, }) { int? count; VoidCallback? onTap; switch (type) { - case _UserInfoType.fan: + case UserInfoType.fan: count = card.fans; onTap = () => FansPage.toFansPage( mid: card.mid, name: card.name, ); - case _UserInfoType.follow: + case UserInfoType.follow: count = card.attention; onTap = () => FollowPage.toFollowPage( mid: card.mid, name: card.name, ); - case _UserInfoType.like: + case UserInfoType.like: count = card.likes?.likeNum; } return GestureDetector( @@ -352,7 +342,7 @@ class UserInfoCard extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Row( - children: _UserInfoType.values + children: UserInfoType.values .map( (e) => Expanded( child: _countWidget( diff --git a/lib/pages/member_favorite/view.dart b/lib/pages/member_favorite/view.dart index 94b50f01b..68af659c2 100644 --- a/lib/pages/member_favorite/view.dart +++ b/lib/pages/member_favorite/view.dart @@ -25,7 +25,7 @@ class MemberFavorite extends StatefulWidget { } class _MemberFavoriteState extends State - with AutomaticKeepAliveClientMixin { + with AutomaticKeepAliveClientMixin, GridMixin { @override bool get wantKeepAlive => true; @@ -115,6 +115,9 @@ class _MemberFavoriteState extends State _controller.setExpand(isFav); (context as Element).markNeedsBuild(); data.refresh(); + if (!isEnd.value) { + isEnd.refresh(); + } }, child: Container( height: 45, @@ -159,18 +162,11 @@ class _MemberFavoriteState extends State if (!_controller.isExpand(isFav)) { return const SliverToBoxAdapter(); } - final end = isEnd.value; if (list != null && list.isNotEmpty) { - return SliverList.builder( - itemCount: list.length + (end ? 0 : 1), + return SliverGrid.builder( + gridDelegate: gridDelegate, + itemCount: list.length, itemBuilder: (context, index) { - if (!end && index == list.length) { - return Obx( - () => isEnd.value - ? const SizedBox.shrink() - : _buildLoadMoreItem(theme, isFav), - ); - } final item = list[index]; return SizedBox( height: 98, @@ -190,6 +186,11 @@ class _MemberFavoriteState extends State } return const SliverToBoxAdapter(); }), + Obx( + () => isEnd.value || !_controller.isExpand(isFav) + ? const SliverToBoxAdapter() + : SliverToBoxAdapter(child: _buildLoadMoreItem(theme, isFav)), + ), ], ); } diff --git a/lib/pages/member_favorite/widget/item.dart b/lib/pages/member_favorite/widget/item.dart index 20795f408..8583d9010 100644 --- a/lib/pages/member_favorite/widget/item.dart +++ b/lib/pages/member_favorite/widget/item.dart @@ -61,10 +61,15 @@ class MemberFavItem extends StatelessWidget { Stack( clipBehavior: Clip.none, children: [ - NetworkImgLayer( - src: item.cover, - width: 140.8, - height: 88, + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, constraints) => NetworkImgLayer( + src: item.cover, + width: constraints.maxWidth, + height: constraints.maxHeight, + ), + ), ), if (item.type == 21) const PBadge( diff --git a/lib/pages/member_home/view.dart b/lib/pages/member_home/view.dart index 402addfc0..553a1477c 100644 --- a/lib/pages/member_home/view.dart +++ b/lib/pages/member_home/view.dart @@ -181,14 +181,13 @@ class _MemberHomeState extends State param1: 'opus', count: res.article!.count!, ), - SliverGrid.builder( - gridDelegate: gridDelegate, - itemBuilder: (context, index) { - return MemberArticleItem( - item: res.article!.item![index], - ); - }, - itemCount: isVertical ? 1 : res.article!.item!.length, + SliverToBoxAdapter( + child: SizedBox( + height: 98, + child: MemberArticleItem( + item: res.article!.item!.first, + ), + ), ), ], if (res.audios?.item?.isNotEmpty == true) ...[ @@ -206,7 +205,7 @@ class _MemberHomeState extends State item: res.audios!.item![index], ); }, - itemCount: isVertical ? 1 : min(2, res.audios!.count!), + itemCount: isVertical ? 1 : min(3, res.audios!.count!), ), ], if (res.comic?.item?.isNotEmpty == true) ...[ @@ -222,7 +221,7 @@ class _MemberHomeState extends State itemBuilder: (context, index) { return MemberComicItem(item: res.comic!.item![index]); }, - itemCount: isVertical ? 1 : min(2, res.comic!.count!), + itemCount: isVertical ? 1 : min(3, res.comic!.count!), ), ], if (res.season?.item?.isNotEmpty == true) ...[ diff --git a/lib/pages/video/member/controller.dart b/lib/pages/video/member/controller.dart index 466137046..399ea9077 100644 --- a/lib/pages/video/member/controller.dart +++ b/lib/pages/video/member/controller.dart @@ -5,6 +5,7 @@ import 'package:PiliPlus/models/member/info.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'; +import 'package:PiliPlus/utils/accounts.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:get/get.dart'; @@ -14,9 +15,9 @@ class HorizontalMemberPageController dynamic mid; - Rx> userState = + final Rx> userState = LoadingState.loading().obs; - RxMap userStat = {}.obs; + final RxMap userStat = {}.obs; @override void onInit() { @@ -30,6 +31,7 @@ class HorizontalMemberPageController if (res['status']) { userState.value = Success(res['data']); getMemberStat(); + getMemberView(); } else { userState.value = Error(res['msg']); } @@ -38,12 +40,14 @@ class HorizontalMemberPageController Future getMemberStat() async { var res = await MemberHttp.memberStat(mid: mid); if (res['status']) { - userStat.value = res['data']; - getMemberView(); + userStat.addAll(res['data']); } } Future getMemberView() async { + if (!Accounts.main.isLogin) { + return; + } var res = await MemberHttp.memberView(mid: mid); if (res['status']) { userStat.addAll(res['data']); diff --git a/lib/pages/video/member/view.dart b/lib/pages/video/member/view.dart index 336c19d4d..dfefac63f 100644 --- a/lib/pages/video/member/view.dart +++ b/lib/pages/video/member/view.dart @@ -1,6 +1,4 @@ import 'package:PiliPlus/common/skeleton/video_card_h.dart'; -import 'package:PiliPlus/common/widgets/button/icon_button.dart'; -import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; @@ -8,6 +6,7 @@ import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/models/common/image_type.dart'; +import 'package:PiliPlus/models/common/member/user_info_type.dart'; import 'package:PiliPlus/models/member/info.dart'; import 'package:PiliPlus/models_new/space/space_archive/item.dart'; import 'package:PiliPlus/models_new/video/video_detail/episode.dart'; @@ -83,21 +82,8 @@ class _HorizontalMemberPageState extends State { Loading() => loadingWidget, Success(:var response) => Column( children: [ - const SizedBox(height: 4), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - iconButton( - context: context, - onPressed: Get.back, - tooltip: '关闭', - icon: const Icon(Icons.clear), - size: 32, - ), - const SizedBox(width: 16), - ], - ), _buildUserInfo(theme, response), + _buildHeader(theme), Expanded( child: refreshIndicator( onRefresh: _controller.onRefresh, @@ -105,7 +91,6 @@ class _HorizontalMemberPageState extends State { controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ - _buildSliverHeader(theme), SliverPadding( padding: EdgeInsets.only( bottom: MediaQuery.viewPaddingOf(context).bottom + 100, @@ -134,53 +119,45 @@ class _HorizontalMemberPageState extends State { }; } - Widget _buildSliverHeader(ThemeData theme) { - return SliverPersistentHeader( - pinned: false, - floating: true, - delegate: CustomSliverPersistentHeaderDelegate( - extent: 40, - bgColor: theme.colorScheme.surface, - child: Container( - height: 40, - padding: const EdgeInsets.fromLTRB(12, 0, 6, 0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Obx( - () { - final count = _controller.count.value; - return Text( - count != -1 ? '共$count视频' : '', - style: const TextStyle(fontSize: 13), - ); - }, + Widget _buildHeader(ThemeData theme) { + return Container( + height: 40, + padding: const EdgeInsets.fromLTRB(12, 0, 6, 0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Obx( + () { + final count = _controller.count.value; + return Text( + count != -1 ? '共$count视频' : '', + style: const TextStyle(fontSize: 13), + ); + }, + ), + SizedBox( + height: 35, + child: TextButton.icon( + onPressed: () => _controller + ..lastAid = widget.videoDetailController.aid.toString() + ..queryBySort(), + icon: Icon( + Icons.sort, + size: 16, + color: theme.colorScheme.secondary, ), - SizedBox( - height: 35, - child: TextButton.icon( - onPressed: () => _controller - ..lastAid = widget.videoDetailController.aid.toString() - ..queryBySort(), - icon: Icon( - Icons.sort, - size: 16, + label: Obx( + () => Text( + _controller.order.value == 'pubdate' ? '最新发布' : '最多播放', + style: TextStyle( + fontSize: 13, color: theme.colorScheme.secondary, ), - label: Obx( - () => Text( - _controller.order.value == 'pubdate' ? '最新发布' : '最多播放', - style: TextStyle( - fontSize: 13, - color: theme.colorScheme.secondary, - ), - ), - ), ), ), - ], + ), ), - ), + ], ), ); } @@ -233,14 +210,15 @@ class _HorizontalMemberPageState extends State { } Widget _buildUserInfo(ThemeData theme, MemberInfoModel memberInfoModel) { - return Row( - children: [ - const SizedBox(width: 16), - _buildAvatar(memberInfoModel.face!), - const SizedBox(width: 10), - Expanded(child: _buildInfo(theme, memberInfoModel)), - const SizedBox(width: 16), - ], + return Padding( + padding: const .only(left: 16, top: 10, right: 16, bottom: 3), + child: Row( + spacing: 10, + children: [ + _buildAvatar(memberInfoModel.face!), + Expanded(child: _buildInfo(theme, memberInfoModel)), + ], + ), ); } @@ -272,52 +250,36 @@ class _HorizontalMemberPageState extends State { ), ], ), - const SizedBox(height: 2), + const SizedBox(height: 4), Obx( () => Row( - children: List.generate(5, (index) { - if (index.isEven) { - return _buildChildInfo( - theme: theme, - title: const ['粉丝', '关注', '获赞'][index ~/ 2], - num: index == 0 - ? _controller.userStat['follower'] != null - ? NumUtils.numFormat(_controller.userStat['follower']) - : '' - : index == 2 - ? _controller.userStat['following'] ?? '' - : _controller.userStat['likes'] != null - ? NumUtils.numFormat(_controller.userStat['likes']) - : '', - onTap: () { - if (index == 0) { - FansPage.toFansPage( - mid: widget.mid, - name: memberInfoModel.name, - ); - } else if (index == 2) { - FollowPage.toFollowPage( - mid: widget.mid, - name: memberInfoModel.name, - ); - } - }, - ); - } else { - return SizedBox( - height: 10, - width: 20, - child: VerticalDivider( - width: 1, - color: theme.colorScheme.outline, + children: UserInfoType.values + .map( + (e) => _buildChildInfo( + theme: theme, + type: e, + userStat: _controller.userStat, + memberInfoModel: memberInfoModel, ), - ); - } - }), + ) + .expand((child) sync* { + yield SizedBox( + height: 10, + width: 20, + child: VerticalDivider( + width: 1, + color: theme.colorScheme.outline, + ), + ); + yield child; + }) + .skip(1) + .toList(), ), ), - const SizedBox(height: 2), + const SizedBox(height: 8), Row( + spacing: 8, children: [ Expanded( child: FilledButton.tonal( @@ -329,6 +291,7 @@ class _HorizontalMemberPageState extends State { ? theme.colorScheme.outline : null, padding: EdgeInsets.zero, + tapTargetSize: .shrinkWrap, visualDensity: const VisualDensity(vertical: -2), ), onPressed: () { @@ -362,11 +325,11 @@ class _HorizontalMemberPageState extends State { ), ), ), - const SizedBox(width: 8), Expanded( child: OutlinedButton( style: OutlinedButton.styleFrom( padding: EdgeInsets.zero, + tapTargetSize: .shrinkWrap, visualDensity: const VisualDensity(vertical: -2), ), onPressed: () => Get.toNamed('/member?mid=${widget.mid}'), @@ -384,14 +347,36 @@ class _HorizontalMemberPageState extends State { Widget _buildChildInfo({ required ThemeData theme, - required String title, - required dynamic num, - required VoidCallback onTap, + required UserInfoType type, + required Map userStat, + required MemberInfoModel memberInfoModel, }) { + dynamic num; + VoidCallback? onTap; + switch (type) { + case UserInfoType.fan: + num = userStat['follower'] != null + ? NumUtils.numFormat(userStat['follower']) + : ''; + onTap = () => FansPage.toFansPage( + mid: widget.mid, + name: memberInfoModel.name, + ); + case UserInfoType.follow: + num = userStat['following'] ?? ''; + onTap = () => FollowPage.toFollowPage( + mid: widget.mid, + name: memberInfoModel.name, + ); + case UserInfoType.like: + num = userStat['likes'] != null + ? NumUtils.numFormat(userStat['likes']) + : ''; + } return GestureDetector( onTap: onTap, child: Text( - '$num$title', + '$num${type.title}', style: TextStyle( fontSize: 14, color: theme.colorScheme.outline,