From 4dc484c3c2654fac71e92d8475190a249e6bbf4e Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 2 Jun 2024 11:40:42 -0700 Subject: [PATCH] Fix follow button never activating on Pixelfed Caused by not being able to decode Relationship due to missing fields. Also disable actions that are unsupported on Pixelfed. Closes #481 --- .../InstanceFeatures/InstanceFeatures.swift | 20 +++++++++++++++++ .../Pachyderm/Model/Relationship.swift | 9 +++++--- Tusker/Screens/Mute/MuteAccountView.swift | 22 ++++++++++--------- .../ProfileStatusesViewController.swift | 19 +++++++++++++--- Tusker/Screens/Utilities/Previewing.swift | 12 ++++++---- 5 files changed, 62 insertions(+), 20 deletions(-) diff --git a/Packages/InstanceFeatures/Sources/InstanceFeatures/InstanceFeatures.swift b/Packages/InstanceFeatures/Sources/InstanceFeatures/InstanceFeatures.swift index 4783fc9d..23cabf9d 100644 --- a/Packages/InstanceFeatures/Sources/InstanceFeatures/InstanceFeatures.swift +++ b/Packages/InstanceFeatures/Sources/InstanceFeatures/InstanceFeatures.swift @@ -217,6 +217,18 @@ public final class InstanceFeatures: ObservableObject { instanceType.isPleroma } + public var muteNotifications: Bool { + !instanceType.isPixelfed + } + + public var blockDomains: Bool { + !instanceType.isPixelfed + } + + public var hideReblogs: Bool { + !instanceType.isPixelfed + } + public init() { } @@ -338,6 +350,14 @@ extension InstanceFeatures { return false } } + + var isPixelfed: Bool { + if case .pixelfed = self { + return true + } else { + return false + } + } } @_spi(InstanceType) public enum MastodonType { diff --git a/Packages/Pachyderm/Sources/Pachyderm/Model/Relationship.swift b/Packages/Pachyderm/Sources/Pachyderm/Model/Relationship.swift index 96c1d03b..db1196ad 100644 --- a/Packages/Pachyderm/Sources/Pachyderm/Model/Relationship.swift +++ b/Packages/Pachyderm/Sources/Pachyderm/Model/Relationship.swift @@ -27,10 +27,13 @@ public struct Relationship: RelationshipProtocol, Decodable, Sendable { self.followedBy = try container.decode(Bool.self, forKey: .followedBy) self.blocking = try container.decode(Bool.self, forKey: .blocking) self.muting = try container.decode(Bool.self, forKey: .muting) - self.mutingNotifications = try container.decode(Bool.self, forKey: .mutingNotifications) + // not supported on pixelfed + self.mutingNotifications = try container.decodeIfPresent(Bool.self, forKey: .mutingNotifications) ?? false self.followRequested = try container.decode(Bool.self, forKey: .followRequested) - self.domainBlocking = try container.decode(Bool.self, forKey: .domainBlocking) - self.showingReblogs = try container.decode(Bool.self, forKey: .showingReblogs) + // not supported on pixelfed + self.domainBlocking = try container.decodeIfPresent(Bool.self, forKey: .domainBlocking) ?? false + // not supported on pixelfed + self.showingReblogs = try container.decodeIfPresent(Bool.self, forKey: .showingReblogs) ?? true self.endorsed = try container.decodeIfPresent(Bool.self, forKey: .endorsed) ?? false } diff --git a/Tusker/Screens/Mute/MuteAccountView.swift b/Tusker/Screens/Mute/MuteAccountView.swift index b4796fc3..5cdc72a4 100644 --- a/Tusker/Screens/Mute/MuteAccountView.swift +++ b/Tusker/Screens/Mute/MuteAccountView.swift @@ -78,18 +78,20 @@ struct MuteAccountView: View { } .accessibilityHidden(true) - Section { - Toggle(isOn: $muteNotifications) { - Text("Hide notifications from this person") - } - } footer: { - if muteNotifications { - Text("This user's posts and notifications will be hidden.") - } else { - Text("This user's posts will be hidden from your timeline. You can still receive notifications from them.") + if mastodonController.instanceFeatures.muteNotifications { + Section { + Toggle(isOn: $muteNotifications) { + Text("Hide notifications from this person") + } + } footer: { + if muteNotifications { + Text("This user's posts and notifications will be hidden.") + } else { + Text("This user's posts will be hidden from your timeline. You can still receive notifications from them.") + } } + .appGroupedListRowBackground() } - .appGroupedListRowBackground() Section { Picker(selection: $duration) { diff --git a/Tusker/Screens/Profile/ProfileStatusesViewController.swift b/Tusker/Screens/Profile/ProfileStatusesViewController.swift index 4eed100d..7a47c82c 100644 --- a/Tusker/Screens/Profile/ProfileStatusesViewController.swift +++ b/Tusker/Screens/Profile/ProfileStatusesViewController.swift @@ -9,6 +9,12 @@ import UIKit import Pachyderm import Combine +import OSLog +#if canImport(Sentry) +import Sentry +#endif + +private let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "ProfileStatusesViewController") class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionViewController, CollectionViewController { @@ -250,9 +256,16 @@ class ProfileStatusesViewController: UIViewController, TimelineLikeCollectionVie state = .setupInitialSnapshot Task { - if let (all, _) = try? await mastodonController.run(Client.getRelationships(accounts: [accountID])), - let relationship = all.first { - self.mastodonController.persistentContainer.addOrUpdate(relationship: relationship) + do { + let (all, _) = try await mastodonController.run(Client.getRelationships(accounts: [accountID])) + if let relationship = all.first { + self.mastodonController.persistentContainer.addOrUpdate(relationship: relationship) + } + } catch { + logger.error("Error fetching relationship: \(String(describing: error))") + #if canImport(Sentry) + SentrySDK.capture(error: error) + #endif } } diff --git a/Tusker/Screens/Utilities/Previewing.swift b/Tusker/Screens/Utilities/Previewing.swift index 8e9c90d5..76d4dc4d 100644 --- a/Tusker/Screens/Utilities/Previewing.swift +++ b/Tusker/Screens/Utilities/Previewing.swift @@ -557,11 +557,14 @@ extension MenuActionProvider { return createAction(identifier: "block", title: "Unblock \(displayName)", systemImageName: "circle.slash", handler: handler(false)) } else { let image = UIImage(systemName: "circle.slash") - return UIMenu(title: "Block", image: image, children: [ + var children = [ UIAction(title: "Cancel", handler: { _ in }), UIAction(title: "Block \(displayName)", image: image, attributes: .destructive, handler: handler(true)), - UIAction(title: "Block \(host)", image: image, attributes: .destructive, handler: domainHandler(true)) - ]) + ] + if mastodonController.instanceFeatures.blockDomains { + children.append(UIAction(title: "Block \(host)", image: image, attributes: .destructive, handler: domainHandler(true))) + } + return UIMenu(title: "Block", image: image, children: children) } } @@ -592,7 +595,8 @@ extension MenuActionProvider { @MainActor private func hideReblogsAction(for relationship: RelationshipMO, mastodonController: MastodonController) -> UIMenuElement? { // don't show action for people that the user isn't following and isn't already hiding reblogs for - guard relationship.following || relationship.showingReblogs else { + guard relationship.following || relationship.showingReblogs, + mastodonController.instanceFeatures.hideReblogs else { return nil } let title = relationship.showingReblogs ? "Hide Reblogs" : "Show Reblogs"