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鈥檛 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 extend custom View in SwiftUI

Issue #763 I usually break down a big struct into smaller views and extensions. For example I have a ClipboardCell that has a lot of onReceive so I want to move these to another component. One way to do that is to extend ClipboardCell struct ClipboardCell: View { let isSelected: Bool @State var showsPreview: Bool @State var showsViewRaw: Bool let onCopy: () -> Void let onDelete: () -> Void } extension ClipboardCell { func onReceiveKeyboard() -> some View { self....

January 28, 2021 路 3 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 use ScrollViewReader in SwiftUI

Issue #761 Explicitly specify id ScrollView { ScrollViewReader { proxy in LazyVStack(spacing: 10) { ForEach(items) { item in Cell(item: item) .id(item.id) } } .padding() .onReceiveKeyboard(onNext: { onNext() if let item = selectedItem { proxy.scrollTo(item.id, anchor: .center) } }, onPrevious: { onPrevious() if let item = selectedItem { proxy.scrollTo(item.id, anchor: .center) } }) } } I usually extract ScrollViewReader into a helper function that use onChange to react to state changes...

January 21, 2021 路 1 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 fix overlapped navigation titles in SwiftUI

Issue #756 extension NavigationLink { func fixOverlap() -> AnyView { if UIDevice.current.userInterfaceIdiom == .phone { return self.isDetailLink(false).erase() } else { return self.erase() } } } Read more https://www.dabblingbadger.com/blog/2020/12/11/a-quick-fix-for-overlapping-navigation-titles-in-swiftui As far as I can tell, this bug only shows up if you: 1) have the navigation title displayMode of a destination view set to .large and 2) have added items to the navigation bar using the .navigationBarItems modifier....

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鈥檛 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: ( 鈥淓rror Domain=ITunesConnectionAuthenticationErrorDomain Code=-22938 "Sign in with the app-specific password you generated....

January 18, 2021 路 2 min 路 Khoa Pham

How to use module import in nodejs

Issue #752 Use esm npm install esm In our code, import as normal const fs = require('fs'); // intended to be run after babel, and in ./dist folder import factory from 'data' const shell = require('shelljs') Then use esm to convert { "name": "generator", "version": "1.0.0", "main": "index.js", "scripts": { "start": "npx babel index.js --out-file dist/index.js && node -r esm dist/index.js" } } Read more https://stackoverflow.com/questions/45854169/how-can-i-use-an-es6-import-in-node-js ...

January 17, 2021 路 1 min 路 Khoa Pham

How to use relative file module with Create React app

Issue #751 Declare data/package.json to make it into node module { "name": "data", "version": "0.1.0", "private": true, "homepage": ".", "main": "main.js" } Then in landing/package.json, use file { "name": "landing", "version": "0.1.0", "private": true, "homepage": ".", "dependencies": { "@emotion/core": "^10.0.28", "react": "^16.13.1", "react-dom": "^16.13.1", "react-image": "^2.4.0", "react-scripts": "3.4.1", "data": "file:../data" }, ...

January 17, 2021 路 1 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 鈥渒LSNoLaunchPermissionErr: User doesn鈥檛 have permission to launch the app (managed networks)鈥 UserInfo={_LSFunction=_LSLaunchWithRunningboard, _LSLine=2508, NSUnderlyingError=0x7fa9c750d850 {Error Domain=RBSRequestErrorDomain Code=5 鈥淟aunch failed....

January 15, 2021 路 2 min 路 Khoa Pham

How to add alternative app icons for iOS

Issue #749 Some apps want to support alternative app icons in Settings where user can choose to update app icon. Here鈥檚 some must do to make it work, as of Xcode 12.2 In Info.plist, must declare CFBundleIcons with both CFBundlePrimaryIcon and CFBundleAlternateIcons Icons must be in project folder, not Asset Catalog Here鈥檚 how it is done on my app PastePal Add app icons to project folder Prepare icons, like Icon1, Icon2 with 2 variants for 2x and 3x....

January 14, 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鈥檛 seem to work. There鈥檚 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 UITextView in SwiftUI

Issue #747 Need to use Coordinator conforming to UITextViewDelegate to apply changes back to Binding import SwiftUI import UIKit struct MyTextView: UIViewRepresentable { @Binding var text: String final class Coordinator: NSObject, UITextViewDelegate { let parent: MyTextView init(parent: MyTextView) { self.parent = parent } func textViewDidChange(_ textView: UITextView) { if textView.text != parent.text { parent.text = textView.text } } } func makeCoordinator() -> Coordinator { Coordinator(parent: self) } func makeUIView(context: Context) -> UITextView { let view = UITextView() view....

January 8, 2021 路 1 min 路 Khoa Pham

How to check app going to background in SwiftUI

Issue #746 From iOS 13, the default is to support multiple scene, so the the old UIApplicationDelegate lifecycle does not work. Double check your Info.plist for UIApplicationSceneManifest key <key>UIApplicationSceneManifest</key> <dict> <key>UIApplicationSupportsMultipleScenes</key> <true/> </dict> One way to be notified about application life cycle is to use UIApplicationDelegateAdaptor and via NotificationCenter import SwiftUI import UIKit import FontAwesomeSwiftUI final class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { FontAwesome....

January 7, 2021 路 1 min 路 Khoa Pham

How to use selection in List in SwiftUI

Issue #745 I used to use selection with Binding where wrappedValue is optional, together with tag in SwiftUI for macOS, and it shows current selection @Binding var selection: Tag? = .all List(section: $selection) { Text("All") .tag(Tag.all) } From the API, looks like Binding<Set> is for multiple selection, and Binding<Optional> is for single selection Looking at List signature, I see that selection uses wrappedValue as Set for Binding<Set<SelectionValue>>? init<Data, ID, RowContent>(Data, id: KeyPath<Data....

January 6, 2021 路 1 min 路 Khoa Pham