Compare commits

...

11 Commits

Author SHA1 Message Date
2b80fcba0d 新增编译模式下对日志进行输出,并且更新了hive缓存取出后进行连通性判断
Some checks failed
Build Android APK / 编译 libcore.aar (push) Has been cancelled
Build Android APK / 编译 Android APK (release) (push) Has been cancelled
Build Android APK / 创建 GitHub Release (push) Has been cancelled
Build Multi-Platform / 编译 libcore (iOS/tvOS) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Android) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Windows) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (macOS) (push) Has been cancelled
Build Multi-Platform / 编译 libcore (Linux) (push) Has been cancelled
Build Multi-Platform / 构建 Android APK (push) Has been cancelled
Build Multi-Platform / 构建 Windows (push) Has been cancelled
Build Multi-Platform / 构建 macOS (push) Has been cancelled
Build Multi-Platform / 构建 Linux (push) Has been cancelled
Build Multi-Platform / 构建 iOS (push) Has been cancelled
Build Multi-Platform / 创建 Release (push) Has been cancelled
Build Windows / 编译 libcore (Windows) (push) Has been cancelled
Build Windows / build (push) Has been cancelled
(cherry picked from commit 40f95d0c463c31428c5f25118f59b0c3a60e73ba)
2025-11-01 23:39:13 -07:00
4c5763647d refactor: 优化日志输出,仅在调试模式下启用
- 为所有 print 语句添加 kDebugMode 检查
- 更新 KRLogUtil 工具类,Release 模式下禁用日志输出
- 优化 18 个文件中的 335+ 条日志语句
- 提升 Release 版本性能并增强安全性

(cherry picked from commit 301f1510ba81fe94fb08e013ca80b3ca708a2e15)
2025-11-01 23:31:11 -07:00
b3ee1cc6dc 修正切换节点长连接还存在的问题,目前使用切换之后先关闭服务在启动服务
(cherry picked from commit 3c0c6dde0969fa9847fa77db78abbb6a098e50ef)
2025-11-01 23:25:38 -07:00
b7a78aa76a 修复:大量的ScreenUtil误用,导致界面可能出现问题
(cherry picked from commit 2829da5267a14a9e0f43ff56060a68f1f8b2ca6a)
2025-11-01 23:25:23 -07:00
18ec3e36fc 修正多语言当中的硬编码,更新七国语言
(cherry picked from commit e72e682f526651453dc44b2db78a5df8ba70a733)
2025-11-01 23:24:02 -07:00
8b982d1ba8 优化核心在切换节点时候以往的浏览器保持长连接导致无法使用新节点的逻辑
(cherry picked from commit c920d9fbcd0589f1051bac5bb5bcb5f5deca1017)
2025-11-01 23:20:06 -07:00
f71575ee91 新增手机号码和手机找回密码优化功能
(cherry picked from commit 577dd6eab9ee403ce78850f71e11a5f48dc265b5)
2025-11-01 23:19:27 -07:00
3f838d224c 新增手机号码注册,手机号码验证码登录
(cherry picked from commit 8e269ab2807642d77a109d6bead0ff12915f1dd7)
2025-11-01 23:18:55 -07:00
9ef53abad5 通过检查两个条件:
1. kr_isLogin.value - 确认用户已登录
  2. !isDeviceLogin() - 确认不是设备登录(游客模式)
  只有同时满足这两个条件(即账号密码登录)时,退出登录按钮才会显示。

(cherry picked from commit 7b0acbb4a81d9d6e25c1bcaf1777dd95fc40bb55)
2025-11-01 23:17:13 -07:00
f379a8ee8f 用户点击邀请按钮 → 立即弹出对话框 → 停留在当前页面
(cherry picked from commit b641d661d7b7c6e5e9fa4d2d8456170ee078b043)
2025-11-01 23:17:12 -07:00
54b0cc44ff 修正vless协议配置问题
(cherry picked from commit 5cbb1654e22841b5078829e926946def1a10201e)
2025-11-01 23:15:52 -07:00
55 changed files with 1717 additions and 3077 deletions

View File

@ -9,6 +9,7 @@
"enterEmail": "Please enter email address",
"enterCode": "Please enter verification code",
"enterPassword": "Please enter password",
"enterPasswordForPhone": "Please enter password (Password Login)",
"reenterPassword": "Please re-enter password",
"forgotPassword": "Forgot Password",
"codeLogin": "Code Login",
@ -18,6 +19,8 @@
"privacyPolicy": "Privacy Policy",
"next": "Next",
"registerNow": "Register Now",
"registerAccount": "Register Account",
"clickToRegister": "Click to Register",
"setAndLogin": "Set and Login",
"enterAccount": "Please enter account",
"passwordMismatch": "The two passwords do not match",
@ -25,7 +28,9 @@
"codeSentCountdown": "Code sent {seconds}s",
"and": "and",
"enterInviteCode": "Enter invite code (optional)",
"registerSuccess": "Registration successful"
"registerSuccess": "Registration successful",
"search": "Search",
"selectOtherRegion": "Select other region"
},
"failure": {
"unexpected": "Unexpected Error",
@ -171,7 +176,8 @@
"friday": "Fri",
"saturday": "Sat",
"sunday": "Sun"
}
},
"processTrafficFailed": "Failed to process traffic log data"
},
"message": {
"title": "Notifications",
@ -367,6 +373,7 @@
"initializing": "Initializing...",
"networkConnectionFailure": "Network connection failed, please check and retry",
"retry": "Retry",
"skip": "Skip",
"networkPermissionFailed": "Failed to get network permission",
"initializationFailed": "Initialization failed"
},
@ -467,5 +474,33 @@
"open_dashboard": "Open Dashboard",
"copy_to_terminal": "Copy to Terminal",
"exit_app": "Exit Application"
},
"crisp": {
"initializingSystem": "Initializing customer service system...",
"initFailed": "Customer service system initialization failed"
},
"common": {
"retry": "Retry",
"tryBrowser": "Try opening with browser",
"cannotOpenBrowser": "Cannot open browser",
"openLinkFailed": "Failed to open link, please try again later",
"cannotOpenTelegram": "Cannot open Telegram link"
},
"subscribe": {
"pleaseSelectFirst": "Please select a subscription first",
"resetPeriodFailed": "Failed to reset subscription period",
"resetPeriodSuccess": "Subscription period reset successfully"
},
"purchase": {
"noAvailablePlans": "No available plans"
},
"payment": {
"cannotOpenLink": "Cannot open payment link",
"linkEmpty": "Payment link is empty",
"unsupportedType": "Unsupported payment type"
},
"account": {
"accountRequired": "Account cannot be empty",
"deleteSuccess": "Account deleted successfully"
}
}

View File

@ -9,6 +9,7 @@
"enterEmail": "Please enter email address",
"enterCode": "Por favor, ingresa el código de verificación",
"enterPassword": "Por favor, ingresa la contraseña",
"enterPasswordForPhone": "Por favor ingrese la contraseña (Inicio de sesión con contraseña)",
"reenterPassword": "Por favor, reingresa la contraseña",
"forgotPassword": "Olvidé mi contraseña",
"codeLogin": "Iniciar sesión con código",
@ -18,6 +19,8 @@
"privacyPolicy": "Política de privacidad",
"next": "Siguiente",
"registerNow": "Registrarse ahora",
"registerAccount": "Registrar Cuenta",
"clickToRegister": "Haga clic para registrarse",
"setAndLogin": "Configurar e iniciar sesión",
"enterAccount": "Por favor, ingresa la cuenta",
"passwordMismatch": "Las dos contraseñas no coinciden",
@ -25,7 +28,9 @@
"codeSentCountdown": "Código enviado {seconds}s",
"and": "y",
"enterInviteCode": "Ingresa código de invitación (opcional)",
"registerSuccess": "Registro exitoso"
"registerSuccess": "Registro exitoso",
"search": "Buscar",
"selectOtherRegion": "Seleccionar otra región"
},
"failure": {
"unexpected": "Error inesperado",
@ -187,7 +192,8 @@
"friday": "Vie",
"saturday": "Sáb",
"sunday": "Dom"
}
},
"processTrafficFailed": "Error al procesar datos de registro de tráfico"
},
"message": {
"title": "Notificaciones",
@ -373,6 +379,7 @@
"initializing": "Inicializando...",
"networkConnectionFailure": "Error de conexión de red, verifique e intente nuevamente",
"retry": "Reintentar",
"skip": "Saltar",
"networkPermissionFailed": "Error al obtener permiso de red",
"initializationFailed": "Error de inicialización"
},
@ -481,5 +488,33 @@
"open_dashboard": "Abrir panel",
"copy_to_terminal": "Copiar al terminal",
"exit_app": "Salir de la aplicación"
},
"crisp": {
"initializingSystem": "Inicializando sistema de atención al cliente...",
"initFailed": "Error al inicializar el sistema de atención al cliente"
},
"common": {
"retry": "Reintentar",
"tryBrowser": "Intentar abrir con navegador",
"cannotOpenBrowser": "No se puede abrir el navegador",
"openLinkFailed": "Error al abrir el enlace, inténtelo más tarde",
"cannotOpenTelegram": "No se puede abrir el enlace de Telegram"
},
"subscribe": {
"pleaseSelectFirst": "Seleccione primero una suscripción",
"resetPeriodFailed": "Error al restablecer el período de suscripción",
"resetPeriodSuccess": "Período de suscripción restablecido exitosamente"
},
"purchase": {
"noAvailablePlans": "No hay planes disponibles"
},
"payment": {
"cannotOpenLink": "No se puede abrir el enlace de pago",
"linkEmpty": "El enlace de pago está vacío",
"unsupportedType": "Tipo de pago no compatible"
},
"account": {
"accountRequired": "La cuenta no puede estar vacía",
"deleteSuccess": "Cuenta eliminada exitosamente"
}
}

View File

@ -1,441 +0,0 @@
{
"login": {
"welcome": "¡Bienvenido a Hi快VPN!",
"verifyPhone": "Verifica tu número de teléfono",
"verifyEmail": "Verifica tu correo electrónico",
"codeSent": "Se ha enviado un código de 6 dígitos a {account}. Por favor, ingrésalo en los próximos 30 minutos.",
"back": "Atrás",
"enterEmailOrPhone": "Ingresa correo o teléfono",
"enterCode": "Por favor, ingresa el código de verificación",
"enterPassword": "Por favor, ingresa la contraseña",
"reenterPassword": "Por favor, reingresa la contraseña",
"forgotPassword": "Olvidé mi contraseña",
"codeLogin": "Iniciar sesión con código",
"passwordLogin": "Iniciar sesión con contraseña",
"agreeTerms": "Iniciar sesión/Crear cuenta, acepto",
"termsOfService": "Términos de servicio",
"privacyPolicy": "Política de privacidad",
"next": "Siguiente",
"registerNow": "Registrarse ahora",
"setAndLogin": "Configurar e iniciar sesión",
"enterAccount": "Por favor, ingresa la cuenta",
"passwordMismatch": "Las dos contraseñas no coinciden",
"sendCode": "Enviar código",
"codeSentCountdown": "Código enviado {seconds}s",
"and": "y",
"enterInviteCode": "Ingresa código de invitación (opcional)",
"registerSuccess": "Registro exitoso"
},
"failure": {
"unexpected": "Error inesperado",
"clash": {
"unexpected": "Error inesperado",
"core": "Error de Clash ${reason}"
},
"singbox": {
"unexpected": "Error de servicio inesperado",
"serviceNotRunning": "Servicio no en ejecución",
"missingPrivilege": "Privilegios insuficientes",
"missingPrivilegeMsg": "El modo VPN requiere privilegios de administrador. Reinicia la aplicación como administrador o cambia el modo de servicio",
"missingGeoAssets": "Faltan recursos GEO",
"missingGeoAssetsMsg": "Faltan archivos de recursos GEO. Considera cambiar los recursos activos o descarga los recursos seleccionados en configuración.",
"invalidConfigOptions": "Opciones de configuración inválidas",
"invalidConfig": "Configuración inválida",
"create": "Error al crear servicio",
"start": "Error al iniciar servicio"
},
"connectivity": {
"unexpected": "Fallo inesperado",
"missingVpnPermission": "Falta permiso VPN",
"missingNotificationPermission": "Falta permiso de notificaciones",
"core": "Error del núcleo"
},
"profiles": {
"unexpected": "Error inesperado",
"notFound": "Perfil no encontrado",
"invalidConfig": "Configuración inválida",
"invalidUrl": "URL inválida"
},
"connection": {
"unexpected": "Error de conexión inesperado",
"timeout": "Tiempo de conexión agotado",
"badResponse": "Respuesta incorrecta",
"connectionError": "Error de conexión",
"badCertificate": "Certificado inválido"
},
"geoAssets": {
"unexpected": "Error inesperado",
"notUpdate": "No hay actualizaciones disponibles",
"activeNotFound": "No se encontraron recursos GEO activos"
}
},
"userInfo": {
"title": "Mi información",
"bindingTip": "Correo/teléfono no vinculado",
"myAccount": "Mi cuenta",
"balance": "Saldo",
"noValidSubscription": "No tiene una suscripción válida",
"subscribeNow": "Suscribirse ahora",
"shortcuts": "Accesos directos",
"adBlock": "Bloqueo de anuncios",
"dnsUnlock": "Desbloqueo DNS",
"contactUs": "Contáctanos",
"others": "Otros",
"logout": "Cerrar sesión",
"logoutConfirmTitle": "Cerrar sesión",
"logoutConfirmMessage": "¿Estás seguro de que quieres cerrar sesión?",
"logoutCancel": "Cancelar",
"vpnWebsite": "Sitio web VPN",
"telegram": "Telegram",
"mail": "Correo",
"phone": "Teléfono",
"customerService": "Servicio al cliente",
"workOrder": "Enviar ticket",
"pleaseLogin": "Por favor, inicia sesión primero",
"subscriptionValid": "Suscripción válida",
"startTime": "Fecha de inicio:",
"expireTime": "Fecha de vencimiento:",
"loginNow": "Iniciar sesión ahora",
"trialPeriod": "Bienvenido a la prueba Premium",
"remainingTime": "Tiempo restante",
"trialExpired": "Prueba expirada, conexión desconectada",
"subscriptionExpired": "Suscripción expirada, conexión desconectada",
"copySuccess": "Copiado con éxito",
"notAvailable": "No disponible",
"deviceLimit": "Límite de dispositivos: {count}",
"reset": "Restablecer",
"trafficUsage": "Usado: {used} / {total}",
"trafficProgress": {
"title": "Uso de tráfico",
"unlimited": "Tráfico ilimitado",
"limited": "Tráfico usado"
},
"switchSubscription": "Cambiar Suscripción",
"resetTrafficTitle": "Restablecer Tráfico",
"resetTrafficMessage": "Ejemplo de restablecimiento de tráfico del plan mensual: restablecer el tráfico del siguiente ciclo mensualmente, y el período de validez de la suscripción se adelantará de {currentTime} a {newTime}",
"trialStatus": "Estado de prueba",
"trialing": "En período de prueba",
"trialEndMessage": "No podrá continuar usando después de que expire el período de prueba",
"lastDaySubscriptionStatus": "Suscripción por expirar",
"lastDaySubscriptionMessage": "Por expirar",
"subscriptionEndMessage": "No podrá continuar usando después de que expire la suscripción",
"trialTimeWithDays": "{days}d {hours}h {minutes}m {seconds}s",
"trialTimeWithHours": "{hours}h {minutes}m {seconds}s",
"trialTimeWithMinutes": "{minutes}m {seconds}s",
"refreshLatency": "Actualizar latencia",
"testLatency": "Probar latencia",
"testing": "Probando latencia",
"refreshLatencyDesc": "Actualizar latencia de todos los nodos",
"testAllNodesLatency": "Probar la latencia de red de todos los nodos",
"autoSelect": "Selección automática",
"selected": "Seleccionado",
"willBeDeleted": "será eliminado",
"deleteAccountWarning": "La eliminación de la cuenta es permanente. Una vez que se elimine su cuenta, no podrá utilizar ninguna función. ¿Continuar?",
"requestDelete": "Solicitar eliminación"
},
"setting": {
"title": "Configuración",
"vpnConnection": "Conexión VPN",
"general": "General",
"autoConnect": "Conexión automática",
"routeRule": "Reglas de ruta",
"countrySelector": "Seleccionar país",
"appearance": "Apariencia",
"notifications": "Notificaciones",
"helpImprove": "Ayúdanos a mejorar",
"helpImproveSubtitle": "Subtítulo de ayuda para mejorar",
"requestDeleteAccount": "Solicitar eliminación de cuenta",
"goToDelete": "Ir a eliminar",
"rateUs": "Califícanos en App Store",
"iosRating": "Calificación iOS",
"version": "Versión",
"switchLanguage": "Cambiar idioma",
"system": "Sistema",
"light": "Claro",
"dark": "Oscuro",
"vpnModeSmart": "Modo inteligente",
"mode": "Modo de salida",
"connectionTypeGlobal": "Proxy global",
"connectionTypeGlobalRemark": "Cuando está activado, todo el tráfico pasa por el proxy",
"connectionTypeRule": "Proxy inteligente",
"connectionTypeRuleRemark": "Cuando el [Modo de salida] está configurado en [Proxy inteligente], el sistema dividirá automáticamente el tráfico nacional e internacional según el país seleccionado: las IPs/dominios nacionales se conectan directamente, mientras que las solicitudes extranjeras se acceden a través del proxy",
"connectionTypeDirect": "Conexión directa",
"connectionTypeDirectRemark": "Cuando está activado, todo el tráfico evita el proxy",
"smartMode": "Modo inteligente",
"secureMode": "Modo seguro"
},
"statistics": {
"title": "Estadísticas",
"vpnStatus": "Estado VPN",
"ipAddress": "Dirección IP",
"connectionTime": "Tiempo de conexión",
"protocol": "Protocolo",
"weeklyProtectionTime": "Tiempo de protección semanal",
"currentStreak": "Racha actual",
"highestStreak": "Mejor racha",
"longestConnection": "Conexión más larga",
"days": "{days} días",
"daysOfWeek": {
"monday": "Lun",
"tuesday": "Mar",
"wednesday": "Mié",
"thursday": "Jue",
"friday": "Vie",
"saturday": "Sáb",
"sunday": "Dom"
}
},
"message": {
"title": "Notificaciones",
"system": "Mensajes del sistema",
"promotion": "Mensajes promocionales"
},
"home": {
"welcome": "Bienvenido a Hi快VPN",
"disconnected": "Desconectado",
"connecting": "Conectando",
"connected": "Conectado",
"disconnecting": "Desconectando",
"currentConnectionTitle": "Conexión actual",
"switchNode": "Cambiar nodo",
"timeout": "Tiempo de espera agotado",
"loading": "Cargando...",
"error": "Error de carga",
"checkNetwork": "Verifique su conexión de red e intente nuevamente",
"retry": "Reintentar",
"connectionSectionTitle": "Método de conexión",
"dedicatedServers": "Servidores dedicados",
"countryRegion": "País/Región",
"serverListTitle": "Grupos de servidores dedicados",
"nodeListTitle": "Todos los nodos",
"countryListTitle": "Lista de países/regiones",
"noServers": "No hay servidores disponibles",
"noNodes": "No hay nodos disponibles",
"noRegions": "No hay regiones disponibles",
"subscriptionDescription": "Obtenga acceso premium a la red global de alta velocidad",
"subscribe": "Suscribirse",
"trialPeriod": "Bienvenido a la versión de prueba Premium",
"remainingTime": "Tiempo restante",
"trialExpired": "Período de prueba expirado, conexión terminada",
"subscriptionExpired": "Suscripción expirada, conexión terminada",
"subscriptionUpdated": "Suscripción actualizada",
"subscriptionUpdatedMessage": "Su información de suscripción ha sido actualizada, actualice para ver el último estado",
"trialStatus": "Estado de prueba",
"trialing": "En período de prueba",
"trialEndMessage": "No podrá continuar usando después de que expire el período de prueba",
"lastDaySubscriptionStatus": "Suscripción por expirar",
"lastDaySubscriptionMessage": "Por expirar",
"subscriptionEndMessage": "No podrá continuar usando después de que expire la suscripción",
"trialTimeWithDays": "{days}d {hours}h {minutes}m {seconds}s",
"trialTimeWithHours": "{hours}h {minutes}m {seconds}s",
"trialTimeWithMinutes": "{minutes}m {seconds}s",
"refreshLatency": "Actualizar latencia",
"testLatency": "Probar latencia",
"testing": "Probando latencia",
"refreshLatencyDesc": "Actualizar latencia de todos los nodos",
"testAllNodesLatency": "Probar la latencia de red de todos los nodos",
"autoSelect": "Selección automática",
"selected": "Seleccionado"
},
"invite": {
"title": "Invitar amigos",
"progress": "Progreso de invitación",
"inviteStats": "Estadísticas de invitación",
"registers": "Registrados",
"totalCommission": "Comisión total",
"rewardDetails": "Detalles de recompensa >",
"steps": "Pasos de invitación",
"inviteFriend": "Invitar amigo",
"acceptInvite": "El amigo acepta la invitación\ny se registra",
"getReward": "Obtener recompensa",
"shareLink": "Compartir por enlace",
"shareQR": "Compartir por código QR",
"rules": "Reglas de invitación",
"rule1": "1. Puedes invitar amigos compartiendo tu enlace o código de invitación exclusivo.",
"rule2": "2. Después de que tu amigo complete el registro e inicie sesión, la recompensa por invitación se enviará automáticamente a tu cuenta.",
"pending": "Pendiente de descarga",
"processing": "En proceso",
"success": "Exitoso",
"expired": "Expirado",
"myInviteCode": "Mi código de invitación",
"inviteCodeCopied": "Código de invitación copiado al portapapeles"
},
"purchaseMembership": {
"purchasePackage": "Comprar Paquete",
"noData": "No hay paquetes disponibles",
"myAccount": "Mi Cuenta",
"selectPackage": "Seleccionar Paquete",
"packageDescription": "Descripción del Paquete",
"paymentMethod": "Método de Pago",
"cancelAnytime": "Puedes cancelar en cualquier momento en la APP",
"startSubscription": "Comenzar Suscripción",
"renewNow": "Renovar Ahora",
"month": "{quantity} meses",
"year": "{quantity} años",
"day": "{quantity} días",
"unlimitedTraffic": "Tráfico Ilimitado",
"unlimitedDevices": "Dispositivos Ilimitados",
"devices": "{count} dispositivos",
"features": "Características del Paquete",
"expand": "Expandir",
"collapse": "Colapsar",
"confirmPurchase": "Confirmar Compra",
"confirmPurchaseDesc": "¿Está seguro de que desea comprar este paquete?"
},
"orderStatus": {
"title": "Estado del Pedido",
"pending": {
"title": "Pago Pendiente",
"description": "Por favor complete el pago"
},
"paid": {
"title": "Pago Recibido",
"description": "Procesando su pedido"
},
"success": {
"title": "¡Felicitaciones! Pago Exitoso",
"description": "Su paquete ha sido comprado exitosamente"
},
"closed": {
"title": "Pedido Cerrado",
"description": "Por favor realice un nuevo pedido"
},
"failed": {
"title": "Pago Fallido",
"description": "Por favor intente el pago nuevamente"
},
"unknown": {
"title": "Estado Desconocido",
"description": "Por favor contacte al servicio al cliente"
},
"checkFailed": {
"title": "Verificación Fallida",
"description": "Por favor intente nuevamente más tarde"
},
"initial": {
"title": "Procesando Pago",
"description": "Por favor espere mientras procesamos su pago"
}
},
"dialog": {
"confirm": "Confirmar",
"cancel": "Cancelar",
"ok": "OK",
"iKnow": "Lo entiendo"
},
"splash": {
"appName": "Hi快VPN",
"slogan": "Red global de alta velocidad",
"initializing": "Inicializando...",
"networkConnectionFailure": "Error de conexión de red, verifique e intente nuevamente",
"retry": "Reintentar",
"networkPermissionFailed": "Error al obtener permiso de red",
"initializationFailed": "Error de inicialización"
},
"network": {
"status": {
"connected": "Conectado",
"disconnected": "Desconectado",
"connecting": "Conectando...",
"disconnecting": "Desconectando...",
"reconnecting": "Reconectando...",
"failed": "Error de conexión"
},
"permission": {
"title": "Permiso de red",
"description": "Se requiere permiso de red para proporcionar el servicio VPN",
"goToSettings": "Ir a configuración",
"cancel": "Cancelar"
}
},
"update": {
"title": "Actualización disponible",
"content": "¿Actualizar ahora?",
"updateNow": "Actualizar ahora",
"updateLater": "Más tarde",
"defaultContent": "1. Optimización del rendimiento de la aplicación\n2. Corrección de problemas conocidos\n3. Mejora de la experiencia del usuario"
},
"kr_invite": {
"close": "Cerrar",
"saveQRCode": "Guardar código QR",
"qrCodeSaved": "Código QR guardado",
"shareLink": "Compartir enlace",
"shareQR": "Compartir código QR",
"myInviteCode": "Mi código de invitación"
},
"country": {
"cn": "China",
"ir": "Irán",
"af": "Afganistán",
"ru": "Rusia",
"id": "Indonesia",
"tr": "Turquía",
"br": "Brasil"
},
"error": {
"200": "Éxito",
"500": "Error interno del servidor",
"10001": "Error de consulta a la base de datos",
"10002": "Error de actualización de la base de datos",
"10003": "Error de inserción en la base de datos",
"10004": "Error de eliminación de la base de datos",
"20001": "El usuario ya existe",
"20002": "El usuario no existe",
"20003": "Contraseña de usuario incorrecta",
"20004": "Usuario deshabilitado",
"20005": "Saldo insuficiente",
"20006": "Registro detenido",
"20007": "Telegram no vinculado",
"20008": "Usuario no ha vinculado OAuth",
"20009": "Código de invitación incorrecto",
"30001": "El nodo ya existe",
"30002": "El nodo no existe",
"30003": "El grupo de nodos ya existe",
"30004": "El grupo de nodos no existe",
"30005": "El grupo de nodos no está vacío",
"400": "Error de parámetros",
"40002": "Token de usuario vacío",
"40003": "Token de usuario inválido",
"40004": "Token de usuario expirado",
"40005": "No ha iniciado sesión",
"401": "Demasiadas solicitudes",
"50001": "El cupón no existe",
"50002": "El cupón ya ha sido usado",
"50003": "El cupón no coincide",
"60001": "Suscripción expirada",
"60002": "Suscripción no disponible",
"60003": "El usuario ya tiene una suscripción",
"60004": "La suscripción ya ha sido usada",
"60005": "Límite de suscripción única excedido",
"60006": "Límite de cuota de suscripción",
"70001": "Código de verificación incorrecto",
"80001": "Error al encolar",
"90001": "Modo de depuración habilitado",
"90002": "Error al enviar SMS",
"90003": "Función SMS no habilitada",
"90004": "Función de correo electrónico no habilitada",
"90005": "Método de inicio de sesión no soportado",
"90006": "El autenticador no soporta este método",
"90007": "Código de país de teléfono vacío",
"90008": "Contraseña vacía",
"90009": "Código de país vacío",
"90010": "Se requiere contraseña o código de verificación",
"90011": "El correo electrónico ya existe",
"90012": "El número de teléfono ya existe",
"90013": "El dispositivo ya existe",
"90014": "Número de teléfono incorrecto",
"90015": "Este cuenta ha alcanzado el límite de envío hoy",
"90017": "El dispositivo no existe",
"90018": "ID de usuario no coincide",
"61001": "El pedido no existe",
"61002": "Método de pago no encontrado",
"61003": "Estado de pedido incorrecto",
"61004": "Período de reinicio insuficiente",
"61005": "Existe tráfico sin usar"
},
"tray": {
"open_dashboard": "Abrir panel",
"copy_to_terminal": "Copiar al terminal",
"exit_app": "Salir de la aplicación"
}
}

View File

@ -9,6 +9,7 @@
"enterEmail": "Please enter email address",
"enterCode": "Palun sisesta kinnituskood",
"enterPassword": "Palun sisesta parool",
"enterPasswordForPhone": "Palun sisestage parool (Parooli sisselogimine)",
"reenterPassword": "Palun sisesta parool uuesti",
"forgotPassword": "Unustasid parooli",
"codeLogin": "Koodiga sisselogimine",
@ -18,6 +19,8 @@
"privacyPolicy": "Privaatsuspoliitikaga",
"next": "Edasi",
"registerNow": "Registreeru kohe",
"registerAccount": "Registreeri konto",
"clickToRegister": "Klõpsa registreerimiseks",
"setAndLogin": "Seadista ja logi sisse",
"enterAccount": "Palun sisesta konto",
"passwordMismatch": "Kaks sisestatud parooli ei ühti",
@ -25,7 +28,9 @@
"codeSentCountdown": "Kood saadetud {seconds}s",
"and": "ja",
"enterInviteCode": "Sisesta kutse kood (valikuline)",
"registerSuccess": "Registreerimine õnnestus"
"registerSuccess": "Registreerimine õnnestus",
"search": "Otsing",
"selectOtherRegion": "Valige teine piirkond"
},
"failure": {
"unexpected": "Ootamatu viga",
@ -171,7 +176,8 @@
"friday": "R",
"saturday": "L",
"sunday": "P"
}
},
"processTrafficFailed": "Liikluslogiandmete töötlemine ebaõnnestus"
},
"message": {
"title": "Teavitused",
@ -364,6 +370,7 @@
"initializing": "Initsialiseerimine...",
"networkConnectionFailure": "Võrguühenduse viga, kontrollige ja proovige uuesti",
"retry": "Proovi uuesti",
"skip": "Jäta vahele",
"networkPermissionFailed": "Võrguõiguse hankimine ebaõnnestus",
"initializationFailed": "Initsialiseerimine ebaõnnestus"
},
@ -464,5 +471,33 @@
"open_dashboard": "Ava armatuurlaud",
"copy_to_terminal": "Kopeeri terminali",
"exit_app": "Välju rakendusest"
},
"crisp": {
"initializingSystem": "Klienditeeninduse süsteemi initsialiseerimine...",
"initFailed": "Klienditeeninduse süsteemi initsialiseerimine ebaõnnestus"
},
"common": {
"retry": "Proovi uuesti",
"tryBrowser": "Proovi brauseriga avada",
"cannotOpenBrowser": "Ei saa brauserit avada",
"openLinkFailed": "Lingi avamine ebaõnnestus, proovige hiljem uuesti",
"cannotOpenTelegram": "Ei saa Telegrami linki avada"
},
"subscribe": {
"pleaseSelectFirst": "Palun valige esmalt tellimus",
"resetPeriodFailed": "Tellimisperioodi lähtestamine ebaõnnestus",
"resetPeriodSuccess": "Tellimisperiood edukalt lähtestatud"
},
"purchase": {
"noAvailablePlans": "Saadaolevad plaanid puuduvad"
},
"payment": {
"cannotOpenLink": "Ei saa makselinki avada",
"linkEmpty": "Makselink on tühi",
"unsupportedType": "Toetamata maksetüüp"
},
"account": {
"accountRequired": "Konto ei saa olla tühi",
"deleteSuccess": "Konto edukalt kustutatud"
}
}

