Tusker/Tusker/Screens/Timeline/InstanceTimelineViewControl...

158 lines
6.0 KiB
Swift

//
// InstanceTimelineViewController.swift
// Tusker
//
// Created by Shadowfacts on 12/19/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
import UIKit
import Pachyderm
@MainActor
protocol InstanceTimelineViewControllerDelegate: AnyObject {
func didSaveInstance(url: URL)
func didUnsaveInstance(url: URL)
}
class InstanceTimelineViewController: TimelineViewController {
weak var instanceTimelineDelegate: InstanceTimelineViewControllerDelegate?
weak var parentMastodonController: MastodonController?
let instanceURL: URL
let instanceMastodonController: MastodonController
private var toggleSaveButton: UIBarButtonItem!
private var isInstanceSaved: Bool {
let req = SavedInstance.fetchRequest(url: instanceURL, account: parentMastodonController!.accountInfo!)
return parentMastodonController!.persistentContainer.viewContext.objectExists(for: req)
}
private var toggleSaveButtonTitle: String {
if isInstanceSaved {
return NSLocalizedString("Unsave", comment: "unsave instance button")
} else {
return NSLocalizedString("Save", comment: "save instance button")
}
}
var browsingEnabled = true
init(for url: URL, parentMastodonController: MastodonController) {
self.parentMastodonController = parentMastodonController
self.instanceURL = url
// the timeline VC only stores a weak reference to it, so we need to store a strong reference to make sure it's not released immediately
instanceMastodonController = MastodonController(instanceURL: url, transient: true)
super.init(for: .public(local: true), mastodonController: instanceMastodonController)
title = url.host!
userActivity = nil // todo: activity for instance-specific timelines
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
toggleSaveButton = UIBarButtonItem(title: toggleSaveButtonTitle, style: .plain, target: self, action: #selector(toggleSaveButtonPressed))
navigationItem.rightBarButtonItem = toggleSaveButton
NotificationCenter.default.addObserver(self, selector: #selector(savedInstancesChanged), name: .savedInstancesChanged, object: nil)
}
@objc func savedInstancesChanged() {
toggleSaveButton.title = toggleSaveButtonTitle
}
override func configureStatusCell(_ cell: TimelineStatusCollectionViewCell, id: String, state: CollapseState, filterResult: Filterer.Result, precomputedContent: NSAttributedString?) {
cell.delegate = browsingEnabled ? self : nil
cell.overrideMastodonController = mastodonController
cell.updateUI(statusID: id, state: state, filterResult: filterResult, precomputedContent: precomputedContent)
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard browsingEnabled else { return }
super.collectionView(collectionView, didSelectItemAt: indexPath)
}
// MARK: Timeline
override func handleLoadAllError(_ error: Swift.Error) async {
guard let error = error as? Client.Error else {
await super.handleLoadAllError(error)
return
}
let code: Int
switch error.type {
case .mastodonError(let c, _), .unexpectedStatus(let c):
code = c
default:
await super.handleLoadAllError(error)
return
}
guard code == 422 || code == 401 else {
await super.handleLoadAllError(error)
return
}
collectionView.isHidden = true
view.backgroundColor = .appBackground
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),
])
}
// MARK: Interaction
@objc func toggleSaveButtonPressed() {
let context = parentMastodonController!.persistentContainer.viewContext
let req = SavedInstance.fetchRequest(url: instanceURL, account: parentMastodonController!.accountInfo!)
let existing = try? context.fetch(req).first
if let existing = existing {
context.delete(existing)
instanceTimelineDelegate?.didUnsaveInstance(url: instanceURL)
} else {
_ = SavedInstance(url: instanceURL, account: parentMastodonController!.accountInfo!, context: context)
instanceTimelineDelegate?.didSaveInstance(url: instanceURL)
}
mastodonController.persistentContainer.save(context: context)
}
}