How to show modal window in SwiftUI for macOS

Issue #768 Use custom NSWindow, set level in becomeKey and call NSApp.runModal to show modal final class ModalWindow: NSWindow { override func becomeKey() { super.becomeKey() level = .statusBar } override func close() { super.close() NSApp.stopModal() } } let window = ModalWindow( contentRect: .zero, styleMask: [.titled, .closable], backing: .buffered, defer: false ) window.titlebarAppearsTransparent = true window.title = "Manage collections" window.center() window.isReleasedWhenClosed = false self.window = window let view = CollectionSettingsView(store: Store.shared) ....

February 3, 2021 · 1 min · Khoa Pham

How to handle keyDown in SwiftUI for macOS

Issue #764 Use a custom KeyAwareView that uses an NSView that checks for keyDown method. In case we can’t handle certain keys, call super.keyDown(with: event) import SwiftUI import KeyboardShortcuts struct KeyAwareView: NSViewRepresentable { let onEvent: (Event) -> Void func makeNSView(context: Context) -> NSView { let view = KeyView() view.onEvent = onEvent DispatchQueue.main.async { view.window?.makeFirstResponder(view) } return view } func updateNSView(_ nsView: NSView, context: Context) {} } extension KeyAwareView { enum Event { case upArrow case downArrow case leftArrow case rightArrow case space case delete case cmdC } } private class KeyView: NSView { var onEvent: (KeyAwareView....

January 29, 2021 · 1 min · Khoa Pham

How to use Sparkle for macOS app

Issue #762 Install Sparkle For now, the latest stable version is 1.24.0 which supports CocoaPods OK, but still, have issues with SPM. Support non sandboxed apps Version 2.0.0 is in beta and supports sandboxed apps To install, use CocoaPods platform :osx, '11.0' target 'MyApp' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! pod 'Sparkle' end Sign In your target, choose Signing & Capability tab, change Signing Certificate from Locally to Development for code sign to work for embedded frameworks...

January 26, 2021 · 2 min · Khoa Pham

How to handle keyDown in NSResponder

Issue #760 import AppKit import Omnia class MyWindow: NSWindow { override func keyDown(with event: NSEvent) { super.keyDown(with: event) if isKey(NSDeleteCharacter, event: event) { NotificationCenter.default.post(Notification(name: .didKeyboardDeleteItem)) } else if isKey(NSUpArrowFunctionKey, event: event) { print("up") } else if isKey(NSDownArrowFunctionKey, event: event) { print("down") } else if isKey(NSLeftArrowFunctionKey, event: event) { print("left") } else if isKey(NSRightArrowFunctionKey, event: event) { print("right") } } private func isKey(_ key: Int, event: NSEvent) -> Bool { if let scalar = UnicodeScalar(key) { return event....

January 21, 2021 · 2 min · Khoa Pham

How to use built in NSImage in macos

Issue #759 Read more https://hetima.github.io/fucking_nsimage_syntax/

January 21, 2021 · 1 min · Khoa Pham

How to handle NSSearchToolbarItem in macOS 11

Issue #758 extension NSToolbarItem.Identifier { static let searchItem: NSToolbarItem.Identifier = NSToolbarItem.Identifier("SearchItem") } let searchItem = NSSearchToolbarItem(itemIdentifier: .searchItem) extension AppDelegate: NSToolbarDelegate { func toolbar( _ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool ) -> NSToolbarItem? { switch itemIdentifier { case .searchItem: searchItem.searchField.delegate = self return searchItem } } extension AppDelegate: NSSearchFieldDelegate { func control( _ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector ) -> Bool { if (commandSelector == #selector(NSResponder.insertNewline(_:))) { print("enter") return true } return false } }

January 21, 2021 · 1 min · Khoa Pham

How to do launch at login for macOS apps

