How to remove duplicates based on property in array in Swift

Issue #441 Make object conform to Equatable and Hashable and use Set to eliminate duplications. Set loses order so we need to sort after uniquing struct App: Equatable, Hashable { static func == (lhs: App, rhs: App) -> Bool { return lhs.name == rhs.name && lhs.bundleId == rhs.bundleId } func hash(into hasher: inout Hasher) { hasher.combine(name) hasher.combine(bundleId) } } let uniqueApps = Array(Set(unsortedApps)) let apps = uniqueApps.sorted(by: { $0.name.lowercased() < $1....

October 3, 2019 · 1 min · 72 words · Khoa

How to get url of app on the iOS AppStore

Issue #440 http://itunes.apple.com/[country]/app/[App–Name]/id[App-ID]?mt=8 For example https://apps.apple.com/nl/app/cutters/id1466739130

October 3, 2019 · 1 min · 6 words · Khoa

How to log Error in Swift

Issue #439 Use localizedDescription We need to provide NSLocalizedDescriptionKey inside user info dictionary, otherwise the outputt string may not be what we want. NSError https://developer.apple.com/documentation/foundation/nserror/1414418-localizeddescription A string containing the localized description of the error. The object in the user info dictionary for the key NSLocalizedDescriptionKey. If the user info dictionary doesn’t contain a value for NSLocalizedDescriptionKey, a default string is constructed from the domain and code. let error = NSError(domain: "com....

October 3, 2019 · 1 min · 164 words · Khoa

How to handle NSTextField change in macOS

Issue #438 Storyboard In Storyboard, NSTextField has an Action option that specify whether Send on Send on Enter only` should be the default behaviour. Code In code, NSTextFieldDelegate notifies whenever text field value changes, and target action notifies when Enter key is pressed import Cocoa class ViewController: NSViewController, NSTextFieldDelegate { @IBOutlet weak var textField: NSTextField! override func viewDidLoad() { super.viewDidLoad() textField.delegate = self } func controlTextDidChange(_ obj: Notification) { let textField = obj....

October 2, 2019 · 1 min · 116 words · Khoa

How to add section header to NSCollectionView in macOS

Issue #437 Normal Use Omnia for itemId extension HeaderCell.swift final class HeaderCell: NSView, NSCollectionViewSectionHeaderView { let label: NSTextField = withObject(NSTextField(labelWithString: "")) { $0.textColor = R.color.header $0.font = R.font.header $0.alignment = .left $0.lineBreakMode = .byTruncatingTail } override init(frame frameRect: NSRect) { super.init(frame: frameRect) addSubviews([label]) activate( label.anchor.centerY, label.anchor.left.constant(8) ) } required init?(coder: NSCoder) { fatalError() } } ViewController.swift collectionView.register( HeaderCell.self, forSupplementaryViewOfKind: NSCollectionView.elementKindSectionHeader, withIdentifier: HeaderCell.itemId ) func collectionView(_ collectionView: NSCollectionView, viewForSupplementaryElementOfKind kind: NSCollectionView.SupplementaryElementKind, at indexPath: IndexPath) -> NSView { if kind == NSCollectionView....

October 2, 2019 · 2 min · 284 words · Khoa

How to show log in Apple Script

Issue #436 Open Script Editor, use log command and look for 4 tabs in bottom panel Result, Messages, Events and Replies log "hello world"

October 1, 2019 · 1 min · 24 words · Khoa

How to show context menu from NSButton in macOS

Issue #435 Use NSMenu and popUp func showQuitMenu() { let menu = NSMenu() let aboutItem = NSMenuItem( title: "About", action: #selector(onAboutTouched(_:)), keyEquivalent: "" ) let quitItem = NSMenuItem( title: "Quit Hacker Pad", action: #selector(onQuitTouched(_:)), keyEquivalent: "" ) aboutItem.target = self quitItem.target = self menu.addItem(aboutItem) menu.addItem(quitItem) menu.popUp( positioning: aboutItem, at: bottomView.quitButton.frame.origin, in: bottomView ) } Use Omnia let menuHandler = MenuHandler() menuHandler.add(title: "About", action: { NSWorkspace.shared.open(URL(string: "https://onmyway133.github.io/")!) }) menuHandler.add(title: "Quit Hacker Pad", action: { NSApp....

