Skip to content

Commit

Permalink
🚀 Add Sparkle updater.
Browse files Browse the repository at this point in the history
  • Loading branch information
sunsetsonwheels committed May 19, 2022
1 parent 5b4f231 commit 4a57986
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 63 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
builds

# Created by https://www.toptal.com/developers/gitignore/api/macos,swift
# Edit at https://www.toptal.com/developers/gitignore?templates=macos,swift
Expand Down Expand Up @@ -115,4 +116,4 @@ fastlane/test_output

iOSInjectionProject/

# End of https://www.toptal.com/developers/gitignore/api/macos,swift
# End of https://www.toptal.com/developers/gitignore/api/macos,swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
2EA352FD26D5201900271909 /* MusicScriptingBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EA352FC26D5201900271909 /* MusicScriptingBridge.swift */; };
2EEA817B26D74993009360AF /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EEA817A26D74993009360AF /* PreferencesView.swift */; };
2EF0AC312813E5F600EEDC5F /* RootNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EF0AC302813E5F600EEDC5F /* RootNavigationView.swift */; };
2EF147612836866100DBD1ED /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 2EF147602836866100DBD1ED /* Sparkle */; };
2EF147632836881300DBD1ED /* SparkleObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EF147622836881300DBD1ED /* SparkleObservable.swift */; };
2EF39E0D268D912200299C7F /* AMDiscordRPCApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EF39E0C268D912200299C7F /* AMDiscordRPCApp.swift */; };
2EF39E0F268D912200299C7F /* RPCStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2EF39E0E268D912200299C7F /* RPCStatusView.swift */; };
2EF39E11268D912300299C7F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2EF39E10268D912300299C7F /* Assets.xcassets */; };
Expand All @@ -22,6 +24,7 @@
2EA352FC26D5201900271909 /* MusicScriptingBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicScriptingBridge.swift; sourceTree = "<group>"; };
2EEA817A26D74993009360AF /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
2EF0AC302813E5F600EEDC5F /* RootNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootNavigationView.swift; sourceTree = "<group>"; };
2EF147622836881300DBD1ED /* SparkleObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SparkleObservable.swift; sourceTree = "<group>"; };
2EF39E09268D912200299C7F /* Apple Music Discord RPC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Apple Music Discord RPC.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2EF39E0C268D912200299C7F /* AMDiscordRPCApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AMDiscordRPCApp.swift; sourceTree = "<group>"; };
2EF39E0E268D912200299C7F /* RPCStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RPCStatusView.swift; sourceTree = "<group>"; };
Expand All @@ -38,6 +41,7 @@
buildActionMask = 2147483647;
files = (
2E6E06E42711BD880028F77D /* SwordRPC in Frameworks */,
2EF147612836866100DBD1ED /* Sparkle in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -49,6 +53,7 @@
children = (
2EA352FC26D5201900271909 /* MusicScriptingBridge.swift */,
2EF39E1C268D913A00299C7F /* DiscordRPCObservable.swift */,
2EF147622836881300DBD1ED /* SparkleObservable.swift */,
);
path = Modals;
sourceTree = "<group>";
Expand Down Expand Up @@ -119,6 +124,7 @@
name = "Apple Music Discord RPC";
packageProductDependencies = (
2E6E06E32711BD880028F77D /* SwordRPC */,
2EF147602836866100DBD1ED /* Sparkle */,
);
productName = AppleMusicRichPresence;
productReference = 2EF39E09268D912200299C7F /* Apple Music Discord RPC.app */;
Expand Down Expand Up @@ -149,6 +155,7 @@
mainGroup = 2EF39E00268D912200299C7F;
packageReferences = (
2E6E06E22711BD880028F77D /* XCRemoteSwiftPackageReference "SwordRPC" */,
2EF1475F2836866100DBD1ED /* XCRemoteSwiftPackageReference "Sparkle" */,
);
productRefGroup = 2EF39E0A268D912200299C7F /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -181,6 +188,7 @@
2EF39E0F268D912200299C7F /* RPCStatusView.swift in Sources */,
2EF39E1D268D913A00299C7F /* DiscordRPCObservable.swift in Sources */,
2EA352FD26D5201900271909 /* MusicScriptingBridge.swift in Sources */,
2EF147632836881300DBD1ED /* SparkleObservable.swift in Sources */,
2EF39E0D268D912200299C7F /* AMDiscordRPCApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -309,10 +317,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = AppleMusicDiscordRPC/AppleMusicDiscordRPC.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_ASSET_PATHS = "\"AppleMusicDiscordRPC/Preview Content\"";
DEVELOPMENT_TEAM = 2VZNUT7D2E;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -323,7 +331,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.3;
MARKETING_VERSION = 1.1.0;
MARKETING_VERSION = 1.2.0;
PRODUCT_BUNDLE_IDENTIFIER = me.jkelol111.AppleMusicDiscordRPC;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
Expand All @@ -336,10 +344,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = AppleMusicDiscordRPC/AppleMusicDiscordRPC.entitlements;
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_ASSET_PATHS = "\"AppleMusicDiscordRPC/Preview Content\"";
DEVELOPMENT_TEAM = 2VZNUT7D2E;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -350,7 +358,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 11.3;
MARKETING_VERSION = 1.1.0;
MARKETING_VERSION = 1.2.0;
PRODUCT_BUNDLE_IDENTIFIER = me.jkelol111.AppleMusicDiscordRPC;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
Expand Down Expand Up @@ -389,6 +397,14 @@
kind = branch;
};
};
2EF1475F2836866100DBD1ED /* XCRemoteSwiftPackageReference "Sparkle" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/sparkle-project/Sparkle";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 2.0.0;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand All @@ -397,6 +413,11 @@
package = 2E6E06E22711BD880028F77D /* XCRemoteSwiftPackageReference "SwordRPC" */;
productName = SwordRPC;
};
2EF147602836866100DBD1ED /* Sparkle */ = {
isa = XCSwiftPackageProductDependency;
package = 2EF1475F2836866100DBD1ED /* XCRemoteSwiftPackageReference "Sparkle" */;
productName = Sparkle;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 2EF39E01268D912200299C7F /* Project object */;
Expand Down
29 changes: 23 additions & 6 deletions AppleMusicDiscordRPC/AppleMusicDiscordRPC/AMDiscordRPCApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,43 @@ enum AppView {
@main
struct AMDiscordRPCApp: App {
@StateObject private var rpcObservable: DiscordRPCObservable = DiscordRPCObservable()
@StateObject private var sparkleObservable: SparkleObservable = SparkleObservable()

@State private var selectedView: AppView? = .rpcStatus

var body: some Scene {
WindowGroup {
RootNavigationView(selectedView: self.$selectedView)
.environmentObject(self.rpcObservable)
.onReceive(NotificationCenter.default.publisher(for: NSApplication.willTerminateNotification)) { output in
self.rpcObservable.disconnectFromDiscord()
}
RootNavigationView(
selectedView: self.$selectedView,
rpcObservable: self.rpcObservable,
sparkleObservable: self.sparkleObservable
)
.onReceive(NotificationCenter.default.publisher(for: NSApplication.didBecomeActiveNotification)) { _ in
NSWindow.allowsAutomaticWindowTabbing = false
NSApp.mainWindow?.standardWindowButton(.zoomButton)?.isEnabled = false
}
.onReceive(NotificationCenter.default.publisher(for: NSApplication.willTerminateNotification)) { _ in
self.rpcObservable.disconnectFromDiscord()
}
}
.commands {
CommandGroup(after: .appInfo) {
Button("Check for Updates...") {
self.sparkleObservable.checkForUpdates()
}
.disabled(!self.sparkleObservable.canCheckForUpdates)
}
CommandGroup(replacing: .appSettings) {
Button("Preferences...") {
self.selectedView = .preferences
}
.keyboardShortcut(",")
}
CommandGroup(replacing: .newItem) {}
CommandGroup(replacing: .help) {}
CommandGroup(replacing: .sidebar) {}
CommandGroup(replacing: .help) {
Link("Open-source on GitHub", destination: URL(string: "https://github.com/jkelol111/AppleMusicDiscordRPC")!)
}
}
}
}
4 changes: 4 additions & 0 deletions AppleMusicDiscordRPC/AppleMusicDiscordRPC/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,9 @@
<string>© 2022-present Nam Thành Nguyễn (jkelol111) et. al.
Licensed under the GPL v3. A copy of the license can be found in the source code.</string>
<key>SUFeedURL</key>
<string>https://raw.githubusercontent.com/jkelol111/AppleMusicDiscordRPC/main/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>XPWtCSFedtgJQkmL90hkuDFmrwzdWEjX6WrFu8Xlqs4=</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,35 @@ import ScriptingBridge
import SwordRPC
import os

fileprivate struct iTunesQueryResults: Decodable {
let artworkUrl100: String
}
class DiscordRPCObservable: ObservableObject {
private struct iTunesQueryResults: Decodable {
let artworkUrl100: String
}

fileprivate struct iTunesQueryResponse: Decodable {
let resultCount: Int
let results: [iTunesQueryResults]
}
private struct iTunesQueryResponse: Decodable {
let resultCount: Int
let results: [iTunesQueryResults]
}

enum AMPlayerStates: String {
case playing = "playing"
case paused = "paused"
case stopped = "stopped"
}
enum AMPlayerStates: String {
case playing = "playing"
case paused = "paused"
case stopped = "stopped"
}

struct DiscordRPCData {
var name: String?
var artist: String?
var album: String?
var totalTime: Double?
var state: AMPlayerStates
}
struct DiscordRPCData {
var name: String?
var artist: String?
var album: String?
var totalTime: Double?
var state: AMPlayerStates
}

struct AMArtwork {
var album: String?
var url: String?
}
struct AMArtwork {
var album: String?
var url: String?
}

class DiscordRPCObservable: ObservableObject {
@Published var rpcData: DiscordRPCData = DiscordRPCData(state: .stopped)
@Published var artwork: AMArtwork = AMArtwork()

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import SwiftUI
import Sparkle

// Adapted from:
// https://github.com/writefreely/writefreely-swiftui-multiplatform/blob/main/macOS/Settings/MacUpdatesViewModel.swift

class SparkleObservable: ObservableObject {
@Published var canCheckForUpdates: Bool = true
private let updaterController: SPUStandardUpdaterController

var automaticallyCheckForUpdates: Bool {
get {
return updaterController.updater.automaticallyChecksForUpdates
}
set(newValue) {
updaterController.updater.automaticallyChecksForUpdates = newValue
}
}

init() {
self.updaterController = SPUStandardUpdaterController(
startingUpdater: true,
updaterDelegate: nil,
userDriverDelegate: nil
)

self.updaterController.updater.publisher(for: \.canCheckForUpdates)
.assign(to: &self.$canCheckForUpdates)

if self.automaticallyCheckForUpdates {
self.updaterController.updater.checkForUpdatesInBackground()
}
}

func checkForUpdates() {
updaterController.checkForUpdates(nil)
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import SwiftUI

struct PreferencesView: View {
@EnvironmentObject var rpcObservable: DiscordRPCObservable
@ObservedObject var rpcObservable: DiscordRPCObservable
@ObservedObject var sparkleObservable: SparkleObservable

@AppStorage("showAlbumArt") var showAlbumArt: Bool = true
@AppStorage("showAlbumArt") private var showAlbumArt: Bool = true
@AppStorage("SUEnableAutomaticChecks") private var shouldCheckUpdates: Bool = false

var body: some View {
Form {
Toggle(isOn: self.$showAlbumArt) {
Text("Show album art")
}
Text("Disabling this will display Apple Music's logo instead.")
Text("We recommend disabling if you have a slow network connection.")
Text("Disabling this will display Apple Music's logo instead. Disable if you have a slow connection.")
Toggle(isOn: self.$shouldCheckUpdates) {
Text("Automatically check for updates")
}
Text("Checks and downloads updates automatically from GitHub.")
}
.padding(20)
.onChange(of: self.showAlbumArt) { _ in
self.rpcObservable.setRPC()
DispatchQueue.main.async {
self.rpcObservable.setRPC()
}
}
.onChange(of: self.shouldCheckUpdates) { _ in
DispatchQueue.main.async {
self.sparkleObservable.automaticallyCheckForUpdates = self.shouldCheckUpdates
}
}
.toolbar {
ToolbarItem {
Expand All @@ -27,9 +39,3 @@ struct PreferencesView: View {
.navigationSubtitle("Preferences")
}
}

struct PreferencesView_Previews: PreviewProvider {
static var previews: some View {
PreferencesView()
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import SwiftUI

struct RPCStatusView: View {
@EnvironmentObject var rpcObservable: DiscordRPCObservable
@ObservedObject var rpcObservable: DiscordRPCObservable

var noArtwork: some View {
Image("NoArtwork")
Expand Down Expand Up @@ -72,9 +72,3 @@ struct RPCStatusView: View {
.padding()
}
}

struct RPCStatusView_Previews: PreviewProvider {
static var previews: some View {
RPCStatusView()
}
}
Loading

0 comments on commit 4a57986

Please sign in to comment.