WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit a38bf63

Browse files
committed
语言处理
1 parent 3794bb7 commit a38bf63

29 files changed

+1269
-1661
lines changed

V2rayU/AppVersion.swift

Lines changed: 126 additions & 531 deletions
Large diffs are not rendered by default.

V2rayU/Base/Download.swift

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,27 @@
66
//
77

88
import Foundation
9+
import SwiftUI
10+
11+
/// 下载状态模型(纯数据结构)
12+
struct DownloadState {
13+
var downloadingVersion: String = ""
14+
var downloadingUrl: String = ""
15+
var progress: Double = 0.0
16+
var speed: String = "0.0 KB/s"
17+
var downloadedSize: String = "0.0 MB"
18+
var totalSize: String = "0.0 MB"
19+
var isFinished: Bool = false
20+
var errorMessage: String? = nil
21+
var downloadedFilePath: String? = nil
22+
}
923

1024
/// 通用下载代理,支持进度、超时、错误、完成回调
11-
class DownloadDelegate: NSObject, URLSessionDelegate, URLSessionDownloadDelegate, @unchecked Sendable {
25+
@MainActor
26+
class DownloadManager: NSObject, ObservableObject, URLSessionDelegate, URLSessionDownloadDelegate {
27+
/// 一个整体的下载状态
28+
@Published var state = DownloadState()
29+
1230
private let timerLock = NSLock()
1331
private var _timer: Timer?
1432
private var timer: Timer? {
@@ -19,7 +37,6 @@ class DownloadDelegate: NSObject, URLSessionDelegate, URLSessionDownloadDelegate
1937
private let timeoutSeconds: Double
2038
private var didTimeout = false
2139
private var downloadTask: URLSessionDownloadTask?
22-
private let onProgress: (Double, String, String) -> Void
2340
private let onSuccess: (String) -> Void
2441
private let onError: (String) -> Void
2542
private var lastWritten: Int64 = 0
@@ -28,27 +45,52 @@ class DownloadDelegate: NSObject, URLSessionDelegate, URLSessionDownloadDelegate
2845
/// 初始化
2946
/// - Parameters:
3047
/// - timeout: 超时时间(秒)
31-
/// - onProgress: 进度回调 0~1
3248
/// - onSuccess: 成功回调,参数为下载文件临时路径
3349
/// - onError: 错误回调,参数为错误信息
3450
init(timeout: Double = 10,
35-
onProgress: @escaping (Double, String, String) -> Void,
3651
onSuccess: @escaping (String) -> Void,
3752
onError: @escaping (String) -> Void) {
3853
timeoutSeconds = timeout
39-
self.onProgress = onProgress
4054
self.onSuccess = onSuccess
4155
self.onError = onError
4256
}
4357

58+
// MARK: - 对外启动下载接口
59+
func startDownload(from urlString: String, version: String, totalSize: Int64, useProxy: Bool = true) {
60+
guard let url = URL(string: urlString) else {
61+
self.state.isFinished = true
62+
self.state.errorMessage = String(localized: .DownloadURLInvalid)
63+
self.onError(self.state.errorMessage)
64+
return
65+
}
66+
state.downloadingVersion = version
67+
state.downloadingUrl = urlString
68+
state.totalSize = formatByte(Double(totalSize))
69+
state.isFinished = false
70+
state.progress = 0.0
71+
state.errorMessage = nil
72+
var config = URLSessionConfiguration.default
73+
if useProxy {
74+
config = getProxyUrlSessionConfigure()
75+
}
76+
session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
77+
let task = session!.downloadTask(with: url)
78+
// 启动超时检测计时器
79+
startTimeout(downloadTask: task)
80+
// 启动下载任务
81+
task.resume()
82+
}
83+
4484
func startTimeout(downloadTask: URLSessionDownloadTask) {
4585
self.downloadTask = downloadTask
4686
timer = Timer.scheduledTimer(withTimeInterval: timeoutSeconds, repeats: false) { [weak self] _ in
4787
guard let self = self else { return }
4888
self.didTimeout = true
4989
downloadTask.cancel()
5090
DispatchQueue.main.async {
51-
self.onError("下载超时,请检查网络或代理设置")
91+
self.state.isFinished = true
92+
self.state.errorMessage = String(localized: .DownloadErrorOccurred)
93+
self.onError(self.state.errorMessage)
5294
}
5395
}
5496
}
@@ -61,7 +103,9 @@ class DownloadDelegate: NSObject, URLSessionDelegate, URLSessionDownloadDelegate
61103
self.didTimeout = true
62104
task.cancel()
63105
DispatchQueue.main.async {
64-
self.onError("下载超时,请检查网络或代理设置")
106+
self.state.isFinished = true
107+
self.state.errorMessage = String(localized: .DownloadTimeoutError)
108+
self.onError(self.state.errorMessage)
65109
}
66110
}
67111
}
@@ -83,10 +127,11 @@ class DownloadDelegate: NSObject, URLSessionDelegate, URLSessionDownloadDelegate
83127
lastWritten = totalBytesWritten
84128
lastTime = now
85129
let progress = totalBytesExpectedToWrite > 0 ? Double(totalBytesWritten) / Double(totalBytesExpectedToWrite) : 0
86-
87-
DispatchQueue.main.async {
88-
self.onProgress(progress, speed, formatByte(Double(totalBytesWritten)))
89-
}
130+
let downloaded = formatByte(Double(totalBytesWritten))
131+
// 更新结构体中的状态
132+
self.state.progress = progress
133+
self.state.speed = speed
134+
self.state.downloadedSize = downloaded
90135
resetTimeout()
91136
}
92137