October 1, 2019 · 1 min · 79 words · Khoa

How to handle UICollectionView reloadData with selected index path

Issue #434 When calling collectionView.reloadData(), selected indexpath stays the same, but be aware that order of data may have changed let selectedData = ... let indexPathForSelectedData = ... collectionView.scrollToItem( at: indexPathForSelectedData, at: .centeredHorizontally, animated: false )

September 30, 2019 · 1 min · 36 words · Khoa

How to make checked NSButton in AppKit

Issue #433 Use Omnia for convenient style and isOn property let checkButton = NSButton(checkboxWithTitle: "", target: nil, action: nil) checkButton.stylePlain(title: "Autosave", color: R.color.text, font: R.font.text) checkButton.isOn = true

September 30, 2019 · 1 min · 28 words · Khoa

How to save files in sandboxed macOS app

Issue #432 Read Container Directories and File System Access When you adopt App Sandbox, your application has access to the following locations: The app container directory. Upon first launch, the operating system creates a special directory for use by your app—and only by your app—called a container. Each user on a system gets an individual container for your app, within their home directory; your app has unfettered read/write access to the container for the user who ran it....

September 28, 2019 · 1 min · 92 words · Khoa

How to add AdMob to Android app

Issue #431 Use AdMob with Firebase https://firebase.google.com/docs/admob/android/quick-start build.gradle buildscript { repositories { google() jcenter() } dependencies { classpath 'com.google.gms:google-services:4.3.2' } } app/build.gradle class Version { class Firebase { static def analytics = "17.2.0" static def ads = "18.2.0" } } dependencies { implementation "com.google.firebase:firebase-analytics:$Version.Firebase.analytics" implementation "com.google.firebase:firebase-ads:$Version.Firebase.ads" } apply plugin: 'com.google.gms.google-services' Manifest.xml <manifest> <application> <!-- Sample AdMob App ID: ca-app-pub-3940256099942544~3347511713 --> <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="[ADMOB_APP_ID]"/> </application> </manifest> MyApplication.kt class MyApplication: Application() { override fun onCreate() { super....

September 27, 2019 · 1 min · 147 words · Khoa

How to notarize electron app

Issue #430 Use electron builder npm install electron-builder@latest --save-dev Prefer electron-builder over electron-packager Configuration https://www.electron.build/configuration/configuration package.json { "name": "icon_generator", "version": "1.3.0", "description": "A macOS app to generate app icons", "main": "babel/main.js", "repository": "https://github.com/onmyway133/IconGenerator", "author": "Khoa Pham", "license": "MIT", "scripts": { "start": "npm run babel && electron .", "babel": "babel ./src --out-dir ./babel --copy-files", "dist": "npm run babel && electron-builder" }, "build": { "appId": "com.onmyway133.IconGenerator", "buildVersion": "20", "productName": "Icon Generator", "icon": "....

September 26, 2019 · 2 min · 314 words · Khoa

How to use marked in WKWebView in AppKit

Issue #429 Use https://github.com/markedjs/marked <!doctype html> <html> <head> <meta charset="utf-8"/> <title>Marked in the browser</title> </head> <body> <div id="content"></div> <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> <script> document.getElementById('content').innerHTML = marked(`# Marked in the browser\n\nRendered by **marked**.`); </script> </body> </html> Should use back tick instead of ' to deal with multiline string, and escape back tick let markdown = markdown.replacingOccurrences(of: "`", with: "\\`") marked(`\(markdown)`); webView.loadHTMLString(string, baseURL: nil) For WKWebView to load even local content, need to enable Outgoing connections, and maybe Incoming connections in Sandbox

