// invite_page.dart — 邀请好友(占位屏) // // TODO(spec-2): 邀请码/链接由后端签发,奖励进度来自 /v1/invite。当前码/链接/奖励进度 // 均为静态占位,仅供 IA 走查——接后端前不接任何真实业务逻辑。 import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../l10n/app_text.dart'; import '../pangolin_theme.dart'; import '../widgets/pangolin_icons.dart'; const String _kDemoInviteCode = 'PANGOLIN-DEMO'; const String _kDemoInviteLink = 'https://pangolin.app/i/PANGOLIN-DEMO'; class InviteScreen extends ConsumerWidget { const InviteScreen({super.key, required this.t, this.onBack, this.embedded = false}); final AppText t; final VoidCallback? onBack; final bool embedded; Future _copy(BuildContext context, String text, String toastLabel) async { await Clipboard.setData(ClipboardData(text: text)); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text(toastLabel), behavior: SnackBarBehavior.floating, duration: const Duration(milliseconds: 1400), )); } } @override Widget build(BuildContext context, WidgetRef ref) { final c = context.pangolin; Widget body = ListView( padding: const EdgeInsets.fromLTRB(20, 4, 20, 24), children: [ _CopyCard( icon: PangolinIcons.gift, label: t.inviteCodeLabel, value: _kDemoInviteCode, mono: true, copyLabel: t.inviteCopyCode, onCopy: () => _copy(context, _kDemoInviteCode, t.copied), ), const SizedBox(height: 14), _CopyCard( icon: PangolinIcons.link, label: t.inviteLinkLabel, value: _kDemoInviteLink, mono: false, copyLabel: t.inviteCopyLink, onCopy: () => _copy(context, _kDemoInviteLink, t.copied), ), const SizedBox(height: 20), Padding( padding: const EdgeInsets.fromLTRB(2, 0, 2, 10), child: Text(t.inviteRewardsTitle, style: PangolinText.sm.copyWith(color: c.fg2, fontWeight: FontWeight.w700, fontSize: 13)), ), Container( decoration: BoxDecoration( color: c.surface, borderRadius: BorderRadius.circular(PangolinRadius.lg), border: Border.all(color: c.border), boxShadow: PangolinShadow.sm, ), clipBehavior: Clip.antiAlias, child: Column(children: [ _RewardRow(icon: PangolinIcons.users, text: t.inviteRewardRegister), Divider(height: 1, color: c.border), _RewardRow(icon: PangolinIcons.crown, text: t.inviteRewardFirstBuy), Divider(height: 1, color: c.border), _RewardRow(icon: PangolinIcons.messageCircle, text: t.inviteRewardJoinTg), ]), ), const SizedBox(height: 20), Padding( padding: const EdgeInsets.fromLTRB(2, 0, 2, 10), child: Text(t.inviteProgressTitle, style: PangolinText.sm.copyWith(color: c.fg2, fontWeight: FontWeight.w700, fontSize: 13)), ), Container( width: double.infinity, padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: c.surface, borderRadius: BorderRadius.circular(PangolinRadius.lg), border: Border.all(color: c.border), boxShadow: PangolinShadow.sm, ), child: Column(children: [ Icon(PangolinIcons.gift, size: 26, color: c.fg3), const SizedBox(height: 10), Text('—', style: PangolinText.body.copyWith(color: c.fg3)), ]), ), ], ); if (embedded) return body; return Scaffold( backgroundColor: c.bg, body: SafeArea( child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.fromLTRB(8, 6, 16, 10), child: Row(children: [ IconButton( onPressed: onBack ?? () => Navigator.of(context).maybePop(), icon: Icon(PangolinIcons.arrowLeft, size: 22, color: c.fg1), ), Text(t.inviteTitle, style: PangolinText.h3.copyWith(color: c.fg1, fontWeight: FontWeight.w700)), ]), ), Expanded(child: body), ]), ), ); } } class _CopyCard extends StatelessWidget { const _CopyCard({ required this.icon, required this.label, required this.value, required this.mono, required this.copyLabel, required this.onCopy, }); final IconData icon; final String label; final String value; final bool mono; final String copyLabel; final VoidCallback onCopy; @override Widget build(BuildContext context) { final c = context.pangolin; return Container( padding: const EdgeInsets.all(18), decoration: BoxDecoration( color: c.surface, borderRadius: BorderRadius.circular(PangolinRadius.xl), border: Border.all(color: c.border), boxShadow: PangolinShadow.sm, ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: [ Container( width: 32, height: 32, decoration: BoxDecoration(color: c.accentSubtle, borderRadius: BorderRadius.circular(PangolinRadius.sm)), child: Icon(icon, size: 17, color: c.accent), ), const SizedBox(width: 10), Text(label, style: PangolinText.sm.copyWith(color: c.fg2, fontWeight: FontWeight.w700, fontSize: 13.5)), ]), const SizedBox(height: 12), Row(children: [ Expanded( child: Text(value, overflow: TextOverflow.ellipsis, style: mono ? PangolinText.mono.copyWith(color: c.fg1, fontWeight: FontWeight.w700, letterSpacing: 1.2, fontSize: 15) : PangolinText.sm.copyWith(color: c.fg1, fontWeight: FontWeight.w600)), ), const SizedBox(width: 10), OutlinedButton.icon( onPressed: onCopy, style: OutlinedButton.styleFrom( foregroundColor: c.accent, side: BorderSide(color: c.accentBorder), shape: const StadiumBorder(), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 8), ), icon: Icon(PangolinIcons.copy, size: 15), label: Text(copyLabel, style: PangolinText.caption.copyWith(fontWeight: FontWeight.w700, fontSize: 12.5)), ), ]), ]), ); } } class _RewardRow extends StatelessWidget { const _RewardRow({required this.icon, required this.text}); final IconData icon; final String text; @override Widget build(BuildContext context) { final c = context.pangolin; return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13), child: Row(children: [ Container( width: 32, height: 32, decoration: BoxDecoration(color: c.accentSubtle, borderRadius: BorderRadius.circular(PangolinRadius.sm)), child: Icon(icon, size: 17, color: c.accent), ), const SizedBox(width: 13), Expanded(child: Text(text, style: PangolinText.sm.copyWith(color: c.fg1, fontWeight: FontWeight.w500, fontSize: 14.5))), ]), ); } }