@@ -96,6 +141,9 @@ class DownloadDelegate: NSObject, URLSessionDelegate, URLSessionDownloadDelegate
96141
let fileName = downloadTask.response?.suggestedFilename ?? ""
97142
guard locationPath != "", fileName != "" else {
98143
logger.info("urlSession: locationPath or fileName missing", )
144+
self.state.isFinished = true
145+
self.state.errorMessage = String(localized: .DownloadSaveFailed) + ": urlSession: locationPath or fileName missing"
146+
self.onError(self.state.errorMessage)
99147
return
100148
}
101149
let documentsPath = NSHomeDirectory() + "/Library/Caches/Download"
@@ -106,18 +154,28 @@ class DownloadDelegate: NSObject, URLSessionDelegate, URLSessionDownloadDelegate
106154
try FileManager.default.removeItem(atPath: filePath)
107155
}
108156
} catch let catchError {
109-
alertDialog(title: "下载失败1", message: "保存出错 = \(catchError.localizedDescription)")
157+
self.state.isFinished = true
158+
self.state.errorMessage = String(localized: .DownloadSaveFailed) + ": \(catchError.localizedDescription)"
159+
self.onError(self.state.errorMessage)
160+
return
110161
}
111162
do {
112163
if FileManager.default.fileExists(atPath: documentsPath) == false {
113164
try FileManager.default.createDirectory(atPath: documentsPath, withIntermediateDirectories: true)
114165
}
166+
// 记录下载文件路径
167+
self.state.downloadedFilePath = filePath
115168
// 移动文件,不然随时被删除
116169
try FileManager.default.moveItem(atPath: locationPath, toPath: filePath)
117170
} catch let catchError {
118-
alertDialog(title: "下载失败2", message: "保存出错 = \(catchError.localizedDescription)")
171+
self.state.isFinished = true
172+
self.state.errorMessage = String(localized: .DownloadSaveFailed) + ": \(catchError.localizedDescription)"
173+
self.onError(self.state.errorMessage)
174+
return
119175
}
120176
DispatchQueue.main.async {
177+
// 更新状态为完成
178+
self.state.isFinished = true
121179
self.onSuccess(filePath)
122180
}
123181
}
@@ -130,7 +188,9 @@ class DownloadDelegate: NSObject, URLSessionDelegate, URLSessionDownloadDelegate
130188
return
131189
}
132190
DispatchQueue.main.async {
133-
self.onError("下载失败: \(error.localizedDescription)")
191+
self.state.isFinished = true
192+
self.state.errorMessage = String(localized: .DownloadErrorOccurred) + ": \(error.localizedDescription)"
193+
self.onError(self.state.errorMessage)
134194
}
135195
}
136196
}

V2rayU/Base/Util.swift

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,6 @@ func noticeTip(title: String = "", informativeText: String = "") {
133133
}
134134

135135

