From 20c4c4bb2fcb7b2d37a451b7e588343a57a0bfe2 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Thu, 2 Feb 2023 23:02:11 -0500 Subject: [PATCH] Start adding non-pure-black dark mode --- .../Sources/Pachyderm/Model/Account.swift | 2 +- Tusker.xcodeproj/project.pbxproj | 8 ++ Tusker/AppDelegate.swift | 21 ++++ Tusker/Preferences/Colors.swift | 104 ++++++++++++++++++ Tusker/Preferences/Preferences.swift | 4 + Tusker/Scenes/MainSceneDelegate.swift | 9 +- .../AccountFollowsListViewController.swift | 13 ++- .../AccountListViewController.swift | 3 +- .../AssetCollectionViewController.swift | 3 +- .../AssetCollectionsListViewController.swift | 1 + .../Bookmarks/BookmarksViewController.swift | 1 + .../Compose/ComposeAttachmentsList.swift | 2 +- Tusker/Screens/Compose/ComposePollView.swift | 6 +- Tusker/Screens/Compose/ComposeView.swift | 9 ++ .../Screens/Compose/MainComposeTextView.swift | 3 +- ...ConversationCollectionViewController.swift | 4 +- .../ConversationViewController.swift | 2 +- .../ExpandThreadCollectionViewCell.swift | 13 +-- .../AddHashtagPinnedTimelineView.swift | 27 ++++- .../CustomizeTimelinesView.swift | 10 ++ .../Customize Timelines/EditFilterView.swift | 19 ++++ .../PinnedTimelinesView.swift | 8 +- .../AddSavedHashtagViewController.swift | 4 +- .../Explore/ExploreViewController.swift | 13 ++- .../FeaturedProfileCollectionViewCell.swift | 1 + .../FeaturedProfileCollectionViewCell.xib | 7 +- .../ProfileDirectoryViewController.swift | 2 +- ...ggestedProfileCardCollectionViewCell.swift | 1 + .../TrendingLinkCardCollectionViewCell.swift | 1 + .../Explore/TrendingLinkTableViewCell.swift | 10 ++ .../Explore/TrendingLinksViewController.swift | 1 + .../EditListAccountsViewController.swift | 10 ++ Tusker/Screens/Mute/MuteAccountView.swift | 8 ++ .../NotificationsTableViewController.swift | 1 + .../InstanceSelectorTableViewController.swift | 7 +- .../Preferences/AppearancePrefsView.swift | 31 +++--- .../ProfileHeaderCollectionViewCell.swift | 2 +- .../ProfileStatusesViewController.swift | 5 +- .../Profile/ProfileViewController.swift | 2 +- .../Screens/Report/ReportAddStatusView.swift | 64 ++++++++--- .../Report/ReportSelectRulesView.swift | 16 +++ Tusker/Screens/Report/ReportView.swift | 18 ++- .../Search/SearchResultsViewController.swift | 36 ++++-- .../Screens/Search/SearchViewController.swift | 6 +- ...nAccountListCollectionViewController.swift | 20 ++++ ...tatusActionAccountListViewController.swift | 2 +- .../InstanceTimelineViewController.swift | 2 +- .../TimelineGapCollectionViewCell.swift | 4 +- .../Timeline/TimelineViewController.swift | 2 + .../Utilities/CustomAlertController.swift | 2 +- .../SegmentedPageViewController.swift | 2 +- .../Asset Picker/AlbumTableViewCell.swift | 10 ++ .../Asset Picker/AllPhotosTableViewCell.swift | 10 ++ Tusker/Views/ContentTextView.swift | 2 +- .../TrendingHashtagCollectionViewCell.swift | 12 +- .../Instance Cell/InstanceTableViewCell.swift | 10 ++ Tusker/Views/LoadingTableViewCell.swift | 2 + ...ActionNotificationGroupTableViewCell.swift | 10 ++ ...FollowNotificationGroupTableViewCell.swift | 10 ++ ...llowRequestNotificationTableViewCell.swift | 10 ++ .../PollFinishedTableViewCell.swift | 10 ++ ...atusUpdatedNotificationTableViewCell.swift | 10 ++ .../Profile Header/ProfileFieldsView.swift | 8 +- .../Profile Header/ProfileHeaderView.swift | 3 + .../Profile Header/ProfileHeaderView.xib | 1 - ...ersationMainStatusCollectionViewCell.swift | 6 + .../TimelineStatusCollectionViewCell.swift | 10 ++ .../Status/TimelineStatusTableViewCell.swift | 10 ++ .../TrendingStatusCollectionViewCell.swift | 21 ++++ Tusker/Views/TrendHistoryView.swift | 2 +- 70 files changed, 615 insertions(+), 94 deletions(-) create mode 100644 Tusker/Preferences/Colors.swift create mode 100644 Tusker/Views/Status/TrendingStatusCollectionViewCell.swift diff --git a/Packages/Pachyderm/Sources/Pachyderm/Model/Account.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/Account.swift index f18a719670..90f316f972 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Model/Account.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/Account.swift @@ -171,7 +171,7 @@ extension Account: CustomDebugStringConvertible { } extension Account { - public struct Field: Codable { + public struct Field: Codable, Equatable { public let name: String public let value: String public let verifiedAt: Date? diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 7f4562a1f8..7f1dc1a57c 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -321,6 +321,8 @@ D6D4DDF0212518A200E1C4BB /* TuskerUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D4DDEF212518A200E1C4BB /* TuskerUITests.swift */; }; D6D706A029466649000827ED /* ScrollingSegmentedControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D7069F29466649000827ED /* ScrollingSegmentedControl.swift */; }; D6D706A72948D4D0000827ED /* TimlineState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D706A62948D4D0000827ED /* TimlineState.swift */; }; + D6D94955298963A900C59229 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D94954298963A900C59229 /* Colors.swift */; }; + D6D9498D298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */; }; D6DD2A3F273C1F4900386A6C /* ComposeAttachmentImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD2A3E273C1F4900386A6C /* ComposeAttachmentImage.swift */; }; D6DD2A45273D6C5700386A6C /* GIFImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD2A44273D6C5700386A6C /* GIFImageView.swift */; }; D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */; }; @@ -734,6 +736,8 @@ D6D7069F29466649000827ED /* ScrollingSegmentedControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollingSegmentedControl.swift; sourceTree = ""; }; D6D706A62948D4D0000827ED /* TimlineState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimlineState.swift; sourceTree = ""; }; D6D706A829498C82000827ED /* Tusker.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Tusker.xcconfig; sourceTree = ""; }; + D6D94954298963A900C59229 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; }; + D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingStatusCollectionViewCell.swift; sourceTree = ""; }; D6DD2A3E273C1F4900386A6C /* ComposeAttachmentImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeAttachmentImage.swift; sourceTree = ""; }; D6DD2A44273D6C5700386A6C /* GIFImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GIFImageView.swift; sourceTree = ""; }; D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarningCopyMode.swift; sourceTree = ""; }; @@ -1166,6 +1170,7 @@ D6ADB6E928E91C30009924AB /* TimelineStatusCollectionViewCell.swift */, D601FA60297B539E00A8E8B5 /* ConversationMainStatusCollectionViewCell.swift */, D6ADB6EB28EA73CB009924AB /* StatusContentContainer.swift */, + D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */, ); path = Status; sourceTree = ""; @@ -1259,6 +1264,7 @@ D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */, D6BC9DB4232D4CE3002CA326 /* NotificationsMode.swift */, D61F75872932DB6000C0B37F /* StatusSwipeAction.swift */, + D6D94954298963A900C59229 /* Colors.swift */, ); path = Preferences; sourceTree = ""; @@ -1986,6 +1992,7 @@ D6AC956723C4347E008C9946 /* MainSceneDelegate.swift in Sources */, D6311C5025B3765B00B27539 /* ImageDataCache.swift in Sources */, D6BC9DD7232D7811002CA326 /* TimelinesPageViewController.swift in Sources */, + D6D9498D298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift in Sources */, D60E2F2E244248BF005F8713 /* MastodonCachePersistentStore.swift in Sources */, D620483623D38075008A63EF /* ContentTextView.swift in Sources */, D651C5B42915B00400236EF6 /* ProfileFieldsView.swift in Sources */, @@ -1995,6 +2002,7 @@ D6A3BC802321B7E600FD64D5 /* FollowNotificationGroupTableViewCell.swift in Sources */, D627944D23A9A03D00D38C68 /* ListTimelineViewController.swift in Sources */, D6D12B2F2925D66500D528E1 /* TimelineGapCollectionViewCell.swift in Sources */, + D6D94955298963A900C59229 /* Colors.swift in Sources */, D6945C3823AC739F005C403C /* InstanceTimelineViewController.swift in Sources */, D625E4822588262A0074BB2B /* DraggableTableViewCell.swift in Sources */, D68E525B24A3D77E0054355A /* TuskerRootViewController.swift in Sources */, diff --git a/Tusker/AppDelegate.swift b/Tusker/AppDelegate.swift index 463f5c1849..136f37429e 100644 --- a/Tusker/AppDelegate.swift +++ b/Tusker/AppDelegate.swift @@ -20,6 +20,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { configureSentry() swizzleStatusBar() + swizzlePresentationController() AppShortcutItem.createItems(for: application) @@ -154,4 +155,24 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Logging.general.error("Unable to swizzle status bar manager") } } + + private func swizzlePresentationController() { + var originalIMP: IMP? + let imp = imp_implementationWithBlock({ (self: UIPresentationController) in + let new = UITraitCollection(pureBlackDarkMode: self.presentingViewController.traitCollection.pureBlackDarkMode) + if let existing = self.overrideTraitCollection { + self.overrideTraitCollection = UITraitCollection(traitsFrom: [existing, new]) + } else { + self.overrideTraitCollection = new + } + let original = unsafeBitCast(originalIMP!, to: (@convention(c) (UIPresentationController) -> Void).self) + original(self) + } as (@convention(block) (UIPresentationController) -> Void)) + let sel = Selector(["Necessary", "If", "Traits", "update", "_"].reversed().joined()) + originalIMP = class_replaceMethod(UIPresentationController.self, sel, imp, "v@:") + if originalIMP == nil { + Logging.general.error("Unable to swizzle presentation controller") + } + } + } diff --git a/Tusker/Preferences/Colors.swift b/Tusker/Preferences/Colors.swift new file mode 100644 index 0000000000..825fa2c233 --- /dev/null +++ b/Tusker/Preferences/Colors.swift @@ -0,0 +1,104 @@ +// +// Colors.swift +// Tusker +// +// Created by Shadowfacts on 1/31/23. +// Copyright © 2023 Shadowfacts. All rights reserved. +// + +import UIKit +import SwiftUI + +extension UIColor { + static let appBackground = UIColor { traitCollection in + if case .dark = traitCollection.userInterfaceStyle, + !traitCollection.pureBlackDarkMode { + return UIColor(hue: 230/360, saturation: 20/100, brightness: 10/100, alpha: 1) + } else { + return .systemBackground + } + } + + static let appSecondaryBackground = UIColor { traitCollection in + if case .dark = traitCollection.userInterfaceStyle, + !traitCollection.pureBlackDarkMode { + if traitCollection.userInterfaceLevel == .elevated { + return UIColor(hue: 230/360, saturation: 25/100, brightness: 10/100, alpha: 1) + } else { + return UIColor(hue: 230/360, saturation: 25/100, brightness: 5/100, alpha: 1) + } + } else { + return .secondarySystemBackground + } + } + + static let appGroupedBackground = UIColor { traitCollection in + if case .dark = traitCollection.userInterfaceStyle, + !traitCollection.pureBlackDarkMode { + return .appSecondaryBackground + } else { + return .systemGroupedBackground + } + } + + static let appSelectedCellBackground = UIColor { traitCollection in + if case .dark = traitCollection.userInterfaceStyle, + !traitCollection.pureBlackDarkMode { + return UIColor(hue: 230/360, saturation: 20/100, brightness: 27/100, alpha: 1) + } else { + return .systemFill + } + } + + static let appGroupedCellBackground = UIColor { traitCollection in + if case .dark = traitCollection.userInterfaceStyle { + if traitCollection.pureBlackDarkMode { + return .secondarySystemBackground + } else { + return .appFill + } + } else { + return .systemBackground + } + } + + static let appFill = UIColor { traitCollection in + if case .dark = traitCollection.userInterfaceStyle, + !traitCollection.pureBlackDarkMode { + return UIColor(hue: 230/360, saturation: 20/100, brightness: 17/100, alpha: 1) + } else { + return .systemFill + } + } +} + +extension Color { + static let appBackground = Color(uiColor: .appBackground) + static let appGroupedBackground = Color(uiColor: .appGroupedBackground) + static let appSecondaryBackground = Color(uiColor: .appSecondaryBackground) + static let appSelectedCellBackground = Color(uiColor: .appGroupedCellBackground) + static let appGroupedCellBackground = Color(uiColor: .appGroupedCellBackground) + static let appFill = Color(uiColor: .appFill) +} + +private let traitsKey: String = ["Traits", "Defined", "client", "_"].reversed().joined() +private let key = "tusker_usePureBlackDarkMode" + +extension UITraitCollection { + var pureBlackDarkMode: Bool { + get { + // default to true to mach OS behavior + (value(forKey: traitsKey) as? [String: Any])?[key] as? Bool ?? true + } + set { + var dict = value(forKey: traitsKey) as? [String: Any] ?? [:] + dict[key] = newValue + setValue(dict, forKey: traitsKey) + } + } + + convenience init(pureBlackDarkMode: Bool) { + self.init() + self.pureBlackDarkMode = pureBlackDarkMode + } +} diff --git a/Tusker/Preferences/Preferences.swift b/Tusker/Preferences/Preferences.swift index d857c78b1c..78da9d3a1c 100644 --- a/Tusker/Preferences/Preferences.swift +++ b/Tusker/Preferences/Preferences.swift @@ -38,6 +38,7 @@ class Preferences: Codable, ObservableObject { let container = try decoder.container(keyedBy: CodingKeys.self) self.theme = try container.decode(UIUserInterfaceStyle.self, forKey: .theme) + self.pureBlackDarkMode = try container.decodeIfPresent(Bool.self, forKey: .pureBlackDarkMode) ?? true self.accentColor = try container.decodeIfPresent(AccentColor.self, forKey: .accentColor) ?? .default self.avatarStyle = try container.decode(AvatarStyle.self, forKey: .avatarStyle) self.hideCustomEmojiInUsernames = try container.decode(Bool.self, forKey: .hideCustomEmojiInUsernames) @@ -92,6 +93,7 @@ class Preferences: Codable, ObservableObject { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(theme, forKey: .theme) + try container.encode(pureBlackDarkMode, forKey: .pureBlackDarkMode) try container.encode(accentColor, forKey: .accentColor) try container.encode(avatarStyle, forKey: .avatarStyle) try container.encode(hideCustomEmojiInUsernames, forKey: .hideCustomEmojiInUsernames) @@ -140,6 +142,7 @@ class Preferences: Codable, ObservableObject { // MARK: Appearance @Published var theme = UIUserInterfaceStyle.unspecified + @Published var pureBlackDarkMode = true @Published var accentColor = AccentColor.default @Published var avatarStyle = AvatarStyle.roundRect @Published var hideCustomEmojiInUsernames = false @@ -202,6 +205,7 @@ class Preferences: Codable, ObservableObject { private enum CodingKeys: String, CodingKey { case theme + case pureBlackDarkMode case accentColor case avatarStyle case hideCustomEmojiInUsernames diff --git a/Tusker/Scenes/MainSceneDelegate.swift b/Tusker/Scenes/MainSceneDelegate.swift index 43c1a731f5..68dfe4529c 100644 --- a/Tusker/Scenes/MainSceneDelegate.swift +++ b/Tusker/Scenes/MainSceneDelegate.swift @@ -243,8 +243,13 @@ class MainSceneDelegate: UIResponder, UIWindowSceneDelegate, TuskerSceneDelegate } @objc func themePrefChanged() { - window?.overrideUserInterfaceStyle = Preferences.shared.theme - window?.tintColor = Preferences.shared.accentColor.color + guard let window else { return } + window.overrideUserInterfaceStyle = Preferences.shared.theme + window.tintColor = Preferences.shared.accentColor.color + let key = ["Controller", "Presentation", "root", "_"].reversed().joined() + if let rootPresentationController = window.value(forKey: key) as? UIPresentationController { + rootPresentationController.overrideTraitCollection = UITraitCollection(pureBlackDarkMode: Preferences.shared.pureBlackDarkMode) + } } func showAddAccount() { diff --git a/Tusker/Screens/Account Follows/AccountFollowsListViewController.swift b/Tusker/Screens/Account Follows/AccountFollowsListViewController.swift index 4ecfc48092..494c6079a7 100644 --- a/Tusker/Screens/Account Follows/AccountFollowsListViewController.swift +++ b/Tusker/Screens/Account Follows/AccountFollowsListViewController.swift @@ -41,7 +41,8 @@ class AccountFollowsListViewController: UIViewController, CollectionViewControll } override func loadView() { - var config = UICollectionLayoutListConfiguration(appearance: .grouped) + var config = UICollectionLayoutListConfiguration(appearance: .plain) + config.backgroundColor = .appBackground config.itemSeparatorHandler = { [unowned self] indexPath, sectionConfig in guard let item = self.dataSource.itemIdentifier(for: indexPath) else { return sectionConfig @@ -65,6 +66,16 @@ class AccountFollowsListViewController: UIViewController, CollectionViewControll let accountCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, item in cell.delegate = self cell.updateUI(accountID: item) + + cell.configurationUpdateHandler = { cell, state in + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + cell.backgroundConfiguration = config + } } let loadingCell = UICollectionView.CellRegistration { cell, indexPath, item in cell.indicator.startAnimating() diff --git a/Tusker/Screens/Account List/AccountListViewController.swift b/Tusker/Screens/Account List/AccountListViewController.swift index b05d1546a5..5a14d24b7c 100644 --- a/Tusker/Screens/Account List/AccountListViewController.swift +++ b/Tusker/Screens/Account List/AccountListViewController.swift @@ -31,7 +31,8 @@ class AccountListViewController: UIViewController, CollectionViewController { } override func loadView() { - let config = UICollectionLayoutListConfiguration(appearance: .grouped) + var config = UICollectionLayoutListConfiguration(appearance: .grouped) + config.backgroundColor = .appGroupedBackground let layout = UICollectionViewCompositionalLayout.list(using: config) view = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.delegate = self diff --git a/Tusker/Screens/Asset Picker/AssetCollectionViewController.swift b/Tusker/Screens/Asset Picker/AssetCollectionViewController.swift index 72f5d27b9a..def706caac 100644 --- a/Tusker/Screens/Asset Picker/AssetCollectionViewController.swift +++ b/Tusker/Screens/Asset Picker/AssetCollectionViewController.swift @@ -72,7 +72,8 @@ class AssetCollectionViewController: UIViewController, UICollectionViewDelegate // bottom ignores safe area because we want cells to underflow bottom of the screen on notched iPhones view.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor), ]) - view.backgroundColor = .systemBackground + view.backgroundColor = .appBackground + collectionView.backgroundColor = .appBackground navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(donePressed)) diff --git a/Tusker/Screens/Asset Picker/AssetCollectionsListViewController.swift b/Tusker/Screens/Asset Picker/AssetCollectionsListViewController.swift index d3c008b21b..ba0bbd7ad6 100644 --- a/Tusker/Screens/Asset Picker/AssetCollectionsListViewController.swift +++ b/Tusker/Screens/Asset Picker/AssetCollectionsListViewController.swift @@ -34,6 +34,7 @@ class AssetCollectionsListViewController: UITableViewController { tableView.register(UINib(nibName: "AlbumTableViewCell", bundle: .main), forCellReuseIdentifier: "albumCell") tableView.allowsFocus = true + tableView.backgroundColor = .appGroupedBackground dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in switch item { diff --git a/Tusker/Screens/Bookmarks/BookmarksViewController.swift b/Tusker/Screens/Bookmarks/BookmarksViewController.swift index cd77c8a0b3..301c8e01dc 100644 --- a/Tusker/Screens/Bookmarks/BookmarksViewController.swift +++ b/Tusker/Screens/Bookmarks/BookmarksViewController.swift @@ -39,6 +39,7 @@ class BookmarksViewController: UIViewController, CollectionViewController, Refre override func loadView() { var config = UICollectionLayoutListConfiguration(appearance: .plain) + config.backgroundColor = .appBackground config.leadingSwipeActionsConfigurationProvider = { [unowned self] in (collectionView.cellForItem(at: $0) as? TimelineStatusCollectionViewCell)?.leadingSwipeActions() } diff --git a/Tusker/Screens/Compose/ComposeAttachmentsList.swift b/Tusker/Screens/Compose/ComposeAttachmentsList.swift index 282fd3837c..743caa0e93 100644 --- a/Tusker/Screens/Compose/ComposeAttachmentsList.swift +++ b/Tusker/Screens/Compose/ComposeAttachmentsList.swift @@ -112,7 +112,7 @@ struct ComposeAttachmentsList: View { self.isShowingAssetPickerPopover = false } // on iPadOS 16, this is necessary to show the dark color in the popover arrow - .background(Color(.systemBackground)) + .background(Color(.appBackground)) .environment(\.colorScheme, .dark) .edgesIgnoringSafeArea(.bottom) .withSheetDetentsIfAvailable() diff --git a/Tusker/Screens/Compose/ComposePollView.swift b/Tusker/Screens/Compose/ComposePollView.swift index ebc4526fd2..073288776d 100644 --- a/Tusker/Screens/Compose/ComposePollView.swift +++ b/Tusker/Screens/Compose/ComposePollView.swift @@ -96,7 +96,7 @@ struct ComposePollView: View { private var backgroundColor: Color { // in light mode, .secondarySystemBackground has a blue-ish hue, which we don't want - colorScheme == .dark ? Color(UIColor.secondarySystemBackground) : Color(white: 0.95) + colorScheme == .dark ? Color.appFill : Color(white: 0.95) } private var buttonBackgroundColor: Color { @@ -174,7 +174,7 @@ struct ComposePollOption: View { private var textField: some View { var field = ComposeEmojiTextField(text: $option.text, placeholder: "Option \(optionIndex + 1)") - return field.backgroundColor(.systemBackground) + return field.backgroundColor(.appBackground) } private func removeOption() { @@ -199,7 +199,7 @@ struct ComposePollOption: View { .cornerRadius(radiusFraction * size) Rectangle() - .foregroundColor(Color(UIColor.systemBackground)) + .foregroundColor(Color(UIColor.appBackground)) .frame(width: innerSize, height: innerSize) .cornerRadius(radiusFraction * innerSize) } diff --git a/Tusker/Screens/Compose/ComposeView.swift b/Tusker/Screens/Compose/ComposeView.swift index eeecbe536c..2d869b70a5 100644 --- a/Tusker/Screens/Compose/ComposeView.swift +++ b/Tusker/Screens/Compose/ComposeView.swift @@ -94,6 +94,9 @@ struct ComposeView: View { var body: some View { ZStack(alignment: .top) { + // just using .background doesn't work; for some reason it gets inset immediately after the software keyboard is dismissed + Color.appBackground + mainList .scrollDismissesKeyboardInteractivelyIfAvailable() @@ -169,11 +172,13 @@ struct ComposeView: View { ) .listRowInsets(EdgeInsets(top: 8, leading: 8, bottom: 4, trailing: 8)) .listRowSeparator(.hidden) + .listRowBackground(Color.appBackground) } header .listRowInsets(EdgeInsets(top: draft.inReplyToID == nil ? 8 : 4, leading: 8, bottom: 4, trailing: 8)) .listRowSeparator(.hidden) + .listRowBackground(Color.appBackground) if uiState.draft.contentWarningEnabled { ComposeEmojiTextField( @@ -184,6 +189,7 @@ struct ComposeView: View { ) .listRowInsets(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8)) .listRowSeparator(.hidden) + .listRowBackground(Color.appBackground) } MainComposeTextView( @@ -192,17 +198,20 @@ struct ComposeView: View { ) .listRowInsets(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8)) .listRowSeparator(.hidden) + .listRowBackground(Color.appBackground) if let poll = draft.poll { ComposePollView(draft: draft, poll: poll) .listRowInsets(EdgeInsets(top: 4, leading: 8, bottom: 4, trailing: 8)) .listRowSeparator(.hidden) + .listRowBackground(Color.appBackground) } ComposeAttachmentsList( draft: draft ) .listRowInsets(EdgeInsets(top: 4, leading: 8, bottom: 8, trailing: 8)) + .listRowBackground(Color.appBackground) } .animation(.default, value: draft.poll?.options.count) .scrollDismissesKeyboardInteractivelyIfAvailable() diff --git a/Tusker/Screens/Compose/MainComposeTextView.swift b/Tusker/Screens/Compose/MainComposeTextView.swift index 2746acc01d..c56574a946 100644 --- a/Tusker/Screens/Compose/MainComposeTextView.swift +++ b/Tusker/Screens/Compose/MainComposeTextView.swift @@ -38,10 +38,11 @@ struct MainComposeTextView: View { @Binding var becomeFirstResponder: Bool @State private var hasFirstAppeared = false @ScaledMetric private var fontSize = 20 + @Environment(\.colorScheme) private var colorScheme var body: some View { ZStack(alignment: .topLeading) { - Color(UIColor.secondarySystemBackground) + colorScheme == .dark ? Color.appFill : Color(uiColor: .secondarySystemBackground) if draft.text.isEmpty { placeholder diff --git a/Tusker/Screens/Conversation/ConversationCollectionViewController.swift b/Tusker/Screens/Conversation/ConversationCollectionViewController.swift index 57915d12b3..a05a3bcd78 100644 --- a/Tusker/Screens/Conversation/ConversationCollectionViewController.swift +++ b/Tusker/Screens/Conversation/ConversationCollectionViewController.swift @@ -47,7 +47,7 @@ class ConversationCollectionViewController: UIViewController, CollectionViewCont override func loadView() { var config = UICollectionLayoutListConfiguration(appearance: .plain) - config.backgroundColor = .secondarySystemBackground + config.backgroundColor = .appSecondaryBackground config.leadingSwipeActionsConfigurationProvider = { [unowned self] in (collectionView.cellForItem(at: $0) as? TimelineStatusCollectionViewCell)?.leadingSwipeActions() } @@ -65,7 +65,7 @@ class ConversationCollectionViewController: UIViewController, CollectionViewCont } // we're not using contenetInsetsReference = .readableContent here because it always insets the cells even if // the collection view's actual width is narrow enough to fit in the readable width, resulting in a bit of the - // background color always peaking through the edges + // background color always peeking through the edges let layout = UICollectionViewCompositionalLayout.list(using: config) view = UICollectionView(frame: .zero, collectionViewLayout: layout) // something about the autoresizing mask breaks resizing the vc diff --git a/Tusker/Screens/Conversation/ConversationViewController.swift b/Tusker/Screens/Conversation/ConversationViewController.swift index 167b6e7a11..83595181d5 100644 --- a/Tusker/Screens/Conversation/ConversationViewController.swift +++ b/Tusker/Screens/Conversation/ConversationViewController.swift @@ -86,7 +86,7 @@ class ConversationViewController: UIViewController { title = NSLocalizedString("Conversation", comment: "conversation screen title") - view.backgroundColor = .secondarySystemBackground + view.backgroundColor = .appSecondaryBackground collapseBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "eye.fill")!, style: .plain, target: self, action: #selector(toggleCollapseButtonPressed)) updateVisibilityBarButtonItem() diff --git a/Tusker/Screens/Conversation/ExpandThreadCollectionViewCell.swift b/Tusker/Screens/Conversation/ExpandThreadCollectionViewCell.swift index e7e1400deb..28685a19ce 100644 --- a/Tusker/Screens/Conversation/ExpandThreadCollectionViewCell.swift +++ b/Tusker/Screens/Conversation/ExpandThreadCollectionViewCell.swift @@ -141,18 +141,13 @@ class ExpandThreadCollectionViewCell: UICollectionViewListCell { } override func updateConfiguration(using state: UICellConfigurationState) { - var config = UIBackgroundConfiguration.listPlainCell() + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) if state.isSelected || state.isHighlighted { - var hue: CGFloat = 0 - var saturation: CGFloat = 0 - var brightness: CGFloat = 0 - UIColor.secondarySystemBackground.getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: nil) - let sign: CGFloat = traitCollection.userInterfaceStyle == .dark ? 1 : -1 - config.backgroundColor = UIColor(hue: hue, saturation: saturation, brightness: max(0, brightness + sign * 0.1), alpha: 1) + config.backgroundColor = .appSelectedCellBackground } else { - config.backgroundColor = .secondarySystemBackground + config.backgroundColor = .appSecondaryBackground } - backgroundConfiguration = config.updated(for: state) + backgroundConfiguration = config } } diff --git a/Tusker/Screens/Customize Timelines/AddHashtagPinnedTimelineView.swift b/Tusker/Screens/Customize Timelines/AddHashtagPinnedTimelineView.swift index f4604c4a9d..7bdad8adfa 100644 --- a/Tusker/Screens/Customize Timelines/AddHashtagPinnedTimelineView.swift +++ b/Tusker/Screens/Customize Timelines/AddHashtagPinnedTimelineView.swift @@ -9,6 +9,21 @@ import SwiftUI import Pachyderm +@available(iOS, obsoleted: 16.0) +struct AddHashtagPinnedTimelineRepresentable: UIViewControllerRepresentable { + typealias UIViewControllerType = UIHostingController + + @Binding var pinnedTimelines: [PinnedTimeline] + + func makeUIViewController(context: Context) -> UIHostingController { + UITableView.appearance(whenContainedInInstancesOf: [UIViewControllerType.self]).backgroundColor = .appGroupedBackground + return UIHostingController(rootView: AddHashtagPinnedTimelineView(pinnedTimelines: $pinnedTimelines)) + } + + func updateUIViewController(_ uiViewController: UIHostingController, context: Context) { + } +} + struct AddHashtagPinnedTimelineView: View { @EnvironmentObject private var mastodonController: MastodonController @Environment(\.dismiss) private var dismiss @@ -57,8 +72,9 @@ struct AddHashtagPinnedTimelineView: View { }) } + @ViewBuilder private var list: some View { - List { + let list = List { Section { if viewModel.searchQuery.isEmpty { forEachTag(savedAndFollowedHashtags) @@ -73,8 +89,17 @@ struct AddHashtagPinnedTimelineView: View { .listRowBackground(EmptyView()) .listRowSeparator(.hidden) } + .listRowBackground(Color.appGroupedCellBackground) } .listStyle(.grouped) + + if #available(iOS 16.0, *) { + list + .scrollContentBackground(.hidden) + .background(Color.appGroupedBackground) + } else { + list + } } private func forEachTag(_ tags: [String]) -> some View { diff --git a/Tusker/Screens/Customize Timelines/CustomizeTimelinesView.swift b/Tusker/Screens/Customize Timelines/CustomizeTimelinesView.swift index f017f8eb86..f18e5df3bd 100644 --- a/Tusker/Screens/Customize Timelines/CustomizeTimelinesView.swift +++ b/Tusker/Screens/Customize Timelines/CustomizeTimelinesView.swift @@ -31,10 +31,15 @@ struct CustomizeTimelinesList: View { if #available(iOS 16.0, *) { NavigationStack { navigationBody + .scrollContentBackground(.hidden) + .background(Color.appGroupedBackground) } } else { NavigationView { navigationBody + .onAppear { + UITableView.appearance(whenContainedInInstancesOf: [UIHostingController.self]).backgroundColor = .appGroupedBackground + } } .navigationViewStyle(.stack) } @@ -51,6 +56,7 @@ struct CustomizeTimelinesList: View { private var navigationBody: some View { List { PinnedTimelinesView(accountPreferences: mastodonController.accountPreferences) + .listRowBackground(Color.appGroupedCellBackground) Section { Toggle(isOn: $preferences.hideReblogsInTimelines) { @@ -62,6 +68,7 @@ struct CustomizeTimelinesList: View { } header: { Text("Home Timeline") } + .listRowBackground(Color.appGroupedCellBackground) Section { filtersForEach(unexpiredFilters) @@ -75,6 +82,7 @@ struct CustomizeTimelinesList: View { } header: { Text("Active Filters") } + .listRowBackground(Color.appGroupedCellBackground) if !expiredFilters.isEmpty { Section { @@ -82,8 +90,10 @@ struct CustomizeTimelinesList: View { } header: { Text("Expired Filters") } + .listRowBackground(Color.appGroupedCellBackground) } } + .listStyle(.insetGrouped) .navigationTitle(Text("Customize Timelines")) .navigationBarTitleDisplayMode(.inline) .toolbar { diff --git a/Tusker/Screens/Customize Timelines/EditFilterView.swift b/Tusker/Screens/Customize Timelines/EditFilterView.swift index 4b1bc535b8..576ec9b9e4 100644 --- a/Tusker/Screens/Customize Timelines/EditFilterView.swift +++ b/Tusker/Screens/Customize Timelines/EditFilterView.swift @@ -72,6 +72,7 @@ struct EditFilterView: View { filter.title = newValue })) } + .listRowBackground(Color.appGroupedCellBackground) } Section { @@ -96,6 +97,7 @@ struct EditFilterView: View { } } } + .listRowBackground(Color.appGroupedCellBackground) Section { if mastodonController.instanceFeatures.filtersV2 { @@ -120,6 +122,7 @@ struct EditFilterView: View { } } } + .listRowBackground(Color.appGroupedCellBackground) Section { ForEach(FilterV1.Context.allCases, id: \.rawValue) { context in @@ -141,7 +144,9 @@ struct EditFilterView: View { } header: { Text("Contexts") } + .listRowBackground(Color.appGroupedCellBackground) } + .scrollContentBackgroundIfAvailable() .navigationTitle(create ? "Add Filter" : "Edit Filter") .navigationBarTitleDisplayMode(.inline) .toolbar { @@ -208,6 +213,20 @@ private struct FilterContextToggleStyle: ToggleStyle { } } +private extension View { + @available(iOS, obsoleted: 16.0) + @ViewBuilder + func scrollContentBackgroundIfAvailable() -> some View { + if #available(iOS 16.0, *) { + self + .scrollContentBackground(.hidden) + .background(Color.appGroupedBackground) + } else { + self + } + } +} + //struct EditFilterView_Previews: PreviewProvider { // static var previews: some View { // EditFilterView() diff --git a/Tusker/Screens/Customize Timelines/PinnedTimelinesView.swift b/Tusker/Screens/Customize Timelines/PinnedTimelinesView.swift index 504731db23..e1e3859c66 100644 --- a/Tusker/Screens/Customize Timelines/PinnedTimelinesView.swift +++ b/Tusker/Screens/Customize Timelines/PinnedTimelinesView.swift @@ -111,7 +111,13 @@ struct PinnedTimelinesView: View { Text("Pinned Timelines") } .sheet(isPresented: $isShowingAddHashtagSheet, content: { - AddHashtagPinnedTimelineView(pinnedTimelines: $pinnedTimelines) + if #available(iOS 16.0, *) { + AddHashtagPinnedTimelineView(pinnedTimelines: $pinnedTimelines) + .edgesIgnoringSafeArea(.bottom) + } else { + AddHashtagPinnedTimelineRepresentable(pinnedTimelines: $pinnedTimelines) + .edgesIgnoringSafeArea(.bottom) + } }) .sheet(isPresented: $isShowingAddInstanceSheet, content: { AddInstancePinnedTimelineView(pinnedTimelines: $pinnedTimelines) diff --git a/Tusker/Screens/Explore/AddSavedHashtagViewController.swift b/Tusker/Screens/Explore/AddSavedHashtagViewController.swift index f02332f4f1..1eb7134a0c 100644 --- a/Tusker/Screens/Explore/AddSavedHashtagViewController.swift +++ b/Tusker/Screens/Explore/AddSavedHashtagViewController.swift @@ -34,15 +34,15 @@ class AddSavedHashtagViewController: UIViewController { title = NSLocalizedString("Search", comment: "search screen title") - view.backgroundColor = .systemGroupedBackground - var config = UICollectionLayoutListConfiguration(appearance: .grouped) + config.backgroundColor = .appGroupedBackground config.headerMode = .supplementary let layout = UICollectionViewCompositionalLayout.list(using: config) collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout) collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] collectionView.delegate = self collectionView.allowsFocus = true + collectionView.backgroundColor = .appGroupedBackground view.addSubview(collectionView) let sectionHeaderCell = UICollectionView.SupplementaryRegistration(elementKind: UICollectionView.elementKindSectionHeader) { (headerView, collectionView, indexPath) in diff --git a/Tusker/Screens/Explore/ExploreViewController.swift b/Tusker/Screens/Explore/ExploreViewController.swift index 7e3925a107..506885cac5 100644 --- a/Tusker/Screens/Explore/ExploreViewController.swift +++ b/Tusker/Screens/Explore/ExploreViewController.swift @@ -43,7 +43,8 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate, Collect super.viewDidLoad() var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) - configuration.trailingSwipeActionsConfigurationProvider = self.trailingSwipeActionsForCell(at:) + configuration.backgroundColor = .appGroupedBackground + configuration.trailingSwipeActionsConfigurationProvider = { [unowned self] in self.trailingSwipeActionsForCell(at: $0) } configuration.headerMode = .supplementary let layout = UICollectionViewCompositionalLayout.list(using: configuration) collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout) @@ -129,6 +130,16 @@ class ExploreViewController: UIViewController, UICollectionViewDelegate, Collect config.text = item.label config.image = item.image cell.contentConfiguration = config + + cell.configurationUpdateHandler = { cell, state in + var config = UIBackgroundConfiguration.listGroupedCell() + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + cell.backgroundConfiguration = config + } switch item { case .addList, .addSavedHashtag, .findInstance: diff --git a/Tusker/Screens/Explore/FeaturedProfileCollectionViewCell.swift b/Tusker/Screens/Explore/FeaturedProfileCollectionViewCell.swift index ca3174891c..151ccce75f 100644 --- a/Tusker/Screens/Explore/FeaturedProfileCollectionViewCell.swift +++ b/Tusker/Screens/Explore/FeaturedProfileCollectionViewCell.swift @@ -39,6 +39,7 @@ class FeaturedProfileCollectionViewCell: UICollectionViewCell { noteTextView.textContainerInset = UIEdgeInsets(top: 16, left: 4, bottom: 16, right: 4) backgroundColor = .clear + clippingView.backgroundColor = .appBackground clippingView.layer.cornerRadius = 5 clippingView.layer.borderWidth = 1 clippingView.layer.masksToBounds = true diff --git a/Tusker/Screens/Explore/FeaturedProfileCollectionViewCell.xib b/Tusker/Screens/Explore/FeaturedProfileCollectionViewCell.xib index 99ec2f5f6c..4faaaaf974 100644 --- a/Tusker/Screens/Explore/FeaturedProfileCollectionViewCell.xib +++ b/Tusker/Screens/Explore/FeaturedProfileCollectionViewCell.xib @@ -1,9 +1,9 @@ - + - + @@ -55,7 +55,6 @@ - Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. @@ -102,7 +101,7 @@ - + diff --git a/Tusker/Screens/Explore/ProfileDirectoryViewController.swift b/Tusker/Screens/Explore/ProfileDirectoryViewController.swift index 88b7d4c0af..6b6b2499ee 100644 --- a/Tusker/Screens/Explore/ProfileDirectoryViewController.swift +++ b/Tusker/Screens/Explore/ProfileDirectoryViewController.swift @@ -64,7 +64,7 @@ class ProfileDirectoryViewController: UIViewController { collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout) collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] - collectionView.backgroundColor = .secondarySystemBackground + collectionView.backgroundColor = .appSecondaryBackground collectionView.register(UINib(nibName: "FeaturedProfileCollectionViewCell", bundle: .main), forCellWithReuseIdentifier: "featuredProfileCell") collectionView.delegate = self collectionView.dragDelegate = self diff --git a/Tusker/Screens/Explore/SuggestedProfileCardCollectionViewCell.swift b/Tusker/Screens/Explore/SuggestedProfileCardCollectionViewCell.swift index 9a0688ac57..dfa0ca60c6 100644 --- a/Tusker/Screens/Explore/SuggestedProfileCardCollectionViewCell.swift +++ b/Tusker/Screens/Explore/SuggestedProfileCardCollectionViewCell.swift @@ -36,6 +36,7 @@ class SuggestedProfileCardCollectionViewCell: UICollectionViewCell { layer.shadowOffset = .zero layer.masksToBounds = false contentView.layer.cornerRadius = 12.5 + contentView.backgroundColor = .appGroupedCellBackground updateLayerColors() headerImageView.cache = .headers diff --git a/Tusker/Screens/Explore/TrendingLinkCardCollectionViewCell.swift b/Tusker/Screens/Explore/TrendingLinkCardCollectionViewCell.swift index 13e11f2292..98bea58c3b 100644 --- a/Tusker/Screens/Explore/TrendingLinkCardCollectionViewCell.swift +++ b/Tusker/Screens/Explore/TrendingLinkCardCollectionViewCell.swift @@ -34,6 +34,7 @@ class TrendingLinkCardCollectionViewCell: UICollectionViewCell { layer.shadowOffset = .zero layer.masksToBounds = false contentView.layer.cornerRadius = 12.5 + contentView.backgroundColor = .appGroupedCellBackground updateLayerColors() addGestureRecognizer(UIHoverGestureRecognizer(target: self, action: #selector(hoverRecognized))) diff --git a/Tusker/Screens/Explore/TrendingLinkTableViewCell.swift b/Tusker/Screens/Explore/TrendingLinkTableViewCell.swift index ce7f1b8f99..5e33451051 100644 --- a/Tusker/Screens/Explore/TrendingLinkTableViewCell.swift +++ b/Tusker/Screens/Explore/TrendingLinkTableViewCell.swift @@ -79,6 +79,16 @@ class TrendingLinkTableViewCell: UITableViewCell { thumbnailView.layer.cornerRadius = 0.05 * thumbnailView.bounds.width } + + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + backgroundConfiguration = config + } func updateUI(card: Card) { self.card = card diff --git a/Tusker/Screens/Explore/TrendingLinksViewController.swift b/Tusker/Screens/Explore/TrendingLinksViewController.swift index 106fb249b5..9eebeb8a3f 100644 --- a/Tusker/Screens/Explore/TrendingLinksViewController.swift +++ b/Tusker/Screens/Explore/TrendingLinksViewController.swift @@ -37,6 +37,7 @@ class TrendingLinksViewController: EnhancedTableViewController { tableView.register(TrendingLinkTableViewCell.self, forCellReuseIdentifier: "trendingLinkCell") tableView.estimatedRowHeight = 100 tableView.allowsFocus = true + tableView.backgroundColor = .appGroupedBackground dataSource = UITableViewDiffableDataSource(tableView: tableView, cellProvider: { tableView, indexPath, item in let cell = tableView.dequeueReusableCell(withIdentifier: "trendingLinkCell", for: indexPath) as! TrendingLinkTableViewCell diff --git a/Tusker/Screens/Lists/EditListAccountsViewController.swift b/Tusker/Screens/Lists/EditListAccountsViewController.swift index 4891959c85..bc595e49eb 100644 --- a/Tusker/Screens/Lists/EditListAccountsViewController.swift +++ b/Tusker/Screens/Lists/EditListAccountsViewController.swift @@ -54,6 +54,7 @@ class EditListAccountsViewController: EnhancedTableViewController { tableView.rowHeight = UITableView.automaticDimension tableView.estimatedRowHeight = 66 tableView.allowsSelection = false + tableView.backgroundColor = .appGroupedBackground dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in guard case let .account(id) = item else { fatalError() } @@ -61,6 +62,15 @@ class EditListAccountsViewController: EnhancedTableViewController { let cell = tableView.dequeueReusableCell(withIdentifier: "accountCell", for: indexPath) as! AccountTableViewCell cell.delegate = self cell.updateUI(accountID: id) + cell.configurationUpdateHandler = { cell, state in + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + cell.backgroundConfiguration = config + } return cell }) dataSource.editListAccountsController = self diff --git a/Tusker/Screens/Mute/MuteAccountView.swift b/Tusker/Screens/Mute/MuteAccountView.swift index 6fde9da3a5..d91cf90a07 100644 --- a/Tusker/Screens/Mute/MuteAccountView.swift +++ b/Tusker/Screens/Mute/MuteAccountView.swift @@ -43,10 +43,15 @@ struct MuteAccountView: View { if #available(iOS 16.0, *) { NavigationStack { navigationViewContent + .scrollContentBackground(.hidden) + .background(Color.appGroupedBackground) } } else { NavigationView { navigationViewContent + .onAppear { + UITableView.appearance(whenContainedInInstancesOf: [UIHostingController.self]).backgroundColor = .appGroupedBackground + } } .navigationViewStyle(.stack) } @@ -85,6 +90,7 @@ struct MuteAccountView: View { Text("This user's posts will be hidden from your timeline. You can still receive notifications from them.") } } + .listRowBackground(Color.appGroupedCellBackground) Section { Picker(selection: $duration) { @@ -99,6 +105,7 @@ struct MuteAccountView: View { Text("The mute will automatically be removed after the selected time.") } } + .listRowBackground(Color.appGroupedCellBackground) Button(action: self.mute) { if isMuting { @@ -113,6 +120,7 @@ struct MuteAccountView: View { } } .disabled(isMuting) + .listRowBackground(Color.appGroupedCellBackground) } .alertWithData("Erorr Muting", data: $error, actions: { error in Button("OK") {} diff --git a/Tusker/Screens/Notifications/NotificationsTableViewController.swift b/Tusker/Screens/Notifications/NotificationsTableViewController.swift index 7e114f2509..aa867b559e 100644 --- a/Tusker/Screens/Notifications/NotificationsTableViewController.swift +++ b/Tusker/Screens/Notifications/NotificationsTableViewController.swift @@ -58,6 +58,7 @@ class NotificationsTableViewController: DiffableTimelineLikeTableViewController< tableView.cellLayoutMarginsFollowReadableWidth = UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac tableView.allowsFocus = true + tableView.backgroundColor = .appBackground NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil) } diff --git a/Tusker/Screens/Onboarding/InstanceSelectorTableViewController.swift b/Tusker/Screens/Onboarding/InstanceSelectorTableViewController.swift index a551b75682..e73d2d84cf 100644 --- a/Tusker/Screens/Onboarding/InstanceSelectorTableViewController.swift +++ b/Tusker/Screens/Onboarding/InstanceSelectorTableViewController.swift @@ -63,6 +63,7 @@ class InstanceSelectorTableViewController: UITableViewController { appearance.configureWithDefaultBackground() navigationItem.scrollEdgeAppearance = appearance + tableView.backgroundColor = .appGroupedBackground tableView.keyboardDismissMode = .interactive tableView.register(UINib(nibName: "InstanceTableViewCell", bundle: .main), forCellReuseIdentifier: instanceCell) tableView.rowHeight = UITableView.automaticDimension @@ -107,6 +108,10 @@ class InstanceSelectorTableViewController: UITableViewController { } .debounce(for: .seconds(1), scheduler: RunLoop.main) .sink { [weak self] in self?.updateSpecificInstance(domain: $0) } + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) loadRecommendedInstances() } @@ -203,7 +208,7 @@ class InstanceSelectorTableViewController: UITableViewController { private func createActivityIndicatorHeader() { let header = UITableViewHeaderFooterView() header.translatesAutoresizingMaskIntoConstraints = false - header.contentView.backgroundColor = .systemGroupedBackground + header.contentView.backgroundColor = .appGroupedBackground activityIndicator = UIActivityIndicatorView(style: .large) activityIndicator.translatesAutoresizingMaskIntoConstraints = false diff --git a/Tusker/Screens/Preferences/AppearancePrefsView.swift b/Tusker/Screens/Preferences/AppearancePrefsView.swift index b07802797b..280247bb8e 100644 --- a/Tusker/Screens/Preferences/AppearancePrefsView.swift +++ b/Tusker/Screens/Preferences/AppearancePrefsView.swift @@ -6,21 +6,19 @@ // import SwiftUI +import Combine struct AppearancePrefsView : View { @ObservedObject var preferences = Preferences.shared - private var theme: Binding = Binding(get: { - Preferences.shared.theme - }, set: { - Preferences.shared.theme = $0 - NotificationCenter.default.post(name: .themePreferenceChanged, object: nil) - }) - private var accentColor: Binding = Binding { - Preferences.shared.accentColor - } set: { - Preferences.shared.accentColor = $0 - NotificationCenter.default.post(name: .themePreferenceChanged, object: nil) + 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: { @@ -41,13 +39,17 @@ struct AppearancePrefsView : View { private var themeSection: some View { Section { - Picker(selection: theme, label: Text("Theme")) { + Picker(selection: $preferences.theme, label: Text("Theme")) { Text("Use System Theme").tag(UIUserInterfaceStyle.unspecified) Text("Light").tag(UIUserInterfaceStyle.light) Text("Dark").tag(UIUserInterfaceStyle.dark) } - Picker(selection: accentColor, label: Text("Accent Color")) { + Toggle(isOn: $preferences.pureBlackDarkMode) { + Text("Pure Black Dark Mode") + } + + Picker(selection: $preferences.accentColor, label: Text("Accent Color")) { ForEach(Preferences.AccentColor.allCases, id: \.rawValue) { color in HStack { Text(color.name) @@ -60,6 +62,9 @@ struct AppearancePrefsView : View { } } } + .onReceive(appearanceChangePublisher) { _ in + NotificationCenter.default.post(name: .themePreferenceChanged, object: nil) + } } private var accountsSection: some View { diff --git a/Tusker/Screens/Profile/ProfileHeaderCollectionViewCell.swift b/Tusker/Screens/Profile/ProfileHeaderCollectionViewCell.swift index c4c9d234f6..bc7303d078 100644 --- a/Tusker/Screens/Profile/ProfileHeaderCollectionViewCell.swift +++ b/Tusker/Screens/Profile/ProfileHeaderCollectionViewCell.swift @@ -23,7 +23,7 @@ class ProfileHeaderCollectionViewCell: UICollectionViewCell { override init(frame: CGRect) { super.init(frame: frame) - contentView.backgroundColor = .systemBackground + contentView.backgroundColor = .appBackground isOpaque = true contentView.isOpaque = true } diff --git a/Tusker/Screens/Profile/ProfileStatusesViewController.swift b/Tusker/Screens/Profile/ProfileStatusesViewController.swift index a70f14aec9..c924622151 100644 --- a/Tusker/Screens/Profile/ProfileStatusesViewController.swift +++ b/Tusker/Screens/Profile/ProfileStatusesViewController.swift @@ -56,6 +56,7 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie override func loadView() { var config = UICollectionLayoutListConfiguration(appearance: .plain) + config.backgroundColor = .appBackground config.leadingSwipeActionsConfigurationProvider = { [unowned self] in (collectionView.cellForItem(at: $0) as? TimelineStatusCollectionViewCell)?.leadingSwipeActions() } @@ -82,7 +83,9 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie } let layout = UICollectionViewCompositionalLayout { [unowned self] sectionIndex, environment in if case .header = dataSource.sectionIdentifier(for: sectionIndex) { - return .list(using: .init(appearance: .plain), layoutEnvironment: environment) + var config = UICollectionLayoutListConfiguration(appearance: .plain) + config.backgroundColor = .appBackground + return .list(using: config, layoutEnvironment: environment) } else { let section = NSCollectionLayoutSection.list(using: config, layoutEnvironment: environment) if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { diff --git a/Tusker/Screens/Profile/ProfileViewController.swift b/Tusker/Screens/Profile/ProfileViewController.swift index cf5a29ce23..e4df090e68 100644 --- a/Tusker/Screens/Profile/ProfileViewController.swift +++ b/Tusker/Screens/Profile/ProfileViewController.swift @@ -68,7 +68,7 @@ class ProfileViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .systemBackground + view.backgroundColor = .appBackground for pageController in pageControllers { pageController.profileHeaderDelegate = self diff --git a/Tusker/Screens/Report/ReportAddStatusView.swift b/Tusker/Screens/Report/ReportAddStatusView.swift index d3413f746b..275363ba31 100644 --- a/Tusker/Screens/Report/ReportAddStatusView.swift +++ b/Tusker/Screens/Report/ReportAddStatusView.swift @@ -34,25 +34,57 @@ struct ReportAddStatusView: View { ReportStatusView(status: status, mastodonController: mastodonController) } } + .listRowBackground(Color.appGroupedCellBackground) } + .modifier(ScrollBackgroundModifier()) } else { - ProgressView() - .progressViewStyle(.circular) - .alertWithData("Error Loading Posts", data: $error, actions: { _ in - Button("OK") {} - }, message: { error in - Text(error.localizedDescription) - }) - .task { @MainActor in - do { - let req = Account.getStatuses(report.accountID, range: .count(40), excludeReplies: false, excludeReblogs: true) - let (statuses, _) = try await mastodonController.run(req) - await mastodonController.persistentContainer.addAll(statuses: statuses) - self.statuses = statuses.compactMap { mastodonController.persistentContainer.status(for: $0.id) } - } catch { - self.error = error + ZStack { + // because the background needs to fill the entire screen + Color.appGroupedBackground + .edgesIgnoringSafeArea(.all) + + ProgressView() + .progressViewStyle(.circular) + .alertWithData("Error Loading Posts", data: $error, actions: { _ in + Button("OK") {} + }, message: { error in + Text(error.localizedDescription) + }) + .task { @MainActor in + do { + let req = Account.getStatuses(report.accountID, range: .count(40), excludeReplies: false, excludeReblogs: true) + let (statuses, _) = try await mastodonController.run(req) + await mastodonController.persistentContainer.addAll(statuses: statuses) + self.statuses = statuses.compactMap { mastodonController.persistentContainer.status(for: $0.id) } + } catch { + self.error = error + } } - } + } + } + } +} + +private struct ScrollBackgroundModifier: ViewModifier { + @Environment(\.colorScheme) private var colorScheme + + func body(content: Content) -> some View { + if #available(iOS 16.0, *) { + content + .scrollContentBackground(.hidden) + .background { + // otherwise the pureBlackDarkMode isn't propagated, for some reason? + // even though it is for ReportSelectRulesView?? + let traits: UITraitCollection = { + let t = UITraitCollection(userInterfaceStyle: colorScheme == .dark ? .dark : .light) + t.pureBlackDarkMode = true + return t + }() + Color(uiColor: .appGroupedBackground.resolvedColor(with: traits)) + .edgesIgnoringSafeArea(.all) + } + } else { + content } } } diff --git a/Tusker/Screens/Report/ReportSelectRulesView.swift b/Tusker/Screens/Report/ReportSelectRulesView.swift index bfeb5a7aef..f542cbefcf 100644 --- a/Tusker/Screens/Report/ReportSelectRulesView.swift +++ b/Tusker/Screens/Report/ReportSelectRulesView.swift @@ -47,11 +47,27 @@ struct ReportSelectRulesView: View { .foregroundColor(selectedRuleIDs.contains(rule.id) ? .accentColor : .clear) } } + .listRowBackground(Color.appGroupedCellBackground) } + .withAppBackgroundIfAvailable() .navigationTitle("Rules") } } +private extension View { + @available(iOS, obsoleted: 16.0) + @ViewBuilder + func withAppBackgroundIfAvailable() -> some View { + if #available(iOS 16.0, *) { + self + .scrollContentBackground(.hidden) + .background(Color.appGroupedBackground) + } else { + self + } + } +} + //struct ReportSelectRulesView_Previews: PreviewProvider { // static var previews: some View { // ReportSelectRulesView() diff --git a/Tusker/Screens/Report/ReportView.swift b/Tusker/Screens/Report/ReportView.swift index 095c64d008..cc4353f322 100644 --- a/Tusker/Screens/Report/ReportView.swift +++ b/Tusker/Screens/Report/ReportView.swift @@ -31,11 +31,22 @@ struct ReportView: View { var body: some View { if #available(iOS 16.0, *) { NavigationStack { - navigationViewContent + ZStack { + // .background doesn't work because it somehow changes color when the keyboard appears + Color.appGroupedBackground + .edgesIgnoringSafeArea(.all) + + navigationViewContent + .scrollContentBackground(.hidden) + .scrollDismissesKeyboard(.interactively) + } } } else { NavigationView { navigationViewContent + .onAppear { + UITableView.appearance(whenContainedInInstancesOf: [UIHostingController.self]).backgroundColor = .appGroupedBackground + } } .navigationViewStyle(.stack) } @@ -93,12 +104,14 @@ struct ReportView: View { } header: { Text("Reason") } + .listRowBackground(Color.appGroupedCellBackground) Section { ComposeTextView(text: $report.comment, placeholder: Text("Add any additional comments")) .backgroundColor(.clear) .listRowInsets(EdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)) } + .listRowBackground(Color.appGroupedCellBackground) Section { ForEach(report.statusIDs, id: \.self) { id in @@ -116,12 +129,14 @@ struct ReportView: View { } footer: { Text("Attach posts to your report to provide additional context for moderators.") } + .listRowBackground(Color.appGroupedCellBackground) Section { Toggle("Forward", isOn: $report.forward) } footer: { Text("You can choose to anonymously forward your report to the moderators of **\(account.url.host!)**.") } + .listRowBackground(Color.appGroupedCellBackground) Button(action: self.sendReport) { if isReporting { @@ -134,6 +149,7 @@ struct ReportView: View { } } .disabled(isReporting) + .listRowBackground(Color.appGroupedCellBackground) } .alertWithData("Error Reporting", data: $error, actions: { error in Button("OK") {} diff --git a/Tusker/Screens/Search/SearchResultsViewController.swift b/Tusker/Screens/Search/SearchResultsViewController.swift index d14bd605c9..04bc76b210 100644 --- a/Tusker/Screens/Search/SearchResultsViewController.swift +++ b/Tusker/Screens/Search/SearchResultsViewController.swift @@ -84,25 +84,37 @@ class SearchResultsViewController: EnhancedTableViewController { tableView.register(UINib(nibName: "HashtagTableViewCell", bundle: .main), forCellReuseIdentifier: hashtagCell) tableView.allowsFocus = true + tableView.backgroundColor = .appGroupedBackground dataSource = DataSource(tableView: tableView, cellProvider: { (tableView, indexPath, item) -> UITableViewCell? in + let cell: UITableViewCell switch item { case let .account(id): - let cell = tableView.dequeueReusableCell(withIdentifier: accountCell, for: indexPath) as! AccountTableViewCell - cell.delegate = self - cell.updateUI(accountID: id) - return cell + let accountCell = tableView.dequeueReusableCell(withIdentifier: accountCell, for: indexPath) as! AccountTableViewCell + accountCell.delegate = self + accountCell.updateUI(accountID: id) + cell = accountCell case let .hashtag(tag): - let cell = tableView.dequeueReusableCell(withIdentifier: hashtagCell, for: indexPath) as! HashtagTableViewCell - cell.delegate = self - cell.updateUI(hashtag: tag) - return cell + let hashtagCell = tableView.dequeueReusableCell(withIdentifier: hashtagCell, for: indexPath) as! HashtagTableViewCell + hashtagCell.delegate = self + hashtagCell.updateUI(hashtag: tag) + cell = hashtagCell case let .status(id, state): - let cell = tableView.dequeueReusableCell(withIdentifier: statusCell, for: indexPath) as! TimelineStatusTableViewCell - cell.delegate = self - cell.updateUI(statusID: id, state: state) - return cell + let statusCell = tableView.dequeueReusableCell(withIdentifier: statusCell, for: indexPath) as! TimelineStatusTableViewCell + statusCell.delegate = self + statusCell.updateUI(statusID: id, state: state) + cell = statusCell } + cell.configurationUpdateHandler = { cell, state in + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + cell.backgroundConfiguration = config + } + return cell }) activityIndicator = UIActivityIndicatorView(style: .large) diff --git a/Tusker/Screens/Search/SearchViewController.swift b/Tusker/Screens/Search/SearchViewController.swift index 6b25cafa10..e66b2892a2 100644 --- a/Tusker/Screens/Search/SearchViewController.swift +++ b/Tusker/Screens/Search/SearchViewController.swift @@ -46,6 +46,7 @@ class SearchViewController: UIViewController, CollectionViewController { case .trendingHashtags: var listConfig = UICollectionLayoutListConfiguration(appearance: .grouped) listConfig.headerMode = .supplementary + listConfig.backgroundColor = .appGroupedBackground return .list(using: listConfig, layoutEnvironment: environment) case .trendingLinks: @@ -79,6 +80,7 @@ class SearchViewController: UIViewController, CollectionViewController { case .trendingStatuses: var listConfig = UICollectionLayoutListConfiguration(appearance: .grouped) listConfig.headerMode = .supplementary + listConfig.backgroundColor = .appGroupedBackground return .list(using: listConfig, layoutEnvironment: environment) } } @@ -86,7 +88,7 @@ class SearchViewController: UIViewController, CollectionViewController { collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] collectionView.delegate = self collectionView.dragDelegate = self - collectionView.backgroundColor = .secondarySystemBackground + collectionView.backgroundColor = .appGroupedBackground collectionView.allowsFocus = true view.addSubview(collectionView) @@ -153,7 +155,7 @@ class SearchViewController: UIViewController, CollectionViewController { let trendingLinkCell = UICollectionView.CellRegistration(cellNib: UINib(nibName: "TrendingLinkCardCollectionViewCell", bundle: .main)) { (cell, indexPath, card) in cell.updateUI(card: card) } - let statusCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, item in + let statusCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, item in cell.delegate = self // TODO: filter trends cell.updateUI(statusID: item.0, state: item.1, filterResult: .allow, precomputedContent: nil) diff --git a/Tusker/Screens/Status Action Account List/StatusActionAccountListCollectionViewController.swift b/Tusker/Screens/Status Action Account List/StatusActionAccountListCollectionViewController.swift index cfe934518a..4d8e4dc4ad 100644 --- a/Tusker/Screens/Status Action Account List/StatusActionAccountListCollectionViewController.swift +++ b/Tusker/Screens/Status Action Account List/StatusActionAccountListCollectionViewController.swift @@ -86,10 +86,30 @@ class StatusActionAccountListCollectionViewController: UIViewController, Collect let statusCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, item in cell.delegate = self cell.updateUI(statusID: item.0, state: item.1, filterResult: .allow, precomputedContent: nil) + + cell.configurationUpdateHandler = { cell, state in + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + cell.backgroundConfiguration = config + } } let accountCell = UICollectionView.CellRegistration { [unowned self] cell, indexPath, item in cell.delegate = self cell.updateUI(accountID: item) + + cell.configurationUpdateHandler = { cell, state in + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + cell.backgroundConfiguration = config + } } let loadingCell = UICollectionView.CellRegistration { cell, indexPath, item in cell.indicator.startAnimating() diff --git a/Tusker/Screens/Status Action Account List/StatusActionAccountListViewController.swift b/Tusker/Screens/Status Action Account List/StatusActionAccountListViewController.swift index 34368bc104..c6fc72958d 100644 --- a/Tusker/Screens/Status Action Account List/StatusActionAccountListViewController.swift +++ b/Tusker/Screens/Status Action Account List/StatusActionAccountListViewController.swift @@ -88,7 +88,7 @@ class StatusActionAccountListViewController: UIViewController { title = NSLocalizedString("Reblogged By", comment: "status reblogged by accounts list title") } - view.backgroundColor = .systemBackground + view.backgroundColor = .appBackground NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: nil) } diff --git a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift index e5f9bc4bdf..18d6068e24 100644 --- a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift +++ b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift @@ -87,7 +87,7 @@ class InstanceTimelineViewController: TimelineViewController { switch (error as? Client.Error)?.type { case .mastodonError(422, _), .unexpectedStatus(422): collectionView.isHidden = true - view.backgroundColor = .systemBackground + view.backgroundColor = .appBackground let image = UIImageView(image: UIImage(systemName: "lock.fill")) image.tintColor = .secondaryLabel diff --git a/Tusker/Screens/Timeline/TimelineGapCollectionViewCell.swift b/Tusker/Screens/Timeline/TimelineGapCollectionViewCell.swift index 304a6ff946..d779859f05 100644 --- a/Tusker/Screens/Timeline/TimelineGapCollectionViewCell.swift +++ b/Tusker/Screens/Timeline/TimelineGapCollectionViewCell.swift @@ -19,7 +19,7 @@ class TimelineGapCollectionViewCell: UICollectionViewCell { override var isHighlighted: Bool { didSet { - backgroundColor = isHighlighted ? .systemFill : .systemGroupedBackground + backgroundColor = isHighlighted ? .appFill : .appGroupedBackground } } @@ -38,7 +38,7 @@ class TimelineGapCollectionViewCell: UICollectionViewCell { override init(frame: CGRect) { super.init(frame: frame) - backgroundColor = .systemGroupedBackground + backgroundColor = .appGroupedBackground indicator.isHidden = true indicator.color = .tintColor diff --git a/Tusker/Screens/Timeline/TimelineViewController.swift b/Tusker/Screens/Timeline/TimelineViewController.swift index e5db22c4b0..337379662e 100644 --- a/Tusker/Screens/Timeline/TimelineViewController.swift +++ b/Tusker/Screens/Timeline/TimelineViewController.swift @@ -63,6 +63,7 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro super.viewDidLoad() var config = UICollectionLayoutListConfiguration(appearance: .plain) + config.backgroundColor = .appBackground config.leadingSwipeActionsConfigurationProvider = { [unowned self] in (collectionView.cellForItem(at: $0) as? TimelineStatusCollectionViewCell)?.leadingSwipeActions() } @@ -99,6 +100,7 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro collectionView.delegate = self collectionView.dragDelegate = self collectionView.allowsFocus = true + collectionView.backgroundColor = .appBackground collectionView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(collectionView) NSLayoutConstraint.activate([ diff --git a/Tusker/Screens/Utilities/CustomAlertController.swift b/Tusker/Screens/Utilities/CustomAlertController.swift index 67469a3260..149ffdf237 100644 --- a/Tusker/Screens/Utilities/CustomAlertController.swift +++ b/Tusker/Screens/Utilities/CustomAlertController.swift @@ -47,7 +47,7 @@ class CustomAlertController: UIViewController { blurView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial)) - blurView.backgroundColor = .systemBackground + blurView.backgroundColor = .appBackground blurView.layer.cornerRadius = 15 blurView.layer.cornerCurve = .continuous blurView.layer.masksToBounds = true diff --git a/Tusker/Screens/Utilities/SegmentedPageViewController.swift b/Tusker/Screens/Utilities/SegmentedPageViewController.swift index c8247fe9ca..6b6ccdd977 100644 --- a/Tusker/Screens/Utilities/SegmentedPageViewController.swift +++ b/Tusker/Screens/Utilities/SegmentedPageViewController.swift @@ -79,7 +79,7 @@ class SegmentedPageViewController: UIView override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .systemBackground + view.backgroundColor = .appBackground selectPage(initialPage, animated: false) diff --git a/Tusker/Views/Asset Picker/AlbumTableViewCell.swift b/Tusker/Views/Asset Picker/AlbumTableViewCell.swift index 03747aa225..7d83162fd6 100644 --- a/Tusker/Views/Asset Picker/AlbumTableViewCell.swift +++ b/Tusker/Views/Asset Picker/AlbumTableViewCell.swift @@ -21,6 +21,16 @@ class AlbumTableViewCell: UITableViewCell { thumbnailImageView.layer.cornerRadius = 0.05 * thumbnailImageView.bounds.width } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } + func updateUI(album: PHAssetCollection) { albumTitleLabel.text = album.localizedTitle diff --git a/Tusker/Views/Asset Picker/AllPhotosTableViewCell.swift b/Tusker/Views/Asset Picker/AllPhotosTableViewCell.swift index 4a433986c9..0b0d82b252 100644 --- a/Tusker/Views/Asset Picker/AllPhotosTableViewCell.swift +++ b/Tusker/Views/Asset Picker/AllPhotosTableViewCell.swift @@ -33,5 +33,15 @@ class AllPhotosTableViewCell: UITableViewCell { thumbnailImageView.image = nil } } + + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } } diff --git a/Tusker/Views/ContentTextView.swift b/Tusker/Views/ContentTextView.swift index a67f9b5847..90cf25952d 100644 --- a/Tusker/Views/ContentTextView.swift +++ b/Tusker/Views/ContentTextView.swift @@ -324,7 +324,7 @@ extension ContentTextView: UIContextMenuInteractionDelegate { // Create a dummy containerview for the snapshot view, since using a view with a CALayer mask and UIPreviewParameters(textLineRects:) // causes the mask to be ignored. See FB7832297 let snapshotContainer = UIView(frame: snapshot.bounds) - snapshotContainer.backgroundColor = .systemBackground + snapshotContainer.backgroundColor = .appBackground snapshotContainer.addSubview(snapshot) let preview = UITargetedPreview(view: snapshotContainer, parameters: parameters, target: target) diff --git a/Tusker/Views/Hashtag Cell/TrendingHashtagCollectionViewCell.swift b/Tusker/Views/Hashtag Cell/TrendingHashtagCollectionViewCell.swift index c14a72729b..be9c58c2b8 100644 --- a/Tusker/Views/Hashtag Cell/TrendingHashtagCollectionViewCell.swift +++ b/Tusker/Views/Hashtag Cell/TrendingHashtagCollectionViewCell.swift @@ -18,8 +18,6 @@ class TrendingHashtagCollectionViewCell: UICollectionViewCell { override init(frame: CGRect) { super.init(frame: frame) - backgroundColor = .systemBackground - hashtagLabel.font = .preferredFont(forTextStyle: .title2) hashtagLabel.adjustsFontForContentSizeCategory = true peopleTodayLabel.font = .preferredFont(forTextStyle: .caption1) @@ -60,6 +58,16 @@ class TrendingHashtagCollectionViewCell: UICollectionViewCell { fatalError("init(coder:) has not been implemented") } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + backgroundConfiguration = config + } + func updateUI(hashtag: Hashtag) { hashtagLabel.text = "#\(hashtag.name)" historyView.setHistory(hashtag.history) diff --git a/Tusker/Views/Instance Cell/InstanceTableViewCell.swift b/Tusker/Views/Instance Cell/InstanceTableViewCell.swift index 443aed3064..4d427d2bb9 100644 --- a/Tusker/Views/Instance Cell/InstanceTableViewCell.swift +++ b/Tusker/Views/Instance Cell/InstanceTableViewCell.swift @@ -39,6 +39,16 @@ class InstanceTableViewCell: UITableViewCell { descriptionTextView.adjustsFontForContentSizeCategory = true } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listGroupedCell() + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + backgroundConfiguration = config + } + func updateUI(instance: InstanceSelector.Instance) { self.selectorInstance = instance self.instance = nil diff --git a/Tusker/Views/LoadingTableViewCell.swift b/Tusker/Views/LoadingTableViewCell.swift index c4ede73059..8810814cb6 100644 --- a/Tusker/Views/LoadingTableViewCell.swift +++ b/Tusker/Views/LoadingTableViewCell.swift @@ -14,6 +14,8 @@ class LoadingTableViewCell: UITableViewCell { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) + backgroundColor = .appBackground + indicator.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(indicator) NSLayoutConstraint.activate([ diff --git a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift index f8f0e1b2d1..9c2789229d 100644 --- a/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/ActionNotificationGroupTableViewCell.swift @@ -47,6 +47,16 @@ class ActionNotificationGroupTableViewCell: UITableViewCell { NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil) } + + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } @objc func updateUIForPreferences() { for case let imageView as UIImageView in actionAvatarStackView.arrangedSubviews { diff --git a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift index c7fc1f6361..74bcbffc72 100644 --- a/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowNotificationGroupTableViewCell.swift @@ -43,6 +43,16 @@ class FollowNotificationGroupTableViewCell: UITableViewCell { NotificationCenter.default.addObserver(self, selector: #selector(updateUIForPreferences), name: .preferencesChanged, object: nil) } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } + @objc func updateUIForPreferences() { for case let imageView as UIImageView in avatarStackView.arrangedSubviews { imageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadius(for: imageView) diff --git a/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift b/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift index aa7877c434..629de40339 100644 --- a/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift +++ b/Tusker/Views/Notifications/FollowRequestNotificationTableViewCell.swift @@ -49,6 +49,16 @@ class FollowRequestNotificationTableViewCell: UITableViewCell { updateUIForPreferences() } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } + @objc func updateUIForPreferences() { avatarImageView.layer.cornerRadius = Preferences.shared.avatarStyle.cornerRadiusFraction * 30 diff --git a/Tusker/Views/Notifications/PollFinishedTableViewCell.swift b/Tusker/Views/Notifications/PollFinishedTableViewCell.swift index cc5747f94b..5e61c3990a 100644 --- a/Tusker/Views/Notifications/PollFinishedTableViewCell.swift +++ b/Tusker/Views/Notifications/PollFinishedTableViewCell.swift @@ -37,6 +37,16 @@ class PollFinishedTableViewCell: UITableViewCell { displayNameLabel.font = .preferredFont(forTextStyle: .body).withTraits(.traitBold)! displayNameLabel.adjustsFontForContentSizeCategory = true } + + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } func updateUI(notification: Pachyderm.Notification) { guard let statusID = notification.status?.id, diff --git a/Tusker/Views/Notifications/StatusUpdatedNotificationTableViewCell.swift b/Tusker/Views/Notifications/StatusUpdatedNotificationTableViewCell.swift index 32a70ec4f8..511144c54f 100644 --- a/Tusker/Views/Notifications/StatusUpdatedNotificationTableViewCell.swift +++ b/Tusker/Views/Notifications/StatusUpdatedNotificationTableViewCell.swift @@ -35,6 +35,16 @@ class StatusUpdatedNotificationTableViewCell: UITableViewCell { displayNameLabel.adjustsFontForContentSizeCategory = true } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } + func updateUI(notification: Pachyderm.Notification) { guard notification.kind == .update, let status = notification.status else { diff --git a/Tusker/Views/Profile Header/ProfileFieldsView.swift b/Tusker/Views/Profile Header/ProfileFieldsView.swift index c678d25a5e..2b41bd4d24 100644 --- a/Tusker/Views/Profile Header/ProfileFieldsView.swift +++ b/Tusker/Views/Profile Header/ProfileFieldsView.swift @@ -14,6 +14,8 @@ class ProfileFieldsView: UIView { weak var delegate: ProfileHeaderViewDelegate? + private var fields = [Account.Field]() + private let stack = UIStackView() private var fieldViews: [(EmojiLabel, ProfileFieldValueView)] = [] private var fieldConstraints: [NSLayoutConstraint] = [] @@ -62,9 +64,11 @@ class ProfileFieldsView: UIView { func updateUI(account: AccountMO) { isHidden = account.fields.isEmpty - guard !account.fields.isEmpty else { + guard !account.fields.isEmpty, + fields != account.fields else { return } + fields = account.fields for (name, value) in fieldViews { name.removeFromSuperview() @@ -183,6 +187,7 @@ private class ProfileFieldValueView: UIView { super.init(frame: .zero) textView.isSelectable = false + textView.backgroundColor = .clear textView.defaultFont = .preferredFont(forTextStyle: .body) textView.monospaceFont = UIFontMetrics.default.scaledFont(for: .monospacedSystemFont(ofSize: 17, weight: .regular)) textView.adjustsFontForContentSizeCategory = true @@ -221,7 +226,6 @@ private class ProfileFieldValueView: UIView { textView.topAnchor.constraint(equalTo: topAnchor), textView.bottomAnchor.constraint(equalTo: bottomAnchor), ]) - } required init?(coder: NSCoder) { diff --git a/Tusker/Views/Profile Header/ProfileHeaderView.swift b/Tusker/Views/Profile Header/ProfileHeaderView.swift index 00ac35ed45..5a8295f50d 100644 --- a/Tusker/Views/Profile Header/ProfileHeaderView.swift +++ b/Tusker/Views/Profile Header/ProfileHeaderView.swift @@ -61,6 +61,9 @@ class ProfileHeaderView: UIView { override func awakeFromNib() { super.awakeFromNib() + backgroundColor = .appBackground + + avatarContainerView.backgroundColor = .appBackground avatarContainerView.layer.masksToBounds = true avatarImageView.layer.masksToBounds = true avatarImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(avatarPressed))) diff --git a/Tusker/Views/Profile Header/ProfileHeaderView.xib b/Tusker/Views/Profile Header/ProfileHeaderView.xib index b1b73820e0..d2484a7823 100644 --- a/Tusker/Views/Profile Header/ProfileHeaderView.xib +++ b/Tusker/Views/Profile Header/ProfileHeaderView.xib @@ -79,7 +79,6 @@ - diff --git a/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift b/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift index 279c7d26f6..5cc1473d6e 100644 --- a/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift +++ b/Tusker/Views/Status/ConversationMainStatusCollectionViewCell.swift @@ -317,6 +317,12 @@ class ConversationMainStatusCollectionViewCell: UICollectionViewListCell, Status fatalError("init(coder:) has not been implemented") } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + config.backgroundColor = .appBackground + backgroundConfiguration = config + } + // MARK: Configure UI func updateUI(statusID: String, state: CollapseState) { diff --git a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift index b02b475d5d..e28fb9f1db 100644 --- a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift @@ -351,6 +351,16 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti } } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } + // MARK: Accessibility override var isAccessibilityElement: Bool { diff --git a/Tusker/Views/Status/TimelineStatusTableViewCell.swift b/Tusker/Views/Status/TimelineStatusTableViewCell.swift index 971aeac905..e0bd69bd89 100644 --- a/Tusker/Views/Status/TimelineStatusTableViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusTableViewCell.swift @@ -93,6 +93,16 @@ class TimelineStatusTableViewCell: BaseStatusTableViewCell { updateActionsVisibility() } + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listPlainCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appBackground + } + backgroundConfiguration = config + } + override func createObserversIfNecessary() { super.createObserversIfNecessary() diff --git a/Tusker/Views/Status/TrendingStatusCollectionViewCell.swift b/Tusker/Views/Status/TrendingStatusCollectionViewCell.swift new file mode 100644 index 0000000000..8e7ea298b3 --- /dev/null +++ b/Tusker/Views/Status/TrendingStatusCollectionViewCell.swift @@ -0,0 +1,21 @@ +// +// TrendingStatusCollectionViewCell.swift +// Tusker +// +// Created by Shadowfacts on 2/2/23. +// Copyright © 2023 Shadowfacts. All rights reserved. +// + +import UIKit + +class TrendingStatusCollectionViewCell: TimelineStatusCollectionViewCell { + override func updateConfiguration(using state: UICellConfigurationState) { + var config = UIBackgroundConfiguration.listGroupedCell().updated(for: state) + if state.isHighlighted || state.isSelected { + config.backgroundColor = .appSelectedCellBackground + } else { + config.backgroundColor = .appGroupedCellBackground + } + backgroundConfiguration = config + } +} diff --git a/Tusker/Views/TrendHistoryView.swift b/Tusker/Views/TrendHistoryView.swift index ffdb556a79..5002731714 100644 --- a/Tusker/Views/TrendHistoryView.swift +++ b/Tusker/Views/TrendHistoryView.swift @@ -16,7 +16,7 @@ class TrendHistoryView: UIView { private let curveRadius: CGFloat = 10 /// The base background color used for the graph fill. - var effectiveBackgroundColor = UIColor.systemBackground + var effectiveBackgroundColor = UIColor.appBackground override func layoutSubviews() { super.layoutSubviews()