import 'package:flutter/material.dart'; import 'package:yumi/ui_kit/widgets/svga/sc_svga_asset_widget.dart'; class SCSpecialIdAssets { static const String roomId = 'sc_images/general/room_id.svga'; static const String roomOwnerId = 'sc_images/general/room_id_custom.svga'; static const String userId = 'sc_images/general/user_id.svga'; static const String userIdLarge = 'sc_images/general/user_id_4.svga'; } const LinearGradient _scSpecialIdVipTextGradient = LinearGradient( begin: Alignment.centerLeft, end: Alignment.centerRight, colors: [ Color(0xFFFFD24D), Color(0xFFFF7A4D), Color(0xFFFF4FB3), Color(0xFF8E63FF), Color(0xFF38D6FF), ], ); class SCSpecialIdBadge extends StatelessWidget { const SCSpecialIdBadge({ super.key, required this.idText, this.showAnimated = false, this.assetPath, this.animationWidth = 120, this.animationHeight = 28, this.textPadding = EdgeInsets.zero, this.showTextWhenAnimated = false, this.showTextBesideAnimated = false, this.animatedTextSpacing = 0, this.animatedTextPrefix = '', this.animationTextStyle, this.normalTextStyle, this.normalPrefix = 'ID:', this.showCopyIcon = false, this.showCopyIconWhenAnimated = false, this.copyIconAssetPath = 'sc_images/room/sc_icon_user_card_copy_id.png', this.copyIconSize = 12, this.copyIconSpacing = 5, this.copyIconColor, this.loop = true, this.active = true, this.animationFit = BoxFit.fill, this.inlineAnimationWidth, this.showAnimatedGradientText = false, this.animatedTextGradient, }); final String idText; final bool showAnimated; final String? assetPath; final double animationWidth; final double animationHeight; final EdgeInsetsGeometry textPadding; final bool showTextWhenAnimated; final bool showTextBesideAnimated; final double animatedTextSpacing; final String animatedTextPrefix; final TextStyle? animationTextStyle; final TextStyle? normalTextStyle; final String normalPrefix; final bool showCopyIcon; final bool showCopyIconWhenAnimated; final String copyIconAssetPath; final double copyIconSize; final double copyIconSpacing; final Color? copyIconColor; final bool loop; final bool active; final BoxFit animationFit; final double? inlineAnimationWidth; final bool showAnimatedGradientText; final Gradient? animatedTextGradient; @override Widget build(BuildContext context) { final normalizedId = idText.trim(); final shouldAnimate = showAnimated && (assetPath?.isNotEmpty ?? false) && normalizedId.isNotEmpty; final children = [ shouldAnimate ? (showTextWhenAnimated ? _buildAnimatedBadge(normalizedId) : (showTextBesideAnimated ? _buildAnimatedInlineBadge(normalizedId) : _buildAnimatedAsset())) : _buildPlainBadge(normalizedId), ]; if (showCopyIcon && (!shouldAnimate || showCopyIconWhenAnimated)) { children.add(SizedBox(width: copyIconSpacing)); children.add( Image.asset( copyIconAssetPath, width: copyIconSize, height: copyIconSize, color: copyIconColor, ), ); } return Row( mainAxisSize: MainAxisSize.min, textDirection: TextDirection.ltr, children: children, ); } Widget _buildAnimatedAsset() { return SizedBox( width: animationWidth, height: animationHeight, child: SCSvgaAssetWidget( assetPath: assetPath!, width: animationWidth, height: animationHeight, active: active, loop: loop, fit: animationFit, fallback: const SizedBox.shrink(), ), ); } Widget _buildAnimatedInlineBadge(String normalizedId) { final compactAnimationWidth = inlineAnimationWidth ?? animationHeight; return Row( mainAxisSize: MainAxisSize.min, children: [ SizedBox( width: compactAnimationWidth, height: animationHeight, child: SCSvgaAssetWidget( assetPath: assetPath!, width: compactAnimationWidth, height: animationHeight, active: active, loop: loop, fit: animationFit, fallback: const SizedBox.shrink(), ), ), SizedBox(width: animatedTextSpacing), _buildGradientAwareText('$animatedTextPrefix$normalizedId'), ], ); } Widget _buildGradientAwareText( String text, { TextStyle? styleOverride, TextOverflow overflow = TextOverflow.ellipsis, }) { final style = styleOverride ?? animationTextStyle ?? const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w700, ); if (!showAnimatedGradientText) { return Text(text, maxLines: 1, overflow: overflow, style: style); } return ShaderMask( blendMode: BlendMode.srcIn, shaderCallback: (bounds) { final shaderBounds = Rect.fromLTWH( 0, 0, bounds.width <= 0 ? 1 : bounds.width, bounds.height <= 0 ? 1 : bounds.height, ); return (animatedTextGradient ?? _scSpecialIdVipTextGradient) .createShader(shaderBounds); }, child: Text( text, maxLines: 1, overflow: overflow, style: style.copyWith(color: Colors.white), ), ); } Widget _buildAnimatedBadge(String normalizedId) { return SizedBox( width: animationWidth, height: animationHeight, child: Stack( clipBehavior: Clip.none, children: [ Positioned.fill( child: SCSvgaAssetWidget( assetPath: assetPath!, width: animationWidth, height: animationHeight, active: active, loop: loop, fit: animationFit, fallback: const SizedBox.shrink(), ), ), Positioned.fill( child: Padding( padding: textPadding, child: Align( alignment: Alignment.centerLeft, child: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerLeft, child: _buildGradientAwareText( normalizedId, overflow: TextOverflow.visible, ), ), ), ), ), ], ), ); } Widget _buildPlainBadge(String normalizedId) { return _buildGradientAwareText( '$normalPrefix$normalizedId', styleOverride: normalTextStyle ?? const TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.w600, ), ); } }