From 731b75febef888ee697e17cd008a702af5bf41fa Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Wed, 28 Dec 2016 12:21:30 +0900 Subject: [PATCH 01/13] :arrow_up: Update version --- Fuwari/Info.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Fuwari/Info.plist b/Fuwari/Info.plist index 3f49489..e0cbdb2 100644 --- a/Fuwari/Info.plist +++ b/Fuwari/Info.plist @@ -17,9 +17,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.3 + 0.4 CFBundleVersion - 0.3 + 0.4 Fabric APIKey From 9a592cfec79775fb65c76071be4d5747db329f41 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Wed, 28 Dec 2016 21:59:44 +0900 Subject: [PATCH 02/13] :arrow_up: Update build settings --- Fuwari.xcodeproj/project.pbxproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Fuwari.xcodeproj/project.pbxproj b/Fuwari.xcodeproj/project.pbxproj index 18b0618..b777f57 100644 --- a/Fuwari.xcodeproj/project.pbxproj +++ b/Fuwari.xcodeproj/project.pbxproj @@ -220,7 +220,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0810; - LastUpgradeCheck = 0810; + LastUpgradeCheck = 0820; ORGANIZATIONNAME = AppKnop; TargetAttributes = { BEC844F21DED859300A4A57A = { @@ -405,6 +405,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; @@ -455,6 +456,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_SUSPICIOUS_MOVES = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; From 770fbb8e45031d07ad697359a3518d27303b4b5d Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Wed, 28 Dec 2016 22:00:08 +0900 Subject: [PATCH 03/13] :arrow_up: Update build version --- Fuwari/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Fuwari/Info.plist b/Fuwari/Info.plist index e0cbdb2..048a929 100644 --- a/Fuwari/Info.plist +++ b/Fuwari/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString 0.4 CFBundleVersion - 0.4 + 0.40 Fabric APIKey From 175b667fe4c4ce36e7d144acb23082191c21fbf1 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Wed, 28 Dec 2016 22:00:26 +0900 Subject: [PATCH 04/13] :bug: Fixed app crash bug --- Fuwari/AppDelegate.swift | 1 + Fuwari/HotKeyManager.swift | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Fuwari/AppDelegate.swift b/Fuwari/AppDelegate.swift index d9e2af6..7b2eae6 100644 --- a/Fuwari/AppDelegate.swift +++ b/Fuwari/AppDelegate.swift @@ -27,6 +27,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { promptToAddLoginItems() } + HotKeyManager.shared.configure() MenuManager.shared.configure() } diff --git a/Fuwari/HotKeyManager.swift b/Fuwari/HotKeyManager.swift index 8e5dfac..0107658 100644 --- a/Fuwari/HotKeyManager.swift +++ b/Fuwari/HotKeyManager.swift @@ -27,9 +27,7 @@ final class HotKeyManager: NSObject { }() fileprivate(set) var captureHotKey: HotKey? - override init() { - super.init() - + func configure() { registerHotKey(keyCombo: captureKeyCombo) } } From 9f7f282e26fc6191ed36fd0d5943710477214675 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Sat, 28 Apr 2018 17:25:52 +0900 Subject: [PATCH 05/13] :arrow_up: Upgrade to Swift4 --- Fuwari.xcodeproj/project.pbxproj | 7 +++++-- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ Fuwari/AboutWindowController.swift | 2 +- Fuwari/AppDelegate.swift | 6 +++--- Fuwari/CaptureGuideView.swift | 12 +++++------ Fuwari/FloatWindow.swift | 14 ++++++------- Fuwari/FullScreenWindow.swift | 6 +++--- Fuwari/MenuManager.swift | 4 ++-- Fuwari/PreferencesWindowController.swift | 20 +++++++++---------- Fuwari/ViewController.swift | 12 +++++++---- 10 files changed, 53 insertions(+), 38 deletions(-) create mode 100644 Fuwari.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/Fuwari.xcodeproj/project.pbxproj b/Fuwari.xcodeproj/project.pbxproj index b777f57..d8b1e09 100644 --- a/Fuwari.xcodeproj/project.pbxproj +++ b/Fuwari.xcodeproj/project.pbxproj @@ -226,6 +226,7 @@ BEC844F21DED859300A4A57A = { CreatedOnToolsVersion = 8.1; DevelopmentTeam = QZJ74E9669; + LastSwiftMigration = 0930; ProvisioningStyle = Automatic; }; }; @@ -496,7 +497,8 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = com.appknop.Fuwari; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Debug; }; @@ -516,7 +518,8 @@ MACOSX_DEPLOYMENT_TARGET = 10.11; PRODUCT_BUNDLE_IDENTIFIER = com.appknop.Fuwari; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = On; + SWIFT_VERSION = 4.0; }; name = Release; }; diff --git a/Fuwari.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Fuwari.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Fuwari.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Fuwari/AboutWindowController.swift b/Fuwari/AboutWindowController.swift index 4f6b0a9..64f5e19 100644 --- a/Fuwari/AboutWindowController.swift +++ b/Fuwari/AboutWindowController.swift @@ -10,7 +10,7 @@ import Cocoa class AboutWindowController: NSWindowController { - static let shared = AboutWindowController(windowNibName: "AboutWindowController") + static let shared = AboutWindowController(windowNibName: NSNib.Name(rawValue: "AboutWindowController")) @IBOutlet private weak var versionTextField: NSTextField! { didSet { diff --git a/Fuwari/AppDelegate.swift b/Fuwari/AppDelegate.swift index 7b2eae6..fb57145 100644 --- a/Fuwari/AppDelegate.swift +++ b/Fuwari/AppDelegate.swift @@ -48,7 +48,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { @objc func capture() { NSApp.activate(ignoringOtherApps: true) NotificationCenter.default.post(name: NSNotification.Name(rawValue: Constants.Notification.capture), object: nil) - eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: [.mouseMoved, .leftMouseUp], handler: { + eventMonitor = NSEvent.addGlobalMonitorForEvents(matching: [NSEvent.EventTypeMask.mouseMoved, NSEvent.EventTypeMask.leftMouseUp], handler: { (event: NSEvent) in switch event.type { case .mouseMoved: @@ -78,12 +78,12 @@ class AppDelegate: NSObject, NSApplicationDelegate { NSApp.activate(ignoringOtherApps: true) // Launch on system startup - if alert.runModal() == NSAlertFirstButtonReturn { + if alert.runModal() == NSApplication.ModalResponse.alertFirstButtonReturn { defaults.set(true, forKey: Constants.UserDefaults.loginItem) toggleLoginItemState() } // Do not show this message again - if alert.suppressionButton?.state == NSOnState { + if alert.suppressionButton?.state == .on { defaults.set(true, forKey: Constants.UserDefaults.suppressAlertForLoginItem) } defaults.synchronize() diff --git a/Fuwari/CaptureGuideView.swift b/Fuwari/CaptureGuideView.swift index e116b54..bc5976e 100644 --- a/Fuwari/CaptureGuideView.swift +++ b/Fuwari/CaptureGuideView.swift @@ -55,27 +55,27 @@ class CaptureGuideView: NSView { if startPoint != .zero { NSColor(red: 0, green: 0, blue: 0, alpha: 0.25).set() guideWindowRect = NSRect(x: floor(fmin(startPoint.x, cursorPoint.x)), y: floor(fmin(startPoint.y, cursorPoint.y)), width: floor(fabs(cursorPoint.x - startPoint.x)), height: floor(fabs(cursorPoint.y - startPoint.y))) - NSRectFill(guideWindowRect) + guideWindowRect.fill() NSColor.white.set() - NSFrameRectWithWidth(guideWindowRect, cursorGuideWidth) + guideWindowRect.frame(withWidth: cursorGuideWidth) } } private func drawCursor() { NSColor.darkGray.set() let cursorRectWidth = NSRect(x: cursorPoint.x - cursorSize / 2, y: cursorPoint.y, width: cursorSize, height: 1) - NSRectFill(cursorRectWidth) + cursorRectWidth.fill() let cursorRectHeight = NSRect(x: cursorPoint.x, y: cursorPoint.y - cursorSize / 2, width: 1, height: cursorSize) - NSRectFill(cursorRectHeight) + cursorRectHeight.fill() NSColor(red: 0, green: 0, blue: 0, alpha: 0.25).set() let cursorCenter = NSRect(x: cursorPoint.x - cursorSize / 4 + cursorGuideWidth / 2, y: cursorPoint.y - cursorSize / 4 + cursorGuideWidth / 2, width: cursorSize / 2, height: cursorSize / 2) let path = NSBezierPath(ovalIn: cursorCenter) path.fill() - (Int(cursorPoint.x).description as NSString).draw(at: NSPoint(x: cursorPoint.x + cursorSize / 2, y: cursorPoint.y - cursorSize / 2), withAttributes: [NSFontAttributeName : cursorFont, NSShadowAttributeName : coordinateLabelShadow]) - (Int(frame.height - cursorPoint.y).description as NSString).draw(at: NSPoint(x: cursorPoint.x + cursorSize / 2, y: cursorPoint.y - cursorSize), withAttributes: [NSFontAttributeName : cursorFont, NSShadowAttributeName : coordinateLabelShadow]) + (Int(cursorPoint.x).description as NSString).draw(at: NSPoint(x: cursorPoint.x + cursorSize / 2, y: cursorPoint.y - cursorSize / 2), withAttributes: [.font : cursorFont, .shadow : coordinateLabelShadow]) + (Int(frame.height - cursorPoint.y).description as NSString).draw(at: NSPoint(x: cursorPoint.x + cursorSize / 2, y: cursorPoint.y - cursorSize), withAttributes: [.font : cursorFont, .shadow : coordinateLabelShadow]) } func reset() { diff --git a/Fuwari/FloatWindow.swift b/Fuwari/FloatWindow.swift index 3ad4358..ce7ac4b 100644 --- a/Fuwari/FloatWindow.swift +++ b/Fuwari/FloatWindow.swift @@ -16,10 +16,10 @@ class FloatWindow: NSWindow { var floatDelegate: FloatDelegate? - init(contentRect: NSRect, styleMask style: NSWindowStyleMask = .borderless, backing bufferingType: NSBackingStoreType = .buffered, defer flag: Bool = false, image: CGImage) { + init(contentRect: NSRect, styleMask style: NSWindow.StyleMask = .borderless, backing bufferingType: NSWindow.BackingStoreType = .buffered, defer flag: Bool = false, image: CGImage) { super.init(contentRect: contentRect, styleMask: style, backing: bufferingType, defer: flag) - level = Int(CGWindowLevelForKey(.floatingWindow)) + level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.floatingWindow))) isMovableByWindowBackground = true hasShadow = true contentView?.wantsLayer = true @@ -31,7 +31,7 @@ class FloatWindow: NSWindow { override func keyDown(with event: NSEvent) { super.keyDown(with: event) - if event.modifierFlags.rawValue & NSEventModifierFlags.command.rawValue != 0 { + if event.modifierFlags.rawValue & NSEvent.ModifierFlags.command.rawValue != 0 { switch event.keyCode { case UInt16(kVK_ANSI_S): let saveLabel = NSTextField(frame: NSRect(x: 10, y: 10, width: 80, height: 26)) @@ -64,8 +64,8 @@ class FloatWindow: NSWindow { let cgImage = image as! CGImage let size = CGSize(width: cgImage.width, height: cgImage.height) let nsImage = NSImage(cgImage: cgImage, size: size) - NSPasteboard.general().clearContents() - NSPasteboard.general().writeObjects([nsImage]) + NSPasteboard.general.clearContents() + NSPasteboard.general.writeObjects([nsImage]) } } default: @@ -90,8 +90,8 @@ class FloatWindow: NSWindow { alphaValue = isIn ? 0.0 : 1.0 makeKeyAndOrderFront(self) NSAnimationContext.beginGrouping() - NSAnimationContext.current().completionHandler = completion - NSAnimationContext.current().duration = 0.2 + NSAnimationContext.current.completionHandler = completion + NSAnimationContext.current.duration = 0.2 animator().alphaValue = isIn ? 1.0 : 0.0 NSAnimationContext.endGrouping() } diff --git a/Fuwari/FullScreenWindow.swift b/Fuwari/FullScreenWindow.swift index f4b4797..4238c15 100644 --- a/Fuwari/FullScreenWindow.swift +++ b/Fuwari/FullScreenWindow.swift @@ -19,10 +19,10 @@ class FullScreenWindow: NSWindow { }() private var mouseLocation: NSPoint { - return NSPoint(x: NSEvent.mouseLocation().x - frame.origin.x, y: NSEvent.mouseLocation().y - frame.origin.y) + return NSPoint(x: NSEvent.mouseLocation.x - frame.origin.x, y: NSEvent.mouseLocation.y - frame.origin.y) } - override init(contentRect: NSRect, styleMask style: NSWindowStyleMask, backing bufferingType: NSBackingStoreType, defer flag: Bool) { + override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask, backing bufferingType: NSWindow.BackingStoreType, defer flag: Bool) { super.init(contentRect: contentRect, styleMask: .borderless, backing: .buffered, defer: false) isReleasedWhenClosed = true @@ -32,7 +32,7 @@ class FullScreenWindow: NSWindow { hasShadow = false ignoresMouseEvents = false acceptsMouseMovedEvents = true - level = Int(CGWindowLevelForKey(.assistiveTechHighWindow)) + level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.assistiveTechHighWindow))) makeKeyAndOrderFront(self) contentView = captureGuideView diff --git a/Fuwari/MenuManager.swift b/Fuwari/MenuManager.swift index 95be665..1eae679 100644 --- a/Fuwari/MenuManager.swift +++ b/Fuwari/MenuManager.swift @@ -12,13 +12,13 @@ import Magnet class MenuManager: NSObject { static let shared = MenuManager() - let statusItem = NSStatusBar.system().statusItem(withLength: NSSquareStatusItemLength) + let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) private var captureItem = NSMenuItem() func configure() { if let button = statusItem.button { - button.image = NSImage(named: "MenuIcon") + button.image = NSImage(named: NSImage.Name(rawValue: "MenuIcon")) } captureItem = NSMenuItem(title: LocalizedString.Capture.value, action: #selector(AppDelegate.capture), keyEquivalent: HotKeyManager.shared.captureKeyCombo.characters.lowercased()) diff --git a/Fuwari/PreferencesWindowController.swift b/Fuwari/PreferencesWindowController.swift index a3acaaa..27f5d91 100644 --- a/Fuwari/PreferencesWindowController.swift +++ b/Fuwari/PreferencesWindowController.swift @@ -10,7 +10,7 @@ import Cocoa class PreferencesWindowController: NSWindowController { - static let shared = PreferencesWindowController(windowNibName: "PreferencesWindowController") + static let shared = PreferencesWindowController(windowNibName: NSNib.Name(rawValue: "PreferencesWindowController")) @IBOutlet fileprivate weak var toolBar: NSView! @IBOutlet fileprivate weak var generalImageView: NSImageView! @@ -24,9 +24,9 @@ class PreferencesWindowController: NSWindowController { @IBOutlet fileprivate weak var shortcutButton: NSButton! fileprivate let defaults = UserDefaults.standard - fileprivate let viewController = [NSViewController(nibName: "GeneralPreferenceViewController", bundle: nil)!, - UpdatePreferenceViewController(nibName: "UpdatePreferenceViewController", bundle: nil)!, - ShortcutsPreferenceViewController(nibName: "ShortcutsPreferenceViewController", bundle: nil)!] + fileprivate let viewController = [NSViewController(nibName: NSNib.Name(rawValue: "GeneralPreferenceViewController"), bundle: nil), + UpdatePreferenceViewController(nibName: NSNib.Name(rawValue: "UpdatePreferenceViewController"), bundle: nil), + ShortcutsPreferenceViewController(nibName: NSNib.Name(rawValue: "ShortcutsPreferenceViewController"), bundle: nil)] override func windowDidLoad() { super.windowDidLoad() @@ -64,9 +64,9 @@ extension PreferencesWindowController: NSWindowDelegate { // MARK: - Layout fileprivate extension PreferencesWindowController { private func resetImages() { - generalImageView.image = NSImage(named: Constants.ImageName.generalOff) - updatesImageView.image = NSImage(named: Constants.ImageName.updatesOff) - shortcutImageView.image = NSImage(named: Constants.ImageName.shortcutOff) + generalImageView.image = NSImage(named: NSImage.Name(rawValue: Constants.ImageName.generalOff)) + updatesImageView.image = NSImage(named: NSImage.Name(rawValue: Constants.ImageName.updatesOff)) + shortcutImageView.image = NSImage(named: NSImage.Name(rawValue: Constants.ImageName.shortcutOff)) generalTextField.textColor = .tabTitle updatesTextField.textColor = .tabTitle @@ -78,13 +78,13 @@ fileprivate extension PreferencesWindowController { switch index { case 0: - generalImageView.image = NSImage(named: Constants.ImageName.generalOn) + generalImageView.image = NSImage(named: NSImage.Name(rawValue: Constants.ImageName.generalOn)) generalTextField.textColor = .main case 1: - updatesImageView.image = NSImage(named: Constants.ImageName.updatesOn) + updatesImageView.image = NSImage(named: NSImage.Name(rawValue: Constants.ImageName.updatesOn)) updatesTextField.textColor = .main case 2: - shortcutImageView.image = NSImage(named: Constants.ImageName.shortcutOn) + shortcutImageView.image = NSImage(named: NSImage.Name(rawValue: Constants.ImageName.shortcutOn)) shortcutTextField.textColor = .main default: break } diff --git a/Fuwari/ViewController.swift b/Fuwari/ViewController.swift index 5c0cc6d..db5a0f8 100644 --- a/Fuwari/ViewController.swift +++ b/Fuwari/ViewController.swift @@ -16,7 +16,7 @@ class ViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() - NSScreen.screens()!.forEach { + NSScreen.screens.forEach { let fullScreenWindow = FullScreenWindow(contentRect: $0.frame, styleMask: .borderless, backing: .buffered, defer: false) fullScreenWindow.captureDelegate = self fullScreenWindows.append(fullScreenWindow) @@ -29,6 +29,10 @@ class ViewController: NSViewController { NotificationCenter.default.addObserver(self, selector: #selector(startCapture), name: Notification.Name(rawValue: Constants.Notification.capture), object: nil) } + deinit { + NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: Constants.Notification.capture), object: nil) + } + fileprivate func createFloatWindow(rect: NSRect, image: CGImage) { let floatWindow = FloatWindow(contentRect: rect, image: image) floatWindow.floatDelegate = self @@ -70,13 +74,13 @@ extension ViewController: FloatDelegate { savePanel.canCreateDirectories = true savePanel.showsTagField = false savePanel.nameFieldStringValue = "screenshot-\(formatter.string(from: Date())).png" - savePanel.level = Int(CGWindowLevelForKey(.modalPanelWindow)) + savePanel.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.modalPanelWindow))) savePanel.begin { (result) in - if result == NSFileHandlingPanelOKButton { + if result.rawValue == NSFileHandlingPanelOKButton { guard let url = savePanel.url else { return } let bitmapRep = NSBitmapImageRep(cgImage: image) - let data = bitmapRep.representation(using: .PNG, properties: [:]) + let data = bitmapRep.representation(using: .png, properties: [:]) do { try data?.write(to: url, options: .atomicWrite) } catch { From dc289b683191e184f5b2d445e19b551410c924ac Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Sat, 28 Apr 2018 17:26:20 +0900 Subject: [PATCH 06/13] :arrow_up: Update library --- Cartfile.resolved | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 4eea97a..5faa16a 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,4 +1,4 @@ -github "Clipy/LoginServiceKit" "v1.0.0" -github "Clipy/Magnet" "v2.0.0" -github "sparkle-project/Sparkle" "1.15.1" -github "Clipy/KeyHolder" "v2.0.0" +github "Clipy/KeyHolder" "v2.1.0" +github "Clipy/LoginServiceKit" "v1.2.0" +github "Clipy/Magnet" "v2.1.0" +github "sparkle-project/Sparkle" "1.19.0" From a235eedf2f6268e176929c5fdad0a9cf8eb8e6f5 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Sun, 29 Apr 2018 10:03:27 +0900 Subject: [PATCH 07/13] :heavy_plus_sign: Add various export format --- Fuwari/ViewController.swift | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Fuwari/ViewController.swift b/Fuwari/ViewController.swift index db5a0f8..ac15241 100644 --- a/Fuwari/ViewController.swift +++ b/Fuwari/ViewController.swift @@ -7,11 +7,12 @@ // import Cocoa +import Quartz class ViewController: NSViewController { - fileprivate var windowControllers = [NSWindowController]() - fileprivate var fullScreenWindows = [FullScreenWindow]() + private var windowControllers = [NSWindowController]() + private var fullScreenWindows = [FullScreenWindow]() override func viewDidLoad() { super.viewDidLoad() @@ -33,7 +34,7 @@ class ViewController: NSViewController { NotificationCenter.default.removeObserver(self, name: Notification.Name(rawValue: Constants.Notification.capture), object: nil) } - fileprivate func createFloatWindow(rect: NSRect, image: CGImage) { + private func createFloatWindow(rect: NSRect, image: CGImage) { let floatWindow = FloatWindow(contentRect: rect, image: image) floatWindow.floatDelegate = self let floatWindowController = NSWindowController(window: floatWindow) @@ -73,19 +74,17 @@ extension ViewController: FloatDelegate { let savePanel = NSSavePanel() savePanel.canCreateDirectories = true savePanel.showsTagField = false - savePanel.nameFieldStringValue = "screenshot-\(formatter.string(from: Date())).png" + savePanel.nameFieldStringValue = "screenshot-\(formatter.string(from: Date()))" savePanel.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.modalPanelWindow))) - savePanel.begin { (result) in - if result.rawValue == NSFileHandlingPanelOKButton { - guard let url = savePanel.url else { return } - - let bitmapRep = NSBitmapImageRep(cgImage: image) - let data = bitmapRep.representation(using: .png, properties: [:]) - do { - try data?.write(to: url, options: .atomicWrite) - } catch { - print(error.localizedDescription) - } + let saveOptions = IKSaveOptions(imageProperties: [:], imageUTType: kUTTypePNG as String?) + saveOptions?.addAccessoryView(to: savePanel) + + let result = savePanel.runModal() + if result == .OK { + if let url = savePanel.url as CFURL?, let type = saveOptions?.imageUTType as CFString? { + guard let destination = CGImageDestinationCreateWithURL(url, type, 1, nil) else { return } + CGImageDestinationAddImage(destination, image, saveOptions!.imageProperties! as CFDictionary) + CGImageDestinationFinalize(destination) } } } From 345f9e7b638e77984439147193d3fd8aac49430a Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Sun, 29 Apr 2018 21:00:23 +0900 Subject: [PATCH 08/13] :heavy_plus_sign: Support various KeyCode type --- Fuwari/FloatWindow.swift | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Fuwari/FloatWindow.swift b/Fuwari/FloatWindow.swift index ce7ac4b..dfdfd48 100644 --- a/Fuwari/FloatWindow.swift +++ b/Fuwari/FloatWindow.swift @@ -7,6 +7,7 @@ // import Cocoa +import Magnet import Carbon class FloatWindow: NSWindow { @@ -30,10 +31,12 @@ class FloatWindow: NSWindow { override func keyDown(with event: NSEvent) { super.keyDown(with: event) - + + let combo = KeyCombo(keyCode: Int(event.keyCode), cocoaModifiers: event.modifierFlags) if event.modifierFlags.rawValue & NSEvent.ModifierFlags.command.rawValue != 0 { - switch event.keyCode { - case UInt16(kVK_ANSI_S): + guard let char = combo?.characters.first else { return } + switch char { + case "S": let saveLabel = NSTextField(frame: NSRect(x: 10, y: 10, width: 80, height: 26)) saveLabel.stringValue = "Save" saveLabel.textColor = .white @@ -54,11 +57,11 @@ class FloatWindow: NSWindow { self.floatDelegate?.save(floatWindow: self, image: image as! CGImage) } } - case UInt16(kVK_ANSI_W): + case "W": fade(isIn: false) { self.floatDelegate?.close(floatWindow: self) } - case UInt16(kVK_ANSI_C): + case "C": DispatchQueue.main.asyncAfter(deadline: .now()) { if let image = self.contentView?.layer?.contents { let cgImage = image as! CGImage From f4c000ec1ed0f89ad83da514b9b3537bb844f902 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Mon, 30 Apr 2018 00:11:27 +0900 Subject: [PATCH 09/13] :heavy_plus_sign: Add window scale up/down --- Fuwari/FloatWindow.swift | 92 ++++++++++++++++++++++++++++------------ 1 file changed, 64 insertions(+), 28 deletions(-) diff --git a/Fuwari/FloatWindow.swift b/Fuwari/FloatWindow.swift index dfdfd48..47c9177 100644 --- a/Fuwari/FloatWindow.swift +++ b/Fuwari/FloatWindow.swift @@ -10,6 +10,11 @@ import Cocoa import Magnet import Carbon +protocol FloatDelegate { + func save(floatWindow: FloatWindow, image: CGImage) + func close(floatWindow: FloatWindow) +} + class FloatWindow: NSWindow { override var canBecomeKey: Bool { return true } @@ -17,16 +22,38 @@ class FloatWindow: NSWindow { var floatDelegate: FloatDelegate? + private var originalRect = NSRect() + private var popUpLabel = NSTextField() + private var windowScale = CGFloat(1.0) + private let windowScaleInterval = CGFloat(0.25) + private let minWindowScale = CGFloat(0.25) + private let maxWindowScale = CGFloat(2.5) + init(contentRect: NSRect, styleMask style: NSWindow.StyleMask = .borderless, backing bufferingType: NSWindow.BackingStoreType = .buffered, defer flag: Bool = false, image: CGImage) { super.init(contentRect: contentRect, styleMask: style, backing: bufferingType, defer: flag) + originalRect = contentRect level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.floatingWindow))) isMovableByWindowBackground = true hasShadow = true contentView?.wantsLayer = true contentView?.layer?.contents = image - fade(isIn: true, completion: nil) + popUpLabel = NSTextField(frame: NSRect(x: 10, y: 10, width: 80, height: 26)) + popUpLabel.textColor = .white + popUpLabel.font = NSFont.boldSystemFont(ofSize: 20) + popUpLabel.alignment = .center + popUpLabel.drawsBackground = true + popUpLabel.backgroundColor = NSColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.4) + popUpLabel.wantsLayer = true + popUpLabel.layer?.cornerRadius = 10.0 + popUpLabel.isBordered = false + popUpLabel.isEditable = false + popUpLabel.isSelectable = false + popUpLabel.alphaValue = 0.0 + contentView?.addSubview(popUpLabel) + + fadeWindow(isIn: true) } override func keyDown(with event: NSEvent) { @@ -36,32 +63,18 @@ class FloatWindow: NSWindow { if event.modifierFlags.rawValue & NSEvent.ModifierFlags.command.rawValue != 0 { guard let char = combo?.characters.first else { return } switch char { - case "S": - let saveLabel = NSTextField(frame: NSRect(x: 10, y: 10, width: 80, height: 26)) - saveLabel.stringValue = "Save" - saveLabel.textColor = .white - saveLabel.font = NSFont.boldSystemFont(ofSize: 20) - saveLabel.alignment = .center - saveLabel.drawsBackground = true - saveLabel.backgroundColor = NSColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.4) - saveLabel.wantsLayer = true - saveLabel.layer?.cornerRadius = 10.0 - saveLabel.isBordered = false - saveLabel.isEditable = false - saveLabel.isSelectable = false - contentView?.addSubview(saveLabel) - + case "S": // ⌘S DispatchQueue.main.asyncAfter(deadline: .now()) { if let image = self.contentView?.layer?.contents { - saveLabel.removeFromSuperview() + self.showPopUp(text: "Save") self.floatDelegate?.save(floatWindow: self, image: image as! CGImage) } } - case "W": - fade(isIn: false) { + case "W": // ⌘W + fadeWindow(isIn: false) { self.floatDelegate?.close(floatWindow: self) } - case "C": + case "C": // ⌘C DispatchQueue.main.asyncAfter(deadline: .now()) { if let image = self.contentView?.layer?.contents { let cgImage = image as! CGImage @@ -69,13 +82,26 @@ class FloatWindow: NSWindow { let nsImage = NSImage(cgImage: cgImage, size: size) NSPasteboard.general.clearContents() NSPasteboard.general.writeObjects([nsImage]) + self.showPopUp(text: "Copy") } } + case "=": // ⌘+ + if windowScale < maxWindowScale { + windowScale += windowScaleInterval + setFrame(NSRect(x: frame.origin.x - (originalRect.width / 2 * windowScaleInterval), y: frame.origin.y - (originalRect.height / 2 * windowScaleInterval), width: originalRect.width * windowScale, height: originalRect.height * windowScale), display: true) + } + showPopUp(text: "\(Int(windowScale * 100))%") + case "-": // ⌘- + if windowScale > minWindowScale { + windowScale -= windowScaleInterval + setFrame(NSRect(x: frame.origin.x + (originalRect.width / 2 * windowScaleInterval), y: frame.origin.y + (originalRect.height / 2 * windowScaleInterval), width: originalRect.width * windowScale, height: originalRect.height * windowScale), display: true) + } + showPopUp(text: "\(Int(windowScale * 100))%") default: break } } else if event.keyCode == UInt16(kVK_Escape) { - fade(isIn: false) { + fadeWindow(isIn: false) { self.floatDelegate?.close(floatWindow: self) } } @@ -89,8 +115,23 @@ class FloatWindow: NSWindow { alphaValue = 1.0 } - private func fade(isIn: Bool, completion: (() -> Void)?) { - alphaValue = isIn ? 0.0 : 1.0 + private func showPopUp(text: String, duration: Double = 0.3) { + popUpLabel.stringValue = text + + NSAnimationContext.runAnimationGroup({ context in + context.duration = duration + context.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) + popUpLabel.animator().alphaValue = 1.0 + }) { + NSAnimationContext.runAnimationGroup({ context in + context.duration = duration + context.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) + self.popUpLabel.animator().alphaValue = 0.0 + }) + } + } + + private func fadeWindow(isIn: Bool, completion: (() -> Void)? = nil) { makeKeyAndOrderFront(self) NSAnimationContext.beginGrouping() NSAnimationContext.current.completionHandler = completion @@ -99,8 +140,3 @@ class FloatWindow: NSWindow { NSAnimationContext.endGrouping() } } - -protocol FloatDelegate { - func save(floatWindow: FloatWindow, image: CGImage) - func close(floatWindow: FloatWindow) -} From ff1d33c06436d468fe7c2d408edc0402ae922fb7 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Mon, 30 Apr 2018 08:57:10 +0900 Subject: [PATCH 10/13] :heavy_plus_sign: Add right-click menu --- Fuwari/Base.lproj/Localizable.strings | 10 +++ Fuwari/FloatWindow.swift | 101 +++++++++++++++++--------- Fuwari/LocalizedString.swift | 5 ++ Fuwari/ja.lproj/Localizable.strings | 10 +++ 4 files changed, 93 insertions(+), 33 deletions(-) diff --git a/Fuwari/Base.lproj/Localizable.strings b/Fuwari/Base.lproj/Localizable.strings index 04921c5..18d71ea 100644 --- a/Fuwari/Base.lproj/Localizable.strings +++ b/Fuwari/Base.lproj/Localizable.strings @@ -31,3 +31,13 @@ "Capture" = "Capture"; "About" = "About Fuwari..."; + +"Save" = "Save"; + +"Copy" = "Copy"; + +"Close" = "Close"; + +"Zoom In" = "Zoom In"; + +"Zoom Out" = "Zoom Out"; diff --git a/Fuwari/FloatWindow.swift b/Fuwari/FloatWindow.swift index 47c9177..3ba42b7 100644 --- a/Fuwari/FloatWindow.swift +++ b/Fuwari/FloatWindow.swift @@ -53,6 +53,15 @@ class FloatWindow: NSWindow { popUpLabel.alphaValue = 0.0 contentView?.addSubview(popUpLabel) + menu = NSMenu() + menu?.addItem(NSMenuItem(title: LocalizedString.Save.value, action: #selector(saveImage), keyEquivalent: "s")) + menu?.addItem(NSMenuItem(title: LocalizedString.Copy.value, action: #selector(copyImage), keyEquivalent: "c")) + menu?.addItem(NSMenuItem.separator()) + menu?.addItem(NSMenuItem(title: LocalizedString.ZoomIn.value, action: #selector(zoomInWindow), keyEquivalent: "+")) + menu?.addItem(NSMenuItem(title: LocalizedString.ZoomOut.value, action: #selector(zoomOutWindow), keyEquivalent: "-")) + menu?.addItem(NSMenuItem.separator()) + menu?.addItem(NSMenuItem(title: LocalizedString.Close.value, action: #selector(closeWindow), keyEquivalent: "w")) + fadeWindow(isIn: true) } @@ -64,46 +73,20 @@ class FloatWindow: NSWindow { guard let char = combo?.characters.first else { return } switch char { case "S": // ⌘S - DispatchQueue.main.asyncAfter(deadline: .now()) { - if let image = self.contentView?.layer?.contents { - self.showPopUp(text: "Save") - self.floatDelegate?.save(floatWindow: self, image: image as! CGImage) - } - } - case "W": // ⌘W - fadeWindow(isIn: false) { - self.floatDelegate?.close(floatWindow: self) - } + saveImage() case "C": // ⌘C - DispatchQueue.main.asyncAfter(deadline: .now()) { - if let image = self.contentView?.layer?.contents { - let cgImage = image as! CGImage - let size = CGSize(width: cgImage.width, height: cgImage.height) - let nsImage = NSImage(cgImage: cgImage, size: size) - NSPasteboard.general.clearContents() - NSPasteboard.general.writeObjects([nsImage]) - self.showPopUp(text: "Copy") - } - } + copyImage() case "=": // ⌘+ - if windowScale < maxWindowScale { - windowScale += windowScaleInterval - setFrame(NSRect(x: frame.origin.x - (originalRect.width / 2 * windowScaleInterval), y: frame.origin.y - (originalRect.height / 2 * windowScaleInterval), width: originalRect.width * windowScale, height: originalRect.height * windowScale), display: true) - } - showPopUp(text: "\(Int(windowScale * 100))%") + zoomInWindow() case "-": // ⌘- - if windowScale > minWindowScale { - windowScale -= windowScaleInterval - setFrame(NSRect(x: frame.origin.x + (originalRect.width / 2 * windowScaleInterval), y: frame.origin.y + (originalRect.height / 2 * windowScaleInterval), width: originalRect.width * windowScale, height: originalRect.height * windowScale), display: true) - } - showPopUp(text: "\(Int(windowScale * 100))%") + zoomOutWindow() + case "W": // ⌘W + closeWindow() default: break } } else if event.keyCode == UInt16(kVK_Escape) { - fadeWindow(isIn: false) { - self.floatDelegate?.close(floatWindow: self) - } + closeWindow() } } @@ -115,6 +98,58 @@ class FloatWindow: NSWindow { alphaValue = 1.0 } + override func rightMouseDown(with event: NSEvent) { + if let menu = menu, let contentView = contentView { + NSMenu.popUpContextMenu(menu, with: event, for: contentView) + } + } + + @objc private func saveImage() { + DispatchQueue.main.asyncAfter(deadline: .now()) { + if let image = self.contentView?.layer?.contents { + self.showPopUp(text: "Save") + self.floatDelegate?.save(floatWindow: self, image: image as! CGImage) + } + } + } + + @objc private func copyImage() { + DispatchQueue.main.asyncAfter(deadline: .now()) { + if let image = self.contentView?.layer?.contents { + let cgImage = image as! CGImage + let size = CGSize(width: cgImage.width, height: cgImage.height) + let nsImage = NSImage(cgImage: cgImage, size: size) + NSPasteboard.general.clearContents() + NSPasteboard.general.writeObjects([nsImage]) + self.showPopUp(text: "Copy") + } + } + } + + @objc private func zoomInWindow() { + if windowScale < maxWindowScale { + windowScale += windowScaleInterval + setFrame(NSRect(x: frame.origin.x - (originalRect.width / 2 * windowScaleInterval), y: frame.origin.y - (originalRect.height / 2 * windowScaleInterval), width: originalRect.width * windowScale, height: originalRect.height * windowScale), display: true) + } + + showPopUp(text: "\(Int(windowScale * 100))%") + } + + @objc private func zoomOutWindow() { + if windowScale > minWindowScale { + windowScale -= windowScaleInterval + setFrame(NSRect(x: frame.origin.x + (originalRect.width / 2 * windowScaleInterval), y: frame.origin.y + (originalRect.height / 2 * windowScaleInterval), width: originalRect.width * windowScale, height: originalRect.height * windowScale), display: true) + } + + showPopUp(text: "\(Int(windowScale * 100))%") + } + + @objc private func closeWindow() { + fadeWindow(isIn: false) { + self.floatDelegate?.close(floatWindow: self) + } + } + private func showPopUp(text: String, duration: Double = 0.3) { popUpLabel.stringValue = text diff --git a/Fuwari/LocalizedString.swift b/Fuwari/LocalizedString.swift index 4b8a7b3..bb0c656 100644 --- a/Fuwari/LocalizedString.swift +++ b/Fuwari/LocalizedString.swift @@ -18,6 +18,11 @@ enum LocalizedString: String { case DontLaunch = "Don't Launch" case Capture = "Capture" case About = "About" + case Save = "Save" + case Copy = "Copy" + case Close = "Close" + case ZoomIn = "ZoomIn" + case ZoomOut = "ZoomOut" case TabGeneral = "General" case TabMenu = "Menu" diff --git a/Fuwari/ja.lproj/Localizable.strings b/Fuwari/ja.lproj/Localizable.strings index bbdb957..21a2a1b 100644 --- a/Fuwari/ja.lproj/Localizable.strings +++ b/Fuwari/ja.lproj/Localizable.strings @@ -31,3 +31,13 @@ "Capture" = "キャプチャ"; "About" = "Fuwariについて..."; + +"Save" = "保存"; + +"Copy" = "コピー"; + +"Close" = "閉じる"; + +"Zoom In" = "拡大"; + +"Zoom Out" = "縮小"; From 0a55522cac2467929eb22583208a11c07222a719 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Mon, 30 Apr 2018 16:26:06 +0900 Subject: [PATCH 11/13] :bug: Fix shortcut conflict --- Fuwari.xcodeproj/project.pbxproj | 4 ++++ Fuwari/AppDelegate.swift | 10 +++++----- Fuwari/FloatWindow.swift | 10 ++++++---- Fuwari/FullScreenWindow.swift | 14 ++++++++------ Fuwari/StateManager.swift | 14 ++++++++++++++ Fuwari/ViewController.swift | 16 ++++++++++++++-- 6 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 Fuwari/StateManager.swift diff --git a/Fuwari.xcodeproj/project.pbxproj b/Fuwari.xcodeproj/project.pbxproj index d8b1e09..8198fc7 100644 --- a/Fuwari.xcodeproj/project.pbxproj +++ b/Fuwari.xcodeproj/project.pbxproj @@ -31,6 +31,7 @@ BEC844FB1DED859300A4A57A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BEC844FA1DED859300A4A57A /* Assets.xcassets */; }; BEC844FE1DED859300A4A57A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BEC844FC1DED859300A4A57A /* Main.storyboard */; }; BEC8450C1DF59ECB00A4A57A /* CaptureGuideView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEC8450B1DF59ECB00A4A57A /* CaptureGuideView.swift */; }; + BECCBA7F2096F95000D13978 /* StateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BECCBA7E2096F95000D13978 /* StateManager.swift */; }; BEF57FE51DFD46AE006595B6 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEF57FE41DFD46AE006595B6 /* PreferencesWindowController.swift */; }; BEF57FED1DFD53D3006595B6 /* UpdatePreferenceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEF57FEC1DFD53D3006595B6 /* UpdatePreferenceViewController.swift */; }; BEF57FEF1DFD58D4006595B6 /* NSColor+Fuwari.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEF57FEE1DFD58D4006595B6 /* NSColor+Fuwari.swift */; }; @@ -69,6 +70,7 @@ BEC844FD1DED859300A4A57A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; BEC844FF1DED859300A4A57A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; BEC8450B1DF59ECB00A4A57A /* CaptureGuideView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaptureGuideView.swift; sourceTree = ""; }; + BECCBA7E2096F95000D13978 /* StateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateManager.swift; sourceTree = ""; }; BEF57FE41DFD46AE006595B6 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; BEF57FEC1DFD53D3006595B6 /* UpdatePreferenceViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatePreferenceViewController.swift; sourceTree = ""; }; BEF57FEE1DFD58D4006595B6 /* NSColor+Fuwari.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSColor+Fuwari.swift"; sourceTree = ""; }; @@ -135,6 +137,7 @@ BEC8450B1DF59ECB00A4A57A /* CaptureGuideView.swift */, BE7E82581DF72E7A00F3F2F8 /* FullScreenWindow.swift */, BE7E825A1DF74A2D00F3F2F8 /* FloatWindow.swift */, + BECCBA7E2096F95000D13978 /* StateManager.swift */, BE5BE7A31E065D7800820201 /* HotKeyManager.swift */, BE9777F71E100D1F00E5934F /* MenuManager.swift */, BE6D5E741E12CF5E005492B2 /* AboutWindowController.swift */, @@ -318,6 +321,7 @@ BE6D5E761E12CF5E005492B2 /* AboutWindowController.swift in Sources */, BE5BE7A41E065D7800820201 /* HotKeyManager.swift in Sources */, BE5896A11DFCED26007CE7AC /* LocalizedString.swift in Sources */, + BECCBA7F2096F95000D13978 /* StateManager.swift in Sources */, BEC8450C1DF59ECB00A4A57A /* CaptureGuideView.swift in Sources */, BEC844F71DED859300A4A57A /* AppDelegate.swift in Sources */, BE9777ED1E0E613700E5934F /* UserDefaults+ArchiveData.swift in Sources */, diff --git a/Fuwari/AppDelegate.swift b/Fuwari/AppDelegate.swift index fb57145..d11d450 100644 --- a/Fuwari/AppDelegate.swift +++ b/Fuwari/AppDelegate.swift @@ -16,8 +16,8 @@ import Crashlytics @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { - var eventMonitor: Any? - let defaults = UserDefaults.standard + private var eventMonitor: Any? + private let defaults = UserDefaults.standard func applicationDidFinishLaunching(_ aNotification: Notification) { Fabric.with([Answers.self, Crashlytics.self]) @@ -68,7 +68,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { NSApp.terminate(nil) } - fileprivate func promptToAddLoginItems() { + private func promptToAddLoginItems() { let alert = NSAlert() alert.messageText = LocalizedString.LaunchFuwari.value alert.informativeText = LocalizedString.LaunchSettingInfo.value @@ -89,7 +89,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { defaults.synchronize() } - fileprivate func toggleAddingToLoginItems(_ enable: Bool) { + private func toggleAddingToLoginItems(_ enable: Bool) { let appPath = Bundle.main.bundlePath LoginServiceKit.removeLoginItems(at: appPath) if enable { @@ -97,7 +97,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { } } - fileprivate func toggleLoginItemState() { + private func toggleLoginItemState() { let isInLoginItems = defaults.bool(forKey: Constants.UserDefaults.loginItem) toggleAddingToLoginItems(isInLoginItems) } diff --git a/Fuwari/FloatWindow.swift b/Fuwari/FloatWindow.swift index 3ba42b7..7309a3a 100644 --- a/Fuwari/FloatWindow.swift +++ b/Fuwari/FloatWindow.swift @@ -68,6 +68,10 @@ class FloatWindow: NSWindow { override func keyDown(with event: NSEvent) { super.keyDown(with: event) + if StateManager.shared.isCapturing { + return + } + let combo = KeyCombo(keyCode: Int(event.keyCode), cocoaModifiers: event.modifierFlags) if event.modifierFlags.rawValue & NSEvent.ModifierFlags.command.rawValue != 0 { guard let char = combo?.characters.first else { return } @@ -145,9 +149,7 @@ class FloatWindow: NSWindow { } @objc private func closeWindow() { - fadeWindow(isIn: false) { - self.floatDelegate?.close(floatWindow: self) - } + floatDelegate?.close(floatWindow: self) } private func showPopUp(text: String, duration: Double = 0.3) { @@ -166,7 +168,7 @@ class FloatWindow: NSWindow { } } - private func fadeWindow(isIn: Bool, completion: (() -> Void)? = nil) { + func fadeWindow(isIn: Bool, completion: (() -> Void)? = nil) { makeKeyAndOrderFront(self) NSAnimationContext.beginGrouping() NSAnimationContext.current.completionHandler = completion diff --git a/Fuwari/FullScreenWindow.swift b/Fuwari/FullScreenWindow.swift index 4238c15..fe21492 100644 --- a/Fuwari/FullScreenWindow.swift +++ b/Fuwari/FullScreenWindow.swift @@ -9,6 +9,11 @@ import Cocoa import Carbon +protocol CaptureDelegate { + func didCanceled() + func didCaptured(rect: NSRect, image: CGImage) +} + class FullScreenWindow: NSWindow { var captureDelegate: CaptureDelegate? @@ -40,7 +45,9 @@ class FullScreenWindow: NSWindow { NSEvent.addLocalMonitorForEvents(matching: .keyDown) { (event: NSEvent) -> NSEvent? in if event.keyCode == UInt16(kVK_Escape) { - self.captureDelegate?.didCanceled() + if StateManager.shared.isCapturing { + self.captureDelegate?.didCanceled() + } } return event } @@ -83,8 +90,3 @@ class FullScreenWindow: NSWindow { captureDelegate?.didCaptured(rect: rect.offsetBy(dx: frame.origin.x, dy: frame.origin.y), image: cgImage) } } - -protocol CaptureDelegate { - func didCanceled() - func didCaptured(rect: NSRect, image: CGImage) -} diff --git a/Fuwari/StateManager.swift b/Fuwari/StateManager.swift new file mode 100644 index 0000000..86534d1 --- /dev/null +++ b/Fuwari/StateManager.swift @@ -0,0 +1,14 @@ +// +// StateManager.swift +// Fuwari +// +// Created by Kengo Yokoyama on 2018/04/30. +// Copyright © 2018年 AppKnop. All rights reserved. +// + +import Cocoa + +class StateManager: NSObject { + static let shared = StateManager() + var isCapturing = false +} diff --git a/Fuwari/ViewController.swift b/Fuwari/ViewController.swift index ac15241..818fb2c 100644 --- a/Fuwari/ViewController.swift +++ b/Fuwari/ViewController.swift @@ -13,6 +13,7 @@ class ViewController: NSViewController { private var windowControllers = [NSWindowController]() private var fullScreenWindows = [FullScreenWindow]() + private var isCancelled = false override func viewDidLoad() { super.viewDidLoad() @@ -44,7 +45,7 @@ class ViewController: NSViewController { @objc private func startCapture() { NSCursor.hide() - + StateManager.shared.isCapturing = true fullScreenWindows.forEach { $0.startCapture() } } } @@ -53,18 +54,29 @@ extension ViewController: CaptureDelegate { func didCaptured(rect: NSRect, image: CGImage) { createFloatWindow(rect: rect, image: image) NSCursor.unhide() + StateManager.shared.isCapturing = false fullScreenWindows.forEach { $0.orderOut(nil) } + isCancelled = false } func didCanceled() { NSCursor.unhide() + StateManager.shared.isCapturing = false + isCancelled = true fullScreenWindows.forEach { $0.orderOut(nil) } } } extension ViewController: FloatDelegate { func close(floatWindow: FloatWindow) { - windowControllers.filter({ $0.window === floatWindow }).first?.close() + if !isCancelled { + if windowControllers.filter({ $0.window === floatWindow }).first != nil { + floatWindow.fadeWindow(isIn: false) { + floatWindow.close() + } + } + } + isCancelled = false } func save(floatWindow: FloatWindow, image: CGImage) { From d061647f7f9973cacbd6642ef2f173e4227369d8 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Mon, 30 Apr 2018 16:38:20 +0900 Subject: [PATCH 12/13] :fire: Remove beep sound --- Fuwari/FloatWindow.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Fuwari/FloatWindow.swift b/Fuwari/FloatWindow.swift index 7309a3a..9cf12fd 100644 --- a/Fuwari/FloatWindow.swift +++ b/Fuwari/FloatWindow.swift @@ -66,8 +66,6 @@ class FloatWindow: NSWindow { } override func keyDown(with event: NSEvent) { - super.keyDown(with: event) - if StateManager.shared.isCapturing { return } From d40f9f97da7e7479c415be2b2a3e08c9b95a7688 Mon Sep 17 00:00:00 2001 From: Kengo Yokoyama Date: Mon, 30 Apr 2018 17:32:59 +0900 Subject: [PATCH 13/13] :arrow_up: Update README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 133ed01..b5c8c78 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Floating screenshot like a sticky.

## Requirement -- Swift3+ -- Xcode8+ +- Swift4+ +- Xcode9.3+ ## Contributing 1. Fork it ( https://github.com/kentya6/Fuwari/fork ) @@ -24,7 +24,7 @@ Floating screenshot like a sticky. The MIT License (MIT) -Copyright (c) 2016 Kengo YOKOYAMA +Copyright (c) 2018 Kengo YOKOYAMA ## Author