Mark items as read
This commit is contained in:
parent
96255b2a1f
commit
736e8283e1
|
@ -11,10 +11,11 @@ class HomeCollectionViewCell: UICollectionViewListCell {
|
|||
|
||||
override func updateConfiguration(using state: UICellConfigurationState) {
|
||||
var backgroundConfig = UIBackgroundConfiguration.listGroupedCell().updated(for: state)
|
||||
if !state.isHighlighted && !state.isSelected {
|
||||
if state.isHighlighted || state.isSelected {
|
||||
backgroundConfig.backgroundColor = .appCellHighlightBackground
|
||||
} else {
|
||||
backgroundConfig.backgroundColor = .appBackground
|
||||
}
|
||||
// todo: this breaks the deselection animation
|
||||
self.backgroundConfiguration = backgroundConfig
|
||||
}
|
||||
|
||||
|
|
|
@ -8,11 +8,20 @@
|
|||
import UIKit
|
||||
import SwiftSoup
|
||||
|
||||
protocol ItemCollectionViewCellDelegate: AnyObject {
|
||||
func itemCellSelected(item: Item)
|
||||
}
|
||||
|
||||
class ItemCollectionViewCell: UICollectionViewListCell {
|
||||
|
||||
weak var delegate: ItemCollectionViewCellDelegate?
|
||||
|
||||
private let titleLabel = UILabel()
|
||||
private let feedTitleLabel = UILabel()
|
||||
private let contentLabel = UILabel()
|
||||
private var shouldHighlight = true
|
||||
|
||||
private var item: Item!
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
@ -24,10 +33,8 @@ class ItemCollectionViewCell: UICollectionViewListCell {
|
|||
titleLabel.numberOfLines = 0
|
||||
|
||||
feedTitleLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .subheadline), size: 0)
|
||||
feedTitleLabel.textColor = .tintColor
|
||||
|
||||
contentLabel.font = UIFont(descriptor: .preferredFontDescriptor(withTextStyle: .body).withDesign(.serif)!, size: 0)
|
||||
contentLabel.textColor = .appContentPreviewLabel
|
||||
contentLabel.numberOfLines = 0
|
||||
|
||||
let stack = UIStackView(arrangedSubviews: [
|
||||
|
@ -46,6 +53,14 @@ class ItemCollectionViewCell: UICollectionViewListCell {
|
|||
stack.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8),
|
||||
separatorLayoutGuide.leadingAnchor.constraint(equalTo: stack.leadingAnchor),
|
||||
])
|
||||
|
||||
let doubleTap = DoubleTapRecognizer(target: self, action: #selector(cellDoubleTapped))
|
||||
doubleTap.onTouchesBegan = highlightCell
|
||||
addGestureRecognizer(doubleTap)
|
||||
|
||||
let singleTap = UITapGestureRecognizer(target: self, action: #selector(cellSingleTapped))
|
||||
singleTap.require(toFail: doubleTap)
|
||||
addGestureRecognizer(singleTap)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
|
@ -53,6 +68,8 @@ class ItemCollectionViewCell: UICollectionViewListCell {
|
|||
}
|
||||
|
||||
func updateUI(item: Item) {
|
||||
self.item = item
|
||||
|
||||
titleLabel.text = item.title
|
||||
feedTitleLabel.text = item.feed!.title ?? item.feed!.url?.host
|
||||
if let content = item.content {
|
||||
|
@ -62,6 +79,66 @@ class ItemCollectionViewCell: UICollectionViewListCell {
|
|||
contentLabel.text = ""
|
||||
}
|
||||
contentLabel.isHidden = contentLabel.text?.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ?? true
|
||||
|
||||
setColors()
|
||||
}
|
||||
|
||||
private func setColors() {
|
||||
if item.read {
|
||||
titleLabel.textColor = .secondaryLabel
|
||||
feedTitleLabel.textColor = .secondaryLabel
|
||||
contentLabel.textColor = .secondaryLabel
|
||||
} else {
|
||||
titleLabel.textColor = .label
|
||||
feedTitleLabel.textColor = .tintColor
|
||||
contentLabel.textColor = .appContentPreviewLabel
|
||||
}
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
highlightCell()
|
||||
}
|
||||
|
||||
@objc private func highlightCell() {
|
||||
guard shouldHighlight else { return }
|
||||
shouldHighlight = false
|
||||
UIView.animateKeyframes(withDuration: 0.4, delay: 0, options: .allowUserInteraction) {
|
||||
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.5) {
|
||||
self.backgroundColor = .appCellHighlightBackground
|
||||
}
|
||||
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.5) {
|
||||
self.backgroundColor = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func cellDoubleTapped() {
|
||||
self.item.read = !self.item.read
|
||||
// i don't know why .transition works but .animate doesn't
|
||||
UIView.transition(with: self, duration: 0.2, options: .transitionCrossDissolve) {
|
||||
self.setColors()
|
||||
}
|
||||
shouldHighlight = true
|
||||
}
|
||||
|
||||
@objc private func cellSingleTapped() {
|
||||
delegate?.itemCellSelected(item: item)
|
||||
shouldHighlight = true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class DoubleTapRecognizer: UITapGestureRecognizer {
|
||||
var onTouchesBegan: (() -> Void)!
|
||||
|
||||
override init(target: Any?, action: Selector?) {
|
||||
super.init(target: target, action: action)
|
||||
numberOfTapsRequired = 2
|
||||
delaysTouchesBegan = true
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
onTouchesBegan()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,6 @@ class ItemsViewController: UIViewController {
|
|||
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)
|
||||
|
@ -53,8 +52,9 @@ class ItemsViewController: UIViewController {
|
|||
}
|
||||
|
||||
private func createDataSource() -> UICollectionViewDiffableDataSource<Section, Item> {
|
||||
let itemCell = UICollectionView.CellRegistration<ItemCollectionViewCell, Item> { cell, indexPath, item in
|
||||
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)
|
||||
|
@ -80,12 +80,8 @@ extension ItemsViewController: NSFetchedResultsControllerDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
extension ItemsViewController: UICollectionViewDelegate {
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
guard let item = dataSource.itemIdentifier(for: indexPath) else {
|
||||
return
|
||||
}
|
||||
let vc = ReadViewController(item: item, fervorController: fervorController)
|
||||
show(vc, sender: nil)
|
||||
extension ItemsViewController: ItemCollectionViewCellDelegate {
|
||||
func itemCellSelected(item: Item) {
|
||||
show(ReadViewController(item: item, fervorController: fervorController), sender: nil)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,17 @@ extension UIColor {
|
|||
}
|
||||
}
|
||||
|
||||
static let appCellHighlightBackground = UIColor { traitCollection in
|
||||
switch traitCollection.userInterfaceStyle {
|
||||
case .dark:
|
||||
return UIColor(white: 0.15, alpha: 1)
|
||||
case .unspecified, .light:
|
||||
fallthrough
|
||||
@unknown default:
|
||||
return UIColor(white: 0.9, alpha: 1)
|
||||
}
|
||||
}
|
||||
|
||||
static let appContentPreviewLabel = UIColor { traitCollection in
|
||||
switch traitCollection.userInterfaceStyle {
|
||||
case .dark:
|
||||
|
|
Loading…
Reference in New Issue