source: launchers/macosx/I2PLauncher/userinterface/preferences/PreferencesViewController.swift @ 605f987

Last change on this file since 605f987 was 605f987, checked in by meeh <meeh@…>, 23 months ago

Mac OSX Launcher: UI code updates, integration of firefox manager.

  • Property mode set to 100644
File size: 8.2 KB
Line 
1//
2//  PreferencesViewController.swift
3//  I2PLauncher
4//
5//  Created by Mikal Villa on 07/11/2018.
6//  Copyright © 2018 The I2P Project. All rights reserved.
7//
8// Table view programming guide from Apple:
9// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TableView/Introduction/Introduction.html
10//
11
12import Cocoa
13import ServiceManagement
14
15
16class PreferencesViewController: NSViewController {
17 
18  enum ShowAsMode {
19    case bothIcon
20    case menubarIcon
21    case dockIcon
22  }
23 
24  var changeDockMenubarIconTimer: Timer?
25 
26  // MARK: - Advanced settings objects
27  @IBOutlet weak var advPrefTableView: NSTableView!
28 
29  // MARK: - Launcher settings objects
30  @IBOutlet var radioDockIcon: NSButton?
31  @IBOutlet var radioMenubarIcon: NSButton?
32  @IBOutlet var radioBothIcon: NSButton?
33  @IBOutlet var checkboxStartWithOSX: NSButton?
34  @IBOutlet var checkboxStartFirefoxAlso: NSButton?
35 
36  // MARK: - Router objects
37  @IBOutlet var checkboxStartWithLauncher: NSButton?
38  @IBOutlet var checkboxStopWithLauncher: NSButton?
39  @IBOutlet var buttonResetRouterConfig: NSButton?
40 
41 
42  override func viewDidLoad() {
43    super.viewDidLoad()
44   
45    self.preferredContentSize = NSMakeSize(self.view.frame.size.width, self.view.frame.size.height)
46   
47    if (advPrefTableView != nil) {
48      // For data feeding and view
49      advPrefTableView.delegate = self
50      advPrefTableView.dataSource = self
51     
52      // Responding to Double-Click
53      advPrefTableView.target = self
54      advPrefTableView.doubleAction = #selector(tableViewDoubleClick(_:))
55     
56      // Always redraw preference items which might have changed state since last draw.
57      Preferences.shared().redrawPrefTableItems()
58     
59      // For sorting
60      advPrefTableView.tableColumns[0].sortDescriptorPrototype = NSSortDescriptor(key: "name", ascending: true)
61      advPrefTableView.tableColumns[1].sortDescriptorPrototype = NSSortDescriptor(key: "defaultValue", ascending: true)
62      advPrefTableView.tableColumns[2].sortDescriptorPrototype = NSSortDescriptor(key: "selectedValue", ascending: true)
63    }
64   
65    // Update radio buttons to reflect runtime/stored preferences
66    self.updateRadioButtonEffect(mode: Preferences.shared().showAsIconMode, withSideEffect: false)
67   
68    if (Preferences.shared().stopRouterOnLauncherShutdown) {
69      self.checkboxStopWithLauncher?.state = NSOnState;
70    } else {
71      self.checkboxStopWithLauncher?.state = NSOffState;
72    }
73    if (Preferences.shared().startRouterOnLauncherStart) {
74      self.checkboxStartWithLauncher?.state = NSOnState;
75    } else {
76      self.checkboxStartWithLauncher?.state = NSOffState;
77    }
78   
79   
80  }
81 
82  override func viewDidAppear() {
83    super.viewDidAppear()
84   
85    // Update window title
86    self.parent?.view.window?.title = self.title!
87  }
88 
89  // MARK: - Router settings functions
90 
91  @IBAction func checkboxStartRouterWithLauncherClicked(_ sender: NSButton) {
92    switch sender.state {
93    case NSOnState:
94      print("on")
95      Preferences.shared().startRouterOnLauncherStart = true
96    case NSOffState:
97      print("off")
98      Preferences.shared().startRouterOnLauncherStart = false
99    case NSMixedState:
100      print("mixed")
101    default: break
102    }
103  }
104 
105  @IBAction func checkboxStopRouterWithLauncherClicked(_ sender: NSButton) {
106    switch sender.state {
107    case NSOnState:
108      print("on")
109      Preferences.shared().stopRouterOnLauncherShutdown = true
110    case NSOffState:
111      print("off")
112      Preferences.shared().stopRouterOnLauncherShutdown = false
113    case NSMixedState:
114      print("mixed")
115    default: break
116    }
117  }
118 
119  @IBAction func buttonResetRouterConfigClicked(_ sender: Any) {
120    // TODO: Add a modal dialog asking user if they are **really** sure
121  }
122 
123  // MARK: - Launcher settings functions
124 
125  @IBAction func checkboxStartLauncherOnOSXStartupClicked(_ sender: NSButton) {
126    let launcherAppId = "net.i2p.bootstrap.macosx.StartupItemApp"
127    switch sender.state {
128    case NSOnState:
129      print("on")
130      Preferences.shared()["I2Pref_startLauncherAtLogin"] = true
131      let success = SMLoginItemSetEnabled(launcherAppId as CFString, true)
132      print("SMLoginItemSetEnabled returned \(success)....")
133    case NSOffState:
134      print("off")
135      Preferences.shared()["I2Pref_startLauncherAtLogin"] = false
136      let success = SMLoginItemSetEnabled(launcherAppId as CFString, false)
137      print("SMLoginItemSetEnabled returned \(success)....")
138    case NSMixedState:
139      print("mixed")
140    default: break
141    }
142  }
143  @IBAction func checkboxStartFirefoxAlsoAtLaunchClicked(_ sender: NSButton) {
144    switch sender.state {
145    case NSOnState:
146      print("on")
147    case NSOffState:
148      print("off")
149    case NSMixedState:
150      print("mixed")
151    default: break
152    }
153  }
154 
155  // MARK: - Radio buttons functions
156 
157  func updateDockMenubarIcons(_ mode: ShowAsMode) -> Bool {
158    // Update preferences with latest choise
159    Preferences.shared().showAsIconMode = mode
160    // Update runtime
161    switch mode {
162    case .bothIcon, .dockIcon:
163      // Show dock icon
164      print("Preferences: Update Dock Icon -> Show")
165      if (!getDockIconStateIsShowing()) {
166        return triggerDockIconShowHide(showIcon: true)
167      }
168    case .menubarIcon:
169      // Hide dock icon
170      print("Preferences: Update Dock Icon -> Hide")
171      if (getDockIconStateIsShowing()) {
172        return triggerDockIconShowHide(showIcon: false)
173      }
174    }
175    // Note: In reality, this won't ever happen.
176    // The switch statement above would return before this.
177    return false
178  }
179 
180  func updateRadioButtonEffect(mode: ShowAsMode, withSideEffect: Bool = true) {
181    changeDockMenubarIconTimer?.invalidate()
182   
183    radioDockIcon?.state = NSOffState
184    radioMenubarIcon?.state = NSOffState
185    radioBothIcon?.state = NSOffState
186   
187    switch mode {
188    case .bothIcon:
189      radioBothIcon?.state = NSOnState
190    case .dockIcon:
191      radioDockIcon?.state = NSOnState
192    case .menubarIcon:
193      radioMenubarIcon?.state = NSOnState
194    }
195   
196    if (withSideEffect) {
197      if #available(OSX 10.12, *) {
198        changeDockMenubarIconTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false, block: { _ in
199          // If we're on 10.12 or later
200          self.updateDockMenubarIcons(mode)
201        })
202      } else {
203        // Fallback on earlier versions
204        self.updateDockMenubarIcons(mode)
205      }
206    }
207  }
208 
209  @IBAction func radioBothIconSelected(_ sender: Any) {
210    updateRadioButtonEffect(mode: ShowAsMode.bothIcon)
211  }
212 
213  @IBAction func radioDockIconOnlySelected(_ sender: Any) {
214    updateRadioButtonEffect(mode: ShowAsMode.dockIcon)
215  }
216 
217  @IBAction func radioMenubarOnlySelected(_ sender: Any) {
218    updateRadioButtonEffect(mode: ShowAsMode.menubarIcon)
219  }
220 
221  // MARK: - Triggers
222 
223  func triggerDockIconHideShow(showIcon state: Bool) -> Bool {
224    // Get transform state.
225    var transformState: ProcessApplicationTransformState
226    if state {
227      transformState = ProcessApplicationTransformState(kProcessTransformToForegroundApplication)
228    } else {
229      transformState = ProcessApplicationTransformState(kProcessTransformToUIElementApplication)
230    }
231   
232    // Show / hide dock icon.
233    var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
234    let transformStatus: OSStatus = TransformProcessType(&psn, transformState)
235    return transformStatus == 0
236  }
237 
238  func triggerDockIconShowHide(showIcon state: Bool) -> Bool {
239    var result: Bool
240    if state {
241      result = NSApp.setActivationPolicy(NSApplicationActivationPolicy.regular)
242    } else {
243      result = NSApp.setActivationPolicy(NSApplicationActivationPolicy.accessory)
244    }
245    return result
246  }
247 
248  func getDockIconStateIsShowing() -> Bool {
249    if NSApp.activationPolicy() == NSApplicationActivationPolicy.regular {
250      return true
251    } else {
252      return false
253    }
254  }
255 
256 
257  // MARK: - Advanced
258 
259  @IBAction func checkboxEnableAdvancedPreferencesClicked(_ sender: NSButton) {
260    switch sender.state {
261    case NSOnState:
262      print("on")
263      Preferences.shared().allowAdvancedPreferenceEdit = true
264    case NSOffState:
265      print("off")
266      Preferences.shared().allowAdvancedPreferenceEdit = false
267    case NSMixedState:
268      print("mixed")
269    default: break
270    }
271  }
272
273 
274  // End of Class
275}
276
277
Note: See TracBrowser for help on using the repository browser.