View File

@ -1,423 +0,0 @@
{
"login": {
"welcome": "Tere tulemast Hi快VPN-i!",
"verifyPhone": "Kinnita oma telefoninumber",
"verifyEmail": "Kinnita oma e-post",
"codeSent": "6-kohaline kood on saadetud aadressile {account}. Palun sisesta see 30 minuti jooksul.",
"back": "Tagasi",
"enterEmailOrPhone": "Sisesta e-post või telefoninumber",
"enterCode": "Palun sisesta kinnituskood",
"enterPassword": "Palun sisesta parool",
"reenterPassword": "Palun sisesta parool uuesti",
"forgotPassword": "Unustasid parooli",
"codeLogin": "Koodiga sisselogimine",
"passwordLogin": "Parooliga sisselogimine",
"agreeTerms": "Logi sisse/Loo konto, nõustun",
"termsOfService": "Teenusetingimustega",
"privacyPolicy": "Privaatsuspoliitikaga",
"next": "Edasi",
"registerNow": "Registreeru kohe",
"setAndLogin": "Seadista ja logi sisse",
"enterAccount": "Palun sisesta konto",
"passwordMismatch": "Kaks sisestatud parooli ei ühti",
"sendCode": "Saada kood",
"codeSentCountdown": "Kood saadetud {seconds}s",
"and": "ja",
"enterInviteCode": "Sisesta kutse kood (valikuline)",
"registerSuccess": "Registreerimine õnnestus"
},
"failure": {
"unexpected": "Ootamatu viga",
"clash": {
"unexpected": "Ootamatu viga",
"core": "Clash viga ${reason}"
},
"singbox": {
"unexpected": "Ootamatu teenuse viga",
"serviceNotRunning": "Teenus ei tööta",
"missingPrivilege": "Puuduvad õigused",
"missingPrivilegeMsg": "VPN režiim vajab administraatori õigusi. Taaskäivitage rakendus administraatorina või muutke teenuse režiimi",
"missingGeoAssets": "Puuduvad GEO ressursid",
"missingGeoAssetsMsg": "Puuduvad GEO ressursifailid. Kaaluge aktiivsete ressursside muutmist või laadige valitud ressursid seadetest alla.",
"invalidConfigOptions": "Kehtetud seadistuse valikud",
"invalidConfig": "Kehtetu seadistus",
"create": "Teenuse loomise viga",
"start": "Teenuse käivitamise viga"
},
"connectivity": {
"unexpected": "Ootamatu tõrge",
"missingVpnPermission": "Puudub VPN luba",
"missingNotificationPermission": "Puudub teavituste luba",
"core": "Tuuma viga"
},
"profiles": {
"unexpected": "Ootamatu viga",
"notFound": "Profiili ei leitud",
"invalidConfig": "Kehtetu seadistus",
"invalidUrl": "Kehtetu URL"
},
"connection": {
"unexpected": "Ootamatu ühenduse viga",
"timeout": "Ühenduse ajalõpp",
"badResponse": "Halb vastus",
"connectionError": "Ühenduse viga",
"badCertificate": "Kehtetu sertifikaat"
},
"geoAssets": {
"unexpected": "Ootamatu viga",
"notUpdate": "Uuendusi pole saadaval",
"activeNotFound": "Aktiivseid GEO ressursse ei leitud"
}
},
"userInfo": {
"title": "Minu info",
"bindingTip": "E-post/telefon sidumata",
"myAccount": "Minu konto",
"balance": "Jääk",
"noValidSubscription": "Teil pole kehtivat tellimust",
"subscribeNow": "Telli kohe",
"shortcuts": "Otseteed",
"adBlock": "Reklaami blokeerimine",
"dnsUnlock": "DNS avamine",
"contactUs": "Võta meiega ühendust",
"others": "Muu",
"logout": "Logi välja",
"logoutConfirmTitle": "Logi välja",
"logoutConfirmMessage": "Kas oled kindel, et soovid välja logida?",
"logoutCancel": "Tühista",
"vpnWebsite": "VPN veebileht",
"telegram": "Telegram",
"mail": "E-post",
"phone": "Telefon",
"customerService": "Klienditugi",
"workOrder": "Esita taotlus",
"pleaseLogin": "Palun logi esmalt sisse",
"subscriptionValid": "Tellimus kehtiv",
"startTime": "Algusaeg:",
"expireTime": "Aegumisaeg:",
"loginNow": "Logi kohe sisse",
"trialPeriod": "Tere tulemast Premium prooviperioodi",
"remainingTime": "Järelejäänud aeg",
"trialExpired": "Prooviperiood on lõppenud, ühendus katkestatud",
"subscriptionExpired": "Tellimus on aegunud, ühendus katkestatud",
"switchSubscription": "Vaheta tellimust",
"resetTrafficTitle": "Lähtesta liiklus",
"resetTrafficMessage": "Kuupaketi liikluse lähtestamise näide: lähtesta järgmise tsükli liiklus igakuiselt ja tellimuse kehtivusaeg edasi lükatakse {currentTime} kuni {newTime}",
"reset": "Lähtesta",
"deviceLimit": "Seadmete limiit: {count}",
"trafficUsage": "Kasutatud: {used} / {total}",
"trafficProgress": {
"title": "Liikluse kasutamine",
"unlimited": "Piiramatu liiklus",
"limited": "Kasutatud liiklus"
},
"copySuccess": "Kopeeritud",
"notAvailable": "Pole saadaval",
"willBeDeleted": "kustutatakse",
"deleteAccountWarning": "Konto kustutamine on püsiv. Kui teie konto on kustutatud, ei saa te enam ühtegi funktsiooni kasutada. Jätkata?",
"requestDelete": "Taotle kustutamist"
},
"setting": {
"title": "Seaded",
"vpnConnection": "VPN ühendus",
"general": "Üldine",
"autoConnect": "Automaatne ühendus",
"routeRule": "Marsruudi reeglid",
"countrySelector": "Vali riik",
"appearance": "Välimus",
"notifications": "Teavitused",
"helpImprove": "Aita meil paremaks muutuda",
"helpImproveSubtitle": "Aita meil paremaks muutuda alapealkiri",
"requestDeleteAccount": "Taotle konto kustutamist",
"goToDelete": "Mine kustutama",
"rateUs": "Hinda meid App Store'is",
"iosRating": "iOS hinnang",
"version": "Versioon",
"switchLanguage": "Vaheta keelt",
"system": "Süsteem",
"light": "Hele",
"dark": "Tume",
"vpnModeSmart": "Nutikas režiim",
"mode": "Väljundrežiim",
"connectionTypeGlobal": "Globaalne puhverserver",
"connectionTypeGlobalRemark": "Lubamisel suunatakse kogu liiklus puhverserveri kaudu",
"connectionTypeRule": "Nutikas puhverserver",
"connectionTypeRuleRemark": "Lubamisel, kui väljundrežiim on seatud nutikaks puhverserveriks, valitud riigi põhjal, jaotatakse liiklus automaatselt: kohalikud IP-d/domeenid ühenduvad otse, välismaised päringud suunatakse puhverserverisse",
"connectionTypeDirect": "Otsene ühendus",
"connectionTypeDirectRemark": "Lubamisel suunatakse kogu liiklus otse",
"smartMode": "Nutikas režiim",
"secureMode": "Turvaline režiim"
},
"statistics": {
"title": "Statistika",
"vpnStatus": "VPN olek",
"ipAddress": "IP aadress",
"connectionTime": "Ühenduse aeg",
"protocol": "Protokoll",
"weeklyProtectionTime": "Iganädalane kaitseaeg",
"currentStreak": "Praegune seeria",
"highestStreak": "Parim seeria",
"longestConnection": "Pikim ühendus",
"days": "{days} päeva",
"daysOfWeek": {
"monday": "E",
"tuesday": "T",
"wednesday": "K",
"thursday": "N",
"friday": "R",
"saturday": "L",
"sunday": "P"
}
},
"message": {
"title": "Teavitused",
"system": "Süsteemi sõnumid",
"promotion": "Kampaania sõnumid"
},
"invite": {
"title": "Kutsu sõbrad",
"progress": "Kutse edenemine",
"inviteStats": "Kutse statistika",
"registers": "Registreeritud",
"totalCommission": "Kogu komisjonitasu",
"rewardDetails": "Tasu üksikasjad >",
"steps": "Kutse Sammud",
"inviteFriend": "Kutsu Sõbrad",
"acceptInvite": "Sõbrad aktsepteerivad kutset\nTee tellimus ja registreeru",
"getReward": "Saada Tasu",
"shareLink": "Jaga Linki",
"shareQR": "Jaga QR-koodi",
"rules": "Kutse Reeglid",
"rule1": "1. Saad kutsuda sõpru meiega liituma, jagades oma erilist kutselinki või kutsekoodi.",
"rule2": "2. Pärast seda, kui sõbrad on registreerunud ja sisse loginud, krediteeritakse kutsetasud automaatselt teie kontole.",
"pending": "Ootel",
"processing": "Töötlemisel",
"success": "Õnnestus",
"expired": "Aegunud",
"myInviteCode": "Minu Kutsekood",
"inviteCodeCopied": "Kutsekood kopeeritud lõikelauale",
"close": "Sulge",
"saveQRCode": "Salvesta QR-kood",
"qrCodeSaved": "QR-kood salvestatud",
"copiedToClipboard": "Kopeeritud lõikelauale",
"getInviteCodeFailed": "Kutsekoodi hankimine ebaõnnestus, proovi hiljem uuesti",
"generateQRCodeFailed": "QR-koodi genereerimine ebaõnnestus, proovi hiljem uuesti",
"generateShareLinkFailed": "Jagamislinki genereerimine ebaõnnestus, proovi hiljem uuesti"
},
"purchaseMembership": {
"purchasePackage": "Paketi Ostmine",
"noData": "Saadaval pakette pole",
"myAccount": "Minu Konto",
"selectPackage": "Vali Pakett",
"packageDescription": "Paketi Kirjeldus",
"paymentMethod": "Makseviis",
"cancelAnytime": "Saad igal ajal rakenduses tühistada",
"startSubscription": "Alusta Tellimust",
"renewNow": "Uuenda Kohe",
"month": "{months} kuud",
"year": "{years} aastat",
"day": "{days} päeva",
"unlimitedTraffic": "Piiramatu Liiklus",
"unlimitedDevices": "Piiramatu Seadmete Arv",
"devices": "{count} seadet",
"features": "Paketi Funktsioonid",
"expand": "Laienda",
"collapse": "Sulge",
"confirmPurchase": "Kinnita Ost",
"confirmPurchaseDesc": "Kas olete kindel, et soovite selle paketi osta?"
},
"orderStatus": {
"title": "Tellimuse olek",
"pending": {
"title": "Makse ootel",
"description": "Palun täitke makse"
},
"paid": {
"title": "Makse vastu võetud",
"description": "Tellimust töödeldakse"
},
"success": {
"title": "Palju õnne! Makse õnnestus",
"description": "Teie pakett on edukalt ostetud"
},
"closed": {
"title": "Tellimus suletud",
"description": "Palun esitage uus tellimus"
},
"failed": {
"title": "Makse ebaõnnestus",
"description": "Palun proovige makset uuesti"
},
"unknown": {
"title": "Tundmatu olek",
"description": "Palun võtke ühendust klienditeenindusega"
},
"checkFailed": {
"title": "Kontroll ebaõnnestus",
"description": "Palun proovige hiljem uuesti"
},
"initial": {
"title": "Makset töödeldakse",
"description": "Palun oodake, kui töötleme teie makset"
}
},
"home": {
"welcome": "Tere tulemast Hi快VPN-i",
"disconnected": "Ühendus katkestatud",
"connecting": "Ühendumine",
"connected": "Ühendatud",
"disconnecting": "Ühenduse katkestamine",
"currentConnectionTitle": "Praegune ühendus",
"switchNode": "Vaheta sõlme",
"timeout": "Aegumine",
"loading": "Laadimine...",
"error": "Laadimise viga",
"checkNetwork": "Kontrollige võrguühendust ja proovige uuesti",
"retry": "Proovi uuesti",
"connectionSectionTitle": "Ühendusviis",
"dedicatedServers": "Pühendatud serverid",
"countryRegion": "Riik/Regioon",
"serverListTitle": "Pühendatud serverite grupid",
"nodeListTitle": "Kõik sõlmed",
"countryListTitle": "Riikide/Regioonide nimekiri",
"noServers": "Saadaval pole ühtegi serverit",
"noNodes": "Saadaval pole ühtegi sõlme",
"noRegions": "Saadaval pole ühtegi regiooni",
"subscriptionDescription": "Hankige premium juurdepääs kiirele globaalsele võrgustikule",
"subscribe": "Telli",
"trialPeriod": "Tere tulemast Premium prooviversiooni",
"remainingTime": "Järelejäänud aeg",
"trialExpired": "Prooviaeg on lõppenud, ühendus katkestatud",
"subscriptionExpired": "Tellimus on aegunud, ühendus katkestatud",
"subscriptionUpdated": "Tellimus värskendatud",
"subscriptionUpdatedMessage": "Teie tellimuse teave on värskendatud, värskendage viimase oleku vaatamiseks",
"trialStatus": "Proovi olek",
"trialing": "Proovimas",
"trialEndMessage": "Prooviaja lõppedes ei saa enam kasutada",
"lastDaySubscriptionStatus": "Tellimus aegub varsti",
"lastDaySubscriptionMessage": "Aegub varsti",
"subscriptionEndMessage": "Tellimuse lõppedes ei saa enam kasutada",
"trialTimeWithDays": "{days}p {hours}t {minutes}m {seconds}s",
"trialTimeWithHours": "{hours}t {minutes}m {seconds}s",
"trialTimeWithMinutes": "{minutes}m {seconds}s",
"refreshLatency": "Värskenda latentsust",
"testLatency": "Testi latentsust",
"testing": "Latentsuse testimine",
"refreshLatencyDesc": "Värskenda kõigi sõlmede latentsust",
"testAllNodesLatency": "Testi kõigi sõlmede võrgu latentsust",
"autoSelect": "Automaatne valik",
"selected": "Valitud"
},
"dialog": {
"confirm": "Kinnita",
"cancel": "Tühista",
"ok": "OK"
},
"splash": {
"appName": "Hi快VPN",
"slogan": "Kiire globaalne võrgustik",
"initializing": "Initsialiseerimine...",
"networkConnectionFailure": "Võrguühenduse viga, kontrollige ja proovige uuesti",
"retry": "Proovi uuesti",
"networkPermissionFailed": "Võrguõiguse hankimine ebaõnnestus",
"initializationFailed": "Initsialiseerimine ebaõnnestus"
},
"network": {
"status": {
"connected": "Ühendatud",
"disconnected": "Ühendus katkestatud",
"connecting": "Ühendumine...",
"disconnecting": "Ühenduse katkestamine...",
"reconnecting": "Ühenduse taastamine...",
"failed": "Ühenduse viga"
},
"permission": {
"title": "Võrguõigus",
"description": "VPN teenuse pakkumiseks on vaja võrguõigust",
"goToSettings": "Mine seadetesse",
"cancel": "Tühista"
}
},
"update": {
"title": "Uuendus saadaval",
"content": "Uuendada nüüd?",
"updateNow": "Uuenda nüüd",
"updateLater": "Hiljem",
"defaultContent": "1. Rakenduse jõudluse optimeerimine\n2. Teadaolevate probleemide parandamine\n3. Kasutajamugavuse parandamine"
},
"country": {
"cn": "Hiina",
"ir": "Iraan",
"af": "Afganistan",
"ru": "Venemaa",
"id": "Indoneesia",
"tr": "Türgi",
"br": "Brasiilia"
},
"error": {
"200": "Edukas",
"500": "Serveri sisemine viga",
"10001": "Andmebaasi päringu viga",
"10002": "Andmebaasi uuendamise viga",
"10003": "Andmebaasi sisestamise viga",
"10004": "Andmebaasi kustutamise viga",
"20001": "Kasutaja on juba olemas",
"20002": "Kasutajat pole olemas",
"20003": "Vale kasutaja parool",
"20004": "Kasutaja on keelatud",
"20005": "Ebapiisav saldo",
"20006": "Registreerimine peatatud",
"20007": "Telegram pole seotud",
"20008": "Kasutaja pole OAuth-i seostanud",
"20009": "Vale kutsekood",
"30001": "Sõlm on juba olemas",
"30002": "Sõlme pole olemas",
"30003": "Sõlme grupp on juba olemas",
"30004": "Sõlme gruppi pole olemas",
"30005": "Sõlme grupp pole tühi",
"400": "Parameetri viga",
"40002": "Kasutaja token on tühi",
"40003": "Vale kasutaja token",
"40004": "Kasutaja token on aegunud",
"40005": "Te pole sisse logitud",
"401": "Liiga palju päringuid",
"50001": "Kupongi pole olemas",
"50002": "Kupong on juba kasutatud",
"50003": "Kupong ei vasta",
"60001": "Tellimus on aegunud",
"60002": "Tellimus pole saadaval",
"60003": "Kasutajal on juba tellimus",
"60004": "Tellimus on juba kasutatud",
"60005": "Üksiku tellimuse režiimi limiit ületatud",
"60006": "Tellimuse kvoodi limiit",
"70001": "Vale kinnituskood",
"80001": "Järjekorda lisamise viga",
"90001": "Silumisrežiim on lubatud",
"90002": "SMS-i saatmise viga",
"90003": "SMS funktsioon pole lubatud",
"90004": "E-posti funktsioon pole lubatud",
"90005": "Toetamata sisselogimise meetod",
"90006": "Autentifikaator ei toeta seda meetodit",
"90007": "Telefoni riigi kood on tühi",
"90008": "Parool on tühi",
"90009": "Riigi kood on tühi",
"90010": "Parool või kinnituskood on vajalik",
"90011": "E-post on juba olemas",
"90012": "Telefoninumber on juba olemas",
"90013": "Seade on juba olemas",
"90014": "Vale telefoninumber",
"90015": "See konto on täna saavutanud saatmise limiidi",
"90017": "Seadet pole olemas",
"90018": "Kasutaja ID ei vasta",
"61001": "Tellimust pole olemas",
"61002": "Makseviisi ei leitud",
"61003": "Vale tellimuse olek",
"61004": "Ebapiisav lähtestamise periood",
"61005": "Kasutamata liiklus on olemas"
},
"tray": {
"open_dashboard": "Ava armatuurlaud",
"copy_to_terminal": "Kopeeri terminali",
"exit_app": "Välju rakendusest"
}
}

View File

@ -9,6 +9,7 @@
"enterEmail": "Please enter email address",
"enterCode": "認証コードを入力してください",
"enterPassword": "パスワードを入力してください",
"enterPasswordForPhone": "パスワードを入力してください (パスワードログイン)",
"reenterPassword": "パスワードを再入力してください",
"forgotPassword": "パスワードをお忘れの方",
"codeLogin": "認証コードでログイン",
@ -18,6 +19,8 @@
"privacyPolicy": "プライバシーポリシー",
"next": "次へ",
"registerNow": "今すぐ登録",
"registerAccount": "アカウント登録",
"clickToRegister": "クリックして登録",
"setAndLogin": "設定してログイン",
"enterAccount": "アカウントを入力してください",
"passwordMismatch": "2回のパスワード入力が一致しません",
@ -25,7 +28,9 @@
"codeSentCountdown": "認証コード送信済み {seconds}秒",
"and": "および",
"enterInviteCode": "招待コードを入力(任意)",
"registerSuccess": "登録成功"
"registerSuccess": "登録成功",
"search": "検索",
"selectOtherRegion": "他の地域を選択"
},
"failure": {
"unexpected": "予期せぬエラー",
@ -187,7 +192,8 @@
"friday": "金",
"saturday": "土",
"sunday": "日"
}
},
"processTrafficFailed": "トラフィックログデータの処理に失敗しました"
},
"message": {
"title": "通知",
@ -381,6 +387,7 @@
"initializing": "初期化中...",
"networkConnectionFailure": "ネットワーク接続エラー、確認して再試行してください",
"retry": "再試行",
"skip": "スキップ",
"networkPermissionFailed": "ネットワーク権限の取得に失敗しました",
"initializationFailed": "初期化に失敗しました"
},
@ -481,5 +488,33 @@
"open_dashboard": "ダッシュボードを開く",
"copy_to_terminal": "ターミナルにコピー",
"exit_app": "アプリを終了"
},
"crisp": {
"initializingSystem": "カスタマーサービスシステムを初期化しています...",
"initFailed": "カスタマーサービスシステムの初期化に失敗しました"
},
"common": {
"retry": "再試行",
"tryBrowser": "ブラウザで開いてみる",
"cannotOpenBrowser": "ブラウザを開けません",
"openLinkFailed": "リンクを開けませんでした。後でもう一度お試しください",
"cannotOpenTelegram": "Telegramリンクを開けません"
},
"subscribe": {
"pleaseSelectFirst": "最初にサブスクリプションを選択してください",
"resetPeriodFailed": "サブスクリプション期間のリセットに失敗しました",
"resetPeriodSuccess": "サブスクリプション期間が正常にリセットされました"
},
"purchase": {
"noAvailablePlans": "利用可能なプランはありません"
},
"payment": {
"cannotOpenLink": "支払いリンクを開けません",
"linkEmpty": "支払いリンクが空です",
"unsupportedType": "サポートされていない支払いタイプ"
},
"account": {
"accountRequired": "アカウントは空にできません",
"deleteSuccess": "アカウントが正常に削除されました"
}
}

View File

@ -1,441 +0,0 @@
{
"login": {
"welcome": "Hi快VPNへようこそ",
"verifyPhone": "電話番号を認証",
"verifyEmail": "メールアドレスを認証",
"codeSent": "{account}に6桁のコードを送信しました。30分以内に入力してください。",
"back": "戻る",
"enterEmailOrPhone": "メールアドレスまたは電話番号を入力",
"enterCode": "認証コードを入力してください",
"enterPassword": "パスワードを入力してください",
"reenterPassword": "パスワードを再入力してください",
"forgotPassword": "パスワードをお忘れの方",
"codeLogin": "認証コードでログイン",
"passwordLogin": "パスワードでログイン",
"agreeTerms": "ログイン/アカウント作成,に同意します",
"termsOfService": "利用規約",
"privacyPolicy": "プライバシーポリシー",
"next": "次へ",
"registerNow": "今すぐ登録",
"setAndLogin": "設定してログイン",
"enterAccount": "アカウントを入力してください",
"passwordMismatch": "2回のパスワード入力が一致しません",
"sendCode": "認証コードを送信",
"codeSentCountdown": "認証コード送信済み {seconds}秒",
"and": "および",
"enterInviteCode": "招待コードを入力(任意)",
"registerSuccess": "登録成功"
},
"failure": {
"unexpected": "予期せぬエラー",
"clash": {
"unexpected": "予期せぬエラー",
"core": "Clashエラー ${reason}"
},
"singbox": {
"unexpected": "予期せぬサービスエラー",
"serviceNotRunning": "サービスが実行されていません",
"missingPrivilege": "権限がありません",
"missingPrivilegeMsg": "VPNモードには管理者権限が必要です。管理者として再起動するか、サービスモードを変更してください",
"missingGeoAssets": "GEOリソースファイルがありません",
"missingGeoAssetsMsg": "GEOリソースファイルがありません。アクティブなリソースを変更するか、設定で選択したリソースをダウンロードしてください。",
"invalidConfigOptions": "設定オプションが無効です",
"invalidConfig": "無効な設定",
"create": "サービス作成エラー",
"start": "サービス起動エラー"
},
"connectivity": {
"unexpected": "予期せぬ失敗",
"missingVpnPermission": "VPN権限がありません",
"missingNotificationPermission": "通知権限がありません",
"core": "コアエラー"
},
"profiles": {
"unexpected": "予期せぬエラー",
"notFound": "プロファイルが見つかりません",
"invalidConfig": "無効な設定",
"invalidUrl": "無効なURL"
},
"connection": {
"unexpected": "予期せぬ接続エラー",
"timeout": "接続タイムアウト",
"badResponse": "不正なレスポンス",
"connectionError": "接続エラー",
"badCertificate": "無効な証明書"
},
"geoAssets": {
"unexpected": "予期せぬエラー",
"notUpdate": "利用可能な更新はありません",
"activeNotFound": "アクティブなGEOリソースファイルが見つかりません"
}
},
"userInfo": {
"title": "マイ情報",
"bindingTip": "メール/電話番号が未登録です",
"myAccount": "マイアカウント",
"balance": "残高",
"noValidSubscription": "有効なサブスクリプションがありません",
"subscribeNow": "今すぐ購読",
"shortcuts": "ショートカット",
"adBlock": "広告ブロック",
"dnsUnlock": "DNSアンロック",
"contactUs": "お問い合わせ",
"others": "その他",
"logout": "ログアウト",
"logoutConfirmTitle": "ログアウト",
"logoutConfirmMessage": "ログアウトしますか?",
"logoutCancel": "キャンセル",
"vpnWebsite": "VPN公式サイト",
"telegram": "Telegram",
"mail": "メール",
"phone": "電話",
"customerService": "カスタマーサービス",
"workOrder": "チケット送信",
"pleaseLogin": "ログインしてください",
"subscriptionValid": "サブスクリプション有効",
"startTime": "開始時間:",
"expireTime": "有効期限:",
"loginNow": "今すぐログイン",
"trialPeriod": "トライアル期間",
"remainingTime": "残り時間",
"trialExpired": "トライアル期間が終了しました",
"subscriptionExpired": "サブスクリプションが期限切れです",
"copySuccess": "コピーしました",
"notAvailable": "利用不可",
"willBeDeleted": "削除されます",
"deleteAccountWarning": "アカウントの削除は永久的です。アカウントを削除すると、すべての機能が使用できなくなります。続行しますか?",
"requestDelete": "削除をリクエスト",
"deviceLimit": "デバイス制限:{count}",
"reset": "リセット",
"trafficUsage": "トラフィック:{used} / {total}",
"trafficProgress": {
"title": "トラフィック使用状況",
"unlimited": "無制限",
"limited": "使用済み"
},
"switchSubscription": "サブスクリプションの切り替え",
"resetTrafficTitle": "トラフィックリセット",
"resetTrafficMessage": "月間プランのトラフィックリセット例:次のサイクルのトラフィックを月次でリセットし、サブスクリプションの有効期限が{currentTime}から{newTime}に繰り上げられます",
"trialStatus": "トライアル状態",
"trialing": "トライアル中",
"trialEndMessage": "トライアル期間終了後は使用できなくなります",
"lastDaySubscriptionStatus": "サブスクリプション期限切れ間近",
"lastDaySubscriptionMessage": "期限切れ間近",
"subscriptionEndMessage": "サブスクリプション終了後は使用できなくなります",
"trialTimeWithDays": "{days}日{hours}時間{minutes}分{seconds}秒",
"trialTimeWithHours": "{hours}時間{minutes}分{seconds}秒",
"trialTimeWithMinutes": "{minutes}分{seconds}秒",
"refreshLatency": "レイテンシーを更新",
"testLatency": "レイテンシーテスト",
"testing": "レイテンシーテスト中",
"refreshLatencyDesc": "すべてのノードのレイテンシーを更新",
"testAllNodesLatency": "すべてのノードのネットワークレイテンシーをテスト",
"autoSelect": "自動選択",
"selected": "選択済み"
},
"setting": {
"title": "設定",
"vpnConnection": "VPN接続",
"countrySelector": "国を選択",
"general": "一般",
"autoConnect": "自動接続",
"routeRule": "ルーティングルール",
"appearance": "外観",
"notifications": "通知",
"helpImprove": "改善にご協力ください",
"helpImproveSubtitle": "改善にご協力くださいサブタイトル",
"requestDeleteAccount": "アカウント削除をリクエスト",
"goToDelete": "削除へ",
"rateUs": "App Storeで評価する",
"iosRating": "iOS評価",
"version": "バージョン",
"switchLanguage": "言語を切り替え",
"system": "システム",
"light": "ライト",
"dark": "ダーク",
"vpnModeSmart": "スマートモード",
"mode": "アウトバウンドモード",
"connectionTypeGlobal": "グローバルプロキシ",
"connectionTypeGlobalRemark": "有効時、すべてのトラフィックはプロキシ経由でルーティングされます",
"connectionTypeRule": "スマートプロキシ",
"connectionTypeRuleRemark": "[アウトバウンドモード]が[スマートプロキシ]に設定されている場合、システムは選択された国に基づいて国内と海外のトラフィックを自動的に分割します国内IP/ドメインは直接接続、海外リクエストはプロキシ経由でアクセス",
"connectionTypeDirect": "ダイレクト接続",
"connectionTypeDirectRemark": "有効時、すべてのトラフィックはプロキシをバイパスします",
"smartMode": "スマートモード",
"secureMode": "セキュアモード"
},
"statistics": {
"title": "統計",
"vpnStatus": "VPNステータス",
"ipAddress": "IPアドレス",
"connectionTime": "接続時間",
"protocol": "プロトコル",
"weeklyProtectionTime": "週間保護時間",
"currentStreak": "現在の連続記録",
"highestStreak": "最高記録",
"longestConnection": "最長接続時間",
"days": "{days}日",
"daysOfWeek": {
"monday": "月",
"tuesday": "火",
"wednesday": "水",
"thursday": "木",
"friday": "金",
"saturday": "土",
"sunday": "日"
}
},
"message": {
"title": "通知",
"system": "システムメッセージ",
"promotion": "プロモーションメッセージ"
},
"invite": {
"title": "友達を招待",
"progress": "招待の進捗",
"inviteStats": "招待統計",
"registers": "登録済み",
"totalCommission": "総報酬",
"rewardDetails": "報酬の詳細 >",
"steps": "招待の手順",
"inviteFriend": "友達を招待",
"acceptInvite": "友達が招待を受け入れ\n注文して登録",
"getReward": "報酬を獲得",
"shareLink": "リンクを共有",
"shareQR": "QRコードを共有",
"rules": "招待ルール",
"rule1": "1. 専用の招待リンクまたは招待コードを共有して、友達を招待できます。",
"rule2": "2. 友達が登録とログインを完了すると、招待報酬が自動的にアカウントに付与されます。",
"pending": "保留中",
"processing": "処理中",
"success": "成功",
"expired": "期限切れ",
"myInviteCode": "招待コード",
"inviteCodeCopied": "招待コードをクリップボードにコピーしました",
"close": "閉じる",
"saveQRCode": "QRコードを保存",
"qrCodeSaved": "QRコードを保存しました",
"copiedToClipboard": "クリップボードにコピーしました",
"getInviteCodeFailed": "招待コードの取得に失敗しました。後ほど再試行してください",
"generateQRCodeFailed": "QRコードの生成に失敗しました。後ほど再試行してください",
"generateShareLinkFailed": "共有リンクの生成に失敗しました。後ほど再試行してください"
},
"purchaseMembership": {
"purchasePackage": "パッケージ購入",
"noData": "利用可能なパッケージはありません",
"myAccount": "マイアカウント",
"selectPackage": "パッケージを選択",
"packageDescription": "パッケージ説明",
"paymentMethod": "支払い方法",
"cancelAnytime": "アプリでいつでもキャンセル可能",
"startSubscription": "サブスクリプションを開始",
"renewNow": "今すぐ更新",
"month": "{months}ヶ月",
"year": "{years}年",
"day": "{days}日",
"unlimitedTraffic": "無制限トラフィック",
"unlimitedDevices": "無制限デバイス",
"devices": "{count}台",
"features": "パッケージ機能",
"expand": "展開",
"collapse": "折りたたむ",
"confirmPurchase": "購入を確認",
"confirmPurchaseDesc": "このパッケージを購入してもよろしいですか?",
"subscriptionPrivacyInfo": "サブスクリプションとプライバシー情報"
},
"orderStatus": {
"title": "注文状態",
"pending": {
"title": "支払い待ち",
"description": "支払いを完了してください"
},
"paid": {
"title": "支払い完了",
"description": "注文を処理中です"
},
"success": {
"title": "おめでとうございます!支払い成功",
"description": "パッケージの購入が完了しました"
},
"closed": {
"title": "注文キャンセル",
"description": "新規注文をお願いします"
},
"failed": {
"title": "支払い失敗",
"description": "支払いを再試行してください"
},
"unknown": {
"title": "不明な状態",
"description": "カスタマーサービスにお問い合わせください"
},
"checkFailed": {
"title": "確認失敗",
"description": "後でもう一度お試しください"
},
"initial": {
"title": "支払い処理中",
"description": "支払い処理中です。お待ちください"
}
},
"home": {
"welcome": "Hi快VPNへようこそ",
"disconnected": "未接続",
"connecting": "接続中",
"connected": "接続済み",
"disconnecting": "切断中",
"currentConnectionTitle": "現在の接続",
"switchNode": "ノード切替",
"timeout": "タイムアウト",
"loading": "読み込み中...",
"error": "読み込みエラー",
"checkNetwork": "ネットワーク接続を確認して再試行してください",
"retry": "再試行",
"connectionSectionTitle": "接続方法",
"dedicatedServers": "専用サーバー",
"countryRegion": "国/地域",
"serverListTitle": "専用サーバーグループ",
"nodeListTitle": "全ノード",
"countryListTitle": "国/地域リスト",
"noServers": "利用可能なサーバーがありません",
"noNodes": "利用可能なノードがありません",
"noRegions": "利用可能な地域がありません",
"subscriptionDescription": "プレミアムアクセスで高速グローバルネットワークを利用",
"subscribe": "購読する",
"trialPeriod": "プレミアムトライアルへようこそ",
"remainingTime": "残り時間",
"trialExpired": "トライアル期間が終了し、接続が切断されました",
"subscriptionExpired": "サブスクリプションが期限切れとなり、接続が切断されました",
"subscriptionUpdated": "サブスクリプションが更新されました",
"subscriptionUpdatedMessage": "サブスクリプション情報が更新されました。最新の状態を確認するには更新してください",
"trialStatus": "トライアル状態",
"trialing": "トライアル中",
"trialEndMessage": "トライアル期間終了後は使用できなくなります",
"lastDaySubscriptionStatus": "サブスクリプション期限切れ間近",
"lastDaySubscriptionMessage": "期限切れ間近",
"subscriptionEndMessage": "サブスクリプション終了後は使用できなくなります",
"trialTimeWithDays": "{days}日{hours}時間{minutes}分{seconds}秒",
"trialTimeWithHours": "{hours}時間{minutes}分{seconds}秒",
"trialTimeWithMinutes": "{minutes}分{seconds}秒",
"refreshLatency": "レイテンシー更新",
"testLatency": "レイテンシーテスト",
"testing": "レイテンシーテスト中",
"refreshLatencyDesc": "全ノードのレイテンシーを更新",
"testAllNodesLatency": "全ノードのネットワークレイテンシーをテスト",
"autoSelect": "自動選択",
"selected": "選択済み"
},
"dialog": {
"confirm": "確認",
"cancel": "キャンセル",
"ok": "OK",
"iKnow": "分かりました"
},
"splash": {
"appName": "Hi快VPN",
"slogan": "高速グローバルネットワーク",
"initializing": "初期化中...",
"networkConnectionFailure": "ネットワーク接続エラー、確認して再試行してください",
"retry": "再試行",
"networkPermissionFailed": "ネットワーク権限の取得に失敗しました",
"initializationFailed": "初期化に失敗しました"
},
"network": {
"status": {
"connected": "接続済み",
"disconnected": "未接続",
"connecting": "接続中...",
"disconnecting": "切断中...",
"reconnecting": "再接続中...",
"failed": "接続エラー"
},
"permission": {
"title": "ネットワーク権限",
"description": "VPNサービスを提供するにはネットワーク権限が必要です",
"goToSettings": "設定へ",
"cancel": "キャンセル"
}
},
"update": {
"title": "アップデートが利用可能",
"content": "今すぐアップデートしますか?",
"updateNow": "今すぐアップデート",
"updateLater": "後で",
"defaultContent": "1. アプリのパフォーマンス最適化\n2. 既知の問題の修正\n3. ユーザー体験の向上"
},
"country": {
"cn": "中国",
"ir": "イラン",
"af": "アフガニスタン",
"ru": "ロシア",
"id": "インドネシア",
"tr": "トルコ",
"br": "ブラジル"
},
"error": {
"200": "成功",
"500": "サーバー内部エラー",
"10001": "データベースクエリエラー",
"10002": "データベース更新エラー",
"10003": "データベース挿入エラー",
"10004": "データベース削除エラー",
"20001": "ユーザーは既に存在します",
"20002": "ユーザーが存在しません",
"20003": "ユーザーパスワードが間違っています",
"20004": "ユーザーは無効化されています",
"20005": "残高不足",
"20006": "登録は停止されています",
"20007": "Telegramが未連携です",
"20008": "ユーザーがOAuthを連携していません",
"20009": "招待コードが間違っています",
"30001": "ノードは既に存在します",
"30002": "ノードが存在しません",
"30003": "ノードグループは既に存在します",
"30004": "ノードグループが存在しません",
"30005": "ノードグループは空ではありません",
"400": "パラメータエラー",
"40002": "ユーザートークンが空です",
"40003": "ユーザートークンが無効です",
"40004": "ユーザートークンの有効期限が切れています",
"40005": "ログインしていません",
"401": "リクエストが多すぎます",
"50001": "クーポンが存在しません",
"50002": "クーポンは既に使用されています",
"50003": "クーポンが一致しません",
"60001": "サブスクリプションの有効期限が切れています",
"60002": "サブスクリプションは利用できません",
"60003": "ユーザーは既にサブスクリプションを持っています",
"60004": "サブスクリプションは既に使用されています",
"60005": "単一サブスクリプションモードの制限を超えています",
"60006": "サブスクリプションクォータ制限",
"70001": "認証コードが間違っています",
"80001": "キューイングエラー",
"90001": "デバッグモードが有効です",
"90002": "SMS送信エラー",
"90003": "SMS機能が有効になっていません",
"90004": "メール機能が有効になっていません",
"90005": "サポートされていないログイン方法",
"90006": "認証器がこの方法をサポートしていません",
"90007": "電話国番号が空です",
"90008": "パスワードが空です",
"90009": "国番号が空です",
"90010": "パスワードまたは認証コードが必要です",
"90011": "メールアドレスは既に存在します",
"90012": "電話番号は既に存在します",
"90013": "デバイスは既に存在します",
"90014": "電話番号が間違っています",
"90015": "このアカウントは本日の送信制限に達しました",
"90017": "デバイスが存在しません",
"90018": "ユーザーIDが一致しません",
"61001": "注文が存在しません",
"61002": "支払い方法が見つかりません",
"61003": "注文状態が間違っています",
"61004": "リセット期間が不足しています",
"61005": "未使用のトラフィックが存在します"
},
"tray": {
"open_dashboard": "ダッシュボードを開く",
"copy_to_terminal": "ターミナルにコピー",
"exit_app": "アプリを終了"
}
}

