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

How to make stepper with plus and minus buttons in SwiftUI for macOS

Issue #717 Try to use predefined system colors in Human Interface Guidelines for macOS Here we use this color unemphasizedSelectedTextBackgroundColor for button background HStack(spacing: 1) { makeUnderListButton(action: {}, icon: .plus) makeUnderListButton(action: {}, icon: .minus) } .background(Color(NSColor.unemphasizedSelectedTextBackgroundColor)) .cornerRadius(4) func makeUnderListButton(action: @escaping () -> Void, icon: AwesomeIcon) -> some View { Button(action: action) { Text(icon.rawValue) .font(.awesome(style: .solid, size: 14)) } .buttonStyle(HighlightButtonStyle(h: 8, v: 6, cornerRadius: 4)) } Another thing is List, where we have selected and alternative background colors....

December 21, 2020 · 1 min · Khoa Pham

How to fix Picker not showing selection in SwiftUI

Issue #716 I have an enum that conforms to CaseIterable that I want to show in Picker enum Position: String, Codable, CaseIterable, Identifiable { var id: String { rawValue } case left case right case bottom case top } Picker(selection: $preference.position, label: Text("Position")) { ForEach(Preference.Position.allCases) { position in Text(position.rawValue) } } It compiles and runs just fine, but Picker does not show current selection regardless of any Picker style I choose....

December 20, 2020 · 2 min · Khoa Pham

How to add toolbar programatically in macOS

Issue #713 To setup toolbar, we need to implement NSToolbarDelegate that provides toolbar items. This delegate is responsible for many things Set visible and allowed items with toolbarDefaultItemIdentifiers Provide item with itemForItemIdentifier Being notified with toolbarWillAddItem and toolbarDidRemoveItem window.toolbarStyle = .unifiedCompact let toolbar = NSToolbar(identifier: "Toolbar") toolbar.displayMode = .iconAndLabel toolbar.delegate = (NSApp.delegate as! AppDelegate) toolbar.insertItem(withItemIdentifier: .add, at: 0) toolbar.insertItem(withItemIdentifier: .settings, at: 1) window.toolbar = toolbar extension NSToolbarItem.Identifier { static let add = NSToolbarItem....

December 15, 2020 · 1 min · Khoa Pham

How to show sidebar in SwiftUI for macOS

Issue #710 Starting from macOS 11, we can use List with SidebarListStyle inside NavigationView to declare master detail view. The SidebarListStyle makes list translucent. It automatically handles selection and marks selected row in list with accent color. struct MainView: some View { var body: some View { NavigationView { sidebar ContentView() } } private var sidebar: some View { List { Group { Text("Categories") .foregroundColor(.gray) ForEach(categories) { category in NavigationLink(destination: ContentView(category: category)) { Label(category....

December 13, 2020 · 1 min · Khoa Pham

How to support right click menu to NSStatusItem

Issue #707 The trick is to set the button oinside of statusItem to send actions on both leftMouseUp and rightMouseUp. Another thing to note is we use popUpMenu on NSStatusItem, although it is marked as deprecated on macOS 10.14. We can set menu but that overrides left click. import Omnia private let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) private let statusItemMenuHandler = MenuHandler() func setupStatusMenu() { if let button = statusItem.button { button....

December 7, 2020 · 1 min · Khoa Pham

How to convert from paid to free with IAP

Issue #703 What is receipt Read When to refresh a receipt vs restore purchases in iOS? From iOS 7, every app downloaded from the store has a receipt (for downloading/buying the app) at appStoreReceiptURL. When users purchases something via In App Purchase, the content at appStoreReceiptURL is updated with purchases information. Most of the cases, you just need to refresh the receipt (at appStoreReceiptURL) so that you know which transactions users have made....

November 30, 2020 · 9 min · Khoa Pham

How to disable NSTextView in SwiftUI

Issue #702 The trick is to use an overlay MessageTextView(text: $input.message) .overlay(obscure) var obscure: AnyView { if store.pricingPlan.isPro { return EmptyView().erase() } else { return Color.black.opacity(0.01).erase() } }

November 27, 2020 · 1 min · Khoa Pham

How to check dark mode in AppKit for macOS apps

Issue #693 AppKit app has its theme information stored in UserDefaults key AppleInterfaceStyle, if is dark, it contains String Dark. Another way is to detect appearance via NSView struct R { static let dark = DarkTheme() static let light = LightTheme() static var theme: Theme { let isDark = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark" return isDark ? dark : light } } Another way is to rely on appearance on NSView. You can quickly check via NSApp....

November 10, 2020 · 2 min · Khoa Pham

How to make full size content view in SwiftUI for macOS

Issue #689 func applicationDidFinishLaunching(_ aNotification: Notification) { // extend to title bar let contentView = ContentView() // .padding(.top, 24) // can padding to give some space .edgesIgnoringSafeArea(.top) // specify fullSizeContentView window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), styleMask: [.titled, .closable, .miniaturizable, .texturedBackground, .resizable, .fullSizeContentView], backing: .buffered, defer: false ) window.center() window.setFrameAutosaveName("My App") // window.title = ... // no title // window.toolbar = NSToolbar() // use toolbar if wanted....

November 3, 2020 · 1 min · Khoa Pham

How to style multiline Text in SwiftUI for macOS

Issue #681 Only need to specify fixedSize on text to preserve ideal height. The maximum number of lines is 1 if the value is less than 1. If the value is nil, the text uses as many lines as required. The default is nil. Text(longText) .lineLimit(nil) // No need .fixedSize(horizontal: false, vertical: true) If the Text is inside a row in a List, fixedSize causes the row to be in middle of the List, workaround is to use ScrollView and vertical StackView....

October 7, 2020 · 1 min · Khoa Pham