How to make simple HUD in SwiftUI

Issue #723 Use @ViewBuilder to build dynamic content for our HUD. For blur effect, here I use NSVisualEffectView, but we can use .blur modifier also struct HUD<Content>: View where Content: View { let content: () -> Content init(@ViewBuilder content: @escaping () -> Content) { self.content = content } var body: some View { content() .frame(width: 80, height: 80) .background( VisualEffectView(material: .hudWindow) .clipShape(RoundedRectangle(cornerRadius: 12)) .shadow(color: Color.black.opacity(0.22), radius: 12, x: 0, y: 5) ) } } Then we can make some wrappers for information and progress HUD...

December 26, 2020 · 1 min · 132 words · Khoa

How to instrument SwiftUI app

Issue #722 With Xcode 12, we can fire up Instrument to profile our app. Select SwiftUI template There are many profiles in that template, I find SwiftUI and Time Profile very useful. Here’s the profile I run for my app PastePal SwiftUI View Body This shows how many instance of View with body invocation are there, both for SwiftUI views and our app views Taking a look at SwiftUI profile, it shows that ClipboardCell is taking most of the time, here over 7 seconds...

December 25, 2020 · 2 min · 294 words · Khoa

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 · 18 words · Khoa

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 · 73 words · Khoa

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 · 187 words · Khoa

How to make sharing menu in SwiftUI for macOS

Issue #718 Use NSSharingService.sharingServices(forItems:) with an array of one empty string gives a list of sharing items. There we show image and title of each menu item. We should cache sharing items as that can cause performance issue import SwiftUI import AppKit import EasySwiftUI extension NSSharingService { private static let items = NSSharingService.sharingServices(forItems: [""]) static func submenu(text: String) -> some View { return Menu( content: { ForEach(items, id: \.title) { item in Button(action: { item....

December 23, 2020 · 1 min · 112 words · Khoa

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 · 129 words · Khoa

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 · 259 words · Khoa

My year in review 2020

Issue #715 I remember this time last year in December 2019, I spent almost every single bit of my free time on Puma because I want a Swift friendly version of fastlane that suits my need and leverages Swift 5 features. Here’s my review of my work in year 2020. Blogging I started blogging on GitHub issue, starting from Issue 1 Hello world, again, now I have over 670 issues, which were generated into blog posts at my website https://onmyway133....

December 16, 2020 · 7 min · 1461 words · Khoa

How to do didSet for State and Binding in SwiftUI

Issue #714 Below is an example of a parent ContentView with State and a child Sidebar with a Binding. The didSet is only called for the property that is changed. When we click Button in ContentView, that changes State property, so only the didSet in ContentView is called When we click Button in Sidebar, that changes Binding property, so only the didSet in Sidebar is called enum Tag: String { case all case settings } struct ContentView: View { @State private var tag: Tag = ....

December 16, 2020 · 2 min · 325 words · Khoa

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 · 202 words · Khoa

How to declare network Error with enum in Swift

Issue #712 Describe all possible paths in your program with enum. This is great to track down bugs and to not miss representing potential cases in UI. Errors can come from app layer, backend layer to network issues. Enum is handy in both UIKit and SwiftUI enum NetworkError: Swift.Error { enum RequestError { case invalidRequest(URLRequest) case encodingError(Swift.EncodingError) case other(NSError) } enum ServerError { case decodingError(Swift.DecodingError) case noInternetConnection case timeout case internalServerError case other(statusCode: Int, response: HTTPURLResponse) } case requestError(RequestError) case serverError(ServerError) } and note that Foundation has NSError with a bunch of well defined error code ready to use....

December 14, 2020 · 2 min · 249 words · Khoa

How to programatically select row in List in SwiftUI

Issue #711 List has a selection parameter where we can pass selection binding. As we can see here selection is of type optional Binding<Set<SelectionValue>>? where SelectionValue is any thing conforming to Hasable @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public struct List<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View { @available(watchOS, unavailable) public init(selection: Binding<Set<SelectionValue>>?, @ViewBuilder content: () -> Content) So we can programatically control selection by tagging row with our own Tag...

December 13, 2020 · 1 min · 113 words · Khoa

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 · 199 words · Khoa

How to mock UNNotificationResponse in unit tests

Issue #708 The best way to test is to not have to mock at all. The second best way is to have your own abstraction over the things you would like to test, either it is in form of protocol or some function injection. But in case you want a quick way to test things, and want to test as real as possible, then for some cases we can be creative to mock the real objects....

December 7, 2020 · 3 min · 507 words · Khoa

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 · 131 words · Khoa

How to convert struct to Core Data NSManagedObject

Issue #706 Use Mirror and set key value as NSManagedObject subclasses from NSObject import CoreData final class ManagedObjectConverter { func convert<M>(m: M, context: NSManagedObjectContext) throws -> NSManagedObject { let entityName = String(describing: m) guard let entityDescription = NSEntityDescription.entity( forEntityName: entityName, in: context ) else { throw AppError.parsing } let managedObject = NSManagedObject( entity: entityDescription, insertInto: context ) let mirror = Mirror(reflecting: m) guard mirror.displayStyle == .struct else { throw AppError.parsing } for case let (label?...

December 7, 2020 · 1 min · 91 words · Khoa

How to format ISO date string in Javascript

Issue #705 Supposed we have date in format ISO8601 and we want to get rid of T and millisecond and timezone Z const date = new Date() date.toDateString() // "Sat Dec 05 2020" date.toString() // "Sat Dec 05 2020 06:58:19 GMT+0100 (Central European Standard Time)" date.toISOString() // "2020-12-05T05:58:19.081Z" We can use toISOString, then split base on the dot . then remove character T date .toISOString() .split('.')[0] .replace('T', ' ')

December 5, 2020 · 1 min · 69 words · Khoa

How to declare Error in Swift

Issue #704 We used to declare enum that conforms to Error, but any type like struct or class can conform to Error as well. enum NetworkError: Error { case failToCreateRequest case failToParseResponse case failToReachServe } struct DetailError: Error { let networkError: Error let createdAt: Date let tag: String } final class TrackError: Error { let trackId: String let detailError: DetailError let trackSession: String init(trackId: String, detailError: DetailError, trackSession: String) { self....

December 5, 2020 · 1 min · 103 words · Khoa

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 · 1834 words · Khoa