diff --git a/lib/common/widgets/avatar.dart b/lib/common/widgets/avatar.dart deleted file mode 100644 index ef7c2d96..00000000 --- a/lib/common/widgets/avatar.dart +++ /dev/null @@ -1,172 +0,0 @@ -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 String? garbPendantImage; - final dynamic roomId; - final VoidCallback? onTap; - - const Avatar({ - super.key, - required this.avatar, - this.size = 80, - 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 - : _BadgeType.institution; - - 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 (!garbPendantImage.isNullOrEmpty) - Positioned( - top: -size * 0.375, // -(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: size / 12), - decoration: BoxDecoration( - color: colorScheme.secondaryContainer, - borderRadius: BorderRadius.circular(size / 6), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - Icons.equalizer_rounded, - size: size / 3, - color: colorScheme.onSecondaryContainer, - ), - Text( - '直播中', - style: TextStyle( - height: 0.5, - fontSize: size / 6, - color: colorScheme.onSecondaryContainer, - ), - ), - ], - ), - ), - ), - ) - else if (_badgeType != _BadgeType.none) - _buildBadge(context, colorScheme), - ], - ); - } - - Widget _buildAvatar(ColorScheme colorScheme) => DecoratedBox( - decoration: BoxDecoration( - border: Border.all( - width: size / 32, - color: colorScheme.surface, - ), - shape: BoxShape.circle, - ), - child: NetworkImgLayer( - src: avatar, - width: size, - height: size, - type: 'avatar', - )); - - Widget _buildBadge(BuildContext context, ColorScheme colorScheme) { - final child = switch (_badgeType) { - _BadgeType.vip => Container( - padding: EdgeInsets.all(size / 32), - decoration: BoxDecoration( - border: Border.all( - width: size / 32, - color: colorScheme.surface, - ), - shape: BoxShape.circle, - // color: _badgeType.color, - color: context.vipColor, - ), - child: Text( - '大', - style: TextStyle( - // backgroundColor: Color(0xFFFF6699), - height: 1.1, - fontWeight: FontWeight.w900, - color: colorScheme.surface, - fontSize: size / 5, - ), - ), - ), - _ => DecoratedBox( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: colorScheme.surface, - ), - child: Icon( - Icons.offline_bolt, - color: _badgeType.color, - size: size / 3, - semanticLabel: _badgeType.desc, - ), - ), - }; - return Positioned( - right: 0, - bottom: 0, - child: IgnorePointer(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), - Colors.yellow, - Colors.lightBlueAccent - ][index]; -} diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index ed13bf8b..40699cf8 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -1,6 +1,5 @@ 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'; @@ -13,6 +12,7 @@ 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,29 +38,15 @@ class AuthorPanel extends StatelessWidget { this.onSetTop, }); - Widget _buildAvatar() => Avatar( - avatar: item.modules.moduleAuthor.face, - size: 34, - isVip: (item.modules.moduleAuthor?.vip?['status'] ?? 0) > 0, - officialType: null, // 已被注释 - garbPendantImage: item.modules.moduleAuthor?.pendant?['image'], - onTap: (item.modules.moduleAuthor.type == 'AUTHOR_TYPE_PGC' || - item.modules.moduleAuthor.type == 'AUTHOR_TYPE_UGC_SEASON') - ? null // 番剧 - : () { - feedBack(); - Get.toNamed( - '/member?mid=${item.modules.moduleAuthor.mid}', - arguments: { - 'face': item.modules.moduleAuthor.face, - }, - ); - }, + Widget _buildAvatar(double size) => NetworkImgLayer( + width: size, + height: size, + type: 'avatar', + src: item.modules.moduleAuthor.face, ); @override Widget build(BuildContext context) { - final theme = Theme.of(context); String? pubTime = item.modules.moduleAuthor.pubTs != null ? isSave ? DateTime.fromMillisecondsSinceEpoch( @@ -77,7 +63,31 @@ class AuthorPanel extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, children: [ - _buildAvatar(), + GestureDetector( + onTap: () { + // 番剧 + if (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), + ), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -90,16 +100,18 @@ class AuthorPanel extends StatelessWidget { item.modules.moduleAuthor!.vip['status'] > 0 && item.modules.moduleAuthor!.vip['type'] == 2 ? context.vipColor - : theme.colorScheme.onSurface, - fontSize: theme.textTheme.titleSmall!.fontSize, + : Theme.of(context).colorScheme.onSurface, + fontSize: + Theme.of(context).textTheme.titleSmall!.fontSize, ), ), if (pubTime != null) Text( '$pubTime${item.modules.moduleAuthor.pubAction != null ? ' ${item.modules.moduleAuthor.pubAction}' : ''}', style: TextStyle( - color: theme.colorScheme.outline, - fontSize: theme.textTheme.labelSmall!.fontSize, + color: Theme.of(context).colorScheme.outline, + fontSize: + Theme.of(context).textTheme.labelSmall!.fontSize, ), ), ], @@ -121,7 +133,7 @@ class AuthorPanel extends StatelessWidget { const BorderRadius.all(Radius.circular(4)), border: Border.all( width: 1.25, - color: theme.colorScheme.primary, + color: Theme.of(context).colorScheme.primary, ), ), child: Text( @@ -129,7 +141,7 @@ class AuthorPanel extends StatelessWidget { style: TextStyle( height: 1, fontSize: 12, - color: theme.colorScheme.primary, + color: Theme.of(context).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 901bd428..cf82019f 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -1,6 +1,7 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/page_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'; @@ -98,31 +99,53 @@ class DynamicPanel extends StatelessWidget { ); } }, - 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), - ], - ), + 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, + 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 3f359a6a..e9b64892 100644 --- a/lib/pages/member/widget/user_info_card.dart +++ b/lib/pages/member/widget/user_info_card.dart @@ -1,6 +1,7 @@ -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'; @@ -71,24 +72,24 @@ class UserInfoCard extends StatelessWidget { _buildHeader(BuildContext context) { bool darken = Theme.of(context).brightness == Brightness.dark; - String imgUrl = Utils.thumbnailImgUrl(darken - ? images.nightImgurl?.isEmpty == true - ? images.imgUrl - : images.nightImgurl - : images.imgUrl); + String? imgUrl = darken + ? (images.nightImgurl?.isEmpty == true + ? images.imgUrl?.http2https + : images.nightImgurl?.http2https) + : 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: imgUrl, + imageUrl: imgUrl?.http2https ?? '', width: double.infinity, height: 135, - imageBuilder: (context, imageProvider) => DecoratedBox( + imageBuilder: (context, imageProvider) => Container( decoration: BoxDecoration( image: DecorationImage( image: imageProvider, @@ -134,24 +135,15 @@ class UserInfoCard extends StatelessWidget { ), if (card.vip?.vipStatus == 1) ...[ const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 5), - decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(10)), - color: context.vipColor), - child: Text( - card.vip!.label!.text!, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 10, - color: Theme.of(context).colorScheme.surface), - ), + Image.network( + card.vip!.label!.image!.http2https, + height: 20, ), ], - if (card.nameplate?.imageSmall?.isNotEmpty == true) ...[ + if (card.nameplate?.image?.isNotEmpty == true) ...[ const SizedBox(width: 8), - CachedNetworkImage( - imageUrl: Utils.thumbnailImgUrl(card.nameplate!.imageSmall), + Image.network( + card.nameplate!.image!.http2https, height: 20, ), ], @@ -188,7 +180,7 @@ class UserInfoCard extends StatelessWidget { if (card.officialVerify?.desc?.isNotEmpty == true) Container( margin: const EdgeInsets.only(left: 20, top: 8, right: 20), - padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), + padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 2), decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: Theme.of(context).colorScheme.onInverseSurface, @@ -199,12 +191,16 @@ class UserInfoCard extends StatelessWidget { if (card.officialVerify?.icon?.isNotEmpty == true) ...[ WidgetSpan( alignment: PlaceholderAlignment.middle, - child: Icon( - Icons.offline_bolt, - color: card.officialVerify?.type == 0 - ? Colors.yellow - : Colors.lightBlueAccent, - size: 18, + child: DecoratedBox( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.surface, + ), + child: CachedNetworkImage( + width: 18, + height: 18, + imageUrl: card.officialVerify!.icon!.http2https, + ), ), ), TextSpan( @@ -231,7 +227,9 @@ 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( @@ -413,7 +411,8 @@ class UserInfoCard extends StatelessWidget { 0 => '关注', 1 => '悄悄关注', 2 => '已关注', - 4 || 6 => '已互关', + 4 => '互相关注', + 6 => '已互关', 128 => '移除黑名单', -10 => '特别关注', // 该状态码并不是官方状态码 _ => relation.toString(), @@ -429,20 +428,51 @@ 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: card.officialVerify!.icon!.http2https, + width: 22, + height: 22, + ) + : Image.asset( + 'assets/images/big-vip.png', + width: 22, + height: 22, + ), + ), + ); + _buildAvatar(BuildContext context) => Hero( - tag: card.face ?? '', - child: Avatar( - avatar: card.face ?? '', - size: 80, - officialType: card.officialVerify?.type, - isVip: (card.vip?.vipStatus ?? -1) > 0, - garbPendantImage: card.pendant!.image!, - roomId: live is Map && ((live['liveStatus'] as int?) ?? 0) == 1 - ? live['roomid'] - : null, - onTap: () => context - .imageView(imgList: [SourceModel(url: card.face.http2https)]), - )); + 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, + ), + ), + ), + ); _buildV(BuildContext context) => Column( mainAxisSize: MainAxisSize.min, @@ -463,6 +493,32 @@ 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( + 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, @@ -541,6 +597,39 @@ 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, @@ -558,7 +647,40 @@ class UserInfoCard extends StatelessWidget { top: 10, bottom: card.prInfo?.content?.isNotEmpty == true ? 0 : 10, ), - child: _buildAvatar(context), + 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: 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), + ), + ], + ), ), Expanded( child: Column( diff --git a/lib/pages/search_panel/user/widgets/item.dart b/lib/pages/search_panel/user/widgets/item.dart index 37d6897b..d60ffc4b 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/avatar.dart'; +import 'package:PiliPlus/common/widgets/network_img_layer.dart'; import 'package:PiliPlus/models/search/result.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart'; @@ -25,12 +25,35 @@ class SearchUserItem extends StatelessWidget { child: Row( children: [ const SizedBox(width: 15), - Avatar( - avatar: item.upic ?? '', - size: 42, - isVip: false, - officialType: item.officialVerify?['type'], - roomId: item.isLive == 1 ? item.roomId : null, + 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 + ? Colors.yellow + : Colors.lightBlueAccent, + size: 14, + ), + ), + ), + ], ), const SizedBox(width: 10), Column( diff --git a/lib/pages/video/detail/introduction/view.dart b/lib/pages/video/detail/introduction/view.dart index b187c4fc..3a99b4e4 100644 --- a/lib/pages/video/detail/introduction/view.dart +++ b/lib/pages/video/detail/introduction/view.dart @@ -1,6 +1,5 @@ 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'; @@ -312,25 +311,57 @@ class _VideoInfoState extends State { mainAxisSize: MainAxisSize.min, children: [ Obx( - () => Avatar( - avatar: videoIntroController - .userStat - .value['card']?['face'] ?? - '', - size: 35, - isVip: (videoIntroController + () => Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + type: 'avatar', + src: videoIntroController .userStat .value['card'] - ?['vip']?['status'] ?? - -1) > - 0, - officialType: videoIntroController - .userStat.value['card'] - ?['official_verify']?['type'], - garbPendantImage: - videoIntroController.userStat - .value['card'] - ?['pendant']?['image'], + ?['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 + ? Colors.yellow + : Colors + .lightBlueAccent, + size: 14, + ), + ), + ), + ], ), ), const SizedBox(width: 10), 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 bccbf63c..ed471443 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item_grpc.dart @@ -1,7 +1,6 @@ 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'; @@ -176,18 +175,96 @@ class ReplyItemGrpc extends StatelessWidget { ); } - Widget lfAvtar() => Avatar( - avatar: replyItem.member.face, - size: 34, - isVip: replyItem.member.vipStatus > 0, - officialType: replyItem.member.officialVerifyType.toInt(), - garbPendantImage: replyItem.member.hasGarbPendantImage() - ? replyItem.member.garbPendantImage - : null, - onTap: () { - feedBack(); - Get.toNamed('/member?mid=${replyItem.mid}'); - }); + 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, + bottom: 0, + child: Container( + decoration: BoxDecoration( + //borderRadius: BorderRadius.circular(7), + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.surface, + ), + child: Image.asset( + 'assets/images/big-vip.png', + height: 14, + semanticLabel: "大会员", + ), + ), + ), + //https://www.bilibili.com/blackboard/activity-whPrHsYJ2.html + if (replyItem.member.officialVerifyType == 0) + Positioned( + left: 0, + bottom: 0, + child: Container( + decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(8), + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.surface, + ), + child: const Icon( + Icons.offline_bolt, + color: Colors.yellow, + size: 14, + semanticLabel: "认证个人", + ), + ), + ) + else if (replyItem.member.officialVerifyType == 1) + Positioned( + left: 0, + bottom: 0, + child: Container( + decoration: BoxDecoration( + // borderRadius: BorderRadius.circular(8), + shape: BoxShape.circle, + color: Theme.of(context).colorScheme.surface, + ), + child: const Icon( + Icons.offline_bolt, + color: Colors.lightBlueAccent, + size: 14, + semanticLabel: "认证机构", + ), + ), + ), + ], + ); + } Widget content(BuildContext context) { return Column( @@ -195,76 +272,83 @@ class ReplyItemGrpc extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ /// fix Stack内GestureDetector onTap无效 - Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - lfAvtar(), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - replyItem.member.name, - style: TextStyle( - color: (replyItem.member.vipStatus > 0 && - replyItem.member.vipType == 2) - ? context.vipColor - : Theme.of(context).colorScheme.outline, - fontSize: 13, - ), - ), - const SizedBox(width: 6), - Image.asset( - 'assets/images/lv/lv${replyItem.member.isSeniorMember == 1 ? '6_s' : replyItem.member.level}.png', - height: 11, - semanticLabel: "等级:${replyItem.member.level}", - ), - const SizedBox(width: 6), - if (replyItem.mid == upMid) - const PBadge( - text: 'UP', - size: 'small', - stack: 'normal', - fs: 9, - ), - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - replyLevel == '' - ? DateTime.fromMillisecondsSinceEpoch( - replyItem.ctime.toInt() * 1000) - .toString() - .substring(0, 19) - : Utils.dateFormat(replyItem.ctime.toInt()), - style: TextStyle( - fontSize: - Theme.of(context).textTheme.labelSmall!.fontSize, - color: Theme.of(context).colorScheme.outline, - ), - ), - if (replyItem.replyControl.location.isNotEmpty) + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () { + feedBack(); + Get.toNamed('/member?mid=${replyItem.mid}'); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + lfAvtar(context), + const SizedBox(width: 12), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ Text( - ' • ${replyItem.replyControl.location}', + replyItem.member.name, style: TextStyle( - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize, - color: Theme.of(context).colorScheme.outline), + color: (replyItem.member.vipStatus > 0 && + replyItem.member.vipType == 2) + ? context.vipColor + : Theme.of(context).colorScheme.outline, + fontSize: 13, + ), ), - ], - ) - ], - ), - ], + const SizedBox(width: 6), + Image.asset( + 'assets/images/lv/lv${replyItem.member.isSeniorMember == 1 ? '6_s' : replyItem.member.level}.png', + height: 11, + semanticLabel: "等级:${replyItem.member.level}", + ), + const SizedBox(width: 6), + if (replyItem.mid == upMid) + const PBadge( + text: 'UP', + size: 'small', + stack: 'normal', + fs: 9, + ), + ], + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + replyLevel == '' + ? DateTime.fromMillisecondsSinceEpoch( + replyItem.ctime.toInt() * 1000) + .toString() + .substring(0, 19) + : Utils.dateFormat(replyItem.ctime.toInt()), + style: TextStyle( + fontSize: + Theme.of(context).textTheme.labelSmall!.fontSize, + color: Theme.of(context).colorScheme.outline, + ), + ), + if (replyItem.replyControl.location.isNotEmpty) + Text( + ' • ${replyItem.replyControl.location}', + style: TextStyle( + fontSize: Theme.of(context) + .textTheme + .labelSmall! + .fontSize, + color: Theme.of(context).colorScheme.outline), + ), + ], + ) + ], + ), + ], + ), ), // title Padding(