jellyflood/Swiftfin/App/SwiftfinApp+ValueObservatio...

125 lines
4.1 KiB
Swift

//
// Swiftfin is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at https://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2025 Jellyfin & Jellyfin Contributors
//
import Combine
import Defaults
import Factory
import Foundation
import SwiftUI
// Following class is necessary to observe values that can either
// be a user *or* an app setting and only one should apply at a time.
//
// Also just to separate out value observation
// TODO: could clean up?
extension SwiftfinApp {
class ValueObservation: ObservableObject {
private var accentColorCancellable: AnyCancellable?
private var appearanceCancellable: AnyCancellable?
private var lastSignInUserIDCancellable: AnyCancellable?
private var splashScreenCancellable: AnyCancellable?
init() {
// MARK: signed in observation
lastSignInUserIDCancellable = Task {
for await newValue in Defaults.updates(.lastSignedInUserID) {
Container.shared.mediaPlayerManager.reset()
if case .signedIn = newValue {
setUserDefaultsObservation()
} else {
setAppDefaultsObservation()
}
}
}
.asAnyCancellable()
}
// MARK: user observation
private func setUserDefaultsObservation() {
accentColorCancellable?.cancel()
appearanceCancellable?.cancel()
splashScreenCancellable?.cancel()
accentColorCancellable = Task {
for await newValue in Defaults.updates(.userAccentColor) {
await MainActor.run {
Defaults[.accentColor] = newValue
UIApplication.shared.setAccentColor(newValue.uiColor)
}
}
}
.asAnyCancellable()
appearanceCancellable = Task {
for await newValue in Defaults.updates(.userAppearance) {
await MainActor.run {
Defaults[.appearance] = newValue
UIApplication.shared.setAppearance(newValue.style)
}
}
}
.asAnyCancellable()
}
// MARK: app observation
private func setAppDefaultsObservation() {
accentColorCancellable?.cancel()
appearanceCancellable?.cancel()
splashScreenCancellable?.cancel()
accentColorCancellable = Task {
await MainActor.run {
Defaults[.accentColor] = .jellyfinPurple
UIApplication.shared.setAccentColor(Color.jellyfinPurple.uiColor)
}
}
.asAnyCancellable()
appearanceCancellable = Task {
for await newValue in Defaults.updates(.appAppearance) {
// other cancellable will set appearance if enabled
// and need to avoid races
guard !Defaults[.selectUserUseSplashscreen] else { continue }
await MainActor.run {
Defaults[.appearance] = newValue
UIApplication.shared.setAppearance(newValue.style)
}
}
}
.asAnyCancellable()
splashScreenCancellable = Task {
for await newValue in Defaults.updates(.selectUserUseSplashscreen) {
await MainActor.run {
if newValue {
Defaults[.appearance] = .dark
UIApplication.shared.setAppearance(.dark)
} else {
Defaults[.appearance] = Defaults[.appAppearance]
UIApplication.shared.setAppearance(Defaults[.appAppearance].style)
}
}
}
}
.asAnyCancellable()
}
}
}