// node.dart — 加速节点数据模型 import '../l10n/app_text.dart'; /// 节点标签(决定副标题语义胶囊)。 enum NodeTag { none, streaming, p2p } /// 单个加速节点。名称按语言单显;副标题脱敏(无红线词)。 class Node { const Node({ required this.code, required this.nameZh, required this.nameEn, required this.ping, this.uuid = '', this.tier = 'free', this.tag = NodeTag.none, }); /// 服务端 UUID,用于 POST /v1/nodes/{uuid}/connect。 /// 演示节点为空字符串。 final String uuid; /// 2 字母国家码(HK/JP/SG…),界面以码块渲染,绝不用 emoji 国旗。 final String code; final String nameZh; final String nameEn; /// 节点层级:'free' | 'pro'。 final String tier; /// 演示延迟(ms);真实节点由探针数据填充。 final int ping; final NodeTag tag; String localizedName(AppLang lang) => lang == AppLang.zh ? nameZh : nameEn; /// 副标题:有标签时显示语义文字,否则用拉丁地名(两语言通用,不串语言)。 String localizedSub(AppLang lang) { switch (tag) { case NodeTag.streaming: return lang == AppLang.zh ? '流媒体优化' : 'Streaming'; case NodeTag.p2p: return 'P2P'; case NodeTag.none: return nameEn; } } } /// 智能选择的哨兵选中值。 const String kSmartNodeCode = 'AUTO'; /// 演示节点清单(对齐 design/ui_kits/mobile/parts.jsx 的 SERVERS)。 const List kDemoNodes = [ Node(code: 'HK', nameZh: '香港 · 流媒体', nameEn: 'Hong Kong', ping: 18, tag: NodeTag.streaming), Node(code: 'JP', nameZh: '日本 东京', nameEn: 'Tokyo', ping: 32, tag: NodeTag.p2p), Node(code: 'SG', nameZh: '新加坡', nameEn: 'Singapore', ping: 54, tag: NodeTag.p2p), Node(code: 'TW', nameZh: '台湾 台北', nameEn: 'Taipei', ping: 28), Node(code: 'US', nameZh: '美国 洛杉矶', nameEn: 'Los Angeles', ping: 146, tag: NodeTag.streaming), Node(code: 'DE', nameZh: '德国 法兰克福', nameEn: 'Frankfurt', ping: 198), Node(code: 'UK', nameZh: '英国 伦敦', nameEn: 'London', ping: 210), Node(code: 'KR', nameZh: '韩国 首尔', nameEn: 'Seoul', ping: 41), ];