Tusker/Tusker/Screens/Notifications/NotificationLoadingViewCont...

156 lines
5.8 KiB
Swift

//
// NotificationLoadingViewController.swift
// Tusker
//
// Created by Shadowfacts on 4/12/24.
// Copyright © 2024 Shadowfacts. All rights reserved.
//
import UIKit
import Pachyderm
class NotificationLoadingViewController: UIViewController {
private let notificationID: String
private let mastodonController: MastodonController
init(notificationID: String, mastodonController: MastodonController) {
self.notificationID = notificationID
self.mastodonController = mastodonController
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .secondarySystemBackground
let indicator = UIActivityIndicatorView(style: .medium)
indicator.startAnimating()
indicator.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(indicator)
NSLayoutConstraint.activate([
indicator.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor),
indicator.centerYAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerYAnchor),
])
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Task {
let request = Client.getNotification(id: notificationID)
do {
let (notification, _) = try await mastodonController.run(request)
await withCheckedContinuation { continuation in
mastodonController.persistentContainer.addAll(notifications: [notification]) {
continuation.resume()
}
}
showNotification(notification)
} catch {
showLoadingError(error)
}
}
}
private func showNotification(_ notification: Pachyderm.Notification) {
let vc: UIViewController
switch notification.kind {
case .mention, .status, .poll, .update:
guard let statusID = notification.status?.id else {
showLoadingError(Error.missingStatus)
return
}
vc = ConversationViewController(for: statusID, state: .unknown, mastodonController: mastodonController)
case .reblog, .favourite:
guard let statusID = notification.status?.id else {
showLoadingError(Error.missingStatus)
return
}
let actionType = notification.kind == .reblog ? StatusActionAccountListViewController.ActionType.reblog : .favorite
vc = StatusActionAccountListViewController(actionType: actionType, statusID: statusID, statusState: .unknown, accountIDs: [notification.account.id], mastodonController: mastodonController)
case .follow:
vc = ProfileViewController(accountID: notification.account.id, mastodonController: mastodonController)
case .followRequest:
// todo
return
case .unknown:
showLoadingError(Error.unknownType)
return
}
guard let navigationController else {
fatalError("Don't know how to show notification VC outside of navigation controller")
}
navigationController.viewControllers[navigationController.viewControllers.count - 1] = vc
}
private func showLoadingError(_ error: any Swift.Error) {
let image = UIImageView(image: UIImage(systemName: "exclamationmark.triangle.fill")!)
image.tintColor = .secondaryLabel
image.contentMode = .scaleAspectFit
let title = UILabel()
title.textColor = .secondaryLabel
title.font = .preferredFont(forTextStyle: .title1).withTraits(.traitBold)!
title.adjustsFontForContentSizeCategory = true
title.text = "Couldn't Load Notification"
let subtitle = UILabel()
subtitle.textColor = .secondaryLabel
subtitle.font = .preferredFont(forTextStyle: .body)
subtitle.adjustsFontForContentSizeCategory = true
subtitle.numberOfLines = 0
subtitle.textAlignment = .center
if let error = error as? Error {
subtitle.text = error.localizedDescription
} else if let error = error as? Client.Error {
subtitle.text = error.localizedDescription
} else {
subtitle.text = error.localizedDescription
}
let stack = UIStackView(arrangedSubviews: [
image,
title,
subtitle,
])
stack.axis = .vertical
stack.alignment = .center
stack.spacing = 8
stack.isAccessibilityElement = true
stack.accessibilityLabel = "\(title.text!). \(subtitle.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),
])
}
}
private enum Error: LocalizedError {
case missingStatus
case unknownType
var errorDescription: String? {
switch self {
case .missingStatus:
"Missing status for mention/status notification"
case .unknownType:
"Unknown notification type"
}
}
}