mirror of
https://github.com/VernissageApp/Vernissage.git
synced 2024-12-24 16:11:15 +01:00
128 lines
4.7 KiB
Swift
128 lines
4.7 KiB
Swift
//
|
|
// https://mczachurski.dev
|
|
// Copyright © 2022 Marcin Czachurski and the repository contributors.
|
|
// Licensed under the MIT License.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct HomeFeedView: View {
|
|
@Environment(\.managedObjectContext) private var viewContext
|
|
@EnvironmentObject var applicationState: ApplicationState
|
|
@EnvironmentObject var routerPath: RouterPath
|
|
|
|
@State private var allItemsLoaded = false
|
|
@State private var state: ViewState = .loading
|
|
|
|
@FetchRequest var dbStatuses: FetchedResults<StatusData>
|
|
|
|
init(accountId: String) {
|
|
_dbStatuses = FetchRequest<StatusData>(
|
|
sortDescriptors: [SortDescriptor(\.id, order: .reverse)],
|
|
predicate: NSPredicate(format: "pixelfedAccount.id = %@", accountId))
|
|
}
|
|
|
|
var body: some View {
|
|
switch state {
|
|
case .loading:
|
|
LoadingIndicator()
|
|
.task {
|
|
await self.loadData()
|
|
}
|
|
case .loaded:
|
|
if self.dbStatuses.isEmpty {
|
|
NoDataView(imageSystemName: "photo.on.rectangle.angled", text: "Unfortunately, there are no photos here.")
|
|
} else {
|
|
self.timeline()
|
|
}
|
|
case .error(let error):
|
|
ErrorView(error: error) {
|
|
self.state = .loading
|
|
await self.loadData()
|
|
}
|
|
.padding()
|
|
}
|
|
}
|
|
|
|
@ViewBuilder
|
|
private func timeline() -> some View {
|
|
ScrollView {
|
|
LazyVStack {
|
|
ForEach(dbStatuses, id: \.self) { item in
|
|
if self.shouldUpToDateBeVisible(statusId: item.id) {
|
|
self.upToDatePlaceholder()
|
|
}
|
|
|
|
ImageRow(statusData: item)
|
|
}
|
|
|
|
if allItemsLoaded == false {
|
|
LoadingIndicator()
|
|
.task {
|
|
do {
|
|
if let account = self.applicationState.account {
|
|
let newStatusesCount = try await HomeTimelineService.shared.loadOnBottom(for: account)
|
|
if newStatusesCount == 0 {
|
|
allItemsLoaded = true
|
|
}
|
|
}
|
|
} catch {
|
|
ErrorService.shared.handle(error, message: "Error during download statuses from server.", showToastr: !Task.isCancelled)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.refreshable {
|
|
do {
|
|
if let account = self.applicationState.account {
|
|
if let lastSeenStatusId = try await HomeTimelineService.shared.loadOnTop(for: account) {
|
|
try await HomeTimelineService.shared.save(lastSeenStatusId: lastSeenStatusId, for: account)
|
|
self.applicationState.lastSeenStatusId = lastSeenStatusId
|
|
}
|
|
}
|
|
} catch {
|
|
ErrorService.shared.handle(error, message: "Error during download statuses from server.", showToastr: !Task.isCancelled)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func loadData() async {
|
|
do {
|
|
if let account = self.applicationState.account {
|
|
_ = try await HomeTimelineService.shared.loadOnTop(for: account)
|
|
}
|
|
|
|
self.state = .loaded
|
|
} catch {
|
|
if !Task.isCancelled {
|
|
ErrorService.shared.handle(error, message: "Error during download statuses from server.", showToastr: true)
|
|
self.state = .error(error)
|
|
} else {
|
|
ErrorService.shared.handle(error, message: "Error during download statuses from server.", showToastr: false)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func shouldUpToDateBeVisible(statusId: String) -> Bool {
|
|
return self.applicationState.lastSeenStatusId != dbStatuses.first?.id && self.applicationState.lastSeenStatusId == statusId
|
|
}
|
|
|
|
@ViewBuilder
|
|
private func upToDatePlaceholder() -> some View {
|
|
VStack(alignment: .center) {
|
|
Image(systemName: "checkmark.seal")
|
|
.resizable()
|
|
.frame(width: 64, height: 64)
|
|
.fontWeight(.ultraLight)
|
|
.foregroundColor(.accentColor.opacity(0.6))
|
|
Text("You're all caught up")
|
|
.font(.title2)
|
|
.fontWeight(.thin)
|
|
.foregroundColor(Color.mainTextColor.opacity(0.6))
|
|
}
|
|
.padding(.vertical, 8)
|
|
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width * 0.75)
|
|
}
|
|
}
|