forked from zelo72/mastodon-ios
199 lines
6.9 KiB
Swift
199 lines
6.9 KiB
Swift
//
|
|
// Item.swift
|
|
// Mastodon
|
|
//
|
|
// Created by sxiaojian on 2021/1/27.
|
|
//
|
|
|
|
import Combine
|
|
import CoreData
|
|
import CoreDataStack
|
|
import Foundation
|
|
import MastodonSDK
|
|
import DifferenceKit
|
|
|
|
/// Note: update Equatable when change case
|
|
enum Item {
|
|
// timeline
|
|
case homeTimelineIndex(objectID: NSManagedObjectID, attribute: StatusAttribute)
|
|
|
|
// thread
|
|
case root(statusObjectID: NSManagedObjectID, attribute: StatusAttribute)
|
|
case reply(statusObjectID: NSManagedObjectID, attribute: StatusAttribute)
|
|
case leaf(statusObjectID: NSManagedObjectID, attribute: StatusAttribute)
|
|
case leafBottomLoader(statusObjectID: NSManagedObjectID)
|
|
|
|
// normal list
|
|
case status(objectID: NSManagedObjectID, attribute: StatusAttribute)
|
|
|
|
// loader
|
|
case homeMiddleLoader(upperTimelineIndexAnchorObjectID: NSManagedObjectID)
|
|
case publicMiddleLoader(statusID: String)
|
|
case topLoader
|
|
case bottomLoader
|
|
case emptyBottomLoader
|
|
|
|
case emptyStateHeader(attribute: EmptyStateHeaderAttribute)
|
|
|
|
// reports
|
|
case reportStatus(objectID: NSManagedObjectID, attribute: ReportStatusAttribute)
|
|
}
|
|
|
|
extension Item {
|
|
class StatusAttribute {
|
|
var isSeparatorLineHidden: Bool
|
|
|
|
/// is media loaded or not
|
|
let isImageLoaded = CurrentValueSubject<Bool, Never>(false)
|
|
|
|
/// flag for current sensitive content reveal state
|
|
///
|
|
/// - true: displaying sensitive content
|
|
/// - false: displaying content warning overlay
|
|
let isRevealing = CurrentValueSubject<Bool, Never>(false)
|
|
|
|
init(isSeparatorLineHidden: Bool = false) {
|
|
self.isSeparatorLineHidden = isSeparatorLineHidden
|
|
}
|
|
}
|
|
|
|
class EmptyStateHeaderAttribute: Hashable {
|
|
let id = UUID()
|
|
let reason: Reason
|
|
|
|
enum Reason: Equatable {
|
|
case noStatusFound
|
|
case blocking(name: String?)
|
|
case blocked(name: String?)
|
|
case suspended(name: String?)
|
|
|
|
static func == (lhs: Item.EmptyStateHeaderAttribute.Reason, rhs: Item.EmptyStateHeaderAttribute.Reason) -> Bool {
|
|
switch (lhs, rhs) {
|
|
case (.noStatusFound, noStatusFound): return true
|
|
case (.blocking(let nameLeft), blocking(let nameRight)): return nameLeft == nameRight
|
|
case (.blocked(let nameLeft), blocked(let nameRight)): return nameLeft == nameRight
|
|
case (.suspended(let nameLeft), .suspended(let nameRight)): return nameLeft == nameRight
|
|
default: return false
|
|
}
|
|
}
|
|
}
|
|
|
|
init(reason: Reason) {
|
|
self.reason = reason
|
|
}
|
|
|
|
static func == (lhs: Item.EmptyStateHeaderAttribute, rhs: Item.EmptyStateHeaderAttribute) -> Bool {
|
|
return lhs.reason == rhs.reason
|
|
}
|
|
|
|
func hash(into hasher: inout Hasher) {
|
|
hasher.combine(id)
|
|
}
|
|
}
|
|
|
|
class ReportStatusAttribute: StatusAttribute {
|
|
var isSelected: Bool
|
|
|
|
init(isSeparatorLineHidden: Bool = false, isSelected: Bool = false) {
|
|
self.isSelected = isSelected
|
|
super.init(isSeparatorLineHidden: isSeparatorLineHidden)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
extension Item: Equatable {
|
|
static func == (lhs: Item, rhs: Item) -> Bool {
|
|
switch (lhs, rhs) {
|
|
case (.homeTimelineIndex(let objectIDLeft, _), .homeTimelineIndex(let objectIDRight, _)):
|
|
return objectIDLeft == objectIDRight
|
|
case (.root(let objectIDLeft, _), .root(let objectIDRight, _)):
|
|
return objectIDLeft == objectIDRight
|
|
case (.reply(let objectIDLeft, _), .reply(let objectIDRight, _)):
|
|
return objectIDLeft == objectIDRight
|
|
case (.leaf(let objectIDLeft, _), .leaf(let objectIDRight, _)):
|
|
return objectIDLeft == objectIDRight
|
|
case (.leafBottomLoader(let objectIDLeft), .leafBottomLoader(let objectIDRight)):
|
|
return objectIDLeft == objectIDRight
|
|
case (.status(let objectIDLeft, _), .status(let objectIDRight, _)):
|
|
return objectIDLeft == objectIDRight
|
|
case (.homeMiddleLoader(let upperLeft), .homeMiddleLoader(let upperRight)):
|
|
return upperLeft == upperRight
|
|
case (.publicMiddleLoader(let upperLeft), .publicMiddleLoader(let upperRight)):
|
|
return upperLeft == upperRight
|
|
case (.topLoader, .topLoader):
|
|
return true
|
|
case (.bottomLoader, .bottomLoader):
|
|
return true
|
|
case (.emptyBottomLoader, .emptyBottomLoader):
|
|
return true
|
|
case (.emptyStateHeader(let attributeLeft), .emptyStateHeader(let attributeRight)):
|
|
return attributeLeft == attributeRight
|
|
case (.reportStatus(let objectIDLeft, _), .reportStatus(let objectIDRight, _)):
|
|
return objectIDLeft == objectIDRight
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Item: Hashable {
|
|
func hash(into hasher: inout Hasher) {
|
|
switch self {
|
|
case .homeTimelineIndex(let objectID, _):
|
|
hasher.combine(objectID)
|
|
case .root(let objectID, _):
|
|
hasher.combine(objectID)
|
|
case .reply(let objectID, _):
|
|
hasher.combine(objectID)
|
|
case .leaf(let objectID, _):
|
|
hasher.combine(objectID)
|
|
case .leafBottomLoader(let objectID):
|
|
hasher.combine(objectID)
|
|
case .status(let objectID, _):
|
|
hasher.combine(objectID)
|
|
case .homeMiddleLoader(upperTimelineIndexAnchorObjectID: let upper):
|
|
hasher.combine(String(describing: Item.homeMiddleLoader.self))
|
|
hasher.combine(upper)
|
|
case .publicMiddleLoader(let upper):
|
|
hasher.combine(String(describing: Item.publicMiddleLoader.self))
|
|
hasher.combine(upper)
|
|
case .topLoader:
|
|
hasher.combine(String(describing: Item.topLoader.self))
|
|
case .bottomLoader:
|
|
hasher.combine(String(describing: Item.bottomLoader.self))
|
|
case .emptyBottomLoader:
|
|
hasher.combine(String(describing: Item.emptyBottomLoader.self))
|
|
case .emptyStateHeader(let attribute):
|
|
hasher.combine(attribute)
|
|
case .reportStatus(let objectID, _):
|
|
hasher.combine(objectID)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Item: Differentiable { }
|
|
|
|
extension Item {
|
|
var statusObjectItem: StatusObjectItem? {
|
|
switch self {
|
|
case .homeTimelineIndex(let objectID, _):
|
|
return .homeTimelineIndex(objectID: objectID)
|
|
case .root(let objectID, _),
|
|
.reply(let objectID, _),
|
|
.leaf(let objectID, _),
|
|
.status(let objectID, _),
|
|
.reportStatus(let objectID, _):
|
|
return .status(objectID: objectID)
|
|
case .leafBottomLoader,
|
|
.homeMiddleLoader,
|
|
.publicMiddleLoader,
|
|
.topLoader,
|
|
.bottomLoader,
|
|
.emptyBottomLoader,
|
|
.emptyStateHeader:
|
|
return nil
|
|
}
|
|
}
|
|
}
|