View File

@ -9,6 +9,7 @@
"enterEmail": "Please enter email address",
"enterCode": "Введите код подтверждения",
"enterPassword": "Введите пароль",
"enterPasswordForPhone": "Пожалуйста, введите пароль (Вход с паролем)",
"reenterPassword": "Повторите пароль",
"forgotPassword": "Забыли пароль",
"codeLogin": "Вход по коду",
@ -18,6 +19,8 @@
"privacyPolicy": "Политикой конфиденциальности",
"next": "Далее",
"registerNow": "Зарегистрироваться",
"registerAccount": "Зарегистрировать аккаунт",
"clickToRegister": "Нажмите, чтобы зарегистрироваться",
"setAndLogin": "Установить и войти",
"enterAccount": "Введите аккаунт",
"passwordMismatch": "Два введенных пароля не совпадают",
@ -25,7 +28,9 @@
"codeSentCountdown": "Код отправлен {seconds}с",
"and": "и",
"enterInviteCode": "Введите код приглашения (необязательно)",
"registerSuccess": "Регистрация успешна"
"registerSuccess": "Регистрация успешна",
"search": "Поиск",
"selectOtherRegion": "Выбрать другой регион"
},
"failure": {
"unexpected": "Непредвиденная ошибка",
@ -187,7 +192,8 @@
"friday": "Пт",
"saturday": "Сб",
"sunday": "Вс"
}
},
"processTrafficFailed": "Не удалось обработать данные журнала трафика"
},
"message": {
"title": "Уведомления",
@ -464,6 +470,7 @@
"initializing": "Инициализация...",
"networkConnectionFailure": "Ошибка подключения к сети, проверьте и повторите попытку",
"retry": "Повторить",
"skip": "Пропустить",
"networkPermissionFailed": "Не удалось получить разрешение на использование сети",
"initializationFailed": "Ошибка инициализации"
},
@ -482,5 +489,33 @@
"goToSettings": "Перейти в настройки",
"cancel": "Отмена"
}
},
"crisp": {
"initializingSystem": "Инициализация системы обслуживания клиентов...",
"initFailed": "Не удалось инициализировать систему обслуживания клиентов"
},
"common": {
"retry": "Повторить",
"tryBrowser": "Попробовать открыть в браузере",
"cannotOpenBrowser": "Не удается открыть браузер",
"openLinkFailed": "Не удалось открыть ссылку, попробуйте позже",
"cannotOpenTelegram": "Не удается открыть ссылку Telegram"
},
"subscribe": {
"pleaseSelectFirst": "Сначала выберите подписку",
"resetPeriodFailed": "Не удалось сбросить период подписки",
"resetPeriodSuccess": "Период подписки успешно сброшен"
},
"purchase": {
"noAvailablePlans": "Нет доступных планов"
},
"payment": {
"cannotOpenLink": "Не удается открыть ссылку для оплаты",
"linkEmpty": "Ссылка для оплаты пуста",
"unsupportedType": "Неподдерживаемый тип оплаты"
},
"account": {
"accountRequired": "Учетная запись не может быть пустой",
"deleteSuccess": "Учетная запись успешно удалена"
}
}

View File

@ -1,442 +0,0 @@
{
"login": {
"welcome": "Добро пожаловать в Hi快VPN!",
"verifyPhone": "Подтвердите номер телефона",
"verifyEmail": "Подтвердите email",
"codeSent": "6-значный код отправлен на {account}. Введите его в течение 30 минут.",
"back": "Назад",
"enterEmailOrPhone": "Введите email или номер телефона",
"enterCode": "Введите код подтверждения",
"enterPassword": "Введите пароль",
"reenterPassword": "Повторите пароль",
"forgotPassword": "Забыли пароль",
"codeLogin": "Вход по коду",
"passwordLogin": "Вход по паролю",
"agreeTerms": "Вход/Создать аккаунт, я соглашаюсь с",
"termsOfService": "Условиями использования",
"privacyPolicy": "Политикой конфиденциальности",
"next": "Далее",
"registerNow": "Зарегистрироваться",
"setAndLogin": "Установить и войти",
"enterAccount": "Введите аккаунт",
"passwordMismatch": "Два введенных пароля не совпадают",
"sendCode": "Отправить код",
"codeSentCountdown": "Код отправлен {seconds}с",
"and": "и",
"enterInviteCode": "Введите код приглашения (необязательно)",
"registerSuccess": "Регистрация успешна"
},
"failure": {
"unexpected": "Непредвиденная ошибка",
"clash": {
"unexpected": "Непредвиденная ошибка",
"core": "Ошибка Clash ${reason}"
},
"singbox": {
"unexpected": "Непредвиденная ошибка сервиса",
"serviceNotRunning": "Сервис не запущен",
"missingPrivilege": "Отсутствуют привилегии",
"missingPrivilegeMsg": "Режим VPN требует прав администратора. Перезапустите приложение с правами администратора или измените режим сервиса",
"missingGeoAssets": "Отсутствуют GEO-ресурсы",
"missingGeoAssetsMsg": "Отсутствуют файлы GEO-ресурсов. Измените активные ресурсы или загрузите выбранные ресурсы в настройках.",
"invalidConfigOptions": "Недопустимые параметры конфигурации",
"invalidConfig": "Недопустимая конфигурация",
"create": "Ошибка создания сервиса",
"start": "Ошибка запуска сервиса"
},
"connectivity": {
"unexpected": "Непредвиденный сбой",
"missingVpnPermission": "Отсутствует разрешение VPN",
"missingNotificationPermission": "Отсутствует разрешение на уведомления",
"core": "Ошибка ядра"
},
"profiles": {
"unexpected": "Непредвиденная ошибка",
"notFound": "Профиль не найден",
"invalidConfig": "Недопустимая конфигурация",
"invalidUrl": "Недопустимый URL"
},
"connection": {
"unexpected": "Непредвиденная ошибка подключения",
"timeout": "Тайм-аут подключения",
"badResponse": "Некорректный ответ",
"connectionError": "Ошибка подключения",
"badCertificate": "Недействительный сертификат"
},
"geoAssets": {
"unexpected": "Непредвиденная ошибка",
"notUpdate": "Нет доступных обновлений",
"activeNotFound": "Активные GEO-ресурсы не найдены"
}
},
"userInfo": {
"title": "Моя информация",
"bindingTip": "Email/телефон не привязаны",
"myAccount": "Мой аккаунт",
"balance": "Баланс",
"noValidSubscription": "Нет активной подписки",
"subscribeNow": "Подписаться сейчас",
"shortcuts": "Ярлыки",
"adBlock": "Блокировка рекламы",
"dnsUnlock": "Разблокировка DNS",
"contactUs": "Связаться с нами",
"others": "Прочее",
"logout": "Выйти",
"logoutConfirmTitle": "Выйти",
"logoutConfirmMessage": "Вы уверены, что хотите выйти?",
"logoutCancel": "Отмена",
"vpnWebsite": "Сайт VPN",
"telegram": "Telegram",
"mail": "Email",
"phone": "Телефон",
"customerService": "Служба поддержки",
"workOrder": "Создать заявку",
"pleaseLogin": "Пожалуйста, войдите",
"subscriptionValid": "Подписка активна",
"startTime": "Время начала:",
"expireTime": "Срок действия:",
"loginNow": "Войти сейчас",
"trialPeriod": "Добро пожаловать в пробную версию Premium",
"remainingTime": "Осталось времени",
"trialExpired": "Пробный период истёк, соединение разорвано",
"subscriptionExpired": "Подписка истекла, соединение разорвано",
"switchSubscription": "Сменить подписку",
"resetTrafficTitle": "Сброс трафика",
"resetTrafficMessage": "Пример сброса трафика месячного плана: сброс трафика следующего цикла ежемесячно, и срок действия подписки будет перенесен с {currentTime} на {newTime}",
"reset": "Сбросить",
"trafficUsage": "Использовано: {used} / {total}",
"trafficProgress": {
"title": "Использование трафика",
"unlimited": "Безлимитный трафик",
"limited": "Использованный трафик"
},
"deviceLimit": "Лимит устройств: {count}",
"copySuccess": "Скопировано успешно",
"notAvailable": "Недоступно",
"willBeDeleted": "Будет удалено",
"deleteAccountWarning": "Удаление аккаунта необратимо. После удаления аккаунта вы не сможете использовать все функции. Продолжить?",
"requestDelete": "Запросить удаление",
"trialStatus": "Статус пробного периода",
"trialing": "Пробный период",
"trialEndMessage": "После окончания пробного периода использование будет невозможно",
"lastDaySubscriptionStatus": "Подписка скоро истечет",
"lastDaySubscriptionMessage": "Скоро истечет",
"subscriptionEndMessage": "После окончания подписки использование будет невозможно",
"trialTimeWithDays": "{days}д {hours}ч {minutes}м {seconds}с",
"trialTimeWithHours": "{hours}ч {minutes}м {seconds}с",
"trialTimeWithMinutes": "{minutes}м {seconds}с",
"refreshLatency": "Обновить задержку",
"testLatency": "Тест задержки",
"testing": "Тестирование задержки",
"refreshLatencyDesc": "Обновить задержку всех узлов",
"testAllNodesLatency": "Тест сетевой задержки всех узлов",
"autoSelect": "Автоматический выбор",
"selected": "Выбрано"
},
"setting": {
"title": "Настройки",
"countrySelector": "Выбрать страну",
"vpnConnection": "VPN-подключение",
"general": "Общие",
"autoConnect": "Автоподключение",
"routeRule": "Правила маршрутизации",
"appearance": "Внешний вид",
"notifications": "Уведомления",
"helpImprove": "Помогите нам улучшить",
"helpImproveSubtitle": "Подзаголовок помощи в улучшении",
"requestDeleteAccount": "Запросить удаление аккаунта",
"goToDelete": "Перейти к удалению",
"rateUs": "Оцените нас в App Store",
"iosRating": "Оценка iOS",
"version": "Версия",
"switchLanguage": "Сменить язык",
"system": "Система",
"light": "Светлая",
"dark": "Тёмная",
"vpnModeSmart": "Умный режим",
"mode": "Исходящий режим",
"connectionTypeGlobal": "Глобальный прокси",
"connectionTypeGlobalRemark": "При включении весь трафик проходит через прокси",
"connectionTypeRule": "Умный прокси",
"connectionTypeRuleRemark": "Когда [Исходящий режим] установлен на [Умный прокси], система автоматически разделяет внутренний и международный трафик в соответствии с выбранной страной: внутренние IP/домены подключаются напрямую, а зарубежные запросы проходят через прокси",
"connectionTypeDirect": "Прямое подключение",
"connectionTypeDirectRemark": "При включении весь трафик обходит прокси",
"smartMode": "Умный режим",
"secureMode": "Безопасный режим"
},
"statistics": {
"title": "Статистика",
"vpnStatus": "Статус VPN",
"ipAddress": "IP-адрес",
"connectionTime": "Время подключения",
"protocol": "Протокол",
"weeklyProtectionTime": "Время защиты за неделю",
"currentStreak": "Текущая серия",
"highestStreak": "Рекорд",
"longestConnection": "Самое долгое подключение",
"days": "{days} дн.",
"daysOfWeek": {
"monday": "Пн",
"tuesday": "Вт",
"wednesday": "Ср",
"thursday": "Чт",
"friday": "Пт",
"saturday": "Сб",
"sunday": "Вс"
}
},
"message": {
"title": "Уведомления",
"system": "Системные сообщения",
"promotion": "Рекламные сообщения"
},
"invite": {
"title": "Пригласить друзей",
"progress": "Прогресс приглашений",
"inviteStats": "Статистика приглашений",
"registers": "Зарегистрировано",
"totalCommission": "Общая комиссия",
"rewardDetails": "Детали вознаграждения >",
"steps": "Шаги Приглашения",
"inviteFriend": "Пригласить Друзей",
"acceptInvite": "Друзья принимают приглашение",
"getReward": "Получить Вознаграждение",
"shareLink": "Поделиться Ссылкой",
"shareQR": "Поделиться QR-кодом",
"rules": "Правила Приглашения",
"rule1": "1. Вы можете приглашать друзей присоединиться к нам, поделившись своей уникальной ссылкой или кодом приглашения.",
"rule2": "2. После того, как друзья завершат регистрацию и войдут в систему, вознаграждения за приглашение будут автоматически зачислены на ваш счет.",
"pending": "В Ожидании",
"processing": "В Обработке",
"success": "Успешно",
"expired": "Истекло",
"myInviteCode": "Мой Код Приглашения",
"inviteCodeCopied": "Код приглашения скопирован в буфер обмена",
"close": "Закрыть",
"saveQRCode": "Сохранить QR-код",
"qrCodeSaved": "QR-код сохранен",
"copiedToClipboard": "Скопировано в буфер обмена",
"getInviteCodeFailed": "Не удалось получить код приглашения, попробуйте позже",
"generateQRCodeFailed": "Не удалось сгенерировать QR-код, попробуйте позже",
"generateShareLinkFailed": "Не удалось сгенерировать ссылку для общего доступа, попробуйте позже"
},
"purchaseMembership": {
"purchasePackage": "Купить Пакет",
"noData": "Нет доступных пакетов",
"myAccount": "Мой Аккаунт",
"selectPackage": "Выбрать Пакет",
"packageDescription": "Описание Пакета",
"paymentMethod": "Способ Оплаты",
"cancelAnytime": "Вы можете отменить в любое время в приложении",
"startSubscription": "Начать Подписку",
"subscriptionPrivacyInfo": "Информация о Подписке и Конфиденциальности",
"month": "{months} Месяц(ев)",
"year": "{years} Год(а)",
"day": "{days} день",
"unlimitedTraffic": "Безлимитный трафик",
"unlimitedDevices": "Безлимитные устройства",
"devices": "{count} устройств",
"trafficLimit": "Ограничение трафика",
"deviceLimit": "Лимит устройств: {count}",
"features": "Функции пакета",
"expand": "Развернуть",
"collapse": "Свернуть",
"confirmPurchase": "Подтвердить покупку",
"confirmPurchaseDesc": "Вы уверены, что хотите приобрести этот пакет?"
},
"orderStatus": {
"title": "Статус заказа",
"pending": {
"title": "Ожидание оплаты",
"description": "Пожалуйста, завершите оплату"
},
"paid": {
"title": "Оплата получена",
"description": "Обработка вашего заказа"
},
"success": {
"title": "Поздравляем! Оплата успешна",
"description": "Ваш пакет успешно приобретен"
},
"closed": {
"title": "Заказ закрыт",
"description": "Пожалуйста, сделайте новый заказ"
},
"failed": {
"title": "Ошибка оплаты",
"description": "Пожалуйста, попробуйте оплату снова"
},
"unknown": {
"title": "Неизвестный статус",
"description": "Пожалуйста, свяжитесь со службой поддержки"
},
"checkFailed": {
"title": "Ошибка проверки",
"description": "Пожалуйста, попробуйте позже"
},
"initial": {
"title": "Обработка оплаты",
"description": "Пожалуйста, подождите, пока мы обрабатываем вашу оплату"
}
},
"home": {
"welcome": "Добро пожаловать в Hi快VPN",
"disconnected": "Не подключено",
"connecting": "Подключение",
"connected": "Подключено",
"disconnecting": "Отключение",
"currentConnectionTitle": "Текущее подключение",
"switchNode": "Сменить узел",
"timeout": "Тайм-аут",
"loading": "Загрузка...",
"error": "Ошибка загрузки",
"checkNetwork": "Проверьте подключение к сети и повторите попытку",
"retry": "Повторить",
"connectionSectionTitle": "Способ подключения",
"dedicatedServers": "Выделенные серверы",
"countryRegion": "Страна/Регион",
"serverListTitle": "Группы выделенных серверов",
"nodeListTitle": "Все узлы",
"countryListTitle": "Список стран/регионов",
"noServers": "Нет доступных серверов",
"noNodes": "Нет доступных узлов",
"noRegions": "Нет доступных регионов",
"subscriptionDescription": "Подпишитесь для доступа к глобальной высокоскоростной сети",
"subscribe": "Подписаться сейчас",
"trialPeriod": "Добро пожаловать в пробную версию Premium",
"remainingTime": "Осталось времени",
"trialExpired": "Пробный период истёк, соединение разорвано",
"subscriptionExpired": "Подписка истекла, соединение разорвано",
"subscriptionUpdated": "Подписка обновлена",
"subscriptionUpdatedMessage": "Ваша информация о подписке обновлена, пожалуйста, обновите страницу для просмотра последнего статуса",
"trialStatus": "Статус пробного периода",
"trialing": "Пробный период",
"trialEndMessage": "После окончания пробного периода сервис будет недоступен",
"lastDaySubscriptionStatus": "Подписка скоро истекает",
"lastDaySubscriptionMessage": "Скоро истекает",
"subscriptionEndMessage": "После окончания подписки сервис будет недоступен",
"trialTimeWithDays": "{days}д {hours}ч {minutes}м {seconds}с",
"trialTimeWithHours": "{hours}ч {minutes}м {seconds}с",
"trialTimeWithMinutes": "{minutes}м {seconds}с",
"testLatency": "Тест задержки",
"testing": "Тестирование задержки",
"refreshLatency": "Обновить задержку",
"refreshLatencyDesc": "Обновить задержку всех узлов",
"testAllNodesLatency": "Тест сетевой задержки всех узлов",
"autoSelect": "Автоматический выбор",
"selected": "Выбрано"
},
"dialog": {
"confirm": "Подтвердить",
"cancel": "Отмена",
"ok": "OK",
"iKnow": "Я понял"
},
"update": {
"title": "Доступна новая версия",
"content": "Хотите обновить сейчас?",
"updateNow": "Обновить сейчас",
"later": "Позже",
"defaultContent": "1. Оптимизация производительности приложения\n2. Исправление известных проблем\n3. Улучшение пользовательского опыта"
},
"country": {
"cn": "Китай",
"ir": "Иран",
"af": "Афганистан",
"ru": "Россия",
"id": "Индонезия",
"tr": "Турция",
"br": "Бразилия"
},
"error": {
"200": "Успех",
"500": "Внутренняя ошибка сервера",
"10001": "Ошибка запроса базы данных",
"10002": "Ошибка обновления базы данных",
"10003": "Ошибка вставки в базу данных",
"10004": "Ошибка удаления из базы данных",
"20001": "Пользователь уже существует",
"20002": "Пользователь не существует",
"20003": "Ошибка пароля пользователя",
"20004": "Пользователь отключен",
"20005": "Недостаточно средств",
"20006": "Регистрация остановлена",
"20007": "Telegram не привязан",
"20008": "Пользователь не привязал метод OAuth",
"20009": "Ошибка кода приглашения",
"30001": "Узел уже существует",
"30002": "Узел не существует",
"30003": "Группа узлов уже существует",
"30004": "Группа узлов не существует",
"30005": "Группа узлов не пуста",
"400": "Ошибка параметра",
"40002": "Токен пользователя пуст",
"40003": "Токен пользователя недействителен",
"40004": "Срок действия токена пользователя истек",
"40005": "Недопустимый доступ",
"401": "Слишком много запросов",
"50001": "Купон не существует",
"50002": "Купон был использован",
"50003": "Купон не совпадает",
"60001": "Подписка истекла",
"60002": "Подписка недоступна",
"60003": "У пользователя уже есть подписка",
"60004": "Подписка уже использована",
"60005": "Режим одной подписки превышает лимит",
"60006": "Лимит квоты подписки",
"70001": "Ошибка кода подтверждения",
"80001": "Ошибка постановки в очередь",
"90001": "Режим отладки включен",
"90002": "Ошибка отправки SMS",
"90003": "SMS не включены",
"90004": "Электронная почта не включена",
"90005": "Неподдерживаемый метод входа",
"90006": "Аутентификатор не поддерживает этот метод",
"90007": "Код телефонного региона пуст",
"90008": "Пароль пуст",
"90009": "Код региона пуст",
"90010": "Требуется пароль или код подтверждения",
"90011": "Электронная почта уже существует",
"90012": "Телефон уже существует",
"90013": "Устройство уже существует",
"90014": "Ошибка номера телефона",
"90015": "Этот аккаунт достиг лимита отправки на сегодня",
"90017": "Устройство не существует",
"90018": "ID пользователя не совпадает",
"61001": "Заказ не существует",
"61002": "Способ оплаты не найден",
"61003": "Ошибка статуса заказа",
"61004": "Недостаточный период сброса",
"61005": "Существует неиспользованный трафик"
},
"tray": {
"open_dashboard": "Открыть панель",
"copy_to_terminal": "Копировать в терминал",
"exit_app": "Выйти из приложения"
},
"splash": {
"appName": "Hi快VPN",
"slogan": "Высокоскоростная глобальная сеть",
"initializing": "Инициализация...",
"networkConnectionFailure": "Ошибка подключения к сети, проверьте и повторите попытку",
"retry": "Повторить",
"networkPermissionFailed": "Не удалось получить разрешение на использование сети",
"initializationFailed": "Ошибка инициализации"
},
"network": {
"status": {
"connected": "Подключено",
"disconnected": "Отключено",
"connecting": "Подключение...",
"disconnecting": "Отключение...",
"reconnecting": "Переподключение...",
"failed": "Ошибка подключения"
},
"permission": {
"title": "Разрешение сети",
"description": "Требуется разрешение на использование сети для предоставления VPN-сервиса",
"goToSettings": "Перейти в настройки",
"cancel": "Отмена"
}
}
}

View File

@ -56,6 +56,7 @@
"enterEmail": "请输入电子邮箱",
"enterCode": "请输入验证码",
"enterPassword": "请输入密码",
"enterPasswordForPhone": "请输入密码 (密码登录)",
"reenterPassword": "请再次输入密码",
"forgotPassword": "忘记密码",
"codeLogin": "验证码登录",
@ -65,6 +66,8 @@
"privacyPolicy": "隐私政策",
"next": "下一步",
"registerNow": "立即注册",
"registerAccount": "注册账号",
"clickToRegister": "点我注册",
"setAndLogin": "设置并登录",
"enterAccount": "请输入账户",
"passwordMismatch": "两次密码输入不一致",
@ -73,6 +76,8 @@
"and": "和",
"enterInviteCode": "请输入邀请码",
"registerSuccess": "注册成功"
"search": "搜索",
"selectOtherRegion": "选择其他地区"
},
"failure": {
"unexpected": "意外错误",
@ -234,7 +239,8 @@
"friday": "周\n五",
"saturday": "周\n六",
"sunday": "周\n日"
}
},
"processTrafficFailed": "处理流量日志数据失败"
},
"message": {
"title": "通知",
@ -264,6 +270,7 @@
"myInviteCode": "我的邀请码",
"inviteCodeCopied": "邀请码已复制到剪贴板",
"close": "关闭",
"pleaseLoginFirst": "请先登录后查看邀请码",
"saveQRCode": "保存二维码",
"qrCodeSaved": "二维码已保存",
"copiedToClipboard": "已复制到剪贴板",
@ -383,6 +390,7 @@
"initializing": "正在初始化...",
"networkConnectionFailure": "网络连接失败,请检查并重试",
"retry": "重试",
"skip": "跳过",
"networkPermissionFailed": "获取网络权限失败",
"initializationFailed": "初始化失败"
},
@ -483,5 +491,33 @@
"open_dashboard": "打开面板",
"copy_to_terminal": "复制到终端",
"exit_app": "退出应用"
},
"crisp": {
"initializingSystem": "正在初始化客服系统...",
"initFailed": "客服系统初始化失败"
},
"common": {
"retry": "重试",
"tryBrowser": "尝试使用浏览器打开",
"cannotOpenBrowser": "无法打开浏览器",
"openLinkFailed": "打开链接失败,请稍后重试",
"cannotOpenTelegram": "无法打开Telegram链接"
},
"subscribe": {
"pleaseSelectFirst": "请先选择订阅",
"resetPeriodFailed": "重置订阅周期失败",
"resetPeriodSuccess": "重置订阅周期成功"
},
"purchase": {
"noAvailablePlans": "没有可用的套餐"
},
"payment": {
"cannotOpenLink": "无法打开支付链接",
"linkEmpty": "支付链接为空",
"unsupportedType": "不支持的支付类型"
},
"account": {
"accountRequired": "账号不能为空",
"deleteSuccess": "删除账号成功"
}
}

View File

@ -9,6 +9,7 @@
"enterEmail": "請輸入電子郵箱",
"enterCode": "請輸入驗證碼",
"enterPassword": "請輸入密碼",
"enterPasswordForPhone": "請輸入密碼 (密碼登錄)",
"reenterPassword": "請再次輸入密碼",
"forgotPassword": "忘記密碼",
"codeLogin": "驗證碼登錄",
@ -18,6 +19,8 @@
"privacyPolicy": "隱私政策",
"next": "下一步",
"registerNow": "立即註冊",
"registerAccount": "註冊賬號",
"clickToRegister": "點我註冊",
"setAndLogin": "設置並登錄",
"enterAccount": "請輸入賬戶",
"passwordMismatch": "兩次密碼輸入不一致",
@ -25,7 +28,9 @@
"codeSentCountdown": "驗證碼已發送 {seconds}s",
"and": "和",
"enterInviteCode": "請輸入邀請碼(選填)",
"registerSuccess": "註冊成功"
"registerSuccess": "註冊成功",
"search": "搜尋",
"selectOtherRegion": "選擇其他地區"
},
"failure": {
"unexpected": "意外錯誤",
@ -172,7 +177,8 @@
"friday": "週\n五",
"saturday": "週\n六",
"sunday": "週\n日"
}
},
"processTrafficFailed": "處理流量日誌資料失敗"
},
"message": {
"title": "通知",
@ -448,6 +454,7 @@
"initializing": "正在初始化...",
"networkConnectionFailure": "網絡連接失敗,請檢查並重試",
"retry": "重試",
"skip": "跳過",
"networkPermissionFailed": "獲取網絡權限失敗",
"initializationFailed": "初始化失敗"
},
@ -466,5 +473,33 @@
"goToSettings": "前往設置",
"cancel": "取消"
}
},
"crisp": {
"initializingSystem": "正在初始化客服系統...",
"initFailed": "客服系統初始化失敗"
},
"common": {
"retry": "重試",
"tryBrowser": "嘗試使用瀏覽器開啟",
"cannotOpenBrowser": "無法開啟瀏覽器",
"openLinkFailed": "開啟連結失敗,請稍後重試",
"cannotOpenTelegram": "無法開啟Telegram連結"
},
"subscribe": {
"pleaseSelectFirst": "請先選擇訂閱",
"resetPeriodFailed": "重置訂閱週期失敗",
"resetPeriodSuccess": "重置訂閱週期成功"
},
"purchase": {
"noAvailablePlans": "沒有可用的套餐"
},
"payment": {
"cannotOpenLink": "無法開啟支付連結",
"linkEmpty": "支付連結為空",
"unsupportedType": "不支援的支付類型"
},
"account": {
"accountRequired": "帳號不能為空",
"deleteSuccess": "刪除帳號成功"
}
}

View File

@ -1,426 +0,0 @@
{
"login": {
"welcome": "歡迎使用 Hi快VPN!",
"verifyPhone": "驗證您的手機號",
"verifyEmail": "驗證您的郵箱",
"codeSent": "已向 {account} 發送6位數代碼。請在接下來的 30 分鐘內輸入。",
"back": "返回",
"enterEmailOrPhone": "輸入郵箱或者手機號",
"enterCode": "請輸入驗證碼",
"enterPassword": "請輸入密碼",
"reenterPassword": "請再次輸入密碼",
"forgotPassword": "忘記密碼",
"codeLogin": "驗證碼登錄",
"passwordLogin": "密碼登錄",
"agreeTerms": "登錄/創建賬戶,即表示我同意",
"termsOfService": "服務條款",
"privacyPolicy": "隱私政策",
"next": "下一步",
"registerNow": "立即註冊",
"setAndLogin": "設置並登錄",
"enterAccount": "請輸入賬戶",
"passwordMismatch": "兩次密碼輸入不一致",
"sendCode": "發送驗證碼",
"codeSentCountdown": "驗證碼已發送 {seconds}s",
"and": "和",
"enterInviteCode": "請輸入邀請碼(選填)",
"registerSuccess": "註冊成功"
},
"failure": {
"unexpected": "意外錯誤",
"clash": {
"unexpected": "意外錯誤",
"core": "Clash 錯誤 ${reason}"
},
"singbox": {
"unexpected": "意外服務錯誤",
"serviceNotRunning": "服務未運行",
"missingPrivilege": "缺少權限",
"missingPrivilegeMsg": "VPN 模式需要管理員權限。以管理員身份重新啟動應用程序或更改服務模式",
"missingGeoAssets": "缺失 GEO 資源文件",
"missingGeoAssetsMsg": "缺失 GEO 資源文件。請考慮更改激活的資源文件或在設置中下載所選資源文件。",
"invalidConfigOptions": "配置選項無效",
"invalidConfig": "無效配置",
"create": "服務創建錯誤",
"start": "服務啟動錯誤"
},
"connectivity": {
"unexpected": "意外失敗",
"missingVpnPermission": "缺少 VPN 權限",
"missingNotificationPermission": "缺少通知權限",
"core": "核心錯誤"
},
"profiles": {
"unexpected": "意外錯誤",
"notFound": "未找到配置文件",
"invalidConfig": "無效配置",
"invalidUrl": "網址無效"
},
"connection": {
"unexpected": "意外連接錯誤",
"timeout": "連接超時",
"badResponse": "錯誤響應",
"connectionError": "連接錯誤",
"badCertificate": "證書無效"
},
"geoAssets": {
"unexpected": "意外錯誤",
"notUpdate": "無可用更新",
"activeNotFound": "未找到激活的 GEO 資源文件"
}
},
"userInfo": {
"title": "我的信息",
"bindingTip": "未綁定郵箱/手機號",
"myAccount": "我的賬號",
"balance": "餘額",
"noValidSubscription": "您沒有有效的訂閱",
"subscribeNow": "立即訂閱",
"shortcuts": "快捷鍵",
"adBlock": "廣告攔截",
"dnsUnlock": "DNS 解鎖",
"contactUs": "聯繫我們",
"others": "其他",
"logout": "退出登錄",
"logoutConfirmTitle": "退出登錄",
"logoutConfirmMessage": "確定要退出登錄嗎?",
"logoutCancel": "取消",
"vpnWebsite": "VPN 官網",
"telegram": "Telegram",
"mail": "郵箱",
"phone": "電話",
"customerService": "人工客服",
"workOrder": "填寫工單",
"pleaseLogin": "請先登錄賬號",
"subscriptionValid": "訂閱有效",
"startTime": "開始時間:",
"expireTime": "到期時間:",
"loginNow": "立即登錄",
"trialPeriod": "歡迎使用高級試用版",
"remainingTime": "剩餘時間",
"trialExpired": "試用期已結束,連接已斷開",
"subscriptionExpired": "訂閱已過期,連接已斷開",
"copySuccess": "複製成功",
"notAvailable": "暫無",
"willBeDeleted": "將被刪除",
"deleteAccountWarning": "賬號刪除是永久性的。一旦您的賬號被刪除,您將無法使用任何功能。是否繼續?",
"requestDelete": "請求刪除",
"switchSubscription": "切換訂閱",
"resetTrafficTitle": "重置流量",
"resetTrafficMessage": "月付套餐流量重置示例:將下一個週期的流量按月重置,訂閱有效期將從{currentTime}提前至{newTime}",
"reset": "重置",
"trafficUsage": "已用: {used} / {total}",
"trafficProgress": {
"title": "流量使用情況",
"unlimited": "不限流量",
"limited": "已用流量"
},
"deviceLimit": "設備限制: {count}"
},
"setting": {
"title": "設置",
"vpnConnection": "VPN連接",
"general": "通用",
"autoConnect": "自動連接",
"routeRule": "路由規則",
"countrySelector": "選擇國家",
"appearance": "外觀",
"notifications": "通知",
"helpImprove": "幫助我們改進",
"helpImproveSubtitle": "幫助我們改進的副標題",
"requestDeleteAccount": "請求刪除賬號",
"goToDelete": "去刪除",
"rateUs": "在 App Store 上為我們評分",
"iosRating": "iOS評分",
"version": "版本",
"switchLanguage": "切換語言",
"system": "系統",
"light": "淺色",
"dark": "深色",
"vpnModeSmart": "智能模式",
"mode": "出站模式",
"connectionTypeGlobal": "全域代理",
"connectionTypeGlobalRemark": "啟用後,所有流量均通過代理伺服器轉發",
"connectionTypeRule": "智能代理",
"connectionTypeRuleRemark": "當[出站模式]設置為[智能代理]時根據所選國家系統自動分流國內IP/域名直連,境外請求透過代理訪問",
"connectionTypeDirect": "直連",
"connectionTypeDirectRemark": "啟用後,所有流量均不經代理直接訪問",
"smartMode": "智能模式",
"secureMode": "安全模式",
"deviceLimit": "設備限制: {count}"
},
"statistics": {
"title": "統計",
"vpnStatus": "VPN 狀態",
"ipAddress": "IP地址",
"connectionTime": "連接時間",
"protocol": "協議",
"weeklyProtectionTime": "每週保護時間",
"currentStreak": "當前連續記錄",
"highestStreak": "最高記錄",
"longestConnection": "最長連接時間",
"days": "{days}天",
"daysOfWeek": {
"monday": "週\n一",
"tuesday": "週\n二",
"wednesday": "週\n三",
"thursday": "週\n四",
"friday": "週\n五",
"saturday": "週\n六",
"sunday": "週\n日"
}
},
"message": {
"title": "通知",
"system": "系統消息",
"promotion": "促銷消息"
},
"invite": {
"title": "邀請好友",
"progress": "邀請進度",
"inviteStats": "邀請統計",
"registers": "已註冊",
"totalCommission": "總佣金",
"rewardDetails": "獎勵明細 >",
"steps": "邀請步驟",
"inviteFriend": "邀請好友",
"acceptInvite": "好友接受邀請\n下單並註冊",
"getReward": "獲得獎勵",
"shareLink": "分享連結",
"shareQR": "分享二維碼",
"rules": "邀請規則",
"rule1": "1、您可以通過分享專屬邀請連結或邀請碼給好友邀請他們加入我們。",
"rule2": "2、好友完成註冊並登錄後邀請獎勵將自動發放至您的賬戶。",
"pending": "待下載",
"processing": "在路上",
"success": "已成功",
"expired": "已失效",
"myInviteCode": "我的邀請碼",
"inviteCodeCopied": "邀請碼已複製到剪貼板",
"close": "關閉",
"saveQRCode": "保存二維碼",
"qrCodeSaved": "二維碼已保存",
"copiedToClipboard": "已複製到剪貼板",
"getInviteCodeFailed": "獲取邀請碼失敗,請稍後重試",
"generateQRCodeFailed": "生成二維碼失敗,請稍後重試",
"generateShareLinkFailed": "生成分享連結失敗,請稍後重試"
},
"purchaseMembership": {
"purchasePackage": "購買套餐",
"noData": "暫無可用套餐",
"myAccount": "我的賬號",
"selectPackage": "選擇套餐",
"packageDescription": "套餐描述",
"paymentMethod": "支付方式",
"cancelAnytime": "您可以隨時在APP上取消",
"startSubscription": "開始訂閱",
"renewNow": "立即續訂",
"month": "{months}個月",
"year": "{years}年",
"day": "{days}天",
"unlimitedTraffic": "不限流量",
"unlimitedDevices": "不限設備",
"devices": "{count}台",
"trafficLimit": "流量限制",
"deviceLimit": "設備限制",
"features": "套餐特性",
"expand": "展開",
"collapse": "收起",
"confirmPurchase": "確認購買",
"confirmPurchaseDesc": "您確定要購買此套餐嗎?"
},
"home": {
"welcome": "歡迎使用 Hi快VPN",
"disconnected": "已斷開連接",
"connecting": "正在連接",
"connected": "已連接",
"disconnecting": "正在斷開連接",
"currentConnectionTitle": "當前連接",
"switchNode": "切換節點",
"timeout": "超時",
"loading": "載入中...",
"error": "載入失敗",
"checkNetwork": "請檢查網絡連接並重試",
"retry": "重試",
"connectionSectionTitle": "連接方式",
"dedicatedServers": "專用伺服器",
"countryRegion": "國家/地區",
"serverListTitle": "專用伺服器群組",
"nodeListTitle": "所有節點",
"countryListTitle": "國家/地區列表",
"noServers": "暫無可用伺服器",
"noNodes": "暫無可用節點",
"noRegions": "暫無可用地區",
"subscriptionDescription": "訂閱會員,暢享全球高速網絡",
"subscribe": "立即訂閱",
"trialPeriod": "歡迎使用 Premium 試用版",
"remainingTime": "剩餘時間",
"trialExpired": "試用期已結束,已斷開連接",
"subscriptionExpired": "訂閱已過期,已斷開連接",
"subscriptionUpdated": "訂閱已更新",
"subscriptionUpdatedMessage": "您的訂閱信息已更新,請刷新頁面查看最新狀態",
"trialStatus": "試用狀態",
"trialing": "試用中",
"trialEndMessage": "試用期結束後將無法使用",
"lastDaySubscriptionStatus": "訂閱即將到期",
"lastDaySubscriptionMessage": "即將到期",
"subscriptionEndMessage": "訂閱到期後將無法使用",
"trialTimeWithDays": "{days}天 {hours}時 {minutes}分 {seconds}秒",
"trialTimeWithHours": "{hours}時 {minutes}分 {seconds}秒",
"trialTimeWithMinutes": "{minutes}分 {seconds}秒",
"refreshLatency": "刷新延遲",
"testLatency": "測試延遲",
"testing": "正在測試延遲",
"refreshLatencyDesc": "刷新所有節點的延遲",
"testAllNodesLatency": "測試所有節點的網絡延遲",
"autoSelect": "自動選擇",
"selected": "已選擇"
},
"dialog": {
"confirm": "確認",
"cancel": "取消",
"ok": "我知道了"
},
"update": {
"title": "發現新版本",
"content": "是否立即更新?",
"updateNow": "立即更新",
"updateLater": "稍後",
"defaultContent": "1. 優化應用性能\n2. 修復已知問題\n3. 改進用戶體驗"
},
"orderStatus": {
"title": "訂單狀態",
"pending": {
"title": "待支付",
"description": "請完成支付"
},
"paid": {
"title": "已支付",
"description": "正在處理您的訂單"
},
"success": {
"title": "恭喜你!支付成功",
"description": "您的套餐已經購買成功了"
},
"closed": {
"title": "訂單已關閉",
"description": "請重新下單"
},
"failed": {
"title": "支付失敗",
"description": "請重新嘗試支付"
},
"unknown": {
"title": "未知狀態",
"description": "請聯繫客服"
},
"checkFailed": {
"title": "檢查失敗",
"description": "請稍後重試"
},
"initial": {
"title": "支付中",
"description": "請稍候,正在處理您的支付"
}
},
"country": {
"cn": "中國",
"ir": "伊朗",
"af": "阿富汗",
"ru": "俄羅斯",
"id": "印尼",
"tr": "土耳其",
"br": "巴西"
},
"error": {
"200": "成功",
"500": "服務器內部錯誤",
"10001": "數據庫查詢錯誤",
"10002": "數據庫更新錯誤",
"10003": "數據庫插入錯誤",
"10004": "數據庫刪除錯誤",
"20001": "用戶已存在",
"20002": "用戶不存在",
"20003": "用戶密碼錯誤",
"20004": "用戶已被禁用",
"20005": "餘額不足",
"20006": "註冊已暫停",
"20007": "未綁定 Telegram",
"20008": "用戶未綁定 OAuth",
"20009": "邀請碼錯誤",
"30001": "節點已存在",
"30002": "節點不存在",
"30003": "節點群組已存在",
"30004": "節點群組不存在",
"30005": "節點群組不為空",
"400": "參數錯誤",
"40002": "用戶令牌為空",
"40003": "用戶令牌無效",
"40004": "用戶令牌已過期",
"40005": "未登錄",
"401": "請求過多",
"50001": "優惠券不存在",
"50002": "優惠券已使用",
"50003": "優惠券不匹配",
"60001": "訂閱已過期",
"60002": "訂閱不可用",
"60003": "用戶已有訂閱",
"60004": "訂閱已使用",
"60005": "單次訂閱模式超出限制",
"60006": "訂閱配額限制",
"70001": "驗證碼錯誤",
"80001": "加入隊列錯誤",
"90001": "調試模式已啟用",
"90002": "發送短信錯誤",
"90003": "短信功能未啟用",
"90004": "郵件功能未啟用",
"90005": "不支持的登錄方式",
"90006": "驗證器不支持此方式",
"90007": "電話國家代碼為空",
"90008": "密碼為空",
"90009": "國家代碼為空",
"90010": "需要密碼或驗證碼",
"90011": "郵箱已存在",
"90012": "手機號已存在",
"90013": "設備已存在",
"90014": "手機號錯誤",
"90015": "該賬號今日已達到發送限制",
"90017": "設備不存在",
"90018": "用戶 ID 不匹配",
"61001": "訂閱不存在",
"61002": "未找到支付方式",
"61003": "訂閱狀態錯誤",
"61004": "重置期不足",
"61005": "存在未使用流量"
},
"tray": {
"open_dashboard": "打開面板",
"copy_to_terminal": "複製到終端",
"exit_app": "退出應用"
},
"splash": {
"appName": "Hi快VPN",
"slogan": "暢享全球高速網絡",
"initializing": "正在初始化...",
"networkConnectionFailure": "網絡連接失敗,請檢查並重試",
"retry": "重試",
"networkPermissionFailed": "獲取網絡權限失敗",
"initializationFailed": "初始化失敗"
},
"network": {
"status": {
"connected": "已連接",
"disconnected": "已斷開連接",
"connecting": "正在連接...",
"disconnecting": "正在斷開連接...",
"reconnecting": "正在重新連接...",
"failed": "連接失敗"
},
"permission": {
"title": "網絡權限",
"description": "需要網絡權限以提供 VPN 服務",
"goToSettings": "前往設置",
"cancel": "取消"
}
}
}

View File

@ -1,427 +0,0 @@
{
"login": {
"welcome": "歡迎使用 Hi快VPN!",
"verifyPhone": "驗證您的手機號",
"verifyEmail": "驗證您的郵箱",
"codeSent": "已向 {account} 發送6位數代碼。請在接下來的 30 分鐘內輸入。",
"back": "返回",
"enterEmailOrPhone": "輸入郵箱或者手機號",
"enterEmail": "Please enter email address",
"enterCode": "請輸入驗證碼",
"enterPassword": "請輸入密碼",
"reenterPassword": "請再次輸入密碼",
"forgotPassword": "忘記密碼",
"codeLogin": "驗證碼登錄",
"passwordLogin": "密碼登錄",
"agreeTerms": "登錄/創建賬戶,即表示我同意",
"termsOfService": "服務條款",
"privacyPolicy": "隱私政策",
"next": "下一步",
"registerNow": "立即註冊",
"setAndLogin": "設置並登錄",
"enterAccount": "請輸入賬戶",
"passwordMismatch": "兩次密碼輸入不一致",
"sendCode": "發送驗證碼",
"codeSentCountdown": "驗證碼已發送 {seconds}s",
"and": "和",
"enterInviteCode": "請輸入邀請碼(選填)",
"registerSuccess": "註冊成功"
},
"failure": {
"unexpected": "意外錯誤",
"clash": {
"unexpected": "意外錯誤",
"core": "Clash 錯誤 ${reason}"
},
"singbox": {
"unexpected": "意外服務錯誤",
"serviceNotRunning": "服務未運行",
"missingPrivilege": "缺少權限",
"missingPrivilegeMsg": "VPN 模式需要管理員權限。以管理員身份重新啟動應用程序或更改服務模式",
"missingGeoAssets": "缺失 GEO 資源文件",
"missingGeoAssetsMsg": "缺失 GEO 資源文件。請考慮更改激活的資源文件或在設置中下載所選資源文件。",
"invalidConfigOptions": "配置選項無效",
"invalidConfig": "無效配置",
"create": "服務創建錯誤",
"start": "服務啟動錯誤"
},
"connectivity": {
"unexpected": "意外失敗",
"missingVpnPermission": "缺少 VPN 權限",
"missingNotificationPermission": "缺少通知權限",
"core": "核心錯誤"
},
"profiles": {
"unexpected": "意外錯誤",
"notFound": "未找到配置文件",
"invalidConfig": "無效配置",
"invalidUrl": "網址無效"
},
"connection": {
"unexpected": "意外連接錯誤",
"timeout": "連接超時",
"badResponse": "錯誤響應",
"connectionError": "連接錯誤",
"badCertificate": "證書無效"
},
"geoAssets": {
"unexpected": "意外錯誤",
"notUpdate": "無可用更新",
"activeNotFound": "未找到激活的 GEO 資源文件"
}
},
"userInfo": {
"title": "我的信息",
"bindingTip": "未綁定郵箱/手機號",
"myAccount": "我的賬號",
"balance": "餘額",
"noValidSubscription": "您沒有有效的訂閱",
"subscribeNow": "立即訂閱",
"shortcuts": "快捷鍵",
"adBlock": "廣告攔截",
"dnsUnlock": "DNS 解鎖",
"contactUs": "聯繫我們",
"others": "其他",
"logout": "退出登錄",
"logoutConfirmTitle": "退出登錄",
"logoutConfirmMessage": "確定要退出登錄嗎?",
"logoutCancel": "取消",
"vpnWebsite": "VPN 官網",
"telegram": "Telegram",
"mail": "郵箱",
"phone": "電話",
"customerService": "人工客服",
"workOrder": "填寫工單",
"pleaseLogin": "請先登錄賬號",
"subscriptionValid": "訂閱有效",
"startTime": "開始時間:",
"expireTime": "到期時間:",
"loginNow": "立即登錄",
"trialPeriod": "歡迎使用高級試用版",
"remainingTime": "剩餘時間",
"trialExpired": "試用期已結束,連接已斷開",
"subscriptionExpired": "訂閱已過期,連接已斷開",
"copySuccess": "複製成功",
"notAvailable": "暫無",
"willBeDeleted": "將被刪除",
"deleteAccountWarning": "賬號刪除是永久性的。一旦您的賬號被刪除,您將無法使用任何功能。是否繼續?",
"requestDelete": "請求刪除",
"switchSubscription": "切換訂閱",
"resetTrafficTitle": "重置流量",
"resetTrafficMessage": "月付套餐流量重置示例:將下一個週期的流量按月重置,訂閱有效期將從{currentTime}提前至{newTime}",
"reset": "重置",
"trafficUsage": "已用: {used} / {total}",
"trafficProgress": {
"title": "流量使用情況",
"unlimited": "不限流量",
"limited": "已用流量"
},
"deviceLimit": "設備限制: {count}"
},
"setting": {
"title": "設置",
"vpnConnection": "VPN連接",
"general": "通用",
"autoConnect": "自動連接",
"routeRule": "路由規則",
"countrySelector": "選擇國家",
"appearance": "外觀",
"notifications": "通知",
"helpImprove": "幫助我們改進",
"helpImproveSubtitle": "幫助我們改進的副標題",
"requestDeleteAccount": "請求刪除賬號",
"goToDelete": "去刪除",
"rateUs": "在 App Store 上為我們評分",
"iosRating": "iOS評分",
"version": "版本",
"switchLanguage": "切換語言",
"system": "系統",
"light": "淺色",
"dark": "深色",
"vpnModeSmart": "智能模式",
"mode": "出站模式",
"connectionTypeGlobal": "全域代理",
"connectionTypeGlobalRemark": "啟用後,所有流量均通過代理伺服器轉發",
"connectionTypeRule": "智能代理",
"connectionTypeRuleRemark": "當[出站模式]設置為[智能代理]時根據所選國家系統自動分流國內IP/域名直連,境外請求透過代理訪問",
"connectionTypeDirect": "直連",
"connectionTypeDirectRemark": "啟用後,所有流量均不經代理直接訪問",
"smartMode": "智能模式",
"secureMode": "安全模式",
"deviceLimit": "設備限制: {count}"
},
"statistics": {
"title": "統計",
"vpnStatus": "VPN 狀態",
"ipAddress": "IP地址",
"connectionTime": "連接時間",
"protocol": "協議",
"weeklyProtectionTime": "每週保護時間",
"currentStreak": "當前連續記錄",
"highestStreak": "最高記錄",
"longestConnection": "最長連接時間",
"days": "{days}天",
"daysOfWeek": {
"monday": "週\n一",
"tuesday": "週\n二",
"wednesday": "週\n三",
"thursday": "週\n四",
"friday": "週\n五",
"saturday": "週\n六",
"sunday": "週\n日"
}
},
"message": {
"title": "通知",
"system": "系統消息",
"promotion": "促銷消息"
},
"invite": {
"title": "邀請好友",
"progress": "邀請進度",
"inviteStats": "邀請統計",
"registers": "已註冊",
"totalCommission": "總佣金",
"rewardDetails": "獎勵明細 >",
"steps": "邀請步驟",
"inviteFriend": "邀請好友",
"acceptInvite": "好友接受邀請\n下單並註冊",
"getReward": "獲得獎勵",
"shareLink": "分享連結",
"shareQR": "分享二維碼",
"rules": "邀請規則",
"rule1": "1、您可以通過分享專屬邀請連結或邀請碼給好友邀請他們加入我們。",
"rule2": "2、好友完成註冊並登錄後邀請獎勵將自動發放至您的賬戶。",
"pending": "待下載",
"processing": "在路上",
"success": "已成功",
"expired": "已失效",
"myInviteCode": "我的邀請碼",
"inviteCodeCopied": "邀請碼已複製到剪貼板",
"close": "關閉",
"saveQRCode": "保存二維碼",
"qrCodeSaved": "二維碼已保存",
"copiedToClipboard": "已複製到剪貼板",
"getInviteCodeFailed": "獲取邀請碼失敗,請稍後重試",
"generateQRCodeFailed": "生成二維碼失敗,請稍後重試",
"generateShareLinkFailed": "生成分享連結失敗,請稍後重試"
},
"purchaseMembership": {
"purchasePackage": "購買套餐",
"noData": "暫無可用套餐",
"myAccount": "我的賬號",
"selectPackage": "選擇套餐",
"packageDescription": "套餐描述",
"paymentMethod": "支付方式",
"cancelAnytime": "您可以隨時在APP上取消",
"startSubscription": "開始訂閱",
"renewNow": "立即續訂",
"month": "{months}個月",
"year": "{years}年",
"day": "{days}天",
"unlimitedTraffic": "不限流量",
"unlimitedDevices": "不限設備",
"devices": "{count}台",
"trafficLimit": "流量限制",
"deviceLimit": "設備限制",
"features": "套餐特性",
"expand": "展開",
"collapse": "收起",
"confirmPurchase": "確認購買",
"confirmPurchaseDesc": "您確定要購買此套餐嗎?"
},
"home": {
"welcome": "歡迎使用 Hi快VPN",
"disconnected": "已斷開連接",
"connecting": "正在連接",
"connected": "已連接",
"disconnecting": "正在斷開連接",
"currentConnectionTitle": "當前連接",
"switchNode": "切換節點",
"timeout": "超時",
"loading": "載入中...",
"error": "載入失敗",
"checkNetwork": "請檢查網絡連接並重試",
"retry": "重試",
"connectionSectionTitle": "連接方式",
"dedicatedServers": "專用伺服器",
"countryRegion": "國家/地區",
"serverListTitle": "專用伺服器群組",
"nodeListTitle": "所有節點",
"countryListTitle": "國家/地區列表",
"noServers": "暫無可用伺服器",
"noNodes": "暫無可用節點",
"noRegions": "暫無可用地區",
"subscriptionDescription": "訂閱會員,暢享全球高速網絡",
"subscribe": "立即訂閱",
"trialPeriod": "歡迎使用 Premium 試用版",
"remainingTime": "剩餘時間",
"trialExpired": "試用期已結束,已斷開連接",
"subscriptionExpired": "訂閱已過期,已斷開連接",
"subscriptionUpdated": "訂閱已更新",
"subscriptionUpdatedMessage": "您的訂閱信息已更新,請刷新頁面查看最新狀態",
"trialStatus": "試用狀態",
"trialing": "試用中",
"trialEndMessage": "試用期結束後將無法使用",
"lastDaySubscriptionStatus": "訂閱即將到期",
"lastDaySubscriptionMessage": "即將到期",
"subscriptionEndMessage": "訂閱到期後將無法使用",
"trialTimeWithDays": "{days}天 {hours}時 {minutes}分 {seconds}秒",
"trialTimeWithHours": "{hours}時 {minutes}分 {seconds}秒",
"trialTimeWithMinutes": "{minutes}分 {seconds}秒",
"refreshLatency": "刷新延遲",
"testLatency": "測試延遲",
"testing": "正在測試延遲",
"refreshLatencyDesc": "刷新所有節點的延遲",
"testAllNodesLatency": "測試所有節點的網絡延遲",
"autoSelect": "自動選擇",
"selected": "已選擇"
},
"dialog": {
"confirm": "確認",
"cancel": "取消",
"ok": "我知道了"
},
"update": {
"title": "發現新版本",
"content": "是否立即更新?",
"updateNow": "立即更新",
"updateLater": "稍後",
"defaultContent": "1. 優化應用性能\n2. 修復已知問題\n3. 改進用戶體驗"
},
"orderStatus": {
"title": "訂單狀態",
"pending": {
"title": "待支付",
"description": "請完成支付"
},
"paid": {
"title": "已支付",
"description": "正在處理您的訂單"
},
"success": {
"title": "恭喜你!支付成功",
"description": "您的套餐已經購買成功了"
},
"closed": {
"title": "訂單已關閉",
"description": "請重新下單"
},
"failed": {
"title": "支付失敗",
"description": "請重新嘗試支付"
},
"unknown": {
"title": "未知狀態",
"description": "請聯繫客服"
},
"checkFailed": {
"title": "檢查失敗",
"description": "請稍後重試"
},
"initial": {
"title": "支付中",
"description": "請稍候,正在處理您的支付"
}
},
"country": {
"cn": "中國",
"ir": "伊朗",
"af": "阿富汗",
"ru": "俄羅斯",
"id": "印尼",
"tr": "土耳其",
"br": "巴西"
},
"error": {
"200": "成功",
"500": "服務器內部錯誤",
"10001": "數據庫查詢錯誤",
"10002": "數據庫更新錯誤",
"10003": "數據庫插入錯誤",
"10004": "數據庫刪除錯誤",
"20001": "用戶已存在",
"20002": "用戶不存在",
"20003": "用戶密碼錯誤",
"20004": "用戶已被禁用",
"20005": "餘額不足",
"20006": "註冊已暫停",
"20007": "未綁定 Telegram",
"20008": "用戶未綁定 OAuth",
"20009": "邀請碼錯誤",
"30001": "節點已存在",
"30002": "節點不存在",
"30003": "節點群組已存在",
"30004": "節點群組不存在",
"30005": "節點群組不為空",
"400": "參數錯誤",
"40002": "用戶令牌為空",
"40003": "用戶令牌無效",
"40004": "用戶令牌已過期",
"40005": "未登錄",
"401": "請求過多",
"50001": "優惠券不存在",
"50002": "優惠券已使用",
"50003": "優惠券不匹配",
"60001": "訂閱已過期",
"60002": "訂閱不可用",
"60003": "用戶已有訂閱",
"60004": "訂閱已使用",
"60005": "單次訂閱模式超出限制",
"60006": "訂閱配額限制",
"70001": "驗證碼錯誤",
"80001": "加入隊列錯誤",
"90001": "調試模式已啟用",
"90002": "發送短信錯誤",
"90003": "短信功能未啟用",
"90004": "郵件功能未啟用",
"90005": "不支持的登錄方式",
"90006": "驗證器不支持此方式",
"90007": "電話國家代碼為空",
"90008": "密碼為空",
"90009": "國家代碼為空",
"90010": "需要密碼或驗證碼",
"90011": "郵箱已存在",
"90012": "手機號已存在",
"90013": "設備已存在",
"90014": "手機號錯誤",
"90015": "該賬號今日已達到發送限制",
"90017": "設備不存在",
"90018": "用戶 ID 不匹配",
"61001": "訂閱不存在",
"61002": "未找到支付方式",
"61003": "訂閱狀態錯誤",
"61004": "重置期不足",
"61005": "存在未使用流量"
},
"tray": {
"open_dashboard": "打開面板",
"copy_to_terminal": "複製到終端",
"exit_app": "退出應用"
},
"splash": {
"appName": "Hi快VPN",
"slogan": "暢享全球高速網絡",
"initializing": "正在初始化...",
"networkConnectionFailure": "網絡連接失敗,請檢查並重試",
"retry": "重試",
"networkPermissionFailed": "獲取網絡權限失敗",
"initializationFailed": "初始化失敗"
},
"network": {
"status": {
"connected": "已連接",
"disconnected": "已斷開連接",
"connecting": "正在連接...",
"disconnecting": "正在斷開連接...",
"reconnecting": "正在重新連接...",
"failed": "連接失敗"
},
"permission": {
"title": "網絡權限",
"description": "需要網絡權限以提供 VPN 服務",
"goToSettings": "前往設置",
"cancel": "取消"
}
}
}

