From 00631f3b8164e842e88b02ec59c32e8db1acba8c Mon Sep 17 00:00:00 2001 From: Qiu Yuzhou Date: Wed, 11 Sep 2019 23:33:02 +0800 Subject: [PATCH] Show an import window instead of importing from pasteboard. --- ShadowsocksX-NG.xcodeproj/project.pbxproj | 18 ++++++ ShadowsocksX-NG/AppDelegate.swift | 27 ++++---- .../Base.lproj/ImportWindowController.xib | 64 +++++++++++++++++++ ShadowsocksX-NG/Base.lproj/MainMenu.xib | 6 +- ShadowsocksX-NG/ImportWindowController.swift | 57 +++++++++++++++++ ShadowsocksX-NG/ServerProfileManager.swift | 29 +++++++++ .../ImportWindowController.strings | 9 +++ .../zh-Hans.lproj/MainMenu.strings | 3 + 8 files changed, 198 insertions(+), 15 deletions(-) create mode 100644 ShadowsocksX-NG/Base.lproj/ImportWindowController.xib create mode 100644 ShadowsocksX-NG/ImportWindowController.swift create mode 100644 ShadowsocksX-NG/zh-Hans.lproj/ImportWindowController.strings diff --git a/ShadowsocksX-NG.xcodeproj/project.pbxproj b/ShadowsocksX-NG.xcodeproj/project.pbxproj index 669cc65..6d38170 100644 --- a/ShadowsocksX-NG.xcodeproj/project.pbxproj +++ b/ShadowsocksX-NG.xcodeproj/project.pbxproj @@ -54,6 +54,8 @@ 9B7297E7214D69C300FD24AA /* libmbedcrypto.2.12.0.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7297E5214D68F800FD24AA /* libmbedcrypto.2.12.0.dylib */; }; 9B7297EA214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B7297E8214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift */; }; 9B7297EC214DA88A00FD24AA /* ShareServerProfilesWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B7297EE214DA88A00FD24AA /* ShareServerProfilesWindowController.xib */; }; + 9B72FB62232782A300C6AAAE /* ImportWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B72FB60232782A300C6AAAE /* ImportWindowController.swift */; }; + 9B74B5E9232949B100DEA386 /* ImportWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9B74B5EB232949B100DEA386 /* ImportWindowController.xib */; }; 9B84DAED2163A72F00DFF068 /* Diagnose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B84DAEC2163A72F00DFF068 /* Diagnose.swift */; }; 9B86459D1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */; }; 9B938D991E864B38005F5636 /* menu_g_icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 9B938D931E864B38005F5636 /* menu_g_icon.png */; }; @@ -214,6 +216,9 @@ 9B7297E8214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareServerProfilesWindowController.swift; sourceTree = ""; }; 9B7297ED214DA88A00FD24AA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ShareServerProfilesWindowController.xib; sourceTree = ""; }; 9B7297F0214DA89000FD24AA /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ShareServerProfilesWindowController.strings"; sourceTree = ""; }; + 9B72FB60232782A300C6AAAE /* ImportWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportWindowController.swift; sourceTree = ""; }; + 9B74B5EF232949D400DEA386 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ImportWindowController.xib; sourceTree = ""; }; + 9B74B5F1232949E800DEA386 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/ImportWindowController.strings"; sourceTree = ""; }; 9B84DAEC2163A72F00DFF068 /* Diagnose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Diagnose.swift; sourceTree = ""; }; 9B86459C1E7C2CAD00A84029 /* ProxyInterfacesViewCtrl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxyInterfacesViewCtrl.swift; sourceTree = ""; }; 9B938D931E864B38005F5636 /* menu_g_icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = menu_g_icon.png; sourceTree = ""; }; @@ -433,6 +438,8 @@ 9B3546711E802B1200B510B4 /* ToastWindowController.xib */, 9B7297E8214D7C6B00FD24AA /* ShareServerProfilesWindowController.swift */, 9B7297EE214DA88A00FD24AA /* ShareServerProfilesWindowController.xib */, + 9B72FB60232782A300C6AAAE /* ImportWindowController.swift */, + 9B74B5EB232949B100DEA386 /* ImportWindowController.xib */, ); name = UI; sourceTree = ""; @@ -652,6 +659,7 @@ 9B3F7BFF1E82BF5B00C68B75 /* libev.4.dylib in Resources */, 1C82DBAA1FA96FB600B32551 /* install_simple_obfs.sh in Resources */, 9B938D9A1E864B38005F5636 /* menu_g_icon@2x.png in Resources */, + 9B74B5E9232949B100DEA386 /* ImportWindowController.xib in Resources */, 9BBECA07232404FB00C632DB /* terminal-logo.png in Resources */, 9B938D9E1E864B38005F5636 /* menu_p_icon@2x.png in Resources */, 9B9CBCAF1E263B1600FC61AA /* libpcre.1.dylib in Resources */, @@ -810,6 +818,7 @@ 9B3FFF141D0705810019A709 /* Notifications.swift in Sources */, 9BEEF0701D04DDB100FC52B3 /* ServerProfileManager.swift in Sources */, 9BEEF06E1D04DCE400FC52B3 /* ServerProfile.swift in Sources */, + 9B72FB62232782A300C6AAAE /* ImportWindowController.swift in Sources */, 9B3FFF0D1D05FEB30019A709 /* Utils.swift in Sources */, 9BEEF0751D04EF3E00FC52B3 /* PreferencesWindowController.swift in Sources */, 9B0BFFE91D0460A70040E62B /* AppDelegate.swift in Sources */, @@ -891,6 +900,15 @@ name = ShareServerProfilesWindowController.xib; sourceTree = ""; }; + 9B74B5EB232949B100DEA386 /* ImportWindowController.xib */ = { + isa = PBXVariantGroup; + children = ( + 9B74B5EF232949D400DEA386 /* Base */, + 9B74B5F1232949E800DEA386 /* zh-Hans */, + ); + name = ImportWindowController.xib; + sourceTree = ""; + }; 9BAFE2E41E83ED7F00F71CCE /* PreferencesWinController.xib */ = { isa = PBXVariantGroup; children = ( diff --git a/ShadowsocksX-NG/AppDelegate.swift b/ShadowsocksX-NG/AppDelegate.swift index efd03c2..cb1eb88 100755 --- a/ShadowsocksX-NG/AppDelegate.swift +++ b/ShadowsocksX-NG/AppDelegate.swift @@ -20,6 +20,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele var editUserRulesWinCtrl: UserRulesController! var allInOnePreferencesWinCtrl: PreferencesWinController! var toastWindowCtrl: ToastWindowController! + var importWinCtrl: ImportWindowController! @IBOutlet weak var window: NSWindow! @IBOutlet weak var statusMenu: NSMenu! @@ -266,6 +267,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele shareWinCtrl.window?.makeKeyAndOrderFront(nil) } + @IBAction func showImportWindow(_ sender: NSMenuItem) { + if importWinCtrl != nil { + importWinCtrl.close() + } + importWinCtrl = ImportWindowController(windowNibName: .init(rawValue: "ImportWindowController")) + importWinCtrl.showWindow(self) + NSApp.activate(ignoringOtherApps: true) + importWinCtrl.window?.makeKeyAndOrderFront(nil) + } + @IBAction func scanQRCodeFromScreen(_ sender: NSMenuItem) { ScanQRCodeOnScreen() } @@ -276,7 +287,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele if let text = pb.string(forType: NSPasteboard.PasteboardType.URL) { if let url = URL(string: text) { NotificationCenter.default.post( - name: Notification.Name(rawValue: "NOTIFY_FOUND_SS_URL"), object: nil + name: NOTIFY_FOUND_SS_URL, object: nil , userInfo: [ "urls": [url], "source": "pasteboard", @@ -293,7 +304,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele urls = urls.filter { $0.scheme == "ss" } NotificationCenter.default.post( - name: Notification.Name(rawValue: "NOTIFY_FOUND_SS_URL"), object: nil + name: NOTIFY_FOUND_SS_URL, object: nil , userInfo: [ "urls": urls, "source": "pasteboard", @@ -543,7 +554,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele if let urlString = event.paramDescriptor(forKeyword: AEKeyword(keyDirectObject))?.stringValue { if let url = URL(string: urlString) { NotificationCenter.default.post( - name: Notification.Name(rawValue: "NOTIFY_FOUND_SS_URL"), object: nil + name: NOTIFY_FOUND_SS_URL, object: nil , userInfo: [ "urls": [url], "source": "url", @@ -570,7 +581,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele let urls: [URL] = userInfo["urls"] as! [URL] let mgr = ServerProfileManager.instance - var addCount = 0 var subtitle: String = "" if userInfo["source"] as! String == "qrcode" { @@ -581,17 +591,10 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele subtitle = "By import from pasteboard".localized } - for url in urls { - if let profile = ServerProfile(url: url) { - mgr.profiles.append(profile) - addCount = addCount + 1 - } - } + let addCount = mgr.addServerProfileByURL(urls: urls) if addCount > 0 { sendNotify("Add \(addCount) Shadowsocks Server Profile".localized, subtitle, "") - mgr.save() - self.updateServersMenu() } else { sendNotify("", "", "Not found valid qrcode or url of shadowsocks profile".localized) } diff --git a/ShadowsocksX-NG/Base.lproj/ImportWindowController.xib b/ShadowsocksX-NG/Base.lproj/ImportWindowController.xib new file mode 100644 index 0000000..bd9f584 --- /dev/null +++ b/ShadowsocksX-NG/Base.lproj/ImportWindowController.xib @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ShadowsocksX-NG/Base.lproj/MainMenu.xib b/ShadowsocksX-NG/Base.lproj/MainMenu.xib index 60a4c72..0e2593c 100755 --- a/ShadowsocksX-NG/Base.lproj/MainMenu.xib +++ b/ShadowsocksX-NG/Base.lproj/MainMenu.xib @@ -80,10 +80,10 @@ - + - + @@ -98,7 +98,7 @@ - + diff --git a/ShadowsocksX-NG/ImportWindowController.swift b/ShadowsocksX-NG/ImportWindowController.swift new file mode 100644 index 0000000..99aa114 --- /dev/null +++ b/ShadowsocksX-NG/ImportWindowController.swift @@ -0,0 +1,57 @@ +// +// ImportWindowController.swift +// ShadowsocksX-NG +// +// Created by 邱宇舟 on 2019/9/10. +// Copyright © 2019 qiuyuzhou. All rights reserved. +// + +import Cocoa + +class ImportWindowController: NSWindowController { + @IBOutlet weak var inputBox: NSTextField! + + override func windowDidLoad() { + super.windowDidLoad() + + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. + + let pb = NSPasteboard.general + if #available(OSX 10.13, *) { + if let text = pb.string(forType: NSPasteboard.PasteboardType.URL) { + if let url = URL(string: text) { + if url.scheme == "ss" { + inputBox.stringValue = text + } + } + } + } + if let text = pb.string(forType: NSPasteboard.PasteboardType.string) { + let urls = ServerProfileManager.findURLSInText(text) + if urls.count > 0 { + inputBox.stringValue = text + } + } + } + + @IBAction func handleImport(_ sender: NSButton) { + let mgr = ServerProfileManager.instance + let urls = ServerProfileManager.findURLSInText(inputBox.stringValue) + let addCount = mgr.addServerProfileByURL(urls: urls) + + if addCount > 0 { + let alert = NSAlert.init() + alert.alertStyle = .informational; + alert.messageText = "Success to add \(addCount) server.".localized + alert.addButton(withTitle: "OK") + alert.runModal() + self.close() + } else { + let alert = NSAlert.init() + alert.alertStyle = .informational; + alert.messageText = "Not found valid shadowsocks server urls.".localized + alert.addButton(withTitle: "OK") + alert.runModal() + } + } +} diff --git a/ShadowsocksX-NG/ServerProfileManager.swift b/ShadowsocksX-NG/ServerProfileManager.swift index 12636ea..4fd64e4 100644 --- a/ShadowsocksX-NG/ServerProfileManager.swift +++ b/ShadowsocksX-NG/ServerProfileManager.swift @@ -62,4 +62,33 @@ class ServerProfileManager: NSObject { return nil } } + + func addServerProfileByURL(urls: [URL]) -> Int { + var addCount = 0 + + for url in urls { + if let profile = ServerProfile(url: url) { + profiles.append(profile) + addCount = addCount + 1 + } + } + + if addCount > 0 { + save() + NotificationCenter.default + .post(name: NOTIFY_SERVER_PROFILES_CHANGED, object: nil) + } + + return addCount + } + + static func findURLSInText(_ text: String) -> [URL] { + var urls = text.split(separator: "\n") + .map { String($0).trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) } + .map { URL(string: $0) } + .filter { $0 != nil } + .map { $0! } + urls = urls.filter { $0.scheme == "ss" } + return urls + } } diff --git a/ShadowsocksX-NG/zh-Hans.lproj/ImportWindowController.strings b/ShadowsocksX-NG/zh-Hans.lproj/ImportWindowController.strings new file mode 100644 index 0000000..fd6799d --- /dev/null +++ b/ShadowsocksX-NG/zh-Hans.lproj/ImportWindowController.strings @@ -0,0 +1,9 @@ + +/* Class = "NSButtonCell"; title = "Import"; ObjectID = "EW8-ld-aGr"; */ +"EW8-ld-aGr.title" = "导入"; + +/* Class = "NSWindow"; title = "Import Server URLs"; ObjectID = "F0z-JX-Cv5"; */ +"F0z-JX-Cv5.title" = "导入服务器URLs"; + +/* Class = "NSTextFieldCell"; placeholderString = "Copy your shadowsocks URLs to here"; ObjectID = "h31-8G-f2d"; */ +"h31-8G-f2d.placeholderString" = "复制shadowsocks URLs到这里"; diff --git a/ShadowsocksX-NG/zh-Hans.lproj/MainMenu.strings b/ShadowsocksX-NG/zh-Hans.lproj/MainMenu.strings index 30e4c5b..07ee484 100644 --- a/ShadowsocksX-NG/zh-Hans.lproj/MainMenu.strings +++ b/ShadowsocksX-NG/zh-Hans.lproj/MainMenu.strings @@ -112,3 +112,6 @@ /* Class = "NSMenuItem"; title = "Export Diagnosis..."; ObjectID = "eNh-vY-utd"; */ "eNh-vY-utd.title" = "导出诊断信息..."; + +/* Class = "NSMenuItem"; title = "Import Server URLs..."; ObjectID = "geG-dQ-OYl"; */ +"geG-dQ-OYl.title" = "导入服务器URLs...";