Browse Source

RStudio Server manager/switcher

tags/v1.5.0
boB Rudis 5 years ago
parent
commit
73620e82e4
No known key found for this signature in database GPG Key ID: 1D7529BE14E2BBA9
  1. 8
      RSwitch.xcodeproj/project.pbxproj
  2. 164
      RSwitch/Base.lproj/Main.storyboard
  3. 17
      RSwitch/Swift/AppDelegate.swift
  4. 4
      RSwitch/Swift/Menu.swift
  5. 8
      RSwitch/Swift/MenuActions/RStudioServerAction.swift
  6. 73
      RSwitch/Swift/NewSessionViewController.swift
  7. 33
      RSwitch/Swift/SessionWindowController.swift
  8. 2
      RSwitch/Swift/Sessions/RStudioServerSession.swift
  9. 21
      RSwitch/Swift/Sessions/RStudioServerSessionManager.swift
  10. 16
      RSwitch/Swift/WebViewController.swift

8
RSwitch.xcodeproj/project.pbxproj

@ -16,6 +16,7 @@
01073F1D2311E64E007162C9 /* DownloadRStudio.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F1C2311E64E007162C9 /* DownloadRStudio.swift */; };
01073F1F2311E67D007162C9 /* HandleUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F1E2311E67D007162C9 /* HandleUpdate.swift */; };
01073F212311E6BD007162C9 /* HandleRSwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01073F202311E6BD007162C9 /* HandleRSwitch.swift */; };
010A1C1423215B0900E32A9A /* SessionWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 010A1C1323215B0900E32A9A /* SessionWindowController.swift */; };
011951B4231F00A000B62C3A /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 011951B3231F00A000B62C3A /* Preferences.swift */; };
0178970D230ED25100F8F5BC /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0178970C230ED25100F8F5BC /* AboutViewController.swift */; };
018A8C3B2312C7BC0006E87D /* libprocInfo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 018A8C3A2312C7BC0006E87D /* libprocInfo.a */; };
@ -25,6 +26,7 @@
0198B99E23196689003F7578 /* BrowseMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B99D23196689003F7578 /* BrowseMenuAction.swift */; };
0198B9A0231970ED003F7578 /* AppAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B99F231970ED003F7578 /* AppAlerts.swift */; };
0198B9AA23197D3A003F7578 /* Running.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0198B9A923197D3A003F7578 /* Running.swift */; };
01B611EC232176A200432807 /* NewSessionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01B611EB232176A200432807 /* NewSessionViewController.swift */; };
01D3E43A232119DD00E3BC02 /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D3E439232119DD00E3BC02 /* WebViewController.swift */; };
01D3E43C23211B4C00E3BC02 /* RStudioServerAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D3E43B23211B4C00E3BC02 /* RStudioServerAction.swift */; };
01D3E43F2321315900E3BC02 /* RStudioServerSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01D3E43E2321315900E3BC02 /* RStudioServerSession.swift */; };
@ -47,6 +49,7 @@
01073F1C2311E64E007162C9 /* DownloadRStudio.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadRStudio.swift; sourceTree = "<group>"; };
01073F1E2311E67D007162C9 /* HandleUpdate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleUpdate.swift; sourceTree = "<group>"; };
01073F202311E6BD007162C9 /* HandleRSwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandleRSwitch.swift; sourceTree = "<group>"; };
010A1C1323215B0900E32A9A /* SessionWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionWindowController.swift; sourceTree = "<group>"; };
011951B3231F00A000B62C3A /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
016750FB2319A7A4009E2FD6 /* RSwitch.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RSwitch.entitlements; sourceTree = "<group>"; };
0178970C230ED25100F8F5BC /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
@ -60,6 +63,7 @@
0198B99D23196689003F7578 /* BrowseMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowseMenuAction.swift; sourceTree = "<group>"; };
0198B99F231970ED003F7578 /* AppAlerts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppAlerts.swift; sourceTree = "<group>"; };
0198B9A923197D3A003F7578 /* Running.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Running.swift; sourceTree = "<group>"; };
01B611EB232176A200432807 /* NewSessionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewSessionViewController.swift; sourceTree = "<group>"; };
01D3E439232119DD00E3BC02 /* WebViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = "<group>"; };
01D3E43B23211B4C00E3BC02 /* RStudioServerAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RStudioServerAction.swift; sourceTree = "<group>"; };
01D3E43E2321315900E3BC02 /* RStudioServerSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RStudioServerSession.swift; sourceTree = "<group>"; };
@ -107,6 +111,8 @@
01073F142311E370007162C9 /* Notify.swift */,
01F3EF0D230E635300DF5DF9 /* ViewController.swift */,
01D3E439232119DD00E3BC02 /* WebViewController.swift */,
010A1C1323215B0900E32A9A /* SessionWindowController.swift */,
01B611EB232176A200432807 /* NewSessionViewController.swift */,
);
path = Swift;
sourceTree = "<group>";
@ -353,6 +359,7 @@
01073F212311E6BD007162C9 /* HandleRSwitch.swift in Sources */,
0198B9A0231970ED003F7578 /* AppAlerts.swift in Sources */,
011951B4231F00A000B62C3A /* Preferences.swift in Sources */,
010A1C1423215B0900E32A9A /* SessionWindowController.swift in Sources */,
01D3E43C23211B4C00E3BC02 /* RStudioServerAction.swift in Sources */,
018A8C3F2312CB480006E87D /* procHelper.m in Sources */,
01D3E43A232119DD00E3BC02 /* WebViewController.swift in Sources */,
@ -371,6 +378,7 @@
01F3EF0E230E635300DF5DF9 /* ViewController.swift in Sources */,
01F3EF0C230E635300DF5DF9 /* AppDelegate.swift in Sources */,
01D3E441232131F300E3BC02 /* RStudioServerSessionManager.swift in Sources */,
01B611EC232176A200432807 /* NewSessionViewController.swift in Sources */,
01073F0F2311AE2E007162C9 /* String+Version.swift in Sources */,
0198B99E23196689003F7578 /* BrowseMenuAction.swift in Sources */,
01073F132311E1CF007162C9 /* Globals.swift in Sources */,

