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 f18a7196..90f316f9 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 7f4562a1..7f1dc1a5 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 463f5c18..136f3742 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 00000000..825fa2c2 --- /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 d857c78b..78da9d3a 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 43c1a731..68dfe452 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 4ecfc480..494c6079 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 b05d1546..5a14d24b 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 72f5d27b..def706ca 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 d3c008b2..ba0bbd7a 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 cd77c8a0..301c8e01 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 282fd383..743caa0e 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 ebc4526f..07328877 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 eeecbe53..2d869b70 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 2746acc0..c56574a9 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 57915d12..a05a3bcd 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 167b6e7a..83595181 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 e7e1400d..28685a19 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 f4604c4a..7bdad8ad 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 f017f8eb..f18e5df3 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 4b1bc535..576ec9b9 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 504731db..e1e3859c 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 f02332f4..1eb7134a 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 7e3925a1..506885ca 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 ca317489..151ccce7 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 99ec2f5f..4faaaaf9 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 88b7d4c0..6b6b2499 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 9a0688ac..dfa0ca60 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 13e11f22..98bea58c 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 ce7f1b8f..5e334510 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 106fb249..9eebeb8a 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 4891959c..bc595e49 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 6fde9da3..d91cf90a 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 7e114f25..aa867b55 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 a551b756..e73d2d84 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 b0780279..280247bb 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 c4c9d234..bc7303d0 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 a70f14ae..c9246221 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 cf5a29ce..e4df090e 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 d3413f74..275363ba 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 bfeb5a7a..f542cbef 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 095c64d0..cc4353f3 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 d14bd605..04bc76b2 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 6b25cafa..e66b2892 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 cfe93451..4d8e4dc4 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 34368bc1..c6fc7295 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 e5f9bc4b..18d6068e 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 304a6ff9..d779859f 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 e5db22c4..33737966 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 67469a32..149ffdf2 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 c8247fe9..6b6ccdd9 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 03747aa2..7d83162f 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 4a433986..0b0d82b2 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 a67f9b58..90cf2595 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 c14a7272..be9c58c2 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 443aed30..4d427d2b 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 c4ede730..8810814c 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 f8f0e1b2..9c278922 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 c7fc1f63..74bcbffc 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 aa7877c4..629de403 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 cc5747f9..5e61c399 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 32a70ec4..511144c5 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 c678d25a..2b41bd4d 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 00ac35ed..5a8295f5 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 b1b73820..d2484a78 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 279c7d26..5cc1473d 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 b02b475d..e28fb9f1 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 971aeac9..e0bd69bd 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 00000000..8e7ea298 --- /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 ffdb556a..50027317 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()