September 26, 2019 · 1 min · 78 words · Khoa

How to enable NSMenuItem in AppKit

Issue #428 Need to set target let item = NSMenuItem( title: title, action: #selector(onMenuItemClicked(_:)), keyEquivalent: "" ) item.target = self Sometimes, need to check autoenablesItems Indicates whether the menu automatically enables and disables its menu items. This property contains a Boolean value, indicating whether the menu automatically enables and disables its menu items. If set to true, menu items of the menu are automatically enabled and disabled according to rules computed by the NSMenuValidation informal protocol....

September 25, 2019 · 1 min · 84 words · Khoa

How to use generic NSCollectionView in macOS

Issue #427 See CollectionViewHandler Use ClickedCollectionView to detect clicked index for context menu. Embed NSCollectionView inside NSScrollView to enable scrolling import AppKit public class CollectionViewHandler<Item: Equatable, Cell: NSCollectionViewItem> : NSObject, NSCollectionViewDataSource, NSCollectionViewDelegateFlowLayout { public let layout = NSCollectionViewFlowLayout() public let scrollView = NSScrollView() public let collectionView = ClickedCollectionView() public var items = [Item]() public var itemSize: () -> CGSize = { .zero } public var configure: (Item, Cell) -> Void = { _, _ in } override init() { super....

September 24, 2019 · 2 min · 261 words · Khoa

How to use throttle and debounce in RxSwift

Issue #426 throttle https://rxmarbles.com/#throttle Returns an Observable that emits the first and the latest item emitted by the source Observable during sequential time windows of a specified duration. This operator makes sure that no two elements are emitted in less then dueTime. .throttle(.milliseconds(500), scheduler: MainScheduler.instance) In a time window, only the first item gets emitted. 💡 In other words, in a time window, take first and discard following. For example, when failure, we show error message but don’t want to show error messages consecutively....

September 19, 2019 · 1 min · 196 words · Khoa

How to use flatMap and compactMap in Swift

Issue #425 flatMap: map and flatten array of arrays compactMap: map and flatten array of optionals

September 19, 2019 · 1 min · 16 words · Khoa

How to use Firebase ID token

Issue #424 https://medium.com/@jwngr/demystifying-firebase-auth-tokens-e0c533ed330c One confusing point here that people often do not realize is that even though the custom token itself expires after one hour, a modern client SDK authenticated with that custom token will stay authenticated beyond that hour! What happens under the hood is that the custom token is sent to the Firebase Auth service in exchange for an ID token and refresh token pair which are used to keep the client SDK authenticated...

September 17, 2019 · 2 min · 249 words · Khoa

How to use custom domain for GitHub pages

Issue #423 In DNS settings Add 4 A records A @ 185.199.110.153 A @ 185.199.111.153 A @ 185.199.108.153 A @ 185.199.109.153 and 1 CNAME record CNAME www learntalks.github.io In GitHub Select custom domain and type learntalks.com In source public/CNAME learntalks.com

September 17, 2019 · 1 min · 40 words · Khoa

How to constrain to views inside UICollectionViewCell in iOS

Issue #422 To constrain views outside to elements inside UICollectionViewCell, we can use UILayoutGuide. Need to make layout guide the same constraints as the real elements let imageViewGuide = UILayoutGuide() collectionView.addLayoutGuide(imageViewGuide) NSLayoutConstraint.on([ imageViewGuide.topAnchor.constraint(equalTo: collectionView.topAnchor, constant: 16), imageViewGuide.heightAnchor.constraint(equalTo: collectionView.heightAnchor, multiplier: 0.5) ]) NSLayoutConstraint.on([ loadingIndicator.centerXAnchor.constraint(equalTo: collectionView.centerXAnchor), loadingIndicator.centerYAnchor.constraint(equalTo: imageViewGuide.centerYAnchor) ])

September 17, 2019 · 1 min · 47 words · Khoa