Proper threading UI
This commit is contained in:
parent
0b5ad32a92
commit
ac32410200
|
@ -45,6 +45,7 @@ public protocol AnyStatus {
|
||||||
var emojis: [Emoji] { get }
|
var emojis: [Emoji] { get }
|
||||||
var url: String? { get }
|
var url: String? { get }
|
||||||
var application: Application? { get }
|
var application: Application? { get }
|
||||||
|
var inReplyToId: String? { get }
|
||||||
var inReplyToAccountId: String? { get }
|
var inReplyToAccountId: String? { get }
|
||||||
var visibility: Visibility { get }
|
var visibility: Visibility { get }
|
||||||
var poll: Poll? { get }
|
var poll: Poll? { get }
|
||||||
|
@ -97,6 +98,7 @@ public struct Status: AnyStatus, Codable, Identifiable, Equatable, Hashable, Sta
|
||||||
public let emojis: [Emoji]
|
public let emojis: [Emoji]
|
||||||
public let url: String?
|
public let url: String?
|
||||||
public let application: Application?
|
public let application: Application?
|
||||||
|
public let inReplyToId: String?
|
||||||
public let inReplyToAccountId: String?
|
public let inReplyToAccountId: String?
|
||||||
public let visibility: Visibility
|
public let visibility: Visibility
|
||||||
public let poll: Poll?
|
public let poll: Poll?
|
||||||
|
@ -126,6 +128,7 @@ public struct Status: AnyStatus, Codable, Identifiable, Equatable, Hashable, Sta
|
||||||
emojis: [],
|
emojis: [],
|
||||||
url: "https://example.com",
|
url: "https://example.com",
|
||||||
application: nil,
|
application: nil,
|
||||||
|
inReplyToId: nil,
|
||||||
inReplyToAccountId: nil,
|
inReplyToAccountId: nil,
|
||||||
visibility: .pub,
|
visibility: .pub,
|
||||||
poll: nil,
|
poll: nil,
|
||||||
|
@ -160,6 +163,7 @@ public struct Status: AnyStatus, Codable, Identifiable, Equatable, Hashable, Sta
|
||||||
emojis: reblog.emojis,
|
emojis: reblog.emojis,
|
||||||
url: reblog.url,
|
url: reblog.url,
|
||||||
application: reblog.application,
|
application: reblog.application,
|
||||||
|
inReplyToId: reblog.inReplyToId,
|
||||||
inReplyToAccountId: reblog.inReplyToAccountId,
|
inReplyToAccountId: reblog.inReplyToAccountId,
|
||||||
visibility: reblog.visibility,
|
visibility: reblog.visibility,
|
||||||
poll: reblog.poll,
|
poll: reblog.poll,
|
||||||
|
@ -199,6 +203,7 @@ public struct ReblogStatus: AnyStatus, Codable, Identifiable, Equatable, Hashabl
|
||||||
public let emojis: [Emoji]
|
public let emojis: [Emoji]
|
||||||
public let url: String?
|
public let url: String?
|
||||||
public var application: Application?
|
public var application: Application?
|
||||||
|
public let inReplyToId: String?
|
||||||
public let inReplyToAccountId: String?
|
public let inReplyToAccountId: String?
|
||||||
public let visibility: Visibility
|
public let visibility: Visibility
|
||||||
public let poll: Poll?
|
public let poll: Poll?
|
||||||
|
|
|
@ -40,17 +40,8 @@ public struct StatusDetailView: View {
|
||||||
case .loading:
|
case .loading:
|
||||||
loadingDetailView
|
loadingDetailView
|
||||||
|
|
||||||
case let .display(status, context, date):
|
case let .display(statuses):
|
||||||
if !context.ancestors.isEmpty {
|
makeStatusesListView(statuses: statuses)
|
||||||
makeStatusesListView(statuses: context.ancestors)
|
|
||||||
}
|
|
||||||
|
|
||||||
makeCurrentStatusView(status: status)
|
|
||||||
.id(date)
|
|
||||||
|
|
||||||
if !context.descendants.isEmpty {
|
|
||||||
makeStatusesListView(statuses: context.descendants)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isLoaded {
|
if !isLoaded {
|
||||||
loadingContextView
|
loadingContextView
|
||||||
|
@ -107,7 +98,7 @@ public struct StatusDetailView: View {
|
||||||
var isReplyToPrevious: Bool = false
|
var isReplyToPrevious: Bool = false
|
||||||
if let index = statuses.firstIndex(where: { $0.id == status.id }),
|
if let index = statuses.firstIndex(where: { $0.id == status.id }),
|
||||||
index > 0,
|
index > 0,
|
||||||
statuses[index - 1].inReplyToAccountId == status.account.id {
|
statuses[index - 1].id == status.inReplyToId {
|
||||||
isReplyToPrevious = true
|
isReplyToPrevious = true
|
||||||
}
|
}
|
||||||
let viewModel: StatusRowViewModel = .init(status: status,
|
let viewModel: StatusRowViewModel = .init(status: status,
|
||||||
|
@ -120,7 +111,12 @@ public struct StatusDetailView: View {
|
||||||
.fill(theme.tintColor)
|
.fill(theme.tintColor)
|
||||||
.frame(width: 2)
|
.frame(width: 2)
|
||||||
}
|
}
|
||||||
StatusRowView(viewModel: viewModel)
|
if self.viewModel.statusId == status.id {
|
||||||
|
makeCurrentStatusView(status: status)
|
||||||
|
.id(Date())
|
||||||
|
} else {
|
||||||
|
StatusRowView(viewModel: viewModel)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.listRowBackground(viewModel.highlightRowColor)
|
.listRowBackground(viewModel.highlightRowColor)
|
||||||
.listRowInsets(.init(top: 12,
|
.listRowInsets(.init(top: 12,
|
||||||
|
@ -135,7 +131,7 @@ public struct StatusDetailView: View {
|
||||||
client: client,
|
client: client,
|
||||||
routerPath: routerPath,
|
routerPath: routerPath,
|
||||||
isCompact: false,
|
isCompact: false,
|
||||||
isFocused: true))
|
isFocused: !viewModel.isLoadingContext))
|
||||||
.overlay {
|
.overlay {
|
||||||
GeometryReader { reader in
|
GeometryReader { reader in
|
||||||
VStack {}
|
VStack {}
|
||||||
|
|
|
@ -11,10 +11,11 @@ class StatusDetailViewModel: ObservableObject {
|
||||||
var client: Client?
|
var client: Client?
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
case loading, display(status: Status, context: StatusContext, date: Date), error(error: Error)
|
case loading, display(statuses: [Status]), error(error: Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var state: State = .loading
|
@Published var state: State = .loading
|
||||||
|
@Published var isLoadingContext = false
|
||||||
@Published var title: LocalizedStringKey = ""
|
@Published var title: LocalizedStringKey = ""
|
||||||
@Published var scrollToId: String?
|
@Published var scrollToId: String?
|
||||||
|
|
||||||
|
@ -25,7 +26,7 @@ class StatusDetailViewModel: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
init(status: Status) {
|
init(status: Status) {
|
||||||
state = .display(status: status, context: .empty(), date: Date())
|
state = .display(statuses: [status])
|
||||||
title = "status.post-from-\(status.account.displayNameWithoutEmojis)"
|
title = "status.post-from-\(status.account.displayNameWithoutEmojis)"
|
||||||
statusId = status.id
|
statusId = status.id
|
||||||
remoteStatusURL = nil
|
remoteStatusURL = nil
|
||||||
|
@ -71,14 +72,20 @@ class StatusDetailViewModel: ObservableObject {
|
||||||
private func fetchStatusDetail(animate: Bool) async {
|
private func fetchStatusDetail(animate: Bool) async {
|
||||||
guard let client, let statusId else { return }
|
guard let client, let statusId else { return }
|
||||||
do {
|
do {
|
||||||
|
isLoadingContext = true
|
||||||
let data = try await fetchContextData(client: client, statusId: statusId)
|
let data = try await fetchContextData(client: client, statusId: statusId)
|
||||||
title = "status.post-from-\(data.status.account.displayNameWithoutEmojis)"
|
title = "status.post-from-\(data.status.account.displayNameWithoutEmojis)"
|
||||||
|
var statuses = data.context.ancestors
|
||||||
|
statuses.append(data.status)
|
||||||
|
statuses.append(contentsOf: data.context.descendants)
|
||||||
if animate {
|
if animate {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
state = .display(status: data.status, context: data.context, date: Date())
|
isLoadingContext = false
|
||||||
|
state = .display(statuses: statuses)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
state = .display(status: data.status, context: data.context, date: Date())
|
isLoadingContext = false
|
||||||
|
state = .display(statuses: statuses)
|
||||||
scrollToId = statusId
|
scrollToId = statusId
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
Loading…
Reference in New Issue