Tusker/Tusker/Screens/Notifications/NotificationsPageViewContro...

183 lines
6.5 KiB
Swift

//
// NotificationsPageViewController.swift
// Tusker
//
// Created by Shadowfacts on 9/13/19.
// Copyright © 2019 Shadowfacts. All rights reserved.
//
import UIKit
import Pachyderm
import TuskerPreferences
class NotificationsPageViewController: SegmentedPageViewController<NotificationsPageViewController.Page> {
weak var mastodonController: MastodonController!
var initialMode: NotificationsMode?
private lazy var announcementsButton: UIButton = {
#if os(visionOS)
var config = UIButton.Configuration.borderedProminent()
#else
var config = UIButton.Configuration.plain()
// We don't want a background for this button, even when accessibility button shapes are enabled, because it's in the navbar.
config.background.backgroundColor = .clear
#endif
config.image = UIImage(systemName: "megaphone.fill")
config.contentInsets = .zero
let button = UIButton(configuration: config)
button.addTarget(self, action: #selector(announcementsButtonPresesd), for: .touchUpInside)
return button
}()
private var unreadAnnouncements: AnnouncementsCollection?
init(initialMode: NotificationsMode? = nil, mastodonController: MastodonController) {
self.initialMode = initialMode
self.mastodonController = mastodonController
super.init(pages: [.all, .mentions]) { page in
let vc = NotificationsCollectionViewController(allowedTypes: page.allowedTypes, mastodonController: mastodonController)
vc.title = page.title
vc.userActivity = page.userActivity(accountID: mastodonController.accountInfo!.id)
vc.updatesNotificationsMarker = page == .all
return vc
}
title = Page.all.title
tabBarItem.image = UIImage(systemName: "bell.fill")
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: announcementsButton)
announcementsButton.isHidden = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
selectMode(initialMode ?? Preferences.shared.defaultNotificationsMode)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Task {
await checkForAnnouncements()
}
}
func selectMode(_ mode: NotificationsMode) {
let page: Page
switch mode {
case .allNotifications:
page = .all
case .mentionsOnly:
page = .mentions
}
selectPage(page, animated: false)
}
private func checkForAnnouncements() async {
guard mastodonController.instanceFeatures.instanceAnnouncements else {
navigationItem.rightBarButtonItem = nil
return
}
let announcements: [Announcement]
do {
(announcements, _) = try await mastodonController.run(Announcement.all())
} catch {
Logging.general.error("Error fetching announcements: \(String(describing: error))")
return
}
let unread = announcements.filter { $0.read == false }
if unread.isEmpty {
unreadAnnouncements = nil
if #available(iOS 17.0, *) {
announcementsButton.imageView!.addSymbolEffect(.disappear)
} else {
UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseInOut) {
self.announcementsButton.transform = CGAffineTransform(scaleX: 0.8, y: 0.8)
self.announcementsButton.layer.opacity = 0
} completion: { _ in
self.announcementsButton.transform = .identity
self.announcementsButton.layer.opacity = 1
}
}
} else {
announcementsButton.isHidden = false
announcementsButton.layer.opacity = 1
unreadAnnouncements = AnnouncementsCollection(announcements: unread)
if #available(iOS 17.0, *) {
// make sure to remove the .disappear effect, which stays around indefinitely
announcementsButton.imageView!.removeAllSymbolEffects()
announcementsButton.imageView!.addSymbolEffect(.bounce)
} else {
UIView.animate(withDuration: 0.2, delay: 0.1, options: .curveEaseInOut) {
self.announcementsButton.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
} completion: { _ in
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut) {
self.announcementsButton.transform = .identity
}
}
}
}
}
@objc private func announcementsButtonPresesd() {
guard let unreadAnnouncements else {
return
}
show(AnnouncementsHostingController(announcements: unreadAnnouncements, mastodonController: mastodonController), sender: nil)
}
}
extension NotificationsPageViewController {
enum Page: SegmentedPageViewControllerPage {
case all
case mentions
var title: String {
switch self {
case .all:
return NSLocalizedString("Notifications", comment: "notifications tab title")
case .mentions:
return NSLocalizedString("Mentions", comment: "mentions tab title")
}
}
var segmentedControlTitle: String {
title
}
var allowedTypes: [Pachyderm.Notification.Kind] {
switch self {
case .all:
var set = Set(Pachyderm.Notification.Kind.allCases)
set.remove(.unknown)
return Array(set)
case .mentions:
return [.mention]
}
}
@MainActor
func userActivity(accountID: String) -> NSUserActivity {
switch self {
case .all:
return UserActivityManager.checkNotificationsActivity(mode: .allNotifications, accountID: accountID)
case .mentions:
return UserActivityManager.checkNotificationsActivity(mode: .mentionsOnly, accountID: accountID)
}
}
}
}
extension NotificationsPageViewController: StateRestorableViewController {
func stateRestorationActivity() -> NSUserActivity? {
return currentPage.userActivity(accountID: mastodonController.accountInfo!.id)
}
}