Skip to content

Instantly share code, notes, and snippets.

@shirakaba
Last active May 24, 2020 15:08
Show Gist options
  • Save shirakaba/7a00363b23841f8630af1376fe26a3ce to your computer and use it in GitHub Desktop.
Save shirakaba/7a00363b23841f8630af1376fe26a3ce to your computer and use it in GitHub Desktop.
LinguaBrowse Mac (React Native macOS + iOS Swift app) old AppDelegate
//
// AppDelegate.swift
// LinguaBrowse
//
// Created by jamie on 07/06/2018.
// Copyright © 2018 Facebook. All rights reserved.
//
import Foundation
import StoreKit
#if canImport(UIKit)
import UIKit
import PKHUD
import Strongbox
#elseif canImport(Cocoa)
import Cocoa
import AppKit
import PKHUDMACOS
#endif
enum ToggleableButtonIdentifiers: String {
case toggleLinks
case toggleRt
}
#if canImport(UIKit)
// http://www.ikantam.com/blog/swift-modules-in-react-native
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var bridge: RCTBridge!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
let rootView: RCTRootView = RCTRootView(bridge: RNBridgeDelegate.sharedInstance.bridge, moduleName: "LinguaBrowse", initialProperties: nil)
RNBridgeDelegate.sharedInstance.bridge = rootView.bridge
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let rootViewController = UIViewController()
rootViewController.view = rootView
self.window!.rootViewController = rootViewController;
self.window!.makeKeyAndVisible()
return true
}
}
#else
// https://stackoverflow.com/questions/30401118/what-has-replaced-the-main-m-file-in-xcode-6-3
// @NSApplicationMain
class AppDelegate: NSObject, /*: RCTEventEmitter, */ NSApplicationDelegate, NSToolbarDelegate, NSWindowDelegate, NSSearchFieldDelegate {
var restorationClass: NSWindowRestoration.Type?
var window: NSWindow?
// var bridge: RCTBridge!
var argv: NSMutableArray!
// var sourceURL: URL!
var langToLearnMenuItem: NSMenuItem!
var definitionsMenuItem: NSMenuItem!
var navSeg: NSSegmentedControl!
var backButton: ReduxAwareToolbarButton!
var forwardButton: ReduxAwareToolbarButton!
var refreshButton: ReduxAwareToolbarButton!
var toggleLinksButton: ReduxAwareToolbarButton!
var toggleRtButton: ReduxAwareToolbarButton!
var shopButton: ToolbarButton!
let searchField: NSSearchField = NSSearchField()
let shopWindow = ShopWindowVC()
override init(){
super.init()
// let wv = WKWebView(frame: NSRect(x: 0, y: 0, width: 0, height: 0))
// -- Init Window
let contentSize: NSRect = NSMakeRect(200, 500, 1000, 500);
// http://robin.github.io/cocoa/mac/2016/03/28/title-bar-and-toolbar-showcase/
// To embrace translucency: https://asciiwwdc.com/2014/sessions/220
self.window = DraggyWindow(contentRect: contentSize, styleMask: [.titled, .resizable, .miniaturizable, .closable /*, .fullSizeContentView */], backing: .buffered, defer: false)
let windowController: NSWindowController = NSWindowController(window: self.window)
self.window?.title = "LinguaBrowse"
self.window?.titlebarAppearsTransparent = false
self.window?.titleVisibility = .hidden
self.window?.appearance = NSAppearance(named: .vibrantLight)
windowController.showWindow(self.window)
windowController.shouldCascadeWindows = false;
windowController.windowFrameAutosaveName = NSWindow.FrameAutosaveName(rawValue: "LinguaBrowse")
self.searchField.isEnabled = false
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
print("version (CFBundleShortVersionString): \(version)")
if(version == "1.0.0" || version == "1.0.1"){
// Stores as an __NSCFBoolean, which can be cast to Bool when unarchived.
// For macOS, if the unarchived value is printed without casting, the string "1" or parhaps the number 1 is printed.
let _ : Bool = Strongbox().archive(true, key: Products.EarlyBird)
}
}
// self.setDefaultURL()
// TODO: accessibility labels
if #available(macOS 10.12, *) {
self.navSeg = NSSegmentedControl(images: [NSImage(named: .goBackTemplate)!, NSImage(named: .goForwardTemplate)!], trackingMode: .momentary, target: self, action: #selector(AppDelegate.onNavSegmentPress(_:)))
} else {
let seg: NSSegmentedControl = NSSegmentedControl()
seg.segmentCount = 2
seg.trackingMode = .momentary
seg.setImage(NSImage(named: .leftFacingTriangleTemplate)!, forSegment: 0)
seg.setImage(NSImage(named: .rightFacingTriangleTemplate)!, forSegment: 1)
seg.target = self
seg.action = #selector(AppDelegate.onNavSegmentPress(_:))
self.navSeg = seg
}
self.navSeg.segmentStyle = .separated
self.navSeg.sizeToFit()
self.navSeg.target = self // redundant.
// self.backButton = ReduxAwareToolbarButton(activeImage: NSImage(named: .goBackTemplate)!, bridgeDelegate: RNBridgeDelegate.sharedInstance) { (redux: Redux) -> Void in
// redux.sendEvent(withName: ReduxEvents.navigateHistory.rawValue, body: ["value": -1])
// }
// self.forwardButton = ReduxAwareToolbarButton(activeImage: NSImage(named: .goForwardTemplate)!, bridgeDelegate: RNBridgeDelegate.sharedInstance) { (redux: Redux) -> Void in
// redux.sendEvent(withName: ReduxEvents.navigateHistory.rawValue, body: ["value": 1])
// }
self.refreshButton = ReduxAwareToolbarButton(activeImage: NSImage(named: .refreshTemplate)!, bridgeDelegate: RNBridgeDelegate.sharedInstance, frame: NSMakeRect(0, 0, 50, 35)) { (redux: Redux) -> Void in
redux.sendEvent(withName: ReduxEvents.navigateHistory.rawValue, body: ["value": 0])
}
self.shopButton = ToolbarButton(activeImage: NSImage(named: .applicationIcon)!, inactiveImage: nil, startActive: true, frame: nil, action: { () -> Void in
print("Clicked shop button")
// self.shopWindow.view.frame = CGRect(x: 0, y: 0, width: 400, height: 300)
// self.window?.contentView = self.shopWindow.view
let shopWindow = ShopWindow(contentViewController: self.shopWindow)
self.shopWindow.registerWindowForProductsTable(shopWindow)
shopWindow.delegate = shopWindow
let minWidth: CGFloat = ProductsTable.colWidths.reduce(0, +)
let PKHUDMACOSHeight: CGFloat = 156.0
let widthMinusTitlebar: CGFloat = minWidth - 22
shopWindow.contentMinSize = NSSize(width: minWidth, height: PKHUDMACOSHeight)
shopWindow.setContentSize(NSSize(width: minWidth + 10, height: widthMinusTitlebar))
shopWindow.title = "Shop"
shopWindow.standardWindowButton(.miniaturizeButton)?.isHidden = true // yellow button
shopWindow.standardWindowButton(.zoomButton)?.isHidden = true // green button
shopWindow.standardWindowButton(.fullScreenButton)?.isHidden = true
// shopWindow.standardWindowButton(.closeButton)?.isEnabled = false
// shopWindow.showsToolbarButton = true
// shopWindow.titleVisibility = .visible
// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Sheets/Tasks/UsingAppModalDialogs.html#//apple_ref/doc/uid/TP40001207-BABFIBIA
// NSApplication.shared.mainWindow?.beginSheet(shopWindow, completionHandler: { (response: NSApplication.ModalResponse) in })
NSApplication.shared.runModal(for: shopWindow)
// let shopWindowController = NSWindowController(window: shopWindow)
// shopWindowController.showWindow(self)
})
// TODO: set initial state for toggleLinksButton from stored Redux userPrefs.
self.toggleLinksButton = ReduxAwareToolbarButton(activeImage: NSImage(rawName: "link_active").tinting(with: NSColor.gray), inactiveImage: NSImage(rawName: "link_inactive").tinting(with: NSColor.gray), startActive: true, bridgeDelegate: RNBridgeDelegate.sharedInstance, frame: NSMakeRect(0, 0, 50, 40)) { (redux: Redux) -> Void in
redux.sendEvent(withName: ReduxEvents.toggleLinks.rawValue, body: ["toActive": !self.toggleLinksButton.active]) // Where 'active' means 'links active'.
HUD.dimsBackground = false
HUD.allowsInteraction = true
HUD.flash(.label(self.toggleLinksButton.active ? "Links deactivated." : "Links activated."), onView: self.window!.contentView, delay: 1.0) { _ in }
// HUD.show(.label(self.toggleLinksButton.active ? "Links deactivated." : "Links activated."), onView: self.window!.contentView, delay: 1.0) { _ in }
// HUD.flash(.label(self.toggleLinksButton.active ? "Links deactivated." : "Links activated."), onView: self.window!.contentView)
// HUD.flash(.label(self.toggleLinksButton.active ? "Links deactivated." : "Links activated."), delay: 1.0) { _ in }
}
self.toggleRtButton = ReduxAwareToolbarButton(activeImage: NSImage(rawName: "togglert_active").tinting(with: NSColor.gray), inactiveImage: NSImage(rawName: "togglert_inactive").tinting(with: NSColor.gray), startActive: true, bridgeDelegate: RNBridgeDelegate.sharedInstance, frame: NSMakeRect(0, 0, 50, 40)) { (redux: Redux) -> Void in
redux.sendEvent(withName: ReduxEvents.toggleRt.rawValue, body: ["toVisible": !self.toggleRtButton.active]) // Where 'active' means 'rtVisible'.
HUD.dimsBackground = false
HUD.allowsInteraction = true
HUD.flash(.label(self.toggleRtButton.active ? "Transcriptions hidden." : "Transcriptions visible."), onView: self.window!.contentView, delay: 1.0) { _ in }
}
// Disabled until Redux calls up to it.
// self.backButton.button.isEnabled = false
// self.forwardButton.button.isEnabled = false
self.navSeg.setEnabled(false, forSegment: 0)
self.navSeg.setEnabled(false, forSegment: 1)
self.toggleLinksButton.button.isEnabled = false
self.toggleRtButton.button.isEnabled = false
self.refreshButton.button.isEnabled = false
// -- Init Toolbar
let toolbar: NSToolbar = NSToolbar(identifier: NSToolbar.Identifier(rawValue: "mainToolbar"))
toolbar.delegate = self
toolbar.sizeMode = .regular // regular-size controls and 32 x 32 pixel icons
self.window?.toolbar = toolbar
// -- Init Menu
self.setUpMainMenu()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// func setDefaultURL(){
// self.sourceURL = RNBridgeDelegate.sharedInstance.sourceURL
// }
func setUpMainMenu(){
let mainMenu: NSMenu = NSMenu(title: "")
// NSMenuItem *containerItem = [[NSMenuItem alloc] init];
let containerItem: NSMenuItem = NSMenuItem()
let rootMenu: NSMenu = NSMenu(title: "")
containerItem.submenu = rootMenu
mainMenu.addItem(containerItem)
rootMenu.addItem(withTitle: "Quit LinguaBrowse", action: #selector(AppDelegate.terminate(_:)), keyEquivalent: "q")
NSApp.mainMenu = mainMenu
let editItemContainer: NSMenuItem = NSMenuItem()
let editMenu: NSMenu = NSMenu(title: "Edit")
editItemContainer.submenu = editMenu
editMenu.autoenablesItems = false
editMenu.addItem(withTitle: "Undo", action: #selector(AppDelegate.undo), keyEquivalent: "z")
editMenu.addItem(withTitle: "Redo", action: #selector(AppDelegate.redo), keyEquivalent: "Z")
editMenu.addItem(withTitle: "Cut", action: #selector(AppDelegate.cut), keyEquivalent: "x")
editMenu.addItem(withTitle: "Copy", action: #selector(AppDelegate.copy(_:)), keyEquivalent: "c")
editMenu.addItem(withTitle: "Paste", action: #selector(AppDelegate.paste(_:)), keyEquivalent: "v")
editMenu.addItem(withTitle: "SelectAll", action: #selector(AppDelegate.selectAll(_:)), keyEquivalent: "a")
NSApp.mainMenu?.addItem(editItemContainer)
let settingsItemContainer: NSMenuItem = NSMenuItem()
let settingsMenu: NSMenu = NSMenu(title: "Settings")
// settingsMenu.addItem(withTitle: "Whatever", action: #selector(AppDelegate.undo), keyEquivalent: "z")
settingsMenu.autoenablesItems = false
settingsItemContainer.submenu = settingsMenu
self.langToLearnMenuItem = AppDelegate.addLangSubmenu("Language to learn", menu: settingsMenu, data: LocaleUtils.supportedLanguageIds, selector: #selector(setByLang(_:)), itemTarget: self, menuIdentifier: "lang")
self.langToLearnMenuItem.isEnabled = false
self.definitionsMenuItem = AppDelegate.addLangSubmenu("Dictionary definitions", menu: settingsMenu, data: LocaleUtils.supportedLanguageIds, selector: #selector(setByLang(_:)), itemTarget: self, menuIdentifier: "def")
self.definitionsMenuItem.isEnabled = false
// let dictionaryDefinitionsMenuItem: NSMenuItem = NSMenuItem()
// dictionaryDefinitionsMenuItem.title = "Dictionary definitions"
// let dictionaryDefinitionsMenu: NSMenu = NSMenu() // Title won't be displayed; submenu's will.
// dictionaryDefinitionsMenuItem.submenu = dictionaryDefinitionsMenu
//
// LocaleUtils.supportedLanguageIds.forEach {
// let item: NSMenuItem = NSMenuItem(title: LocaleUtils.getColloquialNameForLanguageId($0), action: #selector(setDictionaryDefinitions(_:)), keyEquivalent: "")
// item.target = self // Hacking with macOS, p465
// item.isEnabled = true
// dictionaryDefinitionsMenu.addItem(item)
// }
// dictionaryDefinitionsMenu.autoenablesItems = false
// settingsMenu.addItem(dictionaryDefinitionsMenuItem)
NSApp.mainMenu?.addItem(settingsItemContainer)
}
static func addLangSubmenu(_ title: String, menu: NSMenu, data: [String], selector: Selector, itemTarget: AnyObject, menuIdentifier: String) -> NSMenuItem {
let dictionaryDefinitionsMenuItem: NSMenuItem = NSMenuItem()
dictionaryDefinitionsMenuItem.title = title
let dictionaryDefinitionsMenu: NSMenu = NSMenu() // Title won't be displayed; submenu's will.
dictionaryDefinitionsMenuItem.submenu = dictionaryDefinitionsMenu
data.forEach {
let item: NSMenuItem = NSMenuItem(title: LocaleUtils.getColloquialNameForLanguageId($0), action: selector, keyEquivalent: "")
item.identifier = NSUserInterfaceItemIdentifier(rawValue: "\(menuIdentifier)-\($0)")
item.target = itemTarget // Hacking with macOS, p465
item.isEnabled = true
dictionaryDefinitionsMenu.addItem(item)
}
dictionaryDefinitionsMenu.autoenablesItems = false
menu.addItem(dictionaryDefinitionsMenuItem)
return dictionaryDefinitionsMenuItem
}
// override func supportedEvents() -> [String]! {
// return ["onSearchExample", "setLanguageToStudy", "setDictionaryDefinitions"]
// }
@objc func setByLang(_ sender: NSMenuItem?){
guard let item: NSMenuItem = sender else { return; }
// print(item.title)
item.menu?.items.forEach { $0.state = .off }
item.state = .on
guard let id: NSUserInterfaceItemIdentifier = item.identifier else { return; }
guard let reduxInstance: Redux = RNBridgeDelegate.sharedInstance.bridge.module(forName: "Redux") as? Redux else {
return print("unable to get reference to redux module instance!")
}
if(id.rawValue.starts(with: "lang")){
print("Set 'language to study' to: \(item.title)")
reduxInstance.sendEvent(withName: ReduxEvents.setLanguageToStudy.rawValue, body: ["lang": LocaleUtils.getLanguageIdForColloquialName(item.title)])
reduxInstance.sendEvent(withName: ReduxEvents.navigateHistory.rawValue, body: ["value": 0])
// RNBridgeDelegate.sharedInstance.bridge.eventDispatcher().sendDeviceEvent(withName: ReduxEvents.setLanguageToStudy.rawValue, body: ["lang": LocaleUtils.getLanguageIdForColloquialName(item.title)])
// self.sendEvent(withName: ReduxEvents.setLanguageToStudy.rawValue, body: ["lang": item.title])
} else if(id.rawValue.starts(with: "def")){
print("Set 'dictionary definitions' to: \(item.title)")
reduxInstance.sendEvent(withName: ReduxEvents.setDictionaryDefinitions.rawValue, body: ["lang": LocaleUtils.getLanguageIdForColloquialName(item.title)])
// RNBridgeDelegate.sharedInstance.bridge.eventDispatcher().sendDeviceEvent(withName: ReduxEvents.setDictionaryDefinitions.rawValue, body: ["lang": LocaleUtils.getLanguageIdForColloquialName(item.title)])
// self.sendEvent(withName: ReduxEvents.setDictionaryDefinitions.rawValue, body: ["lang": LocaleUtils.getLanguageIdForColloquialName(item.title)])
}
}
@objc func setLanguageTolearn(_ sender: NSMenuItem?){
guard let item: NSMenuItem = sender else { return; }
print(item.title)
item.menu?.items.forEach { $0.state = .off }
item.state = .on
}
/* To be called by the app. */
func setLanguageTolearn(langId: String, which: String){
var menuItem: NSMenuItem!
// var menu: NSMenu!
switch which {
case "languageToStudy":
menuItem = self.langToLearnMenuItem
case "dictionaryDefinitions":
menuItem = self.definitionsMenuItem
default:
menuItem = nil;
}
guard menuItem != nil else { return; }
guard let submenu = menuItem.submenu else { return; }
submenu.items.forEach { $0.state = .off }
let matches: [NSMenuItem] = submenu.items.filter { LocaleUtils.getLanguageIdForColloquialName($0.title) == langId }
guard matches.count == 1 else { return; }
matches[0].state = .on
menuItem.isEnabled = true
}
@objc func terminate(_ someVar: Any?){
print("terminate stub")
}
@objc func cut(_ someVar: Any?){
print("cut stub")
}
@objc func copy(_ someVar: Any?){
print("copy stub")
}
@objc func paste(_ someVar: Any?){
print("paste stub")
}
@objc func selectAll(_ someVar: Any?){
print("selectAll stub")
}
@objc func undo(){
self.window?.undoManager?.undo()
}
@objc func redo(){
self.window?.undoManager?.redo()
}
func loadSource(for bridge: RCTBridge!, onProgress: RCTSourceLoadProgressBlock!, onComplete loadCallback: RCTSourceLoadBlock!) {
RCTJavaScriptLoader.loadBundle(at: RNBridgeDelegate.sharedInstance.sourceURL(for: bridge), onProgress: onProgress, onComplete: loadCallback)
}
func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
// return @[NSToolbarFlexibleSpaceItemIdentifier, @"searchBar", NSToolbarFlexibleSpaceItemIdentifier, @"resetButton"];
// return NSToolbar(identifier: .init(""))
return [
// NSToolbarItem.Identifier(rawValue: "backButton"),
// NSToolbarItem.Identifier(rawValue: "forwardButton"),
NSToolbarItem.Identifier(rawValue: "navSegment"),
NSToolbarItem.Identifier(rawValue: "refreshButton"),
NSToolbarItem.Identifier.flexibleSpace,
NSToolbarItem.Identifier(rawValue: "toggleLinksButton"),
NSToolbarItem.Identifier(rawValue: "toggleRtButton"),
NSToolbarItem.Identifier.flexibleSpace,
NSToolbarItem.Identifier(rawValue: "searchBar"),
NSToolbarItem.Identifier.flexibleSpace,
NSToolbarItem.Identifier(rawValue: "shopButton"),
// NSToolbarItem.Identifier(rawValue: "resetButton")
]
}
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
return [
// NSToolbarItem.Identifier(rawValue: "backButton"),
// NSToolbarItem.Identifier(rawValue: "forwardButton"),
NSToolbarItem.Identifier(rawValue: "navSegment"),
NSToolbarItem.Identifier(rawValue: "refreshButton"),
NSToolbarItem.Identifier.flexibleSpace,
NSToolbarItem.Identifier(rawValue: "toggleLinksButton"),
NSToolbarItem.Identifier(rawValue: "toggleRtButton"),
NSToolbarItem.Identifier.flexibleSpace,
NSToolbarItem.Identifier(rawValue: "searchBar"),
NSToolbarItem.Identifier.flexibleSpace,
// NSToolbarItem.Identifier(rawValue: "shopButton"),
// NSToolbarItem.Identifier(rawValue: "resetButton")
]
}
func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
let item: NSToolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
switch(itemIdentifier.rawValue){
case "searchBar":
// let searchField: NSSearchField = NSSearchField()
self.searchField.setFrameSize(NSMakeSize(400, searchField.intrinsicContentSize.height))
self.searchField.delegate = self
// https://developer.apple.com/documentation/appkit/nssearchfield/1533976-sendswholesearchstring?language=objc
self.searchField.sendsWholeSearchString = true
self.searchField.cell?.sendsActionOnEndEditing = false
self.searchField.recentsAutosaveName = NSSearchField.RecentsAutosaveName(rawValue: "mainSearchField")
self.searchField.placeholderString = "Search Example"
self.searchField.action = #selector(AppDelegate.searchURLorQuery(_:))
item.view = self.searchField
return item
case "resetButton":
// let button: NSButton = makeToolbarButton(imageName: .refreshTemplate, selector: #selector(AppDelegate.resetBridgeToDefault))
let resetToolbarButton: ToolbarButton = ToolbarButton(activeImage: NSImage(named: .refreshTemplate)!) { () -> Void in
self.resetBridgeToDefault()
}
item.view = resetToolbarButton.button
return item
// case "backButton":
// item.view = self.backButton.button
// return item
// case "forwardButton":
// item.view = self.forwardButton.button
// return item
case "refreshButton":
item.view = self.refreshButton.button
return item
case "navSegment":
item.view = self.navSeg
return item
case "toggleLinksButton":
item.view = self.toggleLinksButton.button
return item
case "toggleRtButton":
item.view = self.toggleRtButton.button
return item
case "shopButton":
item.view = self.shopButton.button
return item
default:
return nil
}
}
@objc func onNavSegmentPress(_ sender: NSSegmentedControl){
guard let bridge: RCTBridge = RNBridgeDelegate.sharedInstance.bridge else {
return print("Bridge not yet initialised!")
}
guard let redux: Redux = bridge.module(forName: "Redux") as? Redux else {
return print("Unable to get reference to 'Redux' module instance!")
}
switch(sender.selectedSegment){
case 0:
redux.sendEvent(withName: ReduxEvents.navigateHistory.rawValue, body: ["value": -1])
case 1:
redux.sendEvent(withName: ReduxEvents.navigateHistory.rawValue, body: ["value": 1])
case 2:
redux.sendEvent(withName: ReduxEvents.navigateHistory.rawValue, body: ["value": 0])
default:
break
}
}
@objc func resetBridgeToDefault(){
// self.setDefaultURL()
RNBridgeDelegate.sharedInstance.bridge.reload()
}
@IBAction
@objc func searchURLorQuery(_ sender: NSTextField?){
guard let textField = sender else { return; }
guard textField.stringValue.lengthOfBytes(using: .utf8) > 0 else { return; }
// Testing for whitespace prevents regex crash for: "http://www.bing.com/search?q=sonic+boom 2"
var url: URL?
if(textField.stringValue.rangeOfCharacter(from: .whitespacesAndNewlines) == nil && Utils.validateURL(textField.stringValue)){
// textField.stringValue.hasPrefix("www.") ? "http://" + textField.stringValue : textField.stringValue)
guard let encodedURL: String = textField.stringValue.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
return Utils.makeSimpleAlert(title: "Invalid search term", message: "Invalid characters used in search term; please input only UTF-8 characters so that URL-encoding will succeed.").beginSheetModal(for: self.window!, completionHandler: { (modalResponse: NSApplication.ModalResponse) -> Void in
})
}
url = URL(string: encodedURL)
guard url != nil else { return; }
// WebView requires a protocol in order to load a URL (otherwise fires error). If people want eg. ftp://, they'll have to specify it explicitly, but it IS supported.
if(url!.scheme == nil){
// Appears this is redundant, as validateURL() returns false for "//www.example.com".
guard !encodedURL.hasPrefix("//") else {
return Utils.makeSimpleAlert(title: "Invalid URL", message: "Relative protocols are not accepted; please enter a URL in the format \"http://www.example.com\".").beginSheetModal(for: self.window!, completionHandler: { (modalResponse: NSApplication.ModalResponse) -> Void in
})
}
// We default to HTTP protocol. If HTTPS is available, it seems to redirect there anyway.
url = URL(string: "http://" + encodedURL)
}
} else {
guard let searchTerms: String = textField.stringValue.replacingOccurrences(of: " ", with: "+").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
return Utils.makeSimpleAlert(title: "Invalid search term", message: "Invalid characters used in search term; please input only UTF-8 characters so that URL-encoding will succeed.").beginSheetModal(for: self.window!, completionHandler: { (modalResponse: NSApplication.ModalResponse) -> Void in
})
}
url = URL(string: "http://www.bing.com/search?q=\(String(describing: searchTerms))")!
}
guard url != nil else {
return Utils.makeSimpleAlert(title: "Invalid URL", message: "URL invalid; please enter a URL in the format \"http://www.example.com\".").beginSheetModal(for: self.window!, completionHandler: { (modalResponse: NSApplication.ModalResponse) -> Void in
})
}
// in Obj-C: bridge.modules[@"Redux"]
guard let redux: Redux = RNBridgeDelegate.sharedInstance.bridge.module(forName: "Redux") as? Redux else {
return print("unable to get reference to redux module instance!")
}
redux.sendEvent(withName: ReduxEvents.onSearchExample.rawValue, body: ["query": url!.absoluteString])
// self.sendEvent(withName: ReduxEvents.onSearchExample.rawValue, body: ["query": sender?.stringValue])
// RNBridgeDelegate.sharedInstance.bridge.eventDispatcher().sendDeviceEvent(withName: ReduxEvents.onSearchExample.rawValue, body: ["query": url!.absoluteString])
// if ([[sender stringValue] containsString:@"http"]) {
// _sourceURL =[NSURL URLWithString:[sender stringValue]];
// _bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:nil];
// NSString * moduleName = [_sourceURL.lastPathComponent stringByReplacingOccurrencesOfString:@".macos.bundle" withString:@""];
// RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:_bridge
// moduleName:moduleName
// initialProperties:nil];
// NSLog(@"moduleName: %@", moduleName);
// [self.window setContentView:rootView];
// } else {
// [_bridge.eventDispatcher sendDeviceEventWithName:@"onSearchExample"
// body:@{@"query": [sender stringValue]}
// ];
// }
}
func setSearchFieldURL(_ URL: String){
self.searchField.stringValue = URL
}
private var ocrPort: Int = 7355;
private var pdfPort: Int = 8888;
func setServicePort(_ service: String, _ port: Int){
if(service == "ocr"){
self.ocrPort = port;
} else if(service == "pdf"){
self.pdfPort = port;
}
}
// func applicationWillFinishLaunching(_ notification: Notification) {
// }
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
func applicationDidFinishLaunching(_ notification: Notification) {
let purchaseObserver: SKPaymentTransactionObserver = IAPHelper(productIds: Products.productIdentifiers)
Products.store = purchaseObserver as! IAPHelper
SKPaymentQueue.default().add(purchaseObserver)
// print("didFinishLaunching, with argv: \(self.argv)")
// https://github.com/ptmt/react-native-macos/blob/master/RNTester/RNTester/AppDelegate.m#L70
RNBridgeDelegate.sharedInstance.bridge = RCTBridge(delegate: RNBridgeDelegate.sharedInstance, launchOptions: [ "argv" : self.argv ])
// https://stackoverflow.com/questions/31583605/how-to-change-content-view-of-window
// TODO: Try out self.window.contentViewController.view instead.
self.window?.makeMain()
// self.window?.setFrame(NSRect(x:0, y:0, width: 1280, height: 800), display: true)
// self.window?.contentViewController?.view = RCTRootView(bridge: RNBridgeDelegate.sharedInstance.bridge, moduleName: "LinguaBrowse", initialProperties: nil)
// if(Products.isPurchased(Products.RemoveAds))
self.window?.contentView = RCTRootView(bridge: RNBridgeDelegate.sharedInstance.bridge, moduleName: "LinguaBrowse", initialProperties: nil)
// if(State.wasPresentedTrialChoice()){
// // if(Products.isPurchased(<#T##productIdentifier: String##String#>))
// self.window?.contentView = RCTRootView(bridge: RNBridgeDelegate.sharedInstance.bridge, moduleName: "LinguaBrowse", initialProperties: nil)
// } else {
// firstTimeStartupAlert()
// }
// self.window?.registerForDraggedTypes([NSPasteboard.PasteboardType.fileURL])
self.window?.registerForDraggedTypes([
NSPasteboard.PasteboardType(rawValue: kUTTypeFileURL as String),
NSPasteboard.PasteboardType(rawValue: kUTTypeItem as String)
])
}
func firstTimeStartupAlert() {
let alert: NSAlert = Utils.makeSimpleAlert(title: "Begin free trial", message: "Begin your free 14-day trial of LinguaBrowse?")
alert.addButton(withTitle: "Exit")
alert.beginSheetModal(for: self.window!, completionHandler: { (modalResponse: NSApplication.ModalResponse) -> Void in
if(modalResponse == NSApplication.ModalResponse.alertFirstButtonReturn){
State.setPresentedTrialChoice(true)
self.window?.contentView = RCTRootView(bridge: RNBridgeDelegate.sharedInstance.bridge, moduleName: "LinguaBrowse", initialProperties: nil)
} else {
NSApplication.shared.terminate(self)
}
})
}
func applicationWillTerminate(_ notification: Notification) {
SKPaymentQueue.default().remove(Products.store)
}
}
#endif
extension NSImage {
convenience init(named name: String, width: Double, height: Double){
self.init(named: NSImage.Name(rawValue: name))!
// self.size = CGSize(width: width, height: height)
}
convenience init(rawName: String){
self.init(named: NSImage.Name(rawValue: rawName))!
self.size = CGSize(width: 22, height: 22)
}
func tinting(with tintColor: NSColor) -> NSImage {
guard let cgImage = self.cgImage(forProposedRect: nil, context: nil, hints: nil) else { return self }
return NSImage(size: size, flipped: false) { bounds in
guard let context = NSGraphicsContext.current?.cgContext else { return false }
tintColor.set()
context.clip(to: bounds, mask: cgImage)
context.fill(bounds)
return true
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment