diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
index 6ec23cf5d..18c8840d8 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,7 +7,7 @@
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 10
+ 13
Mastodon - RTL.xcscheme_^#shared#^_
diff --git a/Mastodon/Diffiable/Item/NotificationItem.swift b/Mastodon/Diffiable/Item/NotificationItem.swift
index ba0d0c140..f26d2e43d 100644
--- a/Mastodon/Diffiable/Item/NotificationItem.swift
+++ b/Mastodon/Diffiable/Item/NotificationItem.swift
@@ -9,7 +9,7 @@ import CoreData
import Foundation
enum NotificationItem {
- case notification(objectID: NSManagedObjectID)
+ case notification(objectID: NSManagedObjectID, attribute: Item.StatusAttribute)
case bottomLoader
}
@@ -17,7 +17,7 @@ enum NotificationItem {
extension NotificationItem: Equatable {
static func == (lhs: NotificationItem, rhs: NotificationItem) -> Bool {
switch (lhs, rhs) {
- case (.notification(let idLeft), .notification(let idRight)):
+ case (.notification(let idLeft, _), .notification(let idRight, _)):
return idLeft == idRight
case (.bottomLoader, .bottomLoader):
return true
@@ -30,7 +30,7 @@ extension NotificationItem: Equatable {
extension NotificationItem: Hashable {
func hash(into hasher: inout Hasher) {
switch self {
- case .notification(let id):
+ case .notification(let id, _):
hasher.combine(id)
case .bottomLoader:
hasher.combine(String(describing: NotificationItem.bottomLoader.self))
diff --git a/Mastodon/Diffiable/Section/NotificationSection.swift b/Mastodon/Diffiable/Section/NotificationSection.swift
index 5ccab431c..9c59350b4 100644
--- a/Mastodon/Diffiable/Section/NotificationSection.swift
+++ b/Mastodon/Diffiable/Section/NotificationSection.swift
@@ -22,15 +22,14 @@ extension NotificationSection {
timestampUpdatePublisher: AnyPublisher,
managedObjectContext: NSManagedObjectContext,
delegate: NotificationTableViewCellDelegate,
- dependency: NeedsDependency,
- requestUserID: String
+ dependency: NeedsDependency
) -> UITableViewDiffableDataSource {
UITableViewDiffableDataSource(tableView: tableView) {
[weak delegate, weak dependency]
(tableView, indexPath, notificationItem) -> UITableViewCell? in
guard let dependency = dependency else { return nil }
switch notificationItem {
- case .notification(let objectID):
+ 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 {
@@ -46,14 +45,18 @@ extension NotificationSection {
if let status = notification.status {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: NotificationStatusTableViewCell.self), for: indexPath) as! NotificationStatusTableViewCell
cell.delegate = delegate
+ let activeMastodonAuthenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value
+ let requestUserID = activeMastodonAuthenticationBox?.userID ?? ""
let frame = CGRect(x: 0, y: 0, width: tableView.readableContentGuide.layoutFrame.width - NotificationStatusTableViewCell.statusPadding.left - NotificationStatusTableViewCell.statusPadding.right, height: tableView.readableContentGuide.layoutFrame.height)
- StatusSection.configure(cell: cell,
- dependency: dependency,
- readableLayoutFrame: frame,
- timestampUpdatePublisher: timestampUpdatePublisher,
- status: status,
- requestUserID: requestUserID,
- statusItemAttribute: Item.StatusAttribute(isStatusTextSensitive: false, isStatusSensitive: false))
+ StatusSection.configure(
+ cell: cell,
+ dependency: dependency,
+ readableLayoutFrame: frame,
+ timestampUpdatePublisher: timestampUpdatePublisher,
+ status: status,
+ requestUserID: requestUserID,
+ statusItemAttribute: attribute
+ )
timestampUpdatePublisher
.sink { _ in
let timeText = notification.createAt.shortTimeAgoSinceNow
diff --git a/Mastodon/Scene/Notification/NotificationViewController.swift b/Mastodon/Scene/Notification/NotificationViewController.swift
index ad9a7472e..57b5dc639 100644
--- a/Mastodon/Scene/Notification/NotificationViewController.swift
+++ b/Mastodon/Scene/Notification/NotificationViewController.swift
@@ -36,6 +36,7 @@ final class NotificationViewController: UIViewController, NeedsDependency {
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
tableView.tableFooterView = UIView()
tableView.estimatedRowHeight = UITableView.automaticDimension
+ tableView.backgroundColor = .clear
return tableView
}()
@@ -45,13 +46,14 @@ final class NotificationViewController: UIViewController, NeedsDependency {
extension NotificationViewController {
override func viewDidLoad() {
super.viewDidLoad()
+
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
navigationItem.titleView = segmentControl
segmentControl.addTarget(self, action: #selector(NotificationViewController.segmentedControlValueChanged(_:)), for: .valueChanged)
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
- tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
+ tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
@@ -65,6 +67,7 @@ extension NotificationViewController {
viewModel.contentOffsetAdjustableTimelineViewControllerDelegate = self
viewModel.setupDiffableDataSource(for: tableView, delegate: self, dependency: self)
viewModel.viewDidLoad.send()
+
// bind refresh control
viewModel.isFetchingLatestNotification
.receive(on: DispatchQueue.main)
@@ -83,6 +86,8 @@ extension NotificationViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
+ tableView.deselectRow(with: transitionCoordinator, animated: animated)
+
// needs trigger manually after onboarding dismiss
setNeedsStatusBarAppearanceUpdate()
}
@@ -159,11 +164,10 @@ extension NotificationViewController {
extension NotificationViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- tableView.deselectRow(at: indexPath, animated: true)
guard let diffableDataSource = viewModel.diffableDataSource else { return }
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
switch item {
- case .notification(let objectID):
+ case .notification(let objectID, _):
let notification = context.managedObjectContext.object(with: objectID) as! MastodonNotification
if let status = notification.status {
let viewModel = ThreadViewModel(context: context, optionalStatus: status)
@@ -199,6 +203,7 @@ extension NotificationViewController: ContentOffsetAdjustableTimelineViewControl
}
}
+// MARK: - NotificationTableViewCellDelegate
extension NotificationViewController: NotificationTableViewCellDelegate {
func userAvatarDidPressed(notification: MastodonNotification) {
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
@@ -210,6 +215,18 @@ extension NotificationViewController: NotificationTableViewCellDelegate {
func parent() -> UIViewController {
self
}
+
+ func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton) {
+ StatusProviderFacade.responseToStatusContentWarningRevealAction(dependency: self, cell: cell)
+ }
+
+ func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView) {
+ StatusProviderFacade.responseToStatusContentWarningRevealAction(dependency: self, cell: cell)
+ }
+
+ func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView) {
+ StatusProviderFacade.responseToStatusContentWarningRevealAction(dependency: self, cell: cell)
+ }
}
// MARK: - UIScrollViewDelegate
diff --git a/Mastodon/Scene/Notification/NotificationViewModel+diffable.swift b/Mastodon/Scene/Notification/NotificationViewModel+diffable.swift
index 5bd2d92dd..cd28c5f5a 100644
--- a/Mastodon/Scene/Notification/NotificationViewModel+diffable.swift
+++ b/Mastodon/Scene/Notification/NotificationViewModel+diffable.swift
@@ -20,16 +20,13 @@ extension NotificationViewModel {
.autoconnect()
.share()
.eraseToAnyPublisher()
- guard let userid = activeMastodonAuthenticationBox.value?.userID else {
- return
- }
+
diffableDataSource = NotificationSection.tableViewDiffableDataSource(
for: tableView,
timestampUpdatePublisher: timestampUpdatePublisher,
managedObjectContext: context.managedObjectContext,
delegate: delegate,
- dependency: dependency,
- requestUserID: userid
+ dependency: dependency
)
}
}
@@ -67,9 +64,31 @@ extension NotificationViewModel: NSFetchedResultsControllerDelegate {
DispatchQueue.main.async {
let oldSnapshot = diffableDataSource.snapshot()
+ var oldSnapshotAttributeDict: [NSManagedObjectID : Item.StatusAttribute] = [:]
+ for item in oldSnapshot.itemIdentifiers {
+ guard case let .notification(objectID, attribute) = item else { continue }
+ oldSnapshotAttributeDict[objectID] = attribute
+ }
var newSnapshot = NSDiffableDataSourceSnapshot()
newSnapshot.appendSections([.main])
- newSnapshot.appendItems(notifications.map { NotificationItem.notification(objectID: $0.objectID) }, toSection: .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)
if !notifications.isEmpty, self.noMoreNotification.value == false {
newSnapshot.appendItems([.bottomLoader], toSection: .main)
}
diff --git a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
index 871adcaeb..7b76dd2f0 100644
--- a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
+++ b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
@@ -8,6 +8,7 @@
import Combine
import Foundation
import UIKit
+import ActiveLabel
final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
static let actionImageBorderWidth: CGFloat = 2
@@ -78,8 +79,7 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
override func prepareForReuse() {
super.prepareForReuse()
avatatImageView.af.cancelImageRequest()
- statusView.isStatusTextSensitive = false
- statusView.cleanUpContentWarning()
+ statusView.updateContentWarningDisplay(isHidden: true, animated: false)
statusView.pollTableView.dataSource = nil
statusView.playerContainerView.reset()
statusView.playerContainerView.isHidden = true
@@ -99,6 +99,9 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
override func layoutSubviews() {
super.layoutSubviews()
+
+ // precondition: app is active
+ guard UIApplication.shared.applicationState == .active else { return }
DispatchQueue.main.async {
self.statusView.drawContentWarningImageView()
}
@@ -107,6 +110,8 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
extension NotificationStatusTableViewCell {
func configure() {
+ backgroundColor = Asset.Colors.Background.systemBackground.color
+
let containerStackView = UIStackView()
containerStackView.axis = .horizontal
containerStackView.alignment = .top
@@ -154,7 +159,6 @@ extension NotificationStatusTableViewCell {
actionImageView.centerYAnchor.constraint(equalTo: actionImageBackground.centerYAnchor)
])
-
let actionStackView = UIStackView()
actionStackView.axis = .horizontal
actionStackView.distribution = .fill
@@ -187,13 +191,12 @@ extension NotificationStatusTableViewCell {
statusBorder.trailingAnchor.constraint(equalTo: statusView.trailingAnchor, constant: 12),
])
+ statusView.delegate = self
statusStackView.addArrangedSubview(statusBorder)
containerStackView.addArrangedSubview(statusStackView)
- statusView.contentWarningBlurContentImageView.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
- statusView.isUserInteractionEnabled = false
// remove item don't display
statusView.actionToolbarContainer.removeFromStackView()
// it affect stackView's height,need remove
@@ -206,4 +209,54 @@ extension NotificationStatusTableViewCell {
statusBorder.layer.borderColor = Asset.Colors.Border.notification.color.cgColor
actionImageBackground.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
}
+
+ override func setHighlighted(_ highlighted: Bool, animated: Bool) {
+ super.setHighlighted(highlighted, animated: animated)
+
+ resetContentOverlayBlurImageBackgroundColor(selected: highlighted)
+ }
+
+ override func setSelected(_ selected: Bool, animated: Bool) {
+ super.setSelected(selected, animated: animated)
+
+ resetContentOverlayBlurImageBackgroundColor(selected: selected)
+ }
+
+ private func resetContentOverlayBlurImageBackgroundColor(selected: Bool) {
+ let imageViewBackgroundColor: UIColor? = selected ? selectedBackgroundView?.backgroundColor : backgroundColor
+ statusView.contentWarningOverlayView.blurContentImageView.backgroundColor = imageViewBackgroundColor
+ }
+}
+
+// MARK: - StatusViewDelegate
+extension NotificationStatusTableViewCell: StatusViewDelegate {
+ func statusView(_ statusView: StatusView, headerInfoLabelDidPressed label: UILabel) {
+ // do nothing
+ }
+
+ func statusView(_ statusView: StatusView, avatarButtonDidPressed button: UIButton) {
+ // do nothing
+ }
+
+ func statusView(_ statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton) {
+ delegate?.notificationStatusTableViewCell(self, statusView: statusView, revealContentWarningButtonDidPressed: button)
+ }
+
+ func statusView(_ statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView) {
+ delegate?.notificationStatusTableViewCell(self, statusView: statusView, contentWarningOverlayViewDidPressed: contentWarningOverlayView)
+ }
+
+ func statusView(_ statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView) {
+ delegate?.notificationStatusTableViewCell(self, statusView: statusView, playerContainerView: playerContainerView, contentWarningOverlayViewDidPressed: contentWarningOverlayView)
+ }
+
+ func statusView(_ statusView: StatusView, pollVoteButtonPressed button: UIButton) {
+ // do nothing
+ }
+
+ func statusView(_ statusView: StatusView, activeLabel: ActiveLabel, didSelectActiveEntity entity: ActiveEntity) {
+ // do nothing
+ }
+
+
}
diff --git a/Mastodon/Scene/Notification/TableViewCell/NotificationTableViewCell.swift b/Mastodon/Scene/Notification/TableViewCell/NotificationTableViewCell.swift
index 60b43ac35..619bffa17 100644
--- a/Mastodon/Scene/Notification/TableViewCell/NotificationTableViewCell.swift
+++ b/Mastodon/Scene/Notification/TableViewCell/NotificationTableViewCell.swift
@@ -16,6 +16,11 @@ protocol NotificationTableViewCellDelegate: AnyObject {
func parent() -> UIViewController
func userAvatarDidPressed(notification: MastodonNotification)
+
+ func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
+ func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
+ func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
+
}
final class NotificationTableViewCell: UITableViewCell {