View File

@ -78,7 +78,7 @@ SPEC CHECKSUMS:
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe
EasyPermissionX: ff4c438f6ee80488f873b4cb921e32d982523067
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_udid: f7c3884e6ec2951efe4f9de082257fc77c4d15e9
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94

View File

@ -1081,21 +1081,141 @@ class KRDomain {
);
}
///
/// 1
static Future<void> kr_loadBaseDomain() async {
KRLogUtil.kr_i('📂 开始从 Hive 加载域名配置', tag: 'KRDomain');
final startTime = DateTime.now();
try {
// 🔧 Android 15 15
await Future.any([
_executeLoadAndVerify(),
Future.delayed(const Duration(seconds: 15), () {
throw TimeoutException('域名加载和验证总超时15秒');
}),
]);
} on TimeoutException catch (e) {
final duration = DateTime.now().difference(startTime).inSeconds;
KRLogUtil.kr_e('⏱️ 域名加载验证超时($duration 秒): $e', tag: 'KRDomain');
// 使
if (kr_baseDomains.isNotEmpty) {
kr_currentDomain = kr_baseDomains[0];
KRLogUtil.kr_w('⚠️ 超时后使用默认域名: $kr_currentDomain', tag: 'KRDomain');
}
} catch (e) {
final duration = DateTime.now().difference(startTime).inSeconds;
KRLogUtil.kr_e('❌ 域名加载异常($duration 秒): $e', tag: 'KRDomain');
// 使
if (kr_baseDomains.isNotEmpty) {
kr_currentDomain = kr_baseDomains[0];
}
}
final totalDuration = DateTime.now().difference(startTime).inMilliseconds;
KRLogUtil.kr_i('✅ 域名加载完成,耗时: ${totalDuration}ms当前域名: $kr_currentDomain', tag: 'KRDomain');
}
///
static Future<void> _executeLoadAndVerify() async {
//
String? savedDomains = await _storage.kr_readData(key: kr_domainsKey);
if (savedDomains != null) {
kr_baseDomains = savedDomains.split(',');
if (savedDomains != null && savedDomains.isNotEmpty) {
kr_baseDomains = savedDomains.split(',').where((d) => d.isNotEmpty).toList();
KRLogUtil.kr_i('📋 从 Hive 加载的域名列表: $kr_baseDomains', tag: 'KRDomain');
} else {
KRLogUtil.kr_w('⚠️ Hive 中没有保存的域名列表,使用默认配置', tag: 'KRDomain');
}
//
String? savedDomain = await _storage.kr_readData(key: kr_domainKey);
if (savedDomain != null && kr_baseDomains.contains(savedDomain)) {
kr_currentDomain = savedDomain;
KRLogUtil.kr_i('📌 从 Hive 加载的当前域名: $savedDomain', tag: 'KRDomain');
if (savedDomain != null && savedDomain.isNotEmpty && kr_baseDomains.contains(savedDomain)) {
// 🔧 Android 15 Hive
KRLogUtil.kr_i('🔍 验证 Hive 缓存域名的可用性: $savedDomain', tag: 'KRDomain');
try {
// 3
bool isAvailable = await kr_fastCheckDomainAvailability(savedDomain).timeout(
const Duration(seconds: 3),
onTimeout: () {
KRLogUtil.kr_w('⏱️ 域名验证超时(3秒),视为不可用', tag: 'KRDomain');
return false;
},
);
if (isAvailable) {
kr_currentDomain = savedDomain;
KRLogUtil.kr_i('✅ Hive 缓存域名验证通过,继续使用: $kr_currentDomain', tag: 'KRDomain');
return;
} else {
KRLogUtil.kr_w('❌ Hive 缓存域名不可用: $savedDomain,需要切换', tag: 'KRDomain');
}
} catch (e) {
KRLogUtil.kr_e('❌ 域名验证异常: $e,需要切换', tag: 'KRDomain');
}
} else {
if (savedDomain == null || savedDomain.isEmpty) {
KRLogUtil.kr_w('⚠️ Hive 中没有保存的当前域名', tag: 'KRDomain');
} else {
KRLogUtil.kr_w('⚠️ Hive 缓存的域名 $savedDomain 不在域名列表中', tag: 'KRDomain');
}
}
// 🔧 Android 15 Hive
KRLogUtil.kr_i('🔄 Hive 域名不可用,开始选择可用域名...', tag: 'KRDomain');
// 3
for (String domain in kr_baseDomains) {
try {
KRLogUtil.kr_i('🧪 测试域名: $domain', tag: 'KRDomain');
bool isAvailable = await kr_fastCheckDomainAvailability(domain).timeout(
const Duration(seconds: 3),
onTimeout: () {
KRLogUtil.kr_w('⏱️ 域名 $domain 验证超时(3秒)', tag: 'KRDomain');
return false;
},
);
if (isAvailable) {
kr_currentDomain = domain;
await kr_saveCurrentDomain();
KRLogUtil.kr_i('✅ 找到可用域名: $kr_currentDomain,已保存到 Hive', tag: 'KRDomain');
return;
}
} catch (e) {
KRLogUtil.kr_w('⚠️ 域名 $domain 验证异常: $e', tag: 'KRDomain');
}
}
// 5
KRLogUtil.kr_w('⚠️ 所有主域名都不可用,尝试备用域名...', tag: 'KRDomain');
try {
String? backupDomain = await kr_tryLocalBackupDomains().timeout(
const Duration(seconds: 5),
onTimeout: () {
KRLogUtil.kr_w('⏱️ 备用域名获取超时', tag: 'KRDomain');
return null;
},
);
if (backupDomain != null) {
kr_currentDomain = backupDomain;
await kr_saveCurrentDomain();
KRLogUtil.kr_i('✅ 使用备用域名: $kr_currentDomain', tag: 'KRDomain');
return;
}
} catch (e) {
KRLogUtil.kr_w('⚠️ 备用域名获取异常: $e', tag: 'KRDomain');
}
// 使使
if (kr_baseDomains.isNotEmpty) {
kr_currentDomain = kr_baseDomains[0];
await kr_saveCurrentDomain();
KRLogUtil.kr_w('⚠️ 无法验证任何域名,使用默认域名: $kr_currentDomain', tag: 'KRDomain');
} else {
KRLogUtil.kr_e('❌ 没有可用的域名配置!', tag: 'KRDomain');
}
}
@ -1123,6 +1243,19 @@ class KRDomain {
}
class AppConfig {
///
///
///
/// 🔧
/// true便
/// false I/O
///
///
/// - Beta true
/// - false
static const bool enableInitLogCollection = true;
///
///
///

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:get/get.dart';
import '../response/kr_node_list.dart';
import 'package:flutter/foundation.dart';
///
class KROutboundItem {
@ -50,14 +51,18 @@ class KROutboundItem {
// 🔧 使API格式
// port serverAddr
if (nodeListItem.port > 0 && nodeListItem.serverAddr.isNotEmpty) {
print(' 节点 ${nodeListItem.name} 使用直接字段构建配置');
if (kDebugMode) {
print(' 节点 ${nodeListItem.name} 使用直接字段构建配置');
}
_buildConfigFromFields(nodeListItem);
return;
}
// config API格式
if (nodeListItem.config.isEmpty) {
print('❌ 节点 ${nodeListItem.name} 缺少配置信息无port或config');
if (kDebugMode) {
print('❌ 节点 ${nodeListItem.name} 缺少配置信息无port或config');
}
config = {};
return;
}
@ -66,8 +71,12 @@ class KROutboundItem {
try {
json = jsonDecode(nodeListItem.config) as Map<String, dynamic>;
} catch (e) {
print('❌ 节点 ${nodeListItem.name} 的 config 解析失败: $e,尝试使用直接字段');
print('📄 Config 内容: ${nodeListItem.config}');
if (kDebugMode) {
print('❌ 节点 ${nodeListItem.name} 的 config 解析失败: $e,尝试使用直接字段');
}
if (kDebugMode) {
print('📄 Config 内容: ${nodeListItem.config}');
}
_buildConfigFromFields(nodeListItem);
return;
}
@ -237,14 +246,30 @@ class KROutboundItem {
/// API格式
void _buildConfigFromFields(KrNodeListItem nodeListItem) {
print('🔧 开始构建节点配置 - 协议: ${nodeListItem.protocol}, 名称: ${nodeListItem.name}');
print('📋 节点详细信息:');
print(' - serverAddr: ${nodeListItem.serverAddr}');
print(' - port: ${nodeListItem.port}');
print(' - uuid: ${nodeListItem.uuid}');
print(' - method: ${nodeListItem.method}');
print(' - config: ${nodeListItem.config}');
print(' - protocols: ${nodeListItem.protocols}');
if (kDebugMode) {
print('🔧 开始构建节点配置 - 协议: ${nodeListItem.protocol}, 名称: ${nodeListItem.name}');
}
if (kDebugMode) {
print('📋 节点详细信息:');
}
if (kDebugMode) {
print(' - serverAddr: ${nodeListItem.serverAddr}');
}
if (kDebugMode) {
print(' - port: ${nodeListItem.port}');
}
if (kDebugMode) {
print(' - uuid: ${nodeListItem.uuid}');
}
if (kDebugMode) {
print(' - method: ${nodeListItem.method}');
}
if (kDebugMode) {
print(' - config: ${nodeListItem.config}');
}
if (kDebugMode) {
print(' - protocols: ${nodeListItem.protocols}');
}
// 🔧 config transport
Map<String, dynamic>? transportConfig;
@ -254,7 +279,9 @@ class KROutboundItem {
if (nodeListItem.protocols.isNotEmpty) {
try {
final protocolsList = jsonDecode(nodeListItem.protocols) as List;
print('📄 解析到 protocols 数组,共 ${protocolsList.length} 个协议');
if (kDebugMode) {
print('📄 解析到 protocols 数组,共 ${protocolsList.length} 个协议');
}
//
Map<String, dynamic>? matchedProtocol;
@ -263,14 +290,18 @@ class KROutboundItem {
final type = protocolMap['type']?.toString().toLowerCase() ?? '';
final enable = protocolMap['enable'] ?? true;
print(' 📋 协议: type=$type, enable=$enable');
if (kDebugMode) {
print(' 📋 协议: type=$type, enable=$enable');
}
// hysteria hysteria2 hysteria
if (type == nodeListItem.protocol.toLowerCase() ||
(nodeListItem.protocol == 'hysteria' && type == 'hysteria2') ||
(nodeListItem.protocol == 'hysteria2' && type == 'hysteria')) {
matchedProtocol = protocolMap;
print(' ✅ 找到匹配的协议配置: $type');
if (kDebugMode) {
print(' ✅ 找到匹配的协议配置: $type');
}
break;
}
}
@ -279,7 +310,9 @@ class KROutboundItem {
// transport
if (matchedProtocol['network'] != null || matchedProtocol['transport'] != null) {
final network = matchedProtocol['network'] ?? matchedProtocol['transport'];
print(' 📡 传输协议: $network');
if (kDebugMode) {
print(' 📡 传输协议: $network');
}
if (network == 'ws' || network == 'websocket') {
transportConfig = {
@ -290,20 +323,26 @@ class KROutboundItem {
if (host != null && host.toString().isNotEmpty) {
transportConfig['headers'] = {'Host': host.toString()};
}
print(' ✅ WebSocket transport: $transportConfig');
if (kDebugMode) {
print(' ✅ WebSocket transport: $transportConfig');
}
} else if (network == 'grpc') {
transportConfig = {
'type': 'grpc',
'service_name': matchedProtocol['grpc_service_name'] ?? matchedProtocol['service_name'] ?? '',
};
print(' ✅ gRPC transport: $transportConfig');
if (kDebugMode) {
print(' ✅ gRPC transport: $transportConfig');
}
} else if (network == 'http' || network == 'h2') {
transportConfig = {
'type': 'http',
'host': [matchedProtocol['http_host'] ?? matchedProtocol['host'] ?? ''],
'path': matchedProtocol['http_path'] ?? matchedProtocol['path'] ?? '/',
};
print(' ✅ HTTP transport: $transportConfig');
if (kDebugMode) {
print(' ✅ HTTP transport: $transportConfig');
}
}
}
@ -319,11 +358,15 @@ class KROutboundItem {
'allow_insecure': matchedProtocol['allow_insecure'] ?? matchedProtocol['insecure'] ?? true,
'fingerprint': matchedProtocol['fingerprint'] ?? 'chrome',
};
print(' ✅ Security config: security=$security, tls_enabled=$tlsEnabled, config=$securityConfig');
if (kDebugMode) {
print(' ✅ Security config: security=$security, tls_enabled=$tlsEnabled, config=$securityConfig');
}
}
}
} catch (e) {
print('⚠️ 解析 protocols 字段失败: $e');
if (kDebugMode) {
print('⚠️ 解析 protocols 字段失败: $e');
}
}
}
@ -331,21 +374,29 @@ class KROutboundItem {
if (transportConfig == null && nodeListItem.config.isNotEmpty) {
try {
final configJson = jsonDecode(nodeListItem.config) as Map<String, dynamic>;
print('📄 解析到 config JSON: $configJson');
if (kDebugMode) {
print('📄 解析到 config JSON: $configJson');
}
// transport
if (configJson['transport'] != null && configJson['transport'] != 'tcp') {
transportConfig = _buildTransport(configJson);
print('✅ 从 config 找到 transport 配置: $transportConfig');
if (kDebugMode) {
print('✅ 从 config 找到 transport 配置: $transportConfig');
}
}
// security_config
if (configJson['security_config'] != null) {
securityConfig = configJson['security_config'] as Map<String, dynamic>;
print('✅ 从 config 找到 security_config: $securityConfig');
if (kDebugMode) {
print('✅ 从 config 找到 security_config: $securityConfig');
}
}
} catch (e) {
print('⚠️ 解析 config 字段失败: $e');
if (kDebugMode) {
print('⚠️ 解析 config 字段失败: $e');
}
}
}
@ -364,9 +415,15 @@ class KROutboundItem {
"method": finalMethod,
"password": nodeListItem.uuid
};
print('✅ Shadowsocks 节点配置构建成功: ${nodeListItem.name}');
print('📄 使用加密方法: $finalMethod');
print('📄 完整配置: $config');
if (kDebugMode) {
print('✅ Shadowsocks 节点配置构建成功: ${nodeListItem.name}');
}
if (kDebugMode) {
print('📄 使用加密方法: $finalMethod');
}
if (kDebugMode) {
print('📄 完整配置: $config');
}
break;
case "vless":
// IP地址
@ -381,7 +438,9 @@ class KROutboundItem {
// 🔧 security_config TLS
final bool vlessTlsEnabled = securityConfig?['tls_enabled'] ?? false;
print('🔐 VLESS TLS 状态: enabled=$vlessTlsEnabled');
if (kDebugMode) {
print('🔐 VLESS TLS 状态: enabled=$vlessTlsEnabled');
}
config = {
"type": "vless",
@ -400,8 +459,12 @@ class KROutboundItem {
}
}
};
print('✅ VLESS 节点配置构建成功: ${nodeListItem.name}');
print('📄 完整配置: $config');
if (kDebugMode) {
print('✅ VLESS 节点配置构建成功: ${nodeListItem.name}');
}
if (kDebugMode) {
print('📄 完整配置: $config');
}
break;
case "vmess":
// IP地址
@ -416,7 +479,9 @@ class KROutboundItem {
// 🔧 security_config TLS
final bool tlsEnabled = securityConfig?['tls_enabled'] ?? false;
print('🔐 TLS 状态: enabled=$tlsEnabled');
if (kDebugMode) {
print('🔐 TLS 状态: enabled=$tlsEnabled');
}
config = {
"type": "vmess",
@ -437,8 +502,12 @@ class KROutboundItem {
}
}
};
print('✅ VMess 节点配置构建成功: ${nodeListItem.name}');
print('📄 完整配置: $config');
if (kDebugMode) {
print('✅ VMess 节点配置构建成功: ${nodeListItem.name}');
}
if (kDebugMode) {
print('📄 完整配置: $config');
}
break;
case "trojan":
// IP地址
@ -468,16 +537,28 @@ class KROutboundItem {
}
}
};
print('✅ Trojan 节点配置构建成功: ${nodeListItem.name}');
print('📄 完整配置: $config');
if (kDebugMode) {
print('✅ Trojan 节点配置构建成功: ${nodeListItem.name}');
}
if (kDebugMode) {
print('📄 完整配置: $config');
}
break;
case "hysteria":
case "hysteria2":
// "hysteria" Hysteria2
print('🔍 构建 Hysteria2 节点: ${nodeListItem.name}');
print(' - serverAddr: ${nodeListItem.serverAddr}');
print(' - port: ${nodeListItem.port}');
print(' - uuid: ${nodeListItem.uuid}');
if (kDebugMode) {
print('🔍 构建 Hysteria2 节点: ${nodeListItem.name}');
}
if (kDebugMode) {
print(' - serverAddr: ${nodeListItem.serverAddr}');
}
if (kDebugMode) {
print(' - port: ${nodeListItem.port}');
}
if (kDebugMode) {
print(' - uuid: ${nodeListItem.uuid}');
}
//
final bool isDomain = !RegExp(r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$')
@ -494,11 +575,17 @@ class KROutboundItem {
if (isDomain) "server_name": nodeListItem.serverAddr,
}
};
print('✅ Hysteria2 节点配置构建成功');
print('📄 完整配置: ${jsonEncode(config)}');
if (kDebugMode) {
print('✅ Hysteria2 节点配置构建成功');
}
if (kDebugMode) {
print('📄 完整配置: ${jsonEncode(config)}');
}
break;
default:
print('⚠️ 不支持的协议类型: ${nodeListItem.protocol}');
if (kDebugMode) {
print('⚠️ 不支持的协议类型: ${nodeListItem.protocol}');
}
config = {};
}
}

View File

@ -3,6 +3,7 @@ import 'kr_group_outbound_list.dart';
import '../response/kr_node_list.dart';
import 'kr_outbound_item.dart';
import 'package:flutter/foundation.dart';
///
class KrOutboundsList {
@ -47,14 +48,24 @@ class KrOutboundsList {
final KROutboundItem item = KROutboundItem(element);
// 🔍 country
print('🗺️ 构建节点: name="${element.name}", tag="${item.tag}", country="${item.country}"');
print(' - element.country: "${element.country}"');
print(' - item.country: "${item.country}"');
print(' - country.isEmpty: ${item.country.isEmpty}');
if (kDebugMode) {
print('🗺️ 构建节点: name="${element.name}", tag="${item.tag}", country="${item.country}"');
}
if (kDebugMode) {
print(' - element.country: "${element.country}"');
}
if (kDebugMode) {
print(' - item.country: "${item.country}"');
}
if (kDebugMode) {
print(' - country.isEmpty: ${item.country.isEmpty}');
}
// type
if (item.config.isEmpty || !item.config.containsKey('type')) {
print('⚠️ 跳过无效节点: ${element.name},配置为空或缺少 type 字段');
if (kDebugMode) {
print('⚠️ 跳过无效节点: ${element.name},配置为空或缺少 type 字段');
}
continue; //
}
@ -72,7 +83,9 @@ class KrOutboundsList {
configJsonList.add(item.config);
keyList[item.tag] = item;
print('✅ keyList["${item.tag}"] 已设置country="${item.country}"');
if (kDebugMode) {
print('✅ keyList["${item.tag}"] 已设置country="${item.country}"');
}
}
// KRGroupOutboundList groupOutboundList

View File

@ -8,6 +8,7 @@ import 'package:kaer_with_panels/app/services/kr_site_config_service.dart';
import 'dart:async';
import '../../../services/kr_device_info_service.dart';
import 'package:flutter/foundation.dart';
/// Crisp
class KRCrispController extends GetxController {
@ -47,7 +48,9 @@ class KRCrispController extends GetxController {
kr_isInitialized.value = true;
}
} catch (e) {
print('初始化 Crisp 时出错: $e');
if (kDebugMode) {
print('初始化 Crisp 时出错: $e');
}
if (!_kr_isDisposed) {
kr_isInitialized.value = false;
}
@ -125,9 +128,13 @@ class KRCrispController extends GetxController {
'device_id': deviceId,
});
print('Crisp 初始化完成');
if (kDebugMode) {
print('Crisp 初始化完成');
}
} catch (e) {
print('初始化 Crisp 时出错: $e');
if (kDebugMode) {
print('初始化 Crisp 时出错: $e');
}
crispController = null;
rethrow;
}
@ -155,7 +162,9 @@ class KRCrispController extends GetxController {
kr_isLoading.value = false;
}
} catch (e) {
print('清理 Crisp 资源时出错: $e');
if (kDebugMode) {
print('清理 Crisp 资源时出错: $e');
}
}
}

View File

@ -50,7 +50,7 @@ class KRDeleteAccountController extends GetxController {
Future<void> kr_sendCode() async {
final account = KRAppRunData.getInstance().kr_account.value;
if (account == null || account.isEmpty) {
KRCommonUtil.kr_showToast('账号不能为空');
KRCommonUtil.kr_showToast('account.accountRequired'.tr);
return;
}
@ -98,7 +98,7 @@ class KRDeleteAccountController extends GetxController {
KRCommonUtil.kr_showToast(error.msg);
},
(success) {
KRCommonUtil.kr_showToast('删除账号成功');
KRCommonUtil.kr_showToast('account.deleteSuccess'.tr);
KRAppRunData.getInstance().kr_loginOut();
},
);

View File

@ -67,7 +67,7 @@ class KRDeviceManagementView extends GetView<KRDeviceManagementController> {
size: 64.w,
color: Theme.of(context).textTheme.bodySmall?.color,
),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
Text(
'暂无登录设备',
style: KrAppTextStyle(
@ -172,7 +172,7 @@ class KRDeviceManagementView extends GetView<KRDeviceManagementController> {
Container(
padding: EdgeInsets.symmetric(
horizontal: 8.w,
vertical: 2.w,
vertical: 2.h,
),
decoration: BoxDecoration(
color: Colors.green.withOpacity(0.1),
@ -189,7 +189,7 @@ class KRDeviceManagementView extends GetView<KRDeviceManagementController> {
],
],
),
SizedBox(height: 4.w),
SizedBox(height: 4.h),
Text(
'ID: ${identifier.substring(0, identifier.length > 12 ? 12 : identifier.length)}...',
style: KrAppTextStyle(
@ -205,7 +205,7 @@ class KRDeviceManagementView extends GetView<KRDeviceManagementController> {
onPressed: () => controller.deleteDevice(id),
style: TextButton.styleFrom(
foregroundColor: Theme.of(context).colorScheme.error,
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.w),
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 8.h),
),
child: Text(
'删除',
@ -219,9 +219,9 @@ class KRDeviceManagementView extends GetView<KRDeviceManagementController> {
),
// 线
if (ip.isNotEmpty || lastLogin.isNotEmpty) ...[
SizedBox(height: 12.w),
SizedBox(height: 12.h),
Divider(height: 1, color: Theme.of(context).dividerColor),
SizedBox(height: 12.w),
SizedBox(height: 12.h),
],
//
if (ip.isNotEmpty)
@ -230,7 +230,7 @@ class KRDeviceManagementView extends GetView<KRDeviceManagementController> {
'IP地址',
ip,
),
if (ip.isNotEmpty && lastLogin.isNotEmpty) SizedBox(height: 8.w),
if (ip.isNotEmpty && lastLogin.isNotEmpty) SizedBox(height: 8.h),
if (lastLogin.isNotEmpty)
_buildInfoRow(
context,

View File

@ -29,6 +29,7 @@ import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
import 'package:kaer_with_panels/app/utils/kr_common_util.dart';
import 'package:kaer_with_panels/app/utils/kr_secure_storage.dart';
import 'package:kaer_with_panels/app/services/singbox_imp/kr_sing_box_imp.dart';
import 'package:flutter/foundation.dart';
class KRHomeController extends GetxController with WidgetsBindingObserver {
///
@ -264,6 +265,14 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
kr_forceSyncConnectionStatus();
_checkQuickConnectAutoStart();
});
// 🔧 Android 15 5
Future.delayed(const Duration(seconds: 5), () {
if (kr_bottomPanelHeight.value < 100) {
KRLogUtil.kr_w('检测到底部面板高度异常(${kr_bottomPanelHeight.value}),强制修正', tag: 'HomeController');
kr_updateBottomPanelHeight();
}
});
}
@ -271,11 +280,22 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
void _kr_initLoginStatus() {
KRLogUtil.kr_i('初始化登录状态', tag: 'HomeController');
//
Timer(const Duration(seconds: 10), () {
// 🔧 Android 15 8
Timer(const Duration(seconds: 8), () {
if (kr_currentListStatus.value == KRHomeViewsListStatus.kr_loading) {
KRLogUtil.kr_w('订阅服务初始化超时,设置为错误状态', tag: 'HomeController');
kr_currentListStatus.value = KRHomeViewsListStatus.kr_error;
KRLogUtil.kr_w('⏱️ 订阅服务初始化超时(8秒),强制设置为无数据状态', tag: 'HomeController');
// 🔧 Android 15 none error
kr_currentListStatus.value = KRHomeViewsListStatus.kr_none;
//
kr_updateBottomPanelHeight();
KRLogUtil.kr_i('✅ 已强制切换到默认视图', tag: 'HomeController');
}
});
// 🔧 Android 15 3
Timer(const Duration(seconds: 3), () {
if (kr_currentListStatus.value == KRHomeViewsListStatus.kr_loading) {
KRLogUtil.kr_w('⚠️ 订阅服务初始化已耗时3秒可能网络较慢', tag: 'HomeController');
}
});
@ -498,7 +518,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
void _bindConnectionStatus() {
//
ever(KRSingBoxImp.instance.kr_status, (status) {
print('🔵 Controller 收到状态变化: ${status.runtimeType}');
if (kDebugMode) {
print('🔵 Controller 收到状态变化: ${status.runtimeType}');
}
KRLogUtil.kr_i('🔄 连接状态变化: $status', tag: 'HomeController');
KRLogUtil.kr_i('📊 当前状态类型: ${status.runtimeType}', tag: 'HomeController');
@ -526,7 +548,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
break;
case SingboxStarted():
KRLogUtil.kr_i('🟢 状态: 已启动', tag: 'HomeController');
print('🔵 状态变为 Started, 当前延迟=${kr_currentNodeLatency.value}');
if (kDebugMode) {
print('🔵 状态变为 Started, 当前延迟=${kr_currentNodeLatency.value}');
}
//
_cancelConnectionTimeout();
@ -538,10 +562,14 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
// 🔧 -1(),0()
if (kr_currentNodeLatency.value == -1) {
print('🔵 强制将延迟从 -1 更新为 0');
if (kDebugMode) {
print('🔵 强制将延迟从 -1 更新为 0');
}
kr_currentNodeLatency.value = 0;
kr_currentNodeLatency.refresh(); //
print('🔵 延迟值已刷新');
if (kDebugMode) {
print('🔵 延迟值已刷新');
}
}
// 🔧
@ -551,7 +579,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
kr_isConnected.refresh();
// UI
update();
print('🔵 状态更新完成,当前延迟=${kr_currentNodeLatency.value}');
if (kDebugMode) {
print('🔵 状态更新完成,当前延迟=${kr_currentNodeLatency.value}');
}
break;
case SingboxStopping():
KRLogUtil.kr_i('🟠 状态: 正在停止', tag: 'HomeController');
@ -637,12 +667,16 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
final currentStatus = KRSingBoxImp.instance.kr_status.value;
KRLogUtil.kr_i('🔵 toggleSwitch 被调用: value=$value, currentStatus=$currentStatus', tag: 'HomeController');
print('🔵 toggleSwitch: value=$value, currentStatus=$currentStatus');
if (kDebugMode) {
print('🔵 toggleSwitch: value=$value, currentStatus=$currentStatus');
}
// 🔧 : hiddify-app "switching status, debounce"
if (currentStatus is SingboxStarting || currentStatus is SingboxStopping) {
KRLogUtil.kr_i('🔄 正在切换中,忽略本次操作 (当前状态: $currentStatus)', tag: 'HomeController');
print('🔵 忽略操作:正在切换中');
if (kDebugMode) {
print('🔵 忽略操作:正在切换中');
}
return;
}
@ -650,17 +684,23 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
if (value) {
//
KRLogUtil.kr_i('🔄 开始连接...', tag: 'HomeController');
print('🔵 执行 kr_start()');
if (kDebugMode) {
print('🔵 执行 kr_start()');
}
await KRSingBoxImp.instance.kr_start();
KRLogUtil.kr_i('✅ 连接命令已发送', tag: 'HomeController');
print('🔵 kr_start() 完成');
if (kDebugMode) {
print('🔵 kr_start() 完成');
}
// 🔧 : 3
await _waitForStatus(SingboxStarted, maxSeconds: 3);
} else {
//
KRLogUtil.kr_i('🛑 开始断开连接...', tag: 'HomeController');
print('🔵 执行 kr_stop()');
if (kDebugMode) {
print('🔵 执行 kr_stop()');
}
await KRSingBoxImp.instance.kr_stop().timeout(
const Duration(seconds: 10),
onTimeout: () {
@ -669,32 +709,44 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
},
);
KRLogUtil.kr_i('✅ 断开命令已发送', tag: 'HomeController');
print('🔵 kr_stop() 完成');
if (kDebugMode) {
print('🔵 kr_stop() 完成');
}
// 🔧 : 2
await _waitForStatus(SingboxStopped, maxSeconds: 2);
}
} catch (e) {
KRLogUtil.kr_e('❌ 切换失败: $e', tag: 'HomeController');
print('🔵 切换失败: $e');
if (kDebugMode) {
print('🔵 切换失败: $e');
}
//
kr_forceSyncConnectionStatus();
}
print('🔵 toggleSwitch 完成,当前 kr_isConnected=${kr_isConnected.value}');
if (kDebugMode) {
print('🔵 toggleSwitch 完成,当前 kr_isConnected=${kr_isConnected.value}');
}
}
/// 🔧
Future<void> _waitForStatus(Type expectedType, {int maxSeconds = 3}) async {
print('🔵 等待状态变为: $expectedType');
if (kDebugMode) {
print('🔵 等待状态变为: $expectedType');
}
final startTime = DateTime.now();
while (DateTime.now().difference(startTime).inSeconds < maxSeconds) {
final currentStatus = KRSingBoxImp.instance.kr_status.value;
print('🔵 当前状态: ${currentStatus.runtimeType}');
if (kDebugMode) {
print('🔵 当前状态: ${currentStatus.runtimeType}');
}
if (currentStatus.runtimeType == expectedType) {
print('🔵 状态已达到: $expectedType');
if (kDebugMode) {
print('🔵 状态已达到: $expectedType');
}
// kr_isConnected
kr_forceSyncConnectionStatus();
return;
@ -703,7 +755,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
await Future.delayed(const Duration(milliseconds: 100));
}
print('🔵 等待超时,强制同步状态');
if (kDebugMode) {
print('🔵 等待超时,强制同步状态');
}
kr_forceSyncConnectionStatus();
}
@ -988,9 +1042,9 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
return true;
}
// 4. VPN已连接
// 4. VPN已连接VPN以断开现有连接并应用新节点
try {
KRLogUtil.kr_i('🔌 VPN已连接开始切换后台节点: $tag', tag: 'HomeController');
KRLogUtil.kr_i('🔌 VPN已连接将重启VPN以断开现有连接: $tag', tag: 'HomeController');
// 🔧
KRLogUtil.kr_i('📊 当前活动组数量: ${KRSingBoxImp.instance.kr_activeGroups.length}', tag: 'HomeController');
@ -1007,22 +1061,61 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
kr_currentNodeLatency.value = -1;
kr_isLatency.value = true; //
//
KRLogUtil.kr_i('⏳ 调用 kr_selectOutbound($tag),等待完成...', tag: 'HomeController');
await KRSingBoxImp.instance.kr_selectOutbound(tag);
KRLogUtil.kr_i('✅ kr_selectOutbound 完成,开始更新 UI', tag: 'HomeController');
// 🔧
KRLogUtil.kr_i('💾 保存新节点选择: $tag', tag: 'HomeController');
await KRSecureStorage().kr_saveData(key: 'SELECTED_NODE_TAG', value: tag);
// 🔧 A增强VPN连接以断开所有现有长连接
KRLogUtil.kr_i('🔄 [增强] 停止VPN连接以断开现有连接...', tag: 'HomeController');
await KRSingBoxImp.instance.kr_stop(); // VPN
// 🚀 A增强
KRLogUtil.kr_i('⏳ [增强] 等待VPN完全停止1500ms确保旧连接全部断开...', tag: 'HomeController');
await Future.delayed(const Duration(milliseconds: 1500)); // 800ms增加到1500ms
KRLogUtil.kr_i('🔄 [增强] 启动VPN并应用新节点: $tag', tag: 'HomeController');
await KRSingBoxImp.instance.kr_start(); // VPN使
// 🚀 A增强VPN完全建立
KRLogUtil.kr_i('⏳ [增强] 等待VPN完全启动2500ms确保新连接完全建立...', tag: 'HomeController');
await Future.delayed(const Duration(milliseconds: 2500)); // 1500ms增加到2500ms
// UI
kr_cutSeletedTag.value = tag;
kr_updateConnectionInfo();
kr_moveToSelectedNode();
// 🔧
// UI继续显示"正在连接"
await Future.delayed(const Duration(milliseconds: 200)); //
// 🚀 A增强
KRLogUtil.kr_i('⏳ [增强] 等待活动组更新500ms...', tag: 'HomeController');
await Future.delayed(const Duration(milliseconds: 500)); // 200ms增加到500ms
// 🚀 A增强
KRLogUtil.kr_i('🔍 [增强] 验证节点切换是否成功...', tag: 'HomeController');
try {
//
final activeGroups = KRSingBoxImp.instance.kr_activeGroups;
final selectGroup = activeGroups.firstWhere(
(group) => group.tag == 'select',
orElse: () => throw Exception('未找到 select 组'),
);
KRLogUtil.kr_i('📊 [增强] Select组当前选中: ${selectGroup.selected}', tag: 'HomeController');
KRLogUtil.kr_i('📊 [增强] 目标节点: $tag', tag: 'HomeController');
if (selectGroup.selected != tag) {
KRLogUtil.kr_w('⚠️ [增强] 节点选择验证失败,实际选中: ${selectGroup.selected}', tag: 'HomeController');
//
} else {
KRLogUtil.kr_i('✅ [增强] 节点选择验证成功!', tag: 'HomeController');
}
} catch (e) {
KRLogUtil.kr_w('⚠️ [增强] 节点验证过程出错: $e', tag: 'HomeController');
}
//
_kr_updateLatencyOnConnected();
KRLogUtil.kr_i('✅ 节点切换成功: $tag', tag: 'HomeController');
KRLogUtil.kr_i('✅ 节点切换成功(已重启VPN断开旧连接): $tag', tag: 'HomeController');
return true;
} catch (switchError) {
@ -1034,6 +1127,13 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
kr_currentNodeName.value = originalTag; // 🔧
kr_currentNodeLatency.value = -2; //
//
try {
await KRSecureStorage().kr_saveData(key: 'SELECTED_NODE_TAG', value: originalTag);
} catch (e) {
KRLogUtil.kr_e('❌ 恢复节点选择失败: $e', tag: 'HomeController');
}
//
KRCommonUtil.kr_showToast('节点切换失败,已恢复为: $originalTag');
@ -1333,8 +1433,10 @@ class KRHomeController extends GetxController with WidgetsBindingObserver {
//
void kr_updateBottomPanelHeight() {
// 🔧 Android 15
if (kr_subscribeService.kr_currentStatus ==
KRHomeViewsListStatus.kr_loading) {
KRHomeViewsListStatus.kr_loading &&
kr_currentListStatus.value != KRHomeViewsListStatus.kr_loading) {
return;
}

View File

@ -50,81 +50,76 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
}
Widget _kr_buildDefaultView(BuildContext context) {
// 使 GetX .obs 访
final hasValidSubscription =
controller.kr_subscribeService.kr_currentSubscribe.value != null;
final isTrial = controller.kr_subscribeService.kr_isTrial;
final isLastDay = controller.kr_subscribeService.kr_isLastDayOfSubscription;
// 🔧 Android 15
bool hasValidSubscription = false;
bool isTrial = false;
bool isLastDay = false;
try {
hasValidSubscription = controller.kr_subscribeService.kr_currentSubscribe.value != null;
isTrial = controller.kr_subscribeService.kr_isTrial.value;
isLastDay = controller.kr_subscribeService.kr_isLastDayOfSubscription.value;
} catch (e) {
KRLogUtil.kr_e('获取订阅数据异常: $e', tag: 'HomeBottomPanel');
}
final isNotLoggedIn = controller.kr_currentViewStatus.value ==
KRHomeViewsStatus.kr_notLoggedIn;
KRLogUtil.kr_i('构建默认视图', tag: 'HomeBottomPanel');
KRLogUtil.kr_i('是否未登录: $isNotLoggedIn', tag: 'HomeBottomPanel');
KRLogUtil.kr_i('是否有有效订阅: $hasValidSubscription', tag: 'HomeBottomPanel');
KRLogUtil.kr_i('是否试用: ${isTrial.value}', tag: 'HomeBottomPanel');
KRLogUtil.kr_i('是否试用: $isTrial', tag: 'HomeBottomPanel');
KRLogUtil.kr_i('当前高度: ${controller.kr_bottomPanelHeight.value}',
tag: 'HomeBottomPanel');
// 🔧 UI
return Column(
mainAxisSize: MainAxisSize.min,
children: [
//
if (isNotLoggedIn)
// 使 SingleChildScrollView
SingleChildScrollView(
// - 使 Expanded + ScrollView
Expanded(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 🔧
if (hasValidSubscription)
//
Container(
margin: EdgeInsets.only(top: 12.h),
child: const KRHomeConnectionInfoView(),
)
else
//
Container(
margin: EdgeInsets.only(top: 12.h, left: 12.w, right: 12.w),
child: const KRSubscriptionCard(),
),
// 2.
if (hasValidSubscription && isTrial)
Container(
margin: EdgeInsets.only(top: 12.h),
child: const KRHomeTrialCard(),
),
// 3.
if (hasValidSubscription && isLastDay && !isTrial)
Container(
margin: EdgeInsets.only(top: 12.h),
child: const KRHomeLastDayCard(),
),
// 4. -
Padding(
padding:
EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.w),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
child: const KRHomeConnectionOptionsView(),
),
],
),
)
else
// 使
Expanded(
child: SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 1.
if (hasValidSubscription)
Container(
margin: EdgeInsets.only(top: 12.h),
child: const KRHomeConnectionInfoView())
else
Container(
margin:
EdgeInsets.only(top: 12.h, left: 12.w, right: 12.w),
child: const KRSubscriptionCard()),
// 2.
if (hasValidSubscription && isTrial.value)
Container(
margin: EdgeInsets.only(top: 12.h),
child: const KRHomeTrialCard(),
),
// 3.
if (hasValidSubscription && isLastDay.value && !isTrial.value)
Container(
margin: EdgeInsets.only(top: 12.h),
child: const KRHomeLastDayCard(),
),
// 4.
Padding(
padding:
EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.w),
child: const KRHomeConnectionOptionsView(),
),
],
),
),
),
),
],
);
}
@ -134,17 +129,56 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
KRLogUtil.kr_i('当前高度: ${controller.kr_bottomPanelHeight.value}',
tag: 'HomeBottomPanel');
return Center(
child: CircularProgressIndicator(
color: Colors.green,
strokeWidth: 2.0,
),
// 🔧 Android 15 +
//
return Stack(
children: [
//
Opacity(
opacity: 0.5,
child: _kr_buildDefaultView(Get.context!),
),
//
Center(
child: Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: Get.context!.theme.cardColor,
borderRadius: BorderRadius.circular(12.r),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(
color: Colors.green,
strokeWidth: 3.0,
),
SizedBox(height: 12.h),
Text(
'正在加载...',
style: TextStyle(
fontSize: 14.sp,
color: Get.context!.theme.textTheme.bodyMedium?.color,
),
),
],
),
),
),
],
);
}
Widget _kr_buildErrorView(BuildContext context) {
return Container(
height: 200.w,
height: 200.h,
padding: EdgeInsets.all(16.w),
child: Center(
child: Column(
@ -155,7 +189,7 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
size: 48.w,
color: Theme.of(context).colorScheme.error,
),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
Text(
AppTranslations.kr_home.error,
style: KrAppTextStyle(
@ -164,7 +198,7 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
color: Theme.of(context).textTheme.bodyMedium?.color,
),
),
SizedBox(height: 8.w),
SizedBox(height: 8.h),
Text(
AppTranslations.kr_home.checkNetwork,
style: KrAppTextStyle(
@ -172,7 +206,7 @@ class KRHomeBottomPanel extends GetView<KRHomeController> {
color: Theme.of(context).textTheme.bodySmall?.color,
),
),
SizedBox(height: 24.w),
SizedBox(height: 24.h),
SizedBox(
width: 200.w,
height: 44.h,

View File

@ -10,6 +10,7 @@ import 'package:kaer_with_panels/app/services/singbox_imp/kr_sing_box_imp.dart';
import 'package:kaer_with_panels/singbox/model/singbox_status.dart';
import '../controllers/kr_home_controller.dart';
import '../models/kr_home_views_status.dart';
import 'package:flutter/foundation.dart';
class KRHomeConnectionInfoView extends GetView<KRHomeController> {
const KRHomeConnectionInfoView({super.key});
@ -26,7 +27,7 @@ class KRHomeConnectionInfoView extends GetView<KRHomeController> {
return Container(
margin: EdgeInsets.symmetric(horizontal: 16.w),
width: double.infinity,
height: 116.w,
height: 116.h,
decoration: ShapeDecoration(
color: Theme.of(context).cardColor,
shape: RoundedRectangleBorder(
@ -73,7 +74,7 @@ class KRHomeConnectionInfoView extends GetView<KRHomeController> {
),
],
),
SizedBox(height: 10.w),
SizedBox(height: 10.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -82,7 +83,9 @@ class KRHomeConnectionInfoView extends GetView<KRHomeController> {
// 🔧 使 Obx
Obx(() {
final countryCode = controller.kr_getCurrentNodeCountry();
print('🌍 ConnectionInfo 更新,国家代码: $countryCode');
if (kDebugMode) {
print('🌍 ConnectionInfo 更新,国家代码: $countryCode');
}
return KRCountryFlag(
countryCode: countryCode,
);
@ -99,12 +102,14 @@ class KRHomeConnectionInfoView extends GetView<KRHomeController> {
fontWeight: FontWeight.w500,
),
),
SizedBox(height: 6.w),
SizedBox(height: 6.h),
Row(
children: [
Obx(() {
final delay = controller.kr_currentNodeLatency.value;
print('🔵 UI延迟显示更新: delay=$delay');
if (kDebugMode) {
print('🔵 UI延迟显示更新: delay=$delay');
}
//
Color getLatencyColor(int delay) {
@ -227,7 +232,9 @@ class KRHomeConnectionInfoView extends GetView<KRHomeController> {
final isSwitching = status is SingboxStarting || status is SingboxStopping;
// 🔧
print('🔵 Switch UI 更新: status=${status.runtimeType}, isConnected=$isConnected, isSwitching=$isSwitching');
if (kDebugMode) {
print('🔵 Switch UI 更新: status=${status.runtimeType}, isConnected=$isConnected, isSwitching=$isSwitching');
}
return CupertinoSwitch(
value: isConnected,
@ -235,7 +242,9 @@ class KRHomeConnectionInfoView extends GetView<KRHomeController> {
onChanged: isSwitching
? null
: (bool value) {
print('🔵 Switch onChanged 触发: 请求=$value, 当前状态=$status');
if (kDebugMode) {
print('🔵 Switch onChanged 触发: 请求=$value, 当前状态=$status');
}
controller.kr_toggleSwitch(value);
},
activeColor: Colors.blue,

View File

@ -26,7 +26,7 @@ class KRHomeConnectionOptionsView extends GetView<KRHomeController> {
color: Theme.of(context).textTheme.bodyMedium?.color,
),
),
SizedBox(height: 8.w),
SizedBox(height: 8.h),
_buildConnectionOption(
"home_ct",
AppTranslations.kr_home.countryRegion,
@ -66,7 +66,7 @@ class KRHomeConnectionOptionsView extends GetView<KRHomeController> {
height: 32.w,
color: Theme.of(context).textTheme.bodyMedium?.color,
),
SizedBox(height: 12.w),
SizedBox(height: 12.h),
Row(
children: [
Expanded(

View File

@ -64,7 +64,7 @@ class KRHomeLastDayCard extends GetView<KRHomeController> {
),
//
SizedBox(height: 10.w),
SizedBox(height: 10.h),
Row(
children: [
Container(
@ -123,7 +123,7 @@ class KRHomeLastDayCard extends GetView<KRHomeController> {
?.color,
),
),
SizedBox(height: 4.w),
SizedBox(height: 4.h),
Text(
AppTranslations.kr_home.subscriptionEndMessage,
style: KrAppTextStyle(

View File

@ -16,6 +16,7 @@ import 'package:kaer_with_panels/app/widgets/kr_network_image.dart';
import '../../../widgets/kr_simple_loading.dart';
import '../../../../singbox/model/singbox_proxy_type.dart';
import 'package:flutter/foundation.dart';
///
///
@ -71,7 +72,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
Widget _buildServerList(BuildContext context) {
return Container(
width: ScreenUtil().screenWidth,
height: 360.w, //
height: 360.h, //
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
borderRadius: BorderRadius.only(
@ -83,7 +84,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
children: [
//
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.w),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -221,7 +222,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
country.isExpand.value = !country.isExpand.value;
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 12.w),
padding: EdgeInsets.symmetric(vertical: 12.h),
child: Row(
children: [
KRCountryFlag(
@ -281,7 +282,9 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
// 🔧 async
onTap: () async {
try {
print('🔄 用户点击节点: ${server.tag}');
if (kDebugMode) {
print('🔄 用户点击节点: ${server.tag}');
}
// 使
final success = await controller
.kr_performNodeSwitch(server.tag);
@ -290,19 +293,25 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
if (success) {
controller.kr_currentListStatus.value =
KRHomeViewsListStatus.kr_none;
print('✅ 节点切换成功,关闭列表');
if (kDebugMode) {
print('✅ 节点切换成功,关闭列表');
}
} else {
print('❌ 节点切换失败,列表保持打开');
if (kDebugMode) {
print('❌ 节点切换失败,列表保持打开');
}
}
} catch (e) {
print('❌ 节点切换异常: $e');
if (kDebugMode) {
print('❌ 节点切换异常: $e');
}
KRLogUtil.kr_e('节点切换异常: $e',
tag: 'NodeListView');
}
},
child: Container(
padding: EdgeInsets.symmetric(
vertical: 8.w,
vertical: 8.h,
horizontal: 16.w,
),
decoration: BoxDecoration(
@ -397,7 +406,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
}
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 4.w),
padding: EdgeInsets.symmetric(vertical: 4.h),
child: _kr_buildNodeListItem(
context,
item: server,
@ -444,13 +453,13 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
onClose: () =>
controller.kr_currentListStatus.value = KRHomeViewsListStatus.kr_none,
),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
Expanded(
child: Column(
children: [
Expanded(child: listContent),
//
SizedBox(height: 12.w),
SizedBox(height: 12.h),
],
),
),
@ -544,7 +553,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
return Container(
key: ValueKey(item.id),
padding: EdgeInsets.symmetric(vertical: 8.w),
padding: EdgeInsets.symmetric(vertical: 8.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -575,7 +584,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
? Container(
margin: EdgeInsets.only(left: 4.w),
padding: EdgeInsets.symmetric(
horizontal: 4.w, vertical: 1.w),
horizontal: 4.w, vertical: 1.h),
decoration: BoxDecoration(
color: krModernGreenLight.withOpacity(0.1),
borderRadius: BorderRadius.circular(4.w),
@ -593,7 +602,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
),
],
),
SizedBox(height: 2.w),
SizedBox(height: 2.h),
Text(
item.city,
style: KrAppTextStyle(
@ -666,7 +675,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
InkWell(
onTap: () => controller.kr_urlTest(),
child: Container(
padding: EdgeInsets.symmetric(vertical: 8.w),
padding: EdgeInsets.symmetric(vertical: 8.h),
margin: EdgeInsets.only(top: 8.w), //
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
@ -719,7 +728,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
),
),
if (!controller.kr_isLatency.value) ...[
SizedBox(height: 2.w),
SizedBox(height: 2.h),
Text(
AppTranslations.kr_home.refreshLatencyDesc,
style: KrAppTextStyle(
@ -766,7 +775,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
}
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 8.w),
padding: EdgeInsets.symmetric(vertical: 8.h),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
@ -801,7 +810,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
Container(
margin: EdgeInsets.only(left: 4.w),
padding: EdgeInsets.symmetric(
horizontal: 4.w, vertical: 1.w),
horizontal: 4.w, vertical: 1.h),
decoration: BoxDecoration(
color:
krModernGreenLight.withOpacity(0.1),
@ -818,7 +827,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
),
],
),
SizedBox(height: 2.w),
SizedBox(height: 2.h),
Obx(() {
//
String selectedNode =
@ -920,7 +929,7 @@ class KRHomeNodeListView extends GetView<KRHomeController> {
}
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 4.w),
padding: EdgeInsets.symmetric(vertical: 4.h),
child: _kr_buildNodeListItem(
context,
item: node,

View File

@ -65,7 +65,7 @@ class KRHomeTrialCard extends GetView<KRHomeController> {
),
//
SizedBox(height: 10.w),
SizedBox(height: 10.h),
Row(
children: [
Container(
@ -133,7 +133,7 @@ class KRHomeTrialCard extends GetView<KRHomeController> {
: Theme.of(context).textTheme.bodyMedium?.color,
),
),
SizedBox(height: 4.w),
SizedBox(height: 4.h),
Text(
AppTranslations.kr_home.trialEndMessage,
style: KrAppTextStyle(

View File

@ -5,6 +5,7 @@ import 'package:latlong2/latlong.dart';
import '../../../utils/kr_fm_tc.dart';
import '../controllers/kr_home_controller.dart';
import '../../../utils/kr_log_util.dart';
import 'package:flutter/foundation.dart';
///
class KRHomeMapView extends GetView<KRHomeController> {
@ -187,12 +188,16 @@ return GetBuilder<KRHomeController>(
///
Marker _buildStyledMarker(dynamic node) {
print("原始Marker${node}");
if (kDebugMode) {
print("原始Marker${node}");
}
int type = 0;
MaterialColor markerColor = Colors.grey;
//
bool status = controller.kr_isConnected.value;
print("连接状态:$status");
if (kDebugMode) {
print("连接状态:$status");
}
if(status){
if (node.urlTestDelay.value == 0) {
// 0使

View File

@ -37,7 +37,7 @@ class KRSubscribeSelectorView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.w),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
decoration: BoxDecoration(
color: Colors.blue.withOpacity(0.05),
borderRadius: BorderRadius.only(
@ -78,7 +78,7 @@ class KRSubscribeSelectorView extends StatelessWidget {
final subscribes = homeController.kr_subscribeService.kr_availableSubscribes;
if (subscribes.isEmpty) {
return Padding(
padding: EdgeInsets.symmetric(vertical: 16.w, horizontal: 12.w),
padding: EdgeInsets.symmetric(vertical: 16.h, horizontal: 12.w),
child: Column(
children: [
Icon(
@ -86,7 +86,7 @@ class KRSubscribeSelectorView extends StatelessWidget {
size: 48.w,
color: Theme.of(context).textTheme.bodyLarge?.color?.withOpacity(0.3),
),
SizedBox(height: 12.w),
SizedBox(height: 12.h),
Text(
AppTranslations.kr_purchaseMembership.noData,
style: KrAppTextStyle(
@ -105,7 +105,7 @@ class KRSubscribeSelectorView extends StatelessWidget {
),
child: ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.symmetric(vertical: 4.w, horizontal: 4.w),
padding: EdgeInsets.symmetric(vertical: 4.h, horizontal: 4.w),
itemCount: subscribes.length,
itemBuilder: (context, index) {
final subscribe = subscribes[index];
@ -123,7 +123,7 @@ class KRSubscribeSelectorView extends StatelessWidget {
),
);
}),
SizedBox(height: 8.w),
SizedBox(height: 8.h),
],
),
);
@ -159,7 +159,7 @@ class _SubscribeItem extends StatelessWidget {
}
return Padding(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.w),
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
child: Material(
color: Colors.transparent,
child: InkWell(
@ -199,7 +199,7 @@ class _SubscribeItem extends StatelessWidget {
),
if (isCurrent)
Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.w),
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 2.h),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(16.r),
@ -222,7 +222,7 @@ class _SubscribeItem extends StatelessWidget {
),
],
),
SizedBox(height: 8.w),
SizedBox(height: 8.h),
Text(
isUnlimited
? AppTranslations.kr_purchaseMembership.unlimitedTraffic
@ -234,7 +234,7 @@ class _SubscribeItem extends StatelessWidget {
),
),
if (!isUnlimited) ...[
SizedBox(height: 8.w),
SizedBox(height: 8.h),
ClipRRect(
borderRadius: BorderRadius.circular(4.r),
child: LinearProgressIndicator(

View File

@ -158,7 +158,7 @@ class KRInviteController extends GetxController {
borderRadius: BorderRadius.circular(16.r),
),
child: Container(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 24.w),
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 24.h),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -170,7 +170,7 @@ class KRInviteController extends GetxController {
color: Theme.of(Get.context!).textTheme.titleMedium?.color,
),
),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
@ -195,7 +195,7 @@ class KRInviteController extends GetxController {
foregroundColor: Colors.black,
),
),
SizedBox(height: 20.w),
SizedBox(height: 20.h),
Container(
width: double.infinity,
height: 44.w,

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:kaer_with_panels/app/common/app_config.dart';
import 'package:kaer_with_panels/app/localization/app_translations.dart';
import 'package:kaer_with_panels/app/widgets/kr_local_image.dart';
import '../controllers/kr_invite_controller.dart';

View File

@ -75,6 +75,9 @@ class KRLoginController extends GetxController
///
var kr_loginStatus = KRLoginProgressStatus.kr_registerSendCode.obs;
/// 使true=false=
var kr_isPasswordLogin = true.obs;
///
var _countdown = 60; //
late Timer _timer;
@ -172,8 +175,8 @@ class KRLoginController extends GetxController
}
// entry kr_loginByPsd
}
//
_timer = Timer(Duration.zero, () {});

View File

@ -11,6 +11,7 @@ import 'package:kaer_with_panels/app/widgets/hi_help_entrance.dart';
import 'package:kaer_with_panels/app/common/app_run_data.dart';
import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_controller.dart';
import 'package:kaer_with_panels/app/services/kr_site_config_service.dart';
import 'package:flutter/foundation.dart';
class KRLoginView extends GetView<KRLoginController> {
const KRLoginView({super.key});

View File

@ -35,7 +35,7 @@ class KRSearchAreaView extends GetView<KRSearchAreaController> {
onTap: () {}, //
child: Container(
width: 300.w,
height: 450.w,
height: 450.h,
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
color: theme.primaryColor,
@ -46,18 +46,18 @@ class KRSearchAreaView extends GetView<KRSearchAreaController> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'选择其他地区',
'login.selectOtherRegion'.tr,
style: KrAppTextStyle(
fontSize: 15.w,
fontWeight: FontWeight.w500,
color: theme.textTheme.titleMedium?.color),
),
SizedBox(height: 10.w),
SizedBox(height: 10.h),
TextField(
onChanged: (value) => controller.searchQuery.value = value,
decoration: InputDecoration(
prefixIcon: Icon(Icons.search, color: Colors.grey),
hintText: '搜索',
hintText: 'login.search'.tr,
hintStyle: TextStyle(color: Colors.grey),
filled: true,
// fillColor: Colors.grey.shade200,
@ -65,11 +65,11 @@ class KRSearchAreaView extends GetView<KRSearchAreaController> {
borderRadius: BorderRadius.circular(8.w),
borderSide: BorderSide.none,
),
contentPadding: EdgeInsets.symmetric(vertical: 10.w),
contentPadding: EdgeInsets.symmetric(vertical: 10.h),
),
style: theme.textTheme.bodyMedium?.copyWith(fontSize: 14.sp, fontFamily: 'AlibabaPuHuiTi-Regular',),
),
// SizedBox(height: 5.w),
// SizedBox(height: 5.h),
Obx(() => Expanded(
child: ListView.builder(
padding: EdgeInsets.zero,
@ -84,7 +84,7 @@ class KRSearchAreaView extends GetView<KRSearchAreaController> {
},
child: Container(
padding: EdgeInsets.symmetric(
vertical: 10.w, horizontal: 0),
vertical: 10.h, horizontal: 0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(

View File

@ -6,6 +6,10 @@ import 'package:kaer_with_panels/app/modules/kr_statistics/views/kr_statistics_v
import 'package:kaer_with_panels/app/modules/kr_user_info/views/kr_user_info_view.dart';
import 'package:kaer_with_panels/app/modules/kr_user_info/controllers/kr_user_info_controller.dart';
import 'package:kaer_with_panels/app/widgets/kr_keep_alive_wrapper.dart';
import 'package:kaer_with_panels/app/common/app_run_data.dart';
import 'package:kaer_with_panels/app/localization/app_translations.dart';
import 'package:kaer_with_panels/app/widgets/dialogs/kr_dialog.dart';
import 'package:kaer_with_panels/app/routes/app_pages.dart';
import '../../../widgets/kr_language_switch_dialog.dart';
@ -56,9 +60,38 @@ class KRMainController extends GetxController {
/// MainRoutes的枚举类
kr_setPage(int index) {
// 🔒 (index=1)
if (index == 1) {
final appRunData = KRAppRunData.getInstance();
final isDeviceLogin = appRunData.isDeviceLogin();
final isLoggedIn = appRunData.kr_isLogin.value && !isDeviceLogin;
//
if (!isLoggedIn) {
KRDialog.show(
title: AppTranslations.kr_dialog.deviceLoginBindingTitle,
message: AppTranslations.kr_dialog.deviceLoginBindingMessage,
confirmText: AppTranslations.kr_dialog.kr_ok,
cancelText: AppTranslations.kr_dialog.kr_cancel,
onConfirm: () {
Get.back(); //
//
Future.delayed(const Duration(milliseconds: 300), () {
Get.toNamed(Routes.MR_LOGIN);
});
},
onCancel: () {
Get.back(); //
},
);
return; //
}
}
//
kr_currentIndex.value = index;
pageController.jumpToPage(index);
//
if (index == MainRoutes.USER_CENTER.i) {
final userInfoController = Get.find<KRUserInfoController>();

View File

@ -10,6 +10,7 @@ import '../../../utils/kr_event_bus.dart';
import '../../../utils/kr_common_util.dart';
import '../../../localization/app_translations.dart';
import '../../../utils/kr_log_util.dart';
import 'package:flutter/foundation.dart';
/// Tauri
class KROrderStatusController extends GetxController {
@ -71,12 +72,24 @@ class KROrderStatusController extends GetxController {
@override
void onInit() {
super.onInit();
print('═══════════════════════════════════════');
print('📊 订单状态页面初始化');
print(' 订单号: $kr_order');
print(' 支付方式: $kr_paymentType');
print(' Checkout类型: $kr_checkoutType');
print('═══════════════════════════════════════');
if (kDebugMode) {
print('═══════════════════════════════════════');
}
if (kDebugMode) {
print('📊 订单状态页面初始化');
}
if (kDebugMode) {
print(' 订单号: $kr_order');
}
if (kDebugMode) {
print(' 支付方式: $kr_paymentType');
}
if (kDebugMode) {
print(' Checkout类型: $kr_checkoutType');
}
if (kDebugMode) {
print('═══════════════════════════════════════');
}
//
kr_checkPaymentStatus();
@ -92,7 +105,9 @@ class KROrderStatusController extends GetxController {
@override
void onClose() {
print('🔚 订单状态页面关闭,清理定时器');
if (kDebugMode) {
print('🔚 订单状态页面关闭,清理定时器');
}
kr_timer?.cancel();
kr_countdownTimer?.cancel();
super.onClose();
@ -100,7 +115,9 @@ class KROrderStatusController extends GetxController {
/// Tauri 5
void kr_startCheckingPaymentStatus() {
print('🔄 启动支付状态轮询每5秒检查一次');
if (kDebugMode) {
print('🔄 启动支付状态轮询每5秒检查一次');
}
// 5
kr_timer = Timer.periodic(const Duration(seconds: 5), (timer) {
@ -118,7 +135,9 @@ class KROrderStatusController extends GetxController {
if (kr_orderCreatedAt == null) {
//
kr_formattedCountdown.value = '15:00';
print('⏱️ 倒计时更新: 等待订单创建时间...');
if (kDebugMode) {
print('⏱️ 倒计时更新: 等待订单创建时间...');
}
return;
}
@ -128,12 +147,24 @@ class KROrderStatusController extends GetxController {
final timeLeft = targetTime - now;
print('⏱️ 倒计时调试信息:');
print(' 当前时间(ms): $now');
print(' 创建时间(ms): $createdAt');
print(' 目标时间(ms): $targetTime');
print(' 剩余时间(ms): $timeLeft');
print(' 剩余时间(秒): ${(timeLeft / 1000).floor()}');
if (kDebugMode) {
print('⏱️ 倒计时调试信息:');
}
if (kDebugMode) {
print(' 当前时间(ms): $now');
}
if (kDebugMode) {
print(' 创建时间(ms): $createdAt');
}
if (kDebugMode) {
print(' 目标时间(ms): $targetTime');
}
if (kDebugMode) {
print(' 剩余时间(ms): $timeLeft');
}
if (kDebugMode) {
print(' 剩余时间(秒): ${(timeLeft / 1000).floor()}');
}
if (timeLeft > 0) {
kr_countdown.value = timeLeft;
@ -141,7 +172,9 @@ class KROrderStatusController extends GetxController {
final minutes = (timeLeft / 60000).floor();
final seconds = ((timeLeft % 60000) / 1000).floor();
kr_formattedCountdown.value = '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
print(' 格式化倒计时: ${kr_formattedCountdown.value}');
if (kDebugMode) {
print(' 格式化倒计时: ${kr_formattedCountdown.value}');
}
} else {
//
kr_countdown.value = 0;
@ -149,7 +182,9 @@ class KROrderStatusController extends GetxController {
kr_countdownTimer?.cancel();
kr_timer?.cancel();
print('⏱️ 订单支付超时15分钟');
if (kDebugMode) {
print('⏱️ 订单支付超时15分钟');
}
kr_statusTitle.value = AppTranslations.kr_orderStatus.closedTitle;
kr_statusDescription.value = AppTranslations.kr_orderStatus.timeoutMessage;
kr_isLoading.value = false;
@ -161,14 +196,18 @@ class KROrderStatusController extends GetxController {
final now = DateTime.now().millisecondsSinceEpoch;
try {
print('🔍 检查订单状态 [${kr_order}]');
if (kDebugMode) {
print('🔍 检查订单状态 [${kr_order}]');
}
// 使
final result = await kr_subscribeApi.kr_queryOrderStatus(kr_order);
result.fold(
(error) {
print('❌ 查询失败: ${error.msg}');
if (kDebugMode) {
print('❌ 查询失败: ${error.msg}');
}
KRLogUtil.kr_e('检查支付状态失败: ${error.msg}', tag: 'OrderStatusController');
kr_isLoading.value = false;
kr_statusTitle.value = AppTranslations.kr_orderStatus.checkFailedTitle;
@ -186,13 +225,23 @@ class KROrderStatusController extends GetxController {
isMilliseconds ? timestamp : timestamp * 1000
);
print('📅 订单创建时间: ${kr_orderCreatedAt}');
print('📅 原始时间戳: $timestamp');
print('📅 时间戳类型: ${isMilliseconds ? "毫秒级" : "秒级"}');
print('📅 转换后时间戳(ms): ${kr_orderCreatedAt!.millisecondsSinceEpoch}');
if (kDebugMode) {
print('📅 订单创建时间: ${kr_orderCreatedAt}');
}
if (kDebugMode) {
print('📅 原始时间戳: $timestamp');
}
if (kDebugMode) {
print('📅 时间戳类型: ${isMilliseconds ? "毫秒级" : "秒级"}');
}
if (kDebugMode) {
print('📅 转换后时间戳(ms): ${kr_orderCreatedAt!.millisecondsSinceEpoch}');
}
}
print('📊 订单状态: ${kr_orderStatus.kr_status} (${_getStatusName(kr_orderStatus.kr_status)})');
if (kDebugMode) {
print('📊 订单状态: ${kr_orderStatus.kr_status} (${_getStatusName(kr_orderStatus.kr_status)})');
}
switch (kr_orderStatus.kr_status) {
case kr_statusPending:
@ -204,7 +253,9 @@ class KROrderStatusController extends GetxController {
case kr_statusPaid:
//
print('✅ 订单已支付,等待确认...');
if (kDebugMode) {
print('✅ 订单已支付,等待确认...');
}
kr_statusTitle.value = AppTranslations.kr_orderStatus.paidTitle;
kr_statusDescription.value = AppTranslations.kr_orderStatus.paidDescription;
kr_statusIcon.value = 'payment_success';
@ -212,7 +263,9 @@ class KROrderStatusController extends GetxController {
case kr_statusFinished:
//
print('🎉 订单完成!停止轮询');
if (kDebugMode) {
print('🎉 订单完成!停止轮询');
}
kr_isPaymentSuccess.value = true;
kr_isLoading.value = false;
kr_timer?.cancel();
@ -226,7 +279,9 @@ class KROrderStatusController extends GetxController {
case kr_statusClose:
//
print('❌ 订单已关闭');
if (kDebugMode) {
print('❌ 订单已关闭');
}
kr_isLoading.value = false;
kr_timer?.cancel();
kr_countdownTimer?.cancel();
@ -237,7 +292,9 @@ class KROrderStatusController extends GetxController {
case kr_statusFailed:
//
print('❌ 支付失败');
if (kDebugMode) {
print('❌ 支付失败');
}
kr_isLoading.value = false;
kr_timer?.cancel();
kr_countdownTimer?.cancel();
@ -248,7 +305,9 @@ class KROrderStatusController extends GetxController {
default:
//
print('⚠️ 未知状态: ${kr_orderStatus.kr_status}');
if (kDebugMode) {
print('⚠️ 未知状态: ${kr_orderStatus.kr_status}');
}
kr_isLoading.value = false;
kr_timer?.cancel();
kr_countdownTimer?.cancel();
@ -262,7 +321,9 @@ class KROrderStatusController extends GetxController {
},
);
} catch (error) {
print('❌ 异常: $error');
if (kDebugMode) {
print('❌ 异常: $error');
}
KRLogUtil.kr_e('检查支付状态失败: $error', tag: 'OrderStatusController');
kr_isLoading.value = false;
kr_statusTitle.value = AppTranslations.kr_orderStatus.checkFailedTitle;

View File

@ -13,6 +13,7 @@ import '../../../model/response/kr_payment_methods.dart';
import '../../../routes/app_pages.dart';
import '../../../services/api_service/kr_api.user.dart';
import '../../../utils/kr_event_bus.dart';
import 'package:flutter/foundation.dart';
///
///

View File

@ -248,7 +248,7 @@ class KRSettingView extends GetView<KRSettingController> {
// "点击这里登录/注册"
return _kr_buildActionTile(
context,
title: "登录/注册",
title: 'userInfo.loginRegister'.tr,
trailing: "",
onTap: () => Get.toNamed(Routes.MR_LOGIN),
);

View File

@ -27,8 +27,12 @@ import 'package:kaer_with_panels/app/localization/app_translations.dart';
import 'package:kaer_with_panels/app/modules/kr_home/controllers/kr_home_controller.dart';
import 'package:kaer_with_panels/app/modules/kr_home/models/kr_home_views_status.dart';
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:kaer_with_panels/app/utils/kr_init_log_collector.dart';
class KRSplashController extends GetxController {
// 🔧
final _initLog = KRInitLogCollector();
//
final RxBool kr_isLoading = true.obs;
@ -86,9 +90,35 @@ class KRSplashController extends GetxController {
KRLogUtil.kr_i('🌐 后台任务:网站配置和设备登录', tag: 'SplashController');
_kr_initSiteConfig(); //
//
print('🔧 立即开始主初始化流程...');
_kr_initialize();
// 🔧
if (kDebugMode) {
print('🔧 初始化日志收集器...');
}
_initializeAndStart();
}
/// 🔧
Future<void> _initializeAndStart() async {
try {
//
await _initLog.initialize();
_initLog.logPhaseStart('应用启动');
_initLog.log('KRSplashController.onInit 被调用', tag: 'Splash');
if (kDebugMode) {
print('✅ 日志收集器初始化完成');
print('🔧 立即开始主初始化流程...');
}
//
_kr_initialize();
} catch (e) {
if (kDebugMode) {
print('❌ 日志收集器初始化失败: $e,继续执行主流程');
}
// 使
_kr_initialize();
}
}
//
@ -116,11 +146,11 @@ class KRSplashController extends GetxController {
KRLogUtil.kr_i('[SPLASH_TIMING] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
try {
// 🔧 P2优化10
// 🔧 Android 15 2520 + 5
await Future.any([
_executeSiteConfigInit(),
Future.delayed(const Duration(seconds: 10), () {
throw TimeoutException('网站配置加载超时(10秒)');
Future.delayed(const Duration(seconds: 25), () {
throw TimeoutException('网站配置加载超时(25秒)');
}),
]);
} on TimeoutException catch (e) {
@ -178,11 +208,11 @@ class KRSplashController extends GetxController {
print('✅ 设备登录已启用,开始初始化设备信息...');
// 🔧 P2优化8
// 🔧 Android 15 15
await Future.any([
_executeDeviceLogin(),
Future.delayed(const Duration(seconds: 8), () {
throw TimeoutException('设备登录超时(8秒)');
Future.delayed(const Duration(seconds: 15), () {
throw TimeoutException('设备登录超时(15秒)');
}),
]);
@ -237,15 +267,19 @@ class KRSplashController extends GetxController {
Future<void> _kr_initialize() async {
try {
_initLog.logPhaseStart('主初始化流程');
_initLog.log('开始执行 _kr_initialize', tag: 'Splash');
KRLogUtil.kr_i('🔧 开始执行 _kr_initialize', tag: 'SplashController');
// 🔧 P0修复30
// 🔧 Android 15 15
await Future.any([
_executeInitialization(),
Future.delayed(const Duration(seconds: 30), () {
throw TimeoutException('初始化超时:30秒内未完成');
Future.delayed(const Duration(seconds: 15), () {
throw TimeoutException('初始化超时:15秒内未完成');
}),
]);
_initLog.logPhaseEnd('主初始化流程', success: true);
} on TimeoutException catch (e) {
// 🔧 P2优化
KRLogUtil.kr_e('⏱️ 初始化超时: $e', tag: 'SplashController');
@ -311,24 +345,51 @@ class KRSplashController extends GetxController {
// 🔧 P0修复
Future<void> _executeInitialization() async {
_initLog.log('🔍 开始执行核心初始化流程', tag: 'Init');
//
if (Platform.isIOS || Platform.isAndroid) {
_initLog.log('📱 检测到移动平台,检查网络权限', tag: 'Init');
KRLogUtil.kr_i('📱 移动平台,检查网络权限...', tag: 'SplashController');
final bool hasNetworkPermission = await KRNetworkCheck.kr_initialize(
Get.context!,
onPermissionGranted: () async {
await _kr_continueInitialization();
},
);
if (!hasNetworkPermission) {
kr_hasError.value = true;
kr_errorMessage.value = AppTranslations.kr_splash.kr_networkPermissionFailed;
KRLogUtil.kr_e('❌ 网络权限检查失败', tag: 'SplashController');
try {
_initLog.log('开始网络权限检查超时8秒', tag: 'Init');
// 🔧 Android 15 8
final bool hasNetworkPermission = await KRNetworkCheck.kr_initialize(
Get.context!,
onPermissionGranted: () async {
_initLog.logSuccess('网络权限已授予', tag: 'Init');
await _kr_continueInitialization();
},
).timeout(
const Duration(seconds: 8),
onTimeout: () {
_initLog.logWarning('网络权限检查超时8秒', tag: 'Init');
KRLogUtil.kr_w('⏱️ 网络权限检查超时,执行降级初始化', tag: 'SplashController');
return false;
},
);
if (!hasNetworkPermission) {
// 🔧 Android 15
_initLog.logWarning('网络权限检查失败或超时,执行降级初始化', tag: 'Init');
KRLogUtil.kr_w('⚠️ 网络权限检查失败或超时,执行降级初始化', tag: 'SplashController');
await _executeMinimalInitialization();
Get.offAllNamed(Routes.KR_MAIN);
return;
}
_initLog.logSuccess('网络权限检查通过', tag: 'Init');
} catch (e) {
_initLog.logError('网络权限检查异常,执行降级初始化', tag: 'Init', error: e);
KRLogUtil.kr_w('⚠️ 网络权限检查异常: $e,执行降级初始化', tag: 'SplashController');
await _executeMinimalInitialization();
Get.offAllNamed(Routes.KR_MAIN);
return;
}
} else {
//
_initLog.log('💻 检测到桌面平台,直接执行初始化', tag: 'Init');
KRLogUtil.kr_i('💻 桌面平台,直接执行初始化', tag: 'SplashController');
await _kr_continueInitialization();
}
@ -336,22 +397,44 @@ class KRSplashController extends GetxController {
Future<void> _kr_continueInitialization() async {
try {
_initLog.logSeparator();
_initLog.log('🚀 启动页主流程开始', tag: 'Continue');
_initLog.logSeparator();
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
KRLogUtil.kr_i('🚀 启动页主流程开始...', tag: 'SplashController');
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
//
// 🔧 Android 15
if (Platform.isIOS || Platform.isAndroid) {
_initLog.log('📱 检查网络连接状态超时5秒', tag: 'Continue');
KRLogUtil.kr_i('📱 检查网络连接...', tag: 'SplashController');
final bool isConnected = await KRNetworkCheck.kr_checkNetworkConnection();
if (!isConnected) {
kr_hasError.value = true;
kr_errorMessage.value = AppTranslations.kr_splash.kr_networkConnectionFailed;
KRLogUtil.kr_e('❌ 网络连接失败', tag: 'SplashController');
return;
try {
// 5
final bool isConnected = await KRNetworkCheck.kr_checkNetworkConnection().timeout(
const Duration(seconds: 5),
onTimeout: () {
_initLog.logWarning('网络连接检查超时5秒继续初始化', tag: 'Continue');
KRLogUtil.kr_w('⏱️ 网络连接检查超时,继续初始化', tag: 'SplashController');
return true; //
},
);
if (isConnected) {
_initLog.logSuccess('网络连接正常', tag: 'Continue');
KRLogUtil.kr_i('✅ 网络连接正常', tag: 'SplashController');
} else {
// 🔧 Android 15
_initLog.logWarning('网络未连接,应用将以离线模式启动', tag: 'Continue');
KRLogUtil.kr_w('⚠️ 网络未连接,应用将以离线模式启动', tag: 'SplashController');
}
} catch (e) {
// 🔧 Android 15
_initLog.logError('网络检查异常,继续初始化', tag: 'Continue', error: e);
KRLogUtil.kr_w('⚠️ 网络检查异常: $e,继续初始化', tag: 'SplashController');
}
KRLogUtil.kr_i('✅ 网络连接正常', tag: 'SplashController');
} else {
_initLog.log('💻 桌面平台,跳过网络连接检查', tag: 'Continue');
KRLogUtil.kr_i('💻 桌面平台,跳过网络连接检查', tag: 'SplashController');
}
@ -375,19 +458,22 @@ class KRSplashController extends GetxController {
_logStepTiming('设备登录检查完成');
//
_initLog.log('⚙️ 开始初始化应用配置(域名加载等)', tag: 'Continue');
KRLogUtil.kr_i('⚙️ 开始初始化应用配置...', tag: 'SplashController');
await AppConfig().initConfig(
onSuccess: () async {
//
_initLog.logSuccess('应用配置初始化成功', tag: 'Continue');
KRLogUtil.kr_i('✅ 应用配置初始化成功,继续后续步骤', tag: 'SplashController');
await _kr_continueAfterConfig();
},
);
} catch (e) {
//
KRLogUtil.kr_e('❌ 启动页初始化异常: $e', tag: 'SplashController');
kr_hasError.value = true;
kr_errorMessage.value = '${AppTranslations.kr_splash.kr_initializationFailed}$e';
// 🔧 Android 15
_initLog.logError('启动页初始化异常,执行降级策略', tag: 'Continue', error: e);
KRLogUtil.kr_w('⚠️ 启动页初始化异常,执行降级策略: $e', tag: 'SplashController');
await _executeMinimalInitialization();
Get.offAllNamed(Routes.KR_MAIN);
}
}
@ -424,6 +510,19 @@ class KRSplashController extends GetxController {
KRLogUtil.kr_i('🎫 Token存在: $hasToken', tag: 'SplashController');
KRLogUtil.kr_i('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━', tag: 'SplashController');
// 🔧
_initLog.logSeparator();
_initLog.log('准备进入主页', tag: 'Splash');
_initLog.log('最终登录状态: $loginStatus', tag: 'Splash');
_initLog.log('Token存在: $hasToken', tag: 'Splash');
_initLog.logSuccess('正常初始化流程完成', tag: 'Splash');
//
await _initLog.finalize();
if (kDebugMode && _initLog.getLogFilePath() != null) {
print('📁 初始化日志文件: ${_initLog.getLogFilePath()}');
}
//
_logStepTiming('开始页面导航');
if(loginStatus) {
@ -444,10 +543,14 @@ class KRSplashController extends GetxController {
print('🕐 启动失败总耗时: ${totalMs}ms (${totalDuration.inSeconds}.${(totalMs % 1000).toString().padLeft(3, '0')}s)');
//
_initLog.logError('启动初始化失败', tag: 'Splash', error: e);
KRLogUtil.kr_e('启动初始化失败: $e', tag: 'SplashController');
KRLogUtil.kr_e('⏰ 启动失败总耗时: ${totalMs}ms', tag: 'SplashController');
kr_hasError.value = true;
kr_errorMessage.value = '${AppTranslations.kr_splash.kr_initializationFailed}$e';
//
await _initLog.finalize();
}
}

View File

@ -101,7 +101,7 @@ class KRSplashView extends GetView<KRSplashController> {
),
),
child: Text(
'跳过',
'splash.skip'.tr,
style: KrAppTextStyle(
fontSize: 14,
color: Colors.grey,

View File

@ -154,7 +154,7 @@ class KRStatisticsController extends GetxController {
}
kr_weeklyData.value = weeklyHours;
} catch (e) {
KRCommonUtil.kr_showToast('处理流量日志数据失败');
KRCommonUtil.kr_showToast('statistics.processTrafficFailed'.tr);
KRLogUtil.kr_e('处理流量日志数据失败: $e', tag: 'Statistics');
}
}

View File

@ -152,7 +152,7 @@ class KRStatisticsView extends GetView<KRStatisticsController> {
),
],
),
SizedBox(height: 8.w),
SizedBox(height: 8.h),
Text(
value,
style: KrAppTextStyle(
@ -188,9 +188,9 @@ class KRStatisticsView extends GetView<KRStatisticsController> {
),
),
),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
SizedBox(
height: 200.w,
height: 200.h,
child: Obx(() => LineChart(
LineChartData(
gridData: FlGridData(show: false),
@ -297,7 +297,7 @@ class KRStatisticsView extends GetView<KRStatisticsController> {
),
],
),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
Obx(() => _kr_buildLongestConnection(context)),
],
),
@ -322,7 +322,7 @@ class KRStatisticsView extends GetView<KRStatisticsController> {
color: Theme.of(context).textTheme.bodySmall?.color,
),
),
SizedBox(height: 8.w),
SizedBox(height: 8.h),
Text(
value,
style: KrAppTextStyle(

View File

@ -85,7 +85,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
_kr_buildShortcutSection(context),
_kr_buildOtherSection(context),
_kr_buildLogoutButton(context),
SizedBox(height: 30.w),
SizedBox(height: 30.h),
],
),
),
@ -142,7 +142,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
}
: null,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.w),
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 12.h),
decoration: shouldShowLoginPrompt
? BoxDecoration(
color: const Color(0xFF1797FF).withOpacity(0.05),
@ -282,7 +282,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.w),
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration(
color: Theme.of(context).cardColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(12.w),
@ -309,7 +309,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
),
],
),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
//
Row(
children: [
@ -332,10 +332,10 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
),
],
),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
//
_kr_buildTrafficProgress(context, subscribe),
SizedBox(height: 16.w),
SizedBox(height: 16.h),
//
_kr_buildSubscriptionActions(context, subscribe),
],
@ -443,7 +443,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
},
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.w),
EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h),
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
@ -477,7 +477,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
],
),
if (totalTraffic > 0) ...[
SizedBox(height: 6.w),
SizedBox(height: 6.h),
Stack(
children: [
Container(
@ -539,7 +539,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
backgroundColor: const Color(0xFF1797FF),
foregroundColor: Colors.white,
elevation: 0,
padding: EdgeInsets.symmetric(vertical: 12.w),
padding: EdgeInsets.symmetric(vertical: 12.h),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.w),
),
@ -603,7 +603,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
backgroundColor: const Color(0xFF1797FF),
foregroundColor: Colors.white,
elevation: 0,
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 8.w),
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 8.h),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.w),
),
@ -647,7 +647,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
color: Theme.of(context).textTheme.bodyMedium?.color,
),
),
SizedBox(height: 12.w),
SizedBox(height: 12.h),
Column(
children: [
_kr_buildShortcutContainer(
@ -702,7 +702,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
onTap: onTap,
child: Container(
height: 62.w,
margin: EdgeInsets.symmetric(vertical: 6.w),
margin: EdgeInsets.symmetric(vertical: 6.h),
padding: EdgeInsets.only(left: 12.w, right: 12.w),
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
@ -763,7 +763,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
color: Theme.of(context).textTheme.bodyMedium?.color,
),
),
SizedBox(height: 12.w),
SizedBox(height: 12.h),
Obx(() => Wrap(
spacing: 12.w,
runSpacing: 12.w,
@ -812,7 +812,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
),
],
),
SizedBox(height: 8.w),
SizedBox(height: 8.h),
Text(
controller.getTitle(item.type),
style: KrAppTextStyle(
@ -823,7 +823,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
SizedBox(height: 4.w),
SizedBox(height: 4.h),
Text(
item.subtitle,
style: KrAppTextStyle(
@ -841,8 +841,13 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
// 退
Widget _kr_buildLogoutButton(BuildContext context) {
return Obx(() => Visibility(
visible: KRAppRunData.getInstance().kr_isLogin.value,
return Obx(() {
final appRunData = KRAppRunData.getInstance();
// 退
final isAccountLogin = appRunData.kr_isLogin.value && !appRunData.isDeviceLogin();
return Visibility(
visible: isAccountLogin,
child: Container(
width: double.infinity,
margin: EdgeInsets.all(16.w),
@ -858,7 +863,7 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
},
style: TextButton.styleFrom(
backgroundColor: Theme.of(context).cardColor,
padding: EdgeInsets.symmetric(vertical: 12.w),
padding: EdgeInsets.symmetric(vertical: 12.h),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.w),
),
@ -872,7 +877,8 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
),
),
),
));
);
});
}
//
@ -910,17 +916,17 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
}
if (!launched) {
KRCommonUtil.kr_showToast("尝试使用浏览器打开");
KRCommonUtil.kr_showToast("common.tryBrowser".tr);
// 使
try {
final Uri webUrl = Uri.parse(tgUrl);
if (await canLaunchUrl(webUrl)) {
await launchUrl(webUrl, mode: LaunchMode.externalApplication);
} else {
KRCommonUtil.kr_showToast("无法打开浏览器");
KRCommonUtil.kr_showToast("common.cannotOpenBrowser".tr);
}
} catch (e) {
KRCommonUtil.kr_showToast("打开链接失败,请稍后重试");
KRCommonUtil.kr_showToast("common.openLinkFailed".tr);
}
}
} else {
@ -930,10 +936,10 @@ class KRUserInfoView extends GetView<KRUserInfoController> {
if (await canLaunchUrl(webUrl)) {
await launchUrl(webUrl);
} else {
KRCommonUtil.kr_showToast("无法打开Telegram链接");
KRCommonUtil.kr_showToast("common.cannotOpenTelegram".tr);
}
} catch (e) {
KRCommonUtil.kr_showToast("打开链接失败,请稍后重试");
KRCommonUtil.kr_showToast("common.openLinkFailed".tr);
}
}
break;

View File

@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:kaer_with_panels/app/common/app_run_data.dart';
import 'package:kaer_with_panels/app/common/app_config.dart';
@ -30,27 +31,33 @@ class BaseResponse<T> {
if (shouldDecrypt && cipherText.isNotEmpty && nonce.isNotEmpty) {
try {
print('═══════════════════════════════════════');
print('🔐 检测到加密响应,开始解密...');
print('📥 加密数据长度: ${cipherText.length} 字符');
print('⏰ 时间戳: $nonce');
if (kDebugMode) {
print('═══════════════════════════════════════');
print('🔐 检测到加密响应,开始解密...');
print('📥 加密数据长度: ${cipherText.length} 字符');
print('⏰ 时间戳: $nonce');
}
final decrypted = KRAesUtil.decryptData(cipherText, nonce, AppConfig.kr_encryptionKey);
body = jsonDecode(decrypted);
print('✅ 解密成功');
print('');
print('📦 解密后的完整数据:');
// JSON便
final bodyStr = JsonEncoder.withIndent(' ').convert(body);
print(bodyStr);
print('═══════════════════════════════════════');
if (kDebugMode) {
print('✅ 解密成功');
print('');
print('📦 解密后的完整数据:');
// JSON便
final bodyStr = JsonEncoder.withIndent(' ').convert(body);
print(bodyStr);
print('═══════════════════════════════════════');
}
KRLogUtil.kr_i('🔓 解密成功', tag: 'BaseResponse');
} catch (e) {
print('❌ 解密失败: $e');
print('⚠️ 将使用原始数据');
print('═══════════════════════════════════════');
if (kDebugMode) {
print('❌ 解密失败: $e');
print('⚠️ 将使用原始数据');
print('═══════════════════════════════════════');
}
KRLogUtil.kr_e('❌ 解密失败: $e', tag: 'BaseResponse');
body = dataMap;
}

View File

@ -22,6 +22,7 @@ import 'package:loggy/loggy.dart';
import '../utils/kr_aes_util.dart';
import '../utils/kr_log_util.dart';
import 'package:flutter/foundation.dart';
// import 'package:video/app/utils/common_util.dart';
// import 'package:video/app/utils/log_util.dart';
@ -316,31 +317,47 @@ class HttpUtil {
class MyInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
print('>>> Request │ ${options.method}${options.uri}');
if (kDebugMode) {
print('>>> Request │ ${options.method}${options.uri}');
}
if (options.data != null) {
print('Body: ${options.data}');
if (kDebugMode) {
print('Body: ${options.data}');
}
}
handler.next(options);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
print('<<< Response │ ${response.requestOptions.method}${response.statusCode} ${response.statusMessage}${response.requestOptions.uri}');
if (kDebugMode) {
print('<<< Response │ ${response.requestOptions.method}${response.statusCode} ${response.statusMessage}${response.requestOptions.uri}');
}
if (response.data != null) {
print('Body: ${response.data}');
if (kDebugMode) {
print('Body: ${response.data}');
}
}
handler.next(response);
}
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
print('<<< Error │ ${err.requestOptions.method}${err.requestOptions.uri}');
print('Error Type: ${err.type}');
if (kDebugMode) {
print('<<< Error │ ${err.requestOptions.method}${err.requestOptions.uri}');
}
if (kDebugMode) {
print('Error Type: ${err.type}');
}
if (err.message != null) {
print('Error Message: ${err.message}');
if (kDebugMode) {
print('Error Message: ${err.message}');
}
}
if (err.response?.data != null) {
print('Response Data: ${err.response?.data}');
if (kDebugMode) {
print('Response Data: ${err.response?.data}');
}
}
handler.next(err);
}
@ -350,17 +367,25 @@ class MyInterceptor extends Interceptor {
class _KRSimpleHttpInterceptor extends Interceptor {
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
print('>>> Request │ ${options.method}${options.uri}');
if (kDebugMode) {
print('>>> Request │ ${options.method}${options.uri}');
}
if (options.data != null) {
print('Body: ${options.data}');
if (kDebugMode) {
print('Body: ${options.data}');
}
// data time
if (options.data is Map<String, dynamic>) {
final data = options.data as Map<String, dynamic>;
if (data.containsKey('data') && data.containsKey('time')) {
try {
print('');
print('🔐 检测到加密请求,正在解密...');
if (kDebugMode) {
print('');
}
if (kDebugMode) {
print('🔐 检测到加密请求,正在解密...');
}
//
final encryptedData = data['data'] as String;
final nonce = data['time'] as String;
@ -369,17 +394,25 @@ class _KRSimpleHttpInterceptor extends Interceptor {
nonce,
AppConfig.kr_encryptionKey,
);
print('🔓 解密后的原始请求数据:');
if (kDebugMode) {
print('🔓 解密后的原始请求数据:');
}
// JSON
try {
final jsonData = jsonDecode(decrypted);
final prettyJson = JsonEncoder.withIndent(' ').convert(jsonData);
print(prettyJson);
if (kDebugMode) {
print(prettyJson);
}
} catch (_) {
print(decrypted);
if (kDebugMode) {
print(decrypted);
}
}
} catch (e) {
print('⚠️ 请求解密失败: $e');
if (kDebugMode) {
print('⚠️ 请求解密失败: $e');
}
}
}
}
@ -389,9 +422,13 @@ class _KRSimpleHttpInterceptor extends Interceptor {
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
print('<<< Response │ ${response.requestOptions.method}${response.statusCode} ${response.statusMessage}${response.requestOptions.uri}');
if (kDebugMode) {
print('<<< Response │ ${response.requestOptions.method}${response.statusCode} ${response.statusMessage}${response.requestOptions.uri}');
}
if (response.data != null) {
print('Body: ${response.data}');
if (kDebugMode) {
print('Body: ${response.data}');
}
// data time
if (response.data is Map<String, dynamic>) {
@ -403,8 +440,12 @@ class _KRSimpleHttpInterceptor extends Interceptor {
nestedData.containsKey('data') &&
nestedData.containsKey('time')) {
try {
print('');
print('🔐 检测到加密响应,正在解密...');
if (kDebugMode) {
print('');
}
if (kDebugMode) {
print('🔐 检测到加密响应,正在解密...');
}
//
final encryptedData = nestedData['data'] as String;
final nonce = nestedData['time'] as String;
@ -413,17 +454,25 @@ class _KRSimpleHttpInterceptor extends Interceptor {
nonce,
AppConfig.kr_encryptionKey,
);
print('🔓 解密后的原始响应数据: ${response.requestOptions.uri}');
if (kDebugMode) {
print('🔓 解密后的原始响应数据:');
}
// JSON
try {
final jsonData = jsonDecode(decrypted);
final prettyJson = JsonEncoder.withIndent(' ').convert(jsonData);
print(prettyJson);
if (kDebugMode) {
print(prettyJson);
}
} catch (_) {
print(decrypted);
if (kDebugMode) {
print(decrypted);
}
}
} catch (e) {
print('⚠️ 响应解密失败: $e');
if (kDebugMode) {
print('⚠️ 响应解密失败: $e');
}
}
}
}
@ -433,13 +482,21 @@ class _KRSimpleHttpInterceptor extends Interceptor {
@override
void onError(DioException err, ErrorInterceptorHandler handler) {
print('<<< Error │ ${err.requestOptions.method}${err.requestOptions.uri}');
print('Error Type: ${err.type}');
if (kDebugMode) {
print('<<< Error │ ${err.requestOptions.method}${err.requestOptions.uri}');
}
if (kDebugMode) {
print('Error Type: ${err.type}');
}
if (err.message != null) {
print('Error Message: ${err.message}');
if (kDebugMode) {
print('Error Message: ${err.message}');
}
}
if (err.response?.data != null) {
print('Response Data: ${err.response?.data}');
if (kDebugMode) {
print('Response Data: ${err.response?.data}');
}
}
handler.next(err);
}

View File

@ -25,8 +25,11 @@ abstract class Api {
///
static const String kr_deleteAccount = "/v1/public/user/delete_account";
/// -
static const String kr_setNewPsdByForgetPsd = "/v1/app/auth/reset_password";
/// -
static const String kr_resetPassword = "/v1/auth/reset";
/// -
static const String kr_resetPasswordByTelephone = "/v1/auth/reset/telephone";
/// /
static const String kr_nodeList = "/v1/public/subscribe/node/list";

View File

@ -1,4 +1,4 @@
import 'dart:io';
import 'dart:io' as io;
import 'dart:math';
import 'dart:convert';
@ -21,6 +21,8 @@ import '../kr_device_info_service.dart';
import '../kr_site_config_service.dart';
import '../../common/app_config.dart';
import 'package:dio/dio.dart' as dio;
import 'package:kaer_with_panels/app/services/singbox_imp/kr_sing_box_imp.dart';
import 'package:flutter/foundation.dart';
class KRAuthApi {
///
@ -107,6 +109,39 @@ class KRAuthApi {
return right(baseResponse.model.kr_token.toString());
}
/// +++
Future<Either<HttpError, String>> kr_telephoneRegister(
String telephone,
String areaCode,
String password,
String code,
{String? inviteCode}) async {
final Map<String, dynamic> data = <String, dynamic>{};
data['telephone'] = telephone;
data['telephone_area_code'] = areaCode;
data['password'] = password;
data['code'] = code;
data["identifier"] = KRDeviceInfoService().deviceId ?? 'unknown';
//
if (inviteCode != null && inviteCode.isNotEmpty) {
data["invite"] = inviteCode;
}
// cf_token
data["cf_token"] = "";
BaseResponse<KRLoginData> baseResponse = await HttpUtil.getInstance()
.request<KRLoginData>('/v1/auth/register/telephone', data,
method: HttpMethod.POST, isShowLoading: true);
if (!baseResponse.isSuccess) {
return left(
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
}
return right(baseResponse.model.kr_token.toString());
}
///
Future<Either<HttpError, bool>> kr_checkVerificationCode(
String email, String code, int type) async {
@ -151,6 +186,52 @@ class KRAuthApi {
return right(baseResponse.model.kr_token.toString());
}
/// ++
Future<Either<HttpError, String>> kr_telephoneLogin(
String telephone, String areaCode, String password) async {
final Map<String, dynamic> data = <String, dynamic>{};
data['telephone'] = telephone;
data['telephone_area_code'] = areaCode;
data['password'] = password;
final deviceId = KRDeviceInfoService().deviceId ?? 'unknown';
KRLogUtil.kr_i('设备ID: $deviceId', tag: 'KRAuthApi');
data["identifier"] = deviceId;
BaseResponse<KRLoginData> baseResponse = await HttpUtil.getInstance()
.request<KRLoginData>('/v1/auth/login/telephone', data,
method: HttpMethod.POST, isShowLoading: true);
if (!baseResponse.isSuccess) {
return left(
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
}
return right(baseResponse.model.kr_token.toString());
}
/// ++
Future<Either<HttpError, String>> kr_telephoneCodeLogin(
String telephone, String areaCode, String code) async {
final Map<String, dynamic> data = <String, dynamic>{};
data['telephone'] = telephone;
data['telephone_area_code'] = areaCode;
data['telephone_code'] = code;
final deviceId = KRDeviceInfoService().deviceId ?? 'unknown';
KRLogUtil.kr_i('设备ID: $deviceId', tag: 'KRAuthApi');
data["identifier"] = deviceId;
BaseResponse<KRLoginData> baseResponse = await HttpUtil.getInstance()
.request<KRLoginData>('/v1/auth/login/telephone', data,
method: HttpMethod.POST, isShowLoading: true);
if (!baseResponse.isSuccess) {
return left(
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
}
return right(baseResponse.model.kr_token.toString());
}
///
/// type: 1=, 2=, 3=
Future<Either<HttpError, bool>> kr_sendCode(String email, int type) async {
@ -169,6 +250,26 @@ class KRAuthApi {
return right(true);
}
///
/// type: 1=, 2=
Future<Either<HttpError, bool>> kr_sendSmsCode(
String telephone, String areaCode, int type) async {
final Map<String, dynamic> data = <String, dynamic>{};
data['telephone'] = telephone;
data['telephone_area_code'] = areaCode;
data['type'] = type;
BaseResponse<dynamic> baseResponse = await HttpUtil.getInstance()
.request<dynamic>('/v1/common/send_sms_code', data,
method: HttpMethod.POST, isShowLoading: true);
if (!baseResponse.isSuccess) {
return left(
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
}
return right(true);
}
///
Future<Either<HttpError, String>> kr_deleteAccount(String email, String code) async {
final Map<String, dynamic> data = <String, dynamic>{};
@ -186,17 +287,40 @@ class KRAuthApi {
return right("");
}
/// -
Future<Either<HttpError, String>> kr_setNewPsdByForgetPsd(
/// -
Future<Either<HttpError, String>> kr_resetPassword(
String email, String code, String password) async {
final Map<String, dynamic> data = <String, dynamic>{};
data['identifier'] = KRDeviceInfoService().deviceId ?? 'unknown';
data['email'] = email;
data['password'] = password;
data["code"] = code;
data["identifier"] = KRDeviceInfoService().deviceId ?? 'unknown';
data['code'] = code;
data['cf_token'] = ""; // Cloudflare token
BaseResponse<KRLoginData> baseResponse = await HttpUtil.getInstance()
.request<KRLoginData>(Api.kr_setNewPsdByForgetPsd, data,
.request<KRLoginData>(Api.kr_resetPassword, data,
method: HttpMethod.POST, isShowLoading: true);
if (!baseResponse.isSuccess) {
return left(
HttpError(msg: baseResponse.retMsg, code: baseResponse.retCode));
}
return right(baseResponse.model.kr_token.toString());
}
/// -
Future<Either<HttpError, String>> kr_resetPasswordByTelephone(
String telephone, String areaCode, String code, String password) async {
final Map<String, dynamic> data = <String, dynamic>{};
data['identifier'] = KRDeviceInfoService().deviceId ?? 'unknown';
data['telephone'] = telephone;
data['telephone_area_code'] = areaCode;
data['password'] = password;
data['code'] = code;
data['cf_token'] = ""; // Cloudflare token
BaseResponse<KRLoginData> baseResponse = await HttpUtil.getInstance()
.request<KRLoginData>(Api.kr_resetPasswordByTelephone, data,
method: HttpMethod.POST, isShowLoading: true);
if (!baseResponse.isSuccess) {
return left(
@ -343,17 +467,17 @@ class KRAuthApi {
}
String _kr_getUserAgent() {
if (Platform.isAndroid) {
if (io.Platform.isAndroid) {
return 'android';
} else if (Platform.isIOS) {
} else if (io.Platform.isIOS) {
return 'ios';
} else if (Platform.isMacOS) {
} else if (io.Platform.isMacOS) {
return 'mac';
} else if (Platform.isWindows) {
} else if (io.Platform.isWindows) {
return 'windows';
} else if (Platform.isLinux) {
} else if (io.Platform.isLinux) {
return 'linux';
} else if (Platform.isFuchsia) {
} else if (io.Platform.isFuchsia) {
return 'harmony';
} else {
return 'unknown';

View File

@ -27,26 +27,32 @@ class KRDeviceInfoService {
///
Future<void> initialize() async {
try {
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
print('📱 开始初始化设备信息服务');
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
if (kDebugMode) {
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
print('📱 开始初始化设备信息服务');
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
}
KRLogUtil.kr_i('📱 开始初始化设备信息', tag: 'KRDeviceInfoService');
_deviceId = await _getDeviceId();
_deviceDetails = await _getDeviceDetails();
print('✅ 设备信息初始化成功');
print('📱 设备ID: $_deviceId');
print('📱 设备平台: ${getPlatformName()}');
print('📱 设备型号: ${getDeviceModel()}');
print('📱 系统版本: ${getOSVersion()}');
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
if (kDebugMode) {
print('✅ 设备信息初始化成功');
print('📱 设备ID: $_deviceId');
print('📱 设备平台: ${getPlatformName()}');
print('📱 设备型号: ${getDeviceModel()}');
print('📱 系统版本: ${getOSVersion()}');
print('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
}
KRLogUtil.kr_i('✅ 设备信息初始化成功', tag: 'KRDeviceInfoService');
KRLogUtil.kr_i('📱 设备ID - $_deviceId', tag: 'KRDeviceInfoService');
KRLogUtil.kr_i('📱 设备详情 - $_deviceDetails', tag: 'KRDeviceInfoService');
} catch (e) {
print('❌ 设备信息初始化失败: $e');
if (kDebugMode) {
print('❌ 设备信息初始化失败: $e');
}
KRLogUtil.kr_e('❌ 设备信息初始化失败 - $e', tag: 'KRDeviceInfoService');
}
}
@ -79,7 +85,9 @@ class KRDeviceInfoService {
return identifier;
} catch (e) {
print('❌ 获取设备ID失败: $e');
if (kDebugMode) {
print('❌ 获取设备ID失败: $e');
}
KRLogUtil.kr_e('❌ 获取设备ID失败 - $e', tag: 'KRDeviceInfoService');
// ,ID
return await _getOrCreateStoredDeviceId();
@ -119,12 +127,16 @@ class KRDeviceInfoService {
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
print('📱 Android多因子ID生成 - 因子数: ${factors.where((f) => f != null && f.isNotEmpty).length}');
if (kDebugMode) {
print('📱 Android多因子ID生成 - 因子数: ${factors.where((f) => f != null && f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 Android多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
print('❌ Android设备ID获取失败: $e');
if (kDebugMode) {
print('❌ Android设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ Android设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
@ -157,12 +169,16 @@ class KRDeviceInfoService {
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
print('📱 iOS多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
if (kDebugMode) {
print('📱 iOS多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 iOS多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
print('❌ iOS设备ID获取失败: $e');
if (kDebugMode) {
print('❌ iOS设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ iOS设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
@ -193,12 +209,16 @@ class KRDeviceInfoService {
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
print('📱 macOS多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
if (kDebugMode) {
print('📱 macOS多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 macOS多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
print('❌ macOS设备ID获取失败: $e');
if (kDebugMode) {
print('❌ macOS设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ macOS设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
@ -229,12 +249,16 @@ class KRDeviceInfoService {
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
print('📱 Windows多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
if (kDebugMode) {
print('📱 Windows多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 Windows多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
print('❌ Windows设备ID获取失败: $e');
if (kDebugMode) {
print('❌ Windows设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ Windows设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
@ -265,12 +289,16 @@ class KRDeviceInfoService {
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
print('📱 Linux多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
if (kDebugMode) {
print('📱 Linux多因子ID生成 - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
}
KRLogUtil.kr_i('📱 Linux多因子ID - $hash', tag: 'KRDeviceInfoService');
return hash.toString();
} catch (e) {
print('❌ Linux设备ID获取失败: $e');
if (kDebugMode) {
print('❌ Linux设备ID获取失败: $e');
}
KRLogUtil.kr_e('❌ Linux设备ID获取失败 - $e', tag: 'KRDeviceInfoService');
return '';
}
@ -288,16 +316,22 @@ class KRDeviceInfoService {
// UUID
storedId = _generateUniqueId();
await storage.kr_saveData(key: key, value: storedId);
print('📱 生成新的设备ID: $storedId');
if (kDebugMode) {
print('📱 生成新的设备ID: $storedId');
}
KRLogUtil.kr_i('📱 生成新的设备ID - $storedId', tag: 'KRDeviceInfoService');
} else {
print('📱 使用存储的设备ID: $storedId');
if (kDebugMode) {
print('📱 使用存储的设备ID: $storedId');
}
KRLogUtil.kr_i('📱 使用存储的设备ID - $storedId', tag: 'KRDeviceInfoService');
}
return storedId;
} catch (e) {
print('❌ 获取存储的设备ID失败: $e');
if (kDebugMode) {
print('❌ 获取存储的设备ID失败: $e');
}
KRLogUtil.kr_e('❌ 获取存储的设备ID失败 - $e', tag: 'KRDeviceInfoService');
return _generateUniqueId();
}
@ -383,7 +417,9 @@ class KRDeviceInfoService {
'platform': 'unknown',
};
} catch (e) {
print('❌ 获取设备详情失败: $e');
if (kDebugMode) {
print('❌ 获取设备详情失败: $e');
}
KRLogUtil.kr_e('❌ 获取设备详情失败 - $e', tag: 'KRDeviceInfoService');
return {
'platform': 'unknown',

View File

@ -12,10 +12,10 @@ class KRSiteConfigService extends ChangeNotifier {
static final KRSiteConfigService _instance = KRSiteConfigService._internal();
factory KRSiteConfigService() => _instance;
KRSiteConfigService._internal() {
// 🔧 P1修复 10 5
_dio.options.connectTimeout = const Duration(seconds: 5);
_dio.options.sendTimeout = const Duration(seconds: 5);
_dio.options.receiveTimeout = const Duration(seconds: 5);
// 🔧 Android 15 5 20
_dio.options.connectTimeout = const Duration(seconds: 20);
_dio.options.sendTimeout = const Duration(seconds: 20);
_dio.options.receiveTimeout = const Duration(seconds: 20);
// 🔧 HttpClientAdapter使用sing-box的mixed代理
_dio.httpClientAdapter = IOHttpClientAdapter(
@ -47,33 +47,54 @@ class KRSiteConfigService extends ChangeNotifier {
///
Future<bool> initialize() async {
try {
print('🔧 KRSiteConfigService.initialize() 开始执行');
if (kDebugMode) {
print('🔧 KRSiteConfigService.initialize() 开始执行');
}
KRLogUtil.kr_i('🔧 开始初始化网站配置', tag: 'KRSiteConfigService');
// Debug 使
final baseUrl = AppConfig().baseUrl;
print('📍 baseUrl = $baseUrl');
if (kDebugMode) {
print('📍 baseUrl = $baseUrl');
}
final url = '$baseUrl/v1/common/site/config';
print('📍 完整URL = $url');
if (kDebugMode) {
print('📍 完整URL = $url');
}
KRLogUtil.kr_i('📤 请求网站配置 - $url', tag: 'KRSiteConfigService');
print('📤 准备发送 GET 请求到: $url');
print('⏱️ 超时配置: connectTimeout=10s, sendTimeout=10s, receiveTimeout=10s');
if (kDebugMode) {
print('📤 准备发送 GET 请求到: $url');
}
if (kDebugMode) {
// 🔧
print('⏱️ 超时配置: connectTimeout=${_dio.options.connectTimeout}, sendTimeout=${_dio.options.sendTimeout}, receiveTimeout=${_dio.options.receiveTimeout}');
}
print('⏳ 开始发送请求...');
if (kDebugMode) {
print('⏳ 开始发送请求...');
}
final startTime = DateTime.now();
final response = await _dio.get(url);
final endTime = DateTime.now();
final duration = endTime.difference(startTime).inMilliseconds;
print('⏱️ 请求耗时: ${duration}ms');
if (kDebugMode) {
print('⏱️ 请求耗时: ${duration}ms');
}
print('✅ 请求完成,状态码: ${response.statusCode}');
if (kDebugMode) {
print('✅ 请求完成,状态码: ${response.statusCode}');
}
KRLogUtil.kr_i('📥 响应状态码 - ${response.statusCode}', tag: 'KRSiteConfigService');
if (response.statusCode == 200) {
final responseData = response.data;
print('📥 响应数据类型: ${responseData.runtimeType}');
print('📥 响应数据: $responseData');
if (kDebugMode) {
print('📥 响应数据类型: ${responseData.runtimeType}');
}
if (kDebugMode) {
print('📥 响应数据: $responseData');
}
KRLogUtil.kr_i('📥 响应数据 - $responseData', tag: 'KRSiteConfigService');
if (responseData['code'] == 200) {
@ -96,24 +117,46 @@ class KRSiteConfigService extends ChangeNotifier {
return false;
}
} on DioException catch (e, stackTrace) {
print('❌ Dio请求异常: ${e.type}');
print('❌ 错误信息: ${e.message}');
print('❌ 请求URL: ${e.requestOptions.uri}');
print('❌ 连接超时: ${e.requestOptions.connectTimeout}');
print('❌ 发送超时: ${e.requestOptions.sendTimeout}');
print('❌ 接收超时: ${e.requestOptions.receiveTimeout}');
if (e.response != null) {
print('❌ 响应状态码: ${e.response?.statusCode}');
print('❌ 响应数据: ${e.response?.data}');
if (kDebugMode) {
print('❌ Dio请求异常: ${e.type}');
}
if (kDebugMode) {
print('❌ 错误信息: ${e.message}');
}
if (kDebugMode) {
print('❌ 请求URL: ${e.requestOptions.uri}');
}
if (kDebugMode) {
print('❌ 连接超时: ${e.requestOptions.connectTimeout}');
}
if (kDebugMode) {
print('❌ 发送超时: ${e.requestOptions.sendTimeout}');
}
if (kDebugMode) {
print('❌ 接收超时: ${e.requestOptions.receiveTimeout}');
}
if (e.response != null) {
if (kDebugMode) {
print('❌ 响应状态码: ${e.response?.statusCode}');
}
if (kDebugMode) {
print('❌ 响应数据: ${e.response?.data}');
}
}
if (kDebugMode) {
print('📚 堆栈跟踪: $stackTrace');
}
print('📚 堆栈跟踪: $stackTrace');
KRLogUtil.kr_e('❌ Dio异常 - ${e.type}: ${e.message}', tag: 'KRSiteConfigService');
KRLogUtil.kr_e('📚 堆栈: $stackTrace', tag: 'KRSiteConfigService');
return false;
} catch (e, stackTrace) {
print('❌ 未知异常: $e');
print('📚 堆栈跟踪: $stackTrace');
if (kDebugMode) {
print('❌ 未知异常: $e');
}
if (kDebugMode) {
print('📚 堆栈跟踪: $stackTrace');
}
KRLogUtil.kr_e('❌ 初始化失败 - $e', tag: 'KRSiteConfigService');
KRLogUtil.kr_e('📚 堆栈: $stackTrace', tag: 'KRSiteConfigService');
return false;

View File

@ -98,7 +98,7 @@ class KRSubscribeService {
///
Future<void> kr_resetSubscribePeriod() async {
if (kr_currentSubscribe.value == null) {
KRCommonUtil.kr_showToast('请先选择订阅');
KRCommonUtil.kr_showToast('subscribe.pleaseSelectFirst'.tr);
return;
}

View File

@ -22,6 +22,7 @@ import '../../utils/kr_country_util.dart';
import '../../utils/kr_log_util.dart';
import '../../utils/kr_secure_storage.dart';
import '../../common/app_run_data.dart';
import 'package:flutter/foundation.dart';
enum KRConnectionType {
global,
@ -549,14 +550,18 @@ class KRSingBoxImp {
///
/// hiddify-app: libcore UI
void _kr_subscribeToStatus() {
print('🔵 _kr_subscribeToStatus 被调用,重新订阅状态流');
if (kDebugMode) {
print('🔵 _kr_subscribeToStatus 被调用,重新订阅状态流');
}
KRLogUtil.kr_i('🔵 _kr_subscribeToStatus 被调用', tag: 'SingBox');
//
for (var sub in _kr_subscriptions) {
if (sub.hashCode.toString().contains('Status')) {
sub.cancel();
print('🔵 已取消旧的状态订阅');
if (kDebugMode) {
print('🔵 已取消旧的状态订阅');
}
}
}
_kr_subscriptions
@ -565,19 +570,25 @@ class KRSingBoxImp {
_kr_subscriptions.add(
kr_singBox.watchStatus().listen(
(status) {
print('🔵 收到 Native 状态更新: ${status.runtimeType}');
if (kDebugMode) {
print('🔵 收到 Native 状态更新: ${status.runtimeType}');
}
KRLogUtil.kr_i('📡 收到状态更新: $status', tag: 'SingBox');
kr_status.value = status;
},
onError: (error) {
print('🔵 状态流错误: $error');
if (kDebugMode) {
print('🔵 状态流错误: $error');
}
KRLogUtil.kr_e('📡 状态流错误: $error', tag: 'SingBox');
},
cancelOnError: false,
),
);
print('🔵 状态流订阅完成');
if (kDebugMode) {
print('🔵 状态流订阅完成');
}
}
///
@ -1141,7 +1152,9 @@ class KRSingBoxImp {
final selectedNode = await KRSecureStorage().kr_readData(key: _keySelectedNode);
if (selectedNode != null && selectedNode.isNotEmpty) {
KRLogUtil.kr_i('🎯 恢复用户选择的节点: $selectedNode', tag: 'SingBox');
print('🔵 启动后恢复节点选择: $selectedNode');
if (kDebugMode) {
print('🔵 启动后恢复节点选择: $selectedNode');
}
// 500ms确保sing-box完全启动
await Future.delayed(const Duration(milliseconds: 500));
@ -1150,18 +1163,26 @@ class KRSingBoxImp {
try {
await kr_selectOutbound(selectedNode);
KRLogUtil.kr_i('✅ 节点已切换到用户选择: $selectedNode', tag: 'SingBox');
print('🔵 节点切换成功: $selectedNode');
if (kDebugMode) {
print('🔵 节点切换成功: $selectedNode');
}
} catch (e) {
KRLogUtil.kr_e('❌ 节点切换失败: $e', tag: 'SingBox');
print('🔵 节点切换失败: $e');
if (kDebugMode) {
print('🔵 节点切换失败: $e');
}
}
} else {
KRLogUtil.kr_i(' 没有保存的节点选择,使用默认配置', tag: 'SingBox');
print('🔵 没有保存的节点选择,使用默认');
if (kDebugMode) {
print('🔵 没有保存的节点选择,使用默认');
}
}
} catch (e) {
KRLogUtil.kr_e('❌ 恢复节点选择失败: $e', tag: 'SingBox');
print('🔵 恢复节点选择失败: $e');
if (kDebugMode) {
print('🔵 恢复节点选择失败: $e');
}
}
});
} catch (e, stackTrace) {

View File

@ -1,6 +1,8 @@
import 'package:flutter/foundation.dart';
import 'package:loggy/loggy.dart';
///
/// 🔒 Release模式下所有日志都不会输出
class KRLogUtil {
static final KRLogUtil _instance = KRLogUtil._internal();
factory KRLogUtil() => _instance;
@ -8,38 +10,59 @@ class KRLogUtil {
///
static void kr_init() {
Loggy.initLoggy(
logPrinter: PrettyPrinter(),
);
// Debug
if (kDebugMode) {
Loggy.initLoggy(
logPrinter: PrettyPrinter(),
);
}
}
///
/// 🔒 Debug
static void kr_d(String message, {String? tag}) {
Loggy('${tag ?? 'KRLogUtil'}').debug(message);
if (kDebugMode) {
Loggy('${tag ?? 'KRLogUtil'}').debug(message);
}
}
///
/// 🔒 Debug
static void kr_i(String message, {String? tag}) {
Loggy('${tag ?? 'KRLogUtil'}').info(message);
if (kDebugMode) {
Loggy('${tag ?? 'KRLogUtil'}').info(message);
}
}
///
/// 🔒 Debug
static void kr_w(String message, {String? tag}) {
Loggy('${tag ?? 'KRLogUtil'}').warning(message);
if (kDebugMode) {
Loggy('${tag ?? 'KRLogUtil'}').warning(message);
}
}
///
/// 🔒 Debug
static void kr_e(String message, {String? tag, Object? error, StackTrace? stackTrace}) {
Loggy('${tag ?? 'KRLogUtil'}').error(message, error, stackTrace);
if (kDebugMode) {
Loggy('${tag ?? 'KRLogUtil'}').error(message, error, stackTrace);
}
}
///
/// 🔒 Debug
static void kr_network(String message, {String? tag}) {
Loggy('${tag ?? 'Network'}').info(message);
if (kDebugMode) {
Loggy('${tag ?? 'Network'}').info(message);
}
}
///
/// 🔒 Debug
static void kr_performance(String message, {String? tag}) {
Loggy('${tag ?? 'Performance'}').info(message);
if (kDebugMode) {
Loggy('${tag ?? 'Performance'}').info(message);
}
}
}

View File

@ -84,7 +84,7 @@ class KRNetworkCheck {
if (connectivityResult == ConnectivityResult.none) {
return false;
}
//
try {
final result = await InternetAddress.lookup('www.apple.com');
@ -93,13 +93,51 @@ class KRNetworkCheck {
return false;
}
} else {
// Android
final connectivityResult = await Connectivity().checkConnectivity();
return connectivityResult != ConnectivityResult.none;
// 🔧 Android 15
// 1.
final connectivityResult = await Connectivity().checkConnectivity().timeout(
const Duration(seconds: 3),
onTimeout: () {
debugPrint('⚠️ 连接性检查超时');
return ConnectivityResult.none;
},
);
if (connectivityResult == ConnectivityResult.none) {
debugPrint('❌ 网络未连接');
return false;
}
// 2. 🔧 Android 15 DNS
// Android 15 访
try {
final result = await InternetAddress.lookup('www.google.com').timeout(
const Duration(seconds: 5),
onTimeout: () {
debugPrint('⚠️ DNS 解析超时,网络可能不稳定');
return <InternetAddress>[];
},
);
if (result.isEmpty) {
debugPrint('⚠️ DNS 解析失败,但允许继续(可能是网络延迟)');
// 使 DNS
return true;
}
debugPrint('✅ 网络权限检查通过(连接性 + DNS 解析)');
return true;
} catch (e) {
debugPrint('⚠️ DNS 解析异常: $e,但允许继续');
// DNS
return true;
}
}
} catch (e) {
debugPrint('网络权限检查错误: $e');
return false;
debugPrint('❌ 网络权限检查错误: $e');
// 🔧 Android 15 true
//
return true;
}
}
@ -112,7 +150,7 @@ class KRNetworkCheck {
if (connectivityResult == ConnectivityResult.none) {
return false;
}
try {
final result = await InternetAddress.lookup('www.apple.com');
return result.isNotEmpty && result[0].rawAddress.isNotEmpty;
@ -120,12 +158,29 @@ class KRNetworkCheck {
return false;
}
} else {
final connectivityResult = await Connectivity().checkConnectivity();
return connectivityResult != ConnectivityResult.none;
// 🔧 Android 15
final connectivityResult = await Connectivity().checkConnectivity().timeout(
const Duration(seconds: 3),
onTimeout: () {
debugPrint('⚠️ 网络连接检查超时');
return ConnectivityResult.none;
},
);
if (connectivityResult == ConnectivityResult.none) {
debugPrint('❌ 网络未连接');
return false;
}
// 🔧 Android 15 true
// DNS
debugPrint('✅ 网络连接检查通过(${connectivityResult.name}');
return true;
}
} catch (e) {
debugPrint('网络连接检查错误: $e');
return false;
debugPrint('❌ 网络连接检查错误: $e');
// 🔧 Android 15 true
return true;
}
}

View File

@ -107,7 +107,7 @@ class KRDialog extends StatelessWidget {
children: [
if (icon != null) ...[
icon!,
SizedBox(height: 20.w),
SizedBox(height: 20.h),
],
if (title != null) ...[
Text(
@ -121,7 +121,7 @@ class KRDialog extends StatelessWidget {
),
textAlign: TextAlign.center,
),
SizedBox(height: 12.w),
SizedBox(height: 12.h),
],
if (message != null || customMessageWidget != null) ...[
Container(
@ -139,7 +139,7 @@ class KRDialog extends StatelessWidget {
),
),
),
SizedBox(height: 28.w),
SizedBox(height: 28.h),
],
if (cancelText != null) ...[
Row(

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:country_flags/country_flags.dart';
import 'package:flutter/foundation.dart';
class KRCountryFlag extends StatelessWidget {
final String countryCode;
@ -38,17 +39,29 @@ class KRCountryFlag extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 🔍
print('🏳️ KRCountryFlag.build 被调用');
print(' - 原始 countryCode: "$countryCode"');
print(' - countryCode.isEmpty: ${countryCode.isEmpty}');
print(' - countryCode.length: ${countryCode.length}');
if (kDebugMode) {
print('🏳️ KRCountryFlag.build 被调用');
}
if (kDebugMode) {
print(' - 原始 countryCode: "$countryCode"');
}
if (kDebugMode) {
print(' - countryCode.isEmpty: ${countryCode.isEmpty}');
}
if (kDebugMode) {
print(' - countryCode.length: ${countryCode.length}');
}
final processedCode = _getCountryCode(countryCode);
print(' - 处理后 code: "$processedCode"');
if (kDebugMode) {
print(' - 处理后 code: "$processedCode"');
}
//
if (countryCode.isEmpty) {
print(' ❌ 国家代码为空,显示占位符');
if (kDebugMode) {
print(' ❌ 国家代码为空,显示占位符');
}
return Container(
width: width ?? 50.w,
height: height ?? 50.w,
@ -65,7 +78,9 @@ class KRCountryFlag extends StatelessWidget {
final double actualWidth = width ?? 50.w;
final double actualHeight = maintainSize ? actualWidth : (height ?? 50.w);
print(' ✅ 尝试加载国旗: $processedCode');
if (kDebugMode) {
print(' ✅ 尝试加载国旗: $processedCode');
}
Widget flagWidget = CountryFlag.fromCountryCode(
processedCode,