// AppearancePrefsView.swift // Tusker // // Created by Shadowfacts on 6/13/19. // Copyright © 2019 Shadowfacts. All rights reserved. // import SwiftUI import Combine struct AppearancePrefsView : View { @ObservedObject var preferences = Preferences.shared private var appearanceChangePublisher: some Publisher { preferences.$theme .map { _ in () } .merge(with: preferences.$pureBlackDarkMode.map { _ in () }, preferences.$accentColor.map { _ in () } ) // the prefrence publishers are all willSet, but want to notify after the change, so wait one runloop iteration .receive(on: DispatchQueue.main) } private var useCircularAvatars: Binding = Binding(get: { Preferences.shared.avatarStyle == .circle }) { Preferences.shared.avatarStyle = $0 ? .circle : .roundRect } private let accentColorsAndImages: [(Preferences.AccentColor, UIImage?)] = Preferences.AccentColor.allCases.map { color in var image: UIImage? if let color = color.color { if #available(iOS 16.0, *) { image = UIImage(systemName: "circle.fill")!.withTintColor(color, renderingMode: .alwaysTemplate).withRenderingMode(.alwaysOriginal) } else { image = UIGraphicsImageRenderer(size: CGSize(width: 20, height: 20)).image { context in color.setFill() context.cgContext.fillEllipse(in: CGRect(x: 0, y: 0, width: 20, height: 20)) } } } return (color, image) } var body: some View { List { themeSection interfaceSection accountsSection postsSection } .listStyle(.insetGrouped) .appGroupedListBackground(container: PreferencesNavigationController.self) .navigationBarTitle(Text("Appearance")) } private var themeSection: some View { Section { #if !os(visionOS) Picker(selection: $preferences.theme, label: Text("Theme")) { Text("Use System Theme").tag(UIUserInterfaceStyle.unspecified) Text("Light").tag(UIUserInterfaceStyle.light) Text("Dark").tag(UIUserInterfaceStyle.dark) } // macOS system dark mode isn't pure black, so this isn't necessary if !ProcessInfo.processInfo.isMacCatalystApp && !ProcessInfo.processInfo.isiOSAppOnMac { Toggle(isOn: $preferences.pureBlackDarkMode) { Text("Pure Black Dark Mode") } } #endif Picker(selection: $preferences.accentColor, label: Text("Accent Color")) { ForEach(accentColorsAndImages, id: \.0.rawValue) { (color, image) in HStack { Text(color.name) if let image { Spacer() Image(uiImage: image) } } .tag(color) } } } .onReceive(appearanceChangePublisher) { _ in NotificationCenter.default.post(name: .themePreferenceChanged, object: nil) } .appGroupedListRowBackground() } @ViewBuilder private var interfaceSection: some View { let visionIdiom = UIUserInterfaceIdiom(rawValue: 6) if [visionIdiom, .pad, .mac].contains(UIDevice.current.userInterfaceIdiom) { Section(header: Text("Interface")) { WidescreenNavigationPrefsView() } .appGroupedListRowBackground() } } private var accountsSection: some View { Section(header: Text("Accounts")) { Toggle(isOn: useCircularAvatars) { Text("Use Circular Avatars") } Toggle(isOn: $preferences.hideCustomEmojiInUsernames) { Text("Hide Custom Emoji in Usernames") } } .appGroupedListRowBackground() } private var postsSection: some View { Section(header: Text("Posts")) { Toggle(isOn: $preferences.showIsStatusReplyIcon) { Text("Show Status Reply Icons") } Toggle(isOn: $preferences.alwaysShowStatusVisibilityIcon) { Text("Always Show Status Visibility Icons") } Toggle(isOn: $preferences.showLinkPreviews) { Text("Show Link Previews") } Toggle(isOn: $preferences.showAttachmentsInTimeline) { Text("Show Attachments on Timeline") } Toggle(isOn: $preferences.hideActionsInTimeline) { Text("Hide Actions on Timeline") } Toggle(isOn: $preferences.underlineTextLinks) { Text("Underline Links") } NavigationLink("Leading Swipe Actions") { SwipeActionsPrefsView(selection: $preferences.leadingStatusSwipeActions) .edgesIgnoringSafeArea(.all) .navigationTitle("Leading Swipe Actions") } NavigationLink("Trailing Swipe Actions") { SwipeActionsPrefsView(selection: $preferences.trailingStatusSwipeActions) .edgesIgnoringSafeArea(.all) .navigationTitle("Trailing Swipe Actions") } } .appGroupedListRowBackground() } } #if DEBUG struct AppearancePrefsView_Previews : PreviewProvider { static var previews: some View { AppearancePrefsView() } } #endif