2019-12-20 03:41:23 +00:00
|
|
|
//
|
|
|
|
// InstanceTimelineViewController.swift
|
|
|
|
// Tusker
|
|
|
|
//
|
|
|
|
// Created by Shadowfacts on 12/19/19.
|
|
|
|
// Copyright © 2019 Shadowfacts. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
2022-11-02 01:06:06 +00:00
|
|
|
import Pachyderm
|
2019-12-20 03:41:23 +00:00
|
|
|
|
2021-05-22 17:42:53 +00:00
|
|
|
protocol InstanceTimelineViewControllerDelegate: AnyObject {
|
2019-12-20 03:41:23 +00:00
|
|
|
func didSaveInstance(url: URL)
|
|
|
|
func didUnsaveInstance(url: URL)
|
|
|
|
}
|
|
|
|
|
2022-11-02 01:06:06 +00:00
|
|
|
class InstanceTimelineViewController: TimelineViewController {
|
2019-12-20 03:41:23 +00:00
|
|
|
|
2023-02-08 04:52:23 +00:00
|
|
|
weak var instanceTimelineDelegate: InstanceTimelineViewControllerDelegate?
|
2019-12-20 03:41:23 +00:00
|
|
|
|
2020-01-20 16:48:47 +00:00
|
|
|
weak var parentMastodonController: MastodonController?
|
|
|
|
|
2019-12-20 03:41:23 +00:00
|
|
|
let instanceURL: URL
|
2020-01-20 16:18:55 +00:00
|
|
|
let instanceMastodonController: MastodonController
|
2019-12-20 03:41:23 +00:00
|
|
|
|
2022-05-11 02:57:46 +00:00
|
|
|
private var toggleSaveButton: UIBarButtonItem!
|
|
|
|
|
|
|
|
private var isInstanceSaved: Bool {
|
2022-12-19 15:58:14 +00:00
|
|
|
let req = SavedInstance.fetchRequest(url: instanceURL, account: parentMastodonController!.accountInfo!)
|
|
|
|
return parentMastodonController!.persistentContainer.viewContext.objectExists(for: req)
|
2022-05-11 02:57:46 +00:00
|
|
|
}
|
|
|
|
private var toggleSaveButtonTitle: String {
|
|
|
|
if isInstanceSaved {
|
2019-12-20 03:41:23 +00:00
|
|
|
return NSLocalizedString("Unsave", comment: "unsave instance button")
|
|
|
|
} else {
|
|
|
|
return NSLocalizedString("Save", comment: "save instance button")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-13 19:51:06 +00:00
|
|
|
var browsingEnabled = true
|
|
|
|
|
2020-01-20 16:48:47 +00:00
|
|
|
init(for url: URL, parentMastodonController: MastodonController) {
|
|
|
|
self.parentMastodonController = parentMastodonController
|
2019-12-20 03:41:23 +00:00
|
|
|
|
2020-01-20 16:48:47 +00:00
|
|
|
self.instanceURL = url
|
|
|
|
|
2020-01-20 16:18:55 +00:00
|
|
|
// 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
|
2020-05-11 21:57:50 +00:00
|
|
|
instanceMastodonController = MastodonController(instanceURL: url, transient: true)
|
2020-01-08 02:29:15 +00:00
|
|
|
|
2020-01-25 15:37:22 +00:00
|
|
|
super.init(for: .public(local: true), mastodonController: instanceMastodonController)
|
|
|
|
|
|
|
|
title = url.host!
|
|
|
|
userActivity = nil // todo: activity for instance-specific timelines
|
2019-12-20 03:41:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-12-04 17:08:22 +00:00
|
|
|
override func configureStatusCell(_ cell: TimelineStatusCollectionViewCell, id: String, state: CollapseState, filterResult: Filterer.Result, precomputedContent: NSAttributedString?) {
|
2020-09-13 19:51:06 +00:00
|
|
|
cell.delegate = browsingEnabled ? self : nil
|
2022-11-02 01:06:06 +00:00
|
|
|
cell.overrideMastodonController = mastodonController
|
2022-12-04 17:08:22 +00:00
|
|
|
cell.updateUI(statusID: id, state: state, filterResult: filterResult, precomputedContent: precomputedContent)
|
2020-01-06 00:39:37 +00:00
|
|
|
}
|
|
|
|
|
2022-11-02 01:06:06 +00:00
|
|
|
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
2020-09-13 19:51:06 +00:00
|
|
|
guard browsingEnabled else { return }
|
2022-11-02 01:06:06 +00:00
|
|
|
super.collectionView(collectionView, didSelectItemAt: indexPath)
|
2020-01-25 15:44:31 +00:00
|
|
|
}
|
|
|
|
|
2023-01-22 16:18:43 +00:00
|
|
|
// MARK: Timeline
|
|
|
|
|
|
|
|
override func handleLoadAllError(_ error: Swift.Error) async {
|
2023-02-05 16:18:23 +00:00
|
|
|
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
|
2023-01-22 16:18:43 +00:00
|
|
|
default:
|
|
|
|
await super.handleLoadAllError(error)
|
2023-02-05 16:18:23 +00:00
|
|
|
return
|
2023-01-22 16:18:43 +00:00
|
|
|
}
|
2023-02-05 16:18:23 +00:00
|
|
|
guard code == 422 || code == 401 else {
|
|
|
|
await super.handleLoadAllError(error)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
collectionView.isHidden = true
|
2023-02-06 23:15:23 +00:00
|
|
|
view.backgroundColor = .appBackground
|
2023-02-05 16:18:23 +00:00
|
|
|
|
|
|
|
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),
|
|
|
|
])
|
2023-01-22 16:18:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: Interaction
|
2019-12-20 03:41:23 +00:00
|
|
|
@objc func toggleSaveButtonPressed() {
|
2022-05-11 02:57:46 +00:00
|
|
|
let context = parentMastodonController!.persistentContainer.viewContext
|
2022-12-19 15:58:14 +00:00
|
|
|
let req = SavedInstance.fetchRequest(url: instanceURL, account: parentMastodonController!.accountInfo!)
|
|
|
|
let existing = try? context.fetch(req).first
|
2022-05-11 02:57:46 +00:00
|
|
|
if let existing = existing {
|
|
|
|
context.delete(existing)
|
2023-02-08 04:52:23 +00:00
|
|
|
instanceTimelineDelegate?.didUnsaveInstance(url: instanceURL)
|
2019-12-20 03:41:23 +00:00
|
|
|
} else {
|
2022-12-19 15:58:14 +00:00
|
|
|
_ = SavedInstance(url: instanceURL, account: parentMastodonController!.accountInfo!, context: context)
|
2023-02-08 04:52:23 +00:00
|
|
|
instanceTimelineDelegate?.didSaveInstance(url: instanceURL)
|
2019-12-20 03:41:23 +00:00
|
|
|
}
|
2022-10-09 21:06:10 +00:00
|
|
|
mastodonController.persistentContainer.save(context: context)
|
2019-12-20 03:41:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|