import 'package:flutter/material.dart'; import 'package:share_plus/share_plus.dart'; import '../../../core/format.dart'; import '../../../core/theme/tokens.dart'; import '../../../core/ui/app_icons.dart'; import '../my_data.dart'; import 'my_cards.dart'; import '../../../core/i18n/app_locale.dart'; import '../../../core/ui/clipboard_copy.dart'; import '../../campaign/campaign_share.dart' show shareHashtags; /// 프로필 카드 오버레이 — 시안 `374:15738`(명세 `549:22058`). /// /// 닫기 · 프로필 사진 80 · 닉네임 · 티어 카드 · 통계 카드 · 공유 4종(36 원형 아이콘). /// *인스타 공유 · 틱톡 공유 · X 공유 · 링크 복사* class ProfileCard extends StatelessWidget { const ProfileCard({super.key, required this.profile, required this.onShare}); final MyProfile profile; final void Function(String target) onShare; /// 공유 대상과 시안 아이콘. 명세가 적은 순서 그대로다. /// 프로필 웹 주소가 아직 없어 마지막 칸은 「링크 복사」가 아니라 「문구 복사」다. static List get shareTargets => [ appL10n.shareInstagram, appL10n.shareTiktok, 'X', appL10n.shareCopyText, ]; static const _shareIcons = [ 'assets/figma/share-instagram.png', 'assets/figma/share-tiktok.png', 'assets/figma/share-x.png', 'assets/figma/share-link.png', ]; ImageProvider get _photo { final url = profile.photoUrl; return url == null || url.isEmpty ? const AssetImage('assets/figma/avatar-sample.png') : NetworkImage(url); } @override Widget build(BuildContext context) => Padding( padding: const EdgeInsets.fromLTRB(16, 20, 16, 28), child: Column( mainAxisSize: MainAxisSize.min, children: [ Align( alignment: Alignment.centerRight, child: IconButton( tooltip: context.l10n.commonClose, onPressed: () => Navigator.of(context).maybePop(), padding: EdgeInsets.zero, constraints: const BoxConstraints.tightFor(width: 24, height: 24), icon: const ImageIcon( AppIcons.x, size: 24, color: AppColors.onCosmic, ), ), ), const SizedBox(height: 24), CircleAvatar( radius: 40, backgroundColor: AppColors.cosmicSurfaceRaised, backgroundImage: _photo, ), const SizedBox(height: 20), Text(profile.nickname, style: myText(20, FontWeight.w600)), const SizedBox(height: 24), MyTierCard(profile: profile), const SizedBox(height: 19), MyStatsCard(profile: profile), const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ for (final (i, target) in shareTargets.indexed) ...[ if (i > 0) const SizedBox(width: 16), Semantics( button: true, label: target, child: Tooltip( message: target, child: GestureDetector( onTap: () => onShare(target), child: ClipOval( child: Container( width: 36, height: 36, color: Colors.black, alignment: Alignment.center, child: Image.asset( _shareIcons[i], // X 원본은 21 짜리 글리프라 검정 원 안에 그대로 둔다. width: i == 2 ? 21 : 36, height: i == 2 ? 21 : 36, ), ), ), ), ), ), ], ], ), ], ), ); } /// 프로필 공유 문구 — 공유 시트와 복사가 같은 문구를 쓴다. String profileShareText(MyProfile profile, [AppLocalizations? l10n]) => [ (l10n ?? appL10n).myShareText( profile.nickname, '${profile.userLevel}', formatPop(profile.contributedPop), ), shareHashtags().join(' '), ].join('\n'); /// 프로필 카드 공유. 앱별 전용 SDK 없이 OS 공유 시트로 보내고(사용자가 그 안에서 /// 인스타 · 틱톡 · X 를 고른다), 마지막 칸은 문구를 복사한다. 복사했고 앱이 알려야 하면 true /// (Android 13+ 는 시스템이 알린다 — [copyToClipboard]). Future shareProfile( MyProfile profile, String target, { Future Function(ShareParams)? share, }) async { final text = profileShareText(profile); if (target == ProfileCard.shareTargets.last) { var announce = false; await copyToClipboard(text, () => announce = true); return announce; } await (share ?? SharePlus.instance.share)(ShareParams(text: text)); return false; }