// server_tile.dart — 服务器列表行 import 'package:flutter/material.dart'; import '../pangolin_theme.dart'; import 'country_code.dart'; import 'pangolin_icons.dart'; class ServerInfo { const ServerInfo({ required this.code, required this.name, required this.sub, required this.ping, this.nodeId = '', }); final String code, name, sub; final int ping; /// 控制面节点 ID,对应 POST /v1/nodes/:nodeId/connect 路径参数。 /// 留空时降级为使用 [code] 小写值(仅限 mock 联调)。 final String nodeId; String get effectiveNodeId => nodeId.isEmpty ? code.toLowerCase() : nodeId; } class ServerTile extends StatelessWidget { const ServerTile({super.key, required this.server, this.active = false, this.onTap}); final ServerInfo server; final bool active; final VoidCallback? onTap; @override Widget build(BuildContext context) { final c = context.pangolin; return InkWell( onTap: onTap, child: Container( color: active ? c.accentSubtle : Colors.transparent, padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), child: Row( children: [ CountryCode(code: server.code, active: active), const SizedBox(width: 13), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(server.name, style: PangolinText.sm.copyWith(color: c.fg1, fontWeight: FontWeight.w600, fontSize: 15)), const SizedBox(height: 2), Text(server.sub, style: PangolinText.caption.copyWith(color: c.fg3, fontWeight: FontWeight.w400)), ], ), ), Text('${server.ping}ms', style: PangolinText.mono.copyWith(color: c.fg2, fontSize: 12)), const SizedBox(width: 8), SignalBars(ping: server.ping), if (active) ...[const SizedBox(width: 10), Icon(PangolinIcons.check, size: 18, color: c.accent)], ], ), ), ); } }