jellyflood/Shared/Services/SwiftfinDefaults.swift

253 lines
11 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) 2024 Jellyfin & Jellyfin Contributors
//
import Defaults
import Factory
import Foundation
import SwiftUI
import UIKit
// TODO: organize
// TODO: all user settings could be moved to `StoredValues`?
// Note: Only use Defaults for basic single-value settings.
// For larger data types and collections, use `StoredValue` instead.
// MARK: Suites
extension UserDefaults {
// MARK: App
/// Settings that should apply to the app
static let appSuite = UserDefaults(suiteName: "swiftfinApp")!
// MARK: Usser
// TODO: the Factory resolver cannot be used because it would cause freezes, but
// the Defaults value should always be in sync with the latest user and what
// views properly expect. However, this feels like a hack and should be changed?
static var currentUserSuite: UserDefaults {
userSuite(id: Defaults[.lastSignedInUserID] ?? "default")
}
static func userSuite(id: String) -> UserDefaults {
UserDefaults(suiteName: id)!
}
}
private extension Defaults.Keys {
static func AppKey<Value: Defaults.Serializable>(_ name: String) -> Key<Value?> {
Key(name, suite: .appSuite)
}
static func AppKey<Value: Defaults.Serializable>(_ name: String, default: Value) -> Key<Value> {
Key(name, default: `default`, suite: .appSuite)
}
static func UserKey<Value: Defaults.Serializable>(_ name: String, default: Value) -> Key<Value> {
Key(name, default: `default`, suite: .currentUserSuite)
}
}
// MARK: App
extension Defaults.Keys {
/// The _real_ accent color key to be used.
///
/// This is set externally whenever the app or user accent colors change,
/// depending on the current app state.
static var accentColor: Key<Color> = AppKey("accentColor", default: .jellyfinPurple)
/// The _real_ appearance key to be used.
///
/// This is set externally whenever the app or user appearances change,
/// depending on the current app state.
static let appearance: Key<AppAppearance> = AppKey("appearance", default: .system)
/// The accent color default for non-user contexts.
/// Only use for `set`, use `accentColor` for `get`.
static let appAccentColor: Key<Color> = AppKey("appAccentColor", default: .jellyfinPurple)
/// The appearance default for non-user contexts.
/// /// Only use for `set`, use `appearance` for `get`.
static let appAppearance: Key<AppAppearance> = AppKey("appAppearance", default: .system)
static let backgroundSignOutInterval: Key<TimeInterval> = AppKey("backgroundSignOutInterval", default: 3600)
static let backgroundTimeStamp: Key<Date> = AppKey("backgroundTimeStamp", default: Date.now)
static let lastSignedInUserID: Key<String?> = AppKey("lastSignedInUserID")
static let selectUserDisplayType: Key<LibraryDisplayType> = AppKey("selectUserDisplayType", default: .grid)
static let selectUserServerSelection: Key<SelectUserServerSelection> = AppKey("selectUserServerSelection", default: .all)
static let selectUserAllServersSplashscreen: Key<SelectUserServerSelection> = AppKey("selectUserAllServersSplashscreen", default: .all)
static let selectUserUseSplashscreen: Key<Bool> = AppKey("selectUserUseSplashscreen", default: true)
static let signOutOnBackground: Key<Bool> = AppKey("signOutOnBackground", default: true)
static let signOutOnClose: Key<Bool> = AppKey("signOutOnClose", default: true)
}
// MARK: User
extension Defaults.Keys {
/// The accent color default for user contexts.
/// Only use for `set`, use `accentColor` for `get`.
static var userAccentColor: Key<Color> { UserKey("userAccentColor", default: .jellyfinPurple) }
/// The appearance default for user contexts.
/// /// Only use for `set`, use `appearance` for `get`.
static var userAppearance: Key<AppAppearance> { UserKey("userAppearance", default: .system) }
enum Customization {
static let itemViewType: Key<ItemViewType> = UserKey("itemViewType", default: .compactLogo)
static let showPosterLabels: Key<Bool> = UserKey("showPosterLabels", default: true)
static let nextUpPosterType: Key<PosterDisplayType> = UserKey("nextUpPosterType", default: .portrait)
static let recentlyAddedPosterType: Key<PosterDisplayType> = UserKey("recentlyAddedPosterType", default: .portrait)
static let latestInLibraryPosterType: Key<PosterDisplayType> = UserKey("latestInLibraryPosterType", default: .portrait)
static let shouldShowMissingSeasons: Key<Bool> = UserKey("shouldShowMissingSeasons", default: true)
static let shouldShowMissingEpisodes: Key<Bool> = UserKey("shouldShowMissingEpisodes", default: true)
static let similarPosterType: Key<PosterDisplayType> = UserKey("similarPosterType", default: .portrait)
// TODO: have search poster type by types of items if applicable
static let searchPosterType: Key<PosterDisplayType> = UserKey("searchPosterType", default: .portrait)
enum CinematicItemViewType {
static let usePrimaryImage: Key<Bool> = UserKey("cinematicItemViewTypeUsePrimaryImage", default: false)
}
enum Episodes {
static let useSeriesLandscapeBackdrop: Key<Bool> = UserKey("useSeriesBackdrop", default: true)
}
enum Indicators {
static let showFavorited: Key<Bool> = UserKey("showFavoritedIndicator", default: true)
static let showProgress: Key<Bool> = UserKey("showProgressIndicator", default: true)
static let showUnplayed: Key<Bool> = UserKey("showUnplayedIndicator", default: true)
static let showPlayed: Key<Bool> = UserKey("showPlayedIndicator", default: true)
}
enum Library {
static let cinematicBackground: Key<Bool> = UserKey("Customization.Library.cinematicBackground", default: true)
static let enabledDrawerFilters: Key<[ItemFilterType]> = UserKey(
"Library.enabledDrawerFilters",
default: ItemFilterType.allCases
)
static let displayType: Key<LibraryDisplayType> = UserKey("libraryViewType", default: .grid)
static let posterType: Key<PosterDisplayType> = UserKey("libraryPosterType", default: .portrait)
static let listColumnCount: Key<Int> = UserKey("listColumnCount", default: 1)
static let randomImage: Key<Bool> = UserKey("libraryRandomImage", default: true)
static let showFavorites: Key<Bool> = UserKey("libraryShowFavorites", default: true)
static let rememberLayout: Key<Bool> = UserKey("libraryRememberLayout", default: false)
static let rememberSort: Key<Bool> = UserKey("libraryRememberSort", default: false)
}
enum Search {
static let enabledDrawerFilters: Key<[ItemFilterType]> = UserKey(
"Search.enabledDrawerFilters",
default: ItemFilterType.allCases
)
}
}
enum VideoPlayer {
static let autoPlayEnabled: Key<Bool> = UserKey("autoPlayEnabled", default: true)
static let barActionButtons: Key<[VideoPlayerActionButton]> = UserKey(
"barActionButtons",
default: VideoPlayerActionButton.defaultBarActionButtons
)
static let jumpBackwardLength: Key<VideoPlayerJumpLength> = UserKey("jumpBackwardLength", default: .fifteen)
static let jumpForwardLength: Key<VideoPlayerJumpLength> = UserKey("jumpForwardLength", default: .fifteen)
static let menuActionButtons: Key<[VideoPlayerActionButton]> = UserKey(
"menuActionButtons",
default: VideoPlayerActionButton.defaultMenuActionButtons
)
static let resumeOffset: Key<Int> = UserKey("resumeOffset", default: 0)
static let showJumpButtons: Key<Bool> = UserKey("showJumpButtons", default: true)
static let videoPlayerType: Key<VideoPlayerType> = UserKey("videoPlayerType", default: .swiftfin)
enum Gesture {
static let horizontalPanGesture: Key<PanAction> = UserKey("videoPlayerHorizontalPanGesture", default: .none)
static let horizontalSwipeGesture: Key<SwipeAction> = UserKey("videoPlayerHorizontalSwipeGesture", default: .none)
static let longPressGesture: Key<LongPressAction> = UserKey("videoPlayerLongPressGesture", default: .gestureLock)
static let multiTapGesture: Key<MultiTapAction> = UserKey("videoPlayerMultiTapGesture", default: .none)
static let doubleTouchGesture: Key<DoubleTouchAction> = UserKey("videoPlayerDoubleTouchGesture", default: .none)
static let pinchGesture: Key<PinchAction> = UserKey("videoPlayerSwipeGesture", default: .aspectFill)
static let verticalPanGestureLeft: Key<PanAction> = UserKey("videoPlayerVerticalPanGestureLeft", default: .none)
static let verticalPanGestureRight: Key<PanAction> = UserKey("videoPlayerVerticalPanGestureRight", default: .none)
}
enum Overlay {
static let chapterSlider: Key<Bool> = UserKey("chapterSlider", default: true)
static let playbackButtonType: Key<PlaybackButtonType> = UserKey("videoPlayerPlaybackButtonLocation", default: .large)
static let sliderColor: Key<Color> = UserKey("sliderColor", default: Color.white)
static let sliderType: Key<SliderType> = UserKey("sliderType", default: .capsule)
// Timestamp
static let trailingTimestampType: Key<TrailingTimestampType> = UserKey("trailingTimestamp", default: .timeLeft)
static let showCurrentTimeWhileScrubbing: Key<Bool> = UserKey("showCurrentTimeWhileScrubbing", default: true)
static let timestampType: Key<TimestampType> = UserKey("timestampType", default: .split)
}
enum Subtitle {
static let subtitleColor: Key<Color> = UserKey("subtitleColor", default: .white)
static let subtitleFontName: Key<String> = UserKey("subtitleFontName", default: UIFont.systemFont(ofSize: 14).fontName)
static let subtitleSize: Key<Int> = UserKey("subtitleSize", default: 16)
}
enum Transition {
static let pauseOnBackground: Key<Bool> = UserKey("pauseOnBackground", default: false)
static let playOnActive: Key<Bool> = UserKey("playOnActive", default: false)
}
}
// Experimental settings
enum Experimental {
static let downloads: Key<Bool> = UserKey("experimentalDownloads", default: false)
static let forceDirectPlay: Key<Bool> = UserKey("forceDirectPlay", default: false)
static let liveTVForceDirectPlay: Key<Bool> = UserKey("liveTVForceDirectPlay", default: false)
}
// tvos specific
static let downActionShowsMenu: Key<Bool> = UserKey("downActionShowsMenu", default: true)
static let confirmClose: Key<Bool> = UserKey("confirmClose", default: false)
}
// MARK: Debug
#if DEBUG
extension UserDefaults {
static let debugSuite = UserDefaults(suiteName: "swiftfinstore-debug-defaults")!
}
extension Defaults.Keys {
static func DebugKey<Value: Defaults.Serializable>(_ name: String, default: Value) -> Key<Value> {
Key(name, default: `default`, suite: .appSuite)
}
static let sendProgressReports: Key<Bool> = DebugKey("sendProgressReports", default: true)
}
#endif