mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
Merge branch 'fix/timer-setter-leaking' into release/0.6.1
This commit is contained in:
commit
c6514dcdbb
@ -102,6 +102,10 @@ extension MastodonNotification {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static func predicate(validTypesRaws types: [String]) -> NSPredicate {
|
||||||
|
return NSPredicate(format: "%K IN %@", #keyPath(MastodonNotification.typeRaw), types)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension MastodonNotification: Managed {
|
extension MastodonNotification: Managed {
|
||||||
|
@ -30,13 +30,15 @@ extension NotificationSection {
|
|||||||
guard let dependency = dependency else { return nil }
|
guard let dependency = dependency else { return nil }
|
||||||
switch notificationItem {
|
switch notificationItem {
|
||||||
case .notification(let objectID, let attribute):
|
case .notification(let objectID, let attribute):
|
||||||
|
|
||||||
let notification = managedObjectContext.object(with: objectID) as! MastodonNotification
|
let notification = managedObjectContext.object(with: objectID) as! MastodonNotification
|
||||||
guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: notification.typeRaw) else {
|
guard let type = Mastodon.Entity.Notification.NotificationType(rawValue: notification.typeRaw) else {
|
||||||
|
// filter out invalid type using predicate
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
return nil
|
return UITableViewCell()
|
||||||
}
|
}
|
||||||
let timeText = notification.createAt.slowedTimeAgoSinceNow
|
|
||||||
|
let createAt = notification.createAt
|
||||||
|
let timeText = createAt.slowedTimeAgoSinceNow
|
||||||
|
|
||||||
let actionText = type.actionText
|
let actionText = type.actionText
|
||||||
let actionImageName = type.actionImageName
|
let actionImageName = type.actionImageName
|
||||||
@ -57,23 +59,24 @@ extension NotificationSection {
|
|||||||
requestUserID: requestUserID,
|
requestUserID: requestUserID,
|
||||||
statusItemAttribute: attribute
|
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
|
timestampUpdatePublisher
|
||||||
.sink { _ in
|
.sink { [weak cell] _ in
|
||||||
let timeText = notification.createAt.slowedTimeAgoSinceNow
|
guard let cell = cell else { return }
|
||||||
|
let timeText = createAt.slowedTimeAgoSinceNow
|
||||||
cell.actionLabel.text = actionText + " · " + timeText
|
cell.actionLabel.text = actionText + " · " + timeText
|
||||||
}
|
}
|
||||||
.store(in: &cell.disposeBag)
|
.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() {
|
if let url = notification.account.avatarImageURL() {
|
||||||
cell.avatatImageView.af.setImage(
|
cell.avatarImageView.af.setImage(
|
||||||
withURL: url,
|
withURL: url,
|
||||||
placeholderImage: UIImage.placeholder(color: .systemFill),
|
placeholderImage: UIImage.placeholder(color: .systemFill),
|
||||||
imageTransition: .crossDissolve(0.2)
|
imageTransition: .crossDissolve(0.2)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
cell.avatatImageView.gesture().sink { [weak cell] _ in
|
cell.avatarImageView.gesture().sink { [weak cell] _ in
|
||||||
cell?.delegate?.userAvatarDidPressed(notification: notification)
|
cell?.delegate?.userAvatarDidPressed(notification: notification)
|
||||||
}
|
}
|
||||||
.store(in: &cell.disposeBag)
|
.store(in: &cell.disposeBag)
|
||||||
@ -86,8 +89,9 @@ extension NotificationSection {
|
|||||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NotificationTableViewCell.self), for: indexPath) as! NotificationTableViewCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NotificationTableViewCell.self), for: indexPath) as! NotificationTableViewCell
|
||||||
cell.delegate = delegate
|
cell.delegate = delegate
|
||||||
timestampUpdatePublisher
|
timestampUpdatePublisher
|
||||||
.sink { _ in
|
.sink { [weak cell] _ in
|
||||||
let timeText = notification.createAt.slowedTimeAgoSinceNow
|
guard let cell = cell else { return }
|
||||||
|
let timeText = createAt.slowedTimeAgoSinceNow
|
||||||
cell.actionLabel.text = actionText + " · " + timeText
|
cell.actionLabel.text = actionText + " · " + timeText
|
||||||
}
|
}
|
||||||
.store(in: &cell.disposeBag)
|
.store(in: &cell.disposeBag)
|
||||||
|
@ -9,6 +9,7 @@ import CoreData
|
|||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
import os.log
|
import os.log
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
extension NotificationViewModel {
|
extension NotificationViewModel {
|
||||||
func setupDiffableDataSource(
|
func setupDiffableDataSource(
|
||||||
@ -16,7 +17,7 @@ extension NotificationViewModel {
|
|||||||
delegate: NotificationTableViewCellDelegate,
|
delegate: NotificationTableViewCellDelegate,
|
||||||
dependency: NeedsDependency
|
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()
|
.autoconnect()
|
||||||
.share()
|
.share()
|
||||||
.eraseToAnyPublisher()
|
.eraseToAnyPublisher()
|
||||||
@ -44,7 +45,14 @@ extension NotificationViewModel: NSFetchedResultsControllerDelegate {
|
|||||||
|
|
||||||
guard let diffableDataSource = self.diffableDataSource else { return }
|
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 parentManagedObjectContext = fetchedResultsController.managedObjectContext
|
||||||
let managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
let managedObjectContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
|
||||||
managedObjectContext.parent = parentManagedObjectContext
|
managedObjectContext.parent = parentManagedObjectContext
|
||||||
@ -73,19 +81,6 @@ extension NotificationViewModel: NSFetchedResultsControllerDelegate {
|
|||||||
newSnapshot.appendSections([.main])
|
newSnapshot.appendSections([.main])
|
||||||
let items: [NotificationItem] = notifications.map { notification in
|
let items: [NotificationItem] = notifications.map { notification in
|
||||||
let attribute: Item.StatusAttribute = oldSnapshotAttributeDict[notification.objectID] ?? Item.StatusAttribute()
|
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)
|
return NotificationItem.notification(objectID: notification.objectID, attribute: attribute)
|
||||||
}
|
}
|
||||||
newSnapshot.appendItems(items, toSection: .main)
|
newSnapshot.appendItems(items, toSection: .main)
|
||||||
|
@ -17,7 +17,7 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
|
|||||||
var pollCountdownSubscription: AnyCancellable?
|
var pollCountdownSubscription: AnyCancellable?
|
||||||
var delegate: NotificationTableViewCellDelegate?
|
var delegate: NotificationTableViewCellDelegate?
|
||||||
|
|
||||||
let avatatImageView: UIImageView = {
|
let avatarImageView: UIImageView = {
|
||||||
let imageView = UIImageView()
|
let imageView = UIImageView()
|
||||||
imageView.layer.cornerRadius = 4
|
imageView.layer.cornerRadius = 4
|
||||||
imageView.layer.cornerCurve = .continuous
|
imageView.layer.cornerCurve = .continuous
|
||||||
@ -86,7 +86,7 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
|
|||||||
|
|
||||||
override func prepareForReuse() {
|
override func prepareForReuse() {
|
||||||
super.prepareForReuse()
|
super.prepareForReuse()
|
||||||
avatatImageView.af.cancelImageRequest()
|
avatarImageView.af.cancelImageRequest()
|
||||||
statusView.updateContentWarningDisplay(isHidden: true, animated: false)
|
statusView.updateContentWarningDisplay(isHidden: true, animated: false)
|
||||||
statusView.pollTableView.dataSource = nil
|
statusView.pollTableView.dataSource = nil
|
||||||
statusView.playerContainerView.reset()
|
statusView.playerContainerView.reset()
|
||||||
@ -142,13 +142,13 @@ extension NotificationStatusTableViewCell {
|
|||||||
avatarContainer.widthAnchor.constraint(equalToConstant: 47).priority(.required - 1)
|
avatarContainer.widthAnchor.constraint(equalToConstant: 47).priority(.required - 1)
|
||||||
])
|
])
|
||||||
|
|
||||||
avatarContainer.addSubview(avatatImageView)
|
avatarContainer.addSubview(avatarImageView)
|
||||||
avatatImageView.translatesAutoresizingMaskIntoConstraints = false
|
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
avatatImageView.heightAnchor.constraint(equalToConstant: 35).priority(.required - 1),
|
avatarImageView.heightAnchor.constraint(equalToConstant: 35).priority(.required - 1),
|
||||||
avatatImageView.widthAnchor.constraint(equalToConstant: 35).priority(.required - 1),
|
avatarImageView.widthAnchor.constraint(equalToConstant: 35).priority(.required - 1),
|
||||||
avatatImageView.topAnchor.constraint(equalTo: avatarContainer.topAnchor),
|
avatarImageView.topAnchor.constraint(equalTo: avatarContainer.topAnchor),
|
||||||
avatatImageView.leadingAnchor.constraint(equalTo: avatarContainer.leadingAnchor)
|
avatarImageView.leadingAnchor.constraint(equalTo: avatarContainer.leadingAnchor)
|
||||||
])
|
])
|
||||||
|
|
||||||
avatarContainer.addSubview(actionImageBackground)
|
avatarContainer.addSubview(actionImageBackground)
|
||||||
|
@ -49,6 +49,18 @@ extension Mastodon.Entity.Notification {
|
|||||||
|
|
||||||
case _other(String)
|
case _other(String)
|
||||||
|
|
||||||
|
public static var knownCases: [NotificationType] {
|
||||||
|
return [
|
||||||
|
.follow,
|
||||||
|
.followRequest,
|
||||||
|
.mention,
|
||||||
|
.reblog,
|
||||||
|
.favourite,
|
||||||
|
.poll,
|
||||||
|
.status
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
public init?(rawValue: String) {
|
public init?(rawValue: String) {
|
||||||
switch rawValue {
|
switch rawValue {
|
||||||
case "follow": self = .follow
|
case "follow": self = .follow
|
||||||
|
Loading…
x
Reference in New Issue
Block a user