Fix the crash once and for all by using Introspect

This commit is contained in:
Thomas Ricouard 2023-02-03 16:24:09 +01:00
parent 2a1d1fc697
commit 4104fdf4f5
4 changed files with 26 additions and 13 deletions

View File

@ -63,6 +63,15 @@
"version" : "2.5.3"
}
},
{
"identity" : "swiftui-introspect",
"kind" : "remoteSourceControl",
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
"state" : {
"revision" : "f2616860a41f9d9932da412a8978fec79c06fe24",
"version" : "0.1.4"
}
},
{
"identity" : "swiftui-shimmer",
"kind" : "remoteSourceControl",

View File

@ -21,6 +21,7 @@ let package = Package(
.package(name: "Env", path: "../Env"),
.package(name: "Status", path: "../Status"),
.package(name: "DesignSystem", path: "../DesignSystem"),
.package(url: "https://github.com/siteline/SwiftUI-Introspect.git", from: "0.1.4"),
],
targets: [
.target(
@ -31,6 +32,7 @@ let package = Package(
.product(name: "Env", package: "Env"),
.product(name: "Status", package: "Status"),
.product(name: "DesignSystem", package: "DesignSystem"),
.product(name: "Introspect", package: "SwiftUI-Introspect"),
]
),
.testTarget(

View File

@ -5,6 +5,7 @@ import Network
import Shimmer
import Status
import SwiftUI
import Introspect
public struct TimelineView: View {
private enum Constants {
@ -21,7 +22,7 @@ public struct TimelineView: View {
@StateObject private var viewModel = TimelineViewModel()
@State private var wasBackgrounded: Bool = false
@State private var listOpacity: CGFloat = 1
@State private var collectionView: UICollectionView?
@Binding var timeline: TimelineFilter
@Binding var scrollToTopSignal: Int
@ -47,24 +48,25 @@ public struct TimelineView: View {
StatusesListView(fetcher: viewModel)
}
}
.id(client.id + (viewModel.scrollToStatus ?? ""))
.opacity(listOpacity)
.id(client.id)
.environment(\.defaultMinListRowHeight, 1)
.listStyle(.plain)
.scrollContentBackground(.hidden)
.background(theme.primaryBackgroundColor)
.introspect(selector: TargetViewSelector.ancestorOrSiblingContaining,
customize: { (collectionView: UICollectionView) in
self.collectionView = collectionView
})
if viewModel.pendingStatusesEnabled {
PendingStatusesObserverView(observer: viewModel.pendingStatusesObserver)
}
}
.onChange(of: viewModel.scrollToStatus) { statusId in
if let statusId {
viewModel.scrollToStatus = nil
listOpacity = 0
DispatchQueue.main.async {
proxy.scrollTo(statusId, anchor: .top)
listOpacity = 1
}
.onChange(of: viewModel.scrollToIndex) { index in
if let index {
viewModel.scrollToIndex = nil
collectionView?.scrollToItem(at: .init(row: index, section: 0),
at: .top,
animated: false)
}
}
.onChange(of: scrollToTopSignal, perform: { _ in

View File

@ -35,7 +35,7 @@ class TimelineViewModel: ObservableObject {
private let cache: TimelineCache = .shared
@Published var scrollToStatus: String?
@Published var scrollToIndex: Int?
@Published var statusesState: StatusesState = .loading
@Published var timeline: TimelineFilter = .federated {
@ -222,8 +222,8 @@ extension TimelineViewModel: StatusesFetcher {
// We need to update the statuses state, and then scroll to the previous top most status.
if let topStatusId, visibileStatusesIds.contains(topStatusId), scrollToTopVisible {
pendingStatusesObserver.disableUpdate = true
scrollToStatus = topStatusId
statusesState = .display(statuses: statuses, nextPageState: statuses.count < 20 ? .none : .hasNextPage)
scrollToIndex = newStatuses.count + 1
DispatchQueue.main.async {
self.pendingStatusesObserver.disableUpdate = false
self.canStreamEvents = true