mastodon-ios/Mastodon/Scene/Root/Sidebar/SidebarViewModel.swift

207 lines
8.3 KiB
Swift
Raw Normal View History

2021-09-22 13:08:09 +02:00
//
// SidebarViewModel.swift
// Mastodon
//
// Created by Cirno MainasuK on 2021-9-22.
//
import UIKit
import Combine
import CoreData
import CoreDataStack
2021-09-24 13:58:50 +02:00
import Meta
import MastodonMeta
2021-09-22 13:08:09 +02:00
final class SidebarViewModel {
var disposeBag = Set<AnyCancellable>()
// input
let context: AppContext
let searchHistoryFetchedResultController: SearchHistoryFetchedResultController
2021-09-22 13:08:09 +02:00
// output
var diffableDataSource: UICollectionViewDiffableDataSource<Section, Item>?
2021-10-28 13:17:41 +02:00
var secondaryDiffableDataSource: UICollectionViewDiffableDataSource<Section, Item>?
let activeMastodonAuthenticationObjectID = CurrentValueSubject<NSManagedObjectID?, Never>(nil)
2021-09-22 13:08:09 +02:00
init(context: AppContext) {
self.context = context
self.searchHistoryFetchedResultController = SearchHistoryFetchedResultController(managedObjectContext: context.managedObjectContext)
context.authenticationService.activeMastodonAuthentication
.sink { [weak self] authentication in
guard let self = self else { return }
// bind search history
self.searchHistoryFetchedResultController.domain.value = authentication?.domain
self.searchHistoryFetchedResultController.userID.value = authentication?.userID
// bind objectID
self.activeMastodonAuthenticationObjectID.value = authentication?.objectID
}
.store(in: &disposeBag)
try? searchHistoryFetchedResultController.fetchedResultsController.performFetch()
2021-09-22 13:08:09 +02:00
}
}
extension SidebarViewModel {
enum Section: Int, Hashable, CaseIterable {
2021-10-28 13:17:41 +02:00
case main
case secondary
2021-09-22 13:08:09 +02:00
}
enum Item: Hashable {
case tab(MainTabBarController.Tab)
2021-10-28 13:17:41 +02:00
case setting
case compose
2021-09-22 13:08:09 +02:00
}
}
extension SidebarViewModel {
func setupDiffableDataSource(
2021-10-28 13:17:41 +02:00
collectionView: UICollectionView,
secondaryCollectionView: UICollectionView
2021-09-22 13:08:09 +02:00
) {
let tabCellRegistration = UICollectionView.CellRegistration<SidebarListCollectionViewCell, MainTabBarController.Tab> { [weak self] cell, indexPath, item in
guard let self = self else { return }
2021-09-24 13:58:50 +02:00
let imageURL: URL? = {
switch item {
case .me:
let authentication = self.context.authenticationService.activeMastodonAuthentication.value
return authentication?.user.avatarImageURL()
default:
return nil
}
}()
cell.item = SidebarListContentView.Item(
2021-10-28 13:17:41 +02:00
title: item.title,
2021-09-24 13:58:50 +02:00
image: item.sidebarImage,
2021-10-28 13:17:41 +02:00
imageURL: imageURL
2021-09-24 13:58:50 +02:00
)
cell.setNeedsUpdateConfiguration()
cell.isAccessibilityElement = true
cell.accessibilityLabel = item.title
switch item {
case .notification:
Publishers.CombineLatest(
self.context.authenticationService.activeMastodonAuthentication,
self.context.notificationService.unreadNotificationCountDidUpdate
)
.receive(on: DispatchQueue.main)
.sink { [weak cell] authentication, _ in
guard let cell = cell else { return }
let hasUnreadPushNotification: Bool = authentication.flatMap { authentication in
let count = UserDefaults.shared.getNotificationCountWithAccessToken(accessToken: authentication.userAccessToken)
return count > 0
} ?? false
let image = hasUnreadPushNotification ? UIImage(systemName: "bell.badge")! : UIImage(systemName: "bell")!
cell._contentView?.imageView.image = image
}
.store(in: &cell.disposeBag)
case .me:
guard let authentication = self.context.authenticationService.activeMastodonAuthentication.value else { break }
let currentUserDisplayName = authentication.user.displayNameWithFallback ?? "no user"
cell.accessibilityHint = L10n.Scene.AccountList.tabBarHint(currentUserDisplayName)
default:
break
}
}
2021-10-28 13:17:41 +02:00
let cellRegistration = UICollectionView.CellRegistration<SidebarListCollectionViewCell, SidebarListContentView.Item> { [weak self] cell, indexPath, item in
guard let self = self else { return }
2021-10-28 13:17:41 +02:00
cell.item = item
cell.setNeedsUpdateConfiguration()
cell.isAccessibilityElement = true
cell.accessibilityLabel = item.title
2021-09-22 13:08:09 +02:00
}
2021-10-28 13:17:41 +02:00
// header
let headerRegistration = UICollectionView.SupplementaryRegistration<SidebarListHeaderView>(elementKind: UICollectionView.elementKindSectionHeader) { supplementaryView, elementKind, indexPath in
// do nothing
2021-09-22 13:08:09 +02:00
}
let _diffableDataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { collectionView, indexPath, item in
2021-09-22 13:08:09 +02:00
switch item {
case .tab(let tab):
2021-09-24 13:58:50 +02:00
return collectionView.dequeueConfiguredReusableCell(using: tabCellRegistration, for: indexPath, item: tab)
2021-10-28 13:17:41 +02:00
case .setting:
let item = SidebarListContentView.Item(
title: L10n.Common.Controls.Actions.settings,
image: UIImage(systemName: "gear")!,
imageURL: nil
)
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
case .compose:
let item = SidebarListContentView.Item(
title: "Compose", // TODO: update i18n
2021-10-28 13:17:41 +02:00
image: UIImage(systemName: "square.and.pencil")!,
imageURL: nil
)
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
}
}
_diffableDataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in
switch elementKind {
case UICollectionView.elementKindSectionHeader:
return collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: indexPath)
default:
assertionFailure()
return UICollectionReusableView()
2021-09-22 13:08:09 +02:00
}
}
diffableDataSource = _diffableDataSource
2021-09-22 13:08:09 +02:00
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
2021-10-28 13:17:41 +02:00
snapshot.appendSections([.main])
2021-09-22 13:08:09 +02:00
2021-10-28 13:17:41 +02:00
var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
let items: [Item] = [
.tab(.home),
.tab(.search),
.tab(.notification),
.tab(.me),
.setting,
]
sectionSnapshot.append(items, to: nil)
_diffableDataSource.apply(sectionSnapshot, to: .main)
// secondary
let _secondaryDiffableDataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: secondaryCollectionView) { collectionView, indexPath, item in
guard case .compose = item else {
assertionFailure()
return UICollectionViewCell()
2021-09-22 13:08:09 +02:00
}
2021-10-28 13:17:41 +02:00
let item = SidebarListContentView.Item(
title: "Compose", // FIXME:
image: UIImage(systemName: "square.and.pencil")!,
imageURL: nil
)
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: item)
2021-09-22 13:08:09 +02:00
}
2021-10-28 13:17:41 +02:00
// _secondaryDiffableDataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in
// return nil
// }
secondaryDiffableDataSource = _secondaryDiffableDataSource
2021-09-22 13:08:09 +02:00
2021-10-28 13:17:41 +02:00
var secondarySnapshot = NSDiffableDataSourceSnapshot<Section, Item>()
secondarySnapshot.appendSections([.secondary])
2021-10-28 13:17:41 +02:00
var secondarySectionSnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
let secondarySectionItems: [Item] = [
.compose,
]
secondarySectionSnapshot.append(secondarySectionItems, to: nil)
_secondaryDiffableDataSource.apply(secondarySectionSnapshot, to: .secondary)
2021-09-22 13:08:09 +02:00
}
}