import 'dart:convert'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:yumi/app_localizations.dart'; import 'package:yumi/main.dart'; import 'package:yumi/ui_kit/components/sc_debounce_widget.dart'; import 'package:yumi/ui_kit/components/text/sc_text.dart'; import 'package:yumi/shared/data_sources/sources/local/user_manager.dart'; import 'package:yumi/modules/index/main_route.dart'; import 'package:yumi/services/audio/rtm_manager.dart'; import 'package:yumi/ui_kit/widgets/room/room_msg_input.dart'; import 'package:yumi/ui_kit/widgets/room/room_user_card_setting.dart'; import 'package:yumi/ui_kit/widgets/badge/sc_user_badge_strip.dart'; import 'package:marquee/marquee.dart'; import 'package:provider/provider.dart'; import 'package:tencent_cloud_chat_sdk/models/v2_tim_conversation.dart'; import 'package:tencent_cloud_chat_sdk/enum/conversation_type.dart'; import 'package:yumi/ui_kit/components/sc_compontent.dart'; import 'package:yumi/app/routes/sc_fluro_navigator.dart'; import 'package:yumi/shared/tools/sc_lk_dialog_util.dart'; import 'package:yumi/shared/tools/sc_room_utils.dart'; import 'package:yumi/shared/data_sources/models/enum/sc_props_type.dart'; import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart'; import 'package:yumi/shared/business_logic/models/res/login_res.dart'; import 'package:yumi/shared/business_logic/models/res/room_user_card_res.dart' as room_card; import 'package:yumi/services/general/sc_app_general_manager.dart'; import 'package:yumi/services/audio/rtc_manager.dart'; import 'package:yumi/services/auth/user_profile_manager.dart'; import 'package:yumi/modules/gift/gift_page.dart'; import 'package:yumi/ui_kit/widgets/id/sc_special_id_badge.dart'; import 'package:yumi/ui_kit/widgets/props/sc_data_card_resource_view.dart'; import '../../../shared/data_sources/models/enum/sc_room_roles_type.dart'; import '../../../shared/business_logic/models/res/sc_user_identity_res.dart'; import '../../../modules/chat/chat_route.dart'; class RoomUserInfoCard extends StatefulWidget { final String? userId; const RoomUserInfoCard({super.key, this.userId}); @override State createState() => _RoomUserInfoCardState(); } class _RoomUserInfoCardState extends State { static const String _leaveMicActionIconAsset = "sc_images/room/sc_icon_room_user_card_leave_mic.png"; static const String _defaultProfileCardBackgroundAsset = "sc_images/room/sc_bg_room_user_profile_card_default.png"; static const double _profileSheetHeightFactor = 0.4; static const double _dataCardTranslateDownFactor = 0.4; static const double _defaultBackgroundImageFactor = 0.68; SocialChatUserProfileManager? userProvider; String roomId = ""; SCUserIdentityRes? userIdentity; @override void initState() { super.initState(); userProvider = Provider.of( context, listen: false, ); roomId = Provider.of( context, listen: false, ).currenRoom?.roomProfile?.roomProfile?.id ?? ""; userProvider?.roomUserCard(roomId, widget.userId ?? ""); SCAccountRepository().userIdentity(userId: widget.userId).then((v) { if (!mounted) { return; } userIdentity = v; setState(() {}); }); } @override void dispose() { super.dispose(); userProvider?.userCardInfo = null; } @override Widget build(BuildContext context) { final sheetHeight = MediaQuery.of(context).size.height * _profileSheetHeightFactor; return Consumer( builder: (context, ref, child) { final currentUserId = AccountStorage().getCurrentUser()?.userProfile?.id; final isSelf = widget.userId == currentUserId; final rtcProvider = Provider.of(context, listen: false); final currentMicIndex = isSelf && currentUserId != null ? rtcProvider.userOnMaiInIndex(currentUserId) : -1; final canLeaveMic = currentMicIndex > -1; if (ref.userCardInfo == null) { return _buildLoadingSheet(sheetHeight); } return _buildProfileSheet( context: context, ref: ref, rtcProvider: rtcProvider, sheetHeight: sheetHeight, isSelf: isSelf, currentMicIndex: currentMicIndex, canLeaveMic: canLeaveMic, currentUserId: currentUserId, ); }, ); } Widget _buildLoadingSheet(double sheetHeight) { return SizedBox( width: double.infinity, height: sheetHeight, child: ClipRRect( borderRadius: BorderRadius.vertical(top: Radius.circular(18.w)), child: Stack( children: [ Positioned.fill(child: _buildDefaultSheetBackground()), Center( child: Container( width: 55.w, height: 55.w, decoration: BoxDecoration( color: Colors.black26, borderRadius: BorderRadius.circular(8.w), ), child: CupertinoActivityIndicator(color: Colors.white24), ), ), ], ), ), ); } Widget _buildProfileSheet({ required BuildContext context, required SocialChatUserProfileManager ref, required RtcProvider rtcProvider, required double sheetHeight, required bool isSelf, required num currentMicIndex, required bool canLeaveMic, required String? currentUserId, }) { final bottomPadding = MediaQuery.of(context).padding.bottom; final profile = ref.userCardInfo?.userProfile; final dataCard = _activeDataCard(ref.userCardInfo); final canShowReport = currentUserId != widget.userId; final canShowSetting = canShowReport && ref.userCardInfo?.roomRole != SCRoomRolesType.HOMEOWNER.name && (rtcProvider.isFz() || rtcProvider.isGL()); final profileContent = _buildProfileContentLayer( context: context, ref: ref, rtcProvider: rtcProvider, profile: profile, bottomPadding: bottomPadding, isSelf: isSelf, canLeaveMic: canLeaveMic, currentMicIndex: currentMicIndex, canShowReport: canShowReport, canShowSetting: canShowSetting, ); if (dataCard == null) { return SizedBox( width: double.infinity, height: sheetHeight, child: ClipRRect( borderRadius: BorderRadius.vertical(top: Radius.circular(18.w)), child: Stack( children: [ Positioned.fill(child: _buildDefaultSheetBackground()), Positioned.fill(child: profileContent), ], ), ), ); } return _buildDataCardFrame( sheetHeight: sheetHeight, dataCard: dataCard, child: profileContent, ); } Widget _buildDataCardFrame({ required double sheetHeight, required PropsResources dataCard, required Widget child, }) { return SizedBox( width: double.infinity, height: sheetHeight, child: Stack( clipBehavior: Clip.none, children: [ Positioned.fill( child: ClipRRect( borderRadius: BorderRadius.vertical(top: Radius.circular(18.w)), child: DecoratedBox(decoration: _sheetDecoration()), ), ), Positioned( left: 0, right: 0, top: sheetHeight * _dataCardTranslateDownFactor, height: sheetHeight, child: IgnorePointer(child: _buildSheetBackground(dataCard)), ), Positioned.fill( child: ClipRRect( borderRadius: BorderRadius.vertical(top: Radius.circular(18.w)), child: child, ), ), ], ), ); } Widget _buildProfileContentLayer({ required BuildContext context, required SocialChatUserProfileManager ref, required RtcProvider rtcProvider, required SocialChatUserProfile? profile, required double bottomPadding, required bool isSelf, required bool canLeaveMic, required num currentMicIndex, required bool canShowReport, required bool canShowSetting, }) { return Stack( children: [ Positioned.fill( child: LayoutBuilder( builder: (context, constraints) { return Align( alignment: Alignment.topCenter, child: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.topCenter, child: SizedBox( width: constraints.maxWidth, child: Padding( padding: EdgeInsets.fromLTRB( 18.w, 10.w, 18.w, bottomPadding > 6.w ? bottomPadding : 6.w, ), child: Column( mainAxisSize: MainAxisSize.min, children: [ _buildProfileHeader(context, profile, ref), SizedBox(height: 6.w), _buildBadgeStrip( profile?.id ?? widget.userId, ref, profile, ), SizedBox(height: 8.w), _buildActions( context: context, ref: ref, rtcProvider: rtcProvider, isSelf: isSelf, canLeaveMic: canLeaveMic, currentMicIndex: currentMicIndex, ), ], ), ), ), ), ); }, ), ), if (canShowReport) Positioned( top: 14.w, right: 16.w, child: _buildHeaderIconButton( iconAsset: "sc_images/room/sc_icon_user_card_report.png", onTap: () { final route = "${SCMainRoute.report}?type=user&tageId=${widget.userId}"; Navigator.of(context).pop(); SCNavigatorUtils.push( navigatorKey.currentState?.context ?? context, route, replace: false, ); }, ), ), if (canShowSetting) Positioned( top: 14.w, right: 52.w, child: _buildHeaderIconButton( iconAsset: "sc_images/room/sc_icon_room_user_card_setting.png", onTap: () { if (userProvider?.userCardInfo == null) { return; } Navigator.of(context).pop(); showBottomInBottomDialog( navigatorKey.currentState?.context ?? context, RoomUserCardSetting( roomId: roomId, userCardInfo: userProvider?.userCardInfo?.copyWith(), ), ); }, ), ), ], ); } BoxDecoration _sheetDecoration() { return const BoxDecoration(color: Color(0xff061F1E)); } Widget _buildDefaultSheetBackground() { return DecoratedBox( decoration: _sheetDecoration(), child: Center( child: FractionallySizedBox( widthFactor: _defaultBackgroundImageFactor, heightFactor: _defaultBackgroundImageFactor, child: Image.asset( _defaultProfileCardBackgroundAsset, fit: BoxFit.contain, ), ), ), ); } Widget _buildSheetBackground(PropsResources? dataCard) { if (dataCard == null) { return _buildDefaultSheetBackground(); } return SCDataCardResourceView( resource: dataCard, fit: BoxFit.cover, showCoverFallback: false, allowCoverAsResource: false, ); } PropsResources? _activeDataCard(room_card.RoomUserCardRes? cardInfo) { return _activeDataCardFromUseProps(cardInfo?.userProfile?.useProps) ?? _activeDataCardFromUseProps(cardInfo?.useProps); } PropsResources? _activeDataCardFromUseProps(List? useProps) { final now = DateTime.now().millisecondsSinceEpoch; for (final item in useProps ?? const []) { final resource = item.propsResources; if (resource?.type != SCPropsType.DATA_CARD.name) { continue; } final expireText = item.expireTime?.trim() ?? ""; final expireTime = int.tryParse(expireText); if (expireText.isNotEmpty && (expireTime ?? 0) <= now) { continue; } final source = resource?.sourceUrl?.trim() ?? ""; final cover = resource?.cover?.trim() ?? ""; if (source.isNotEmpty || cover.isNotEmpty) { return resource; } } return null; } Widget _buildProfileHeader( BuildContext context, SocialChatUserProfile? profile, SocialChatUserProfileManager ref, ) { return Column( children: [ GestureDetector( onTap: () => _openProfile(context), child: head( url: profile?.userAvatar ?? "", width: 105.w, border: Border.all(color: Colors.white, width: 3), headdress: profile?.getHeaddress()?.sourceUrl, headdressCover: profile?.getHeaddress()?.cover, ), ), SizedBox(height: 5.w), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ msgRoleTag( ref.userCardInfo?.roomRole ?? "", width: 16.w, height: 16.w, ), SizedBox(width: 4.w), socialchatNickNameText( maxWidth: 116.w, profile?.userNickname ?? "", fontSize: 18.sp, textColor: Colors.white, fontWeight: FontWeight.bold, type: "", needScroll: (profile?.userNickname?.characters.length ?? 0) > 12, ), SizedBox(width: 3.w), getVIPBadge( profile?.vipLevel ?? profile?.getVIP()?.name, width: 45.w, height: 25.w, ), SizedBox(width: 3.w), getWealthLevel( profile?.wealthLevel ?? ref.userCardInfo?.userLevel?.wealthLevel ?? 0, width: 42.w, height: 20.w, fontSize: 9.sp, ), SizedBox(width: 2.w), getUserLevel( profile?.charmLevel ?? ref.userCardInfo?.userLevel?.charmLevel ?? 0, width: 42.w, height: 20.w, fontSize: 9.sp, ), ], ), SizedBox(height: 2.w), _buildSpecialIdMetaRow(context, profile), ], ); } Widget _buildSpecialIdMetaRow( BuildContext context, SocialChatUserProfile? profile, ) { final flagUrl = _countryFlagUrl(context, profile); final hasSex = profile?.userSex != null; return Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ SCSpecialIdBadge( idText: profile?.getID() ?? "", showAnimated: profile?.hasSpecialId() ?? false, assetPath: SCSpecialIdAssets.userId, animationWidth: 62.w, animationHeight: 24.w, showTextBesideAnimated: true, animatedTextSpacing: 0, showAnimatedGradientText: profile?.shouldShowColoredSpecialIdText() ?? false, animationTextStyle: TextStyle( color: Colors.white, fontSize: 12.sp, fontWeight: FontWeight.bold, ), normalTextStyle: TextStyle( color: Colors.white, fontSize: 12.sp, fontWeight: FontWeight.bold, ), animationFit: BoxFit.contain, ), if (flagUrl.isNotEmpty) ...[ SizedBox(width: 8.w), _buildCountryFlag(flagUrl), ], if (hasSex) ...[SizedBox(width: 7.w), _buildSexIcon(profile)], ], ); } String _countryFlagUrl(BuildContext context, SocialChatUserProfile? profile) { final countryName = profile?.countryName ?? ""; try { return Provider.of( context, listen: false, ).findCountryByName(countryName)?.nationalFlag ?? ""; } catch (_) { return ""; } } Widget _buildCountryFlag(String flagUrl) { final trimmedUrl = flagUrl.trim(); if (trimmedUrl.isEmpty) { return const SizedBox.shrink(); } return ClipRRect( borderRadius: BorderRadius.circular(2.w), child: netImage( url: trimmedUrl, width: 22.w, height: 15.w, fit: BoxFit.cover, noDefaultImg: true, ), ); } Widget _buildSexIcon(SocialChatUserProfile? profile) { if (profile?.userSex == null) { return const SizedBox.shrink(); } return xb(profile?.userSex, height: 15.w, color: null); } Widget _buildBadgeStrip( String? userId, SocialChatUserProfileManager ref, SocialChatUserProfile? profile, ) { return SCUserBadgeStrip( userId: userId, fallbackBadges: _roomCardFallbackBadges(ref, profile), height: 70.w, badgeHeight: 57.5.w, longBadgeWidth: 145.w, spacing: 20.w, maxBadges: 12, wrap: false, reserveSpace: true, ); } List _roomCardFallbackBadges( SocialChatUserProfileManager ref, SocialChatUserProfile? profile, ) { final wearBadges = profile?.wearBadge ?.where((item) => item.use != false && _hasBadgeUrl(item)) .toList() ?? const []; if (wearBadges.isNotEmpty) { return wearBadges; } return ref.userCardInfo?.useBadge ?.map(_roomUseBadgeToWearBadge) .where(_hasBadgeUrl) .toList() ?? const []; } WearBadge _roomUseBadgeToWearBadge(room_card.UseBadge badge) { return WearBadge( animationUrl: badge.animationUrl, badgeKey: badge.badgeKey, badgeLevel: badge.badgeLevel, badgeName: badge.badgeName, expireTime: badge.expireTime?.toInt(), id: badge.id, milestone: badge.milestone, notSelectUrl: badge.notSelectUrl, selectUrl: badge.selectUrl, type: badge.type, userId: badge.userId, use: true, ); } bool _hasBadgeUrl(WearBadge badge) { return (badge.selectUrl ?? "").trim().isNotEmpty; } Widget _buildActions({ required BuildContext context, required SocialChatUserProfileManager ref, required RtcProvider rtcProvider, required bool isSelf, required bool canLeaveMic, required num currentMicIndex, }) { if (isSelf) { if (!canLeaveMic) { return SizedBox(height: 55.w); } return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: 92.w, child: _buildSheetAction( iconAsset: _leaveMicActionIconAsset, label: SCAppLocalizations.of(context)!.leavelTheMic, onTap: () { Navigator.of(context).pop(); rtcProvider.xiaMai(currentMicIndex); }, ), ), ], ); } return Row( children: [ Expanded( child: _buildSheetAction( iconAsset: "sc_images/room/sc_icon_send_user_message.png", label: SCAppLocalizations.of(context)!.sayHi2, onTap: () => _openChat(context), ), ), Expanded(child: _buildFollowAction(context)), Expanded( child: _buildSheetAction( iconAsset: "sc_images/room/sc_icon_at_tag_user.png", label: SCAppLocalizations.of(context)!.atTag, onTap: () => _openAtInput(context, ref), ), ), Expanded( child: _buildSheetAction( iconAsset: "sc_images/room/sc_icon_send_user_gift.png", label: SCAppLocalizations.of(context)!.send, onTap: () => _openGift(context, ref), ), ), ], ); } Widget _buildSheetAction({ required String iconAsset, required String label, required VoidCallback onTap, }) { return SCDebounceWidget( onTap: onTap, child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 42.w, height: 42.w, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.58), shape: BoxShape.circle, border: Border.all( color: const Color(0xff18F2B1).withValues(alpha: 0.18), ), ), alignment: Alignment.center, child: Image.asset(iconAsset, width: 28.w, height: 28.w), ), SizedBox(height: 5.w), SizedBox( height: 31.w, child: text( label, maxLines: 2, textAlign: TextAlign.center, textColor: Colors.white, fontWeight: FontWeight.w600, fontSize: 12.sp, lineHeight: 1.1, ), ), ], ), ); } Widget _buildFollowAction(BuildContext context) { return SCDebounceWidget( onTap: () { final provider = Provider.of( context, listen: false, ); provider.followUser(widget.userId ?? ""); }, child: Selector( selector: (context, provider) => provider.userCardInfo?.follow ?? false, shouldRebuild: (prev, next) => prev != next, builder: (context, follow, _) { return Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 42.w, height: 42.w, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.58), shape: BoxShape.circle, border: Border.all( color: const Color(0xff18F2B1).withValues(alpha: 0.18), ), ), alignment: Alignment.center, child: Image.asset( follow ? "sc_images/room/sc_icon_user_un_follow.png" : "sc_images/room/sc_icon_user_follow.png", width: 28.w, height: 28.w, ), ), SizedBox(height: 5.w), SizedBox( height: 31.w, child: text( follow ? SCAppLocalizations.of(context)!.followed : SCAppLocalizations.of(context)!.follow, maxLines: 2, textAlign: TextAlign.center, textColor: Colors.white, fontWeight: FontWeight.w600, fontSize: 12.sp, lineHeight: 1.1, ), ), ], ); }, ), ); } Widget _buildHeaderIconButton({ required String iconAsset, required VoidCallback onTap, }) { return SCDebounceWidget( onTap: onTap, child: Container( width: 28.w, height: 28.w, decoration: BoxDecoration( color: Colors.white.withValues(alpha: 0.45), shape: BoxShape.circle, ), alignment: Alignment.center, child: Image.asset( iconAsset, width: 18.w, height: 18.w, color: Colors.black, ), ), ); } void _openProfile(BuildContext context) { final route = "${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == widget.userId}&tageId=${widget.userId}"; Navigator.of(context).pop(); SCNavigatorUtils.push(navigatorKey.currentState?.context ?? context, route); } Future _openChat(BuildContext context) async { final rtmProvider = Provider.of(context, listen: false); Navigator.of(context).pop(); var conversation = V2TimConversation( type: ConversationType.V2TIM_C2C, userID: widget.userId, conversationID: '', ); final didStart = await rtmProvider.startConversation(conversation); if (!didStart || !mounted) return; var json = jsonEncode(conversation.toJson()); SCNavigatorUtils.push( navigatorKey.currentState!.context, "${SCChatRouter.chat}?conversation=${Uri.encodeComponent(json)}", ); } Future _openAtInput( BuildContext context, SocialChatUserProfileManager ref, ) async { if (!SCRoomUtils.touristCanMsg(context)) { return; } final nickname = ref.userCardInfo?.userProfile?.userNickname ?? ""; if (nickname.isEmpty) { return; } Navigator.of(context).pop(); Navigator.push( navigatorKey.currentState?.context ?? context, PopRoute( child: RoomMsgInput( atTextContent: "$nickname", ), ), ); } void _openGift(BuildContext context, SocialChatUserProfileManager ref) { Navigator.of(context).pop(); SmartDialog.show( tag: "showGiftControl", alignment: Alignment.bottomCenter, maskColor: Colors.transparent, animationType: SmartAnimationType.fade, clickMaskDismiss: true, builder: (_) { return GiftPage(toUser: ref.userCardInfo?.userProfile); }, ); } String roleName(String role) { if (role == SCRoomRolesType.HOMEOWNER.name) { return SCAppLocalizations.of(context)!.owner; } else if (role == SCRoomRolesType.ADMIN.name) { return SCAppLocalizations.of(context)!.admin; } else if (role == SCRoomRolesType.MEMBER.name) { return SCAppLocalizations.of(context)!.member; } return SCAppLocalizations.of(context)!.guest; } _buildEmptyCpItem(bool canAdd) { return Container( width: ScreenUtil().screenWidth, margin: EdgeInsets.symmetric(horizontal: 12.w), height: 105.w, decoration: BoxDecoration( image: DecorationImage( image: AssetImage( canAdd ? "sc_images/person/sc_icon_no_cp_item_bg.png" : "sc_images/person/sc_icon_no_cp_item_bg4.png", ), fit: BoxFit.fill, ), ), child: Container( margin: EdgeInsets.only(bottom: 13.w), alignment: AlignmentDirectional.bottomCenter, child: text( SCAppLocalizations.of(context)!.noMatchedCP, fontWeight: FontWeight.w600, fontSize: 12.sp, textColor: canAdd ? Color(0xFFFF79A1) : Colors.white, ), ), ); } Widget _buildCpItem(CPRes item) { return Stack( alignment: AlignmentDirectional.center, children: [ Container( width: ScreenUtil().screenWidth, margin: EdgeInsets.symmetric(horizontal: 15.w), height: 135.w, decoration: BoxDecoration( image: DecorationImage( image: AssetImage("sc_images/person/sc_icon_no_cp_item_bg2.png"), fit: BoxFit.fill, ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox(height: 68.w), Container( alignment: AlignmentDirectional.bottomCenter, child: Row( mainAxisSize: MainAxisSize.min, children: [ Image.asset( "sc_images/person/sc_icon_cp_value_tag.png", height: 18.w, ), SizedBox(width: 5.w), text( _cpVaFormat(item.cpValue ?? 0), fontWeight: FontWeight.w600, fontSize: 12.sp, textColor: Color(0xFFFF79A1), ), ], ), ), SizedBox(height: 8.w), Container( alignment: AlignmentDirectional.bottomCenter, child: text( SCAppLocalizations.of( context, )!.timeSpentTogether(item.days ?? ""), fontWeight: FontWeight.w600, fontSize: 12.sp, textColor: Color(0xFFFF79A1), ), ), Container( alignment: AlignmentDirectional.bottomCenter, child: text( SCAppLocalizations.of(context)!.firstDay(item.firstDay ?? ""), fontWeight: FontWeight.w600, fontSize: 11.sp, textColor: Colors.white, ), ), ], ), ), PositionedDirectional( top: 30.w, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Column( children: [ GestureDetector( child: SizedBox( height: 50.w, child: Stack( alignment: AlignmentDirectional.center, children: [ netImage( url: item.meUserAvatar ?? "", width: 48.w, shape: BoxShape.circle, defaultImg: "sc_images/general/sc_icon_avar_defalt.png", ), Image.asset( "sc_images/person/sc_icon_cp_head_ring.png", ), ], ), ), onTap: () { SCNavigatorUtils.push( context, replace: false, "${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == item.meUserId}&tageId=${item.meUserId}", ); }, ), Container( alignment: Alignment.center, width: 80.w, height: 15.w, child: (item.meUserNickname?.length ?? 0) > 8 ? Marquee( text: item.meUserNickname ?? "", style: TextStyle( fontSize: 10.sp, color: Colors.white, fontWeight: FontWeight.w600, decoration: TextDecoration.none, ), scrollAxis: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.start, blankSpace: 20.0, velocity: 40.0, pauseAfterRound: Duration(seconds: 1), accelerationDuration: Duration(seconds: 1), accelerationCurve: Curves.easeOut, decelerationDuration: Duration(milliseconds: 550), decelerationCurve: Curves.easeOut, ) : Text( item.meUserNickname ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 10.sp, color: Colors.white, fontWeight: FontWeight.w600, decoration: TextDecoration.none, ), ), ), ], ), SizedBox(width: 120.w), Column( children: [ GestureDetector( child: SizedBox( height: 50.w, child: Stack( alignment: AlignmentDirectional.center, children: [ netImage( url: item.cpUserAvatar ?? "", width: 48.w, shape: BoxShape.circle, defaultImg: "sc_images/general/sc_icon_avar_defalt.png", ), Image.asset( "sc_images/person/sc_icon_cp_head_ring.png", ), ], ), ), onTap: () { SCNavigatorUtils.push( context, replace: false, "${SCMainRoute.person}?isMe=${AccountStorage().getCurrentUser()?.userProfile?.id == item.cpUserId}&tageId=${item.cpUserId}", ); }, ), Container( alignment: Alignment.center, width: 80.w, height: 15.w, child: (item.cpUserNickname?.length ?? 0) > 8 ? Marquee( text: item.cpUserNickname ?? "", style: TextStyle( fontSize: 10.sp, color: Colors.white, fontWeight: FontWeight.w600, decoration: TextDecoration.none, ), scrollAxis: Axis.horizontal, crossAxisAlignment: CrossAxisAlignment.start, blankSpace: 20.0, velocity: 40.0, pauseAfterRound: Duration(seconds: 1), accelerationDuration: Duration(seconds: 1), accelerationCurve: Curves.easeOut, decelerationDuration: Duration(milliseconds: 550), decelerationCurve: Curves.easeOut, ) : Text( item.cpUserNickname ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 10.sp, color: Colors.white, fontWeight: FontWeight.w600, decoration: TextDecoration.none, ), ), ), ], ), ], ), ), ], ); } String getUserCardBg() { return ""; } String _cpVaFormat(double cpValue) { int value = cpValue.toInt(); if (value > 99999) { return "${(value / 1000).toStringAsFixed(0)}k"; } return "$value"; } }