mirror of
https://github.com/metabolist/metatext.git
synced 2024-11-22 08:10:59 +00:00
Notifications marker
This commit is contained in:
parent
6294b1c52f
commit
9274cd2615
4 changed files with 48 additions and 15 deletions
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue