From 3d4bcbc0825a5e113f707c7db14db737282dc83c Mon Sep 17 00:00:00 2001 From: My-Responsitories <107370289+My-Responsitories@users.noreply.github.com> Date: Tue, 22 Apr 2025 14:36:01 +0800 Subject: [PATCH] refa: avatar (not radical) (#731) * refa: avatar (not radical) * update Signed-off-by: bggRGjQaUbCoE --------- Signed-off-by: bggRGjQaUbCoE Co-authored-by: bggRGjQaUbCoE --- lib/common/widgets/avatar.dart | 169 ++++++++++++++ lib/pages/dynamics/widgets/author_panel.dart | 76 +++--- lib/pages/dynamics/widgets/dynamic_panel.dart | 71 ++---- lib/pages/member/widget/user_info_card.dart | 220 +++++------------- lib/pages/search_panel/user/widgets/item.dart | 37 +-- lib/pages/video/detail/introduction/view.dart | 65 ++---- .../detail/reply/widgets/reply_item_grpc.dart | 100 +------- 7 files changed, 319 insertions(+), 419 deletions(-) create mode 100644 lib/common/widgets/avatar.dart diff --git a/lib/common/widgets/avatar.dart b/lib/common/widgets/avatar.dart new file mode 100644 index 00000000..adb52db7 --- /dev/null +++ b/lib/common/widgets/avatar.dart @@ -0,0 +1,169 @@ +import 'package:PiliPlus/utils/extension.dart'; +import 'package:PiliPlus/utils/storage.dart'; +import 'package:PiliPlus/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'network_img_layer.dart'; + +class Avatar extends StatelessWidget { + final _BadgeType _badgeType; + final String avatar; + final double size; + final double badgeSize; + final String? garbPendantImage; + final dynamic roomId; + final VoidCallback? onTap; + + const Avatar({ + super.key, + required this.avatar, + this.size = 80, + double? badgeSize, + bool? isVip, + int? officialType, + this.garbPendantImage, + this.roomId, + this.onTap, + }) : _badgeType = officialType == null || officialType < 0 + ? isVip == true + ? _BadgeType.vip + : _BadgeType.none + : officialType == 0 + ? _BadgeType.person + : officialType == 1 + ? _BadgeType.institution + : _BadgeType.none, + badgeSize = badgeSize ?? size / 3; + + static final showDynDecorate = GStorage.showDynDecorate; + + @override + Widget build(BuildContext context) { + final colorScheme = Theme.of(context).colorScheme; + return Stack( + alignment: Alignment.bottomCenter, + clipBehavior: Clip.none, + children: [ + onTap == null + ? _buildAvatar(colorScheme) + : GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: onTap, + child: _buildAvatar(colorScheme), + ), + if (showDynDecorate && !garbPendantImage.isNullOrEmpty) + Positioned( + top: -0.375 * + (size == 80 ? size - 4 : size), // -(size * 1.75 - size) / 2 + child: IgnorePointer( + child: CachedNetworkImage( + width: size * 1.75, + height: size * 1.75, + imageUrl: Utils.thumbnailImgUrl(garbPendantImage), + ), + ), + ), + if (roomId != null) + Positioned( + bottom: 0, + child: InkWell( + onTap: () { + Get.toNamed('/liveRoom?roomid=$roomId'); + }, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 5, vertical: 1), + decoration: BoxDecoration( + color: colorScheme.secondaryContainer, + borderRadius: BorderRadius.circular(36), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + Icons.equalizer_rounded, + size: MediaQuery.textScalerOf(context).scale(16), + color: colorScheme.onSecondaryContainer, + ), + Text( + '直播中', + style: TextStyle( + height: 1, + fontSize: 13, + color: colorScheme.onSecondaryContainer, + ), + ), + ], + ), + ), + ), + ) + else if (_badgeType != _BadgeType.none) + _buildBadge(colorScheme), + ], + ); + } + + Widget _buildAvatar(ColorScheme colorScheme) => size == 80 + ? Container( + decoration: BoxDecoration( + border: Border.all( + width: 2, + color: colorScheme.surface, + ), + shape: BoxShape.circle, + ), + child: NetworkImgLayer( + src: avatar, + width: size, + height: size, + type: 'avatar', + ), + ) + : NetworkImgLayer( + src: avatar, + width: size, + height: size, + type: 'avatar', + ); + + Widget _buildBadge(ColorScheme colorScheme) { + final child = switch (_badgeType) { + _BadgeType.vip => Image.asset( + 'assets/images/big-vip.png', + height: badgeSize, + semanticLabel: _badgeType.desc, + ), + _ => Icon( + Icons.offline_bolt, + color: _badgeType.color, + size: badgeSize, + semanticLabel: _badgeType.desc, + ), + }; + return Positioned( + right: 0, + bottom: 0, + child: IgnorePointer( + child: DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: colorScheme.surface, + ), + child: child), + )); + } +} + +enum _BadgeType { none, vip, person, institution } + +extension _BadgeTypeExt on _BadgeType { + String get desc => const ['', '大会员', '认证个人', '认证机构'][index]; + Color get color => const [ + Colors.transparent, + Color(0xFFFF6699), + Color(0xFFFFCC00), + Colors.lightBlueAccent + ][index]; +} diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index 7e62c50a..e6a2055d 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -1,5 +1,6 @@ import 'dart:math'; +import 'package:PiliPlus/common/widgets/avatar.dart'; import 'package:PiliPlus/common/widgets/report.dart'; import 'package:PiliPlus/common/widgets/save_panel.dart'; import 'package:PiliPlus/http/index.dart'; @@ -12,7 +13,6 @@ import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:PiliPlus/common/widgets/network_img_layer.dart'; import 'package:PiliPlus/http/user.dart'; import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/utils.dart'; @@ -38,15 +38,24 @@ class AuthorPanel extends StatelessWidget { this.onSetTop, }); - Widget _buildAvatar(double size) => NetworkImgLayer( - width: size, - height: size, - type: 'avatar', - src: item.modules.moduleAuthor.face, - ); + Widget _buildAvatar() { + String? pendant = item.modules.moduleAuthor?.pendant?['image']; + Widget avatar = Avatar( + avatar: item.modules.moduleAuthor.face, + size: pendant.isNullOrEmpty ? 40 : 34, + isVip: null, // item.modules.moduleAuthor!.vip['status'] > 0 + officialType: null, // 已被注释 + garbPendantImage: pendant, + ); + if (!pendant.isNullOrEmpty) { + avatar = Padding(padding: const EdgeInsets.all(3), child: avatar); + } + return avatar; + } @override Widget build(BuildContext context) { + final theme = Theme.of(context); String? pubTime = item.modules.moduleAuthor.pubTs != null ? isSave ? DateTime.fromMillisecondsSinceEpoch( @@ -63,31 +72,22 @@ class AuthorPanel extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - GestureDetector( - onTap: () { - // 番剧 - if (item.modules.moduleAuthor.type == 'AUTHOR_TYPE_PGC' || + (item.modules.moduleAuthor.type == 'AUTHOR_TYPE_PGC' || item.modules.moduleAuthor.type == - 'AUTHOR_TYPE_UGC_SEASON') { - return; - } - feedBack(); - Get.toNamed( - '/member?mid=${item.modules.moduleAuthor.mid}', - arguments: { - 'face': 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), - ), + 'AUTHOR_TYPE_UGC_SEASON') + ? _buildAvatar() // 番剧 + : GestureDetector( + onTap: () { + feedBack(); + Get.toNamed( + '/member?mid=${item.modules.moduleAuthor.mid}', + arguments: { + 'face': item.modules.moduleAuthor.face, + }, + ); + }, + child: _buildAvatar(), + ), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -99,18 +99,16 @@ class AuthorPanel extends StatelessWidget { item.modules.moduleAuthor!.vip['status'] > 0 && item.modules.moduleAuthor!.vip['type'] == 2 ? context.vipColor - : Theme.of(context).colorScheme.onSurface, - fontSize: - Theme.of(context).textTheme.titleSmall!.fontSize, + : theme.colorScheme.onSurface, + fontSize: theme.textTheme.titleSmall!.fontSize, ), ), if (pubTime != null) Text( '$pubTime${item.modules.moduleAuthor.pubAction != null ? ' ${item.modules.moduleAuthor.pubAction}' : ''}', style: TextStyle( - color: Theme.of(context).colorScheme.outline, - fontSize: - Theme.of(context).textTheme.labelSmall!.fontSize, + color: theme.colorScheme.outline, + fontSize: theme.textTheme.labelSmall!.fontSize, ), ), ], @@ -132,7 +130,7 @@ class AuthorPanel extends StatelessWidget { const BorderRadius.all(Radius.circular(4)), border: Border.all( width: 1.25, - color: Theme.of(context).colorScheme.primary, + color: theme.colorScheme.primary, ), ), child: Text( @@ -140,7 +138,7 @@ class AuthorPanel extends StatelessWidget { style: TextStyle( height: 1, fontSize: 12, - color: Theme.of(context).colorScheme.primary, + color: theme.colorScheme.primary, ), strutStyle: const StrutStyle( leading: 0, diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index b5b20a69..e1579c08 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -1,8 +1,6 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/page_utils.dart'; -import 'package:PiliPlus/utils/utils.dart'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'action_panel.dart'; @@ -93,54 +91,31 @@ class DynamicPanel extends StatelessWidget { ); } }, - 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: Utils.thumbnailImgUrl( - item.modules.moduleAuthor.pendant['image']), - ), - ), - ), - ], - ) - : _buildContent(context, item, source, callback), + child: 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, + isSave: isSave, + onSetTop: onSetTop, + ), + ), + if (item!.modules!.moduleDynamic!.desc != null || + item!.modules!.moduleDynamic!.major != null) + content(isSave, context, item, source, callback), + forWard(isSave, item, context, source, callback), + const SizedBox(height: 2), + if (source == null) ActionPanel(item: item), + if (source == 'detail' && !isSave) const SizedBox(height: 12), + ], + ), ), ), ); } - - 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, - isSave: isSave, - onSetTop: onSetTop, - ), - ), - if (item!.modules!.moduleDynamic!.desc != null || - item!.modules!.moduleDynamic!.major != null) - content(isSave, context, item, source, callback), - forWard(isSave, item, context, source, callback), - const SizedBox(height: 2), - if (source == null) ActionPanel(item: item), - if (source == 'detail' && !isSave) const SizedBox(height: 12), - ], - ); } diff --git a/lib/pages/member/widget/user_info_card.dart b/lib/pages/member/widget/user_info_card.dart index 7b33ed43..dc2218eb 100644 --- a/lib/pages/member/widget/user_info_card.dart +++ b/lib/pages/member/widget/user_info_card.dart @@ -1,7 +1,6 @@ +import 'package:PiliPlus/common/widgets/avatar.dart'; import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart' show SourceModel; -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'; @@ -72,24 +71,25 @@ class UserInfoCard extends StatelessWidget { _buildHeader(BuildContext context) { bool darken = Theme.of(context).brightness == Brightness.dark; - String? imgUrl = darken - ? (images.nightImgurl?.isEmpty == true - ? images.imgUrl?.http2https - : images.nightImgurl?.http2https) - : images.imgUrl?.http2https; + String imgUrl = (darken + ? images.nightImgurl?.isEmpty == true + ? images.imgUrl + : images.nightImgurl + : images.imgUrl) + .http2https; return Hero( - tag: imgUrl ?? '', + tag: imgUrl, child: GestureDetector( onTap: () { context.imageView( - imgList: [SourceModel(url: imgUrl ?? '')], + imgList: [SourceModel(url: imgUrl)], ); }, child: CachedNetworkImage( imageUrl: Utils.thumbnailImgUrl(imgUrl), width: double.infinity, height: 135, - imageBuilder: (context, imageProvider) => Container( + imageBuilder: (context, imageProvider) => DecoratedBox( decoration: BoxDecoration( image: DecorationImage( image: imageProvider, @@ -118,7 +118,7 @@ class UserInfoCard extends StatelessWidget { onTap: () => Utils.copyText(card.name!), child: Text( card.name!, - strutStyle: StrutStyle( + strutStyle: const StrutStyle( height: 1, leading: 0, fontSize: 17, @@ -141,16 +141,30 @@ class UserInfoCard extends StatelessWidget { semanticLabel: '等级${card.levelInfo?.currentLevel}', ), if (card.vip?.vipStatus == 1) - CachedNetworkImage( - imageUrl: Utils.thumbnailImgUrl(card.vip!.label!.image!, 80), - height: 20, - placeholder: (context, url) { - return const SizedBox.shrink(); - }, + Container( + padding: + const EdgeInsets.symmetric(horizontal: 8, vertical: 3), + decoration: BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10)), + color: context.vipColor), + child: Text( + card.vip?.label?.text ?? '大会员', + strutStyle: const StrutStyle( + height: 1, + fontSize: 10, + fontWeight: FontWeight.bold, + ), + style: TextStyle( + height: 1, + fontWeight: FontWeight.bold, + fontSize: 10, + color: Colors.white, + ), + ), ), - if (card.nameplate?.image?.isNotEmpty == true) + if (card.nameplate?.imageSmall?.isNotEmpty == true) CachedNetworkImage( - imageUrl: Utils.thumbnailImgUrl(card.nameplate!.image!), + imageUrl: Utils.thumbnailImgUrl(card.nameplate!.imageSmall!), height: 20, placeholder: (context, url) { return const SizedBox.shrink(); @@ -164,7 +178,7 @@ class UserInfoCard extends StatelessWidget { margin: const EdgeInsets.only(left: 20, top: 8, right: 20), padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2), decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), + borderRadius: const BorderRadius.all(Radius.circular(12)), color: Theme.of(context).colorScheme.onInverseSurface, ), child: Text.rich( @@ -178,11 +192,12 @@ class UserInfoCard extends StatelessWidget { shape: BoxShape.circle, color: Theme.of(context).colorScheme.surface, ), - child: CachedNetworkImage( - width: 18, - height: 18, - imageUrl: - Utils.thumbnailImgUrl(card.officialVerify!.icon!), + child: Icon( + Icons.offline_bolt, + color: card.officialVerify?.type == 0 + ? const Color(0xFFFFCC00) + : Colors.lightBlueAccent, + size: 18, ), ), ), @@ -210,9 +225,7 @@ class UserInfoCard extends StatelessWidget { padding: const EdgeInsets.only(left: 20, top: 6, right: 20), child: SelectableText( card.sign!.trim().replaceAll(RegExp(r'\n{2,}'), '\n'), - style: const TextStyle( - fontSize: 14, - ), + style: const TextStyle(fontSize: 14), ), ), Padding( @@ -410,51 +423,19 @@ class UserInfoCard extends StatelessWidget { ], ); - _buildBadge(BuildContext context) => IgnorePointer( - child: DecoratedBox( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.surface, - ), - child: card.officialVerify?.icon?.isNotEmpty == true - ? CachedNetworkImage( - imageUrl: Utils.thumbnailImgUrl(card.officialVerify!.icon!), - width: 22, - height: 22, - ) - : Image.asset( - 'assets/images/big-vip.png', - width: 22, - height: 22, - ), - ), - ); - _buildAvatar(BuildContext context) => Hero( - tag: card.face ?? '', - child: GestureDetector( - onTap: () { - context.imageView( - imgList: [SourceModel(url: card.face ?? '')], - ); - }, - child: Container( - decoration: BoxDecoration( - border: Border.all( - width: 2.5, - color: Theme.of(context).colorScheme.surface, - ), - shape: BoxShape.circle, - ), - child: NetworkImgLayer( - src: card.face, - type: 'avatar', - width: 80, - height: 80, - ), - ), - ), - ); + tag: card.face ?? '', + child: Avatar( + avatar: card.face ?? '', + size: 80, + badgeSize: 22, + officialType: card.officialVerify?.type, + isVip: (card.vip?.vipStatus ?? -1) > 0, + garbPendantImage: card.pendant!.image!, + roomId: live is Map && live['liveStatus'] == 1 ? live['roomid'] : null, + onTap: () => context + .imageView(imgList: [SourceModel(url: card.face.http2https)]), + )); _buildV(BuildContext context) => Column( mainAxisSize: MainAxisSize.min, @@ -475,32 +456,6 @@ 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: Utils.thumbnailImgUrl(card.pendant!.image!), - ), - ), - ), - if (card.officialVerify?.icon?.isNotEmpty == true || - (card.vip?.vipStatus ?? -1) > 0) - Positioned( - top: 172, - left: 82, - child: _buildBadge(context), - ), - if (live is Map && ((live['liveStatus'] as int?) ?? 0) == 1) - Positioned( - top: 180, - left: 20, - child: _buildLiveBadge(context), - ), Positioned( left: 120, top: 140, @@ -579,39 +534,6 @@ class UserInfoCard extends StatelessWidget { ); }); - _buildLiveBadge(context) => GestureDetector( - onTap: () { - Get.toNamed('/liveRoom?roomid=${live['roomid']}'); - }, - child: Container( - width: 85, - alignment: Alignment.center, - child: Badge( - label: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.equalizer_rounded, - size: MediaQuery.textScalerOf(context).scale(16), - color: Theme.of(context).colorScheme.onSecondaryContainer, - ), - Text( - '直播中', - style: TextStyle(height: 1), - ) - ], - ), - padding: const EdgeInsets.symmetric( - horizontal: 5, - vertical: 1, - ), - alignment: Alignment.center, - textColor: Theme.of(context).colorScheme.onSecondaryContainer, - backgroundColor: Theme.of(context).colorScheme.secondaryContainer, - ), - ), - ); - _buildH(BuildContext context) => Column( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, @@ -632,41 +554,7 @@ class UserInfoCard extends StatelessWidget { top: 10, bottom: card.prInfo?.content?.isNotEmpty == true ? 0 : 10, ), - child: Stack( - 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: - Utils.thumbnailImgUrl(card.pendant!.image!), - ), - ), - ), - if (card.officialVerify?.icon?.isNotEmpty == true || - (card.vip?.vipStatus ?? -1) > 0) - Positioned( - right: 0, - bottom: 0, - child: _buildBadge(context), - ), - if (live is Map && - ((live['liveStatus'] as int?) ?? 0) == 1) - Positioned( - left: 0, - bottom: -5, - right: 0, - child: _buildLiveBadge(context), - ), - ], - ), + child: _buildAvatar(context), ), Expanded( child: Column( diff --git a/lib/pages/search_panel/user/widgets/item.dart b/lib/pages/search_panel/user/widgets/item.dart index 623cd234..37d6897b 100644 --- a/lib/pages/search_panel/user/widgets/item.dart +++ b/lib/pages/search_panel/user/widgets/item.dart @@ -1,4 +1,4 @@ -import 'package:PiliPlus/common/widgets/network_img_layer.dart'; +import 'package:PiliPlus/common/widgets/avatar.dart'; import 'package:PiliPlus/models/search/result.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -25,35 +25,12 @@ class SearchUserItem extends StatelessWidget { child: Row( children: [ const SizedBox(width: 15), - Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - width: 42, - height: 42, - src: item.upic, - type: 'avatar', - ), - if (item.officialVerify?['type'] == 0 || - item.officialVerify?['type'] == 1) - Positioned( - bottom: 0, - right: 0, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.surface, - ), - child: Icon( - Icons.offline_bolt, - color: item.officialVerify?['type'] == 0 - ? const Color(0xFFFFCC00) - : Colors.lightBlueAccent, - size: 14, - ), - ), - ), - ], + Avatar( + avatar: item.upic ?? '', + size: 42, + isVip: false, + officialType: item.officialVerify?['type'], + roomId: item.isLive == 1 ? item.roomId : null, ), const SizedBox(width: 10), Column( diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index 3caccbb4..154e0949 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:PiliPlus/common/widgets/avatar.dart'; import 'package:PiliPlus/common/widgets/self_sized_horizontal_list.dart'; import 'package:PiliPlus/pages/search/widgets/search_text.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; @@ -296,54 +297,22 @@ class _VideoInfoState extends State { child: Row( mainAxisSize: MainAxisSize.min, children: [ - Obx( - () => Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - type: 'avatar', - src: videoIntroController.userStat - .value['card']?['face'] ?? - '', - width: 35, - height: 35, - fadeInDuration: Duration.zero, - fadeOutDuration: Duration.zero, - ), - if ((videoIntroController.userStat - .value['card'] - ?['official_verify'] - ?['type'] ?? - -1) != - -1) - Positioned( - right: -2, - bottom: -2, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context) - .colorScheme - .surface, - ), - child: Icon( - Icons.offline_bolt, - color: videoIntroController - .userStat - .value['card'] - ?[ - 'official_verify'] - ?['type'] == - 0 - ? const Color(0xFFFFCC00) - : Colors.lightBlueAccent, - size: 14, - ), - ), - ), - ], - ), - ), + Obx(() => Avatar( + avatar: videoIntroController.userStat + .value['card']?['face'] ?? + '', + size: 35, + badgeSize: 14, + isVip: (videoIntroController.userStat + .value['card']?['vip'] + ?['status'] ?? + -1) > + 0, + officialType: videoIntroController + .userStat.value['card'] + ?['official_verify']?['type'], + // garbPendantImage: videoIntroController.userStat.value['card']?['pendant']?['image'], + )), const SizedBox(width: 10), Column( crossAxisAlignment: 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 4c9ab7fc..7b712156 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:PiliPlus/common/constants.dart'; +import 'package:PiliPlus/common/widgets/avatar.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image_view.dart'; import 'package:PiliPlus/common/widgets/report.dart'; @@ -156,93 +157,16 @@ class ReplyItemGrpc extends StatelessWidget { ); } - 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: - Utils.thumbnailImgUrl(replyItem.member.garbPendantImage), - ), - ), - ), - ] else - NetworkImgLayer( - src: replyItem.member.face, - width: 34, - height: 34, - type: 'avatar', - ), - if (replyItem.member.vipStatus > 0) - Positioned( - right: 0, - bottom: 0, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.surface, - ), - child: Image.asset( - 'assets/images/big-vip.png', - height: 14, - semanticLabel: "大会员", - ), - ), - ), - if (replyItem.member.officialVerifyType == 0) - Positioned( - left: 0, - bottom: 0, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.surface, - ), - child: const Icon( - Icons.offline_bolt, - color: Color(0xFFFFCC00), - size: 14, - semanticLabel: "认证个人", - ), - ), - ) - else if (replyItem.member.officialVerifyType == 1) - Positioned( - left: 0, - bottom: 0, - child: Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: Theme.of(context).colorScheme.surface, - ), - child: const Icon( - Icons.offline_bolt, - color: Colors.lightBlueAccent, - size: 14, - semanticLabel: "认证机构", - ), - ), - ), - ], - ); - } + Widget lfAvtar() => Avatar( + avatar: replyItem.member.face, + size: 34, + badgeSize: 14, + isVip: replyItem.member.vipStatus > 0, + officialType: replyItem.member.officialVerifyType.toInt(), + garbPendantImage: replyItem.member.hasGarbPendantImage() + ? replyItem.member.garbPendantImage + : null, + ); Widget content(BuildContext context) { return Column( @@ -259,7 +183,7 @@ class ReplyItemGrpc extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ - lfAvtar(context), + lfAvtar(), const SizedBox(width: 12), Column( crossAxisAlignment: CrossAxisAlignment.start,