136-
func vold() {
137-
138-
}
139-
140136
func getRandomPort() -> UInt16 {
141137
return UInt16.random(in: 49152...65535)
142138
}
@@ -165,13 +161,8 @@ func clearLogFile(logFilePath: String) {
165161
FileManager.default.createFile(atPath: logFilePath, contents: nil, attributes: nil)
166162
} catch let error {
167163
logger.info("clear log file fail: \(error)")
168-
var title = "Clear log file failed"
169-
var toast = "Error: \(error)"
170-
if isMainland {
171-
title = "清除日志文件失败"
172-
toast = "错误: \(error)"
173-
}
174-
alertDialog(title: title, message: toast)
164+
var title = String(localized: .ClearLogFileFailed)
165+
alertDialog(title: title, message: error)
175166
}
176167
}
177168

@@ -184,12 +175,7 @@ func truncateLogFile(_ logFilePath: String) {
184175
}
185176
} catch let error {
186177
logger.info("truncate log file fail: \(error)")
187-
var title = "Truncate log file failed"
188-
var toast = "Error: \(error)"
189-
if isMainland {
190-
title = "清除日志文件失败"
191-
toast = "错误: \(error)"
192-
}
178+
var title = String(localized: .ClearLogFileFailed)
193179
alertDialog(title: title, message: toast)
194180
}
195181
}

V2rayU/Handler/AppInstaller.swift

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,16 @@ actor AppInstaller: NSObject {
6969
}
7070

7171
func showInstallAlert() {
72-
DispatchQueue.main.async {
72+
// 将 UI 操作放到主线程, 同步执行, 确保在调用后才能继续
73+
DispatchQueue.main.sync {
74+
7375
let alert = NSAlert()
7476
alert.alertStyle = .warning
75-
if isMainland {
76-
alert.messageText = "安装V2rayUTool"
77-
alert.informativeText = "V2rayU 需要使用管理员权限安装 V2rayUTool 到 ~/.V2rayU/V2rayUTool"
78-
alert.addButton(withTitle: "安装")
79-
alert.addButton(withTitle: "退出")
80-
} else {
81-
alert.messageText = " Install V2rayUTool"
82-
alert.informativeText = "V2rayU needs to install V2rayUTool into ~/.V2rayU/V2rayUTool with administrator privileges"
83-
alert.addButton(withTitle: "Install")
84-
alert.addButton(withTitle: "Quit")
85-
}
77+
alert.messageText = String(localized: .InstallV2rayUTool)
78+
alert.informativeText = String(localized: .InstallPermissionTip)
79+
alert.addButton(withTitle: String(localized: .Install))
80+
alert.addButton(withTitle: String(localized: .Quit))
81+
8682
switch alert.runModal() {
8783
case .alertFirstButtonReturn:
8884
Task {
@@ -131,12 +127,8 @@ actor AppInstaller: NSObject {
131127
logger.info("executeAppleScript-Output: \(output)")
132128
} catch {
133129
logger.info("executeAppleScript-Error: \(error)")
134-
var title = "Install V2rayUTool Failed"
135-
var toast = "Error: \(error),\nYou need execute scripts manually:\n \(script)"
136-
if isMainland {
137-
title = "安装 V2rayUTool 失败"
138-
toast = "安装失败: \(error)\n, 你需要在命令行手动执行一下: \(script)"
139-
}
130+
var title = String(localized: .InstallFailed)
131+
var toast = "\(String(localized: .InstallFailedManual))\n \(script)"
140132
alertDialog(title: title, message: toast)
141133
}
142134
}

V2rayU/Handler/HttpServer.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,8 @@ actor LocalHttpServer {
3434
logger.info("pacPort: \(pacPort)")
3535

3636
if isPortOpen(pacPort) {
37-
var toast = "pac port \(pacPort) has been used, please replace from advance setting"
38-
var title = "Port is already in use"
39-
if isMainland {
40-
toast = "pac端口 \(pacPort) 已被使用, 请更换"
41-
title = "端口已被占用"
42-
}
37+
var title = String(localized: .PortInUse)
38+
var toast = + "\(pacPort) " + String(localized: .PortInUseTip)
4339
alertDialog(title: title, message: toast)
4440
DispatchQueue.main.async {
4541
showDock(state: true)

0 commit comments

Comments
 (0)