Status detail + context

This commit is contained in:
Thomas Ricouard 2022-12-21 18:28:21 +01:00
parent c2a2fe1f86
commit 07188a6818
5 changed files with 108 additions and 4 deletions

View file

@ -0,0 +1,6 @@
import Foundation
public struct StatusContext: Decodable {
public let ancestors: [Status]
public let descendants: [Status]
}

View file

@ -1,6 +1,8 @@
import Foundation
public enum Statuses: Endpoint {
case status(id: String)
case context(id: String)
case favourite(id: String)
case unfavourite(id: String)
case reblog(id: String)
@ -8,6 +10,10 @@ public enum Statuses: Endpoint {
public func path() -> String {
switch self {
case .status(let id):
return "statuses/\(id)"
case .context(let id):
return "statuses/\(id)/context"
case .favourite(let id):
return "statuses/\(id)/favourite"
case .unfavourite(let id):

View file

@ -24,6 +24,7 @@ public struct NotificationsListView: View {
.padding(.top, DS.Constants.layoutPadding)
}
.task {
viewModel.client = client
await viewModel.fetchNotifications()
}
.refreshable {

View file

@ -1,13 +1,68 @@
import SwiftUI
import Models
import Shimmer
import Routeur
import Network
import DesignSystem
public struct StatusDetailView: View {
private let statusId: String
@EnvironmentObject private var client: Client
@EnvironmentObject private var routeurPath: RouterPath
@StateObject private var viewModel: StatusDetailViewModel
@State private var isLoaded: Bool = false
public init(statusId: String) {
self.statusId = statusId
_viewModel = StateObject(wrappedValue: .init(statusId: statusId))
}
public var body: some View {
Text("Status id \(statusId)")
ScrollViewReader { proxy in
ScrollView {
LazyVStack {
switch viewModel.state {
case .loading:
ForEach(Status.placeholders()) { status in
StatusRowView(viewModel: .init(status: status, isEmbed: false))
.redacted(reason: .placeholder)
.shimmering()
}
case let.display(status, context):
if !context.ancestors.isEmpty {
ForEach(context.ancestors) { ancestor in
StatusRowView(viewModel: .init(status: ancestor, isEmbed: false))
Divider()
.padding(.vertical, DS.Constants.dividerPadding)
}
}
StatusRowView(viewModel: .init(status: status, isEmbed: false))
.id(status.id)
Divider()
.padding(.vertical, DS.Constants.dividerPadding)
if !context.descendants.isEmpty {
ForEach(context.descendants) { descendant in
StatusRowView(viewModel: .init(status: descendant, isEmbed: false))
Divider()
.padding(.vertical, DS.Constants.dividerPadding)
}
}
case let .error(error):
Text(error.localizedDescription)
}
}
.padding(.horizontal, DS.Constants.layoutPadding)
}
.task {
guard !isLoaded else { return }
isLoaded = true
viewModel.client = client
await viewModel.fetchStatusDetail()
DispatchQueue.main.async {
proxy.scrollTo(viewModel.statusId, anchor: .center)
}
}
}
.navigationTitle(viewModel.title)
.navigationBarTitleDisplayMode(.inline)
}
}

View file

@ -0,0 +1,36 @@
import Foundation
import SwiftUI
import Models
import Network
@MainActor
class StatusDetailViewModel: ObservableObject {
public let statusId: String
var client: Client?
enum State {
case loading, display(status: Status, context: StatusContext), error(error: Error)
}
@Published var state: State = .loading
@Published var title: String = ""
init(statusId: String) {
state = .loading
self.statusId = statusId
}
func fetchStatusDetail() async {
guard let client else { return }
do {
state = .loading
let status: Status = try await client.get(endpoint: Statuses.status(id: statusId))
let context: StatusContext = try await client.get(endpoint: Statuses.context(id: statusId))
state = .display(status: status, context: context)
title = "Post from \(status.account.displayName)"
} catch {
state = .error(error: error)
}
}
}