Update On Mon Jul 1 20:30:44 CEST 2024

This commit is contained in:
github-action[bot]
2024-07-01 20:30:45 +02:00
parent 875240255c
commit 91fe520152
260 changed files with 9567 additions and 16831 deletions

View File

@@ -1,7 +1,7 @@
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
source 'https://github.com/CocoaPods/Specs.git'
platform :osx, '10.14'
platform :osx, '11.0'
target 'V2rayU' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
@@ -14,7 +14,6 @@ target 'V2rayU' do
pod 'SwiftyJSON'
# master branch
pod 'Preferences', :git => 'https://github.com/sindresorhus/Preferences.git'
pod 'Sparkle' ,'~> 2.0'
pod 'QRCoder'
pod 'MASShortcut'
pod 'Swifter'

View File

@@ -18,9 +18,9 @@
6618372E23E9BF74000F7410 /* ToastWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6618372C23E9BF73000F7410 /* ToastWindow.xib */; };
66193A8623EE45B200289B6A /* PreferenceRouting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66193A8523EE45B200289B6A /* PreferenceRouting.swift */; };
66193A8923EE46BC00289B6A /* PreferenceRouting.xib in Resources */ = {isa = PBXBuildFile; fileRef = 66193A8723EE46BC00289B6A /* PreferenceRouting.xib */; };
6633A43F2C0A120000C54CA5 /* Sparkle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6633A43E2C0A120000C54CA5 /* Sparkle.swift */; };
663F040625ED4B2C00687600 /* V2rayLaunch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 663F040525ED4B2C00687600 /* V2rayLaunch.swift */; };
664BAC472C2DB0E100654FB7 /* V2rayRouting.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664BAC462C2DB0E100654FB7 /* V2rayRouting.swift */; };
664BAC492C314CD600654FB7 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664BAC482C314CD600654FB7 /* AppVersion.swift */; };
664EB375216C9A5E00B6AE0D /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664EB374216C9A5E00B6AE0D /* AppDelegate.swift */; };
664EB377216C9A5F00B6AE0D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 664EB376216C9A5F00B6AE0D /* Assets.xcassets */; };
664EB392216CA9E800B6AE0D /* ConfigWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 664EB390216CA9E800B6AE0D /* ConfigWindow.swift */; };
@@ -121,11 +121,11 @@
6625848D2AB745E700DFDC1E /* sign.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = sign.sh; sourceTree = "<group>"; };
6625848E2AB746D500DFDC1E /* appdmg.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = appdmg.sh; sourceTree = "<group>"; };
662F0ACE2AB720C700884C17 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = ../en.lproj/PreferenceGeneral.strings; sourceTree = "<group>"; };
6633A43E2C0A120000C54CA5 /* Sparkle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sparkle.swift; sourceTree = "<group>"; };
663F040525ED4B2C00687600 /* V2rayLaunch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = V2rayLaunch.swift; sourceTree = "<group>"; };
664666A021CBD6C60094F0B7 /* libPods-V2rayUTool.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = "libPods-V2rayUTool.a"; sourceTree = BUILT_PRODUCTS_DIR; };
664B95DD217062A500DBC941 /* Alamofire */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Alamofire; path = Pods/Alamofire; sourceTree = "<group>"; };
664BAC462C2DB0E100654FB7 /* V2rayRouting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = V2rayRouting.swift; sourceTree = "<group>"; };
664BAC482C314CD600654FB7 /* AppVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersion.swift; sourceTree = "<group>"; };
664EB371216C9A5E00B6AE0D /* V2rayU.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = V2rayU.app; sourceTree = BUILT_PRODUCTS_DIR; };
664EB374216C9A5E00B6AE0D /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
664EB376216C9A5F00B6AE0D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -267,6 +267,7 @@
6608D9B82182BBAC00A0E0DD /* v2ray */,
664EB376216C9A5F00B6AE0D /* Assets.xcassets */,
664EB374216C9A5E00B6AE0D /* AppDelegate.swift */,
664BAC482C314CD600654FB7 /* AppVersion.swift */,
66ACB19F21757D5B005B5881 /* MainMenu.swift */,
664EB378216C9A5F00B6AE0D /* MainMenu.xib */,
664EB390216CA9E800B6AE0D /* ConfigWindow.swift */,
@@ -287,7 +288,6 @@
6D6DF7F662C35646734A352E /* install.sh */,
6D6DF11F0983AFCBEF1E347B /* Uri.swift */,
6D6DF79424C83391C205CB9C /* Share.swift */,
6633A43E2C0A120000C54CA5 /* Sparkle.swift */,
);
path = V2rayU;
sourceTree = "<group>";
@@ -556,6 +556,7 @@
6608D9DA2182C69D00A0E0DD /* v2rayStruct.swift in Sources */,
66F07CF9236D79540088A4AE /* Ping.swift in Sources */,
664EB392216CA9E800B6AE0D /* ConfigWindow.swift in Sources */,
664BAC492C314CD600654FB7 /* AppVersion.swift in Sources */,
66193A8623EE45B200289B6A /* PreferenceRouting.swift in Sources */,
6D6DF8BFC33F97E9AFCA5A4B /* V2rayConfig.swift in Sources */,
6D6DF6F065067CD879201FF9 /* Import.swift in Sources */,
@@ -568,7 +569,6 @@
6D6DF807BE591BE396221EF3 /* PreferenceAdvance.swift in Sources */,
6D6DFC1D9432F2A60D2156E2 /* PreferenceDns.swift in Sources */,
6D6DF670FFB063EE2360776C /* Uri.swift in Sources */,
6633A43F2C0A120000C54CA5 /* Sparkle.swift in Sources */,
6D6DF41FA8F7C7B020AC4115 /* Share.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -768,7 +768,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -827,7 +827,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
@@ -849,7 +849,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4.2.0;
CURRENT_PROJECT_VERSION = 4.0.0;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
ENABLE_ONLY_ACTIVE_RESOURCES = YES;
@@ -859,8 +859,8 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 4.2.0;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 4.0.0;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = net.yanue.V2rayU;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -883,7 +883,7 @@
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 4.2.0;
CURRENT_PROJECT_VERSION = 4.0.0;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = "";
ENABLE_ONLY_ACTIVE_RESOURCES = YES;
@@ -893,8 +893,8 @@
"$(inherited)",
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.15;
MARKETING_VERSION = 4.2.0;
MACOSX_DEPLOYMENT_TARGET = 11.0;
MARKETING_VERSION = 4.0.0;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = net.yanue.V2rayU;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -915,7 +915,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
@@ -930,7 +930,7 @@
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
ENABLE_HARDENED_RUNTIME = YES;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MACOSX_DEPLOYMENT_TARGET = 11.0;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};

View File

@@ -10,12 +10,10 @@ import Cocoa
import ServiceManagement
import MASShortcut
import Preferences
import Sparkle
import FirebaseCore
let launcherAppIdentifier = "net.yanue.V2rayU.Launcher"
let appVersion = getAppVersion()
let V2rayUpdater = V2rayUpdaterController()
let NOTIFY_TOGGLE_RUNNING_SHORTCUT = Notification.Name(rawValue: "NOTIFY_TOGGLE_RUNNING_SHORTCUT")
let NOTIFY_SWITCH_PROXY_MODE_SHORTCUT = Notification.Name(rawValue: "NOTIFY_SWITCH_PROXY_MODE_SHORTCUT")
@@ -42,6 +40,9 @@ let preferencesWindowController = PreferencesWindowController(
]
)
let langStr = Locale.current.languageCode
let isMainland = langStr == "zh-CN" || langStr == "zh" || langStr == "zh-Hans" || langStr == "zh-Hant"
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
// bar menu

View File

@@ -0,0 +1,614 @@
//
// AppVersion.swift
// V2rayU
//
// Created by yanue on 2024/6/30.
// Copyright © 2024 yanue. All rights reserved.
//
import SwiftUI
import ServiceManagement
// UI.
// SwiftUI + NSWindowController
// UI: Sparkle(https://github.com/sparkle-project/Sparkle)
// https://github.com/yanue/V2rayU/releases
struct GithubRelease: Codable {
let id: Int
let tagName: String
let name: String
let draft: Bool
let prerelease: Bool
let publishedAt: Date // 2024-06-30T09:00:00Z,
let assets: [GithubAsset]
let body: String
enum CodingKeys: String, CodingKey {
case id
case tagName = "tag_name"
case name
case draft
case prerelease
case publishedAt = "published_at"
case assets
case body
}
}
struct GithubAsset: Codable {
let name: String
let browserDownloadUrl: String
enum CodingKeys: String, CodingKey {
case name
case browserDownloadUrl = "browser_download_url"
}
}
let V2rayUpdater = AppCheckController()
// AppCheckController -
class AppCheckController: NSWindowController {
// Declare the contentView as a property to avoid using self before super.init
private var contentView: NSHostingView<ContentView>!
var bindData = BindData()
// Initialize the view and window
init() {
// Initialize the content view with a placeholder closure
let contentView = NSHostingView(rootView: ContentView(
bindData: bindData,
closeWindow: {}
))
// Create the window with specified dimensions and styles
let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
styleMask: [.titled, .closable, .resizable],
backing: .buffered, defer: false)
window.title = "Check V2rayU"
window.contentView = contentView
// Call the super init with the created window
super.init(window: window)
// Update the contentView with the actual closure after super.init
contentView.rootView = ContentView(
bindData: bindData,
closeWindow: closeWindow
)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func windowDidLoad() {
super.windowDidLoad()
}
func checkForUpdates(showWindow: Bool = false) {
if showWindow {
DispatchQueue.main.async {
self.window?.orderFrontRegardless()
self.window?.center()
self.window?.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
}
} else {
// close window
DispatchQueue.main.async {
self.window?.close()
}
}
guard let url = URL(string: "https://api.github.com/repos/yanue/V2rayU/releases") else {
return
}
print("checkForUpdates: \(url)")
let checkTask = URLSession.shared.dataTask(with: url) { data, response, error in
if let error = error {
print("Error fetching release: \(error)")
return
}
guard let data = data else {
print("No data returned")
return
}
print("checkForUpdates: \n \(data)")
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601 //
// try decode data
let data: [GithubRelease] = try decoder.decode([GithubRelease].self, from: data)
//
let sortedData = data.sorted { $0.publishedAt > $1.publishedAt }
//
if let release = sortedData.first {
print("release: \(release.tagName)")
DispatchQueue.main.async {
let releaseVersion = release.tagName.replacingOccurrences(of: "v", with: "").replacingOccurrences(of: "V", with: "").trimmingCharacters(in: .whitespaces) // v4.1.0 => 4.1.0
// get old version
let appVer = appVersion.versionToInt()
let releaseVer = releaseVersion.versionToInt()
// new version is bigger than old version
if appVer.lexicographicallyPrecedes(releaseVer) {
// ,
if !showWindow {
// ,
if let skipVersion = UserDefaults.standard.string(forKey: "skipAppVersion") {
if skipVersion == release.tagName {
print("Skip version: \(skipVersion)")
return
}
}
}
//
let versionController = AppVersionController()
versionController.show(release: release)
// close window
self.closeWindow()
} else {
var title = "You are up to date!"
var toast = "V2rayU \(appVersion) is currently the newest version available."
if isMainland {
title = "当前已经是最新版了"
toast = "V2rayU \(appVersion) 已经是当前最新版了.";
}
// open dialog
alertDialog(title: title, message: toast)
// close window
self.closeWindow()
}
}
}
} catch {
print("Error decoding JSON: \(error)")
DispatchQueue.main.async {
// update progress text
self.bindData.progressText = "Check failed: \(error)"
var title = "Check failed!"
var toast = "\(error)"
if isMainland {
title = "检查失败"
toast = "\(error)";
}
// open dialog
alertDialog(title: title, message: toast)
// sleep 2s
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// close window
self.closeWindow()
}
}
}
}
checkTask.resume()
}
func closeWindow() {
DispatchQueue.main.async {
self.window?.close()
}
}
class BindData: ObservableObject {
@Published var progressText = "check for updates..."
}
struct ContentView: View {
@ObservedObject var bindData: BindData
var closeWindow: () -> Void
var body: some View {
VStack(spacing: 20) {
HStack {
Image("V2rayU")
.resizable()
.frame(width: 64, height: 64)
.cornerRadius(8)
Spacer()
VStack {
HStack {
ProgressView(bindData.progressText) .progressViewStyle(LinearProgressViewStyle()).padding(.horizontal)
}
HStack {
Spacer()
Button(action: {
closeWindow()
}) {
Text("Cancel").font(.body)
}
.padding(.trailing, 20)
}
}
}
.padding()
}
}
}
}
// AppVersionController -
class AppVersionController: NSWindowController {
var bindData = BindData()
private var contentView: NSHostingView<ContentView>!
private var release: GithubRelease!
init() {
let contentView = NSHostingView(rootView: ContentView(
bindData: bindData,
skipAction: { print("Skip action") },
installAction: { print("Install action") }
))
let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 500, height: 300),
styleMask: [.titled, .closable, .resizable],
backing: .buffered, defer: false)
window.title = "Software Update"
window.contentView = contentView
super.init(window: window)
// Update the contentView with the actual closure after super.init
contentView.rootView = ContentView(
bindData: bindData,
skipAction: self.skipAction,
installAction: self.installAction
)
}
func show(release: GithubRelease) {
bindData.title = "A new version of V2rayU is available!"
bindData.description = "V2rayU \(appVersion) is now available—you have \(release.tagName). Would you like to download it now?"
bindData.releaseNotes = release.name + "\n" + release.body
self.release = release
print("bindData.releaseNotes", bindData.releaseNotes)
// bring window to front
window?.orderFrontRegardless()
// center position
window?.center()
// make window key
window?.makeKeyAndOrderFront(nil)
// activate app
NSApp.activate(ignoringOtherApps: true)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func windowDidLoad() {
super.windowDidLoad()
}
//
func installAction() {
DispatchQueue.main.async {
//
let downloadController = AppDownloadController()
downloadController.show(release: self.release)
//
self.window?.close()
}
}
func skipAction() {
print("Skip action")
// UserDefaults
UserDefaults.standard.set(release.tagName, forKey: "skipAppVersion")
//
DispatchQueue.main.async {
self.window?.close()
}
}
class BindData: ObservableObject {
@Published var title = "A new version of V2rayU App is available!"
@Published var description = ""
@Published var releaseNotes = """
"""
}
struct ContentView: View {
@ObservedObject var bindData: BindData
var skipAction: () -> Void
var installAction: () -> Void
var body: some View {
VStack(alignment: .leading, spacing: 10) {
HStack(alignment: .top, spacing: 10) {
// use AppIcon.appiconset to Image
Image("V2rayU")
.resizable()
.frame(width: 64, height: 64)
.padding(.top, 20)
.padding(.leading, 20)
VStack(alignment: .leading, spacing: 5) {
Text(bindData.title)
.font(.headline)
.padding(.top, 20)
Text(bindData.description)
.padding(.trailing, 20)
Text("Release Notes:")
.font(.headline)
.bold()
.padding(.top, 20)
HStack {
//
TextEditor(text: $bindData.releaseNotes)
.lineSpacing(6) //
.frame(height: 120)
.border(Color.gray, width: 1) // 2
.fixedSize(horizontal: false, vertical: true)
Spacer(minLength: 20) // margin 40
}
}
}
HStack {
Button("Skip This Version") {
skipAction()
}
Spacer()
Button("Install Update") {
installAction()
}
.keyboardShortcut(.defaultAction)
}
.padding(20)
}
.frame(width: 500, height: 300)
}
}
}
// AppDownloadController -
class AppDownloadController: NSWindowController, URLSessionDownloadDelegate {
private var contentView: NSHostingView<ContentView>!
var bindData = BindData()
private var downloadTask: URLSessionDownloadTask?
private var destinationURL: URL?
init() {
let contentView = NSHostingView(rootView: ContentView(
bindData: bindData,
cancelDownload: {},
doInstall: {}
))
let window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
styleMask: [.titled, .closable, .resizable],
backing: .buffered, defer: false)
window.title = "Download V2rayU"
window.contentView = contentView
super.init(window: window)
// Update the contentView with the actual closure after super.init
contentView.rootView = ContentView(
bindData: bindData,
cancelDownload: cancelDownload,
doInstall: doInstall
)
self.contentView = contentView
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func windowDidLoad() {
super.windowDidLoad()
}
func show(release: GithubRelease) {
DispatchQueue.main.async {
self.window?.orderFrontRegardless()
self.window?.center()
self.window?.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
}
download(release: release)
}
func download(release: GithubRelease) {
DispatchQueue.main.async {
if let asset = release.assets.first {
self.bindData.dmgUrl = asset.browserDownloadUrl
print("download: \(self.bindData.dmgUrl)")
self.startDownload()
} else {
self.bindData.progressText = "No dmg asset found"
return
}
}
}
private func startDownload() {
guard let url = URL(string: bindData.dmgUrl) else {
DispatchQueue.main.async {
self.bindData.isDownloading = true
self.bindData.progressText = "Invalid dmg url"
}
return
}
DispatchQueue.main.async {
self.bindData.isDownloading = true
self.bindData.progress = 0.0
self.bindData.progressText = "Downloading..."
}
let urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: OperationQueue())
downloadTask = urlSession.downloadTask(with: url)
downloadTask?.resume()
}
private func cancelDownload() {
DispatchQueue.main.async {
self.bindData.isDownloading = false
self.bindData.progress = 0.0
self.bindData.progressText = "Download canceled"
self.downloadTask?.cancel()
print("Download canceled")
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.window?.close()
}
}
func doInstall() {
DispatchQueue.main.async {
if let destinationURL = self.destinationURL {
// open downloaded dmg
NSWorkspace.shared.open(destinationURL)
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
// close window
self.window?.close()
NSApplication.shared.terminate(self)
}
}
}
print("Installing V2rayU")
}
// ---------------------- ui --------------------------------
// MARK: -
class BindData: ObservableObject {
@Published var progressText = "Downloading..."
@Published var dmgUrl: String = ""
@Published var progress: Float = 0.0
@Published var isDownloading: Bool = false
}
// MARK: -
struct ContentView: View {
@ObservedObject var bindData: BindData
var cancelDownload: () -> Void
var doInstall: () -> Void
var body: some View {
VStack(spacing: 20) {
VStack(spacing: 20) {
HStack {
Image("V2rayU")
.resizable()
.frame(width: 64, height: 64)
.cornerRadius(8)
Spacer()
VStack {
HStack {
ProgressView(value: bindData.progress, total: 100) {
Text(bindData.progressText)
}
}
HStack {
Spacer()
if bindData.isDownloading {
Button(action: {
cancelDownload()
}) {
Text("Cancel").font(.body)
}
} else {
Button(action: {
doInstall()
}) {
Text("Install V2rayU").font(.body)
}
}
}
}
}
.padding()
}
}
.padding()
}
}
// ---------------------- --------------------------------
// MARK: - URLSessionDownloadDelegate
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
let fileManager = FileManager.default
let downloadsDirectory = fileManager.urls(for: .downloadsDirectory, in: .userDomainMask).first!
destinationURL = downloadsDirectory.appendingPathComponent(downloadTask.response?.suggestedFilename ?? "V2rayU-macOS.dmg")
do {
try fileManager.moveItem(at: location, to: destinationURL!)
DispatchQueue.main.async {
self.bindData.isDownloading = false
self.bindData.progress = 100.0
self.bindData.progressText = "Download Completed"
}
print("Download finished: \(destinationURL!)")
} catch {
DispatchQueue.main.async {
self.bindData.isDownloading = false
self.bindData.progressText = "File move error: \(error.localizedDescription)"
var title = "Download failed!"
var toast = "\(error)"
if isMainland {
title = "移动文件失败"
toast = "\(error)";
}
// open dialog
alertDialog(title: title, message: toast)
}
print("File move error: \(error.localizedDescription)")
}
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
DispatchQueue.main.async {
self.bindData.progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) * 100
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let error = error {
DispatchQueue.main.async {
self.bindData.isDownloading = false
self.bindData.progressText = "Download Failed: \(error.localizedDescription)"
}
var title = "Download failed!"
var toast = "\(error)"
if isMainland {
title = "下载文件失败"
toast = "\(error)";
}
// open dialog
alertDialog(title: title, message: toast)
print("Download error: \(error.localizedDescription)")
}
}
}

View File

@@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}
}

View File

@@ -1,26 +1,26 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "icon@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "icon@3x 1.png",
"idiom" : "universal",
"filename" : "icon@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,18 @@
{
"images" : [
{
"filename" : "128.png",
"idiom" : "mac",
"scale" : "1x"
},
{
"filename" : "1024.png",
"idiom" : "mac",
"scale" : "2x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21225" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21225"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22690"/>
<capability name="System colors introduced in macOS 10.14" minToolsVersion="10.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -19,7 +19,7 @@
<rect key="frame" x="0.0" y="0.0" width="700" height="360"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YO4-aZ-Rwa">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="YO4-aZ-Rwa">
<rect key="frame" x="309" y="272" width="62" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="V2rayU" id="09i-pj-m0K">
@@ -28,7 +28,7 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5SZ-ig-pGf">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5SZ-ig-pGf">
<rect key="frame" x="266" y="184" width="24" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="🌍" id="K46-M8-1zq">
@@ -37,7 +37,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Te4-BT-hGI">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Te4-BT-hGI">
<rect key="frame" x="286" y="189" width="152" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="github.com/yanue/v2rayU" id="Qby-y7-vli">
@@ -46,7 +46,7 @@
<color key="backgroundColor" name="systemIndigoColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e05-pp-m5L">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="e05-pp-m5L">
<rect key="frame" x="288" y="166" width="122" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="yanue@outlook.com" id="Guc-nt-FeY">
@@ -55,7 +55,7 @@
<color key="backgroundColor" name="systemIndigoColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wuh-jp-WUO">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wuh-jp-WUO">
<rect key="frame" x="266" y="162" width="24" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="📬" id="OUg-qH-sDe">
@@ -64,7 +64,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oNz-CM-Geb">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oNz-CM-Geb">
<rect key="frame" x="267" y="138" width="24" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="🔗" id="rUl-Lc-b4S">
@@ -73,7 +73,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Hji-yO-Zff">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Hji-yO-Zff">
<rect key="frame" x="287" y="143" width="146" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="https://github.com/XTLS" id="Sw8-ch-1M9">
@@ -82,7 +82,7 @@
<color key="backgroundColor" name="systemIndigoColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="huF-fy-g3j">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="huF-fy-g3j">
<rect key="frame" x="262" y="92" width="156" height="14"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" title="Copyright © 2021 yanue.net" id="bCA-au-e3o">
@@ -91,7 +91,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gws-ge-QLa">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="gws-ge-QLa">
<rect key="frame" x="264" y="69" width="156" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" controlSize="mini" lineBreakMode="charWrapping" enabled="NO" sendsActionOnEndEditing="YES" borderStyle="bezel" alignment="center" title="based on Xray-core v1.4.2" usesSingleLineMode="YES" bezelStyle="round" id="8bU-0Q-dTD">
@@ -100,7 +100,7 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GfP-Xl-Rdf">
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GfP-Xl-Rdf">
<rect key="frame" x="306" y="251" width="73" height="13"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Version 1.0" id="gsf-1V-bbM">

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22690"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@@ -18,13 +18,13 @@
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" visibleAtLaunch="NO" animationBehavior="default" id="kRK-Pd-y69" customClass="NSPanel">
<windowStyleMask key="styleMask" closable="YES" miniaturizable="YES" resizable="YES" utility="YES"/>
<rect key="contentRect" x="139" y="81" width="300" height="100"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<rect key="screenRect" x="0.0" y="0.0" width="1800" height="1125"/>
<value key="minSize" type="size" width="200" height="100"/>
<view key="contentView" id="KRY-zc-8By" userLabel="Panel View">
<rect key="frame" x="0.0" y="0.0" width="300" height="100"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="162" translatesAutoresizingMaskIntoConstraints="NO" id="scG-hz-bja" userLabel="Is Name">
<textField focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="162" translatesAutoresizingMaskIntoConstraints="NO" id="scG-hz-bja" userLabel="Is Name">
<rect key="frame" x="24" y="33" width="258" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="Label" usesSingleLineMode="YES" id="eQL-ri-Y7Z">

View File

@@ -7,7 +7,6 @@
//
import Cocoa
import Alamofire
var v2rayConfig: V2rayConfig = V2rayConfig()
@@ -645,22 +644,6 @@ class ConfigWindowController: NSWindowController, NSWindowDelegate, NSTabViewDel
if let importUri = ImportUri.importUri(uri: uri, checkExist: false) {
self.saveImport(importUri: importUri)
} else {
// download json file
Alamofire.request(jsonUrl.stringValue).responseString { DataResponse in
if (DataResponse.error != nil) {
DispatchQueue.main.async{
self.errTip.stringValue = "error: " + DataResponse.error.debugDescription
}
return
}
if DataResponse.value != nil {
DispatchQueue.main.async{
self.configText.string = v2rayConfig.formatJson(json: DataResponse.value ?? text)
}
}
}
}
}

View File

@@ -7,7 +7,11 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleGetInfoString</key>
<string></string>
<key>CFBundleDisplayName</key>
<true/>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
@@ -47,14 +51,10 @@
<true/>
</dict>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2019 yanue. All rights reserved.</string>
<string>Copyright © 2024 yanue. All rights reserved.</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>SUFeedURL</key>
<string>https://v2rayu-61f76.web.app/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>PW8pDnr5VZkmC93gZjUDlHI8gkJSspPoDU3DdhsMkps</string>
</dict>
</plist>

View File

@@ -8,8 +8,6 @@
import Cocoa
import ServiceManagement
import Sparkle
import Alamofire
let menuController = (NSApplication.shared.delegate as? AppDelegate)?.statusMenu.delegate as! MenuController
@@ -335,8 +333,7 @@ class MenuController: NSObject, NSMenuDelegate {
}
@IBAction func checkForUpdate(_ sender: NSMenuItem) {
// need set SUFeedURL into plist
V2rayUpdater.checkForUpdates()
V2rayUpdater.checkForUpdates(showWindow: true)
}
@IBAction func generateQrcode(_ sender: NSMenuItem) {

View File

@@ -6,7 +6,6 @@
// Copyright © 2019 yanue. All rights reserved.
//
import Alamofire
import SwiftyJSON
// ping and choose fastest v2ray

View File

@@ -68,7 +68,6 @@ final class PreferenceGeneralViewController: NSViewController, PreferencePane {
}
@IBAction func checkVersion(_ sender: NSButton) {
// need set SUFeedURL into plist
V2rayUpdater.checkForUpdates()
}

View File

@@ -6,7 +6,6 @@
// Copyright © 2018 yanue. All rights reserved.
//
import Alamofire
import Cocoa
import Preferences

View File

@@ -8,7 +8,6 @@
import Cocoa
import Preferences
import Alamofire
import SwiftyJSON
final class PreferenceSubscribeViewController: NSViewController, PreferencePane, NSTabViewDelegate {

View File

@@ -23,7 +23,7 @@ class V2rayUpdaterController: NSObject, SPUUpdaterDelegate {
func checkForUpdates() {
// check version by github release
checkV2rayUVersion()
// checkV2rayUVersion()
// check by sparkle
fetchAppcast(from: primaryFeedURL) { success in
// 线

View File

@@ -7,7 +7,6 @@
//
import Cocoa
import Alamofire
extension UserDefaults {
enum KEY: String {

View File

@@ -428,58 +428,3 @@ class V2rayLaunch: NSObject {
}
}
}
func checkV2rayUVersion() {
//
Alamofire.request("https://api.github.com/repos/yanue/V2rayU/releases/latest").responseJSON { response in
//to get status code
if let status = response.response?.statusCode {
if status != 200 {
NSLog("error with response status: ", status)
return
}
}
//to get JSON return value
if let result = response.result.value {
guard let JSON = result as? NSDictionary else {
NSLog("error: no tag_name")
return
}
// get tag_name (version)
guard let tag_name = JSON["tag_name"] else {
NSLog("error: no tag_name")
return
}
// get prerelease and draft
guard let prerelease = JSON["prerelease"], let draft = JSON["draft"] else {
// get
NSLog("error: get prerelease or draft")
return
}
// not pre release or draft
if prerelease as! Bool == true || draft as! Bool == true {
NSLog("this release is a prerelease or draft")
return
}
let newVer = (tag_name as! String)
// get old version
let oldVer = appVersion.replacingOccurrences(of: "v", with: "").versionToInt()
let curVer = newVer.replacingOccurrences(of: "v", with: "").versionToInt()
// compare with [Int]
DispatchQueue.main.async {
if oldVer.lexicographicallyPrecedes(curVer) {
menuController.newVersionItem.isHidden = false
menuController.newVersionItem.title = "has new version " + newVer
} else {
menuController.newVersionItem.isHidden = true
}
}
}
}
}

View File

@@ -7,7 +7,6 @@
//
import Cocoa
import Alamofire
import SwiftyJSON
import Yams