Start adding non-pure-black dark mode

This commit is contained in:
Shadowfacts 2023-02-02 23:02:11 -05:00
parent 76268e7a14
commit 20c4c4bb2f
70 changed files with 615 additions and 94 deletions

View File

@ -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?

View File

@ -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 = "<group>"; };
D6D706A62948D4D0000827ED /* TimlineState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimlineState.swift; sourceTree = "<group>"; };
D6D706A829498C82000827ED /* Tusker.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Tusker.xcconfig; sourceTree = "<group>"; };
D6D94954298963A900C59229 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrendingStatusCollectionViewCell.swift; sourceTree = "<group>"; };
D6DD2A3E273C1F4900386A6C /* ComposeAttachmentImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeAttachmentImage.swift; sourceTree = "<group>"; };
D6DD2A44273D6C5700386A6C /* GIFImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GIFImageView.swift; sourceTree = "<group>"; };
D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarningCopyMode.swift; sourceTree = "<group>"; };
@ -1166,6 +1170,7 @@
D6ADB6E928E91C30009924AB /* TimelineStatusCollectionViewCell.swift */,
D601FA60297B539E00A8E8B5 /* ConversationMainStatusCollectionViewCell.swift */,
D6ADB6EB28EA73CB009924AB /* StatusContentContainer.swift */,
D6D9498C298CBB4000C59229 /* TrendingStatusCollectionViewCell.swift */,
);
path = Status;
sourceTree = "<group>";
@ -1259,6 +1264,7 @@
D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */,
D6BC9DB4232D4CE3002CA326 /* NotificationsMode.swift */,
D61F75872932DB6000C0B37F /* StatusSwipeAction.swift */,
D6D94954298963A900C59229 /* Colors.swift */,
);
path = Preferences;
sourceTree = "<group>";
@ -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 */,

View File

@ -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")
}
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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() {

View File

@ -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<AccountCollectionViewCell, String> { [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<LoadingCollectionViewCell, Void> { cell, indexPath, item in
cell.indicator.startAnimating()

View File

@ -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

View File

@ -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))

View File

@ -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 {

View File

@ -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()
}

View File

@ -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()

View File

@ -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)
}

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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
}
}

View File

@ -9,6 +9,21 @@
import SwiftUI
import Pachyderm
@available(iOS, obsoleted: 16.0)
struct AddHashtagPinnedTimelineRepresentable: UIViewControllerRepresentable {
typealias UIViewControllerType = UIHostingController<AddHashtagPinnedTimelineView>
@Binding var pinnedTimelines: [PinnedTimeline]
func makeUIViewController(context: Context) -> UIHostingController<AddHashtagPinnedTimelineView> {
UITableView.appearance(whenContainedInInstancesOf: [UIViewControllerType.self]).backgroundColor = .appGroupedBackground
return UIHostingController(rootView: AddHashtagPinnedTimelineView(pinnedTimelines: $pinnedTimelines))
}
func updateUIViewController(_ uiViewController: UIHostingController<AddHashtagPinnedTimelineView>, 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 {

View File

@ -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<CustomizeTimelinesView>.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 {

View File

@ -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()

View File

@ -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)

View File

@ -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<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionHeader) { (headerView, collectionView, indexPath) in

View File

@ -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:

View File

@ -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

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -55,7 +55,6 @@
</label>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" userInteractionEnabled="NO" contentMode="scaleToFill" verticalCompressionResistancePriority="749" scrollEnabled="NO" editable="NO" textAlignment="natural" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="bvj-F0-ggC" customClass="StatusContentTextView" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="8" y="102" width="384" height="98"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<string key="text">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.</string>
<color key="textColor" systemColor="labelColor"/>
<fontDescription key="fontDescription" type="system" pointSize="14"/>
@ -102,7 +101,7 @@
</objects>
<resources>
<systemColor name="labelColor">
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</systemColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>

View File

@ -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

View File

@ -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

View File

@ -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)))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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<MuteAccountView>.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") {}

View File

@ -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)
}

View File

@ -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

View File

@ -6,21 +6,19 @@
//
import SwiftUI
import Combine
struct AppearancePrefsView : View {
@ObservedObject var preferences = Preferences.shared
private var theme: Binding<UIUserInterfaceStyle> = Binding(get: {
Preferences.shared.theme
}, set: {
Preferences.shared.theme = $0
NotificationCenter.default.post(name: .themePreferenceChanged, object: nil)
})
private var accentColor: Binding<Preferences.AccentColor> = Binding {
Preferences.shared.accentColor
} set: {
Preferences.shared.accentColor = $0
NotificationCenter.default.post(name: .themePreferenceChanged, object: nil)
private var appearanceChangePublisher: some Publisher<Void, Never> {
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<Bool> = 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 {

View File

@ -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
}

View File

@ -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 {

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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()

View File

@ -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<ReportView>.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") {}

View File

@ -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)

View File

@ -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<TrendingLinkCardCollectionViewCell, Card>(cellNib: UINib(nibName: "TrendingLinkCardCollectionViewCell", bundle: .main)) { (cell, indexPath, card) in
cell.updateUI(card: card)
}
let statusCell = UICollectionView.CellRegistration<TimelineStatusCollectionViewCell, (String, CollapseState)> { [unowned self] cell, indexPath, item in
let statusCell = UICollectionView.CellRegistration<TrendingStatusCollectionViewCell, (String, CollapseState)> { [unowned self] cell, indexPath, item in
cell.delegate = self
// TODO: filter trends
cell.updateUI(statusID: item.0, state: item.1, filterResult: .allow, precomputedContent: nil)

View File

@ -86,10 +86,30 @@ class StatusActionAccountListCollectionViewController: UIViewController, Collect
let statusCell = UICollectionView.CellRegistration<TimelineStatusCollectionViewCell, (String, CollapseState)> { [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<AccountCollectionViewCell, String> { [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<LoadingCollectionViewCell, Void> { cell, indexPath, item in
cell.indicator.startAnimating()

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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([

View File

@ -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

View File

@ -79,7 +79,7 @@ class SegmentedPageViewController<Page: SegmentedPageViewControllerPage>: UIView
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
view.backgroundColor = .appBackground
selectPage(initialPage, animated: false)

View File

@ -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

View File

@ -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
}
}

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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([

View File

@ -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 {

View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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 {

View File

@ -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) {

View File

@ -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)))

View File

@ -79,7 +79,6 @@
</textView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vKC-m1-Sbs" customClass="ProfileFieldsView" customModule="Tusker" customModuleProvider="target">
<rect key="frame" x="0.0" y="263.5" width="398" height="128"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstAttribute="height" constant="128" placeholder="YES" id="xbR-M6-H0I"/>
</constraints>

View File

@ -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) {

View File

@ -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 {

View File

@ -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()

View File

@ -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
}
}

View File

@ -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()