2021-01-28 09:10:30 +01:00
//
// T i m e l i n e S e c t i o n . s w i f t
// M a s t o d o n
//
// C r e a t e d b y s x i a o j i a n o n 2 0 2 1 / 1 / 2 7 .
//
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-04 08:09:58 +01:00
timelinePostTableViewCellDelegate : TimelinePostTableViewCellDelegate ,
2021-02-05 10:08:51 +01:00
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 : _ ) :
let cell = tableView . dequeueReusableCell ( withIdentifier : String ( describing : TimelinePostTableViewCell . self ) , for : indexPath ) as ! TimelinePostTableViewCell
// c o n f i g u r e c e l l
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 ) :
let cell = tableView . dequeueReusableCell ( withIdentifier : String ( describing : TimelinePostTableViewCell . self ) , for : indexPath ) as ! TimelinePostTableViewCell
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
// c o n f i g u r e c e l l
managedObjectContext . performAndWait {
let toot = managedObjectContext . object ( with : objectID ) as ! Toot
2021-02-08 11:29:27 +01:00
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 )
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
2021-02-07 07:42:50 +01:00
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 (
cell : TimelinePostTableViewCell ,
2021-02-02 07:10:25 +01:00
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-01 11:06:29 +01:00
// s e t n a m e u s e r n a m e a v a t a r
2021-01-28 09:10:30 +01:00
cell . timelinePostView . nameLabel . text = toot . author . displayName
2021-02-01 11:06:29 +01:00
cell . timelinePostView . usernameLabel . text = " @ " + toot . author . username
cell . timelinePostView . avatarImageView . af . setImage (
withURL : URL ( string : toot . author . avatar ) ! ,
placeholderImage : UIImage . placeholder ( color : . systemFill ) ,
imageTransition : . crossDissolve ( 0.2 )
)
// s e t t e x t
2021-01-29 09:47:32 +01:00
cell . timelinePostView . activeTextLabel . config ( content : toot . content )
2021-02-08 11:29:27 +01:00
// t o o l b a r
let isLike = ( toot . reblog ? ? toot ) . favouritedBy . flatMap ( { $0 . contains ( where : { $0 . id = = requestUserID } ) } ) ? ? false
let favoriteCountTitle : String = {
let count = ( toot . reblog ? ? toot ) . favouritesCount . intValue
return TimelineSection . formattedNumberTitleForActionButton ( count )
} ( )
cell . timelinePostView . actionToolbarContainer . starButton . setTitle ( favoriteCountTitle , for : . normal )
cell . timelinePostView . actionToolbarContainer . isStarButtonHighlight = isLike
2021-02-01 11:06:29 +01:00
// s e t d a t e
2021-02-02 07:10:25 +01:00
let createdAt = ( toot . reblog ? ? toot ) . createdAt
timestampUpdatePublisher
. sink { _ in
cell . timelinePostView . dateLabel . text = createdAt . shortTimeAgoSinceNow
}
. store ( in : & cell . disposeBag )
2021-02-08 11:29:27 +01:00
// o b s e r v e m o d e l c h a n g e
ManagedObjectObserver . observe ( object : toot . reblog ? ? toot )
. receive ( on : DispatchQueue . main )
. sink { _ in
// d o n o t h i n g
} receiveValue : { change in
guard case let . update ( object ) = change . changeType ,
let newToot = object as ? Toot else { return }
let targetToot = newToot . reblog ? ? newToot
let isLike = targetToot . favouritedBy . flatMap ( { $0 . contains ( where : { $0 . id = = requestUserID } ) } ) ? ? false
let favoriteCount = targetToot . favouritesCount . intValue
let favoriteCountTitle = TimelineSection . formattedNumberTitleForActionButton ( favoriteCount )
cell . timelinePostView . actionToolbarContainer . starButton . setTitle ( favoriteCountTitle , for : . normal )
cell . timelinePostView . actionToolbarContainer . isStarButtonHighlight = isLike
os_log ( " %{public}s[%{public}ld], %{public}s: like count label for tweet %s did update: %ld " , ( ( #file as NSString ) . lastPathComponent ) , #line , #function , targetToot . id , favoriteCount )
}
. 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 )
}
}