Add and show filter-banner in "everything"-notifications (if there are any) (IOS-241)
This commit is contained in:
parent
f297cbabc5
commit
4843348034
@ -158,6 +158,7 @@
|
|||||||
D8318A882A4468D300C0FB73 /* NotificationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */; };
|
D8318A882A4468D300C0FB73 /* NotificationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */; };
|
||||||
D8318A8A2A4468DC00C0FB73 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A892A4468DC00C0FB73 /* AboutViewController.swift */; };
|
D8318A8A2A4468DC00C0FB73 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A892A4468DC00C0FB73 /* AboutViewController.swift */; };
|
||||||
D8363B1629469CE200A74079 /* OnboardingNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8363B1529469CE200A74079 /* OnboardingNextView.swift */; };
|
D8363B1629469CE200A74079 /* OnboardingNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8363B1529469CE200A74079 /* OnboardingNextView.swift */; };
|
||||||
|
D83B54F82C2AC2FA00D18A7B /* NotificationFilteringBannerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D83B54F72C2AC2FA00D18A7B /* NotificationFilteringBannerTableViewCell.swift */; };
|
||||||
D84738D42BBD9ABE00ECD52B /* TimelineStatusPill.swift in Sources */ = {isa = PBXBuildFile; fileRef = D84738D32BBD9ABE00ECD52B /* TimelineStatusPill.swift */; };
|
D84738D42BBD9ABE00ECD52B /* TimelineStatusPill.swift in Sources */ = {isa = PBXBuildFile; fileRef = D84738D32BBD9ABE00ECD52B /* TimelineStatusPill.swift */; };
|
||||||
D84FA0932AE6915800987F47 /* MBProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = D84FA0922AE6915800987F47 /* MBProgressHUD */; };
|
D84FA0932AE6915800987F47 /* MBProgressHUD in Frameworks */ = {isa = PBXBuildFile; productRef = D84FA0922AE6915800987F47 /* MBProgressHUD */; };
|
||||||
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */; };
|
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */; };
|
||||||
@ -791,6 +792,7 @@
|
|||||||
D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsViewController.swift; sourceTree = "<group>"; };
|
D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsViewController.swift; sourceTree = "<group>"; };
|
||||||
D8318A892A4468DC00C0FB73 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
|
D8318A892A4468DC00C0FB73 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
|
||||||
D8363B1529469CE200A74079 /* OnboardingNextView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = OnboardingNextView.swift; sourceTree = "<group>"; tabWidth = 4; };
|
D8363B1529469CE200A74079 /* OnboardingNextView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = OnboardingNextView.swift; sourceTree = "<group>"; tabWidth = 4; };
|
||||||
|
D83B54F72C2AC2FA00D18A7B /* NotificationFilteringBannerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationFilteringBannerTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D84738D32BBD9ABE00ECD52B /* TimelineStatusPill.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStatusPill.swift; sourceTree = "<group>"; };
|
D84738D32BBD9ABE00ECD52B /* TimelineStatusPill.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStatusPill.swift; sourceTree = "<group>"; };
|
||||||
D84C099D2B0F9E33009E685E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
D84C099D2B0F9E33009E685E /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||||
D84C099F2B0F9E41009E685E /* Setup.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Setup.md; sourceTree = "<group>"; };
|
D84C099F2B0F9E41009E685E /* Setup.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Setup.md; sourceTree = "<group>"; };
|
||||||
@ -1512,6 +1514,7 @@
|
|||||||
DB63F76E279A7D1100455B82 /* NotificationTableViewCell.swift */,
|
DB63F76E279A7D1100455B82 /* NotificationTableViewCell.swift */,
|
||||||
DB63F774279A997D00455B82 /* NotificationTableViewCell+ViewModel.swift */,
|
DB63F774279A997D00455B82 /* NotificationTableViewCell+ViewModel.swift */,
|
||||||
D8A0729C2BEBA8D7001A4C7C /* AccountWarningNotificationCell.swift */,
|
D8A0729C2BEBA8D7001A4C7C /* AccountWarningNotificationCell.swift */,
|
||||||
|
D83B54F72C2AC2FA00D18A7B /* NotificationFilteringBannerTableViewCell.swift */,
|
||||||
);
|
);
|
||||||
path = Cell;
|
path = Cell;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -3780,6 +3783,7 @@
|
|||||||
2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */,
|
2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */,
|
||||||
DB6B74FC272FF55800C70B6E /* UserSection.swift in Sources */,
|
DB6B74FC272FF55800C70B6E /* UserSection.swift in Sources */,
|
||||||
DB0FCB862796BDA1006C02E2 /* SearchSection.swift in Sources */,
|
DB0FCB862796BDA1006C02E2 /* SearchSection.swift in Sources */,
|
||||||
|
D83B54F82C2AC2FA00D18A7B /* NotificationFilteringBannerTableViewCell.swift in Sources */,
|
||||||
DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */,
|
DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */,
|
||||||
D84738D42BBD9ABE00ECD52B /* TimelineStatusPill.swift in Sources */,
|
D84738D42BBD9ABE00ECD52B /* TimelineStatusPill.swift in Sources */,
|
||||||
D8B5E4F42A4ED0240008970C /* NotificationSettingsViewModel.swift in Sources */,
|
D8B5E4F42A4ED0240008970C /* NotificationSettingsViewModel.swift in Sources */,
|
||||||
|
@ -17,32 +17,30 @@ extension DataSourceFacade {
|
|||||||
item: DataSourceItem
|
item: DataSourceItem
|
||||||
) async {
|
) async {
|
||||||
switch item {
|
switch item {
|
||||||
case .account(account: let account, relationship: _):
|
case .account(account: let account, relationship: _):
|
||||||
let now = Date()
|
let now = Date()
|
||||||
let userID = provider.authContext.mastodonAuthenticationBox.userID
|
let userID = provider.authContext.mastodonAuthenticationBox.userID
|
||||||
let searchEntry = Persistence.SearchHistory.Item(
|
let searchEntry = Persistence.SearchHistory.Item(
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
userID: userID,
|
userID: userID,
|
||||||
account: account,
|
account: account,
|
||||||
hashtag: nil
|
hashtag: nil
|
||||||
)
|
)
|
||||||
|
|
||||||
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
|
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
|
||||||
case .hashtag(let tag):
|
case .hashtag(let tag):
|
||||||
|
|
||||||
let now = Date()
|
let now = Date()
|
||||||
let userID = provider.authContext.mastodonAuthenticationBox.userID
|
let userID = provider.authContext.mastodonAuthenticationBox.userID
|
||||||
let searchEntry = Persistence.SearchHistory.Item(
|
let searchEntry = Persistence.SearchHistory.Item(
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
userID: userID,
|
userID: userID,
|
||||||
account: nil,
|
account: nil,
|
||||||
hashtag: tag
|
hashtag: tag
|
||||||
)
|
)
|
||||||
|
|
||||||
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
|
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
|
||||||
case .status:
|
case .status, .notification, .notificationBanner(_):
|
||||||
break
|
|
||||||
case .notification:
|
|
||||||
break
|
break
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -514,10 +514,8 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Aut
|
|||||||
)
|
)
|
||||||
case .account(let account, _):
|
case .account(let account, _):
|
||||||
await DataSourceFacade.coordinateToProfileScene(provider: self, account: account)
|
await DataSourceFacade.coordinateToProfileScene(provider: self, account: account)
|
||||||
case .notification:
|
case .notification, .hashtag(_), .notificationBanner(_):
|
||||||
assertionFailure("TODO")
|
print("TODO")
|
||||||
case .hashtag(_):
|
|
||||||
assertionFailure("TODO")
|
|
||||||
}
|
}
|
||||||
} // end Task
|
} // end Task
|
||||||
}
|
}
|
||||||
|
@ -618,9 +618,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte
|
|||||||
provider: self,
|
provider: self,
|
||||||
account: account
|
account: account
|
||||||
)
|
)
|
||||||
case .notification:
|
case .notification, .hashtag(_), .notificationBanner(_):
|
||||||
assertionFailure("TODO")
|
|
||||||
case .hashtag(_):
|
|
||||||
assertionFailure("TODO")
|
assertionFailure("TODO")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,42 +22,45 @@ extension UITableViewDelegate where Self: DataSourceProvider & AuthContextProvid
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch item {
|
switch item {
|
||||||
case .account(let account, relationship: _):
|
case .account(let account, relationship: _):
|
||||||
await DataSourceFacade.coordinateToProfileScene(provider: self, account: account)
|
await DataSourceFacade.coordinateToProfileScene(provider: self, account: account)
|
||||||
case .status(let status):
|
case .status(let status):
|
||||||
|
await DataSourceFacade.coordinateToStatusThreadScene(
|
||||||
|
provider: self,
|
||||||
|
target: .status, // remove reblog wrapper
|
||||||
|
status: status
|
||||||
|
)
|
||||||
|
case .hashtag(let tag):
|
||||||
|
await DataSourceFacade.coordinateToHashtagScene(
|
||||||
|
provider: self,
|
||||||
|
tag: tag
|
||||||
|
)
|
||||||
|
case .notification(let notification):
|
||||||
|
let _status: MastodonStatus? = notification.status
|
||||||
|
if let status = _status {
|
||||||
await DataSourceFacade.coordinateToStatusThreadScene(
|
await DataSourceFacade.coordinateToStatusThreadScene(
|
||||||
provider: self,
|
provider: self,
|
||||||
target: .status, // remove reblog wrapper
|
target: .status, // remove reblog wrapper
|
||||||
status: status
|
status: status
|
||||||
)
|
)
|
||||||
case .hashtag(let tag):
|
} else if let accountWarning = notification.entity.accountWarning {
|
||||||
await DataSourceFacade.coordinateToHashtagScene(
|
let url = Mastodon.API.disputesEndpoint(domain: authContext.mastodonAuthenticationBox.domain, strikeId: accountWarning.id)
|
||||||
provider: self,
|
_ = coordinator.present(
|
||||||
tag: tag
|
scene: .safari(url: url),
|
||||||
|
from: self,
|
||||||
|
transition: .safariPresent(animated: true, completion: nil)
|
||||||
)
|
)
|
||||||
case .notification(let notification):
|
|
||||||
let _status: MastodonStatus? = notification.status
|
|
||||||
if let status = _status {
|
|
||||||
await DataSourceFacade.coordinateToStatusThreadScene(
|
|
||||||
provider: self,
|
|
||||||
target: .status, // remove reblog wrapper
|
|
||||||
status: status
|
|
||||||
)
|
|
||||||
} else if let accountWarning = notification.entity.accountWarning {
|
|
||||||
let url = Mastodon.API.disputesEndpoint(domain: authContext.mastodonAuthenticationBox.domain, strikeId: accountWarning.id)
|
|
||||||
_ = coordinator.present(
|
|
||||||
scene: .safari(url: url),
|
|
||||||
from: self,
|
|
||||||
transition: .safariPresent(animated: true, completion: nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
await DataSourceFacade.coordinateToProfileScene(
|
await DataSourceFacade.coordinateToProfileScene(
|
||||||
provider: self,
|
provider: self,
|
||||||
account: notification.entity.account
|
account: notification.entity.account
|
||||||
)
|
)
|
||||||
} // end Task
|
}
|
||||||
} // end func
|
case .notificationBanner(let policy):
|
||||||
|
//TODO: Coordinate to pending notification-screen
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ enum DataSourceItem: Hashable {
|
|||||||
case status(record: MastodonStatus)
|
case status(record: MastodonStatus)
|
||||||
case hashtag(tag: Mastodon.Entity.Tag)
|
case hashtag(tag: Mastodon.Entity.Tag)
|
||||||
case notification(record: MastodonNotification)
|
case notification(record: MastodonNotification)
|
||||||
|
case notificationBanner(policy: Mastodon.Entity.NotificationPolicy)
|
||||||
case account(account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?)
|
case account(account: Mastodon.Entity.Account, relationship: Mastodon.Entity.Relationship?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
|
class NotificationFilteringBannerTableViewCell: UITableViewCell {
|
||||||
|
static let reuseIdentifier = "NotificationFilteringBannerTableViewCell"
|
||||||
|
|
||||||
|
//TODO: Add separator
|
||||||
|
|
||||||
|
func configure(with policy: Mastodon.Entity.NotificationPolicy) {
|
||||||
|
var configuration = defaultContentConfiguration()
|
||||||
|
|
||||||
|
//TODO: Add localization
|
||||||
|
configuration.text = "Filtered notifications"
|
||||||
|
configuration.secondaryText = "\(policy.summary.pendingRequestsCount) people you may know"
|
||||||
|
configuration.image = UIImage(systemName: "archivebox")
|
||||||
|
|
||||||
|
self.contentConfiguration = configuration
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ import Foundation
|
|||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
|
||||||
enum NotificationItem: Hashable {
|
enum NotificationItem: Hashable {
|
||||||
|
case filteredNotifications(policy: Mastodon.Entity.NotificationPolicy)
|
||||||
case feed(record: MastodonFeed)
|
case feed(record: MastodonFeed)
|
||||||
case feedLoader(record: MastodonFeed)
|
case feedLoader(record: MastodonFeed)
|
||||||
case bottomLoader
|
case bottomLoader
|
||||||
|
@ -39,6 +39,7 @@ extension NotificationSection {
|
|||||||
tableView.register(NotificationTableViewCell.self, forCellReuseIdentifier: String(describing: NotificationTableViewCell.self))
|
tableView.register(NotificationTableViewCell.self, forCellReuseIdentifier: String(describing: NotificationTableViewCell.self))
|
||||||
tableView.register(AccountWarningNotificationCell.self, forCellReuseIdentifier: AccountWarningNotificationCell.reuseIdentifier)
|
tableView.register(AccountWarningNotificationCell.self, forCellReuseIdentifier: AccountWarningNotificationCell.reuseIdentifier)
|
||||||
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
|
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
|
||||||
|
tableView.register(NotificationFilteringBannerTableViewCell.self, forCellReuseIdentifier: NotificationFilteringBannerTableViewCell.reuseIdentifier)
|
||||||
|
|
||||||
return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item -> UITableViewCell? in
|
return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item -> UITableViewCell? in
|
||||||
switch item {
|
switch item {
|
||||||
@ -67,6 +68,12 @@ extension NotificationSection {
|
|||||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell
|
||||||
cell.activityIndicatorView.startAnimating()
|
cell.activityIndicatorView.startAnimating()
|
||||||
return cell
|
return cell
|
||||||
|
|
||||||
|
case .filteredNotifications(let policy):
|
||||||
|
let cell = tableView.dequeueReusableCell(withIdentifier: NotificationFilteringBannerTableViewCell.reuseIdentifier, for: indexPath) as! NotificationFilteringBannerTableViewCell
|
||||||
|
cell.configure(with: policy)
|
||||||
|
|
||||||
|
return cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,9 @@ extension NotificationTimelineViewController: DataSourceProvider {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return item
|
return item
|
||||||
default:
|
case .filteredNotifications(let policy):
|
||||||
|
return DataSourceItem.notificationBanner(policy: policy)
|
||||||
|
case .bottomLoader, .feedLoader(_):
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,16 +13,16 @@ import MastodonLocalization
|
|||||||
|
|
||||||
final class NotificationTimelineViewController: UIViewController, NeedsDependency, MediaPreviewableViewController {
|
final class NotificationTimelineViewController: UIViewController, NeedsDependency, MediaPreviewableViewController {
|
||||||
|
|
||||||
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
weak var context: AppContext!
|
||||||
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
weak var coordinator: SceneCoordinator!
|
||||||
|
|
||||||
let mediaPreviewTransitionController = MediaPreviewTransitionController()
|
let mediaPreviewTransitionController = MediaPreviewTransitionController()
|
||||||
|
|
||||||
var disposeBag = Set<AnyCancellable>()
|
var disposeBag = Set<AnyCancellable>()
|
||||||
var observations = Set<NSKeyValueObservation>()
|
var observations = Set<NSKeyValueObservation>()
|
||||||
|
|
||||||
var viewModel: NotificationTimelineViewModel!
|
let viewModel: NotificationTimelineViewModel
|
||||||
|
|
||||||
private(set) lazy var refreshControl: RefreshControl = {
|
private(set) lazy var refreshControl: RefreshControl = {
|
||||||
let refreshControl = RefreshControl()
|
let refreshControl = RefreshControl()
|
||||||
refreshControl.addTarget(self, action: #selector(NotificationTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged)
|
refreshControl.addTarget(self, action: #selector(NotificationTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged)
|
||||||
@ -38,6 +38,16 @@ final class NotificationTimelineViewController: UIViewController, NeedsDependenc
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
let cellFrameCache = NSCache<NSNumber, NSValue>()
|
let cellFrameCache = NSCache<NSNumber, NSValue>()
|
||||||
|
|
||||||
|
init(viewModel: NotificationTimelineViewModel, context: AppContext, coordinator: SceneCoordinator) {
|
||||||
|
self.viewModel = viewModel
|
||||||
|
self.context = context
|
||||||
|
self.coordinator = coordinator
|
||||||
|
|
||||||
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationTimelineViewController {
|
extension NotificationTimelineViewController {
|
||||||
|
@ -33,7 +33,7 @@ extension NotificationTimelineViewModel {
|
|||||||
dataController.$records
|
dataController.$records
|
||||||
.receive(on: DispatchQueue.main)
|
.receive(on: DispatchQueue.main)
|
||||||
.sink { [weak self] records in
|
.sink { [weak self] records in
|
||||||
guard let self = self else { return }
|
guard let self else { return }
|
||||||
guard let diffableDataSource = self.diffableDataSource else { return }
|
guard let diffableDataSource = self.diffableDataSource else { return }
|
||||||
|
|
||||||
Task {
|
Task {
|
||||||
@ -44,6 +44,9 @@ extension NotificationTimelineViewModel {
|
|||||||
}
|
}
|
||||||
var snapshot = NSDiffableDataSourceSnapshot<NotificationSection, NotificationItem>()
|
var snapshot = NSDiffableDataSourceSnapshot<NotificationSection, NotificationItem>()
|
||||||
snapshot.appendSections([.main])
|
snapshot.appendSections([.main])
|
||||||
|
if self.scope == .everything, let notificationPolicy = self.notificationPolicy, notificationPolicy.summary.pendingRequestsCount > 0 {
|
||||||
|
snapshot.appendItems([.filteredNotifications(policy: notificationPolicy)])
|
||||||
|
}
|
||||||
snapshot.appendItems(newItems.removingDuplicates(), toSection: .main)
|
snapshot.appendItems(newItems.removingDuplicates(), toSection: .main)
|
||||||
return snapshot
|
return snapshot
|
||||||
}()
|
}()
|
||||||
|
@ -20,6 +20,7 @@ final class NotificationTimelineViewModel {
|
|||||||
let context: AppContext
|
let context: AppContext
|
||||||
let authContext: AuthContext
|
let authContext: AuthContext
|
||||||
let scope: Scope
|
let scope: Scope
|
||||||
|
let notificationPolicy: Mastodon.Entity.NotificationPolicy?
|
||||||
let dataController: FeedDataController
|
let dataController: FeedDataController
|
||||||
@Published var isLoadingLatest = false
|
@Published var isLoadingLatest = false
|
||||||
@Published var lastAutomaticFetchTimestamp: Date?
|
@Published var lastAutomaticFetchTimestamp: Date?
|
||||||
@ -46,12 +47,14 @@ final class NotificationTimelineViewModel {
|
|||||||
init(
|
init(
|
||||||
context: AppContext,
|
context: AppContext,
|
||||||
authContext: AuthContext,
|
authContext: AuthContext,
|
||||||
scope: Scope
|
scope: Scope,
|
||||||
|
notificationPolicy: Mastodon.Entity.NotificationPolicy?
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.authContext = authContext
|
self.authContext = authContext
|
||||||
self.scope = scope
|
self.scope = scope
|
||||||
self.dataController = FeedDataController(context: context, authContext: authContext)
|
self.dataController = FeedDataController(context: context, authContext: authContext)
|
||||||
|
self.notificationPolicy = notificationPolicy
|
||||||
|
|
||||||
switch scope {
|
switch scope {
|
||||||
case .everything:
|
case .everything:
|
||||||
|
@ -146,17 +146,20 @@ extension NotificationViewController {
|
|||||||
pageSegmentedControl.selectedSegmentIndex = 0
|
pageSegmentedControl.selectedSegmentIndex = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func createViewController(for scope: NotificationTimelineViewModel.Scope) -> UIViewController {
|
private func createViewController(for scope: NotificationTimelineViewModel.Scope) -> UIViewController {
|
||||||
guard let authContext = viewModel?.authContext else { return UITableViewController() }
|
guard let viewModel else { return UITableViewController() }
|
||||||
let viewController = NotificationTimelineViewController()
|
|
||||||
viewController.context = context
|
let viewController = NotificationTimelineViewController(
|
||||||
viewController.coordinator = coordinator
|
viewModel: NotificationTimelineViewModel(
|
||||||
viewController.viewModel = NotificationTimelineViewModel(
|
context: context,
|
||||||
|
authContext: viewModel.authContext,
|
||||||
|
scope: scope, notificationPolicy: viewModel.notificationPolicy
|
||||||
|
),
|
||||||
context: context,
|
context: context,
|
||||||
authContext: authContext,
|
coordinator: coordinator
|
||||||
scope: scope
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return viewController
|
return viewController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ extension SearchResultViewController {
|
|||||||
provider: self,
|
provider: self,
|
||||||
tag: tag
|
tag: tag
|
||||||
)
|
)
|
||||||
case .notification:
|
case .notification, .notificationBanner(_):
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
} // end switch
|
} // end switch
|
||||||
|
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension Mastodon.Entity {
|
extension Mastodon.Entity {
|
||||||
public struct NotificationPolicy: Codable {
|
public struct NotificationPolicy: Codable, Hashable {
|
||||||
let filterNotFollowing: Bool
|
public let filterNotFollowing: Bool
|
||||||
let filterNotFollowers: Bool
|
public let filterNotFollowers: Bool
|
||||||
let filterNewAccounts: Bool
|
public let filterNewAccounts: Bool
|
||||||
let filterPrivateMentions: Bool
|
public let filterPrivateMentions: Bool
|
||||||
let summary: Summary
|
public let summary: Summary
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case filterNotFollowing = "filter_not_following"
|
case filterNotFollowing = "filter_not_following"
|
||||||
@ -18,9 +18,9 @@ extension Mastodon.Entity {
|
|||||||
case summary
|
case summary
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Summary: Codable {
|
public struct Summary: Codable, Hashable {
|
||||||
let pendingRequestsCount: Int
|
public let pendingRequestsCount: Int
|
||||||
let pendingNotificationsCount: Int
|
public let pendingNotificationsCount: Int
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case pendingRequestsCount = "pending_requests_count"
|
case pendingRequestsCount = "pending_requests_count"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user