fix: timer update leaking raise crash in notification scene

This commit is contained in:
CMK 2021-06-15 16:36:42 +08:00
parent 389d0971cd
commit 7d1c150364
5 changed files with 51 additions and 36 deletions

View File

@ -101,6 +101,10 @@ extension MastodonNotification {
])
}
}
public static func predicate(validTypesRaws types: [String]) -> NSPredicate {
return NSPredicate(format: "%K IN %@", #keyPath(MastodonNotification.typeRaw), types)
}
}

View File

@ -30,14 +30,16 @@ extension NotificationSection {
guard let dependency = dependency else { return nil }
switch notificationItem {
case .notification(let objectID, let attribute):
let notification = managedObjectContext.object(with: objectID) as! MastodonNotification
guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: notification.typeRaw) else {
// filter out invalid type using predicate
assertionFailure()
return nil
return UITableViewCell()
}
let timeText = notification.createAt.slowedTimeAgoSinceNow
let createAt = notification.createAt
let timeText = createAt.slowedTimeAgoSinceNow
let actionText = type.actionText
let actionImageName = type.actionImageName
let color = type.color
@ -57,23 +59,24 @@ extension NotificationSection {
requestUserID: requestUserID,
statusItemAttribute: attribute
)
cell.actionImageBackground.backgroundColor = color
cell.nameLabel.text = notification.account.displayName.isEmpty ? notification.account.username : notification.account.displayName
cell.actionLabel.text = actionText + " · " + timeText
timestampUpdatePublisher
.sink { _ in
let timeText = notification.createAt.slowedTimeAgoSinceNow
.sink { [weak cell] _ in
guard let cell = cell else { return }
let timeText = createAt.slowedTimeAgoSinceNow
cell.actionLabel.text = actionText + " · " + timeText
}
.store(in: &cell.disposeBag)
cell.actionImageBackground.backgroundColor = color
cell.actionLabel.text = actionText + " · " + timeText
cell.nameLabel.text = notification.account.displayName.isEmpty ? notification.account.username : notification.account.displayName
if let url = notification.account.avatarImageURL() {
cell.avatatImageView.af.setImage(
cell.avatarImageView.af.setImage(
withURL: url,
placeholderImage: UIImage.placeholder(color: .systemFill),
imageTransition: .crossDissolve(0.2)
)
}
cell.avatatImageView.gesture().sink { [weak cell] _ in
cell.avatarImageView.gesture().sink { [weak cell] _ in
cell?.delegate?.userAvatarDidPressed(notification: notification)
}
.store(in: &cell.disposeBag)
@ -86,8 +89,9 @@ extension NotificationSection {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NotificationTableViewCell.self), for: indexPath) as! NotificationTableViewCell
cell.delegate = delegate
timestampUpdatePublisher
.sink { _ in
let timeText = notification.createAt.slowedTimeAgoSinceNow
.sink { [weak cell] _ in
guard let cell = cell else { return }
let timeText = createAt.slowedTimeAgoSinceNow
cell.actionLabel.text = actionText + " · " + timeText
}
.store(in: &cell.disposeBag)

View File

@ -9,6 +9,7 @@ import CoreData
import CoreDataStack
import os.log
import UIKit
import MastodonSDK
extension NotificationViewModel {
func setupDiffableDataSource(
@ -16,7 +17,7 @@ extension NotificationViewModel {
delegate: NotificationTableViewCellDelegate,
dependency: NeedsDependency
) {
let timestampUpdatePublisher = Timer.publish(every: 30.0, on: .main, in: .common)
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
.autoconnect()
.share()
.eraseToAnyPublisher()
@ -44,7 +45,14 @@ extension NotificationViewModel: NSFetchedResultsControllerDelegate {
guard let diffableDataSource = self.diffableDataSource else { return }
let predicate = fetchedResultsController.fetchRequest.predicate
let predicate: NSPredicate = {
let notificationTypePredicate = MastodonNotification.predicate(
validTypesRaws: Mastodon.Entity.Notification.NotificationType.knownCases.map { $0.rawValue }
)
return fetchedResultsController.fetchRequest.predicate.flatMap {
NSCompoundPredicate(andPredicateWithSubpredicates: [$0, notificationTypePredicate])
} ?? notificationTypePredicate
}()
let parentManagedObjectContext = fetchedResultsController.managedObjectContext
let managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
managedObjectContext.parent = parentManagedObjectContext
@ -73,19 +81,6 @@ extension NotificationViewModel: NSFetchedResultsControllerDelegate {
newSnapshot.appendSections([.main])
let items: [NotificationItem] = notifications.map { notification in
let attribute: Item.StatusAttribute = oldSnapshotAttributeDict[notification.objectID] ?? Item.StatusAttribute()
// let attribute: Item.StatusAttribute = {
// if let attribute = oldSnapshotAttributeDict[notification.objectID] {
// return attribute
// } else if let status = notification.status {
// let attribute = Item.StatusAttribute()
// let isSensitive = status.sensitive || !(status.spoilerText ?? "").isEmpty
// attribute.isRevealing.value = !isSensitive
// return attribute
// } else {
// return Item.StatusAttribute()
// }
// }()
return NotificationItem.notification(objectID: notification.objectID, attribute: attribute)
}
newSnapshot.appendItems(items, toSection: .main)

View File

@ -17,7 +17,7 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
var pollCountdownSubscription: AnyCancellable?
var delegate: NotificationTableViewCellDelegate?
let avatatImageView: UIImageView = {
let avatarImageView: UIImageView = {
let imageView = UIImageView()
imageView.layer.cornerRadius = 4
imageView.layer.cornerCurve = .continuous
@ -86,7 +86,7 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
override func prepareForReuse() {
super.prepareForReuse()
avatatImageView.af.cancelImageRequest()
avatarImageView.af.cancelImageRequest()
statusView.updateContentWarningDisplay(isHidden: true, animated: false)
statusView.pollTableView.dataSource = nil
statusView.playerContainerView.reset()
@ -142,13 +142,13 @@ extension NotificationStatusTableViewCell {
avatarContainer.widthAnchor.constraint(equalToConstant: 47).priority(.required - 1)
])
avatarContainer.addSubview(avatatImageView)
avatatImageView.translatesAutoresizingMaskIntoConstraints = false
avatarContainer.addSubview(avatarImageView)
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
avatatImageView.heightAnchor.constraint(equalToConstant: 35).priority(.required - 1),
avatatImageView.widthAnchor.constraint(equalToConstant: 35).priority(.required - 1),
avatatImageView.topAnchor.constraint(equalTo: avatarContainer.topAnchor),
avatatImageView.leadingAnchor.constraint(equalTo: avatarContainer.leadingAnchor)
avatarImageView.heightAnchor.constraint(equalToConstant: 35).priority(.required - 1),
avatarImageView.widthAnchor.constraint(equalToConstant: 35).priority(.required - 1),
avatarImageView.topAnchor.constraint(equalTo: avatarContainer.topAnchor),
avatarImageView.leadingAnchor.constraint(equalTo: avatarContainer.leadingAnchor)
])
avatarContainer.addSubview(actionImageBackground)

View File

@ -49,6 +49,18 @@ extension Mastodon.Entity.Notification {
case _other(String)
public static var knownCases: [NotificationType] {
return [
.follow,
.followRequest,
.mention,
.reblog,
.favourite,
.poll,
.status
]
}
public init?(rawValue: String) {
switch rawValue {
case "follow": self = .follow