diff --git a/lib/models/dynamics/result.dart b/lib/models/dynamics/result.dart index 6cb746f67..796946d2a 100644 --- a/lib/models/dynamics/result.dart +++ b/lib/models/dynamics/result.dart @@ -129,6 +129,7 @@ class ModuleAuthorModel { this.type, this.vip, this.decorate, + this.pendant, }); String? face; @@ -143,7 +144,7 @@ class ModuleAuthorModel { String? type; Map? vip; Map? decorate; - // Map? pendant; + Map? pendant; ModuleAuthorModel.fromJson(Map json) { face = json['face']; @@ -159,7 +160,7 @@ class ModuleAuthorModel { vip = json['vip']; if (showDynDecorate) { decorate = json['decorate']; - // pendant = json['pendant']; + pendant = json['pendant']; } } diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index 617770a93..f22bc8eb2 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -31,6 +31,13 @@ class AuthorPanel extends StatelessWidget { this.onRemove, }); + Widget _buildAvatar(double size) => NetworkImgLayer( + width: size, + height: size, + type: 'avatar', + src: item.modules.moduleAuthor.face, + ); + @override Widget build(BuildContext context) { return Stack( @@ -57,12 +64,14 @@ class AuthorPanel extends StatelessWidget { }, ); }, - child: NetworkImgLayer( - width: 40, - height: 40, - type: 'avatar', - src: item.modules.moduleAuthor.face, - ), + child: (item.modules.moduleAuthor?.pendant?['image'] as String?) + ?.isNotEmpty == + true + ? Padding( + padding: const EdgeInsets.all(3), + child: _buildAvatar(34), + ) + : _buildAvatar(40), ), const SizedBox(width: 10), Column( @@ -137,58 +146,59 @@ class AuthorPanel extends StatelessWidget { ? Row( mainAxisSize: MainAxisSize.min, children: [ - GestureDetector( - onTap: - item.modules.moduleAuthor.decorate['jump_url'] != null - ? () { - Get.toNamed( - '/webview', - parameters: { - 'url': - '${item.modules.moduleAuthor.decorate['jump_url']}' - }, - ); - } - : null, - child: Stack( - clipBehavior: Clip.none, - alignment: Alignment.centerRight, - children: [ - CachedNetworkImage( - height: 32, - imageUrl: - item.modules.moduleAuthor.decorate['card_url'], - ), - if ((item.modules.moduleAuthor.decorate?['fan'] - ?['num_str'] as String?) - ?.isNotEmpty == - true) - Padding( - padding: const EdgeInsets.only(right: 32), - child: Text( - '${item.modules.moduleAuthor.decorate['fan']['num_str']}', - style: TextStyle( - fontSize: 11, - fontFamily: 'digital_id_num', - color: (item.modules.moduleAuthor - .decorate?['fan'] - ?['color'] as String?) - ?.startsWith('#') == - true - ? Color( - int.parse( - item.modules.moduleAuthor - .decorate['fan']['color'] - .replaceFirst('#', '0xFF'), - ), - ) - : null, - ), + // GestureDetector( + // onTap: + // item.modules.moduleAuthor.decorate['jump_url'] != null + // ? () { + // Get.toNamed( + // '/webview', + // parameters: { + // 'url': + // '${item.modules.moduleAuthor.decorate['jump_url']}' + // }, + // ); + // } + // : null, + // child: + Stack( + clipBehavior: Clip.none, + alignment: Alignment.centerRight, + children: [ + CachedNetworkImage( + height: 32, + imageUrl: + item.modules.moduleAuthor.decorate['card_url'], + ), + if ((item.modules.moduleAuthor.decorate?['fan'] + ?['num_str'] as String?) + ?.isNotEmpty == + true) + Padding( + padding: const EdgeInsets.only(right: 32), + child: Text( + '${item.modules.moduleAuthor.decorate['fan']['num_str']}', + style: TextStyle( + fontSize: 11, + fontFamily: 'digital_id_num', + color: + (item.modules.moduleAuthor.decorate?['fan'] + ?['color'] as String?) + ?.startsWith('#') == + true + ? Color( + int.parse( + item.modules.moduleAuthor + .decorate['fan']['color'] + .replaceFirst('#', '0xFF'), + ), + ) + : null, ), ), - ], - ), + ), + ], ), + // ), _moreWidget(context), ], ) diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index edacd21ce..09affbc40 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -1,5 +1,6 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'action_panel.dart'; import 'author_panel.dart'; @@ -79,27 +80,50 @@ class DynamicPanel extends StatelessWidget { ); } }, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(12, 12, 12, 6), - child: AuthorPanel( - item: item, - source: source, - onRemove: onRemove, - ), - ), - if (item!.modules!.moduleDynamic!.desc != null || - item!.modules!.moduleDynamic!.major != null) - content(context, item, source, callback), - forWard(item, context, source, callback), - const SizedBox(height: 2), - if (source == null) ActionPanel(item: item), - ], - ), + child: (item.modules.moduleAuthor?.pendant?['image'] as String?) + ?.isNotEmpty == + true + ? Stack( + clipBehavior: Clip.none, + children: [ + _buildContent(context, item, source, callback), + Positioned( + left: 2, + top: 2, + child: IgnorePointer( + child: CachedNetworkImage( + width: 60, + height: 60, + imageUrl: item.modules.moduleAuthor.pendant['image'], + ), + ), + ), + ], + ) + : _buildContent(context, item, source, callback), ), ), ); } + + Widget _buildContent(context, item, source, callback) => Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.fromLTRB(12, 12, 12, 6), + child: AuthorPanel( + item: item, + source: source, + onRemove: onRemove, + ), + ), + if (item!.modules!.moduleDynamic!.desc != null || + item!.modules!.moduleDynamic!.major != null) + content(context, item, source, callback), + forWard(item, context, source, callback), + const SizedBox(height: 2), + if (source == null) ActionPanel(item: item), + ], + ); } diff --git a/lib/pages/member/new/widget/user_info_card.dart b/lib/pages/member/new/widget/user_info_card.dart index 466e996ec..294de0058 100644 --- a/lib/pages/member/new/widget/user_info_card.dart +++ b/lib/pages/member/new/widget/user_info_card.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/common/widgets/network_img_layer.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/models/space/card.dart' as space; import 'package:PiliPlus/models/space/images.dart' as space; import 'package:PiliPlus/utils/extension.dart'; @@ -444,22 +445,22 @@ class UserInfoCard extends StatelessWidget { ), ); - _buildAvatar(BuildContext context) => Hero( - tag: card.face ?? 'avatarTag', - child: GestureDetector( - onTap: () { - context.imageView( - imgList: [card.face ?? 'avatarTag'], - ); - }, - child: Container( - decoration: BoxDecoration( - border: Border.all( - width: 2.5, - color: Theme.of(context).colorScheme.surface, - ), - shape: BoxShape.circle, - ), + _buildAvatar(BuildContext context) => Container( + decoration: BoxDecoration( + border: Border.all( + width: 2.5, + color: Theme.of(context).colorScheme.surface, + ), + shape: BoxShape.circle, + ), + child: Hero( + tag: card.face ?? 'avatarTag', + child: GestureDetector( + onTap: () { + context.imageView( + imgList: [card.face ?? 'avatarTag'], + ); + }, child: NetworkImgLayer( src: card.face, type: 'avatar', @@ -489,6 +490,19 @@ class UserInfoCard extends StatelessWidget { left: 20, child: _buildAvatar(context), ), + if (ModuleAuthorModel.showDynDecorate && + card.pendant?.image?.isNotEmpty == true) + Positioned( + top: 82.5, + left: -7.5, + child: IgnorePointer( + child: CachedNetworkImage( + width: 140, + height: 140, + imageUrl: card.pendant!.image!, + ), + ), + ), if (card.officialVerify?.icon?.isNotEmpty == true || (card.vip?.vipStatus ?? -1) > 0) Positioned( @@ -572,6 +586,19 @@ class UserInfoCard extends StatelessWidget { clipBehavior: Clip.none, children: [ _buildAvatar(context), + if (ModuleAuthorModel.showDynDecorate && + card.pendant?.image?.isNotEmpty == true) + Positioned( + top: -27.5, + left: -27.5, + child: IgnorePointer( + child: CachedNetworkImage( + width: 140, + height: 140, + imageUrl: card.pendant!.image!, + ), + ), + ), if (card.officialVerify?.icon?.isNotEmpty == true || (card.vip?.vipStatus ?? -1) > 0) Positioned( diff --git a/lib/pages/setting/widgets/model.dart b/lib/pages/setting/widgets/model.dart index 670a0c123..0249ac1cb 100644 --- a/lib/pages/setting/widgets/model.dart +++ b/lib/pages/setting/widgets/model.dart @@ -1908,7 +1908,7 @@ List get extraSettings => [ ), SettingsModel( settingsType: SettingsType.sw1tch, - title: '展示动态装饰', + title: '展示头像/评论/动态装饰', leading: Icon(MdiIcons.stickerCircleOutline), setKey: SettingBoxKey.showDynDecorate, defaultVal: true, diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index 142ca971f..5ccf56c5e 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -2,8 +2,10 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/imageview.dart'; import 'package:PiliPlus/http/video.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -77,10 +79,56 @@ class ReplyItem extends StatelessWidget { }, child: Column( children: [ - Padding( - padding: const EdgeInsets.fromLTRB(12, 14, 8, 5), - child: content(context), - ), + if (ModuleAuthorModel.showDynDecorate && + (replyItem?.member?.userSailing?.cardbg?['image'] as String?) + ?.isNotEmpty == + true) + Stack( + clipBehavior: Clip.none, + children: [ + Positioned( + top: 8, + right: 12, + child: Stack( + alignment: Alignment.centerRight, + children: [ + CachedNetworkImage( + height: 38, + imageUrl: + replyItem?.member?.userSailing?.cardbg?['image'], + ), + if ((replyItem?.member?.userSailing?.cardbg?['fan'] + ?['num_desc'] as String?) + ?.isNotEmpty == + true) + Text( + 'NO.\n${replyItem?.member?.userSailing?.cardbg?['fan']?['num_desc']}', + style: + (replyItem?.member?.userSailing?.cardbg?['fan'] + ?['color'] as String?) + ?.startsWith('#') == + true + ? TextStyle( + fontSize: 8, + fontFamily: 'digital_id_num', + color: Color( + int.parse( + replyItem?.member?.userSailing + ?.cardbg?['fan']?['color'] + .replaceFirst('#', '0xFF'), + ), + ), + ) + : null, + ), + ], + ), + ), + _buildAuthorPanel(context), + ], + ) + else + _buildAuthorPanel(context), if (needDivider) Divider( indent: 55, @@ -97,18 +145,44 @@ class ReplyItem extends StatelessWidget { ); } - Widget lfAvtar(BuildContext context, String heroTag) { + Widget _buildAuthorPanel(context) => Padding( + padding: const EdgeInsets.fromLTRB(12, 14, 8, 5), + child: content(context), + ); + + Widget lfAvtar(BuildContext context) { return Stack( + clipBehavior: Clip.none, children: [ - Hero( - tag: heroTag, - child: NetworkImgLayer( + if (ModuleAuthorModel.showDynDecorate && + replyItem?.member?.pendant?.image?.isNotEmpty == true) ...[ + Padding( + padding: const EdgeInsets.all(2), + child: NetworkImgLayer( + src: replyItem!.member!.avatar, + width: 30, + height: 30, + type: 'avatar', + ), + ), + Positioned( + left: -9, + top: -9, + child: IgnorePointer( + child: CachedNetworkImage( + width: 52, + height: 52, + imageUrl: replyItem!.member!.pendant!.image!, + ), + ), + ), + ] else + NetworkImgLayer( src: replyItem!.member!.avatar, width: 34, height: 34, type: 'avatar', ), - ), if (replyItem!.member!.vip!['vipStatus'] > 0) Positioned( right: 0, @@ -171,27 +245,25 @@ class ReplyItem extends StatelessWidget { Widget content(BuildContext context) { if (replyItem?.member == null) return const SizedBox(); - final String heroTag = Utils.makeHeroTag(replyItem!.mid); return Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ /// fix Stack内GestureDetector onTap无效 GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { feedBack(); - Get.toNamed('/member?mid=${replyItem!.mid}', arguments: { - 'face': replyItem!.member!.avatar!, - 'heroTag': heroTag - }); + Get.toNamed('/member?mid=${replyItem!.mid}'); }, child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - lfAvtar(context, heroTag), + lfAvtar(context), const SizedBox(width: 12), Column( + mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( @@ -223,6 +295,7 @@ class ReplyItem extends StatelessWidget { ], ), Row( + mainAxisSize: MainAxisSize.min, children: [ Text( Utils.dateFormat(replyItem!.ctime), @@ -470,14 +543,8 @@ class ReplyItem extends StatelessWidget { recognizer: TapGestureRecognizer() ..onTap = () { feedBack(); - final String heroTag = Utils.makeHeroTag( - replies![i].member!.mid); Get.toNamed( - '/member?mid=${replies![i].member!.mid}', - arguments: { - 'face': replies![i].member!.avatar, - 'heroTag': heroTag - }); + '/member?mid=${replies![i].member!.mid}'); }, ), if (replies![i].isUp!) ...[ @@ -682,11 +749,7 @@ class ReplyItem extends StatelessWidget { ), recognizer: TapGestureRecognizer() ..onTap = () { - final String heroTag = Utils.makeHeroTag(userId); - Get.toNamed( - '/member?mid=$userId', - arguments: {'face': '', 'heroTag': heroTag}, - ); + Get.toNamed('/member?mid=$userId'); }, ), ); diff --git a/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart b/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart index 443770f16..6f30e704e 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart @@ -4,9 +4,11 @@ import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/imageview.dart'; import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart'; import 'package:PiliPlus/http/video.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/pages/video/detail/reply/widgets/zan_grpc.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -89,40 +91,116 @@ class ReplyItemGrpc extends StatelessWidget { }, ); }, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(12, 14, 8, 5), - child: content(context), - ), - if (needDivider) - Divider( - indent: 55, - endIndent: 15, - height: 0.3, - color: Theme.of(context) - .colorScheme - .onInverseSurface - .withOpacity(0.5), - ) - ], - ), + child: _buildContent(context), ), ); } - Widget lfAvtar(BuildContext context, String heroTag) { - return Stack( + Widget _buildAuthorPanel(context) => Padding( + padding: const EdgeInsets.fromLTRB(12, 14, 8, 5), + child: content(context), + ); + + Widget _buildContent(context) { + print(replyItem.member.garbCardImage); + return Column( children: [ - Hero( - tag: heroTag, - child: NetworkImgLayer( + if (ModuleAuthorModel.showDynDecorate && + replyItem.member.hasGarbCardImage()) + Stack( + clipBehavior: Clip.none, + children: [ + Positioned( + top: 8, + right: 12, + // child: GestureDetector( + // onTap: replyItem.member.garbCardJumpUrl.isNotEmpty + // ? () { + // Get.toNamed( + // 'webview', + // parameters: { + // 'url': replyItem.member.garbCardJumpUrl + // }, + // ); + // } + // : null, + child: Stack( + alignment: Alignment.centerRight, + children: [ + CachedNetworkImage( + height: 38, + imageUrl: replyItem.member.garbCardImage, + ), + if (replyItem.member.hasGarbCardNumber()) + Text( + 'NO.\n${replyItem.member.garbCardNumber}', + style: replyItem.member.garbCardFanColor.startsWith('#') + ? TextStyle( + fontSize: 8, + fontFamily: 'digital_id_num', + color: Color( + int.parse( + replyItem.member.garbCardFanColor + .replaceFirst('#', '0xFF'), + ), + ), + ) + : null, + ), + ], + ), + ), + // ), + _buildAuthorPanel(context), + ], + ) + else + _buildAuthorPanel(context), + if (needDivider) + Divider( + indent: 55, + endIndent: 15, + height: 0.3, + color: + Theme.of(context).colorScheme.onInverseSurface.withOpacity(0.5), + ) + ], + ); + } + + Widget lfAvtar(BuildContext context) { + return Stack( + clipBehavior: Clip.none, + children: [ + if (ModuleAuthorModel.showDynDecorate && + replyItem.member.hasGarbPendantImage()) ...[ + Padding( + padding: const EdgeInsets.all(2), + child: NetworkImgLayer( + src: replyItem.member.face, + width: 30, + height: 30, + type: 'avatar', + ), + ), + Positioned( + left: -9, + top: -9, + child: IgnorePointer( + child: CachedNetworkImage( + width: 52, + height: 52, + imageUrl: replyItem.member.garbPendantImage, + ), + ), + ), + ] else + NetworkImgLayer( src: replyItem.member.face, width: 34, height: 34, type: 'avatar', ), - ), if (replyItem.member.vipStatus > 0) Positioned( right: 0, @@ -182,28 +260,29 @@ class ReplyItemGrpc extends StatelessWidget { } Widget content(BuildContext context) { - final String heroTag = Utils.makeHeroTag(replyItem.mid); return Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ /// fix Stack内GestureDetector onTap无效 GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { feedBack(); - Get.toNamed('/member?mid=${replyItem.mid}', - arguments: {'face': replyItem.member.face, 'heroTag': heroTag}); + Get.toNamed('/member?mid=${replyItem.mid}'); }, child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ - lfAvtar(context, heroTag), + lfAvtar(context), const SizedBox(width: 12), Column( crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, children: [ Row( + mainAxisSize: MainAxisSize.min, children: [ Text( replyItem.member.name, @@ -232,6 +311,7 @@ class ReplyItemGrpc extends StatelessWidget { ], ), Row( + mainAxisSize: MainAxisSize.min, children: [ Text( Utils.dateFormat(replyItem.ctime.toInt()), @@ -496,15 +576,9 @@ class ReplyItemGrpc extends StatelessWidget { recognizer: TapGestureRecognizer() ..onTap = () { feedBack(); - final String heroTag = Utils.makeHeroTag( - replyItem.replies[i].member.mid); Get.toNamed( - '/member?mid=${replyItem.replies[i].member.mid}', - arguments: { - 'face': - replyItem.replies[i].member.face, - 'heroTag': heroTag - }); + '/member?mid=${replyItem.replies[i].member.mid}', + ); }, ), if (replyItem.replies[i].mid == upMid) ...[ @@ -715,11 +789,7 @@ class ReplyItemGrpc extends StatelessWidget { ), recognizer: TapGestureRecognizer() ..onTap = () { - final String heroTag = Utils.makeHeroTag(userId); - Get.toNamed( - '/member?mid=$userId', - arguments: {'face': '', 'heroTag': heroTag}, - ); + Get.toNamed('/member?mid=$userId'); }, ), );