164
RSwitch/Base.lproj/Main.storyboard

@ -51,6 +51,7 @@
</menuItem>
<menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
<menuItem title="Quit RSwitch" keyEquivalent="q" id="4sb-4s-VLi">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
</connections>
@ -699,16 +700,71 @@
<!--Window Controller-->
<scene sceneID="MKQ-4Y-Oth">
<objects>
<windowController storyboardIdentifier="wkPanelController" id="qjv-aN-QDU" sceneMemberID="viewController">
<window key="window" identifier="wkPanelController" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="0uE-Xe-6tV">
<windowController storyboardIdentifier="wkPanelController" id="qjv-aN-QDU" customClass="SessionWindowController" customModule="RSwitch" sceneMemberID="viewController">
<window key="window" identifier="wkPanelController" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" titleVisibility="hidden" id="0uE-Xe-6tV">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<rect key="contentRect" x="-480" y="985" width="480" height="270"/>
<rect key="screenRect" x="-2560" y="0.0" width="2560" height="1440"/>
<toolbar key="toolbar" implicitIdentifier="120C2095-EF52-4259-9751-99BE445F0A18" explicitIdentifier="sessionDelete" autosavesConfiguration="NO" allowsUserCustomization="NO" showsBaselineSeparator="NO" displayMode="iconAndLabel" sizeMode="regular" id="1h8-Yt-Vhz">
<allowedToolbarItems>
<toolbarItem implicitItemIdentifier="NSToolbarShowColorsItem" id="SDw-ZN-plv"/>
<toolbarItem implicitItemIdentifier="NSToolbarShowFontsItem" id="WNi-eE-iYD"/>
<toolbarItem implicitItemIdentifier="NSToolbarPrintItem" id="xHz-Mi-NXD"/>
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="Jbz-Yu-NVz"/>
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="rDu-xC-TQY"/>
<toolbarItem implicitItemIdentifier="F7A6A7DB-439F-4CDA-A709-0B604ACF7634" explicitItemIdentifier="titleThing" label="Window Title" paletteLabel="Window Title" tag="88" sizingBehavior="auto" id="Cz9-Cn-dUF">
<nil key="toolTip"/>
<textField key="view" identifier="sessionTitle" horizontalHuggingPriority="251" verticalHuggingPriority="750" tag="88" id="gxD-qg-AUg">
<rect key="frame" x="15" y="14" width="45" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" identifier="toolbarTitle" title="Label" id="312-Lg-tJU">
<font key="font" metaFont="fixedUser" size="11"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</toolbarItem>
<toolbarItem implicitItemIdentifier="C5E453F9-B8DF-42A3-B04B-FEC4774D8C17" label="Delete Session" paletteLabel="Delete Session" toolTip="Close this session and delete the session from the sessions popup submenu." tag="77" sizingBehavior="auto" id="RdT-NR-Rq5">
<button key="view" identifier="deleteButton" verticalHuggingPriority="750" tag="77" imageHugsTitle="YES" id="yQr-Wa-hEC">
<rect key="frame" x="0.0" y="14" width="127" height="24"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="roundTextured" title="Delete Session" bezelStyle="texturedRounded" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mLg-dJ-21p">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="message"/>
</buttonCell>
<connections>
<action selector="deletePressed:" target="qjv-aN-QDU" id="diI-k3-yQA"/>
</connections>
</button>
</toolbarItem>
<toolbarItem implicitItemIdentifier="7C1E2141-99F5-4AAF-8DFC-F98346F8B458" explicitItemIdentifier="nickThing" label="Nickname" paletteLabel="Nickname" sizingBehavior="auto" id="z3h-u9-ok2">
<nil key="toolTip"/>
<textField key="view" horizontalHuggingPriority="251" verticalHuggingPriority="750" id="kjS-Ur-lI5">
<rect key="frame" x="11" y="14" width="37" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Label" id="6X3-G1-f3A">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</toolbarItem>
</allowedToolbarItems>
<defaultToolbarItems>
<toolbarItem reference="z3h-u9-ok2"/>
<toolbarItem reference="rDu-xC-TQY"/>
<toolbarItem reference="Cz9-Cn-dUF"/>
<toolbarItem reference="rDu-xC-TQY"/>
<toolbarItem reference="RdT-NR-Rq5"/>
</defaultToolbarItems>
</toolbar>
<connections>
<outlet property="delegate" destination="qjv-aN-QDU" id="ydd-t5-B2B"/>
</connections>
</window>
<connections>
<outlet property="nickField" destination="kjS-Ur-lI5" id="6cc-wZ-qao"/>
<outlet property="titleField" destination="gxD-qg-AUg" id="IKb-uP-5s4"/>
<segue destination="tec-9J-KNb" kind="relationship" relationship="window.shadowedContentViewController" id="idQ-y1-OGg"/>
</connections>
</windowController>
@ -716,6 +772,110 @@
</objects>
<point key="canvasLocation" x="-454" y="470"/>
</scene>
<!--Window Controller-->
<scene sceneID="NLO-A5-Grh">
<objects>
<windowController storyboardIdentifier="newSessPanel" id="hjJ-ZI-mmO" sceneMemberID="viewController">
<window key="window" title="Add New RStudio Server" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" frameAutosaveName="" animationBehavior="default" id="xSx-ho-xah">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<rect key="contentRect" x="425" y="470" width="480" height="153"/>
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1440"/>
<connections>
<outlet property="delegate" destination="hjJ-ZI-mmO" id="rQz-1I-VSd"/>
</connections>
</window>
<connections>
<segue destination="yEm-BG-6ox" kind="relationship" relationship="window.shadowedContentViewController" id="uvs-jg-5j4"/>
</connections>
</windowController>
<customObject id="jcq-2b-z5N" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-663" y="849"/>
</scene>
<!--New Session View Controller-->
<scene sceneID="C6C-1l-Uyb">
<objects>
<viewController id="yEm-BG-6ox" customClass="NewSessionViewController" customModule="RSwitch" sceneMemberID="viewController">
<view key="view" id="7HF-tp-Bfd">
<rect key="frame" x="0.0" y="0.0" width="480" height="132"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="xqf-Ja-9FZ">
<rect key="frame" x="18" y="94" width="161" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="Nickname (for submenu): " id="fok-tt-urE">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="dz6-zg-r72">
<rect key="frame" x="52" y="59" width="127" height="16"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" lineBreakMode="clipping" alignment="right" title="RStudio Server URL:" id="pnD-X4-BT5">
<font key="font" usesAppearanceFont="YES"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" id="tg7-6c-rrS">
<rect key="frame" x="185" y="91" width="275" height="21"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="cva-Md-d45">
<font key="font" metaFont="message"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" id="lSZ-zf-FsV">
<rect key="frame" x="185" y="56" width="275" height="21"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="zy1-gA-fJN">
<font key="font" metaFont="message"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" id="gC9-NN-7E1">
<rect key="frame" x="148" y="9" width="82" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="VDj-IV-qlo">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="message"/>
<string key="keyEquivalent" base64-UTF8="YES">
Gw
</string>
</buttonCell>
<connections>
<action selector="cancelPressed:" target="yEm-BG-6ox" id="VMR-6p-A8Q"/>
</connections>
</button>
<button verticalHuggingPriority="750" id="e6I-ev-l5T">
<rect key="frame" x="263" y="11" width="59" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="mlc-6J-XMQ">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="message"/>
<string key="keyEquivalent" base64-UTF8="YES">
DQ
</string>
</buttonCell>
<connections>
<action selector="okPressed:" target="yEm-BG-6ox" id="Juf-kH-4iI"/>
</connections>
</button>
</subviews>
</view>
<connections>
<outlet property="nickname" destination="tg7-6c-rrS" id="uDa-nB-kUR"/>
<outlet property="okButton" destination="e6I-ev-l5T" id="r88-1K-WJ9"/>
<outlet property="serverURL" destination="lSZ-zf-FsV" id="f0k-iP-6g5"/>
</connections>
</viewController>
<customObject id="nc3-iI-ege" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-595" y="1094"/>
</scene>
<!--Web View Controller-->
<scene sceneID="1Kq-xR-oeu">
<objects>

17
RSwitch/Swift/AppDelegate.swift

@ -8,8 +8,16 @@
import Cocoa
class DeleteSessionViewController : NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
}
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate {
@objc func showAbout(_ sender: NSMenuItem?) {
abtController.showWindow(self)
@ -22,6 +30,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
var mainStoryboard: NSStoryboard!
var abtController: NSWindowController!
var rsController: NSWindowController!
var newSessController: NSWindowController!
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
let statusMenu = NSMenu(title: "RSwitch")
@ -66,12 +75,12 @@ class AppDelegate: NSObject, NSApplicationDelegate {
abtController = (mainStoryboard.instantiateController(withIdentifier: "aboutPanelController") as! NSWindowController)
newSessController = (mainStoryboard.instantiateController(withIdentifier: "newSessPanel") as! NSWindowController)
sess = RStudioServerSessionManager()
// sess.newSession(url: "https://rstudio.hrbrmstr.de", title: "One")
// sess.newSession(url: "https://rud.is/b", title: "Two")
sess.debugSessions()
timer = Timer.scheduledTimer(
timeInterval: 3600,
target: self,
@ -83,7 +92,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
func applicationWillTerminate(_ aNotification: Notification) {
sess.saveSessions()
}
}

4
RSwitch/Swift/Menu.swift

@ -90,7 +90,9 @@ extension AppDelegate: NSMenuDelegate {
// Add a Quit item
menu.addItem(NSMenuItem.separator())
menu.addItem(NSMenuItem(title: "Quit", action: #selector(NSApp.terminate), keyEquivalent: "q"))
let quitItem = NSMenuItem(title: "Quit", action: #selector(NSApp.terminate), keyEquivalent: "q")
quitItem.keyEquivalentModifierMask = NSEvent.ModifierFlags.option
menu.addItem(quitItem)
}

8
RSwitch/Swift/MenuActions/RStudioServerAction.swift

@ -12,17 +12,15 @@ import Cocoa
extension AppDelegate {
@objc func newRstudioServerSession(_ sender: NSMenuItem) {
print("New Session")
newSessController.showWindow(self)
newSessController.window?.orderFront(self)
NSApp.activate(ignoringOtherApps: true)
}
@objc func activateServerSession(_ sender: NSMenuItem) {
print("activate Session")
let sess = (sender.representedObject as! RStudioServerSession)
sess.show()
}
}

73
RSwitch/Swift/NewSessionViewController.swift

@ -0,0 +1,73 @@
//
// NewSessionViewController.swift
// RSwitch
//
// Created by hrbrmstr on 9/5/19.
// Copyright © 2019 Bob Rudis. All rights reserved.
//
import Cocoa
extension String {
var isValidURL: Bool {
let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
if let match = detector.firstMatch(in: self, options: [], range: NSRange(location: 0, length: self.utf16.count)) {
// it is a link, if the match covers the whole string
return match.range.length == self.utf16.count
} else {
return false
}
}
}
class NewSessionViewController: NSViewController {
let appDelegate = NSApplication.shared.delegate as! AppDelegate
@IBOutlet weak var nickname: NSTextField!
@IBOutlet weak var serverURL: NSTextField!
@IBOutlet weak var okButton: NSButton!
@IBAction func okPressed(_ sender: Any) {
appDelegate.sess.newSession(url: serverURL.stringValue, title: nickname.stringValue)
self.view.window?.windowController?.close()
}
@IBAction func cancelPressed(_ sender: Any) {
self.view.window?.windowController?.close()
}
override func viewDidLoad() {
print("VIEW IS LOADING")
super.viewDidLoad()
nickname.delegate = self
serverURL.delegate = self
okButton.isEnabled = false
// Do view setup here.
}
}
extension NewSessionViewController : NSTextFieldDelegate {
func controlTextDidEndEditing(_ notification: Notification) {
let nick = nickname.stringValue
let sURL = serverURL.stringValue
let currNames = appDelegate.sess.sessions!.map {
$0.menuTitle
}
print(currNames)
let nickUnique = !(currNames.firstIndex(of: nick) != nil)
okButton.isEnabled = ((nick.count > 0) && nickUnique && sURL.isValidURL)
}
}

33
RSwitch/Swift/SessionWindowController.swift

@ -0,0 +1,33 @@
//
// SessionWindowController.swift
// RSwitch
//
// Created by hrbrmstr on 9/5/19.
// Copyright © 2019 Bob Rudis. All rights reserved.
//
import Cocoa
import WebKit
class SessionWindowController: NSWindowController {
let appDelegate = NSApplication.shared.delegate as! AppDelegate
@IBOutlet weak var titleField: NSTextField!
@IBOutlet weak var nickField: NSTextField!
@IBAction func deletePressed(_ sender: Any) {
appDelegate.sess.deleteSession(title: nickField.stringValue)
self.window?.windowController = nil
self.window?.close()
}
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
}

2
RSwitch/Swift/Sessions/RStudioServerSession.swift

@ -34,10 +34,10 @@ class RStudioServerSession : Codable {
let mainStoryboard = appDelegate.mainStoryboard!
if (wk == nil) {
print("wk was nil")
wk = (mainStoryboard.instantiateController(withIdentifier: "wkPanelController") as! NSWindowController)
wv = wk!.window?.contentViewController as? WebViewController
wv!.url = url
wv!.nickname = menuTitle
}
wk?.window?.orderFront(appDelegate)

21
RSwitch/Swift/Sessions/RStudioServerSessionManager.swift

@ -19,7 +19,18 @@ class RStudioServerSessionManager {
}
func newSession(url: String, title: String) {
sessions!.append(RStudioServerSession(url: url, title: title))
let s = RStudioServerSession(url: url, title: title)
sessions!.append(s)
saveSessions()
s.show()
}
func deleteSession(title: String) {
sessions = sessions!.filter { $0.menuTitle != title }
saveSessions()
}
func saveSessions() {
let sessionsData = try! JSONEncoder().encode(sessions)
UserDefaults.standard.set(sessionsData, forKey: "rstudioServerSessions")
}
@ -33,12 +44,4 @@ class RStudioServerSessionManager {
}
}
func debugSessions() {
for s in sessions! {
print(s.menuTitle)
}
}
}

16
RSwitch/Swift/WebViewController.swift

@ -9,21 +9,33 @@
import Cocoa
import WebKit
class WebViewController: NSViewController {
class WebViewController: NSViewController, NSTextFieldDelegate {
@IBOutlet weak var rstudioServerView: WKWebView!
var url = "https://rstudio.hrbrmstr.de/"
var url = ""
var nickname = ""
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear() {
super.viewDidAppear()
self.view.window?.title = url
let wc = self.view.window?.windowController as! SessionWindowController
wc.titleField.stringValue = url
wc.nickField.stringValue = nickname
rstudioServerView.configuration.preferences.javaScriptEnabled = true
rstudioServerView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true
let request = URLRequest(url: URL(string: url)!)
rstudioServerView.load(request)
}
override var representedObject: Any? {

Loading…
Cancel
Save