feat: integrate sparkle for auto-updates (closes #131)

This commit is contained in:
louis.pontoise authored and lwouis committed 2020-03-10 14:00:37 +09:00
1 parent 606bae7e71
commit 069382c119
23 files changed
+241 -67

No files matched your search

+2 -2
View File
@@ -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+$/"
+1 -1
View File
@@ -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
View File
@@ -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
+4 -1
View File
@@ -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`.
+12
View File
@@ -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;
};
+6
View File
@@ -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>
+40 -40
View File
@@ -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
}
+2 -2
View File
@@ -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!;
}
}
+5 -3
View File
@@ -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>
+5
View File
@@ -70,6 +70,11 @@ class App: NSApplication, NSApplicationDelegate, NSWindowDelegate {
}
}
@objc
func checkForUpdatesNow(_ sender: NSMenuItem) {
UpdatesTab.checkForUpdatesNow(sender)
}
@objc
func showPreferencesPanel() {
if preferencesWindow == nil {
+2 -2
View File
@@ -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")
+6 -2
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
+31
View File
@@ -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
+9 -3
View File
@@ -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",
+1
View File
@@ -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
View File
@@ -40,7 +40,10 @@ module.exports = {
'@semantic-release/changelog',
[
'@semantic-release/git', {
'assets': ['CHANGELOG.md'],
'assets': [
'CHANGELOG.md',
'appcast.xml'
],
},
],
],