Skip to content

Commit

Permalink
feat: integrate sparkle for auto-updates (closes #131)
Browse files Browse the repository at this point in the history
  • Loading branch information
louis.pontoise authored and lwouis committed Mar 10, 2020
1 parent 606bae7 commit 069382c
Show file tree
Hide file tree
Showing 23 changed files with 241 additions and 67 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ script:
- if [ $IS_RELEASE ]; then ci/set_version_in_app.sh; fi
- ci/build_release.sh
- if [ $IS_RELEASE ]; then ci/package_release.sh; fi
- if [ $IS_RELEASE ]; then ci/update_appcast.sh; fi
- if [ $IS_RELEASE ]; then ci/update_homebrew_cask.sh; fi
- if [ $IS_RELEASE ]; then npx semantic-release; fi
deploy:
provider: releases
Expand All @@ -26,8 +28,6 @@ deploy:
cleanup: false
on:
repo: lwouis/alt-tab-macos
after_deploy:
- ci/update_homebrew_cask.sh
branches:
except:
- "/^v\\d+\\.\\d+\\.\\d+$/"
2 changes: 1 addition & 1 deletion Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ platform :osx, '10.12'
target 'alt-tab-macos' do
use_frameworks!
pod 'LetsMove', '1.24'
pod 'Sparkle', '1.22.0'
pod 'Sparkle', '1.23.0'
end

8 changes: 4 additions & 4 deletions Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
PODS:
- LetsMove (1.24)
- Sparkle (1.22.0)
- Sparkle (1.23.0)

DEPENDENCIES:
- LetsMove (= 1.24)
- Sparkle (= 1.22.0)
- Sparkle (= 1.23.0)

SPEC REPOS:
trunk:
Expand All @@ -13,8 +13,8 @@ SPEC REPOS:

SPEC CHECKSUMS:
LetsMove: fefe56bc7bc7fb7d37049e28a14f297961229fc5
Sparkle: 593ac2e677c07bcb6c3b22d621240e7cbedaab57
Sparkle: 55b1a87ba69d56913375a281546b7c82dec95bb0

PODFILE CHECKSUM: d7356c4f4fea94deb26f1654c141fcd800355daa
PODFILE CHECKSUM: 435b7bc84413df100dee2cabc99746bf7c670f1b

COCOAPODS: 1.8.4
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ Before building my own app, I looked around at similar apps. However, none was c

## Building the project locally

This project has minimal dependency on Xcode-only features (e.g. InterfaceBuilder, Playgrounds). You can build it using 1 command `xcodebuild`.
This project has minimal dependency on Xcode-only features (e.g. InterfaceBuilder, Playgrounds). You can build it using 2 commands:

* `pod install` to fetch the dependencies with [CocoaPods](https://cocoapods.org/)
* `xcodebuild -workspace alt-tab-macos.xcworkspace -scheme Release` to build the .app

Note that on debug builds, to avoid having to re-check the `System Preferences > Security & Privacy` permissions on every build, we use a code-signing certificate. You can generate one on your local machine in one step by running `ci/generate_debug_certificate.sh`.

Expand Down
12 changes: 12 additions & 0 deletions alt-tab-macos.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
D04BA2378832FD7E5DE3BC23 /* Applications.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA66B5B4143D2238F50B9 /* Applications.swift */; };
D04BA26B4E9B4378FA7995DF /* HyperlinkLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA2D2BCBA4C47E25315AF /* HyperlinkLabel.swift */; };
D04BA278D9EFA568C8D18A4C /* Windows.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAD1BED44EAEB77FED8A4 /* Windows.swift */; };
D04BA29A372E8A644273E7B3 /* update_appcast.sh in Resources */ = {isa = PBXBuildFile; fileRef = D04BA0AAAE82C72855DBBA26 /* update_appcast.sh */; };
D04BA2CBF0EFA04CC80EC1BC /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAE80772D25834E440975 /* Window.swift */; };
D04BA308162F8043F8561D03 /* AXUIElement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA40A4291E4F310527DBF /* AXUIElement.swift */; };
D04BA30F92801F5960ACC844 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D04BA7A48641612933710091 /* MainMenu.xib */; };
Expand All @@ -37,10 +38,12 @@
D04BA744F626B2E89331390B /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BA10F57DA97A1D0320122 /* InfoPlist.strings */; };
D04BA79B891E9C89C015D6DD /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAEE5AEEB8692856B45E4 /* InfoPlist.strings */; };
D04BA7F212CDB1B7E101D7A3 /* GridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAFE3AC6E14F394956586 /* GridView.swift */; };
D04BA826A1745BCC7E8C7B26 /* appcast.xml in Resources */ = {isa = PBXBuildFile; fileRef = D04BAAF760E3A8A22BDA84D6 /* appcast.xml */; };
D04BA8373D4DE452C0C081ED /* SF-Pro-Text-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = D04BABC654F40BE74DA25BC7 /* SF-Pro-Text-Regular.otf */; };
D04BA84074E5FD6221720BC7 /* CollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BAACB6648E7C2A4E0339D /* CollectionViewFlowLayout.swift */; };
D04BA8EBC0365A019A27C7EA /* Screen.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA3F15EAE8D8C39B6F2CF /* Screen.swift */; };
D04BA99DE72CE77BA6CE5A56 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAF762580D0252489A11A /* InfoPlist.strings */; };
D04BA9AB730AB1AF4055929D /* UpdatesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA837A9E0A82D54EF4DB0 /* UpdatesTab.swift */; };
D04BA9CCE02D30C8164A552A /* SystemPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA2D2AD6B1CCA3F3A4DD7 /* SystemPermissions.swift */; };
D04BA9EE5D34A2789DCB0EE2 /* Sysctl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D04BA896E37EFD27CAB61DF0 /* Sysctl.swift */; };
D04BAA0F39E6160F5703FC33 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = D04BAC0D42D7FED725746DA5 /* Localizable.strings */; };
Expand Down Expand Up @@ -69,6 +72,7 @@
BF12DEA89785CA78B0FE2706 /* Pods-alt-tab-macos.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-alt-tab-macos.debug.xcconfig"; path = "Target Support Files/Pods-alt-tab-macos/Pods-alt-tab-macos.debug.xcconfig"; sourceTree = "<group>"; };
C0712B3BEA2B3780398C0999 /* Pods_alt_tab_macos.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_alt_tab_macos.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D04BA05F3F36A6D71DCD8475 /* en */ = {isa = PBXFileReference; fileEncoding = 2483028224; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = "<group>"; };
D04BA0AAAE82C72855DBBA26 /* update_appcast.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = update_appcast.sh; sourceTree = "<group>"; };
D04BA0CE87BE264C52987ED1 /* 7 windows - 2 lines - wide window.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "7 windows - 2 lines - wide window.jpg"; sourceTree = "<group>"; };
D04BA0E071D2EDFDB9A20523 /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = "<group>"; };
D04BA0E1C5DBC07108AC2F54 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
Expand Down Expand Up @@ -112,6 +116,7 @@
D04BA8011143819B48F204C2 /* TextArea.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextArea.swift; sourceTree = "<group>"; };
D04BA81CA2D9818FCA9E5024 /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fr; path = InfoPlist.strings; sourceTree = "<group>"; };
D04BA82F792DF53958D92572 /* alt-tab-macos.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "alt-tab-macos.app"; sourceTree = BUILT_PRODUCTS_DIR; };
D04BA837A9E0A82D54EF4DB0 /* UpdatesTab.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdatesTab.swift; sourceTree = "<group>"; };
D04BA896E37EFD27CAB61DF0 /* Sysctl.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sysctl.swift; sourceTree = "<group>"; };
D04BA89FAEC4A5734D892C4B /* build_release.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = build_release.sh; sourceTree = "<group>"; };
D04BA8BEE821E2062F23AA97 /* CollectionViewItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewItem.swift; sourceTree = "<group>"; };
Expand All @@ -122,6 +127,7 @@
D04BAA34E0CB00DED7C04B4F /* 2-rows.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "2-rows.jpg"; sourceTree = "<group>"; };
D04BAA44C837F3A67403B9DB /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
D04BAACB6648E7C2A4E0339D /* CollectionViewFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewFlowLayout.swift; sourceTree = "<group>"; };
D04BAAF760E3A8A22BDA84D6 /* appcast.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = appcast.xml; sourceTree = "<group>"; };
D04BAB6652494D7575057E86 /* 14 windows - 3 lines.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = "14 windows - 3 lines.jpg"; sourceTree = "<group>"; };
D04BABC180117F8785D250E1 /* TextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
D04BABC654F40BE74DA25BC7 /* SF-Pro-Text-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file.otf; path = "SF-Pro-Text-Regular.otf"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -220,6 +226,7 @@
4A443501F57D4759B190C07E /* Pods */,
D04BA2A4F257F4DCE1421758 /* Podfile.lock */,
D04BA0E071D2EDFDB9A20523 /* Podfile */,
D04BAAF760E3A8A22BDA84D6 /* appcast.xml */,
);
sourceTree = "<group>";
};
Expand Down Expand Up @@ -324,6 +331,7 @@
D04BAE93A5854C501639C640 /* update_homebrew_cask.sh */,
D04BA5E819181CB83C5602C7 /* generate_debug_certificate.sh */,
D04BA89FAEC4A5734D892C4B /* build_release.sh */,
D04BA0AAAE82C72855DBBA26 /* update_appcast.sh */,
);
path = ci;
sourceTree = "<group>";
Expand Down Expand Up @@ -352,6 +360,7 @@
D04BACD85D3966B4C9482E52 /* AppearanceTab.swift */,
D04BAE23C37E0F3B07EEE7B1 /* AboutTab.swift */,
D04BABD0C7A6DBA235C650A5 /* ShortcutsTab.swift */,
D04BA837A9E0A82D54EF4DB0 /* UpdatesTab.swift */,
);
path = tabs;
sourceTree = "<group>";
Expand Down Expand Up @@ -539,6 +548,8 @@
D04BA3AE19F48237BDCDDA4F /* Localizable.strings in Resources */,
D04BA3D87405EE52518CCC3E /* Podfile.lock in Resources */,
D04BAE4A31689CCF132372B7 /* Podfile in Resources */,
D04BA29A372E8A644273E7B3 /* update_appcast.sh in Resources */,
D04BA826A1745BCC7E8C7B26 /* appcast.xml in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -636,6 +647,7 @@
D04BA9EE5D34A2789DCB0EE2 /* Sysctl.swift in Sources */,
D04BAC4F69FE9563BC1C5E9C /* DebugProfile.swift in Sources */,
D04BAE4CE37C303DDD0347B8 /* CollectionViewItemView.swift in Sources */,
D04BA9AB730AB1AF4055929D /* UpdatesTab.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
6 changes: 6 additions & 0 deletions alt-tab-macos/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,11 @@
<string></string>
<key>NSSupportsSuddenTermination</key>
<string>true</string>
<key>SUFeedURL</key>
<string>https://raw.githubusercontent.com/lwouis/alt-tab-macos/v3-poc/appcast.xml</string>
<key>SUEnableAutomaticChecks</key>
<string>true</string>
<key>SUPublicEDKey</key>
<string>2e9SQOBoaKElchSa/4QDli/nvYkyuDNfynfzBF6vJK4=</string>
</dict>
</plist>
80 changes: 40 additions & 40 deletions alt-tab-macos/logic/Preferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class Preferences {
MacroPreference("⌘ command", ([kVK_Command, kVK_RightCommand], .command))
])
static let showOnScreenMacro = MacroPreferenceHelper<ShowOnScreenPreference>([
MacroPreference("Main screen", ShowOnScreenPreference.MAIN),
MacroPreference("Screen including mouse", ShowOnScreenPreference.MOUSE),
MacroPreference("Main screen", ShowOnScreenPreference.main),
MacroPreference("Screen including mouse", ShowOnScreenPreference.mouse),
])

static var defaults: [String: String] = [
Expand All @@ -36,7 +36,7 @@ class Preferences {
"windowDisplayDelay": "0",
"theme": themeMacro.macros[0].label,
"showOnScreen": showOnScreenMacro.macros[0].label,
"hideSpaceNumberLabels": String(false)
"hideSpaceNumberLabels": String(false),
]
static var rawValues = [String: String]()

Expand Down Expand Up @@ -89,41 +89,41 @@ class Preferences {

static func updateAndValidateFromString(_ valueName: String, _ value: String) throws {
switch valueName {
case "maxScreenUsage":
maxScreenUsage = try CGFloat(CGFloat(value).orThrow() / 100)
case "minCellsPerRow":
minCellsPerRow = try CGFloat(value).orThrow()
case "maxCellsPerRow":
maxCellsPerRow = try CGFloat(value).orThrow()
case "minRows":
minRows = try CGFloat(value).orThrow()
case "iconSize":
iconSize = try CGFloat(value).orThrow()
case "fontHeight":
fontHeight = try CGFloat(value).orThrow()
font = NSFont.systemFont(ofSize: fontHeight)
case "tabKeyCode":
tabKeyCode = try UInt16(value).orThrow()
case "metaKey":
let p = try metaKeyMacro.labelToMacro[value].orThrow()
metaKeyCodes = p.preferences.0.map { UInt16($0) }
metaModifierFlag = p.preferences.1
case "theme":
let p = try themeMacro.labelToMacro[value].orThrow()
cellBorderWidth = p.preferences.0
cellCornerRadius = p.preferences.1
windowCornerRadius = p.preferences.2
highlightBorderColor = p.preferences.3
highlightBackgroundColor = p.preferences.4
case "windowDisplayDelay":
windowDisplayDelay = DispatchTimeInterval.milliseconds(try Int(value).orThrow())
case "showOnScreen":
let p = try showOnScreenMacro.labelToMacro[value].orThrow()
showOnScreen = p.preferences
case "hideSpaceNumberLabels":
hideSpaceNumberLabels = try Bool(value).orThrow()
default:
throw NSError.make(domain: "Preferences", message: "Tried to update an unknown preference: '\(valueName)' = '\(value)'")
case "maxScreenUsage":
maxScreenUsage = try CGFloat(CGFloat(value).orThrow() / 100)
case "minCellsPerRow":
minCellsPerRow = try CGFloat(value).orThrow()
case "maxCellsPerRow":
maxCellsPerRow = try CGFloat(value).orThrow()
case "minRows":
minRows = try CGFloat(value).orThrow()
case "iconSize":
iconSize = try CGFloat(value).orThrow()
case "fontHeight":
fontHeight = try CGFloat(value).orThrow()
font = NSFont.systemFont(ofSize: fontHeight)
case "tabKeyCode":
tabKeyCode = try UInt16(value).orThrow()
case "metaKey":
let p = try metaKeyMacro.labelToMacro[value].orThrow()
metaKeyCodes = p.preferences.0.map { UInt16($0) }
metaModifierFlag = p.preferences.1
case "theme":
let p = try themeMacro.labelToMacro[value].orThrow()
cellBorderWidth = p.preferences.0
cellCornerRadius = p.preferences.1
windowCornerRadius = p.preferences.2
highlightBorderColor = p.preferences.3
highlightBackgroundColor = p.preferences.4
case "windowDisplayDelay":
windowDisplayDelay = DispatchTimeInterval.milliseconds(try Int(value).orThrow())
case "showOnScreen":
let p = try showOnScreenMacro.labelToMacro[value].orThrow()
showOnScreen = p.preferences
case "hideSpaceNumberLabels":
hideSpaceNumberLabels = try Bool(value).orThrow()
default:
throw NSError.make(domain: "Preferences", message: "Tried to update an unknown preference: '\(valueName)' = '\(value)'")
}
rawValues[valueName] = value
}
Expand Down Expand Up @@ -188,6 +188,6 @@ class MacroPreferenceHelper<T> {
}

enum ShowOnScreenPreference {
case MAIN
case MOUSE
case main
case mouse
}
4 changes: 2 additions & 2 deletions alt-tab-macos/logic/Screen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import Cocoa
class Screen {
static func preferred() -> NSScreen {
switch Preferences.showOnScreen! {
case .MOUSE: return withMouse() ?? NSScreen.main!; // .main as fall-back
case .MAIN: return NSScreen.main!;
case .mouse: return withMouse() ?? NSScreen.main!; // .main as fall-back
case .main: return NSScreen.main!;
}
}

Expand Down
8 changes: 5 additions & 3 deletions alt-tab-macos/resources/MainMenu.xib
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11134" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11134"/>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication"/>
Expand Down Expand Up @@ -669,5 +670,6 @@
</menuItem>
</items>
</menu>
<customObject id="ULp-HF-g0s" customClass="SUUpdater"/>
</objects>
</document>
5 changes: 5 additions & 0 deletions alt-tab-macos/ui/App.swift
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ class App: NSApplication, NSApplicationDelegate, NSWindowDelegate {
}
}

@objc
func checkForUpdatesNow(_ sender: NSMenuItem) {
UpdatesTab.checkForUpdatesNow(sender)
}

@objc
func showPreferencesPanel() {
if preferencesWindow == nil {
Expand Down
4 changes: 2 additions & 2 deletions alt-tab-macos/ui/FeedbackWindow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@ class FeedbackWindow: NSWindow {
}

@objc
private func cancelCallback(senderControl: NSControl) {
private func cancelCallback() {
close()
}

@objc
private func sendCallback(senderControl: NSControl) {
private func sendCallback() {
URLSession.shared.dataTask(with: prepareRequest(), completionHandler: { data, response, error in
if error != nil || response == nil || (response as! HTTPURLResponse).statusCode != 201 {
debugPrint("HTTP call failed:", response ?? "nil", error ?? "nil")
Expand Down
8 changes: 6 additions & 2 deletions alt-tab-macos/ui/Menubar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,20 @@ class Menubar {
item.menu!.addItem(
withTitle: NSLocalizedString("Show", comment: ""),
action: #selector(app.showUi),
keyEquivalent: "s"
keyEquivalent: ""
)
item.menu!.addItem(
withTitle: NSLocalizedString("Preferences…", comment: ""),
action: #selector(app.showPreferencesPanel),
keyEquivalent: ",")
item.menu!.addItem(
withTitle: NSLocalizedString("Check for updates…", comment: ""),
action: #selector(app.checkForUpdatesNow),
keyEquivalent: "")
item.menu!.addItem(
withTitle: NSLocalizedString("Send feedback…", comment: ""),
action: #selector(app.showFeedbackPanel),
keyEquivalent: ",")
keyEquivalent: "")
item.menu!.addItem(NSMenuItem.separator())
item.menu!.addItem(
withTitle: NSLocalizedString("Quit", comment: "") + " " + App.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class PreferencesWindow: NSWindow {
tabViewController.tabStyle = .toolbar
tabViewController.addTabViewItem(ShortcutsTab.make())
tabViewController.addTabViewItem(AppearanceTab.make())
tabViewController.addTabViewItem(UpdatesTab.make())
tabViewController.addTabViewItem(AboutTab.make())
}

Expand Down
Loading

0 comments on commit 069382c

Please sign in to comment.