Issue #757 Use SMLoginItemSetEnabled from Service Management framework Use a helper background app that checks and invokes our main application Copy our helper app into Library/LoginItems helper_dir="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH/Library/LoginItems" final class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { let bundleId = Bundle.main.bundleIdentifier! // TODO:Make this more strict by only replacing at the end let mainBundleId = bundleId.replacingOccurrences(of: "-LaunchAtLoginHelper", with: "") // Ensure the app is not already running guard NSRunningApplication....

January 20, 2021 · 1 min · Khoa Pham

How to use NSWindow style and NSToolbar in AppKit

Issue #755 Read more https://github.com/martinlexow/SwiftUIWindowStyles https://github.com/lukakerr/NSWindowStyles https://github.com/marioaguzman/toolbar

January 20, 2021 · 1 min · Khoa Pham

How to use NSSplitViewController in AppKit

Issue #754 Read more https://github.com/KevinGutowski/SplitConfigurations

January 20, 2021 · 1 min · Khoa Pham

How to create and notarize dmg file

Issue #753 Archive and export app from Xcode Create dmg Use create-dmg It is said that we don’t need to notarize the app, we can just notarize the whole dmg Send dmg to notarize This takes a while xcrun altool -t osx -f PastePal.dmg --primary-bundle-id com.onmyway133.PastePal --notarize-app -u onmyway133@gmail.com -p APP_SPECIFIC_PASSWORD --asc-provider "T78DK947F2" If wrong password, you will get error Error: code -1011 (Failed to authenticate for session: ( “Error Domain=ITunesConnectionAuthenticationErrorDomain Code=-22938 "Sign in with the app-specific password you generated....

January 18, 2021 · 2 min · Khoa Pham

How to open downloaded app from browser in Big Sur

Issue #750 Recently when distributing staging releases of my app PastePal via GitHub release or Google Drive, people had hard time opening it The displayed error is You do not have permission to open the application The more verbose error when using open command in Terminal is The application cannot be opened for an unexpected reason, error=Error Domain=NSOSStatusErrorDomain Code=-10826 “kLSNoLaunchPermissionErr: User doesn’t have permission to launch the app (managed networks)” UserInfo={_LSFunction=_LSLaunchWithRunningboard, _LSLine=2508, NSUnderlyingError=0x7fa9c750d850 {Error Domain=RBSRequestErrorDomain Code=5 “Launch failed....

January 15, 2021 · 2 min · Khoa Pham

How to make popup button in SwiftUI for macOS

Issue #748 There is said to be PopUpButtonPickerStyle and MenuPickerStyle but these don’t seem to work. There’s Menu button it shows a dropdown style. We fake it by fading this and overlay with a button. allowsHitTesting does not work, but disabled seems to do the trick Menu { Button("About", action: ActionService.onAbout) Button("Quit", action: ActionService.onQuit) } label: { Text("") } .frame(width: 24) .opacity(0.01) .overlay( makeButton(action: {}, "gearshape.fill") .disabled(true) .foregroundColor(Color.secondaryLabel) ) Follow pika...

January 13, 2021 · 1 min · Khoa Pham

How to use Apple keyboard key symbols

Issue #743 •  = Apple logo • ⌘ = Command • ⇧ = Shift • ⌫ = Backspace/Delete • ⇪ = Caps lock • ⌥ = Option/Alt • ⌃ = Control • ⎋ = Escape • ←↑→↓ = Arrow Keys • ↩ = Return

January 5, 2021 · 1 min · Khoa Pham

How to disable scrolling in NSTextView for macOS

Issue #733 NSTextView has this handy method to make scrollable NSTextView NSTextView.scrollableTextView(). The solution is to get to the responder outside enclosing NSScrollView, in my case it is the SwiftUI hosting view class DisabledScrollTextView: NSTextView { override func scrollWheel(with event: NSEvent) { // 1st nextResponder is NSClipView // 2nd nextResponder is NSScrollView // 3rd nextResponder is NSResponder SwiftUIPlatformViewHost self.nextResponder?.nextResponder?.nextResponder?.scrollWheel(with: event) } } Then we can construct with our new DisabledScrollTextView.scrollableTextView

