From c3529314d829ae7902a65715c8c8956e390bf9ec Mon Sep 17 00:00:00 2001 From: Svend Date: Wed, 26 Jun 2019 13:49:56 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E6=96=B0=E5=A2=9E=E4=B8=8A?= =?UTF-8?q?=E4=BC=A0=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - :sparkles: 新增上传历史记录功能 - : apple: 修改 macOS 版本要求,最低 10.12 --- uPic.xcodeproj/project.pbxproj | 6 ++ uPic/AppDelegate.swift | 5 +- uPic/Basic/Data+Extension.swift | 8 -- uPic/Basic/PasteboardType+Extension.swift | 25 +++++ uPic/Extensions/NotificationExt.swift | 122 ++++++++++++++++------ uPic/General/Managers/ConfigManager.swift | 8 +- uPic/Models/UpYun/UpYunUploader.swift | 4 +- uPic/StatusMenuController.swift | 17 ++- uPic/en.lproj/Localizable.strings | 3 + uPic/zh-Hans.lproj/Localizable.strings | 3 + 10 files changed, 150 insertions(+), 51 deletions(-) create mode 100644 uPic/Basic/PasteboardType+Extension.swift diff --git a/uPic.xcodeproj/project.pbxproj b/uPic.xcodeproj/project.pbxproj index bd2a316..f185ab3 100644 --- a/uPic.xcodeproj/project.pbxproj +++ b/uPic.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 1647474522B66E3400F9575D /* Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1647474422B66E3400F9575D /* Util.swift */; }; 164C3A0022B2AA6C003ADE39 /* Notifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 164C39FF22B2AA6C003ADE39 /* Notifier.swift */; }; 164C3A0222B2AB22003ADE39 /* ConfigNotifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 164C3A0122B2AB22003ADE39 /* ConfigNotifier.swift */; }; + 165D908622C333740096FF38 /* PasteboardType+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165D908522C333740096FF38 /* PasteboardType+Extension.swift */; }; 1660FCBA22C11C2300372950 /* TencentHostConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1660FCB922C11BA000372950 /* TencentHostConfig.swift */; }; 1660FCBB22C11C7200372950 /* TencentUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1660FCB722C11BA000372950 /* TencentUploader.swift */; }; 1660FCBC22C11C7500372950 /* TencentUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1660FCB822C11BA000372950 /* TencentUtil.swift */; }; @@ -107,6 +108,7 @@ 1647474422B66E3400F9575D /* Util.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Util.swift; sourceTree = ""; }; 164C39FF22B2AA6C003ADE39 /* Notifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notifier.swift; sourceTree = ""; }; 164C3A0122B2AB22003ADE39 /* ConfigNotifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigNotifier.swift; sourceTree = ""; }; + 165D908522C333740096FF38 /* PasteboardType+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PasteboardType+Extension.swift"; sourceTree = ""; }; 1660FCB622C11BA000372950 /* TencentRegion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentRegion.swift; sourceTree = ""; }; 1660FCB722C11BA000372950 /* TencentUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentUploader.swift; sourceTree = ""; }; 1660FCB822C11BA000372950 /* TencentUtil.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TencentUtil.swift; sourceTree = ""; }; @@ -212,6 +214,7 @@ 163632F222B2751D00805E7F /* BoolType.swift */, 164745EF22B65FE900F9575D /* String+Extension.swift */, 1647474222B66ACE00F9575D /* Data+Extension.swift */, + 165D908522C333740096FF38 /* PasteboardType+Extension.swift */, ); path = Basic; sourceTree = ""; @@ -582,6 +585,7 @@ 166B4A5322B9CB4D001288ED /* UpYunConfigView.swift in Sources */, 166B4A5722B9D118001288ED /* PreferencesNotifier.swift in Sources */, 1690E7EB22BF2D9400FC81F8 /* QiniuUploader.swift in Sources */, + 165D908622C333740096FF38 /* PasteboardType+Extension.swift in Sources */, 16A6DC5822AA375700813706 /* AppDelegate.swift in Sources */, 1602ED9722ADEFB200AA8638 /* BaseUploader.swift in Sources */, 163632F322B2751D00805E7F /* BoolType.swift in Sources */, @@ -816,6 +820,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; @@ -839,6 +844,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = com.svend.uPic; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = ""; diff --git a/uPic/AppDelegate.swift b/uPic/AppDelegate.swift index 2ed62a6..bca04f6 100644 --- a/uPic/AppDelegate.swift +++ b/uPic/AppDelegate.swift @@ -127,9 +127,9 @@ extension AppDelegate { if (pasteboardType == NSPasteboard.PasteboardType.png) { let imgData = NSPasteboard.general.data(forType: NSPasteboard.PasteboardType.png) self.uploadFile(nil, data: imgData!) - } else if (pasteboardType == NSPasteboard.PasteboardType.fileURL) { + } else if (pasteboardType == NSPasteboard.PasteboardType.backwardsCompatibleFileURL) { - let filePath = NSPasteboard.general.string(forType: NSPasteboard.PasteboardType.fileURL)! + let filePath = NSPasteboard.general.string(forType: NSPasteboard.PasteboardType.backwardsCompatibleFileURL)! let url = URL(string: filePath)! let fileManager = FileManager.default @@ -259,4 +259,3 @@ extension AppDelegate: NSWindowDelegate, NSDraggingDestination { } } - diff --git a/uPic/Basic/Data+Extension.swift b/uPic/Basic/Data+Extension.swift index 1510f59..6983a2c 100644 --- a/uPic/Basic/Data+Extension.swift +++ b/uPic/Basic/Data+Extension.swift @@ -47,12 +47,4 @@ extension Data { return String(data: self, encoding: .utf8)! } - init(from value: T) { - var value = value - self.init(buffer: UnsafeBufferPointer(start: &value, count: 1)) - } - - func to(type: T.Type) -> T { - return self.withUnsafeBytes { $0.pointee } - } } diff --git a/uPic/Basic/PasteboardType+Extension.swift b/uPic/Basic/PasteboardType+Extension.swift new file mode 100644 index 0000000..152464c --- /dev/null +++ b/uPic/Basic/PasteboardType+Extension.swift @@ -0,0 +1,25 @@ +// +// PasteboardType+Extension.swift +// uPic +// +// Created by Svend Jin on 2019/6/26. +// Copyright © 2019 Svend Jin. All rights reserved. +// + +import Cocoa + + +extension NSPasteboard.PasteboardType { + // MARK: 剪切板扩展,让 10.13 以前的版本也支持 FileUrl 类型 + + static let backwardsCompatibleFileURL: NSPasteboard.PasteboardType = { + + if #available(OSX 10.13, *) { + return NSPasteboard.PasteboardType.fileURL + } else { + return NSPasteboard.PasteboardType(kUTTypeFileURL as String) + } + + } () + +} diff --git a/uPic/Extensions/NotificationExt.swift b/uPic/Extensions/NotificationExt.swift index a38c5c7..3d6bec2 100644 --- a/uPic/Extensions/NotificationExt.swift +++ b/uPic/Extensions/NotificationExt.swift @@ -11,37 +11,12 @@ import UserNotifications class NotificationExt: NSObject { static let shared = 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" - content.userInfo = ["url": body] - - let request = UNNotificationRequest(identifier: "U_PIC_REQUEST", - content: content, - trigger: nil) - - - let category = UNNotificationCategory(identifier: "U_PIC_CATEGORY", - actions: [], - intentIdentifiers: [], - hiddenPreviewsBodyPlaceholder: "", - options: .customDismissAction) - - let notificationCenter = UNUserNotificationCenter.current() - notificationCenter.delegate = self - notificationCenter.setNotificationCategories([category]) - notificationCenter.add(request) { (error) in - if error != nil { - // Handle any errors. - } + if #available(OSX 10.14, *) { + self.sendNotificationByNew(title: title, subTitle: subTitle, body: body) + } else { + self.sendNotificationByOld(title: title, subTitle: subTitle, body: body) } } @@ -87,16 +62,52 @@ class NotificationExt: NSObject { } +@available(OSX 10.14, *) extension NotificationExt: UNUserNotificationCenterDelegate { + + + // MARK: Version Target >= 10.14 + + func sendNotificationByNew(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 = "NOTIFICATION_U_PIC" + content.userInfo = ["body": body] + + let request = UNNotificationRequest(identifier: "U_PIC_REQUEST", + content: content, + trigger: nil) + + + let category = UNNotificationCategory(identifier: "U_PIC_CATEGORY", + actions: [], + intentIdentifiers: [], + hiddenPreviewsBodyPlaceholder: "", + options: .customDismissAction) + + let notificationCenter = UNUserNotificationCenter.current() + notificationCenter.delegate = self + notificationCenter.setNotificationCategories([category]) + notificationCenter.add(request) { (error) in + if error != nil { + // Handle any errors. + } + } + + } // 用户点击弹窗后的回调 func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo - if let url = userInfo["url"] { + if let body = userInfo["body"] { NSPasteboard.general.clearContents() NSPasteboard.general.declareTypes([.string], owner: nil) - NSPasteboard.general.setString(url as! String, forType: .string) + NSPasteboard.general.setString(body as! String, forType: .string) } completionHandler() @@ -107,3 +118,50 @@ extension NotificationExt: UNUserNotificationCenterDelegate { completionHandler([.alert, .sound]) } } + +extension NotificationExt: NSUserNotificationCenterDelegate { + + // MARK: Version Target < 10.14 + + func sendNotificationByOld(title: String, subTitle: String, body: String) -> Void { + + let userNotification = NSUserNotification() + + userNotification.title = title + userNotification.subtitle = subTitle + userNotification.informativeText = body + + userNotification.identifier = "OLD_NOTIFICATION_U_PIC" + userNotification.userInfo = ["body": "body"] + + userNotification.soundName = NSUserNotificationDefaultSoundName + + NSUserNotificationCenter.default.delegate = self + NSUserNotificationCenter.default.removeAllDeliveredNotifications() + NSUserNotificationCenter.default.deliver(userNotification) + + } + + // 当 App 在前台时是否弹出通知 + func userNotificationCenter(_ center: NSUserNotificationCenter, shouldPresent notification: NSUserNotification) -> Bool { + return true + } + + // 推送消息后的回调 + func userNotificationCenter(_ center: NSUserNotificationCenter, didDeliver notification: NSUserNotification) { + print("\(Date(timeIntervalSinceNow: 0)) -> 消息已经推送") + } + + // 用户点击了通知后的回调 + func userNotificationCenter(_ center: NSUserNotificationCenter, didActivate notification: NSUserNotification) { + + if notification.activationType == .contentsClicked { + if let userInfo = notification.userInfo, let body = userInfo["body"] { + NSPasteboard.general.clearContents() + NSPasteboard.general.declareTypes([.string], owner: nil) + NSPasteboard.general.setString(body as! String, forType: .string) + } + } + } + +} diff --git a/uPic/General/Managers/ConfigManager.swift b/uPic/General/Managers/ConfigManager.swift index 1195918..d47a1ae 100644 --- a/uPic/General/Managers/ConfigManager.swift +++ b/uPic/General/Managers/ConfigManager.swift @@ -88,7 +88,7 @@ extension ConfigManager { public var historyLimit: Int { get { - let defaultLimit = 5 + let defaultLimit = 10 let limit = Defaults[.historyLimit] if (limit == nil || limit == 0) { return defaultLimit @@ -97,7 +97,7 @@ extension ConfigManager { } set { - Defaults[.historyLimit] = 5 + Defaults[.historyLimit] = newValue } } @@ -116,13 +116,13 @@ extension ConfigManager { list.append(url) if list.count > self.historyLimit { - list.removeFirst(self.historyLimit - list.count) + list.removeFirst(list.count - self.historyLimit) } self.setHistoryList(items: list) } func clearHistoryList() -> Void { - Defaults[.historyList] = [] + self.setHistoryList(items: []) } } diff --git a/uPic/Models/UpYun/UpYunUploader.swift b/uPic/Models/UpYun/UpYunUploader.swift index 8870f90..118494a 100644 --- a/uPic/Models/UpYun/UpYunUploader.swift +++ b/uPic/Models/UpYun/UpYunUploader.swift @@ -48,7 +48,7 @@ class UpYunUploader: BaseUploader { var saveKey = fileName if (config.folder != nil && config.folder!.count > 0) { - saveKey = "/\(config.folder!)/\(saveKey)" + saveKey = "\(config.folder!)\(saveKey)" } // MARK: 加密 policy @@ -87,7 +87,7 @@ class UpYunUploader: BaseUploader { let json = JSON(value) let code = json["code"] if 200 == code { - super.completed(url: domain + saveKey) + super.completed(url: "\(domain)/\(saveKey)") } else { super.faild(errorMsg: json["message"].string) } diff --git a/uPic/StatusMenuController.swift b/uPic/StatusMenuController.swift index ed03c3b..7fa6af3 100644 --- a/uPic/StatusMenuController.swift +++ b/uPic/StatusMenuController.swift @@ -108,18 +108,31 @@ class StatusMenuController: NSObject, NSMenuDelegate { historyMenuItem.submenu?.removeAllItems() for url in historyList { let menuItem = NSMenuItem(title: url, action: #selector(copyUrl(_:)), keyEquivalent: "") - menuItem.image = NSImage(contentsOf: URL(string: url)!) - menuItem.image?.size = NSSize(width: 40, height: 40) menuItem.target = self historyMenuItem.submenu?.addItem(menuItem) historyMenuItem.submenu?.delegate = self } + + if ((historyMenuItem.submenu?.items.count ?? 0) > 0) { + historyMenuItem.submenu?.addItem(NSMenuItem.separator()) + let menuItem = NSMenuItem(title: NSLocalizedString("status-menu.upload-history-clear", comment: "clear history"), action: #selector(clearHistory(_:)), keyEquivalent: "") + menuItem.target = self + historyMenuItem.submenu?.addItem(menuItem) + } else { + let menuItem = NSMenuItem(title: NSLocalizedString("status-menu.upload-history-empty", comment: "history is empty"), action: nil, keyEquivalent: "") + menuItem.target = self + historyMenuItem.submenu?.addItem(menuItem) + } } @objc func copyUrl(_ sender: NSMenuItem) { let outputUrl = (NSApplication.shared.delegate as? AppDelegate)?.copyUrl(url: sender.title) NotificationExt.sendCopySuccessfulNotification(body: outputUrl) } + + @objc func clearHistory(_ sender: NSMenuItem) { + ConfigManager.shared.clearHistoryList() + } func refreshDefaultHost() { let outputFormat = Defaults[.defaultHostId] diff --git a/uPic/en.lproj/Localizable.strings b/uPic/en.lproj/Localizable.strings index 5308d56..cb1797d 100644 --- a/uPic/en.lproj/Localizable.strings +++ b/uPic/en.lproj/Localizable.strings @@ -72,6 +72,9 @@ /* 菜单栏清空上传历史 */ "status-menu.upload-history-clear" = "Clear upload history"; +/* 菜单栏没有上传历史 */ +"status-menu.upload-history-empty" = "No upload history"; + /* 前往下载 */ "check-update-tip-get-gobutton.title" = "Download"; diff --git a/uPic/zh-Hans.lproj/Localizable.strings b/uPic/zh-Hans.lproj/Localizable.strings index 2f49b10..465f0a9 100644 --- a/uPic/zh-Hans.lproj/Localizable.strings +++ b/uPic/zh-Hans.lproj/Localizable.strings @@ -70,6 +70,9 @@ /* 菜单栏清空上传历史 */ "status-menu.upload-history-clear" = "清空上传历史"; +/* 菜单栏没有上传历史 */ +"status-menu.upload-history-empty" = "暂无上传历史"; + /* 前往下载 */ "check-update-tip-get-gobutton.title" = "前往下载";