mastodon-ios/Mastodon/Diffiable/Section/TimelineSection.swift

139 lines
7.2 KiB
Swift
Raw Normal View History

2021-01-28 09:10:30 +01:00
//
// TimelineSection.swift
// Mastodon
//
// Created by sxiaojian on 2021/1/27.
//
import Combine
import CoreData
import CoreDataStack
import os.log
import UIKit
enum TimelineSection: Equatable, Hashable {
case main
}
extension TimelineSection {
static func tableViewDiffableDataSource(
for tableView: UITableView,
dependency: NeedsDependency,
managedObjectContext: NSManagedObjectContext,
timestampUpdatePublisher: AnyPublisher<Date, Never>,
2021-02-23 08:16:55 +01:00
timelinePostTableViewCellDelegate: StatusTableViewCellDelegate,
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate?
2021-01-28 09:10:30 +01:00
) -> UITableViewDiffableDataSource<TimelineSection, Item> {
2021-02-04 08:09:58 +01:00
UITableViewDiffableDataSource(tableView: tableView) { [weak timelinePostTableViewCellDelegate, weak timelineMiddleLoaderTableViewCellDelegate] tableView, indexPath, item -> UITableViewCell? in
2021-01-28 09:10:30 +01:00
guard let timelinePostTableViewCellDelegate = timelinePostTableViewCellDelegate else { return UITableViewCell() }
switch item {
2021-02-07 07:42:50 +01:00
case .homeTimelineIndex(objectID: let objectID, attribute: _):
2021-02-23 08:16:55 +01:00
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell
2021-02-07 07:42:50 +01:00
// configure cell
managedObjectContext.performAndWait {
let timelineIndex = managedObjectContext.object(with: objectID) as! HomeTimelineIndex
2021-02-08 11:29:27 +01:00
TimelineSection.configure(cell: cell, timestampUpdatePublisher: timestampUpdatePublisher, toot: timelineIndex.toot, requestUserID: timelineIndex.userID)
2021-02-07 07:42:50 +01:00
}
cell.delegate = timelinePostTableViewCellDelegate
return cell
2021-01-28 09:10:30 +01:00
case .toot(let objectID):
2021-02-23 08:16:55 +01:00
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell
2021-02-08 11:29:27 +01:00
let activeMastodonAuthenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value
let requestUserID = activeMastodonAuthenticationBox?.userID ?? ""
2021-01-28 09:10:30 +01:00
// configure cell
managedObjectContext.performAndWait {
let toot = managedObjectContext.object(with: objectID) as! Toot
TimelineSection.configure(cell: cell, timestampUpdatePublisher: timestampUpdatePublisher, toot: toot, requestUserID: requestUserID)
2021-01-28 09:10:30 +01:00
}
cell.delegate = timelinePostTableViewCellDelegate
return cell
2021-02-07 07:42:50 +01:00
case .publicMiddleLoader(let upperTimelineTootID):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self), for: indexPath) as! TimelineMiddleLoaderTableViewCell
cell.delegate = timelineMiddleLoaderTableViewCellDelegate
timelineMiddleLoaderTableViewCellDelegate?.configure(cell: cell, upperTimelineTootID: upperTimelineTootID, timelineIndexobjectID: nil)
2021-02-07 07:42:50 +01:00
return cell
case .homeMiddleLoader(let upperTimelineIndexObjectID):
2021-02-04 08:09:58 +01:00
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self), for: indexPath) as! TimelineMiddleLoaderTableViewCell
cell.delegate = timelineMiddleLoaderTableViewCellDelegate
timelineMiddleLoaderTableViewCellDelegate?.configure(cell: cell, upperTimelineTootID: nil, timelineIndexobjectID: upperTimelineIndexObjectID)
2021-02-04 08:09:58 +01:00
return cell
2021-02-03 06:01:50 +01:00
case .bottomLoader:
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
cell.activityIndicatorView.startAnimating()
return cell
2021-01-28 09:10:30 +01:00
}
}
}
static func configure(
2021-02-23 08:16:55 +01:00
cell: StatusTableViewCell,
timestampUpdatePublisher: AnyPublisher<Date, Never>,
2021-02-08 11:29:27 +01:00
toot: Toot,
requestUserID: String
2021-01-28 09:10:30 +01:00
) {
2021-02-23 08:16:55 +01:00
// set header
cell.statusView.headerContainerStackView.isHidden = toot.reblog == nil
cell.statusView.headerInfoLabel.text = L10n.Common.Controls.Status.userboosted(toot.author.displayName)
// set name username avatar
2021-02-23 08:16:55 +01:00
cell.statusView.nameLabel.text = toot.author.displayName
2021-02-23 09:45:00 +01:00
cell.statusView.usernameLabel.text = "@" + toot.author.acct
2021-02-23 08:16:55 +01:00
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: toot.author.avatarImageURL()))
// set text
2021-02-23 08:16:55 +01:00
cell.statusView.activeTextLabel.config(content: (toot.reblog ?? toot).content)
2021-02-08 11:29:27 +01:00
// toolbar
2021-02-23 08:23:18 +01:00
let replyCountTitle: String = {
let count = (toot.reblog ?? toot).repliesCount?.intValue ?? 0
return TimelineSection.formattedNumberTitleForActionButton(count)
}()
cell.statusView.actionToolbarContainer.replyButton.setTitle(replyCountTitle, for: .normal)
let isLike = (toot.reblog ?? toot).favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
2021-02-08 11:29:27 +01:00
let favoriteCountTitle: String = {
let count = (toot.reblog ?? toot).favouritesCount.intValue
return TimelineSection.formattedNumberTitleForActionButton(count)
}()
2021-02-23 08:16:55 +01:00
cell.statusView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal)
cell.statusView.actionToolbarContainer.isStarButtonHighlight = isLike
// set date
let createdAt = (toot.reblog ?? toot).createdAt
2021-02-23 08:16:55 +01:00
cell.statusView.dateLabel.text = createdAt.shortTimeAgoSinceNow
timestampUpdatePublisher
.sink { _ in
2021-02-23 08:16:55 +01:00
cell.statusView.dateLabel.text = createdAt.shortTimeAgoSinceNow
}
.store(in: &cell.disposeBag)
2021-02-08 11:29:27 +01:00
// observe model change
ManagedObjectObserver.observe(object: toot.reblog ?? toot)
.receive(on: DispatchQueue.main)
.sink { _ in
// do nothing
} receiveValue: { change in
guard case .update(let object) = change.changeType,
2021-02-08 11:29:27 +01:00
let newToot = object as? Toot else { return }
let targetToot = newToot.reblog ?? newToot
let isLike = targetToot.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
2021-02-08 11:29:27 +01:00
let favoriteCount = targetToot.favouritesCount.intValue
let favoriteCountTitle = TimelineSection.formattedNumberTitleForActionButton(favoriteCount)
2021-02-23 08:16:55 +01:00
cell.statusView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal)
cell.statusView.actionToolbarContainer.isStarButtonHighlight = isLike
os_log("%{public}s[%{public}ld], %{public}s: like count label for toot %s did update: %ld", (#file as NSString).lastPathComponent, #line, #function, targetToot.id, favoriteCount)
2021-02-08 11:29:27 +01:00
}
.store(in: &cell.disposeBag)
2021-01-28 09:10:30 +01:00
}
}
extension TimelineSection {
private static func formattedNumberTitleForActionButton(_ number: Int?) -> String {
guard let number = number, number > 0 else { return "" }
return String(number)
}
}