Last active
May 24, 2020 15:08
-
-
Save shirakaba/7a00363b23841f8630af1376fe26a3ce to your computer and use it in GitHub Desktop.
LinguaBrowse Mac (React Native macOS + iOS Swift app) old AppDelegate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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