mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-25 09:41:02 +00:00
Sync with markers API for notifications
This commit is contained in:
parent
4de4c7c82a
commit
590299d102
7 changed files with 59 additions and 19 deletions
|
@ -15,7 +15,7 @@ extension IceCubesApp {
|
||||||
ForEach(availableTabs) { tab in
|
ForEach(availableTabs) { tab in
|
||||||
if tab == selectedTab || sideBarLoadedTabs.contains(tab) {
|
if tab == selectedTab || sideBarLoadedTabs.contains(tab) {
|
||||||
tab
|
tab
|
||||||
.makeContentView(popToRootTab: $popToRootTab)
|
.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab)
|
||||||
.opacity(tab == selectedTab ? 1 : 0)
|
.opacity(tab == selectedTab ? 1 : 0)
|
||||||
.transition(.opacity)
|
.transition(.opacity)
|
||||||
.id("\(tab)\(appAccountsManager.currentAccount.id)")
|
.id("\(tab)\(appAccountsManager.currentAccount.id)")
|
||||||
|
@ -41,7 +41,8 @@ extension IceCubesApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
var notificationsSecondaryColumn: some View {
|
var notificationsSecondaryColumn: some View {
|
||||||
NotificationsTab(popToRootTab: $popToRootTab, lockedType: nil)
|
NotificationsTab(selectedTab: .constant(.notifications),
|
||||||
|
popToRootTab: $popToRootTab, lockedType: nil)
|
||||||
.environment(\.isSecondaryColumn, true)
|
.environment(\.isSecondaryColumn, true)
|
||||||
.frame(maxWidth: .secondaryColumnWidth)
|
.frame(maxWidth: .secondaryColumnWidth)
|
||||||
.id(appAccountsManager.currentAccount.id)
|
.id(appAccountsManager.currentAccount.id)
|
||||||
|
|
|
@ -20,7 +20,7 @@ extension IceCubesApp {
|
||||||
selectedTab = newTab
|
selectedTab = newTab
|
||||||
})) {
|
})) {
|
||||||
ForEach(availableTabs) { tab in
|
ForEach(availableTabs) { tab in
|
||||||
tab.makeContentView(popToRootTab: $popToRootTab)
|
tab.makeContentView(selectedTab: $selectedTab, popToRootTab: $popToRootTab)
|
||||||
.tabItem {
|
.tabItem {
|
||||||
if userPreferences.showiPhoneTabLabel {
|
if userPreferences.showiPhoneTabLabel {
|
||||||
tab.label
|
tab.label
|
||||||
|
@ -34,7 +34,6 @@ extension IceCubesApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.id(appAccountsManager.currentClient.id)
|
.id(appAccountsManager.currentClient.id)
|
||||||
.environment(\.selectedTab, selectedTab)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func badgeFor(tab: Tab) -> Int {
|
private func badgeFor(tab: Tab) -> Int {
|
||||||
|
|
|
@ -11,7 +11,6 @@ import Timeline
|
||||||
struct NotificationsTab: View {
|
struct NotificationsTab: View {
|
||||||
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
|
@Environment(\.isSecondaryColumn) private var isSecondaryColumn: Bool
|
||||||
@Environment(\.scenePhase) private var scenePhase
|
@Environment(\.scenePhase) private var scenePhase
|
||||||
@Environment(\.selectedTab) private var selectedTab: Tab
|
|
||||||
|
|
||||||
@Environment(Theme.self) private var theme
|
@Environment(Theme.self) private var theme
|
||||||
@Environment(Client.self) private var client
|
@Environment(Client.self) private var client
|
||||||
|
@ -22,6 +21,8 @@ struct NotificationsTab: View {
|
||||||
@Environment(PushNotificationsService.self) private var pushNotificationsService
|
@Environment(PushNotificationsService.self) private var pushNotificationsService
|
||||||
@State private var routerPath = RouterPath()
|
@State private var routerPath = RouterPath()
|
||||||
@State private var scrollToTopSignal: Int = 0
|
@State private var scrollToTopSignal: Int = 0
|
||||||
|
|
||||||
|
@Binding var selectedTab: Tab
|
||||||
@Binding var popToRootTab: Tab
|
@Binding var popToRootTab: Tab
|
||||||
|
|
||||||
let lockedType: Models.Notification.NotificationType?
|
let lockedType: Models.Notification.NotificationType?
|
||||||
|
@ -72,6 +73,9 @@ struct NotificationsTab: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.onChange(of: selectedTab, { _, newValue in
|
||||||
|
clearNotifications()
|
||||||
|
})
|
||||||
.onChange(of: pushNotificationsService.handledNotification) { _, newValue in
|
.onChange(of: pushNotificationsService.handledNotification) { _, newValue in
|
||||||
if let newValue, let type = newValue.notification.supportedType {
|
if let newValue, let type = newValue.notification.supportedType {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
||||||
|
|
|
@ -31,7 +31,7 @@ enum Tab: Int, Identifiable, Hashable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func makeContentView(popToRootTab: Binding<Tab>) -> some View {
|
func makeContentView(selectedTab: Binding<Tab>, popToRootTab: Binding<Tab>) -> some View {
|
||||||
switch self {
|
switch self {
|
||||||
case .timeline:
|
case .timeline:
|
||||||
TimelineTab(popToRootTab: popToRootTab)
|
TimelineTab(popToRootTab: popToRootTab)
|
||||||
|
@ -42,9 +42,9 @@ enum Tab: Int, Identifiable, Hashable {
|
||||||
case .federated:
|
case .federated:
|
||||||
TimelineTab(popToRootTab: popToRootTab, timeline: .federated)
|
TimelineTab(popToRootTab: popToRootTab, timeline: .federated)
|
||||||
case .notifications:
|
case .notifications:
|
||||||
NotificationsTab(popToRootTab: popToRootTab, lockedType: nil)
|
NotificationsTab(selectedTab: selectedTab, popToRootTab: popToRootTab, lockedType: nil)
|
||||||
case .mentions:
|
case .mentions:
|
||||||
NotificationsTab(popToRootTab: popToRootTab, lockedType: .mention)
|
NotificationsTab(selectedTab: selectedTab, popToRootTab: popToRootTab, lockedType: .mention)
|
||||||
case .explore:
|
case .explore:
|
||||||
ExploreTab(popToRootTab: popToRootTab)
|
ExploreTab(popToRootTab: popToRootTab)
|
||||||
case .messages:
|
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 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
12
Packages/Models/Sources/Models/Marker.swift
Normal file
12
Packages/Models/Sources/Models/Marker.swift
Normal 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?
|
||||||
|
}
|
22
Packages/Network/Sources/Network/Endpoint/Markers.swift
Normal file
22
Packages/Network/Sources/Network/Endpoint/Markers.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -90,6 +90,7 @@ import SwiftUI
|
||||||
types: queryTypes,
|
types: queryTypes,
|
||||||
limit: Constants.notificationLimit))
|
limit: Constants.notificationLimit))
|
||||||
consolidatedNotifications = await notifications.consolidated(selectedType: selectedType)
|
consolidatedNotifications = await notifications.consolidated(selectedType: selectedType)
|
||||||
|
markAsRead()
|
||||||
nextPageState = notifications.count < Constants.notificationLimit ? .none : .hasNextPage
|
nextPageState = notifications.count < Constants.notificationLimit ? .none : .hasNextPage
|
||||||
} else if let firstId = consolidatedNotifications.first?.id {
|
} else if let firstId = consolidatedNotifications.first?.id {
|
||||||
var newNotifications: [Models.Notification] = await fetchNewPages(minId: firstId, maxPages: 10)
|
var newNotifications: [Models.Notification] = await fetchNewPages(minId: firstId, maxPages: 10)
|
||||||
|
@ -97,6 +98,7 @@ import SwiftUI
|
||||||
newNotifications = newNotifications.filter { notification in
|
newNotifications = newNotifications.filter { notification in
|
||||||
!consolidatedNotifications.contains(where: { $0.id == notification.id })
|
!consolidatedNotifications.contains(where: { $0.id == notification.id })
|
||||||
}
|
}
|
||||||
|
|
||||||
await consolidatedNotifications.insert(
|
await consolidatedNotifications.insert(
|
||||||
contentsOf: newNotifications.consolidated(selectedType: selectedType),
|
contentsOf: newNotifications.consolidated(selectedType: selectedType),
|
||||||
at: 0
|
at: 0
|
||||||
|
@ -107,6 +109,8 @@ import SwiftUI
|
||||||
await currentAccount.fetchFollowerRequests()
|
await currentAccount.fetchFollowerRequests()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
markAsRead()
|
||||||
|
|
||||||
withAnimation {
|
withAnimation {
|
||||||
state = .display(notifications: consolidatedNotifications,
|
state = .display(notifications: consolidatedNotifications,
|
||||||
nextPageState: consolidatedNotifications.isEmpty ? .none : nextPageState)
|
nextPageState: consolidatedNotifications.isEmpty ? .none : nextPageState)
|
||||||
|
@ -161,6 +165,15 @@ import SwiftUI
|
||||||
state = .error(error: error)
|
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) {
|
func handleEvent(event: any StreamEvent) {
|
||||||
Task {
|
Task {
|
||||||
|
|
Loading…
Reference in a new issue