Sync with markers API for notifications

This commit is contained in:
Thomas Ricouard 2023-12-26 16:01:02 +01:00
parent 4de4c7c82a
commit 590299d102
7 changed files with 59 additions and 19 deletions

View file

@ -15,7 +15,7 @@ extension IceCubesApp {
ForEach(availableTabs) { tab in
if tab == selectedTab || sideBarLoadedTabs.contains(tab) {
tab
.makeContentView(popToRootTab: $popToRootTab)
.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab)
.opacity(tab == selectedTab ? 1 : 0)
.transition(.opacity)
.id("\(tab)\(appAccountsManager.currentAccount.id)")
@ -41,7 +41,8 @@ extension IceCubesApp {
}
var notificationsSecondaryColumn: some View {
NotificationsTab(popToRootTab: $popToRootTab, lockedType: nil)
NotificationsTab(selectedTab: .constant(.notifications),
popToRootTab: $popToRootTab, lockedType: nil)
.environment(\.isSecondaryColumn, true)
.frame(maxWidth: .secondaryColumnWidth)
.id(appAccountsManager.currentAccount.id)

View file

@ -20,7 +20,7 @@ extension IceCubesApp {
selectedTab = newTab
})) {
ForEach(availableTabs) { tab in
tab.makeContentView(popToRootTab: $popToRootTab)
tab.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab)
.tabItem {
if userPreferences.showiPhoneTabLabel {
tab.label
@ -34,7 +34,6 @@ extension IceCubesApp {
}
}
.id(appAccountsManager.currentClient.id)
.environment(\.selectedTab, selectedTab)
}
private func badgeFor(tab: Tab) -> Int {

View file

@ -11,7 +11,6 @@ import Timeline
struct NotificationsTab: View {
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
@Environment(\.scenePhase) private var scenePhase
@Environment(\.selectedTab) private var selectedTab: Tab
@Environment(Theme.self) private var theme
@Environment(Client.self) private var client
@ -22,6 +21,8 @@ struct NotificationsTab: View {
@Environment(PushNotificationsService.self) private var pushNotificationsService
@State private var routerPath = RouterPath()
@State private var scrollToTopSignal: Int = 0
@Binding var selectedTab: Tab
@Binding var popToRootTab: Tab
let lockedType: Models.Notification.NotificationType?
@ -72,6 +73,9 @@ struct NotificationsTab: View {
}
}
}
.onChange(of: selectedTab, { _, newValue in
clearNotifications()
})
.onChange(of: pushNotificationsService.handledNotification) { _, newValue in
if let newValue, let type = newValue.notification.supportedType {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {

View file

@ -31,7 +31,7 @@ enum Tab: Int, Identifiable, Hashable {
}
@ViewBuilder
func makeContentView(popToRootTab: Binding<Tab>) -> some View {
func makeContentView(selectedTab: Binding<Tab>, popToRootTab: Binding<Tab>) -> some View {
switch self {
case .timeline:
TimelineTab(popToRootTab: popToRootTab)
@ -42,9 +42,9 @@ enum Tab: Int, Identifiable, Hashable {
case .federated:
TimelineTab(popToRootTab: popToRootTab, timeline: .federated)
case .notifications:
NotificationsTab(popToRootTab: popToRootTab, lockedType: nil)
NotificationsTab(selectedTab: selectedTab, popToRootTab: popToRootTab, lockedType: nil)
case .mentions:
NotificationsTab(popToRootTab: popToRootTab, lockedType: .mention)
NotificationsTab(selectedTab: selectedTab, popToRootTab: popToRootTab, lockedType: .mention)
case .explore:
ExploreTab(popToRootTab: popToRootTab)
case .messages:
@ -113,14 +113,3 @@ enum Tab: Int, Identifiable, Hashable {
}
}
}
private struct SelectedTab: EnvironmentKey {
static let defaultValue: Tab = .timeline
}
extension EnvironmentValues {
var selectedTab: Tab {
get { self[SelectedTab.self] }
set { self[SelectedTab.self] = newValue }
}
}

View file

@ -0,0 +1,12 @@
import Foundation
public struct Marker: Codable, Sendable {
public struct Content: Codable, Sendable {
public let lastReadId: String
public let version: Int
public let updatedAt: ServerDate
}
public let notifications: Content?
public let home: Content?
}

View file

@ -0,0 +1,22 @@
import Foundation
public enum Markers: Endpoint {
case markers
case markNotifications(lastReadId: String)
case markHome(lastReadId: String)
public func path() -> String {
"markers"
}
public func queryItems() -> [URLQueryItem]? {
switch self {
case let .markNotifications(lastReadId):
[URLQueryItem(name: "notifications[last_read_id]", value: lastReadId)]
case let .markHome(lastReadId):
[URLQueryItem(name: "home[last_read_id]", value: lastReadId)]
default:
nil
}
}
}

View file

@ -90,6 +90,7 @@ import SwiftUI
types: queryTypes,
limit: Constants.notificationLimit))
consolidatedNotifications = await notifications.consolidated(selectedType: selectedType)
markAsRead()
nextPageState = notifications.count < Constants.notificationLimit ? .none : .hasNextPage
} else if let firstId = consolidatedNotifications.first?.id {
var newNotifications: [Models.Notification] = await fetchNewPages(minId: firstId, maxPages: 10)
@ -97,6 +98,7 @@ import SwiftUI
newNotifications = newNotifications.filter { notification in
!consolidatedNotifications.contains(where: { $0.id == notification.id })
}
await consolidatedNotifications.insert(
contentsOf: newNotifications.consolidated(selectedType: selectedType),
at: 0
@ -107,6 +109,8 @@ import SwiftUI
await currentAccount.fetchFollowerRequests()
}
markAsRead()
withAnimation {
state = .display(notifications: consolidatedNotifications,
nextPageState: consolidatedNotifications.isEmpty ? .none : nextPageState)
@ -161,6 +165,15 @@ import SwiftUI
state = .error(error: error)
}
}
func markAsRead() {
guard let client, let id = consolidatedNotifications.first?.notifications.first?.id else { return }
Task {
do {
let _: Marker = try await client.post(endpoint: Markers.markNotifications(lastReadId: id))
} catch { }
}
}
func handleEvent(event: any StreamEvent) {
Task {