diff --git a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift index d164a0f3..e5f9bc4b 100644 --- a/Tusker/Screens/Timeline/InstanceTimelineViewController.swift +++ b/Tusker/Screens/Timeline/InstanceTimelineViewController.swift @@ -81,7 +81,53 @@ class InstanceTimelineViewController: TimelineViewController { super.collectionView(collectionView, didSelectItemAt: indexPath) } - // MARK: - Interaction + // MARK: Timeline + + override func handleLoadAllError(_ error: Swift.Error) async { + switch (error as? Client.Error)?.type { + case .mastodonError(422, _), .unexpectedStatus(422): + collectionView.isHidden = true + view.backgroundColor = .systemBackground + + let image = UIImageView(image: UIImage(systemName: "lock.fill")) + image.tintColor = .secondaryLabel + image.contentMode = .scaleAspectFit + + let title = UILabel() + title.textColor = .secondaryLabel + title.font = .preferredFont(forTextStyle: .title1).withTraits(.traitBold)! + title.adjustsFontForContentSizeCategory = true + title.numberOfLines = 0 + title.textAlignment = .center + title.text = "This instance requires an account to view." + + let stack = UIStackView(arrangedSubviews: [ + image, + title, + ]) + stack.axis = .vertical + stack.alignment = .center + stack.spacing = 8 + stack.isAccessibilityElement = true + stack.accessibilityLabel = title.text! + + stack.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(stack) + NSLayoutConstraint.activate([ + image.widthAnchor.constraint(equalToConstant: 64), + image.heightAnchor.constraint(equalToConstant: 64), + + stack.leadingAnchor.constraint(equalToSystemSpacingAfter: view.safeAreaLayoutGuide.leadingAnchor, multiplier: 1), + view.safeAreaLayoutGuide.trailingAnchor.constraint(equalToSystemSpacingAfter: stack.trailingAnchor, multiplier: 1), + stack.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor), + ]) + + default: + await super.handleLoadAllError(error) + } + } + + // MARK: Interaction @objc func toggleSaveButtonPressed() { let context = parentMastodonController!.persistentContainer.viewContext let req = SavedInstance.fetchRequest(url: instanceURL, account: parentMastodonController!.accountInfo!) diff --git a/Tusker/Screens/Timeline/TimelineViewController.swift b/Tusker/Screens/Timeline/TimelineViewController.swift index 17e10b66..99da074b 100644 --- a/Tusker/Screens/Timeline/TimelineViewController.swift +++ b/Tusker/Screens/Timeline/TimelineViewController.swift @@ -856,6 +856,17 @@ class TimelineViewController: UIViewController, TimelineLikeCollectionViewContro self.dataSource.apply(snapshot, animatingDifferences: true) } } + + // this is only implemented here so it's overridable by InstanceTimelineViewController + func handleLoadAllError(_ error: Swift.Error) async { + let config = ToastConfiguration(from: error, with: "Error Loading", in: self) { [weak self] toast in + toast.dismissToast(animated: true) + Task { + await self?.controller.loadInitial() + } + } + self.showToast(configuration: config, animated: true) + } } extension TimelineViewController {