262773a9de
- PaymentFlowController 新增 stopPolling():只停轮询 Timer,不发远程 cancel、 不改 state;PaymentScreen.dispose() 改调它,不再复用 cancel()——离开支付页 (切左导航 tab)不再等同于放弃订单,cancel() 只留给「取消订单」按钮的显式路径。 - redirect 分支 launchUrl 前加 canLaunchUrl 判定 + try-catch,失败时用 showPangolinToast 给可见提示(新增 l10n openAlipayFailed,zh/en 均补)。 - purchase_page.dart::_choose 下单后严格判 phase == awaitingPayment 才跳转 支付页,建单失败(failed)不再误跳。 - 回归测试:payment_pages_test.dart 补两条用例区分 dispose(不触发 cancel、 state 不归 idle)与「取消订单」按钮(远程 cancel + state 归 idle); payment_flow_test.dart 补 stopPolling() 单元测试。
233 lines
7.8 KiB
Dart
233 lines
7.8 KiB
Dart
// app_text.dart — 文案契约(l10n 资源层)
|
|
//
|
|
// 产品任一时刻只显示中文【或】英文(设计铁律 §6 单语言显示),由
|
|
// `localeProvider` 段控切换。所有界面文案必须经此处取用,禁止在组件内
|
|
// 写死中/英字面量。zh / en 两份资源分别在 strings_zh.dart / strings_en.dart。
|
|
//
|
|
// 红线词约束(设计铁律 §13):资源文件不得出现 VPN / 翻墙 / 科学上网 /
|
|
// 突破封锁 / 自由穿越 / Go anywhere。CI `ci/scan-redline.sh` 对本目录做扫描。
|
|
//
|
|
// 注意:这是手写资源(非 flutter gen-l10n 代码生成),保证离线可编译;
|
|
// 接口形态与 .arb 一致,后续可平滑迁移到官方 l10n 工具链。
|
|
|
|
/// 受支持语言。单显——任一时刻只渲染其一。
|
|
enum AppLang { zh, en }
|
|
|
|
/// 全部界面文案的抽象契约。zh / en 各实现一份。
|
|
abstract class AppText {
|
|
const AppText();
|
|
|
|
AppLang get lang;
|
|
|
|
// ── 品牌 / 连接状态 ──
|
|
String get brand;
|
|
String get online;
|
|
String get offline;
|
|
String get capOff;
|
|
String get capConnecting;
|
|
String get capOn;
|
|
String get connectNow; // 连接键 off 态圆内文字
|
|
String get secure; // 连接键圆内「已加密」
|
|
|
|
// ── 底部 / 侧栏导航 ──
|
|
String get tabConnect;
|
|
String get tabServers;
|
|
String get tabStats;
|
|
String get tabMe;
|
|
|
|
// ── 连接页 ──
|
|
String get currentNode;
|
|
String get download;
|
|
String get upload;
|
|
String get latency;
|
|
|
|
// ── 免费额度卡 ──
|
|
String get quotaToday;
|
|
String get minutes;
|
|
String get quotaFree;
|
|
String get watchAd;
|
|
String get adUnlocked;
|
|
|
|
// ── 节点页 ──
|
|
String get chooseNode;
|
|
String get searchPh;
|
|
String get smartSelect;
|
|
// 已连接时点其他节点 → 切换确认(防误触)
|
|
String nodeSwitchTitle(String name);
|
|
String get nodeSwitchBody;
|
|
String get nodeSwitchConfirm;
|
|
// 连通看门狗:当前节点数据面不可用时的提示
|
|
String get nodeUnhealthySwitched; // 智能选择已自动切换
|
|
String get nodeUnhealthyError; // 手动节点:断开并提示
|
|
String get smartSub;
|
|
String get recommended;
|
|
|
|
// ── 统计页 ──
|
|
String get statsTitle;
|
|
String get trafficMonth;
|
|
String get avgPing;
|
|
String get durMonth;
|
|
String get weekTraffic;
|
|
List<String> get days7;
|
|
String get byDevice;
|
|
String get noDeviceUsage;
|
|
// 统计页重设计:周期(月/周/日) · 指标(下行/上行/时长) · 折线 · 设备下拉
|
|
String get periodMonth;
|
|
String get periodWeek;
|
|
String get periodToday;
|
|
String get statDown;
|
|
String get statUp;
|
|
String get statDuration;
|
|
String get chartTwoWeeks;
|
|
String get allDevices;
|
|
|
|
// ── 账户页 ──
|
|
String get meTitle;
|
|
String get proMember;
|
|
String get freePlanName;
|
|
String get expires;
|
|
String get upgradeBtn;
|
|
String get accInfoTitle;
|
|
String get accEmail;
|
|
String get accPassword;
|
|
String get accChange;
|
|
String get myDevices;
|
|
String get devicesSub;
|
|
String get thisDevice;
|
|
String get remove;
|
|
// 设备数超上限挡板(#16):%s = 套餐设备上限数
|
|
String get deviceLimitTitle;
|
|
String get deviceLimitDesc; // "你的套餐最多 %s 台设备,移除一台以继续。"
|
|
String get deviceLimitRemoveOldest;
|
|
// 设备管理(P6):在线状态 / 操作 / 危险确认
|
|
String get devOnline;
|
|
String get devOffline;
|
|
String get devLastOnline; // 「最后在线」前缀(离线设备,取 last_seen)
|
|
String get devNeverLogin;
|
|
String get devForceLogout;
|
|
String get devClearLogin;
|
|
String get devRename;
|
|
String get devRenameHint;
|
|
String get devSave;
|
|
String get devForceLogoutConfirm; // 弹窗正文(含设备名占位 %s)
|
|
String get devClearLoginConfirm;
|
|
String get devCancel;
|
|
// 本设备被其他设备强制下线时的提示框。
|
|
String get sessionRevokedTitle;
|
|
String get sessionRevokedBody;
|
|
String get sessionRevokedOk;
|
|
String get redeemEntry;
|
|
String get contactEntry;
|
|
String get signOut;
|
|
String get language;
|
|
String get darkAppearance;
|
|
String get stateOn;
|
|
String get followLight;
|
|
String get protocol;
|
|
String get settingsTitle;
|
|
String get autostart;
|
|
String get autostartSub;
|
|
String get autoConnect;
|
|
String get autoConnectSub;
|
|
String autoConnectingTo(String name); // 自动连接 toast
|
|
String get smartRoute;
|
|
String get smartRouteSub;
|
|
String get killSwitch;
|
|
String get killSwitchSub;
|
|
String get checkUpdate;
|
|
|
|
// ── 套餐选择 ──
|
|
String get choosePlan;
|
|
String get freePlan;
|
|
String get proPlan;
|
|
String get teamPlan;
|
|
String get perMonth;
|
|
String get current;
|
|
String get upgrade;
|
|
String get choose;
|
|
String get mostPopular;
|
|
List<String> get featsFree;
|
|
List<String> get featsPro;
|
|
List<String> get featsTeam;
|
|
|
|
// ── 兑换 & 购买 ──
|
|
String get redeemTitle;
|
|
String get redeemCodeTitle;
|
|
String get redeemPh;
|
|
String get redeemBtn;
|
|
String get redeemOk;
|
|
String get buyTitle;
|
|
String get buySub;
|
|
String get chStore;
|
|
String get chEmail;
|
|
|
|
// ── 联系我们 ──
|
|
String get contactTitle;
|
|
String get contactIntro;
|
|
String get contactEmail;
|
|
String get contactStore;
|
|
String get contactHoursTitle;
|
|
String get contactHours;
|
|
|
|
// ── 登录 / 注册 ──
|
|
String get authTagline;
|
|
String get tabLogin;
|
|
String get tabRegister;
|
|
String get emailLabel;
|
|
String get emailPh;
|
|
String get pwLabel;
|
|
String get pwPh;
|
|
String get setPwPh;
|
|
String get codeLabel;
|
|
String codeSentTo(String email);
|
|
String get sendCode;
|
|
String get resend;
|
|
String get doLogin;
|
|
String get doNext;
|
|
String get doCreate;
|
|
String get forgotPw;
|
|
String get tos;
|
|
|
|
// ── 首次引导 ──
|
|
String get obSkip;
|
|
String get obNext;
|
|
String get obAllow;
|
|
String get obStart;
|
|
String get ob1Title;
|
|
String get ob1Sub;
|
|
String get ob2Title;
|
|
String get ob2Sub;
|
|
String get ob3Title;
|
|
String get ob3Sub;
|
|
|
|
// ── 购买 / 支付 ──
|
|
String get purchaseTitle; // 购买套餐 / Purchase
|
|
String get paymentTitle; // 支付 / Payment
|
|
String get buyNow; // 立即购买 / Buy now
|
|
String get payMethodAlipay; // 支付宝 / Alipay
|
|
String get payMethodCrypto; // USDT (TRC20)
|
|
String get choosePayMethod; // 选择支付方式 / Choose payment method
|
|
String get proMonthly; // 专业版·月付 / Pro · Monthly
|
|
String get proQuarterly; // 专业版·季付 / Pro · Quarterly
|
|
String get proYearly; // 专业版·年付 / Pro · Yearly
|
|
String get perQuarter; // /季 / /quarter
|
|
String get perYear; // /年 / /year
|
|
String get payAmountLabel; // 转账金额 / Amount
|
|
String get payAddressLabel; // 收款地址 / Address
|
|
String get payNetworkLabel; // 网络 / Network
|
|
String get payExactAmountHint; // 金额须精确一致,到账后自动开通 / Send the exact amount; activates automatically
|
|
String get copied; // 已复制 / Copied
|
|
String get openAlipay; // 打开支付宝支付 / Pay with Alipay
|
|
String get openAlipayHint; // 完成支付后返回,本页会自动刷新 / Return after paying; this page refreshes automatically
|
|
String get openAlipayFailed; // 无法打开支付宝,请检查是否已安装或稍后重试 / Couldn't open Alipay; check it's installed or try again
|
|
String get awaitingPayment; // 等待付款 / Awaiting payment
|
|
String get paySucceeded; // 已开通 / Activated
|
|
String get payExpiresAt; // 有效期至 / Valid until
|
|
String get payDone; // 完成 / Done
|
|
String get payFailed; // 支付失败 / Payment failed
|
|
String get payRetry; // 重试 / Retry
|
|
String get switchPayMethod; // 换一种支付方式 / Switch payment method
|
|
String get cancelOrder; // 取消订单 / Cancel order
|
|
String get qrNotSupported; // 请复制内容后在支付宝内打开 / Copy and open in Alipay
|
|
}
|