From be1ca70ebf38128e58ed38b4fc3b41b4d9cc9b52 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Mon, 4 Dec 2023 16:18:54 -0500 Subject: [PATCH] Add preference for showing attachments in timeline Closes #330 --- .../Sources/TuskerPreferences/Preferences.swift | 4 ++++ Tusker/Screens/Preferences/AppearancePrefsView.swift | 9 ++++++--- Tusker/Screens/Timeline/TimelineViewController.swift | 12 ++++++++++++ .../Views/Attachments/AttachmentsContainerView.swift | 1 + Tusker/Views/Status/StatusCollectionViewCell.swift | 9 +++++++-- .../Status/TimelineStatusCollectionViewCell.swift | 9 +++++++++ 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/Packages/TuskerPreferences/Sources/TuskerPreferences/Preferences.swift b/Packages/TuskerPreferences/Sources/TuskerPreferences/Preferences.swift index 6a099dd1..92cbb5ae 100644 --- a/Packages/TuskerPreferences/Sources/TuskerPreferences/Preferences.swift +++ b/Packages/TuskerPreferences/Sources/TuskerPreferences/Preferences.swift @@ -62,6 +62,7 @@ public final class Preferences: Codable, ObservableObject { self.trailingStatusSwipeActions = try container.decodeIfPresent([StatusSwipeAction].self, forKey: .trailingStatusSwipeActions) ?? trailingStatusSwipeActions self.widescreenNavigationMode = try container.decodeIfPresent(WidescreenNavigationMode.self, forKey: .widescreenNavigationMode) ?? Self.defaultWidescreenNavigationMode self.underlineTextLinks = try container.decodeIfPresent(Bool.self, forKey: .underlineTextLinks) ?? false + self.showAttachmentsInTimeline = try container.decodeIfPresent(Bool.self, forKey: .showAttachmentsInTimeline) ?? true if let existing = try? container.decode(Visibility.self, forKey: .defaultPostVisibility) { self.defaultPostVisibility = .visibility(existing) @@ -127,6 +128,7 @@ public final class Preferences: Codable, ObservableObject { try container.encode(trailingStatusSwipeActions, forKey: .trailingStatusSwipeActions) try container.encode(widescreenNavigationMode, forKey: .widescreenNavigationMode) try container.encode(underlineTextLinks, forKey: .underlineTextLinks) + try container.encode(showAttachmentsInTimeline, forKey: .showAttachmentsInTimeline) try container.encode(defaultPostVisibility, forKey: .defaultPostVisibility) try container.encode(defaultReplyVisibility, forKey: .defaultReplyVisibility) @@ -182,6 +184,7 @@ public final class Preferences: Codable, ObservableObject { private static var defaultWidescreenNavigationMode = WidescreenNavigationMode.splitScreen @Published public var widescreenNavigationMode = Preferences.defaultWidescreenNavigationMode @Published public var underlineTextLinks = false + @Published public var showAttachmentsInTimeline = true // MARK: Composing @Published public var defaultPostVisibility = PostVisibility.serverDefault @@ -253,6 +256,7 @@ public final class Preferences: Codable, ObservableObject { case trailingStatusSwipeActions case widescreenNavigationMode case underlineTextLinks + case showAttachmentsInTimeline case defaultPostVisibility case defaultReplyVisibility diff --git a/Tusker/Screens/Preferences/AppearancePrefsView.swift b/Tusker/Screens/Preferences/AppearancePrefsView.swift index 1e50daa5..d68ff959 100644 --- a/Tusker/Screens/Preferences/AppearancePrefsView.swift +++ b/Tusker/Screens/Preferences/AppearancePrefsView.swift @@ -118,12 +118,15 @@ struct AppearancePrefsView : View { Toggle(isOn: $preferences.alwaysShowStatusVisibilityIcon) { Text("Always Show Status Visibility Icons") } - Toggle(isOn: $preferences.hideActionsInTimeline) { - Text("Hide Actions on Timeline") - } Toggle(isOn: $preferences.showLinkPreviews) { Text("Show Link Previews") } + Toggle(isOn: $preferences.showAttachmentsInTimeline) { + Text("Show Attachments on Timeline") + } + Toggle(isOn: $preferences.hideActionsInTimeline) { + Text("Hide Actions on Timeline") + } Toggle(isOn: $preferences.underlineTextLinks) { Text("Underline Links") } diff --git a/Tusker/Screens/Timeline/TimelineViewController.swift b/Tusker/Screens/Timeline/TimelineViewController.swift index a61095b4..bad9bde6 100644 --- a/Tusker/Screens/Timeline/TimelineViewController.swift +++ b/Tusker/Screens/Timeline/TimelineViewController.swift @@ -164,6 +164,18 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro .store(in: &cancellables) NotificationCenter.default.addObserver(self, selector: #selector(handleStatusDeleted), name: .statusDeleted, object: mastodonController) + Preferences.shared.$showAttachmentsInTimeline + // skip the initial value + .dropFirst() + // publisher fires on willChange, wait the change is actually made + .receive(on: DispatchQueue.main) + .sink { [unowned self] _ in + var snapshot = self.dataSource.snapshot() + snapshot.reconfigureItems(snapshot.itemIdentifiers) + self.dataSource.apply(snapshot, animatingDifferences: false) + } + .store(in: &cancellables) + if userActivity != nil { userActivityNeedsUpdate .debounce(for: .seconds(1), scheduler: DispatchQueue.main) diff --git a/Tusker/Views/Attachments/AttachmentsContainerView.swift b/Tusker/Views/Attachments/AttachmentsContainerView.swift index bd449c9b..ede05727 100644 --- a/Tusker/Views/Attachments/AttachmentsContainerView.swift +++ b/Tusker/Views/Attachments/AttachmentsContainerView.swift @@ -71,6 +71,7 @@ class AttachmentsContainerView: UIView { let newTokens = attachments.map { AttachmentToken(attachment: $0) } guard self.attachmentTokens != newTokens else { + self.isHidden = attachments.isEmpty return } diff --git a/Tusker/Views/Status/StatusCollectionViewCell.swift b/Tusker/Views/Status/StatusCollectionViewCell.swift index 61c93b9a..9fbe1b08 100644 --- a/Tusker/Views/Status/StatusCollectionViewCell.swift +++ b/Tusker/Views/Status/StatusCollectionViewCell.swift @@ -44,6 +44,7 @@ protocol StatusCollectionViewCell: UICollectionViewCell, AttachmentViewDelegate var isGrayscale: Bool { get set } var cancellables: Set { get set } + func updateAttachmentsUI(status: StatusMO) func updateUIForPreferences(status: StatusMO) func updateStatusState(status: StatusMO) func estimateContentHeight() -> CGFloat @@ -91,8 +92,7 @@ extension StatusCollectionViewCell { contentContainer.contentTextView.setTextFrom(status: status, precomputed: precomputedContent) contentContainer.contentTextView.navigationDelegate = delegate - contentContainer.attachmentsView.delegate = self - contentContainer.attachmentsView.updateUI(attachments: status.attachments) + self.updateAttachmentsUI(status: status) contentContainer.pollView.isHidden = status.poll == nil contentContainer.pollView.mastodonController = mastodonController contentContainer.pollView.delegate = delegate @@ -167,6 +167,11 @@ extension StatusCollectionViewCell { return true } + func updateAttachmentsUI(status: StatusMO) { + contentContainer.attachmentsView.delegate = self + contentContainer.attachmentsView.updateUI(attachments: status.attachments) + } + func updateAccountUI(account: AccountMO) { avatarImageView.update(for: account.avatar) displayNameLabel.updateForAccountDisplayName(account: account) diff --git a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift index d1edccd4..7064b7d3 100644 --- a/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift +++ b/Tusker/Views/Status/TimelineStatusCollectionViewCell.swift @@ -645,6 +645,15 @@ class TimelineStatusCollectionViewCell: UICollectionViewListCell, StatusCollecti baseUpdateStatusState(status: status) } + func updateAttachmentsUI(status: StatusMO) { + if Preferences.shared.showAttachmentsInTimeline { + attachmentsView.delegate = self + attachmentsView.updateUI(attachments: status.attachments) + } else { + attachmentsView.isHidden = true + } + } + func estimateContentHeight() -> CGFloat { let width = bounds.width /* leading spacing: */ - 16 /* avatar: */ - 50 /* spacing: 8 */ - 8 /* trailing spacing: */ - 16 return contentContainer.estimateVisibleSubviewHeight(effectiveWidth: width)