feat(mobile): implement invite friends share page with APK QR code & referral marketing
- SharePage: QR code now encodes actual APK download URL from admin-service
(GET /api/v1/app/version/download/{id} via Kong), referral code shown
separately below QR for manual entry on registration
- Add referral reward marketing section: direct bonus / team levels (50
layers) / new user welcome package — drives viral growth
- Show referrer info card when current user was invited via referral code
- Share text updated to marketing copy with APK link + referral code
- VersionChecker.getLatestApkUrl(): fetches latest APK URL regardless of
needUpdate (passes version=0.0.0 to force server response)
- UpdateService.getLatestApkUrl(): exposes APK URL fetch for UI layer
- i18n (zh-CN/zh-TW/en/ja): add 14 new keys for marketing content,
APK download hints, reward program descriptions, and referrer info
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
192bc476c4
commit
9bcb1f864d
|
|
@ -811,6 +811,19 @@ const Map<String, String> en = {
|
||||||
'share.retry': 'Retry',
|
'share.retry': 'Retry',
|
||||||
'share.inviteBanner': 'Invite Friends',
|
'share.inviteBanner': 'Invite Friends',
|
||||||
'share.inviteBannerSub': 'Earn rewards for every referral',
|
'share.inviteBannerSub': 'Earn rewards for every referral',
|
||||||
|
'share.scanToDownload': 'Scan to Download Genex App',
|
||||||
|
'share.apkUrlLoading': 'Fetching download link...',
|
||||||
|
'share.rewardPlanTitle': 'Referral Reward Program',
|
||||||
|
'share.rewardDirect': 'Direct Referral Bonus',
|
||||||
|
'share.rewardDirectDesc': 'Earn a reward for each friend who successfully registers',
|
||||||
|
'share.rewardTeam': 'Team Level Earnings',
|
||||||
|
'share.rewardTeamDesc': 'Earn from multi-level team performance, up to 50 referral levels',
|
||||||
|
'share.rewardNewbie': 'New User Exclusive Perks',
|
||||||
|
'share.rewardNewbieDesc': 'Friends who register with your code receive an exclusive welcome package',
|
||||||
|
'share.myReferrer': 'My Referrer',
|
||||||
|
'share.noReferrer': 'No referrer',
|
||||||
|
'share.joinWith': 'Use my referral code {code} to register on Genex. Scan to download:',
|
||||||
|
'share.shareTextApk': '[Genex Invite] {name} invites you to the digital coupon finance platform!\nSign up with referral code {code} and get exclusive new user rewards.\n📱 Scan or tap to download the App: {link}',
|
||||||
|
|
||||||
// ============ Notification ============
|
// ============ Notification ============
|
||||||
'notification.system': 'System',
|
'notification.system': 'System',
|
||||||
|
|
|
||||||
|
|
@ -812,6 +812,19 @@ const Map<String, String> ja = {
|
||||||
'share.retry': '再試行',
|
'share.retry': '再試行',
|
||||||
'share.inviteBanner': '友達を招待',
|
'share.inviteBanner': '友達を招待',
|
||||||
'share.inviteBannerSub': '友達を招待してポイントをゲット',
|
'share.inviteBannerSub': '友達を招待してポイントをゲット',
|
||||||
|
'share.scanToDownload': 'スキャンしてGenex Appをダウンロード',
|
||||||
|
'share.apkUrlLoading': 'ダウンロードリンクを取得中...',
|
||||||
|
'share.rewardPlanTitle': '紹介報酬プログラム',
|
||||||
|
'share.rewardDirect': '直接紹介ボーナス',
|
||||||
|
'share.rewardDirectDesc': '友達の登録成功ごとに紹介報酬を獲得',
|
||||||
|
'share.rewardTeam': 'チームレベル収益',
|
||||||
|
'share.rewardTeamDesc': '最大50レベルのチーム紹介チェーンで収益獲得',
|
||||||
|
'share.rewardNewbie': '新規ユーザー限定特典',
|
||||||
|
'share.rewardNewbieDesc': '紹介コードで登録した友達は新規ウェルカムパッケージを受け取れます',
|
||||||
|
'share.myReferrer': '紹介者',
|
||||||
|
'share.noReferrer': '紹介者なし',
|
||||||
|
'share.joinWith': '紹介コード {code} でGenexに登録。スキャンしてダウンロード:',
|
||||||
|
'share.shareTextApk': '【Genexへのご招待】{name}さんがデジタルクーポン金融プラットフォームに招待しています!\n紹介コード {code} で登録すると新規特典がもらえます。\n📱 スキャンまたはタップしてダウンロード:{link}',
|
||||||
|
|
||||||
// ============ Notification ============
|
// ============ Notification ============
|
||||||
'notification.system': 'システム',
|
'notification.system': 'システム',
|
||||||
|
|
|
||||||
|
|
@ -812,6 +812,19 @@ const Map<String, String> zhCN = {
|
||||||
'share.retry': '重试',
|
'share.retry': '重试',
|
||||||
'share.inviteBanner': '邀请好友',
|
'share.inviteBanner': '邀请好友',
|
||||||
'share.inviteBannerSub': '推荐好友注册,双方均享福利',
|
'share.inviteBannerSub': '推荐好友注册,双方均享福利',
|
||||||
|
'share.scanToDownload': '扫码下载 Genex App',
|
||||||
|
'share.apkUrlLoading': '正在获取下载链接...',
|
||||||
|
'share.rewardPlanTitle': '推荐奖励计划',
|
||||||
|
'share.rewardDirect': '直接推荐奖励',
|
||||||
|
'share.rewardDirectDesc': '每成功邀请一位好友注册,立即获得推荐奖励',
|
||||||
|
'share.rewardTeam': '团队层级收益',
|
||||||
|
'share.rewardTeamDesc': '多层团队业绩奖励,最高可追溯 50 层关系链',
|
||||||
|
'share.rewardNewbie': '新人专属福利',
|
||||||
|
'share.rewardNewbieDesc': '通过推荐码注册的用户可获得新人专属礼包',
|
||||||
|
'share.myReferrer': '我的推荐人',
|
||||||
|
'share.noReferrer': '暂无推荐人',
|
||||||
|
'share.joinWith': '使用我的推荐码 {code} 注册 Genex,扫码立即下载:',
|
||||||
|
'share.shareTextApk': '【Genex 邀请】{name} 邀请你加入数字券金融平台!\n使用推荐码 {code} 注册,即享新人专属福利。\n📱 扫码或点击下载 App:{link}',
|
||||||
|
|
||||||
// ============ Notification ============
|
// ============ Notification ============
|
||||||
'notification.system': '系统通知',
|
'notification.system': '系统通知',
|
||||||
|
|
|
||||||
|
|
@ -812,6 +812,19 @@ const Map<String, String> zhTW = {
|
||||||
'share.retry': '重試',
|
'share.retry': '重試',
|
||||||
'share.inviteBanner': '邀請好友',
|
'share.inviteBanner': '邀請好友',
|
||||||
'share.inviteBannerSub': '推薦好友註冊,雙方均享福利',
|
'share.inviteBannerSub': '推薦好友註冊,雙方均享福利',
|
||||||
|
'share.scanToDownload': '掃碼下載 Genex App',
|
||||||
|
'share.apkUrlLoading': '正在獲取下載連結...',
|
||||||
|
'share.rewardPlanTitle': '推薦獎勵計劃',
|
||||||
|
'share.rewardDirect': '直接推薦獎勵',
|
||||||
|
'share.rewardDirectDesc': '每成功邀請一位好友註冊,立即獲得推薦獎勵',
|
||||||
|
'share.rewardTeam': '團隊層級收益',
|
||||||
|
'share.rewardTeamDesc': '多層團隊業績獎勵,最高可追溯 50 層關係鏈',
|
||||||
|
'share.rewardNewbie': '新人專屬福利',
|
||||||
|
'share.rewardNewbieDesc': '透過推薦碼註冊的用戶可獲得新人專屬禮包',
|
||||||
|
'share.myReferrer': '我的推薦人',
|
||||||
|
'share.noReferrer': '暫無推薦人',
|
||||||
|
'share.joinWith': '使用我的推薦碼 {code} 註冊 Genex,掃碼立即下載:',
|
||||||
|
'share.shareTextApk': '【Genex 邀請】{name} 邀請你加入數位券金融平台!\n使用推薦碼 {code} 註冊,即享新人專屬福利。\n📱 掃碼或點擊下載 App:{link}',
|
||||||
|
|
||||||
// ============ Notification ============
|
// ============ Notification ============
|
||||||
'notification.system': '系統通知',
|
'notification.system': '系統通知',
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,15 @@ class UpdateService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 获取最新 Android APK 直接下载链接(用于分享页二维码)
|
||||||
|
///
|
||||||
|
/// 通过传入 version=0.0.0 强制服务端返回最新版本信息并提取 downloadUrl。
|
||||||
|
/// 仅在 Android + selfHosted 渠道有效;其他情况返回 null。
|
||||||
|
Future<String?> getLatestApkUrl() async {
|
||||||
|
if (!_isInitialized || _config.channel != UpdateChannel.selfHosted) return null;
|
||||||
|
return await _selfHostedUpdater?.versionChecker.getLatestApkUrl();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> manualCheckUpdate(BuildContext context) async {
|
Future<void> manualCheckUpdate(BuildContext context) async {
|
||||||
if (!_isInitialized) return;
|
if (!_isInitialized) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,37 @@ class VersionChecker {
|
||||||
return latestInfo?.forceUpdate ?? false;
|
return latestInfo?.forceUpdate ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 获取最新 APK 的直接下载链接(忽略 needUpdate,用于分享页二维码)
|
||||||
|
///
|
||||||
|
/// 通过传入 version=0.0.0 强制服务端返回最新版本信息。
|
||||||
|
/// 仅适用于 Android 渠道;iOS 无独立 APK,返回 null。
|
||||||
|
Future<String?> getLatestApkUrl() async {
|
||||||
|
if (!Platform.isAndroid) return null;
|
||||||
|
try {
|
||||||
|
final response = await _dio.get(
|
||||||
|
'/api/v1/app/version/check',
|
||||||
|
queryParameters: {
|
||||||
|
'app_type': 'GENEX_MOBILE',
|
||||||
|
'platform': 'ANDROID',
|
||||||
|
'current_version': '0.0.0',
|
||||||
|
'current_version_code': '0',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (response.statusCode == 200 && response.data != null) {
|
||||||
|
final responseMap = response.data as Map<String, dynamic>;
|
||||||
|
final data = (responseMap['data'] as Map<String, dynamic>?) ?? responseMap;
|
||||||
|
final rawUrl = data['downloadUrl'] as String? ?? '';
|
||||||
|
if (rawUrl.isEmpty) return null;
|
||||||
|
if (!rawUrl.startsWith('http')) return '$apiBaseUrl$rawUrl';
|
||||||
|
return rawUrl;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (e) {
|
||||||
|
debugPrint('[VersionChecker] 获取APK下载链接失败: $e');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 获取版本差异
|
/// 获取版本差异
|
||||||
Future<int> getVersionDiff() async {
|
Future<int> getVersionDiff() async {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -4,30 +4,25 @@
|
||||||
// 路由:/share(从 ProfilePage「邀请好友」横幅入口跳转)
|
// 路由:/share(从 ProfilePage「邀请好友」横幅入口跳转)
|
||||||
//
|
//
|
||||||
// 功能概述:
|
// 功能概述:
|
||||||
// 1. Hero Card — 紫色渐变卡片,包含:
|
// 1. Hero Card — 渐变卡片,包含:
|
||||||
// · 专属二维码(qr_flutter 生成,编码邀请落地页 URL)
|
// · 专属二维码(qr_flutter 生成,编码 APK 直接下载链接)
|
||||||
// · 推荐码胶囊(可点击一键复制)
|
// · 推荐码胶囊(可点击一键复制)
|
||||||
// 2. 邀请进度 — 显示直接推荐人数 + 团队总人数
|
// 2. 邀请进度 — 显示直接推荐人数 + 团队总人数
|
||||||
// 3. 分享操作列表 — 三种快捷方式:复制推荐码 / 复制链接 / 原生分享
|
// 3. 推荐奖励计划 — 营销区块:直接奖励 / 团队收益 / 新人福利
|
||||||
// 4. 主操作按钮 — 「分享给好友」触发系统原生分享弹层
|
// 4. 我的推荐人信息 — 若当前用户是被推荐的,显示推荐人代码
|
||||||
|
// 5. 分享操作列表 — 三种快捷方式:复制推荐码 / 复制链接 / 原生分享
|
||||||
|
// 6. 主操作按钮 — 「分享给好友」触发系统原生分享弹层
|
||||||
//
|
//
|
||||||
// 支持的分享场景(取决于用户设备安装的 App):
|
// 二维码内容:
|
||||||
// 微信 / QQ / WhatsApp / Telegram / Line / Twitter/X
|
// 后端 admin-service 上传的 APK 直接下载链接
|
||||||
// 短信 / 邮件 / AirDrop / 复制到剪贴板 / 保存至文件……
|
// 格式:https://api.gogenex.com/api/v1/app/version/download/{id}
|
||||||
|
// 扫码即可直接下载安装,推荐码通过注册时手动填写进行归因。
|
||||||
//
|
//
|
||||||
// 数据来源:
|
// 分享文案(含推荐码 + APK 链接)用于营销推广。
|
||||||
// GET /api/v1/referral/my → ReferralService.getMyInfo()
|
|
||||||
// 推荐码通过 Kafka 事件在用户注册时自动生成,首次打开此页若
|
|
||||||
// 数据尚未就绪,将显示 Loading → 加载失败 → 重试 流程。
|
|
||||||
//
|
|
||||||
// 邀请链接格式:
|
|
||||||
// https://app.gogenex.com/download?ref={referralCode}
|
|
||||||
// 落地页检测设备后分别跳转 App Store / Google Play / 浏览器下载。
|
|
||||||
// ref 参数由注册流程自动读取并预填推荐码输入框。
|
|
||||||
//
|
//
|
||||||
// 依赖包:
|
// 依赖包:
|
||||||
// qr_flutter ^4.1.0 — 本地生成二维码,无网络依赖
|
// qr_flutter ^4.1.0 — 本地生成二维码,无网络依赖
|
||||||
// share_plus ^10.0.2 — 调用系统原生分享弹层(iOS Share Sheet / Android Sharesheet)
|
// share_plus ^10.0.2 — 调用系统原生分享弹层
|
||||||
// ============================================================
|
// ============================================================
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
@ -38,23 +33,11 @@ import '../../../../app/theme/app_colors.dart';
|
||||||
import '../../../../app/theme/app_typography.dart';
|
import '../../../../app/theme/app_typography.dart';
|
||||||
import '../../../../app/theme/app_spacing.dart';
|
import '../../../../app/theme/app_spacing.dart';
|
||||||
import '../../../../core/services/referral_service.dart';
|
import '../../../../core/services/referral_service.dart';
|
||||||
|
import '../../../../core/updater/update_service.dart';
|
||||||
import '../../../../shared/widgets/genex_button.dart';
|
import '../../../../shared/widgets/genex_button.dart';
|
||||||
import '../../../../app/i18n/app_localizations.dart';
|
import '../../../../app/i18n/app_localizations.dart';
|
||||||
|
|
||||||
/// A9. 邀请好友 / 推广分享页
|
/// A9. 邀请好友 / 推广分享页
|
||||||
///
|
|
||||||
/// 页面生命周期:
|
|
||||||
/// initState → _loadInfo() → [Loading] → [Content | Error]
|
|
||||||
///
|
|
||||||
/// Widget 树概览:
|
|
||||||
/// ```
|
|
||||||
/// Scaffold
|
|
||||||
/// └── SingleChildScrollView
|
|
||||||
/// ├── _buildHeroCard() 渐变卡片:QR 码 + 推荐码
|
|
||||||
/// ├── _buildStatsCard() 邀请进度:直接推荐 | 团队人数
|
|
||||||
/// ├── _buildShareActions() 操作列表:复制码 / 复制链 / 系统分享
|
|
||||||
/// └── GenexButton 主按钮:「分享给好友」
|
|
||||||
/// ```
|
|
||||||
class SharePage extends StatefulWidget {
|
class SharePage extends StatefulWidget {
|
||||||
const SharePage({super.key});
|
const SharePage({super.key});
|
||||||
|
|
||||||
|
|
@ -65,66 +48,67 @@ class SharePage extends StatefulWidget {
|
||||||
class _SharePageState extends State<SharePage> {
|
class _SharePageState extends State<SharePage> {
|
||||||
// ── 状态 ────────────────────────────────────────────────────────────────
|
// ── 状态 ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// 从 referral-service 加载的推荐信息;加载完成前为 null
|
|
||||||
ReferralInfo? _info;
|
ReferralInfo? _info;
|
||||||
|
|
||||||
/// 正在请求后端数据
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
|
|
||||||
/// 请求失败时的错误信息(用于展示重试按钮)
|
|
||||||
String? _error;
|
String? _error;
|
||||||
|
|
||||||
// ── 常量 ────────────────────────────────────────────────────────────────
|
/// 后端 admin-service 上传的 APK 直接下载链接
|
||||||
|
/// 用于二维码内容,扫码即可直接下载安装包
|
||||||
/// App 下载落地页基础地址
|
String? _apkUrl;
|
||||||
///
|
|
||||||
/// 落地页职责:
|
|
||||||
/// 1. 检测 UA(iOS / Android / 其他)
|
|
||||||
/// 2. iOS → 跳转 App Store
|
|
||||||
/// 3. Android → 跳转 Google Play 或直接下载 APK
|
|
||||||
/// 4. 读取 `ref` 参数并存入 localStorage,注册页自动填充推荐码
|
|
||||||
static const String _baseInviteUrl = 'https://app.gogenex.com/download';
|
|
||||||
|
|
||||||
// ── 计算属性 ─────────────────────────────────────────────────────────────
|
// ── 计算属性 ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// 完整邀请链接(二维码内容 + 分享文案使用)
|
/// 二维码内容:优先用 APK 直链,fallback 用 API 域名根路径
|
||||||
///
|
String get _qrContent => _apkUrl ?? 'https://api.gogenex.com';
|
||||||
/// 已加载:https://app.gogenex.com/download?ref=GNXAB2C3
|
|
||||||
/// 未加载:https://app.gogenex.com/download
|
/// 分享用链接(APK 直链 或 fallback)
|
||||||
String get _inviteLink => _info != null
|
String get _shareLink => _apkUrl ?? 'https://api.gogenex.com';
|
||||||
? '$_baseInviteUrl?ref=${_info!.referralCode}'
|
|
||||||
: _baseInviteUrl;
|
|
||||||
|
|
||||||
// ── 生命周期 ─────────────────────────────────────────────────────────────
|
// ── 生命周期 ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_loadInfo();
|
_loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 数据加载 ─────────────────────────────────────────────────────────────
|
// ── 数据加载 ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// 从 referral-service 拉取当前用户的推荐信息
|
/// 并发加载:推荐信息 + APK 下载链接
|
||||||
///
|
Future<void> _loadData() async {
|
||||||
/// 成功:更新 [_info],隐藏 loading
|
|
||||||
/// 失败:记录 [_error],显示重试界面
|
|
||||||
Future<void> _loadInfo() async {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_loading = true;
|
_loading = true;
|
||||||
_error = null;
|
_error = null;
|
||||||
});
|
});
|
||||||
try {
|
|
||||||
final info = await ReferralService.instance.getMyInfo();
|
// 并发请求:referral 信息 + APK 下载链接
|
||||||
if (mounted) setState(() { _info = info; _loading = false; });
|
final results = await Future.wait([
|
||||||
} catch (e) {
|
ReferralService.instance.getMyInfo().then<Object?>((v) => v).catchError((e) => e),
|
||||||
if (mounted) setState(() { _error = e.toString(); _loading = false; });
|
UpdateService().getLatestApkUrl().then<Object?>((v) => v).catchError((_) => null),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
final referralResult = results[0];
|
||||||
|
final apkUrlResult = results[1];
|
||||||
|
|
||||||
|
if (referralResult is ReferralInfo) {
|
||||||
|
setState(() {
|
||||||
|
_info = referralResult;
|
||||||
|
_apkUrl = apkUrlResult as String?;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setState(() {
|
||||||
|
_error = referralResult.toString();
|
||||||
|
_apkUrl = apkUrlResult as String?;
|
||||||
|
_loading = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 用户操作 ─────────────────────────────────────────────────────────────
|
// ── 用户操作 ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// 复制成功后展示浮动 SnackBar(紫色背景 + 勾号图标)
|
|
||||||
void _showCopied(String message) {
|
void _showCopied(String message) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
|
|
@ -145,39 +129,26 @@ class _SharePageState extends State<SharePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 复制推荐码到剪贴板
|
|
||||||
///
|
|
||||||
/// 示例复制内容:GNXAB2C3
|
|
||||||
Future<void> _copyCode() async {
|
Future<void> _copyCode() async {
|
||||||
if (_info == null) return;
|
if (_info == null) return;
|
||||||
await Clipboard.setData(ClipboardData(text: _info!.referralCode));
|
await Clipboard.setData(ClipboardData(text: _info!.referralCode));
|
||||||
if (mounted) _showCopied(context.t('share.codeCopied'));
|
if (mounted) _showCopied(context.t('share.codeCopied'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 复制完整邀请链接到剪贴板
|
|
||||||
///
|
|
||||||
/// 示例:https://app.gogenex.com/download?ref=GNXAB2C3
|
|
||||||
Future<void> _copyLink() async {
|
Future<void> _copyLink() async {
|
||||||
await Clipboard.setData(ClipboardData(text: _inviteLink));
|
await Clipboard.setData(ClipboardData(text: _shareLink));
|
||||||
if (mounted) _showCopied(context.t('share.linkCopied'));
|
if (mounted) _showCopied(context.t('share.linkCopied'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 调用系统原生分享弹层
|
/// 系统原生分享:营销文案 = APK 链接 + 推荐码 + 奖励说明
|
||||||
///
|
|
||||||
/// 分享内容:多行文案(包含推荐码 + 邀请链接)
|
|
||||||
///
|
|
||||||
/// iOS → Share Sheet(AirDrop、微信、邮件、短信……)
|
|
||||||
/// Android → Sharesheet(微信、WhatsApp、Telegram……)
|
|
||||||
///
|
|
||||||
/// 分享文案模板(zh-CN):
|
|
||||||
/// 我在用 Genex 玩数字券金融!使用我的推荐码 {code} 注册,立享专属福利。
|
|
||||||
/// 下载链接:https://app.gogenex.com/download?ref={code}
|
|
||||||
Future<void> _shareNative() async {
|
Future<void> _shareNative() async {
|
||||||
final code = _info?.referralCode ?? '';
|
final code = _info?.referralCode ?? '';
|
||||||
final text = context
|
// 优先用新的营销文案模板(含 {name} 占位符),name 暂用 'Genex 用户'
|
||||||
.t('share.shareText')
|
final template = context.t('share.shareTextApk');
|
||||||
|
final text = template
|
||||||
|
.replaceAll('{name}', 'Genex 用户')
|
||||||
.replaceAll('{code}', code)
|
.replaceAll('{code}', code)
|
||||||
.replaceAll('{link}', _inviteLink);
|
.replaceAll('{link}', _shareLink);
|
||||||
await Share.share(text, subject: context.t('share.nativeShareTitle'));
|
await Share.share(text, subject: context.t('share.nativeShareTitle'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,7 +170,7 @@ class _SharePageState extends State<SharePage> {
|
||||||
),
|
),
|
||||||
body: _loading
|
body: _loading
|
||||||
? _buildLoading()
|
? _buildLoading()
|
||||||
: _error != null
|
: _error != null && _info == null
|
||||||
? _buildError()
|
? _buildError()
|
||||||
: _buildContent(),
|
: _buildContent(),
|
||||||
);
|
);
|
||||||
|
|
@ -225,7 +196,6 @@ class _SharePageState extends State<SharePage> {
|
||||||
|
|
||||||
// ── 错误态 ───────────────────────────────────────────────────────────────
|
// ── 错误态 ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/// 加载失败界面:图标 + 描述文本 + 重试按钮
|
|
||||||
Widget _buildError() {
|
Widget _buildError() {
|
||||||
return Center(
|
return Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|
@ -242,7 +212,7 @@ class _SharePageState extends State<SharePage> {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
onPressed: _loadInfo,
|
onPressed: _loadData,
|
||||||
icon: const Icon(Icons.refresh_rounded),
|
icon: const Icon(Icons.refresh_rounded),
|
||||||
label: Text(context.t('share.retry')),
|
label: Text(context.t('share.retry')),
|
||||||
style: TextButton.styleFrom(foregroundColor: AppColors.primary),
|
style: TextButton.styleFrom(foregroundColor: AppColors.primary),
|
||||||
|
|
@ -261,13 +231,19 @@ class _SharePageState extends State<SharePage> {
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
_buildHeroCard(), // QR 码 + 推荐码
|
_buildHeroCard(), // QR 码(APK 链接)+ 推荐码
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildStatsCard(), // 邀请进度统计
|
_buildStatsCard(), // 邀请进度
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildShareActions(), // 快捷操作列表
|
_buildRewardPlanCard(), // 推荐奖励计划(营销区块)
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
if (_info?.usedCode != null) ...[
|
||||||
|
_buildReferrerCard(), // 我的推荐人
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
],
|
||||||
|
_buildShareActions(), // 快捷操作
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
GenexButton( // 主操作按钮
|
GenexButton(
|
||||||
label: context.t('share.shareToFriend'),
|
label: context.t('share.shareToFriend'),
|
||||||
onPressed: _shareNative,
|
onPressed: _shareNative,
|
||||||
),
|
),
|
||||||
|
|
@ -277,18 +253,10 @@ class _SharePageState extends State<SharePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Hero Card:二维码 + 推荐码 ────────────────────────────────────────────
|
// ── Hero Card:APK 二维码 + 推荐码 ────────────────────────────────────────
|
||||||
//
|
//
|
||||||
// 视觉层次(由外到内):
|
// 二维码内容 = APK 直接下载链接(admin-service 流式返回)
|
||||||
// Container[渐变背景 + 圆角20 + 阴影]
|
// 扫码即触发 Android 下载安装,iOS 浏览器打开提示
|
||||||
// └── Column
|
|
||||||
// ├── 标题行(星形图标 + "扫码下载 Genex")
|
|
||||||
// ├── "Genex" 大字(字间距 3,FontWeight.w800)
|
|
||||||
// ├── Container[白色背景] → QrImageView(180×180,紫色点阵)
|
|
||||||
// └── 推荐码胶囊(半透明白底 + 复制按钮)
|
|
||||||
//
|
|
||||||
// QR 码内容:_inviteLink(如 https://app.gogenex.com/download?ref=GNXAB2C3)
|
|
||||||
// QR 码颜色:eye=深紫 #4834D4,module=主紫 #6C5CE7,背景=白色
|
|
||||||
|
|
||||||
Widget _buildHeroCard() {
|
Widget _buildHeroCard() {
|
||||||
return Container(
|
return Container(
|
||||||
|
|
@ -307,14 +275,14 @@ class _SharePageState extends State<SharePage> {
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 28),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 28),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// ── 顶部标题 ────────────────────────────────────────────────────
|
// ── 顶部标题 ─────────────────────────────────────────────────
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.auto_awesome_rounded, color: Colors.white60, size: 16),
|
const Icon(Icons.auto_awesome_rounded, color: Colors.white60, size: 16),
|
||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
Text(
|
Text(
|
||||||
context.t('share.scanToJoin'),
|
context.t('share.scanToDownload'),
|
||||||
style: AppTypography.bodyMedium.copyWith(color: Colors.white70),
|
style: AppTypography.bodyMedium.copyWith(color: Colors.white70),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -328,10 +296,35 @@ class _SharePageState extends State<SharePage> {
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w800,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
// ── 二维码 ──────────────────────────────────────────────────────
|
// APK 正在加载时显示提示
|
||||||
// 白色衬底卡片包裹 QrImageView,确保二维码在任何背景下均可扫描
|
if (_apkUrl == null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 8),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
height: 10,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
color: Colors.white54,
|
||||||
|
strokeWidth: 1.5,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
context.t('share.apkUrlLoading'),
|
||||||
|
style: AppTypography.caption.copyWith(color: Colors.white54),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
|
// ── 二维码(编码 APK 下载链接)────────────────────────────────
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(14),
|
padding: const EdgeInsets.all(14),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
@ -346,26 +339,23 @@ class _SharePageState extends State<SharePage> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: QrImageView(
|
child: QrImageView(
|
||||||
data: _inviteLink, // 编码完整邀请 URL
|
data: _qrContent,
|
||||||
version: QrVersions.auto, // 自动选择最小版本
|
version: QrVersions.auto,
|
||||||
size: 180,
|
size: 180,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
// 定位图案(三个角的方框)用深紫色
|
|
||||||
eyeStyle: const QrEyeStyle(
|
eyeStyle: const QrEyeStyle(
|
||||||
eyeShape: QrEyeShape.square,
|
eyeShape: QrEyeShape.square,
|
||||||
color: Color(0xFF4834D4),
|
color: Color(0xFF4834D4),
|
||||||
),
|
),
|
||||||
// 数据模块用主紫色
|
|
||||||
dataModuleStyle: const QrDataModuleStyle(
|
dataModuleStyle: const QrDataModuleStyle(
|
||||||
dataModuleShape: QrDataModuleShape.square,
|
dataModuleShape: QrDataModuleShape.square,
|
||||||
color: Color(0xFF6C5CE7),
|
color: Color(0xFF6C5CE7),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 20),
|
||||||
|
|
||||||
// ── 推荐码胶囊 ─────────────────────────────────────────────────
|
// ── 推荐码胶囊(单独展示,注册时手动填写用于归因)──────────────
|
||||||
// 点击整个胶囊即可复制,内嵌「复制推荐码」小按钮提示可交互
|
|
||||||
Text(
|
Text(
|
||||||
context.t('share.myReferralCode'),
|
context.t('share.myReferralCode'),
|
||||||
style: AppTypography.caption.copyWith(color: Colors.white60),
|
style: AppTypography.caption.copyWith(color: Colors.white60),
|
||||||
|
|
@ -376,14 +366,13 @@ class _SharePageState extends State<SharePage> {
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white.withOpacity(0.15), // 半透明白底
|
color: Colors.white.withOpacity(0.15),
|
||||||
borderRadius: BorderRadius.circular(40),
|
borderRadius: BorderRadius.circular(40),
|
||||||
border: Border.all(color: Colors.white30),
|
border: Border.all(color: Colors.white30),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
// 推荐码文字:等宽字体 + 字间距 4,视觉更清晰
|
|
||||||
Text(
|
Text(
|
||||||
_info?.referralCode ?? '------',
|
_info?.referralCode ?? '------',
|
||||||
style: AppTypography.h2.copyWith(
|
style: AppTypography.h2.copyWith(
|
||||||
|
|
@ -394,7 +383,6 @@ class _SharePageState extends State<SharePage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
// 内嵌复制提示按钮
|
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
|
@ -420,6 +408,15 @@ class _SharePageState extends State<SharePage> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// ── 说明文字 ─────────────────────────────────────────────────
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
context.t('share.joinWith')
|
||||||
|
.replaceAll('{code}', _info?.referralCode ?? ''),
|
||||||
|
style: AppTypography.caption.copyWith(color: Colors.white54),
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -427,13 +424,6 @@ class _SharePageState extends State<SharePage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 邀请进度统计卡片 ─────────────────────────────────────────────────────
|
// ── 邀请进度统计卡片 ─────────────────────────────────────────────────────
|
||||||
//
|
|
||||||
// 布局:白色圆角卡片,水平等分两格,中间细竖线分隔
|
|
||||||
// 左:直接推荐人数(Icons.people)
|
|
||||||
// 右:团队总人数(Icons.groups)
|
|
||||||
//
|
|
||||||
// 数据来源:ReferralInfo.directReferralCount / totalTeamCount
|
|
||||||
// 加载前显示 0,刷新后实时更新
|
|
||||||
|
|
||||||
Widget _buildStatsCard() {
|
Widget _buildStatsCard() {
|
||||||
return Container(
|
return Container(
|
||||||
|
|
@ -453,7 +443,6 @@ class _SharePageState extends State<SharePage> {
|
||||||
label: context.t('share.directReferrals'),
|
label: context.t('share.directReferrals'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// 分隔线
|
|
||||||
Container(width: 1, height: 44, color: AppColors.borderLight),
|
Container(width: 1, height: 44, color: AppColors.borderLight),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: _buildStatItem(
|
child: _buildStatItem(
|
||||||
|
|
@ -467,7 +456,6 @@ class _SharePageState extends State<SharePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 单个统计格:图标 + 数值 + 标签
|
|
||||||
Widget _buildStatItem({
|
Widget _buildStatItem({
|
||||||
required IconData icon,
|
required IconData icon,
|
||||||
required String value,
|
required String value,
|
||||||
|
|
@ -489,18 +477,151 @@ class _SharePageState extends State<SharePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 推荐奖励计划(营销区块)──────────────────────────────────────────────
|
||||||
|
//
|
||||||
|
// 展示推荐系统的三大核心收益,用于说服用户积极分享:
|
||||||
|
// 1. 直接推荐奖励 — 每推荐一人注册即得奖励
|
||||||
|
// 2. 团队层级收益 — 最高 50 层关系链收益
|
||||||
|
// 3. 新人专属福利 — 被推荐用户的注册礼包
|
||||||
|
|
||||||
|
Widget _buildRewardPlanCard() {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 4, bottom: 10),
|
||||||
|
child: Text(
|
||||||
|
context.t('share.rewardPlanTitle'),
|
||||||
|
style: AppTypography.labelSmall.copyWith(color: AppColors.textTertiary),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.surface,
|
||||||
|
borderRadius: AppSpacing.borderRadiusMd,
|
||||||
|
border: Border.all(color: AppColors.borderLight),
|
||||||
|
boxShadow: AppSpacing.shadowSm,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
_buildRewardItem(
|
||||||
|
icon: Icons.monetization_on_rounded,
|
||||||
|
iconBg: const Color(0xFFFFF3E0),
|
||||||
|
iconColor: const Color(0xFFFF9800),
|
||||||
|
title: context.t('share.rewardDirect'),
|
||||||
|
desc: context.t('share.rewardDirectDesc'),
|
||||||
|
),
|
||||||
|
const Divider(indent: 60, height: 1),
|
||||||
|
_buildRewardItem(
|
||||||
|
icon: Icons.account_tree_rounded,
|
||||||
|
iconBg: AppColors.infoLight,
|
||||||
|
iconColor: AppColors.info,
|
||||||
|
title: context.t('share.rewardTeam'),
|
||||||
|
desc: context.t('share.rewardTeamDesc'),
|
||||||
|
),
|
||||||
|
const Divider(indent: 60, height: 1),
|
||||||
|
_buildRewardItem(
|
||||||
|
icon: Icons.card_giftcard_rounded,
|
||||||
|
iconBg: AppColors.successLight,
|
||||||
|
iconColor: AppColors.success,
|
||||||
|
title: context.t('share.rewardNewbie'),
|
||||||
|
desc: context.t('share.rewardNewbieDesc'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildRewardItem({
|
||||||
|
required IconData icon,
|
||||||
|
required Color iconBg,
|
||||||
|
required Color iconColor,
|
||||||
|
required String title,
|
||||||
|
required String desc,
|
||||||
|
}) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 38,
|
||||||
|
height: 38,
|
||||||
|
decoration: BoxDecoration(color: iconBg, borderRadius: BorderRadius.circular(10)),
|
||||||
|
child: Icon(icon, size: 20, color: iconColor),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(title, style: AppTypography.bodyMedium.copyWith(fontWeight: FontWeight.w600)),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
desc,
|
||||||
|
style: AppTypography.caption.copyWith(color: AppColors.textSecondary),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── 我的推荐人 ───────────────────────────────────────────────────────────
|
||||||
|
//
|
||||||
|
// 仅在 _info.usedCode != null 时显示(即当前用户是通过推荐码注册的)
|
||||||
|
|
||||||
|
Widget _buildReferrerCard() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.surface,
|
||||||
|
borderRadius: AppSpacing.borderRadiusMd,
|
||||||
|
border: Border.all(color: AppColors.borderLight),
|
||||||
|
boxShadow: AppSpacing.shadowSm,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: 38,
|
||||||
|
height: 38,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.primaryContainer,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.person_add_rounded, size: 20, color: AppColors.primary),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
context.t('share.myReferrer'),
|
||||||
|
style: AppTypography.caption.copyWith(color: AppColors.textTertiary),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
_info?.usedCode ?? context.t('share.noReferrer'),
|
||||||
|
style: AppTypography.bodyMedium.copyWith(
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
letterSpacing: 1.5,
|
||||||
|
fontFamily: 'monospace',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ── 分享操作列表 ─────────────────────────────────────────────────────────
|
// ── 分享操作列表 ─────────────────────────────────────────────────────────
|
||||||
//
|
|
||||||
// 白色圆角卡片,ListTile 列表(Divider 分隔):
|
|
||||||
//
|
|
||||||
// [紫色图标] 复制推荐码 副文本:GNXAB2C3 >
|
|
||||||
// [蓝色图标] 复制链接 副文本:https://... >
|
|
||||||
// [绿色图标] 分享给好友 副文本:通过微信/WhatsApp >
|
|
||||||
//
|
|
||||||
// 每项点击行为:
|
|
||||||
// 复制推荐码 → _copyCode() → 剪贴板 + SnackBar
|
|
||||||
// 复制链接 → _copyLink() → 剪贴板 + SnackBar
|
|
||||||
// 分享给好友 → _shareNative() → 系统原生分享弹层
|
|
||||||
|
|
||||||
Widget _buildShareActions() {
|
Widget _buildShareActions() {
|
||||||
return Column(
|
return Column(
|
||||||
|
|
@ -522,7 +643,6 @@ class _SharePageState extends State<SharePage> {
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// 复制推荐码
|
|
||||||
_buildActionTile(
|
_buildActionTile(
|
||||||
icon: Icons.qr_code_rounded,
|
icon: Icons.qr_code_rounded,
|
||||||
iconBg: AppColors.primaryContainer,
|
iconBg: AppColors.primaryContainer,
|
||||||
|
|
@ -532,17 +652,15 @@ class _SharePageState extends State<SharePage> {
|
||||||
onTap: _copyCode,
|
onTap: _copyCode,
|
||||||
),
|
),
|
||||||
const Divider(indent: 60, height: 1),
|
const Divider(indent: 60, height: 1),
|
||||||
// 复制链接
|
|
||||||
_buildActionTile(
|
_buildActionTile(
|
||||||
icon: Icons.link_rounded,
|
icon: Icons.link_rounded,
|
||||||
iconBg: AppColors.infoLight,
|
iconBg: AppColors.infoLight,
|
||||||
iconColor: AppColors.info,
|
iconColor: AppColors.info,
|
||||||
title: context.t('share.copyLink'),
|
title: context.t('share.copyLink'),
|
||||||
subtitle: _inviteLink,
|
subtitle: _shareLink,
|
||||||
onTap: _copyLink,
|
onTap: _copyLink,
|
||||||
),
|
),
|
||||||
const Divider(indent: 60, height: 1),
|
const Divider(indent: 60, height: 1),
|
||||||
// 系统原生分享
|
|
||||||
_buildActionTile(
|
_buildActionTile(
|
||||||
icon: Icons.share_rounded,
|
icon: Icons.share_rounded,
|
||||||
iconBg: AppColors.successLight,
|
iconBg: AppColors.successLight,
|
||||||
|
|
@ -558,10 +676,6 @@ class _SharePageState extends State<SharePage> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 操作列表项
|
|
||||||
///
|
|
||||||
/// - [iconBg] 图标容器背景色(使用语义色的浅色版本)
|
|
||||||
/// - [subtitle] 单行截断,防止链接/代码过长破坏布局
|
|
||||||
Widget _buildActionTile({
|
Widget _buildActionTile({
|
||||||
required IconData icon,
|
required IconData icon,
|
||||||
required Color iconBg,
|
required Color iconBg,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue