feat: integrate sparkle for auto-updates (closes #131)
This commit is contained in:
1 parent
606bae7e71
commit
069382c119
23 files changed
+241
-67
No files matched your search
+2
-2
@@ -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
|
||||
@@ -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+$/"
|
||||
@@ -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
|
||||
|
||||
+4
-4
@@ -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:
|
||||
@@ -13,8 +13,8 @@ SPEC REPOS:
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
LetsMove: fefe56bc7bc7fb7d37049e28a14f297961229fc5
|
||||
Sparkle: 593ac2e677c07bcb6c3b22d621240e7cbedaab57
|
||||
Sparkle: 55b1a87ba69d56913375a281546b7c82dec95bb0
|
||||
|
||||
PODFILE CHECKSUM: d7356c4f4fea94deb26f1654c141fcd800355daa
|
||||
PODFILE CHECKSUM: 435b7bc84413df100dee2cabc99746bf7c670f1b
|
||||
|
||||
COCOAPODS: 1.8.4
|
||||
@@ -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`.
|
||||
|
||||
|
||||
@@ -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 */; };
|
||||
@@ -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 */; };
|
||||
@@ -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>"; };
|
||||
@@ -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>"; };
|
||||
@@ -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>"; };
|
||||
@@ -220,6 +226,7 @@
|
||||
4A443501F57D4759B190C07E /* Pods */,
|
||||
D04BA2A4F257F4DCE1421758 /* Podfile.lock */,
|
||||
D04BA0E071D2EDFDB9A20523 /* Podfile */,
|
||||
D04BAAF760E3A8A22BDA84D6 /* appcast.xml */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -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>";
|
||||
@@ -352,6 +360,7 @@
|
||||
D04BACD85D3966B4C9482E52 /* AppearanceTab.swift */,
|
||||
D04BAE23C37E0F3B07EEE7B1 /* AboutTab.swift */,
|
||||
D04BABD0C7A6DBA235C650A5 /* ShortcutsTab.swift */,
|
||||
D04BA837A9E0A82D54EF4DB0 /* UpdatesTab.swift */,
|
||||
);
|
||||
path = tabs;
|
||||
sourceTree = "<group>";
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
@@ -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] = [
|
||||
@@ -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]()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -188,6 +188,6 @@ class MacroPreferenceHelper<T> {
|
||||
}
|
||||
|
||||
enum ShowOnScreenPreference {
|
||||
case MAIN
|
||||
case MOUSE
|
||||
case main
|
||||
case mouse
|
||||
}
|
||||
@@ -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!;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"/>
|
||||
@@ -669,5 +670,6 @@
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<customObject id="ULp-HF-g0s" customClass="SUUpdater"/>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -70,6 +70,11 @@ class App: NSApplication, NSApplicationDelegate, NSWindowDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
func checkForUpdatesNow(_ sender: NSMenuItem) {
|
||||
UpdatesTab.checkForUpdatesNow(sender)
|
||||
}
|
||||
|
||||
@objc
|
||||
func showPreferencesPanel() {
|
||||
if preferencesWindow == nil {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
|
||||
@@ -24,16 +24,17 @@ class AboutTab: NSObject {
|
||||
appInfo.spacing = GridView.interPadding
|
||||
let view = GridView.make([
|
||||
[appInfo],
|
||||
[NSButton(title: NSLocalizedString("Send feedback", comment: ""), target: self, action: #selector(feedbackCallback))],
|
||||
[NSButton(title: NSLocalizedString("Send feedback…", comment: ""), target: self, action: #selector(feedbackCallback))],
|
||||
])
|
||||
view.row(at: 1).topPadding = GridView.interPadding * 2
|
||||
view.cell(atColumnIndex: 0, rowIndex: 1).xPlacement = .center
|
||||
let sendFeedbackCell = view.cell(atColumnIndex: 0, rowIndex: 1)
|
||||
sendFeedbackCell.xPlacement = .center
|
||||
sendFeedbackCell.row!.topPadding = GridView.interPadding
|
||||
view.fit()
|
||||
return view
|
||||
}
|
||||
|
||||
@objc
|
||||
static func feedbackCallback(senderControl: NSControl) {
|
||||
static func feedbackCallback() {
|
||||
(App.shared as! App).showFeedbackPanel()
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import Cocoa
|
||||
|
||||
class ShortcutsTab {
|
||||
private static let rowHeight = CGFloat(20)
|
||||
private static let rowHeight = CGFloat(22) // height of the "Tab key" input
|
||||
|
||||
static func make() -> NSTabViewItem {
|
||||
return TabViewItem.make(NSLocalizedString("Shortcuts", comment: ""), NSImage.preferencesGeneralName, makeView())
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import Cocoa
|
||||
import Sparkle
|
||||
|
||||
class UpdatesTab: NSObject {
|
||||
static var dontPeriodicallyCheck: NSButton!
|
||||
static var periodicallyCheck: NSButton!
|
||||
static var periodicallyInstall: NSButton!
|
||||
static var policyObserver = PolicyObserver()
|
||||
|
||||
static func make() -> NSTabViewItem {
|
||||
return TabViewItem.make(NSLocalizedString("Updates", comment: ""), NSImage.refreshTemplateName, makeView())
|
||||
}
|
||||
|
||||
static func makeView() -> NSGridView {
|
||||
dontPeriodicallyCheck = NSButton(radioButtonWithTitle: NSLocalizedString("Don't check for updates periodically", comment: ""), target: self, action: #selector(updatePolicyCallback))
|
||||
dontPeriodicallyCheck.fit()
|
||||
periodicallyCheck = NSButton(radioButtonWithTitle: NSLocalizedString("Check for updates periodically", comment: ""), target: self, action: #selector(updatePolicyCallback))
|
||||
periodicallyCheck.fit()
|
||||
periodicallyInstall = NSButton(radioButtonWithTitle: NSLocalizedString("Auto-install updates periodically", comment: ""), target: self, action: #selector(updatePolicyCallback))
|
||||
periodicallyInstall.fit()
|
||||
let policyLabel = NSTextField(wrappingLabelWithString: NSLocalizedString("Updates policy:", comment: ""))
|
||||
let policies = NSStackView(views: [dontPeriodicallyCheck, periodicallyCheck, periodicallyInstall])
|
||||
policies.alignment = .left
|
||||
policies.orientation = .vertical
|
||||
policies.spacing = GridView.interPadding / 2
|
||||
observePolicy()
|
||||
let view = GridView.make([
|
||||
[policyLabel, policies],
|
||||
[NSButton(title: NSLocalizedString("Check for updates now…", comment: ""), target: self, action: #selector(checkForUpdatesNow))],
|
||||
])
|
||||
view.cell(atColumnIndex: 0, rowIndex: 0).xPlacement = .trailing
|
||||
let row1 = view.row(at: 1)
|
||||
row1.mergeCells(in: NSRange(location: 0, length: 2))
|
||||
row1.topPadding = GridView.interPadding
|
||||
row1.cell(at: 0).xPlacement = .center
|
||||
view.fit()
|
||||
return view
|
||||
}
|
||||
|
||||
private static func observePolicy() {
|
||||
UserDefaults.standard.addObserver(UpdatesTab.policyObserver, forKeyPath: "SUAutomaticallyUpdate", options: [.initial, .new], context: nil)
|
||||
UserDefaults.standard.addObserver(UpdatesTab.policyObserver, forKeyPath: "SUEnableAutomaticChecks", options: [.initial, .new], context: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
static func checkForUpdatesNow(_ sender: Any) {
|
||||
SUUpdater.shared().checkForUpdates(sender)
|
||||
}
|
||||
|
||||
@objc
|
||||
static func updatePolicyCallback() {
|
||||
SUUpdater.shared().automaticallyDownloadsUpdates = periodicallyInstall.state == .on
|
||||
SUUpdater.shared().automaticallyChecksForUpdates = periodicallyInstall.state == .on || periodicallyCheck.state == .on
|
||||
}
|
||||
}
|
||||
|
||||
class PolicyObserver: NSObject {
|
||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
|
||||
if SUUpdater.shared().automaticallyDownloadsUpdates {
|
||||
UpdatesTab.periodicallyInstall.state = .on
|
||||
// Sparkle UI "Automatically download and install updates in the future" doesn't activate periodical checks; we do it manually
|
||||
SUUpdater.shared().automaticallyChecksForUpdates = true
|
||||
} else if SUUpdater.shared().automaticallyChecksForUpdates {
|
||||
UpdatesTab.periodicallyCheck.state = .on
|
||||
} else {
|
||||
UpdatesTab.dontPeriodicallyCheck.state = .on
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" standalone="yes"?>
|
||||
<rss xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" version="2.0">
|
||||
<channel>
|
||||
<title>alt-tab-macos</title>
|
||||
<language>en</language>
|
||||
|
||||
<item>
|
||||
<title>Version 2.3.4</title>
|
||||
<pubDate>Wed, 22 Jan 2020 07:56:00 +0900</pubDate>
|
||||
<sparkle:minimumSystemVersion>10.12</sparkle:minimumSystemVersion>
|
||||
<description><![CDATA[
|
||||
<h2 id="234-2020-01-22"><a href="https://github.com/lwouis/alt-tab-macos/compare/v2.3.3...v2.3.4">2.3.4</a> (2020-01-22)</h2>
|
||||
<h3 id="bug-fixes">Bug Fixes</h3>
|
||||
<ul>
|
||||
<li>escape key was absorbed by the inactive app (closes <a href="https://github.com/lwouis/alt-tab-macos/issues/123">#123</a>) (<a href="https://github.com/lwouis/alt-tab-macos/commit/5260619">5260619</a>)</li>
|
||||
</ul>
|
||||
]]>
|
||||
</description>
|
||||
<enclosure
|
||||
url="https://github.com/lwouis/alt-tab-macos/releases/download/v2.3.4/AltTab-2.3.4.zip"
|
||||
sparkle:version="2.3.4"
|
||||
sparkle:shortVersionString="2.3.4"
|
||||
sparkle:edSignature="YrGOkoXui4ORoYckJZRC8/oSPOwZmWBF0zSJh1SFisqpNov3X/I8Wg0YgJfJEHpXQFuAuxsOGKux70rKpJVeDg==" length="4315142"
|
||||
type="application/octet-stream"/>
|
||||
</item>
|
||||
|
||||
</channel>
|
||||
</rss>
|
||||
+1
-1
@@ -18,4 +18,4 @@ echo "$APPLE_P12_CERTIFICATE" | base64 --decode > $certificateFile.p12
|
||||
security import $certificateFile.p12 -P "$APPLE_P12_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
|
||||
security set-key-partition-list -S apple-tool:,apple: -s -k $keychainPassword $keychain
|
||||
# build release .app
|
||||
xcodebuild CODE_SIGN_IDENTITY="Developer ID Application: Louis Pontoise (QXD7GW8FHY)"
|
||||
xcodebuild CODE_SIGN_IDENTITY="Developer ID Application: Louis Pontoise (QXD7GW8FHY)" -workspace alt-tab-macos.xcworkspace -scheme Release
|
||||
@@ -4,5 +4,7 @@ set -exu
|
||||
|
||||
semanticRelease=$(npx semantic-release --dry-run --ci false)
|
||||
version=$(echo "$semanticRelease" | sed -nE 's/.+The next release version is (.+)/\1/p')
|
||||
changelogDelta=$(echo "$semanticRelease" | sed -n '/Release note for version/,$p' | sed '1d')
|
||||
|
||||
echo "$version" > VERSION.txt
|
||||
echo "$changelogDelta" > CHANGELOG_DELTA.txt
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -exu
|
||||
|
||||
version="$(cat VERSION.txt)"
|
||||
changelogDelta="$(npx marked < CHANGELOG_DELTA.txt)"
|
||||
date="$(date +'%a, %d %b %Y %H:%M:%S %z')"
|
||||
minimumSystemVersion="$(sed -En 's/MACOSX_DEPLOYMENT_TARGET = (.+);/\1/p' alt-tab-macos.xcodeproj/project.pbxproj | head -n 1 | awk '{$1=$1};1')"
|
||||
version="$(cat VERSION.txt)"
|
||||
zipName="AltTab-$version.zip"
|
||||
edSignatureAndLength=$(Pods/Sparkle/bin/sign_update -s $SPARKLE_ED_PRIVATE_KEY "build/Release/$zipName")
|
||||
|
||||
echo "
|
||||
<item>
|
||||
<title>Version $version</title>
|
||||
<pubDate>$date</pubDate>
|
||||
<sparkle:minimumSystemVersion>$minimumSystemVersion</sparkle:minimumSystemVersion>
|
||||
<description><![CDATA[
|
||||
$changelogDelta
|
||||
]]>
|
||||
</description>
|
||||
<enclosure
|
||||
url=\"https://github.com/lwouis/alt-tab-macos/releases/download/v$version/$zipName\"
|
||||
sparkle:version=\"$version\"
|
||||
sparkle:shortVersionString=\"$version\"
|
||||
$edSignatureAndLength
|
||||
type=\"application/octet-stream\"/>
|
||||
</item>
|
||||
" > ITEM.txt
|
||||
|
||||
sed -i '' -e "/<\/language>/r ITEM.txt" appcast.xml
|
||||
Generated
+9
-3
@@ -2380,9 +2380,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"marked": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
|
||||
"integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==",
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.8.0.tgz",
|
||||
"integrity": "sha512-MyUe+T/Pw4TZufHkzAfDj6HarCBWia2y27/bhuYkTaiUnfDYFnCP3KUN+9oM7Wi6JA2rymtVYbQu3spE0GCmxQ==",
|
||||
"dev": true
|
||||
},
|
||||
"marked-terminal": {
|
||||
@@ -6669,6 +6669,12 @@
|
||||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"marked": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz",
|
||||
"integrity": "sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==",
|
||||
"dev": true
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"@semantic-release/changelog": "^3.0.4",
|
||||
"@semantic-release/git": "^7.0.16",
|
||||
"husky": "^3.0.4",
|
||||
"marked": "^0.8.0",
|
||||
"semantic-release": "^15.13.24"
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -40,7 +40,10 @@ module.exports = {
|
||||
'@semantic-release/changelog',
|
||||
[
|
||||
'@semantic-release/git', {
|
||||
'assets': ['CHANGELOG.md'],
|
||||
'assets': [
|
||||
'CHANGELOG.md',
|
||||
'appcast.xml'
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user