StatusRow: Flatify the hierarchy to work around iOS 16.4 issues
This commit is contained in:
parent
87ef2f2a39
commit
43a4551d9b
|
@ -10,35 +10,32 @@ public struct StatusRowView: View {
|
|||
@Environment(\.isInCaptureMode) private var isInCaptureMode: Bool
|
||||
@Environment(\.redactionReasons) private var reasons
|
||||
@Environment(\.isCompact) private var isCompact: Bool
|
||||
|
||||
|
||||
@EnvironmentObject private var theme: Theme
|
||||
@EnvironmentObject private var client: Client
|
||||
|
||||
|
||||
@StateObject var viewModel: StatusRowViewModel
|
||||
|
||||
|
||||
// StateObject accepts an @autoclosure which only allocates the view model once when the view gets on screen.
|
||||
public init(viewModel: @escaping () -> StatusRowViewModel) {
|
||||
_viewModel = StateObject(wrappedValue: viewModel())
|
||||
}
|
||||
|
||||
|
||||
var contextMenu: some View {
|
||||
StatusRowContextMenu(viewModel: viewModel)
|
||||
}
|
||||
|
||||
|
||||
public var body: some View {
|
||||
if viewModel.isFiltered, let filter = viewModel.filter {
|
||||
switch filter.filter.filterAction {
|
||||
case .warn:
|
||||
makeFilterView(filter: filter.filter)
|
||||
.listRowBackground(viewModel.highlightRowColor)
|
||||
case .hide:
|
||||
EmptyView()
|
||||
.listRowSeparator(.hidden)
|
||||
.listRowInsets(.init())
|
||||
}
|
||||
} else {
|
||||
VStack(alignment: .leading) {
|
||||
let status: AnyStatus = viewModel.status.reblog ?? viewModel.status
|
||||
VStack(alignment: .leading) {
|
||||
if viewModel.isFiltered, let filter = viewModel.filter {
|
||||
switch filter.filter.filterAction {
|
||||
case .warn:
|
||||
makeFilterView(filter: filter.filter)
|
||||
case .hide:
|
||||
EmptyView()
|
||||
}
|
||||
} else {
|
||||
if !isCompact, theme.avatarPosition == .leading {
|
||||
StatusRowReblogView(viewModel: viewModel)
|
||||
StatusRowReplyView(viewModel: viewModel)
|
||||
|
@ -85,76 +82,76 @@ public struct StatusRowView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
viewModel.markSeen()
|
||||
if reasons.isEmpty {
|
||||
if !isCompact, viewModel.embeddedStatus == nil {
|
||||
Task {
|
||||
await viewModel.loadEmbeddedStatus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.contextMenu {
|
||||
contextMenu
|
||||
}
|
||||
.swipeActions(edge: .trailing) {
|
||||
if !isCompact {
|
||||
StatusRowSwipeView(viewModel: viewModel, mode: .trailing)
|
||||
}
|
||||
}
|
||||
.swipeActions(edge: .leading) {
|
||||
if !isCompact {
|
||||
StatusRowSwipeView(viewModel: viewModel, mode: .leading)
|
||||
}
|
||||
}
|
||||
.listRowBackground(viewModel.highlightRowColor)
|
||||
.listRowInsets(.init(top: 12,
|
||||
leading: .layoutPadding,
|
||||
bottom: 12,
|
||||
trailing: .layoutPadding))
|
||||
.accessibilityElement(children: viewModel.isFocused ? .contain : .combine)
|
||||
.accessibilityActions {
|
||||
if UIAccessibility.isVoiceOverRunning {
|
||||
accesibilityActions
|
||||
}
|
||||
}
|
||||
.background {
|
||||
Color.clear
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
viewModel.navigateToDetail()
|
||||
}
|
||||
}
|
||||
.overlay {
|
||||
if viewModel.isLoadingRemoteContent {
|
||||
remoteContentLoadingView
|
||||
}
|
||||
}
|
||||
.alert(isPresented: $viewModel.showDeleteAlert, content: {
|
||||
Alert(
|
||||
title: Text("status.action.delete.confirm.title"),
|
||||
message: Text("status.action.delete.confirm.message"),
|
||||
primaryButton: .destructive(
|
||||
Text("status.action.delete"))
|
||||
{
|
||||
Task {
|
||||
await viewModel.delete()
|
||||
}
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
})
|
||||
.alignmentGuide(.listRowSeparatorLeading) { _ in
|
||||
-100
|
||||
}
|
||||
.environmentObject(
|
||||
StatusDataControllerProvider.shared.dataController(for: viewModel.status.reblog ?? viewModel.status,
|
||||
client: client)
|
||||
)
|
||||
}
|
||||
.onAppear {
|
||||
viewModel.markSeen()
|
||||
if reasons.isEmpty {
|
||||
if !isCompact, viewModel.embeddedStatus == nil {
|
||||
Task {
|
||||
await viewModel.loadEmbeddedStatus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.contextMenu {
|
||||
contextMenu
|
||||
}
|
||||
.swipeActions(edge: .trailing) {
|
||||
if !isCompact {
|
||||
StatusRowSwipeView(viewModel: viewModel, mode: .trailing)
|
||||
}
|
||||
}
|
||||
.swipeActions(edge: .leading) {
|
||||
if !isCompact {
|
||||
StatusRowSwipeView(viewModel: viewModel, mode: .leading)
|
||||
}
|
||||
}
|
||||
.listRowBackground(viewModel.highlightRowColor)
|
||||
.listRowInsets(.init(top: 12,
|
||||
leading: .layoutPadding,
|
||||
bottom: 12,
|
||||
trailing: .layoutPadding))
|
||||
.accessibilityElement(children: viewModel.isFocused ? .contain : .combine)
|
||||
.accessibilityActions {
|
||||
if UIAccessibility.isVoiceOverRunning {
|
||||
accesibilityActions
|
||||
}
|
||||
}
|
||||
.background {
|
||||
Color.clear
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
viewModel.navigateToDetail()
|
||||
}
|
||||
}
|
||||
.overlay {
|
||||
if viewModel.isLoadingRemoteContent {
|
||||
remoteContentLoadingView
|
||||
}
|
||||
}
|
||||
.alert(isPresented: $viewModel.showDeleteAlert, content: {
|
||||
Alert(
|
||||
title: Text("status.action.delete.confirm.title"),
|
||||
message: Text("status.action.delete.confirm.message"),
|
||||
primaryButton: .destructive(
|
||||
Text("status.action.delete"))
|
||||
{
|
||||
Task {
|
||||
await viewModel.delete()
|
||||
}
|
||||
},
|
||||
secondaryButton: .cancel()
|
||||
)
|
||||
})
|
||||
.alignmentGuide(.listRowSeparatorLeading) { _ in
|
||||
-100
|
||||
}
|
||||
.environmentObject(
|
||||
StatusDataControllerProvider.shared.dataController(for: viewModel.status.reblog ?? viewModel.status,
|
||||
client: client)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@ViewBuilder
|
||||
private var accesibilityActions: some View {
|
||||
// Add the individual mentions as accessibility actions
|
||||
|
@ -163,20 +160,20 @@ public struct StatusRowView: View {
|
|||
viewModel.routerPath.navigate(to: .accountDetail(id: mention.id))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button(viewModel.displaySpoiler ? "status.show-more" : "status.show-less") {
|
||||
withAnimation {
|
||||
viewModel.displaySpoiler.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button("@\(viewModel.status.account.username)") {
|
||||
viewModel.routerPath.navigate(to: .accountDetail(id: viewModel.status.account.id))
|
||||
}
|
||||
|
||||
|
||||
contextMenu
|
||||
}
|
||||
|
||||
|
||||
private func makeFilterView(filter: Filter) -> some View {
|
||||
HStack {
|
||||
Text("status.filter.filtered-by-\(filter.title)")
|
||||
|
@ -189,7 +186,7 @@ public struct StatusRowView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var remoteContentLoadingView: some View {
|
||||
ZStack(alignment: .center) {
|
||||
VStack {
|
||||
|
|
Loading…
Reference in New Issue