Notifications marker

This commit is contained in:
Justin Mazzocchi 2021-02-19 19:21:55 -08:00
parent 6294b1c52f
commit 9274cd2615
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
4 changed files with 48 additions and 15 deletions

View file

@ -14,6 +14,8 @@ public protocol CollectionService {
var navigationService: NavigationService { get } var navigationService: NavigationService { get }
var positionTimeline: Timeline? { get } var positionTimeline: Timeline? { get }
func request(maxId: String?, minId: String?, search: Search?) -> AnyPublisher<Never, Error> func request(maxId: String?, minId: String?, search: Search?) -> AnyPublisher<Never, Error>
func requestMarkerLastReadId() -> AnyPublisher<CollectionItem.Id, Error>
func setMarkerLastReadId(_ id: CollectionItem.Id) -> AnyPublisher<CollectionItem.Id, Error>
} }
extension CollectionService { extension CollectionService {
@ -30,4 +32,10 @@ extension CollectionService {
public var titleLocalizationComponents: AnyPublisher<[String], Never> { Empty().eraseToAnyPublisher() } public var titleLocalizationComponents: AnyPublisher<[String], Never> { Empty().eraseToAnyPublisher() }
public var positionTimeline: Timeline? { nil } public var positionTimeline: Timeline? { nil }
public func requestMarkerLastReadId() -> AnyPublisher<CollectionItem.Id, Error> { Empty().eraseToAnyPublisher() }
public func setMarkerLastReadId(_ id: CollectionItem.Id) -> AnyPublisher<CollectionItem.Id, Error> {
Empty().eraseToAnyPublisher()
}
} }

View file

@ -119,12 +119,6 @@ public extension IdentityService {
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }
func getMarker(_ markerTimeline: Marker.Timeline) -> AnyPublisher<Marker, Error> {
mastodonAPIClient.request(MarkersEndpoint.get([markerTimeline]))
.compactMap { $0[markerTimeline.rawValue] }
.eraseToAnyPublisher()
}
func getLocalLastReadId(timeline: Timeline) -> String? { func getLocalLastReadId(timeline: Timeline) -> String? {
contentDatabase.lastReadId(timelineId: timeline.id) contentDatabase.lastReadId(timelineId: timeline.id)
} }

View file

@ -55,4 +55,16 @@ extension NotificationsService: CollectionService {
.flatMap { contentDatabase.insert(notifications: $0.result) } .flatMap { contentDatabase.insert(notifications: $0.result) }
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }
public func requestMarkerLastReadId() -> AnyPublisher<CollectionItem.Id, Error> {
mastodonAPIClient.request(MarkersEndpoint.get([.notifications]))
.compactMap { $0.values.first?.lastReadId }
.eraseToAnyPublisher()
}
public func setMarkerLastReadId(_ id: CollectionItem.Id) -> AnyPublisher<CollectionItem.Id, Error> {
mastodonAPIClient.request(MarkersEndpoint.post([.notifications: id]))
.compactMap { $0.values.first?.lastReadId }
.eraseToAnyPublisher()
}
} }

View file

@ -21,10 +21,11 @@ public class CollectionItemsViewModel: ObservableObject {
private var topVisibleIndexPath = IndexPath(item: 0, section: 0) private var topVisibleIndexPath = IndexPath(item: 0, section: 0)
private let lastReadId = CurrentValueSubject<String?, Never>(nil) private let lastReadId = CurrentValueSubject<String?, Never>(nil)
private var lastSelectedLoadMore: LoadMore? private var lastSelectedLoadMore: LoadMore?
private var hasRequestedUsingMarker = false private var localLastReadId: CollectionItem.Id?
private var markerScrollPositionItemId: CollectionItem.Id? private var markerLastReadId: CollectionItem.Id?
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
// swiftlint:disable:next function_body_length
public init(collectionService: CollectionService, identityContext: IdentityContext) { public init(collectionService: CollectionService, identityContext: IdentityContext) {
self.collectionService = collectionService self.collectionService = collectionService
self.identityContext = identityContext self.identityContext = identityContext
@ -50,18 +51,32 @@ public class CollectionItemsViewModel: ObservableObject {
.sink { _ in } .sink { _ in }
.store(in: &cancellables) .store(in: &cancellables)
let debouncedLastReadId = lastReadId
.compactMap { $0 }
.removeDuplicates()
.debounce(for: .seconds(Self.lastReadIdDebounceInterval), scheduler: DispatchQueue.global())
.share()
debouncedLastReadId
.filter { [weak self] in
guard let markerLastReadId = self?.markerLastReadId else { return false }
return $0 > markerLastReadId
}
.flatMap { collectionService.setMarkerLastReadId($0) }
.receive(on: DispatchQueue.main)
.sink { _ in } receiveValue: { [weak self] in self?.markerLastReadId = $0 }
.store(in: &cancellables)
if let timeline = collectionService.positionTimeline { if let timeline = collectionService.positionTimeline {
if identityContext.appPreferences.positionBehavior(timeline: timeline) == .localRememberPosition { if identityContext.appPreferences.positionBehavior(timeline: timeline) == .localRememberPosition {
markerScrollPositionItemId = identityContext.service.getLocalLastReadId(timeline: timeline) localLastReadId = identityContext.service.getLocalLastReadId(timeline: timeline)
} }
lastReadId debouncedLastReadId
.filter { _ in .filter { _ in
identityContext.appPreferences.positionBehavior(timeline: timeline) == .localRememberPosition identityContext.appPreferences.positionBehavior(timeline: timeline) == .localRememberPosition
} }
.compactMap { $0 }
.removeDuplicates()
.debounce(for: .seconds(Self.lastReadIdDebounceInterval), scheduler: DispatchQueue.global())
.flatMap { identityContext.service.setLocalLastReadId($0, timeline: timeline) } .flatMap { identityContext.service.setLocalLastReadId($0, timeline: timeline) }
.sink { _ in } receiveValue: { _ in } .sink { _ in } receiveValue: { _ in }
.store(in: &cancellables) .store(in: &cancellables)
@ -119,6 +134,10 @@ extension CollectionItemsViewModel: CollectionViewModel {
receiveCompletion: { [weak self] _ in self?.loadingSubject.send(false) }) receiveCompletion: { [weak self] _ in self?.loadingSubject.send(false) })
.sink { _ in } .sink { _ in }
.store(in: &cancellables) .store(in: &cancellables)
collectionService.requestMarkerLastReadId()
.sink { _ in } receiveValue: { [weak self] in self?.markerLastReadId = $0 }
.store(in: &cancellables)
} }
public func select(indexPath: IndexPath) { public func select(indexPath: IndexPath) {
@ -375,9 +394,9 @@ private extension CollectionItemsViewModel {
let items = lastUpdate.sections.map(\.items).reduce([], +) let items = lastUpdate.sections.map(\.items).reduce([], +)
let newItems = newSections.map(\.items).reduce([], +) let newItems = newSections.map(\.items).reduce([], +)
if let itemId = markerScrollPositionItemId, if let itemId = localLastReadId,
newItems.contains(where: { $0.itemId == itemId }) { newItems.contains(where: { $0.itemId == itemId }) {
markerScrollPositionItemId = nil localLastReadId = nil
return itemId return itemId
} }