Path: blob/main/SignalServiceKit/UISupport/WallpaperStore.swift
1 views
//
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public import UIKit
public class WallpaperStore {
public static let wallpaperDidChangeNotification = NSNotification.Name("wallpaperDidChangeNotification")
private enum Constants {
static let globalPersistenceKey = "global"
}
private let wallpaperImageStore: WallpaperImageStore
private let enumStore: KeyValueStore
private let dimmingStore: KeyValueStore
init(
wallpaperImageStore: WallpaperImageStore,
) {
self.enumStore = KeyValueStore(collection: "Wallpaper+Enum")
self.dimmingStore = KeyValueStore(collection: "Wallpaper+Dimming")
self.wallpaperImageStore = wallpaperImageStore
}
// MARK: - Persistence Keys
private static func persistenceKey(for threadUniqueId: String?) -> String {
return threadUniqueId ?? Constants.globalPersistenceKey
}
private static func threadUniqueId(for persistenceKey: String) -> String? {
if persistenceKey == Constants.globalPersistenceKey {
return nil
}
return persistenceKey
}
// MARK: - Getters & Setters
public func setBuiltIn(_ wallpaper: Wallpaper, for thread: TSThread? = nil) async throws {
owsAssertDebug(wallpaper != .photo)
try await _set(wallpaper, for: thread)
}
public func setPhoto(_ photo: UIImage, for thread: TSThread? = nil) async throws {
try await _set(.photo, photo: photo, for: thread)
}
private func _set(_ wallpaper: Wallpaper?, photo: UIImage? = nil, for thread: TSThread?) async throws {
owsAssertDebug(photo == nil || wallpaper == .photo)
let onInsert = { [self] (tx: DBWriteTransaction) -> Void in
self.setWallpaperType(wallpaper, for: thread?.uniqueId, tx: tx)
}
if let thread {
try await wallpaperImageStore.setWallpaperImage(photo, for: thread, onInsert: onInsert)
} else {
try await wallpaperImageStore.setGlobalThreadWallpaperImage(photo, onInsert: onInsert)
}
}
/// Set just the type; doesn't override any wallpaper image that may be set.
public func setWallpaperType(_ wallpaper: Wallpaper?, for threadUniqueId: String?, tx: DBWriteTransaction) {
enumStore.setString(wallpaper?.rawValue, key: Self.persistenceKey(for: threadUniqueId), transaction: tx)
postWallpaperDidChangeNotification(for: threadUniqueId, tx: tx)
}
public func fetchWallpaper(for threadUniqueId: String?, tx: DBReadTransaction) -> Wallpaper? {
guard let raw = enumStore.getString(Self.persistenceKey(for: threadUniqueId), transaction: tx) else {
return nil
}
guard let wallpaper = Wallpaper(rawValue: raw) else {
owsFailDebug("Unexpected wallpaper \(raw)")
return nil
}
return wallpaper
}
/// Return either the per-thread wallpaper setting, or the global setting if none is set on the thread.
public func fetchWallpaperForRendering(
for threadUniqueId: String?,
tx: DBReadTransaction,
) -> Wallpaper? {
return Self.fetchResolvedValue(for: threadUniqueId) {
return fetchWallpaper(for: $0, tx: tx)
}
}
/// Fetches a thread-specific value (if set) or the global value.
public static func fetchResolvedValue<ThreadType, ResultType>(for thread: ThreadType?, fetchBlock: (ThreadType?) -> ResultType?) -> ResultType? {
if let thread, let threadValue = fetchBlock(thread) { return threadValue }
return fetchBlock(nil)
}
public func fetchUniqueThreadIdsWithWallpaper(tx: DBReadTransaction) -> [String?] {
return enumStore.allKeys(transaction: tx).map { Self.threadUniqueId(for: $0) }
}
public func setDimInDarkMode(_ dimInDarkMode: Bool?, for threadUniqueId: String?, tx: DBWriteTransaction) {
let key = Self.persistenceKey(for: threadUniqueId)
if let dimInDarkMode {
dimmingStore.setBool(dimInDarkMode, key: key, transaction: tx)
} else {
dimmingStore.removeValue(forKey: key, transaction: tx)
}
postWallpaperDidChangeNotification(for: threadUniqueId, tx: tx)
}
public func fetchDimInDarkMode(for threadUniqueId: String?, tx: DBReadTransaction) -> Bool? {
return dimmingStore.getBool(Self.persistenceKey(for: threadUniqueId), transaction: tx)
}
public func fetchDimInDarkModeForRendering(for threadUniqueId: String?, tx: DBReadTransaction) -> Bool {
return Self.fetchResolvedValue(for: threadUniqueId) {
return fetchDimInDarkMode(for: $0, tx: tx)
} ?? Wallpaper.shouldDimInDarkModeDefaultValue
}
// MARK: - Resetting Values
public func reset(for thread: TSThread?, tx: DBWriteTransaction) {
let threadUniqueId = thread?.uniqueId
enumStore.removeValue(forKey: Self.persistenceKey(for: threadUniqueId), transaction: tx)
dimmingStore.removeValue(forKey: Self.persistenceKey(for: threadUniqueId), transaction: tx)
postWallpaperDidChangeNotification(for: threadUniqueId, tx: tx)
}
public func resetAll(tx: DBWriteTransaction) {
enumStore.removeAll(transaction: tx)
dimmingStore.removeAll(transaction: tx)
postWallpaperDidChangeNotification(for: nil, tx: tx)
}
private func postWallpaperDidChangeNotification(for threadUniqueId: String?, tx: DBWriteTransaction) {
tx.addSyncCompletion {
NotificationCenter.default.postOnMainThread(name: Self.wallpaperDidChangeNotification, object: threadUniqueId)
}
}
}