From ac3241020054c8362f411f01c32147c0ff196424 Mon Sep 17 00:00:00 2001 From: Thomas Ricouard Date: Thu, 16 Feb 2023 17:07:52 +0100 Subject: [PATCH] Proper threading UI --- Packages/Models/Sources/Models/Status.swift | 5 ++++ .../Status/Detail/StatusDetailView.swift | 24 ++++++++----------- .../Status/Detail/StatusDetailViewModel.swift | 15 ++++++++---- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Packages/Models/Sources/Models/Status.swift b/Packages/Models/Sources/Models/Status.swift index 3ea51f0a..355c753f 100644 --- a/Packages/Models/Sources/Models/Status.swift +++ b/Packages/Models/Sources/Models/Status.swift @@ -45,6 +45,7 @@ public protocol AnyStatus { var emojis: [Emoji] { get } var url: String? { get } var application: Application? { get } + var inReplyToId: String? { get } var inReplyToAccountId: String? { get } var visibility: Visibility { get } var poll: Poll? { get } @@ -97,6 +98,7 @@ public struct Status: AnyStatus, Codable, Identifiable, Equatable, Hashable, Sta public let emojis: [Emoji] public let url: String? public let application: Application? + public let inReplyToId: String? public let inReplyToAccountId: String? public let visibility: Visibility public let poll: Poll? @@ -126,6 +128,7 @@ public struct Status: AnyStatus, Codable, Identifiable, Equatable, Hashable, Sta emojis: [], url: "https://example.com", application: nil, + inReplyToId: nil, inReplyToAccountId: nil, visibility: .pub, poll: nil, @@ -160,6 +163,7 @@ public struct Status: AnyStatus, Codable, Identifiable, Equatable, Hashable, Sta emojis: reblog.emojis, url: reblog.url, application: reblog.application, + inReplyToId: reblog.inReplyToId, inReplyToAccountId: reblog.inReplyToAccountId, visibility: reblog.visibility, poll: reblog.poll, @@ -199,6 +203,7 @@ public struct ReblogStatus: AnyStatus, Codable, Identifiable, Equatable, Hashabl public let emojis: [Emoji] public let url: String? public var application: Application? + public let inReplyToId: String? public let inReplyToAccountId: String? public let visibility: Visibility public let poll: Poll? diff --git a/Packages/Status/Sources/Status/Detail/StatusDetailView.swift b/Packages/Status/Sources/Status/Detail/StatusDetailView.swift index 0d3d1ac5..6d8c8689 100644 --- a/Packages/Status/Sources/Status/Detail/StatusDetailView.swift +++ b/Packages/Status/Sources/Status/Detail/StatusDetailView.swift @@ -40,17 +40,8 @@ public struct StatusDetailView: View { case .loading: loadingDetailView - case let .display(status, context, date): - if !context.ancestors.isEmpty { - makeStatusesListView(statuses: context.ancestors) - } - - makeCurrentStatusView(status: status) - .id(date) - - if !context.descendants.isEmpty { - makeStatusesListView(statuses: context.descendants) - } + case let .display(statuses): + makeStatusesListView(statuses: statuses) if !isLoaded { loadingContextView @@ -107,7 +98,7 @@ public struct StatusDetailView: View { var isReplyToPrevious: Bool = false if let index = statuses.firstIndex(where: { $0.id == status.id }), index > 0, - statuses[index - 1].inReplyToAccountId == status.account.id { + statuses[index - 1].id == status.inReplyToId { isReplyToPrevious = true } let viewModel: StatusRowViewModel = .init(status: status, @@ -120,7 +111,12 @@ public struct StatusDetailView: View { .fill(theme.tintColor) .frame(width: 2) } - StatusRowView(viewModel: viewModel) + if self.viewModel.statusId == status.id { + makeCurrentStatusView(status: status) + .id(Date()) + } else { + StatusRowView(viewModel: viewModel) + } } .listRowBackground(viewModel.highlightRowColor) .listRowInsets(.init(top: 12, @@ -135,7 +131,7 @@ public struct StatusDetailView: View { client: client, routerPath: routerPath, isCompact: false, - isFocused: true)) + isFocused: !viewModel.isLoadingContext)) .overlay { GeometryReader { reader in VStack {} diff --git a/Packages/Status/Sources/Status/Detail/StatusDetailViewModel.swift b/Packages/Status/Sources/Status/Detail/StatusDetailViewModel.swift index c79147ab..9cbb7354 100644 --- a/Packages/Status/Sources/Status/Detail/StatusDetailViewModel.swift +++ b/Packages/Status/Sources/Status/Detail/StatusDetailViewModel.swift @@ -11,10 +11,11 @@ class StatusDetailViewModel: ObservableObject { var client: Client? 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 isLoadingContext = false @Published var title: LocalizedStringKey = "" @Published var scrollToId: String? @@ -25,7 +26,7 @@ class StatusDetailViewModel: ObservableObject { } init(status: Status) { - state = .display(status: status, context: .empty(), date: Date()) + state = .display(statuses: [status]) title = "status.post-from-\(status.account.displayNameWithoutEmojis)" statusId = status.id remoteStatusURL = nil @@ -71,14 +72,20 @@ class StatusDetailViewModel: ObservableObject { private func fetchStatusDetail(animate: Bool) async { guard let client, let statusId else { return } do { + isLoadingContext = true let data = try await fetchContextData(client: client, statusId: statusId) 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 { withAnimation { - state = .display(status: data.status, context: data.context, date: Date()) + isLoadingContext = false + state = .display(statuses: statuses) } } else { - state = .display(status: data.status, context: data.context, date: Date()) + isLoadingContext = false + state = .display(statuses: statuses) scrollToId = statusId } } catch {