forked from I2P_Developers/i2p.i2p

* Fixed startup option so the launcher can start at OSX login/bootup. * Added I2P Browser to the list of "firefox" browsers to detect. * Changed hardcoded path lookup to native "registry" lookup for firefox application. * Made the advanced preferences table editable by the user. * Cleanup of old and/or unused code. * Bugfixes.
306 lines
9.6 KiB
Swift
306 lines
9.6 KiB
Swift
//
|
|
// PreferencesViewController.swift
|
|
// I2PLauncher
|
|
//
|
|
// Created by Mikal Villa on 07/11/2018.
|
|
// Copyright © 2018 The I2P Project. All rights reserved.
|
|
//
|
|
// Table view programming guide from Apple:
|
|
// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TableView/Introduction/Introduction.html
|
|
//
|
|
|
|
import Cocoa
|
|
import ServiceManagement
|
|
|
|
|
|
class PreferencesViewController: NSViewController {
|
|
|
|
enum ShowAsMode {
|
|
case bothIcon
|
|
case menubarIcon
|
|
case dockIcon
|
|
}
|
|
|
|
var changeDockMenubarIconTimer: Timer?
|
|
|
|
// MARK: - Advanced settings objects
|
|
@IBOutlet weak var advPrefTableView: NSTableView!
|
|
|
|
// MARK: - Launcher settings objects
|
|
@IBOutlet var radioDockIcon: NSButton?
|
|
@IBOutlet var radioMenubarIcon: NSButton?
|
|
@IBOutlet var radioBothIcon: NSButton?
|
|
@IBOutlet var checkboxStartWithOSX: NSButton?
|
|
@IBOutlet var checkboxStartFirefoxAlso: NSButton?
|
|
|
|
// MARK: - Router objects
|
|
@IBOutlet var checkboxStartWithLauncher: NSButton?
|
|
@IBOutlet var checkboxStopWithLauncher: NSButton?
|
|
@IBOutlet var buttonResetRouterConfig: NSButton?
|
|
|
|
@IBAction func onEnterInTextField(_ sender: NSTextField) {
|
|
let selectedRowNumber = advPrefTableView.selectedRow
|
|
print("Trying to store preferences")
|
|
let currentItem = Preferences.shared()[selectedRowNumber]
|
|
currentItem?.selectedValue = sender.stringValue
|
|
Preferences.shared()[selectedRowNumber] = currentItem
|
|
UserDefaults.standard.set(sender.stringValue, forKey: (currentItem?.name)!)
|
|
Preferences.shared().syncPref()
|
|
}
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
self.preferredContentSize = NSMakeSize(self.view.frame.size.width, self.view.frame.size.height)
|
|
|
|
if (advPrefTableView != nil) {
|
|
// For data feeding and view
|
|
advPrefTableView.delegate = self
|
|
advPrefTableView.dataSource = self
|
|
|
|
// Responding to Double-Click
|
|
advPrefTableView.target = self
|
|
advPrefTableView.doubleAction = #selector(tableViewDoubleClick(_:))
|
|
|
|
// Always redraw preference items which might have changed state since last draw.
|
|
Preferences.shared().redrawPrefTableItems()
|
|
|
|
// For sorting
|
|
advPrefTableView.tableColumns[0].sortDescriptorPrototype = NSSortDescriptor(key: "name", ascending: true)
|
|
advPrefTableView.tableColumns[1].sortDescriptorPrototype = NSSortDescriptor(key: "defaultValue", ascending: true)
|
|
advPrefTableView.tableColumns[2].sortDescriptorPrototype = NSSortDescriptor(key: "selectedValue", ascending: true)
|
|
|
|
self.advPrefTableView.isEnabled = Preferences.shared().allowAdvancedPreferenceEdit
|
|
}
|
|
|
|
// Update radio buttons to reflect runtime/stored preferences
|
|
self.updateRadioButtonEffect(mode: Preferences.shared().showAsIconMode, withSideEffect: false)
|
|
|
|
if (Preferences.shared().stopRouterOnLauncherShutdown) {
|
|
self.checkboxStopWithLauncher?.state = NSOnState;
|
|
} else {
|
|
self.checkboxStopWithLauncher?.state = NSOffState;
|
|
}
|
|
if (Preferences.shared().startRouterOnLauncherStart) {
|
|
self.checkboxStartWithLauncher?.state = NSOnState;
|
|
} else {
|
|
self.checkboxStartWithLauncher?.state = NSOffState;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
override func viewDidAppear() {
|
|
super.viewDidAppear()
|
|
|
|
// Update window title
|
|
self.parent?.view.window?.title = self.title!
|
|
}
|
|
|
|
// MARK: - Router settings functions
|
|
|
|
@IBAction func checkboxStartRouterWithLauncherClicked(_ sender: NSButton) {
|
|
switch sender.state {
|
|
case NSOnState:
|
|
print("on")
|
|
Preferences.shared().startRouterOnLauncherStart = true
|
|
case NSOffState:
|
|
print("off")
|
|
Preferences.shared().startRouterOnLauncherStart = false
|
|
case NSMixedState:
|
|
print("mixed")
|
|
default: break
|
|
}
|
|
}
|
|
|
|
@IBAction func checkboxStopRouterWithLauncherClicked(_ sender: NSButton) {
|
|
switch sender.state {
|
|
case NSOnState:
|
|
print("on")
|
|
Preferences.shared().stopRouterOnLauncherShutdown = true
|
|
case NSOffState:
|
|
print("off")
|
|
Preferences.shared().stopRouterOnLauncherShutdown = false
|
|
case NSMixedState:
|
|
print("mixed")
|
|
default: break
|
|
}
|
|
}
|
|
|
|
@IBAction func buttonResetRouterConfigClicked(_ sender: Any) {
|
|
// TODO: Add a modal dialog asking user if they are **really** sure
|
|
}
|
|
|
|
// MARK: - Launcher settings functions
|
|
|
|
@IBAction func checkboxStartLauncherOnOSXStartupClicked(_ sender: NSButton) {
|
|
let launcherAppId = "net.i2p.bootstrap.macosx.StartupItemApp"
|
|
let startupMgr = Startup()
|
|
switch sender.state {
|
|
case NSOnState:
|
|
print("on")
|
|
Preferences.shared()["I2Pref_startLauncherAtLogin"] = true
|
|
if (Preferences.shared()["I2Pref_useServiceManagementAsStartupTool"] as! Bool)
|
|
{
|
|
let success = SMLoginItemSetEnabled(launcherAppId as CFString, true)
|
|
print("SMLoginItemSetEnabled returned \(success)....")
|
|
} else {
|
|
startupMgr.addLoginItem(Startup.appPath())
|
|
print("Shared file for auto-startup added. (viewable via OSX Preferences -> Users -> Login Items)")
|
|
}
|
|
case NSOffState:
|
|
print("off")
|
|
Preferences.shared()["I2Pref_startLauncherAtLogin"] = false
|
|
if (Preferences.shared()["I2Pref_useServiceManagementAsStartupTool"] as! Bool)
|
|
{
|
|
let success = SMLoginItemSetEnabled(launcherAppId as CFString, false)
|
|
print("SMLoginItemSetEnabled returned \(success)....")
|
|
} else {
|
|
startupMgr.removeLoginItem(Startup.appPath())
|
|
print("Shared file for auto-startup removed (if any). (viewable via OSX Preferences -> Users -> Login Items)")
|
|
}
|
|
case NSMixedState:
|
|
print("mixed")
|
|
default: break
|
|
}
|
|
}
|
|
@IBAction func checkboxStartFirefoxAlsoAtLaunchClicked(_ sender: NSButton) {
|
|
switch sender.state {
|
|
case NSOnState:
|
|
print("launch firefox: on")
|
|
Preferences.shared().alsoStartFirefoxOnLaunch = true
|
|
case NSOffState:
|
|
print("launch firefox: off")
|
|
Preferences.shared().alsoStartFirefoxOnLaunch = false
|
|
case NSMixedState:
|
|
print("mixed")
|
|
default: break
|
|
}
|
|
}
|
|
|
|
// MARK: - Radio buttons functions
|
|
|
|
func updateDockMenubarIcons(_ mode: ShowAsMode) -> Bool {
|
|
// Update preferences with latest choise
|
|
Preferences.shared().showAsIconMode = mode
|
|
// Update runtime
|
|
switch mode {
|
|
case .bothIcon, .dockIcon:
|
|
// Show dock icon
|
|
print("Preferences: Update Dock Icon -> Show")
|
|
if (!getDockIconStateIsShowing()) {
|
|
return triggerDockIconShowHide(showIcon: true)
|
|
}
|
|
case .menubarIcon:
|
|
// Hide dock icon
|
|
print("Preferences: Update Dock Icon -> Hide")
|
|
if (getDockIconStateIsShowing()) {
|
|
return triggerDockIconShowHide(showIcon: false)
|
|
}
|
|
}
|
|
// Note: In reality, this won't ever happen.
|
|
// The switch statement above would return before this.
|
|
return false
|
|
}
|
|
|
|
func updateRadioButtonEffect(mode: ShowAsMode, withSideEffect: Bool = true) {
|
|
changeDockMenubarIconTimer?.invalidate()
|
|
|
|
radioDockIcon?.state = NSOffState
|
|
radioMenubarIcon?.state = NSOffState
|
|
radioBothIcon?.state = NSOffState
|
|
|
|
switch mode {
|
|
case .bothIcon:
|
|
radioBothIcon?.state = NSOnState
|
|
case .dockIcon:
|
|
radioDockIcon?.state = NSOnState
|
|
case .menubarIcon:
|
|
radioMenubarIcon?.state = NSOnState
|
|
}
|
|
|
|
if (withSideEffect) {
|
|
if #available(OSX 10.12, *) {
|
|
changeDockMenubarIconTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false, block: { _ in
|
|
// If we're on 10.12 or later
|
|
self.updateDockMenubarIcons(mode)
|
|
})
|
|
} else {
|
|
// Fallback on earlier versions
|
|
self.updateDockMenubarIcons(mode)
|
|
}
|
|
}
|
|
}
|
|
|
|
@IBAction func radioBothIconSelected(_ sender: Any) {
|
|
updateRadioButtonEffect(mode: ShowAsMode.bothIcon)
|
|
}
|
|
|
|
@IBAction func radioDockIconOnlySelected(_ sender: Any) {
|
|
updateRadioButtonEffect(mode: ShowAsMode.dockIcon)
|
|
}
|
|
|
|
@IBAction func radioMenubarOnlySelected(_ sender: Any) {
|
|
updateRadioButtonEffect(mode: ShowAsMode.menubarIcon)
|
|
}
|
|
|
|
// MARK: - Triggers
|
|
|
|
func triggerDockIconHideShow(showIcon state: Bool) -> Bool {
|
|
// Get transform state.
|
|
var transformState: ProcessApplicationTransformState
|
|
if state {
|
|
transformState = ProcessApplicationTransformState(kProcessTransformToForegroundApplication)
|
|
} else {
|
|
transformState = ProcessApplicationTransformState(kProcessTransformToUIElementApplication)
|
|
}
|
|
|
|
// Show / hide dock icon.
|
|
var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
|
|
let transformStatus: OSStatus = TransformProcessType(&psn, transformState)
|
|
return transformStatus == 0
|
|
}
|
|
|
|
func triggerDockIconShowHide(showIcon state: Bool) -> Bool {
|
|
var result: Bool
|
|
if state {
|
|
result = NSApp.setActivationPolicy(NSApplicationActivationPolicy.regular)
|
|
} else {
|
|
result = NSApp.setActivationPolicy(NSApplicationActivationPolicy.accessory)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func getDockIconStateIsShowing() -> Bool {
|
|
if NSApp.activationPolicy() == NSApplicationActivationPolicy.regular {
|
|
return true
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
|
|
// MARK: - Advanced
|
|
|
|
@IBAction func checkboxEnableAdvancedPreferencesClicked(_ sender: NSButton) {
|
|
switch sender.state {
|
|
case NSOnState:
|
|
print("on")
|
|
Preferences.shared().allowAdvancedPreferenceEdit = true
|
|
self.advPrefTableView.isEnabled = true
|
|
case NSOffState:
|
|
print("off")
|
|
Preferences.shared().allowAdvancedPreferenceEdit = false
|
|
self.advPrefTableView.isEnabled = false
|
|
case NSMixedState:
|
|
print("mixed")
|
|
default: break
|
|
}
|
|
}
|
|
|
|
|
|
// End of Class
|
|
}
|
|
|
|
|