frenzy-ios/Reader/Screens/Items/ItemsViewController.swift

134 lines
5.7 KiB
Swift

//
// ItemsViewController.swift
// Reader
//
// Created by Shadowfacts on 1/9/22.
//
import UIKit
import CoreData
import SafariServices
class ItemsViewController: UIViewController {
let fervorController: FervorController
let fetchRequest: NSFetchRequest<Item>
private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
private var resultsController: NSFetchedResultsController<Item>!
init(fetchRequest: NSFetchRequest<Item>, fervorController: FervorController) {
self.fervorController = fervorController
self.fetchRequest = fetchRequest
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
var configuration = UICollectionLayoutListConfiguration(appearance: .plain)
configuration.backgroundColor = .appBackground
let layout = UICollectionViewCompositionalLayout.list(using: configuration)
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.register(ItemCollectionViewCell.self, forCellWithReuseIdentifier: "itemCell")
view.addSubview(collectionView)
dataSource = createDataSource()
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.items])
dataSource.apply(snapshot, animatingDifferences: false)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: "published", ascending: false)]
resultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: fervorController.persistentContainer.viewContext, sectionNameKeyPath: nil, cacheName: nil)
resultsController.delegate = self
try! resultsController.performFetch()
}
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
let itemCell = UICollectionView.CellRegistration<ItemCollectionViewCell, Item> { [unowned self] cell, indexPath, item in
cell.updateUI(item: item)
cell.delegate = self
}
let dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) { collectionView, indexPath, item in
return collectionView.dequeueConfiguredReusableCell(using: itemCell, for: indexPath, item: item)
}
return dataSource
}
}
extension ItemsViewController {
enum Section: Hashable {
case items
}
}
extension ItemsViewController: NSFetchedResultsControllerDelegate {
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
var snapshot = self.dataSource.snapshot()
snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .items))
// use resultsController here instead of controller so we don't have to cast
snapshot.appendItems(resultsController.fetchedObjects!, toSection: .items)
self.dataSource.apply(snapshot, animatingDifferences: false)
}
}
extension ItemsViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
guard let item = dataSource.itemIdentifier(for: indexPath) else {
return nil
}
return UIContextMenuConfiguration(identifier: nil, previewProvider: {
ReadViewController(item: item, fervorController: self.fervorController)
}, actionProvider: { _ in
var children: [UIAction] = []
if let url = item.url {
children.append(UIAction(title: "Open in Safari", image: UIImage(systemName: "safari"), handler: { [weak self] _ in
let vc = SFSafariViewController(url: url)
vc.preferredControlTintColor = .appTintColor
self?.present(vc, animated: true)
}))
children.append(UIAction(title: "Share", image: UIImage(systemName: "square.and.arrow.up"), handler: { [weak self] _ in
self?.present(UIActivityViewController(activityItems: [url], applicationActivities: nil), animated: true)
}))
}
if item.read {
children.append(UIAction(title: "Mark as Unread", image: UIImage(systemName: "checkmark.circle"), handler: { _ in
item.read = false
}))
} else {
children.append(UIAction(title: "Mark as Read", image: UIImage(systemName: "checkmark.circle.fill"), handler: { _ in
item.read = true
}))
}
return UIMenu(children: children)
})
}
func collectionView(_ collectionView: UICollectionView, willPerformPreviewActionForMenuWith configuration: UIContextMenuConfiguration, animator: UIContextMenuInteractionCommitAnimating) {
guard let vc = animator.previewViewController else {
return
}
animator.preferredCommitStyle = .pop
animator.addCompletion {
self.show(vc, sender: nil)
}
}
}
extension ItemsViewController: ItemCollectionViewCellDelegate {
func itemCellSelected(cell: ItemCollectionViewCell, item: Item) {
cell.setRead(true, animated: true)
show(ReadViewController(item: item, fervorController: fervorController), sender: nil)
}
}