// // View+AppListStyle.swift // Tusker // // Created by Shadowfacts on 2/6/23. // Copyright © 2023 Shadowfacts. All rights reserved. // import SwiftUI import Combine import TuskerPreferences extension View { func appGroupedListBackground(container: UIAppearanceContainer.Type) -> some View { self.modifier(AppGroupedListBackground(container: container)) } func appGroupedListRowBackground() -> some View { self.modifier(AppGroupedListRowBackground()) } } private struct AppGroupedListBackground: ViewModifier { let container: any UIAppearanceContainer.Type @Environment(\.colorScheme) private var colorScheme @Environment(\.pureBlackDarkMode) private var environmentPureBlackDarkMode private var pureBlackDarkMode: Bool { // using @PreferenceObserving just does not work for this, so try the environment key when available // if it's not available, the color won't update automatically, but it will be correct when the view is created if #available(iOS 17.0, *) { environmentPureBlackDarkMode } else { false } } func body(content: Content) -> some View { if #available(iOS 16.0, *) { if colorScheme == .dark, !pureBlackDarkMode { content .scrollContentBackground(.hidden) .background(Color.appGroupedBackground.edgesIgnoringSafeArea(.all)) } else { content } } else { content .onAppear { UITableView.appearance(whenContainedInInstancesOf: [container]).backgroundColor = .appGroupedBackground } } } } private struct AppGroupedListRowBackground: ViewModifier { @Environment(\.colorScheme) private var colorScheme @PreferenceObserving(\.$pureBlackDarkMode) private var pureBlackDarkMode func body(content: Content) -> some View { if colorScheme == .dark, !pureBlackDarkMode { content .listRowBackground(Color.appGroupedCellBackground) } else { content } } } @propertyWrapper private struct PreferenceObserving: DynamicProperty { typealias PrefKeyPath = KeyPath> let keyPath: PrefKeyPath @StateObject private var observer: Observer init(_ keyPath: PrefKeyPath) { self.keyPath = keyPath self._observer = StateObject(wrappedValue: Observer(keyPath: keyPath)) } var wrappedValue: Key.Value { Preferences.shared.getValue(preferenceKeyPath: keyPath) } @MainActor private class Observer: ObservableObject { private var cancellable: AnyCancellable? init(keyPath: PrefKeyPath) { cancellable = Preferences.shared[keyPath: keyPath].sink { [unowned self] _ in self.objectWillChange.send() } } } }