IceCubesApp/Packages/Status/Sources/Status/Row/StatusRowView.swift

199 lines
5.8 KiB
Swift
Raw Normal View History

2022-12-19 11:28:55 +00:00
import DesignSystem
2023-01-17 10:36:01 +00:00
import EmojiText
import Env
import Models
2022-12-19 14:51:25 +00:00
import Network
2022-12-30 18:31:17 +00:00
import Shimmer
2023-01-17 10:36:01 +00:00
import SwiftUI
2022-11-21 08:31:32 +00:00
2022-12-18 19:30:19 +00:00
public struct StatusRowView: View {
2022-12-17 12:37:46 +00:00
@Environment(\.redactionReasons) private var reasons
2022-12-24 14:09:17 +00:00
@EnvironmentObject private var theme: Theme
2022-12-20 19:33:45 +00:00
@StateObject var viewModel: StatusRowViewModel
2023-01-17 10:36:01 +00:00
2022-12-20 19:33:45 +00:00
public init(viewModel: StatusRowViewModel) {
_viewModel = StateObject(wrappedValue: viewModel)
2022-12-18 19:30:19 +00:00
}
2023-01-17 10:36:01 +00:00
var contextMenu: some View {
StatusRowContextMenu(viewModel: viewModel)
}
2023-01-27 19:36:40 +00:00
2022-12-18 19:30:19 +00:00
public var body: some View {
2023-01-03 11:24:15 +00:00
if viewModel.isFiltered, let filter = viewModel.filter {
switch filter.filter.filterAction {
case .warn:
makeFilterView(filter: filter.filter)
2023-02-15 18:10:34 +00:00
.listRowBackground(viewModel.highlightRowColor)
2023-01-03 11:24:15 +00:00
case .hide:
EmptyView()
2023-02-15 18:10:34 +00:00
.listRowSeparator(.hidden)
2022-12-24 09:14:47 +00:00
}
2023-01-03 11:24:15 +00:00
} else {
let status: AnyStatus = viewModel.status.reblog ?? viewModel.status
VStack(alignment: .leading) {
if !viewModel.isCompact, theme.avatarPosition == .leading {
StatusRowReblogView(viewModel: viewModel)
StatusRowReplyView(viewModel: viewModel)
}
HStack(alignment: .top, spacing: .statusColumnsSpacing) {
if !viewModel.isCompact,
theme.avatarPosition == .leading {
Button {
viewModel.routerPath.navigate(to: .accountDetailWithAccount(account: status.account))
} label: {
AvatarView(url: status.account.avatar, size: .status)
}
2023-01-03 11:24:15 +00:00
}
VStack(alignment: .leading) {
if !viewModel.isCompact, theme.avatarPosition == .top {
StatusRowReblogView(viewModel: viewModel)
StatusRowReplyView(viewModel: viewModel)
}
VStack(alignment: .leading, spacing: 8) {
let status: AnyStatus = viewModel.status.reblog ?? viewModel.status
if !viewModel.isCompact {
StatusRowHeaderView(status: status, viewModel: viewModel)
}
StatusRowContentView(status: status, viewModel: viewModel)
.contentShape(Rectangle())
.onTapGesture {
viewModel.navigateToDetail()
}
}
.accessibilityElement(children: viewModel.isFocused ? .contain : .combine)
.accessibilityAction {
viewModel.navigateToDetail()
}
if viewModel.showActions, theme.statusActionsDisplay != .none {
StatusRowActionsView(viewModel: viewModel)
.padding(.top, 8)
.tint(viewModel.isFocused ? theme.tintColor : .gray)
.contentShape(Rectangle())
.onTapGesture {
viewModel.navigateToDetail()
}
}
2023-01-03 11:24:15 +00:00
}
}
2022-12-23 16:50:51 +00:00
}
2023-01-03 11:24:15 +00:00
.onAppear {
viewModel.markSeen()
2023-01-22 08:51:43 +00:00
if reasons.isEmpty {
if !viewModel.isCompact, viewModel.embeddedStatus == nil {
Task {
await viewModel.loadEmbeddedStatus()
}
}
}
2022-12-27 06:51:44 +00:00
}
2023-01-22 05:38:30 +00:00
.contextMenu {
contextMenu
2023-01-22 05:38:30 +00:00
}
2023-02-01 20:51:03 +00:00
.swipeActions(edge: .trailing) {
2023-02-04 12:30:07 +00:00
if !viewModel.isCompact {
StatusRowSwipeView(viewModel: viewModel, mode: .trailing)
2023-02-04 12:30:07 +00:00
}
2023-02-01 20:51:03 +00:00
}
.swipeActions(edge: .leading) {
2023-02-04 12:30:07 +00:00
if !viewModel.isCompact {
StatusRowSwipeView(viewModel: viewModel, mode: .leading)
2023-02-04 12:30:07 +00:00
}
2023-02-01 20:51:03 +00:00
}
2023-02-15 18:10:34 +00:00
.listRowBackground(viewModel.highlightRowColor)
.listRowInsets(.init(top: 12,
leading: .layoutPadding,
bottom: 12,
trailing: .layoutPadding))
2023-01-22 05:38:30 +00:00
.accessibilityElement(children: viewModel.isFocused ? .contain : .combine)
.accessibilityActions {
2023-02-15 18:27:26 +00:00
if UIAccessibility.isVoiceOverRunning {
accesibilityActions
}
2023-01-22 05:38:30 +00:00
}
.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(
2023-02-12 15:29:41 +00:00
Text("status.action.delete"))
{
Task {
await viewModel.delete()
}
},
secondaryButton: .cancel()
)
})
.alignmentGuide(.listRowSeparatorLeading) { _ in
-100
}
2022-12-20 19:33:45 +00:00
}
2023-01-03 11:24:15 +00:00
}
2023-02-12 15:29:41 +00:00
2023-02-09 08:12:44 +00:00
@ViewBuilder
private var accesibilityActions: some View {
// Add the individual mentions as accessibility actions
ForEach(viewModel.status.mentions, id: \.id) { mention in
Button("@\(mention.username)") {
viewModel.routerPath.navigate(to: .accountDetail(id: mention.id))
2023-02-09 08:12:44 +00:00
}
}
2023-02-12 15:29:41 +00:00
2023-02-09 08:12:44 +00:00
Button(viewModel.displaySpoiler ? "status.show-more" : "status.show-less") {
withAnimation {
viewModel.displaySpoiler.toggle()
}
}
2023-02-12 15:29:41 +00:00
2023-02-09 08:12:44 +00:00
Button("@\(viewModel.status.account.username)") {
viewModel.routerPath.navigate(to: .accountDetail(id: viewModel.status.account.id))
2023-02-09 08:12:44 +00:00
}
2023-02-12 15:29:41 +00:00
2023-02-09 08:12:44 +00:00
contextMenu
}
2023-01-17 10:36:01 +00:00
2023-01-03 11:24:15 +00:00
private func makeFilterView(filter: Filter) -> some View {
HStack {
Text("status.filter.filtered-by-\(filter.title)")
2023-01-03 11:24:15 +00:00
Button {
withAnimation {
viewModel.isFiltered = false
}
} label: {
Text("status.filter.show-anyway")
2023-01-03 11:24:15 +00:00
}
2022-12-27 08:11:12 +00:00
}
2022-12-16 12:16:48 +00:00
}
private var remoteContentLoadingView: some View {
ZStack(alignment: .center) {
VStack {
Spacer()
HStack {
Spacer()
ProgressView()
Spacer()
}
Spacer()
}
}
.background(Color.black.opacity(0.40))
.transition(.opacity)
}
2022-11-21 08:31:32 +00:00
}