From f6650872e06514cb150e2356db34fe06690febb7 Mon Sep 17 00:00:00 2001 From: Svend Date: Sun, 9 Jun 2019 11:21:18 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E6=96=B0=E5=A2=9E=E4=BA=86?= =?UTF-8?q?=E5=A4=9A=E7=A7=8D=E4=B8=8A=E4=BC=A0=E6=96=B9=E5=BC=8F=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E6=A3=80=E6=9F=A5=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 支持上传剪切板中的图片 \n-支持拖拽图片到应用状态栏直接上传 \n-支持截图上传 \n-支持检查更新 --- README.md | 44 +++- uPic.xcodeproj/project.pbxproj | 36 +++ .../xcdebugger/Breakpoints_v2.xcbkptlist | 6 +- uPic/AppDelegate.swift | 211 ++++++++++-------- .../Contents.json | 0 .../icon_32x32.png | Bin .../uploadIcon.imageset/Contents.json | 26 +++ .../uploadIcon.imageset/icon_16x16.png | Bin 0 -> 1703 bytes .../uploadIcon.imageset/icon_32x32.png | Bin 0 -> 2450 bytes .../uploadIcon.imageset/media-up.png | Bin 0 -> 1089 bytes uPic/Model/SmmsPic.swift | 60 +++++ uPic/Supporting Files/Info.plist | 2 +- uPic/Supporting Files/uPic.entitlements | 2 + uPic/Utils/Util.swift | 38 ++++ uPic/en.lproj/Localizable.strings | 43 +++- uPic/extension/NSDragingInfoExt.swift | 33 +++ uPic/extension/NotificationExt.swift | 49 ++++ uPic/extension/UPicUpdater.swift | 66 ++++++ uPic/zh-Hans.lproj/Localizable.strings | 41 +++- 19 files changed, 551 insertions(+), 106 deletions(-) rename uPic/Assets.xcassets/{StatusBarButtonImage.imageset => statusIcon.imageset}/Contents.json (100%) rename uPic/Assets.xcassets/{StatusBarButtonImage.imageset => statusIcon.imageset}/icon_32x32.png (100%) create mode 100644 uPic/Assets.xcassets/uploadIcon.imageset/Contents.json create mode 100644 uPic/Assets.xcassets/uploadIcon.imageset/icon_16x16.png create mode 100644 uPic/Assets.xcassets/uploadIcon.imageset/icon_32x32.png create mode 100644 uPic/Assets.xcassets/uploadIcon.imageset/media-up.png create mode 100644 uPic/Model/SmmsPic.swift create mode 100644 uPic/Utils/Util.swift create mode 100644 uPic/extension/NSDragingInfoExt.swift create mode 100644 uPic/extension/NotificationExt.swift create mode 100644 uPic/extension/UPicUpdater.swift diff --git a/README.md b/README.md index 87a5f73..3eab596 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,46 @@ -# uPic -超级简洁的基于 https://sm.ms 图床的第三方上传客户端 +## uPic +超级简洁的基于 https://sm.ms 图床的 Mac 版上传客户端 -![pic](https://i.loli.net/2019/06/08/5cfb8f61f2a3796018.png) -### TODO +![pic](https://i.loli.net/2019/06/09/5cfc720f0f7c339579.png) + +### Features * [x] 支持 URL、HTML Img、Markdown 输出格式 +* [x] 支持上传剪切板中复制的图片 +* [x] 支付拖拽图片到应用图标直接上传 +* [x] 支持截图上传、微信、QQ等第三方截图的也可以 + +* [x] 支持检查更新 + + + +### Preview + +* 选择文件上传 + + ![select](http://s2.svend.cc/projects/uPic/selectUpload.gif) + +* 复制图片上传 + + ![copy](http://s2.svend.cc/projects/uPic/copyUpload.gif) + +* 截图上传 + + ![截图](http://s2.svend.cc/projects/uPic/screenshotUpload.gif) + +* 拖拽上传 + + ![drag](http://s2.svend.cc/projects/uPic/dragUpload.gif) + + + +### Thanks + +本人完全是一名 Mac 开发新手,能开发出这个小项目离不开他们的帮助: -* [ ] 支持上传剪切板中复制的图片 +- [https://www.smslit.top/](https://www.smslit.top/) -* [ ] 支付拖拽图片到应用图标直接上传 \ No newline at end of file +- [https://www.cnswift.org/](https://www.cnswift.org/) \ No newline at end of file diff --git a/uPic.xcodeproj/project.pbxproj b/uPic.xcodeproj/project.pbxproj index 38cdf12..a57458f 100644 --- a/uPic.xcodeproj/project.pbxproj +++ b/uPic.xcodeproj/project.pbxproj @@ -9,6 +9,11 @@ /* Begin PBXBuildFile section */ 1623611B22AB935300E4025C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1623611D22AB935300E4025C /* InfoPlist.strings */; }; 1623612322AB951E00E4025C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1623612522AB951E00E4025C /* Localizable.strings */; }; + 1675516022ABE4A800D3EB6F /* SmmsPic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675515F22ABE4A800D3EB6F /* SmmsPic.swift */; }; + 1675516222ABF80300D3EB6F /* NSDragingInfoExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675516122ABF80300D3EB6F /* NSDragingInfoExt.swift */; }; + 1675516422AC102700D3EB6F /* NotificationExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675516322AC102700D3EB6F /* NotificationExt.swift */; }; + 1675516722ACAA0600D3EB6F /* UPicUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675516622ACAA0600D3EB6F /* UPicUpdater.swift */; }; + 1675516A22ACAA5900D3EB6F /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1675516922ACAA5900D3EB6F /* Util.swift */; }; 16A6DC5822AA375700813706 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16A6DC5722AA375700813706 /* AppDelegate.swift */; }; 16A6DC5A22AA375700813706 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16A6DC5922AA375700813706 /* ViewController.swift */; }; 16A6DC5C22AA375800813706 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 16A6DC5B22AA375800813706 /* Assets.xcassets */; }; @@ -25,6 +30,11 @@ 1623612422AB951E00E4025C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; 1623612622AB951F00E4025C /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; 1626E8C622AAB6B1006DCF0F /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 1675515F22ABE4A800D3EB6F /* SmmsPic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmmsPic.swift; sourceTree = ""; }; + 1675516122ABF80300D3EB6F /* NSDragingInfoExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSDragingInfoExt.swift; sourceTree = ""; }; + 1675516322AC102700D3EB6F /* NotificationExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationExt.swift; sourceTree = ""; }; + 1675516622ACAA0600D3EB6F /* UPicUpdater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UPicUpdater.swift; sourceTree = ""; }; + 1675516922ACAA5900D3EB6F /* Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = ""; }; 16A6DC5722AA375700813706 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 16A6DC5922AA375700813706 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 16A6DC5B22AA375800813706 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -59,6 +69,24 @@ path = Pods; sourceTree = ""; }; + 1675516522AC165600D3EB6F /* extension */ = { + isa = PBXGroup; + children = ( + 1675516122ABF80300D3EB6F /* NSDragingInfoExt.swift */, + 1675516322AC102700D3EB6F /* NotificationExt.swift */, + 1675516622ACAA0600D3EB6F /* UPicUpdater.swift */, + ); + path = extension; + sourceTree = ""; + }; + 1675516822ACAA4B00D3EB6F /* Utils */ = { + isa = PBXGroup; + children = ( + 1675516922ACAA5900D3EB6F /* Util.swift */, + ); + path = Utils; + sourceTree = ""; + }; 16A6DC4B22AA375700813706 = { isa = PBXGroup; children = ( @@ -73,6 +101,7 @@ 16A6DC5622AA375700813706 /* uPic */ = { isa = PBXGroup; children = ( + 1675516822ACAA4B00D3EB6F /* Utils */, 1623611D22AB935300E4025C /* InfoPlist.strings */, 16A6DC6922AA3B1800813706 /* Model */, 16A6DC6722AA3ABF00813706 /* View Controllers */, @@ -81,6 +110,7 @@ 16A6DC5D22AA375800813706 /* Main.storyboard */, 16A6DC6822AA3AD900813706 /* Supporting Files */, 1623612522AB951E00E4025C /* Localizable.strings */, + 1675516522AC165600D3EB6F /* extension */, ); path = uPic; sourceTree = ""; @@ -105,6 +135,7 @@ 16A6DC6922AA3B1800813706 /* Model */ = { isa = PBXGroup; children = ( + 1675515F22ABE4A800D3EB6F /* SmmsPic.swift */, ); path = Model; sourceTree = ""; @@ -241,8 +272,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1675516722ACAA0600D3EB6F /* UPicUpdater.swift in Sources */, 16A6DC5A22AA375700813706 /* ViewController.swift in Sources */, + 1675516422AC102700D3EB6F /* NotificationExt.swift in Sources */, 16A6DC5822AA375700813706 /* AppDelegate.swift in Sources */, + 1675516A22ACAA5900D3EB6F /* Util.swift in Sources */, + 1675516022ABE4A800D3EB6F /* SmmsPic.swift in Sources */, + 1675516222ABF80300D3EB6F /* NSDragingInfoExt.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/uPic.xcodeproj/xcuserdata/svend.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/uPic.xcodeproj/xcuserdata/svend.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index c745893..5ac8a7d 100644 --- a/uPic.xcodeproj/xcuserdata/svend.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/uPic.xcodeproj/xcuserdata/svend.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -10,11 +10,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "uPic/AppDelegate.swift" - timestampString = "581684737.237993" + timestampString = "581743054.161335" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "27" - endingLineNumber = "27" + startingLineNumber = "28" + endingLineNumber = "28" landmarkName = "applicationDidFinishLaunching(_:)" landmarkType = "7"> diff --git a/uPic/AppDelegate.swift b/uPic/AppDelegate.swift index a5ed581..729b8e8 100644 --- a/uPic/AppDelegate.swift +++ b/uPic/AppDelegate.swift @@ -9,7 +9,6 @@ import Cocoa import SwiftyJSON import Alamofire -import UserNotifications @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @@ -21,7 +20,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ aNotification: Notification) { // Insert code here to initialize your application if let button = statusItem.button { - button.image = NSImage(named:NSImage.Name("StatusBarButtonImage")) + button.image = NSImage(named:NSImage.Name("statusIcon")) + button.window?.delegate = self + button.window?.registerForDraggedTypes([NSPasteboard.PasteboardType("NSFilenamesPboardType")]) } constructStatusMenu() } @@ -39,14 +40,18 @@ extension AppDelegate { /* 构建状态栏菜单 */ func constructStatusMenu() { let menu = NSMenu() - let menuItem = NSMenuItem(title: NSLocalizedString("status-menu.select", comment: "选择文件"), action: #selector(AppDelegate.selectFile(_:)), keyEquivalent: "P") + let menuItem = NSMenuItem(title: NSLocalizedString("status-menu.select", comment: "选择文件"), action: #selector(AppDelegate.selectFile(_:)), keyEquivalent: "u") menuItem.image = NSImage(named:NSImage.Name("StatusBarButtonImage")) menu.addItem(menuItem) + menu.addItem(withTitle: NSLocalizedString("status-menu.pasteboard", comment: "上传剪切板中的图片"), action: #selector(uploadByPasteboard), keyEquivalent: "p") + menu.addItem(withTitle: NSLocalizedString("status-menu.screenshot", comment: "截图上传"), action: #selector(screenshotAndUpload), keyEquivalent: "c") + menu.addItem(NSMenuItem(title: NSLocalizedString("status-menu.clear", comment: "清除历史上传"), action: #selector(clearHistory), keyEquivalent: "")) menu.addItem(NSMenuItem.separator()) self.createOutputFormatMenu(menu: menu) menu.addItem(NSMenuItem(title: NSLocalizedString("status-menu.about", comment: "关于"), action: #selector(showAboutMe), keyEquivalent: "")) + menu.addItem(withTitle: NSLocalizedString("status-menu.check-update", comment: "检查更新"), action: #selector(checkUpdate), keyEquivalent: "u") menu.addItem(NSMenuItem(title: NSLocalizedString("status-menu.quit", comment: "退出"), action: #selector(NSApplication.terminate(_:)), keyEquivalent: "q")) statusItem.menu = menu @@ -86,60 +91,55 @@ extension AppDelegate { openPanel.canChooseDirectories = false openPanel.canCreateDirectories = false openPanel.canChooseFiles = true - openPanel.allowedFileTypes = ["png", "jpg", "jpeg", "svg", "gif"] + openPanel.allowedFileTypes = SmmsPic.imageTypes openPanel.begin { (result) -> Void in openPanel.close() if result.rawValue == NSApplication.ModalResponse.OK.rawValue { let selectedPath = openPanel.url!.path let url: URL = URL(fileURLWithPath: selectedPath) - - AF.upload(multipartFormData: { (multipartFormData:MultipartFormData) in - multipartFormData.append(url, withName: "smfile") - }, to: "https://sm.ms/api/upload", method: HTTPMethod.post).responseJSON { response in - switch response.result { - case .success(let value): - let json = JSON(value) - let code = json["code"] - if "error" == code { - let msg = json["msg"].stringValue - debugPrint(msg) - self.sendNotification(title: NSLocalizedString("upload.notification.error.title", comment: "上传失败通知标题"), subTitle: "", body: msg) - } else { - let data = json["data"] - self.onUploadSuccess(data: data) - } - case .failure(let error): - print(error) - } - } - + SmmsPic.share.upload(url, callback: self.uploadCallBack) } } } - @objc func showAboutMe() { - - let infoDic = Bundle.main.infoDictionary - let appNameStr = NSLocalizedString("app-name", comment: "APP 名称") - let versionStr = infoDic?["CFBundleShortVersionString"] as! String - let appInfo = appNameStr + " v" + versionStr + @objc func uploadByPasteboard() { + let pasteboardType = NSPasteboard.general.types?.first - let alert = NSAlert() - alert.alertStyle = NSAlert.Style.informational - alert.messageText = NSLocalizedString("about-window.title", comment: "关于窗口的标题:关于") - alert.informativeText = "\(appInfo) \(NSLocalizedString("about-window.message", comment: "关于窗口的消息:上传图片到 https://sm.ms")) \n\nAuthor: Svend Jin \nWebsite: https://svend.cc \nGithub: https://github.com/gee1k/uPic" - let button = NSButton(title: "Github", target: nil, action: #selector(openGithub)) - alert.accessoryView = button - alert.addButton(withTitle: NSLocalizedString("alert-info-button.titile", comment: "提示窗口确定按钮的标题:确定")) - alert.window.titlebarAppearsTransparent = true - alert.runModal() + if (pasteboardType == NSPasteboard.PasteboardType.png) { + let imgData = NSPasteboard.general.data(forType: NSPasteboard.PasteboardType.png) + SmmsPic.share.upload(imgData!, callback: self.uploadCallBack) + } else if (pasteboardType == NSPasteboard.PasteboardType.fileURL) { + + let filePath = NSPasteboard.general.string(forType: NSPasteboard.PasteboardType.fileURL)! + let url = URL(string: filePath)! + + if (!SmmsPic.imageTypes.contains(url.pathExtension)) { + NotificationExt.share.sendNotification(title: NSLocalizedString("upload.notification.error.title", comment: "上传失败"), subTitle: "", body: NSLocalizedString("copied-file-format-is-not-supported", comment: "复制的文件格式不支持")) + return + } + + let fileManager = FileManager.default + if (!url.isFileURL || !fileManager.fileExists(atPath: url.path)) { + debugPrint("复制的文件不存在或已被删除!") + NotificationExt.share.sendNotification(title: NSLocalizedString("upload.notification.error.title", comment: "上传失败"), subTitle: "", body: NSLocalizedString("copied-file-does-not-exist", comment: "复制的文件不存在或已被删除")) + return + } + SmmsPic.share.upload(url, callback: self.uploadCallBack) + } else { + NotificationExt.share.sendNotification(title: NSLocalizedString("upload.notification.error.title", comment: "上传失败"), subTitle: "", body: NSLocalizedString("copied-file-format-is-not-supported", comment: "复制的文件格式不支持")) + } } - @objc func openGithub() { - if let url = URL(string: "https://github.com/gee1k/uPic"), NSWorkspace.shared.open(url) { - print("default browser was successfully opened") - } + @objc func screenshotAndUpload() { + + let task = Process() + task.launchPath = "/usr/sbin/screencapture" + task.arguments = ["-i", "-c"] + task.launch() + task.waitUntilExit() + + self.uploadByPasteboard() } @objc func changeOutputFormat(_ sender: NSMenuItem!) { @@ -152,22 +152,43 @@ extension AppDelegate { } } - self.setOutputFomart(format: sender.tag) } @objc func clearHistory() { - AF.request("https://sm.ms/api/clear").validate().responseJSON { response in - switch response.result { - case .success(let value): - let json = JSON(value) - let code = json["code"] - let msg = json["msg"].stringValue - let title = "error" == code ? NSLocalizedString("clear.notification.error.title", comment: "清除历史上传失败通知标题") : NSLocalizedString("clear.notification.success.title", comment: "清除历史上传失败通知标题") - self.sendNotification(title: title, subTitle: "", body: msg) - case .failure(let error): - print(error) - } + SmmsPic.share.clearHistory(callback: {(data:JSON) -> Void in + let code = data["code"] + let msg = data["msg"].stringValue + let title = "error" == code ? NSLocalizedString("clear.notification.error.title", comment: "清除历史上传失败通知标题") : NSLocalizedString("clear.notification.success.title", comment: "清除历史上传失败通知标题") + NotificationExt.share.sendNotification(title: title, subTitle: "", body: msg) + }) + } + + + @objc func showAboutMe() { + alertInfo(withText: NSLocalizedString("about-window.title", comment: "关于窗口的标题:关于"), withMessage: "\(getAppInfo()) \(NSLocalizedString("about-window.message", comment: "关于窗口的消息:上传图片到 https://sm.ms")) \n\nAuthor: Svend Jin \nWebsite: https://svend.cc \nGithub: https://github.com/gee1k/uPic \n", oKButtonTitle: "Github", cancelButtonTitle: NSLocalizedString("alert-info-button.titile", comment: "提示窗口确定按钮的标题:确定"), okHandler: openGithub) + } + + @objc func checkUpdate() { + UPicUpdater.share.check(){} + } + + + @objc func openGithub() { + if let url = URL(string: "https://github.com/gee1k/uPic"), NSWorkspace.shared.open(url) { + print("default browser was successfully opened") + } + } + + func uploadCallBack(data: JSON) { + let code = data["code"] + if "error" == code { + let msg = data["msg"].stringValue + debugPrint(msg) + NotificationExt.share.sendNotification(title: NSLocalizedString("upload.notification.error.title", comment: "上传失败通知标题"), subTitle: "", body: msg) + } else { + let data = data["data"] + self.onUploadSuccess(data: data) } } @@ -195,11 +216,51 @@ extension AppDelegate { NSPasteboard.general.declareTypes([.string], owner: nil) NSPasteboard.general.setString(url, forType: .string) - self.sendNotification(title: NSLocalizedString("upload.notification.success.title", comment: "上传成功通知标题"), subTitle: NSLocalizedString("upload.notification.success.subtitle", comment: "上传成功通知副标题"), body: url) + NotificationExt.share.sendNotification(title: NSLocalizedString("upload.notification.success.title", comment: "上传成功通知标题"), subTitle: NSLocalizedString("upload.notification.success.subtitle", comment: "上传成功通知副标题"), body: url) } } +extension AppDelegate: NSWindowDelegate, NSDraggingDestination { + + func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation { + if sender.isImageFile { + if let button = statusItem.button { + button.image = NSImage(named: "uploadIcon") + } + return .copy + } + return .generic + } + + func performDragOperation(_ sender: NSDraggingInfo) -> Bool { + let uploadCallBack = self.uploadCallBack + if sender.isImageFile { + let imgurl = sender.draggedFileURL!.absoluteURL + let imgData = NSData(contentsOf: imgurl!) + SmmsPic.share.upload(imgData! as Data, callback: uploadCallBack) + return true + } + return false + } + + func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool { + return true + } + + func draggingExited(_ sender: NSDraggingInfo?) { + if let button = statusItem.button { + button.image = NSImage(named: "statusIcon") + } + } + + func draggingEnded(_ sender: NSDraggingInfo) { + if let button = statusItem.button { + button.image = NSImage(named: "statusIcon") + } + } +} + extension AppDelegate { @@ -227,39 +288,3 @@ extension AppDelegate { return UserDefaults.standard.integer(forKey: "output-format") } } - -extension AppDelegate: UNUserNotificationCenterDelegate { - - // MARK: 本地通知扩展 - - func sendNotification(title: String, subTitle: String, body: String) -> Void { - let content = UNMutableNotificationContent() - content.title = title - content.subtitle = subTitle - content.body = body - - content.sound = UNNotificationSound.default - content.categoryIdentifier = "U_PIC" - - - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false) - let request = UNNotificationRequest(identifier: "U_PIC_REQUEST", - content: content, - trigger: trigger) - - // Schedule the request with the system. - let notificationCenter = UNUserNotificationCenter.current() - notificationCenter.delegate = self - notificationCenter.add(request) { (error) in - if error != nil { - // Handle any errors. - } - } - - } - - // 配置通知发起时的行为 alert -> 显示弹窗, sound -> 播放提示音 - func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { - completionHandler([.alert, .sound]) - } -} diff --git a/uPic/Assets.xcassets/StatusBarButtonImage.imageset/Contents.json b/uPic/Assets.xcassets/statusIcon.imageset/Contents.json similarity index 100% rename from uPic/Assets.xcassets/StatusBarButtonImage.imageset/Contents.json rename to uPic/Assets.xcassets/statusIcon.imageset/Contents.json diff --git a/uPic/Assets.xcassets/StatusBarButtonImage.imageset/icon_32x32.png b/uPic/Assets.xcassets/statusIcon.imageset/icon_32x32.png similarity index 100% rename from uPic/Assets.xcassets/StatusBarButtonImage.imageset/icon_32x32.png rename to uPic/Assets.xcassets/statusIcon.imageset/icon_32x32.png diff --git a/uPic/Assets.xcassets/uploadIcon.imageset/Contents.json b/uPic/Assets.xcassets/uploadIcon.imageset/Contents.json new file mode 100644 index 0000000..824ae92 --- /dev/null +++ b/uPic/Assets.xcassets/uploadIcon.imageset/Contents.json @@ -0,0 +1,26 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_16x16.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icon_32x32.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "media-up.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/uPic/Assets.xcassets/uploadIcon.imageset/icon_16x16.png b/uPic/Assets.xcassets/uploadIcon.imageset/icon_16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..145e1d2304591b32e61e0bb66470e0fd2b1e2d7c GIT binary patch literal 1703 zcmV;Y23YxtP)Hg1+lHrgWSWcKdPn90sKGrRqvPeo9CG3uKX#J{(IASm?@+di}}l?o-=)F3E6 zwD^Ni=!>T7nL9I?X}YoAW$t|Qo$sD|?zw001?ah|SeB6#0T!CBEf+H4bBB+JJu8re zhoBb*p;u8ID_yBf0ya+zcePvJL&AGs+11_tpRKn>9TgyPA7ZoSs0)aX0r00)%XR^J z`jH<$>RKN5V(7OqK*TS4xZz{h!*f1C3ECFkK$#7nA@pGN!$;%jYv zwjAKwmYb0gKL(K8-kPtb5${A?tlI~wzMrJ6wTdBr=Y%%%EaEMQ&o}4FQ^DA)s*}Z> z!FI&AHCpoWI|RUqx?7s@$8!5^Q=anY%X@i5{QA6kNcMelpE>R6eCYFpmMsVT zrI(b06~u#xf1yS}_UGdMvD``!0~u->P=lA4?YN`hilQ z|3tHka)7T{2CGqwjZfMwx$5irQN_*|e4l)UHmiYuz74Yp1t^#>hrJ3-SOXDcC_o0^ z7T9R1gAN8V6s;5)ieI5-7aQlmJn}lUna#nz!j%5V$X|o`xX!dHWQRV27P1=rj;t2b zW$~+pTw@bIek?ZvKPDL<64`^#UNTAck#RBsB6*5DP4<%UA_FqU$I>2EH_cM;u)Q~SI+rg`Rn{L z_AC5qq~L$#SMj%U$6Cz0vP{G5Y*=%5RT^yu;}-DInZ=349rJPVM6C3K^oO)8y(fJr{l>k`ead~!ea?NsT>_Ci%bnxC;Vy6= zb6>{xYV#Ue-+LB$7`JEXmTRm^AtP)R9u{)KHsMiWGV&)32xCG~*nyU<>-!d;FP=Re z4r3qYr~6#KE>;1F`>_J_P5xC?ROxV(DIHdCO*p$HRQI@7^PwV@Pvuf+ z5K}u-6REM(K@W$srgorh0{i?O)v0c>QtHxU-hBdD(>iYJ4b2sIOVX2K8m~4gmYVA5 zh^QEb$V`rCQ-|7ZS{nuL-t>?3n=-o(6I(7vocj#GzCZEo`!3>+v;dYIfPu#&ZWzzX z2i^rZ^Mu;6+rb@?NPG+6)c5T6zxpzGe*M(x+{AON=PiJ>H#?ob-|uwRK0yDg0B4PV z0id6JRRdfL?*IS-Nl8ROR5%gElD|(BQ4q&x=I!1B2LwD1e;~PNrG+LC3u81nAza)D zotKa!8e&1E7WyaHs)g1XVsh5T!VM^DMFqxC7`4zdYP8^hXt-lX{B@4R0C|7iHPdf)fGMx2?_e9EcL1VIq)#G0Lg`FydHDSaIPzuSD6NZVL$;P9(T zMg%2p(avTaMvv6F}(%9cnhFIc1d98Vxt^;LyRL3y836&-+n;pJaE%U;Fy{ zOuDUW$t76m@6W{9Y z;L!7@<#~;b6iQdM*3pISZW}jE0C9+GoA2{yCwfd|vP2}2iB_D@VWxP{QcZ#1JUEWy zN+hv2JX$JxPUdkC+`Tzmn7k}@-$L?@(K<{g6N=%*+{0Ui!o)zt&N2Hsv5GhwPF=hP zb_wAgfK|_aBy`b~XJ_xNwz}v%GIBBF`&Ux+WF<|=Sp-TO+Z>CzK|}xm literal 0 HcmV?d00001 diff --git a/uPic/Assets.xcassets/uploadIcon.imageset/icon_32x32.png b/uPic/Assets.xcassets/uploadIcon.imageset/icon_32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..bc0c11067d6bd378b46af7b60ffff4ce3105092c GIT binary patch literal 2450 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 z literal 0 HcmV?d00001 diff --git a/uPic/Model/SmmsPic.swift b/uPic/Model/SmmsPic.swift new file mode 100644 index 0000000..6a2afc2 --- /dev/null +++ b/uPic/Model/SmmsPic.swift @@ -0,0 +1,60 @@ +// +// SmmsPic.swift +// uPic +// +// Created by Svend Jin on 2019/6/8. +// Copyright © 2019 Svend Jin. All rights reserved. +// + +import Cocoa +import SwiftyJSON +import Alamofire + +class SmmsPic { + static let share = SmmsPic() + + static let imageTypes = ["png", "jpg", "tiff", "jpeg", "gif"] + + enum PicUrl: String { + case upload = "https://sm.ms/api/upload" + case clear = "https://sm.ms/api/clear" + } + + private func _upload(_ multipartFormData: @escaping ((MultipartFormData) -> Void), callback: @escaping ((JSON) -> Void)) { + NotificationExt.share.sendNotification(title: NSLocalizedString("upload.notification.start.title", comment: "开始上传通知标题"), subTitle: NSLocalizedString("upload.notification.start.subtitle", comment: "开始上传通知副标题"), body: "") + AF.upload(multipartFormData: multipartFormData, to: PicUrl.upload.rawValue, method: HTTPMethod.post).responseJSON { response in + switch response.result { + case .success(let value): + let json = JSON(value) + callback(json) + case .failure(let error): + print(error) + } + } + } + + func upload(_ filePath: URL, callback: @escaping ((JSON) -> Void)) { + self._upload({ (multipartFormData:MultipartFormData) in + multipartFormData.append(filePath, withName: "smfile") + }, callback: callback) + } + + func upload(_ imgData: Data, callback: @escaping ((JSON) -> Void)) { + self._upload({ (multipartFormData:MultipartFormData) in + multipartFormData.append(imgData, withName: "smfile", fileName: "smfile.png", + mimeType: "image/png") + }, callback: callback) + } + + func clearHistory(callback: @escaping ((JSON) -> Void)) { + AF.request(PicUrl.clear.rawValue).validate().responseJSON { response in + switch response.result { + case .success(let value): + let json = JSON(value) + callback(json) + case .failure(let error): + print(error) + } + } + } +} diff --git a/uPic/Supporting Files/Info.plist b/uPic/Supporting Files/Info.plist index 3c2763b..05ba43b 100644 --- a/uPic/Supporting Files/Info.plist +++ b/uPic/Supporting Files/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.1 + 0.2 CFBundleVersion 1 LSApplicationCategoryType diff --git a/uPic/Supporting Files/uPic.entitlements b/uPic/Supporting Files/uPic.entitlements index 40b639e..2b8b733 100644 --- a/uPic/Supporting Files/uPic.entitlements +++ b/uPic/Supporting Files/uPic.entitlements @@ -10,5 +10,7 @@ com.apple.security.network.server + com.apple.security.temporary-exception.mach-register.global-name + com.apple.screencapture.interactive diff --git a/uPic/Utils/Util.swift b/uPic/Utils/Util.swift new file mode 100644 index 0000000..5364f25 --- /dev/null +++ b/uPic/Utils/Util.swift @@ -0,0 +1,38 @@ +// +// Util.swift +// uPic +// +// Created by Svend Jin on 2019/6/9. +// Copyright © 2019 Svend Jin. All rights reserved. +// + +import Cocoa + +func getAppInfo() -> String { + let infoDic = Bundle.main.infoDictionary + let appNameStr = NSLocalizedString("app-name", comment: "APP 名称") + let versionStr = infoDic?["CFBundleShortVersionString"] as! String + return appNameStr + " v" + versionStr +} + +func alertInfo(withText: String, withMessage: String) { + let alert = NSAlert() + alert.messageText = withText + alert.informativeText = withMessage + alert.addButton(withTitle: NSLocalizedString("alert-info-button.titile", comment: "提示窗口确定按钮的标题:确定")) + alert.window.titlebarAppearsTransparent = true + alert.runModal() +} + +func alertInfo(withText messageText: String, withMessage message: String, oKButtonTitle: String, cancelButtonTitle: String, okHandler:@escaping (()-> Void)) { + let alert = NSAlert() + alert.alertStyle = NSAlert.Style.informational + alert.messageText = messageText + alert.informativeText = message + alert.addButton(withTitle: oKButtonTitle) + alert.addButton(withTitle: cancelButtonTitle) + alert.window.titlebarAppearsTransparent = true + if alert.runModal() == .alertFirstButtonReturn { + okHandler() + } +} diff --git a/uPic/en.lproj/Localizable.strings b/uPic/en.lproj/Localizable.strings index acf6a97..9a5f278 100644 --- a/uPic/en.lproj/Localizable.strings +++ b/uPic/en.lproj/Localizable.strings @@ -20,13 +20,25 @@ "about-window.title" = "About"; /* 上传成功通知标题 */ -"upload.notification.success.title" = "uploaded successfully"; +"upload.notification.success.title" = "Uploaded successfully"; /* 上传成功通知副标题 */ "upload.notification.success.subtitle" = "URL has been copied to the clipboard, paste and use it!"; /* 上传失败通知标题 */ -"upload.notification.error.title" = "uploaded fail"; +"upload.notification.error.title" = "Uploaded fail"; + +/* 开始上传标题 */ +"upload.notification.start.title" = "Start upload"; + +/* 开始上传副标题 */ +"upload.notification.start.subtitle" = "The picture is being uploaded, please wait!"; + +/* 复制的文件不存在 */ +"copied-file-does-not-exist" = "The copied file does not exist or has been deleted!"; + +/* 所复制的文件格式不支持 */ +"copied-file-format-is-not-supported" = "The copied file format is not supported!"; /* 清除历史上传成功通知标题 */ "clear.notification.success.title" = "clear history successfully"; @@ -37,6 +49,12 @@ /* 状态栏菜单选择文件 */ "status-menu.select" = "Select File"; +/* 状态栏菜单屏幕截图 */ +"status-menu.screenshot" = "Screenshot And Upload"; + +/* 状态栏菜单上传剪切板中的图片 */ +"status-menu.pasteboard" = "Upload Image From Pasteboard"; + /* 状态栏菜单清空历史上传 */ "status-menu.clear" = "Clear History"; @@ -48,3 +66,24 @@ /* 状态栏菜单退出 */ "status-menu.quit" = "Quit"; + +/* 菜单栏检查更新按钮标题:检查更新 */ +"status-menu.check-update" = "Check for updates"; + +/* 前往下载 */ +"check-update-tip-get-gobutton.title" = "Download"; + +/* 忽略 */ +"check-update-tip-get-ignorebutton.title" = "Ignore"; + +/* 发现新版本 */ +"check-update-tip-get.message" = "Found new version!"; + +/* 网络异常! */ +"check-update-tip-network.message" = "Connection Invalid!"; + +/* 没有更新! */ +"check-update-tip-none.message" = "No updates!"; + +/* 检查更新 */ +"check-update-tip.title" = "Check for updates"; diff --git a/uPic/extension/NSDragingInfoExt.swift b/uPic/extension/NSDragingInfoExt.swift new file mode 100644 index 0000000..350ddff --- /dev/null +++ b/uPic/extension/NSDragingInfoExt.swift @@ -0,0 +1,33 @@ +// +// NSDragingInfoExt.swift +// uPic +// +// Created by Svend Jin on 2019/6/8. +// Copyright © 2019 Svend Jin. All rights reserved. +// + +import Cocoa + +extension NSDraggingInfo { + + var imageFileExtensions: [String] { + get { + return SmmsPic.imageTypes + } + } + + var draggedFileURL: NSURL? { + let filenames = draggingPasteboard.propertyList(forType: NSPasteboard.PasteboardType("NSFilenamesPboardType")) as? [String] + let path = filenames?.first + return path.map(NSURL.init) + } + + var isImageFile: Bool { + get { + guard let fileExtension = draggedFileURL?.pathExtension?.lowercased() else { + return false + } + return imageFileExtensions.contains(fileExtension) + } + } +} diff --git a/uPic/extension/NotificationExt.swift b/uPic/extension/NotificationExt.swift new file mode 100644 index 0000000..d4a55eb --- /dev/null +++ b/uPic/extension/NotificationExt.swift @@ -0,0 +1,49 @@ +// +// NotificationExt.swift +// uPic +// +// Created by Svend Jin on 2019/6/8. +// Copyright © 2019 Svend Jin. All rights reserved. +// + +import Cocoa +import UserNotifications + +class NotificationExt: NSObject, UNUserNotificationCenterDelegate { + static let share = NotificationExt() + + // MARK: 本地通知扩展 + + func sendNotification(title: String, subTitle: String, body: String) -> Void { + let content = UNMutableNotificationContent() + content.title = title + content.subtitle = subTitle + content.body = body + + content.sound = UNNotificationSound.default + content.categoryIdentifier = "U_PIC" + + +// let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0, repeats: false) + let request = UNNotificationRequest(identifier: "U_PIC_REQUEST", + content: content, + trigger: nil) + + // Schedule the request with the system. + let notificationCenter = UNUserNotificationCenter.current() + notificationCenter.delegate = self + notificationCenter.add(request) { (error) in + if error != nil { + // Handle any errors. + } + } + + } + + // 配置通知发起时的行为 alert -> 显示弹窗, sound -> 播放提示音 + func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { + completionHandler([.alert, .sound]) + } + +} + diff --git a/uPic/extension/UPicUpdater.swift b/uPic/extension/UPicUpdater.swift new file mode 100644 index 0000000..7c0d30b --- /dev/null +++ b/uPic/extension/UPicUpdater.swift @@ -0,0 +1,66 @@ +// +// UPicUpdater.swift +// uPic +// +// Created by Svend Jin on 2019/6/9. +// Copyright © 2019 Svend Jin. All rights reserved. +// + +import Cocoa + +class UPicUpdater { + private let url: URL? + private let user: String + + static let share = UPicUpdater(user: "gee1k") + + init(user: String) { + self.user = user + let proName = Bundle.main.infoDictionary!["CFBundleExecutable"]! + self.url = URL(string: "https://raw.githubusercontent.com/\(user)/\(proName)/master/\(proName)/Supporting%20Files/Info.plist") + } + + func check(callback: @escaping (()->Void)) { + let session = URLSession(configuration: .default) + let task = session.dataTask(with: self.url!) { (data, response, error) in + self.checkUpdateRequestSuccess(data: data, response: response, error: error, callback: callback) + } + task.resume() + } + + private func checkUpdateRequestSuccess(data:Data?, response:URLResponse?, error:Error?, callback: @escaping (()->Void)) -> Void { + DispatchQueue.main.async { + callback() + if let httpResponse = response as? HTTPURLResponse { + if httpResponse.statusCode != 200 { + alertInfo(withText: NSLocalizedString("check-update-tip.title", comment: "检查更新"), + withMessage: NSLocalizedString("check-update-tip-network.message", comment: "网络异常!")) + return + } + var propertyListForamt = PropertyListSerialization.PropertyListFormat.xml + do { + let infoPlist = try PropertyListSerialization.propertyList(from: data!, options: PropertyListSerialization.ReadOptions.mutableContainersAndLeaves, format: &propertyListForamt) as! [String: AnyObject] + let latestVersion = infoPlist["CFBundleShortVersionString"] as! String + let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String + if latestVersion == appVersion { + alertInfo(withText: NSLocalizedString("check-update-tip.title", comment: "检查更新"), + withMessage: NSLocalizedString("check-update-tip-none.message", comment: "没有更新!")) + return + } + + alertInfo(withText: NSLocalizedString("check-update-tip.title", comment: "检查更新"), + withMessage: NSLocalizedString("check-update-tip-get.message", comment: "发现新版本") + " v\(latestVersion)", + oKButtonTitle: NSLocalizedString("check-update-tip-get-gobutton.title", comment: "前往下载"), + cancelButtonTitle: NSLocalizedString("check-update-tip-get-ignorebutton.title", comment: "忽略")) { + if let url = URL(string: "https://github.com/\(self.user)/\(Bundle.main.infoDictionary!["CFBundleExecutable"]!)/releases/tag/v" + latestVersion) { + NSWorkspace.shared.open(url) + } + } + } catch { + // :TODO 加日志 + print("Error reading plist: \(error), format: \(propertyListForamt)") + } + } + } + } +} diff --git a/uPic/zh-Hans.lproj/Localizable.strings b/uPic/zh-Hans.lproj/Localizable.strings index e62531f..ba8c334 100644 --- a/uPic/zh-Hans.lproj/Localizable.strings +++ b/uPic/zh-Hans.lproj/Localizable.strings @@ -25,7 +25,13 @@ "upload.notification.success.subtitle" = "URL 已复制到剪切板,快去粘贴使用吧!"; /* 上传失败通知标题 */ -"upload.notification.error.title" = "长传失败"; +"upload.notification.error.title" = "上传失败"; + +/* 开始上传标题 */ +"upload.notification.start.title" = "开始上传"; + +/* 开始上传副标题 */ +"upload.notification.start.subtitle" = "图片正在上传,请稍后!"; /* 清除历史上传成功通知标题 */ "clear.notification.success.title" = "清除历史上传成功"; @@ -33,9 +39,21 @@ /* 清除历史上传失败通知标题 */ "clear.notification.error.title" = "清除历史上传失败"; +/* 复制的文件不存在 */ +"copied-file-does-not-exist" = "复制的文件不存在或已被删除!"; + +/* 复制的文件格式不支持 */ +"copied-file-format-is-not-supported" = "复制的文件格式不支持!"; + /* 状态栏菜单选择文件 */ "status-menu.select" = "选择文件"; +/* 状态栏菜单屏幕截图 */ +"status-menu.screenshot" = "截图上传"; + +/* 状态栏菜单上传剪切板中的图片 */ +"status-menu.pasteboard" = "上传剪切板中的图片"; + /* 状态栏菜单清空历史上传 */ "status-menu.clear" = "清空历史上传"; @@ -47,3 +65,24 @@ /* 状态栏菜单退出 */ "status-menu.quit" = "退出"; + +/* 菜单栏检查更新按钮标题:检查更新 */ +"status-menu.check-update" = "检查更新"; + +/* 前往下载 */ +"check-update-tip-get-gobutton.title" = "前往下载"; + +/* 忽略 */ +"check-update-tip-get-ignorebutton.title" = "忽略"; + +/* 发现新版本 */ +"check-update-tip-get.message" = "发现新版本"; + +/* 网络异常! */ +"check-update-tip-network.message" = "网络异常!"; + +/* 没有更新! */ +"check-update-tip-none.message" = "没有更新!"; + +/* 检查更新 */ +"check-update-tip.title" = "检查更新";