Vernissage/Vernissage/Views/NotificationsView.swift

136 lines
4.6 KiB
Swift
Raw Normal View History

2022-12-30 18:20:54 +01:00
//
// https://mczachurski.dev
2023-01-18 18:41:42 +01:00
// Copyright © 2023 Marcin Czachurski and the repository contributors.
2022-12-30 18:20:54 +01:00
// Licensed under the MIT License.
//
2023-01-18 18:41:42 +01:00
2022-12-30 18:20:54 +01:00
import SwiftUI
2023-01-18 18:41:42 +01:00
import MastodonKit
2022-12-30 18:20:54 +01:00
struct NotificationsView: View {
2023-01-18 18:41:42 +01:00
@EnvironmentObject var applicationState: ApplicationState
@State var accountId: String
@State private var notifications: [MastodonKit.Notification] = []
@State private var allItemsLoaded = false
2023-02-01 18:40:28 +01:00
@State private var state: ViewState = .loading
2023-01-18 18:41:42 +01:00
@State private var minId: String?
@State private var maxId: String?
2023-02-01 18:40:28 +01:00
private let defaultPageSize = 40
2023-01-18 18:41:42 +01:00
2022-12-30 18:20:54 +01:00
var body: some View {
2023-02-01 18:40:28 +01:00
self.mainBody()
.navigationBarTitle("Notifications")
}
@ViewBuilder
private func mainBody() -> some View {
switch state {
case .loading:
LoadingIndicator()
.task {
await self.loadNotifications()
2023-01-18 18:41:42 +01:00
}
2023-02-01 18:40:28 +01:00
case .loaded:
if self.notifications.isEmpty {
NoDataView(imageSystemName: "bell", text: "Unfortunately, there is nothing here.")
2023-01-18 18:41:42 +01:00
} else {
2023-02-01 18:40:28 +01:00
List {
ForEach(notifications, id: \.id) { notification in
NotificationRow(notification: notification)
}
if allItemsLoaded == false {
HStack {
Spacer()
LoadingIndicator()
.task {
await self.loadMoreNotifications()
}
Spacer()
}
.listRowSeparator(.hidden)
}
}
.listStyle(PlainListStyle())
.refreshable {
await self.loadNewNotifications()
2023-01-18 18:41:42 +01:00
}
}
2023-02-01 18:40:28 +01:00
case .error(let error):
ErrorView(error: error) {
self.state = .loading
await self.loadMoreNotifications()
}
.padding()
2023-01-18 18:41:42 +01:00
}
}
func loadNotifications() async {
2023-02-01 18:40:28 +01:00
do {
2023-01-22 21:44:07 +01:00
let linkable = try await NotificationService.shared.notifications(
for: self.applicationState.account,
2023-01-18 18:41:42 +01:00
maxId: maxId,
minId: minId,
limit: 5)
self.minId = linkable.link?.minId
self.maxId = linkable.link?.maxId
self.notifications = linkable.data
2023-02-01 18:40:28 +01:00
if linkable.data.isEmpty {
2023-01-18 18:41:42 +01:00
self.allItemsLoaded = true
}
2023-02-01 18:40:28 +01:00
self.state = .loaded
2023-01-18 18:41:42 +01:00
} catch {
2023-02-01 18:40:28 +01:00
if !Task.isCancelled {
ErrorService.shared.handle(error, message: "Error during download notifications from server.", showToastr: true)
self.state = .error(error)
} else {
ErrorService.shared.handle(error, message: "Error during download notifications from server.", showToastr: false)
}
2023-01-18 18:41:42 +01:00
}
}
private func loadMoreNotifications() async {
do {
2023-01-22 21:44:07 +01:00
let linkable = try await NotificationService.shared.notifications(
for: self.applicationState.account,
2023-01-18 18:41:42 +01:00
maxId: self.maxId,
limit: self.defaultPageSize)
2023-02-01 18:40:28 +01:00
if linkable.data.isEmpty {
2023-01-18 18:41:42 +01:00
self.allItemsLoaded = true
2023-02-01 20:01:18 +01:00
return
2023-01-18 18:41:42 +01:00
}
2023-02-01 20:01:18 +01:00
self.maxId = linkable.link?.maxId
self.notifications.append(contentsOf: linkable.data)
2023-01-18 18:41:42 +01:00
} catch {
2023-01-20 13:47:38 +01:00
ErrorService.shared.handle(error, message: "Error during download notifications from server.", showToastr: !Task.isCancelled)
2023-01-18 18:41:42 +01:00
}
}
private func loadNewNotifications() async {
do {
2023-01-22 21:44:07 +01:00
let linkable = try await NotificationService.shared.notifications(
for: self.applicationState.account,
2023-01-18 18:41:42 +01:00
minId: self.minId,
limit: self.defaultPageSize)
if let first = linkable.data.first, self.notifications.contains(where: { notification in notification.id == first.id }) {
// We have all notifications, we don't have to do anything.
return
}
self.minId = linkable.link?.minId
2023-01-22 21:44:07 +01:00
self.notifications.insert(contentsOf: linkable.data, at: 0)
2023-01-18 18:41:42 +01:00
} catch {
2023-01-20 13:47:38 +01:00
ErrorService.shared.handle(error, message: "Error during download notifications from server.", showToastr: !Task.isCancelled)
2023-01-18 18:41:42 +01:00
}
}
2022-12-30 18:20:54 +01:00
}