December 31, 2020 · 1 min · Khoa Pham

How to make attributed string Text in SwiftUI for macOS

Issue #730 Use NSTextField with maximumNumberOfLines import AppKit import SwiftUI struct AttributedText: NSViewRepresentable { let attributedString: NSAttributedString init(_ attributedString: NSAttributedString) { self.attributedString = attributedString } func makeNSView(context: Context) -> NSTextField { let textField = NSTextField() textField.lineBreakMode = .byClipping textField.maximumNumberOfLines = 0 textField.isBordered = false return textField } func updateNSView(_ nsView: NSTextField, context: Context) { nsView.attributedStringValue = attributedString } } TextField has problem with wrapping, we can use TextView struct AttributedTextView: NSViewRepresentable { typealias NSViewType = NSScrollView let attributedText: NSAttributedString?...

December 31, 2020 · 1 min · Khoa Pham

How to do copy paste delete in Swift for macOS

Issue #729 @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @IBAction func copy(_ sender: Any) { print("copy", sender) } @IBAction func paste(_ sender: Any) { print("paste", sender) } } For delete, we can listen to keyDown in NSWindow class MyWindow: NSWindow { override func keyDown(with event: NSEvent) { super.keyDown(with: event) guard let deleteScalar = UnicodeScalar(NSDeleteCharacter), event.charactersIgnoringModifiers == String(deleteScalar) else { return } NotificationCenter.default.post(Notification(name: .didKeyboardDeleteItem)) } }

December 30, 2020 · 1 min · Khoa Pham

How to make visual effect blur in SwiftUI for macOS

Issue #724 We can use .blur modifier, but with VisualEffectView gives us more options for material and blending mode. public struct VisualEffectView: NSViewRepresentable { let material: NSVisualEffectView.Material let blendingMode: NSVisualEffectView.BlendingMode public init( material: NSVisualEffectView.Material = .contentBackground, blendingMode: NSVisualEffectView.BlendingMode = .withinWindow ) { self.material = material self.blendingMode = blendingMode } public func makeNSView(context: Context) -> NSVisualEffectView { let visualEffectView = NSVisualEffectView() visualEffectView.material = material visualEffectView.blendingMode = blendingMode visualEffectView.state = NSVisualEffectView.State.active return visualEffectView } public func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context) { visualEffectView....

December 26, 2020 · 1 min · Khoa Pham

How to force set frame explicitly for NSWindow

Issue #721 For setFrame to take effect mainWindow.setFrame(rect, display: true) we can remove auto save frame flag mainWindow.setFrameAutosaveName("MyApp.MainWindow")

December 25, 2020 · 1 min · Khoa Pham

How to rotate NSStatusItem

Issue #720 NSStatusItem is backed by NSButton, we can animate this inner button. We need to specify position and anchorPoint for button’s layer so it rotates around its center point guard let button = statusItem.button else { return } let animation = CABasicAnimation(keyPath: "transform.rotation.z") animation.fromValue = 0 animation.toValue = CGFloat.pi * 2 animation.duration = 0.25 animation.repeatCount = 1 button.layer?.position = NSPoint(x: NSMidX(button.frame), y: NSMidY(button.frame)) button.layer?.anchorPoint = NSPoint(x: 0.5, y: 0.5) button....

December 23, 2020 · 1 min · Khoa Pham

How to show image and text in menu item in SwiftUI for macOS

Issue #719 From SwiftUI 2 for macOS 11.0, we have access to Menu for creating menu and submenu. Usually we use Button for interactive menu items and Text for disabled menu items. The easy way to customize menu with image is to call Menu with content and label. Pay attention to how we use Button and Label inside Content to create interactive menu items Menu( content: { ForEach(collections) { collection in Button(action: {) { Label(collection....

December 23, 2020 · 1 min · Khoa Pham