Remove Client and RouterPath from StatusRowView env object

This commit is contained in:
Thomas Ricouard 2023-02-15 08:46:14 +01:00
parent 07153e1142
commit d958d10036
15 changed files with 96 additions and 70 deletions

View file

@ -29,7 +29,7 @@ public struct ReportView: View {
} }
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
StatusEmbeddedView(status: status) StatusEmbeddedView(status: status, client: .init(server: ""), routerPath: RouterPath())
.allowsHitTesting(false) .allowsHitTesting(false)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
} }

View file

@ -3,6 +3,7 @@ import Env
import Models import Models
import Status import Status
import SwiftUI import SwiftUI
import Network
struct DisplaySettingsView: View { struct DisplaySettingsView: View {
typealias FontState = Theme.FontState typealias FontState = Theme.FontState
@ -12,7 +13,9 @@ struct DisplaySettingsView: View {
@EnvironmentObject private var userPreferences: UserPreferences @EnvironmentObject private var userPreferences: UserPreferences
@State private var isFontSelectorPresented = false @State private var isFontSelectorPresented = false
private var previewStatusViewModel = StatusRowViewModel(status: Status.placeholder(forSettings: true, language: "la")) // translate from latin button private var previewStatusViewModel = StatusRowViewModel(status: Status.placeholder(forSettings: true, language: "la"),
client: Client(server: ""),
routerPath: RouterPath()) // translate from latin button
var body: some View { var body: some View {
Form { Form {
Section("settings.display.example-toot") { Section("settings.display.example-toot") {

View file

@ -68,7 +68,7 @@ public struct AccountDetailView: View {
if viewModel.selectedTab == .statuses { if viewModel.selectedTab == .statuses {
pinnedPostsView pinnedPostsView
} }
StatusesListView(fetcher: viewModel) StatusesListView(fetcher: viewModel, client: client, routerPath: routerPath)
case .followedTags: case .followedTags:
tagsListView tagsListView
case .lists: case .lists:
@ -336,7 +336,7 @@ public struct AccountDetailView: View {
.listRowSeparator(.hidden) .listRowSeparator(.hidden)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
ForEach(viewModel.pinned) { status in ForEach(viewModel.pinned) { status in
StatusRowView(viewModel: .init(status: status)) StatusRowView(viewModel: .init(status: status, client: client, routerPath: routerPath))
} }
Rectangle() Rectangle()
.fill(theme.secondaryBackgroundColor) .fill(theme.secondaryBackgroundColor)

View file

@ -81,7 +81,7 @@ public struct ExploreView: View {
private var loadingView: some View { private var loadingView: some View {
ForEach(Status.placeholders()) { status in ForEach(Status.placeholders()) { status in
StatusRowView(viewModel: .init(status: status, isCompact: false)) StatusRowView(viewModel: .init(status: status, client: client, routerPath: routerPath, isCompact: false))
.padding(.vertical, 8) .padding(.vertical, 8)
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
@ -112,7 +112,7 @@ public struct ExploreView: View {
if !results.statuses.isEmpty { if !results.statuses.isEmpty {
Section("explore.section.posts") { Section("explore.section.posts") {
ForEach(results.statuses) { status in ForEach(results.statuses) { status in
StatusRowView(viewModel: .init(status: status)) StatusRowView(viewModel: .init(status: status, client: client, routerPath: routerPath))
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
.padding(.vertical, 8) .padding(.vertical, 8)
} }
@ -184,7 +184,7 @@ public struct ExploreView: View {
Section("explore.section.trending.posts") { Section("explore.section.trending.posts") {
ForEach(viewModel.trendingStatuses ForEach(viewModel.trendingStatuses
.prefix(upTo: viewModel.trendingStatuses.count > 3 ? 3 : viewModel.trendingStatuses.count)) { status in .prefix(upTo: viewModel.trendingStatuses.count > 3 ? 3 : viewModel.trendingStatuses.count)) { status in
StatusRowView(viewModel: .init(status: status, isCompact: false)) StatusRowView(viewModel: .init(status: status, client: client, routerPath: routerPath, isCompact: false))
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
.padding(.vertical, 8) .padding(.vertical, 8)
} }
@ -192,7 +192,7 @@ public struct ExploreView: View {
NavigationLink { NavigationLink {
List { List {
ForEach(viewModel.trendingStatuses) { status in ForEach(viewModel.trendingStatuses) { status in
StatusRowView(viewModel: .init(status: status, isCompact: false)) StatusRowView(viewModel: .init(status: status, client: client, routerPath: routerPath, isCompact: false))
.listRowBackground(theme.primaryBackgroundColor) .listRowBackground(theme.primaryBackgroundColor)
.padding(.vertical, 8) .padding(.vertical, 8)
} }

View file

@ -4,8 +4,10 @@ import Env
import Models import Models
import Status import Status
import SwiftUI import SwiftUI
import Network
struct NotificationRowView: View { struct NotificationRowView: View {
@EnvironmentObject private var client: Client
@EnvironmentObject private var currentAccount: CurrentAccount @EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var theme: Theme @EnvironmentObject private var theme: Theme
@EnvironmentObject private var routerPath: RouterPath @EnvironmentObject private var routerPath: RouterPath
@ -132,9 +134,17 @@ struct NotificationRowView: View {
if let status = notification.status { if let status = notification.status {
HStack { HStack {
if type == .mention { if type == .mention {
StatusRowView(viewModel: .init(status: status, isCompact: true, showActions: true)) StatusRowView(viewModel: .init(status: status,
client: client,
routerPath: routerPath,
isCompact: true,
showActions: true))
} else { } else {
StatusRowView(viewModel: .init(status: status, isCompact: true, showActions: false)) StatusRowView(viewModel: .init(status: status,
client: client,
routerPath: routerPath,
isCompact: true,
showActions: false))
.lineLimit(4) .lineLimit(4)
.foregroundColor(.gray) .foregroundColor(.gray)
} }

View file

@ -43,7 +43,7 @@ public struct StatusDetailView: View {
case let .display(status, context, date): case let .display(status, context, date):
if !context.ancestors.isEmpty { if !context.ancestors.isEmpty {
ForEach(context.ancestors) { ancestor in ForEach(context.ancestors) { ancestor in
StatusRowView(viewModel: .init(status: ancestor, isCompact: false)) StatusRowView(viewModel: .init(status: ancestor, client: client, routerPath: routerPath, isCompact: false))
} }
} }
@ -52,7 +52,7 @@ public struct StatusDetailView: View {
if !context.descendants.isEmpty { if !context.descendants.isEmpty {
ForEach(context.descendants) { descendant in ForEach(context.descendants) { descendant in
StatusRowView(viewModel: .init(status: descendant, isCompact: false)) StatusRowView(viewModel: .init(status: descendant, client: client, routerPath: routerPath, isCompact: false))
} }
} }
@ -108,6 +108,8 @@ public struct StatusDetailView: View {
private func makeCurrentStatusView(status: Status) -> some View { private func makeCurrentStatusView(status: Status) -> some View {
StatusRowView(viewModel: .init(status: status, StatusRowView(viewModel: .init(status: status,
client: client,
routerPath: routerPath,
isCompact: false, isCompact: false,
isFocused: true)) isFocused: true))
.overlay { .overlay {
@ -135,7 +137,7 @@ public struct StatusDetailView: View {
private var loadingDetailView: some View { private var loadingDetailView: some View {
ForEach(Status.placeholders()) { status in ForEach(Status.placeholders()) { status in
StatusRowView(viewModel: .init(status: status, isCompact: false)) StatusRowView(viewModel: .init(status: status, client: client, routerPath: routerPath, isCompact: false))
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
} }
} }

View file

@ -15,6 +15,7 @@ public struct StatusEditorView: View {
@EnvironmentObject private var theme: Theme @EnvironmentObject private var theme: Theme
@EnvironmentObject private var client: Client @EnvironmentObject private var client: Client
@EnvironmentObject private var currentAccount: CurrentAccount @EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var routerPath: RouterPath
@Environment(\.dismiss) private var dismiss @Environment(\.dismiss) private var dismiss
@StateObject private var viewModel: StatusEditorViewModel @StateObject private var viewModel: StatusEditorViewModel
@ -45,13 +46,13 @@ public struct StatusEditorView: View {
.padding(.horizontal, .layoutPadding) .padding(.horizontal, .layoutPadding)
StatusEditorMediaView(viewModel: viewModel) StatusEditorMediaView(viewModel: viewModel)
if let status = viewModel.embeddedStatus { if let status = viewModel.embeddedStatus {
StatusEmbeddedView(status: status) StatusEmbeddedView(status: status, client: client, routerPath: routerPath)
.padding(.horizontal, .layoutPadding) .padding(.horizontal, .layoutPadding)
.disabled(true) .disabled(true)
} else if let status = viewModel.replyToStatus { } else if let status = viewModel.replyToStatus {
Divider() Divider()
.padding(.top, 20) .padding(.top, 20)
StatusEmbeddedView(status: status) StatusEmbeddedView(status: status, client: client, routerPath: routerPath)
.padding(.horizontal, .layoutPadding) .padding(.horizontal, .layoutPadding)
.disabled(true) .disabled(true)
} }

View file

@ -2,22 +2,32 @@ import DesignSystem
import EmojiText import EmojiText
import Models import Models
import SwiftUI import SwiftUI
import Env
import Network
@MainActor @MainActor
public struct StatusEmbeddedView: View { public struct StatusEmbeddedView: View {
@EnvironmentObject private var theme: Theme @EnvironmentObject private var theme: Theme
public let status: Status public let status: Status
public let client: Client
public let routerPath: RouterPath
public init(status: Status) { public init(status: Status, client: Client, routerPath: RouterPath) {
self.status = status self.status = status
self.client = client
self.routerPath = routerPath
} }
public var body: some View { public var body: some View {
HStack { HStack {
VStack(alignment: .leading) { VStack(alignment: .leading) {
makeAccountView(account: status.reblog?.account ?? status.account) makeAccountView(account: status.reblog?.account ?? status.account)
StatusRowView(viewModel: .init(status: status, isCompact: true, showActions: false)) StatusRowView(viewModel: .init(status: status,
client: client,
routerPath: routerPath,
isCompact: true,
showActions: false))
} }
Spacer() Spacer()
} }

View file

@ -3,23 +3,28 @@ import Env
import Models import Models
import Shimmer import Shimmer
import SwiftUI import SwiftUI
import Network
public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher { public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
@EnvironmentObject private var theme: Theme @EnvironmentObject private var theme: Theme
@ObservedObject private var fetcher: Fetcher @ObservedObject private var fetcher: Fetcher
private let isRemote: Bool private let isRemote: Bool
private let routerPath: RouterPath
private let client: Client
public init(fetcher: Fetcher, isRemote: Bool = false) { public init(fetcher: Fetcher, client: Client, routerPath: RouterPath, isRemote: Bool = false) {
self.fetcher = fetcher self.fetcher = fetcher
self.isRemote = isRemote self.isRemote = isRemote
self.client = client
self.routerPath = routerPath
} }
public var body: some View { public var body: some View {
switch fetcher.statusesState { switch fetcher.statusesState {
case .loading: case .loading:
ForEach(Status.placeholders()) { status in ForEach(Status.placeholders()) { status in
StatusRowView(viewModel: .init(status: status, isCompact: false)) StatusRowView(viewModel: .init(status: status, client: client, routerPath: routerPath, isCompact: false))
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
} }
case .error: case .error:
@ -35,7 +40,7 @@ public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
case let .display(statuses, nextPageState): case let .display(statuses, nextPageState):
ForEach(statuses, id: \.viewId) { status in ForEach(statuses, id: \.viewId) { status in
let viewModel = StatusRowViewModel(status: status, isCompact: false, isRemote: isRemote) let viewModel = StatusRowViewModel(status: status, client: client, routerPath: routerPath, isCompact: false, isRemote: isRemote)
if viewModel.filter?.filter.filterAction != .hide { if viewModel.filter?.filter.filterAction != .hide {
StatusRowView(viewModel: viewModel) StatusRowView(viewModel: viewModel)
.id(status.id) .id(status.id)

View file

@ -6,7 +6,6 @@ import SwiftUI
struct StatusActionsView: View { struct StatusActionsView: View {
@EnvironmentObject private var theme: Theme @EnvironmentObject private var theme: Theme
@EnvironmentObject private var routerPath: RouterPath
@ObservedObject var viewModel: StatusRowViewModel @ObservedObject var viewModel: StatusRowViewModel
@MainActor @MainActor
@ -108,7 +107,7 @@ struct StatusActionsView: View {
HapticManager.shared.fireHaptic(of: .notification(.success)) HapticManager.shared.fireHaptic(of: .notification(.success))
switch action { switch action {
case .respond: case .respond:
routerPath.presentedSheet = .replyToStatusEditor(status: viewModel.localStatus ?? viewModel.status) viewModel.routerPath.presentedSheet = .replyToStatusEditor(status: viewModel.localStatus ?? viewModel.status)
case .favorite: case .favorite:
if viewModel.isFavorited { if viewModel.isFavorited {
await viewModel.unFavorite() await viewModel.unFavorite()

View file

@ -6,7 +6,6 @@ struct StatusRowContextMenu: View {
@EnvironmentObject private var preferences: UserPreferences @EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var account: CurrentAccount @EnvironmentObject private var account: CurrentAccount
@EnvironmentObject private var currentInstance: CurrentInstance @EnvironmentObject private var currentInstance: CurrentInstance
@EnvironmentObject private var routerPath: RouterPath
@ObservedObject var viewModel: StatusRowViewModel @ObservedObject var viewModel: StatusRowViewModel
@ -41,7 +40,7 @@ struct StatusRowContextMenu: View {
systemImage: "bookmark") systemImage: "bookmark")
} }
Button { Button {
routerPath.presentedSheet = .replyToStatusEditor(status: viewModel.status) viewModel.routerPath.presentedSheet = .replyToStatusEditor(status: viewModel.status)
} label: { } label: {
Label("status.action.reply", systemImage: "arrowshape.turn.up.left") Label("status.action.reply", systemImage: "arrowshape.turn.up.left")
} }
@ -49,7 +48,7 @@ struct StatusRowContextMenu: View {
if viewModel.status.visibility == .pub, !viewModel.isRemote { if viewModel.status.visibility == .pub, !viewModel.isRemote {
Button { Button {
routerPath.presentedSheet = .quoteStatusEditor(status: viewModel.status) viewModel.routerPath.presentedSheet = .quoteStatusEditor(status: viewModel.status)
} label: { } label: {
Label("status.action.quote", systemImage: "quote.bubble") Label("status.action.quote", systemImage: "quote.bubble")
} }
@ -110,7 +109,7 @@ struct StatusRowContextMenu: View {
} }
if currentInstance.isEditSupported { if currentInstance.isEditSupported {
Button { Button {
routerPath.presentedSheet = .editStatusEditor(status: viewModel.status) viewModel.routerPath.presentedSheet = .editStatusEditor(status: viewModel.status)
} label: { } label: {
Label("status.action.edit", systemImage: "pencil") Label("status.action.edit", systemImage: "pencil")
} }
@ -123,12 +122,12 @@ struct StatusRowContextMenu: View {
if !viewModel.isRemote { if !viewModel.isRemote {
Section(viewModel.status.account.acct) { Section(viewModel.status.account.acct) {
Button { Button {
routerPath.presentedSheet = .mentionStatusEditor(account: viewModel.status.account, visibility: .pub) viewModel.routerPath.presentedSheet = .mentionStatusEditor(account: viewModel.status.account, visibility: .pub)
} label: { } label: {
Label("status.action.mention", systemImage: "at") Label("status.action.mention", systemImage: "at")
} }
Button { Button {
routerPath.presentedSheet = .mentionStatusEditor(account: viewModel.status.account, visibility: .direct) viewModel.routerPath.presentedSheet = .mentionStatusEditor(account: viewModel.status.account, visibility: .direct)
} label: { } label: {
Label("status.action.message", systemImage: "tray.full") Label("status.action.message", systemImage: "tray.full")
} }
@ -136,7 +135,7 @@ struct StatusRowContextMenu: View {
} }
Section { Section {
Button(role: .destructive) { Button(role: .destructive) {
routerPath.presentedSheet = .report(status: viewModel.status.reblogAsAsStatus ?? viewModel.status) viewModel.routerPath.presentedSheet = .report(status: viewModel.status.reblogAsAsStatus ?? viewModel.status)
} label: { } label: {
Label("status.action.report", systemImage: "exclamationmark.bubble") Label("status.action.report", systemImage: "exclamationmark.bubble")
} }

View file

@ -5,7 +5,6 @@ import SwiftUI
struct StatusRowDetailView: View { struct StatusRowDetailView: View {
@Environment(\.openURL) private var openURL @Environment(\.openURL) private var openURL
@EnvironmentObject private var routerPath: RouterPath
@ObservedObject var viewModel: StatusRowViewModel @ObservedObject var viewModel: StatusRowViewModel
@ -40,7 +39,7 @@ struct StatusRowDetailView: View {
Spacer() Spacer()
} }
.onTapGesture { .onTapGesture {
routerPath.presentedSheet = .statusEditHistory(status: viewModel.status.id) viewModel.routerPath.presentedSheet = .statusEditHistory(status: viewModel.status.id)
} }
.underline() .underline()
.font(.scaledCaption) .font(.scaledCaption)
@ -50,7 +49,7 @@ struct StatusRowDetailView: View {
if viewModel.favoritesCount > 0 { if viewModel.favoritesCount > 0 {
Divider() Divider()
Button { Button {
routerPath.navigate(to: .favoritedBy(id: viewModel.status.id)) viewModel.routerPath.navigate(to: .favoritedBy(id: viewModel.status.id))
} label: { } label: {
HStack { HStack {
Text("status.summary.n-favorites \(viewModel.favoritesCount)") Text("status.summary.n-favorites \(viewModel.favoritesCount)")
@ -66,7 +65,7 @@ struct StatusRowDetailView: View {
if viewModel.reblogsCount > 0 { if viewModel.reblogsCount > 0 {
Divider() Divider()
Button { Button {
routerPath.navigate(to: .rebloggedBy(id: viewModel.status.id)) viewModel.routerPath.navigate(to: .rebloggedBy(id: viewModel.status.id))
} label: { } label: {
HStack { HStack {
Text("status.summary.n-boosts \(viewModel.reblogsCount)") Text("status.summary.n-boosts \(viewModel.reblogsCount)")

View file

@ -10,8 +10,6 @@ public struct StatusRowView: View {
@Environment(\.redactionReasons) private var reasons @Environment(\.redactionReasons) private var reasons
@EnvironmentObject private var preferences: UserPreferences @EnvironmentObject private var preferences: UserPreferences
@EnvironmentObject private var theme: Theme @EnvironmentObject private var theme: Theme
@EnvironmentObject private var client: Client
@EnvironmentObject private var routerPath: RouterPath
@StateObject var viewModel: StatusRowViewModel @StateObject var viewModel: StatusRowViewModel
public init(viewModel: StatusRowViewModel) { public init(viewModel: StatusRowViewModel) {
@ -42,7 +40,7 @@ public struct StatusRowView: View {
let status: AnyStatus = viewModel.status.reblog ?? viewModel.status let status: AnyStatus = viewModel.status.reblog ?? viewModel.status
{ {
Button { Button {
routerPath.navigate(to: .accountDetailWithAccount(account: status.account)) viewModel.routerPath.navigate(to: .accountDetailWithAccount(account: status.account))
} label: { } label: {
AvatarView(url: status.account.avatar, size: .status) AvatarView(url: status.account.avatar, size: .status)
} }
@ -59,7 +57,7 @@ public struct StatusRowView: View {
.tint(viewModel.isFocused ? theme.tintColor : .gray) .tint(viewModel.isFocused ? theme.tintColor : .gray)
.contentShape(Rectangle()) .contentShape(Rectangle())
.onTapGesture { .onTapGesture {
viewModel.navigateToDetail(routerPath: routerPath) viewModel.navigateToDetail()
} }
} }
} }
@ -68,7 +66,6 @@ public struct StatusRowView: View {
.onAppear { .onAppear {
viewModel.markSeen() viewModel.markSeen()
if reasons.isEmpty { if reasons.isEmpty {
viewModel.client = client
if !viewModel.isCompact, viewModel.embeddedStatus == nil { if !viewModel.isCompact, viewModel.embeddedStatus == nil {
Task { Task {
await viewModel.loadEmbeddedStatus() await viewModel.loadEmbeddedStatus()
@ -105,7 +102,7 @@ public struct StatusRowView: View {
Color.clear Color.clear
.contentShape(Rectangle()) .contentShape(Rectangle())
.onTapGesture { .onTapGesture {
viewModel.navigateToDetail(routerPath: routerPath) viewModel.navigateToDetail()
} }
} }
.overlay { .overlay {
@ -138,7 +135,7 @@ public struct StatusRowView: View {
// Add the individual mentions as accessibility actions // Add the individual mentions as accessibility actions
ForEach(viewModel.status.mentions, id: \.id) { mention in ForEach(viewModel.status.mentions, id: \.id) { mention in
Button("@\(mention.username)") { Button("@\(mention.username)") {
routerPath.navigate(to: .accountDetail(id: mention.id)) viewModel.routerPath.navigate(to: .accountDetail(id: mention.id))
} }
} }
@ -149,7 +146,7 @@ public struct StatusRowView: View {
} }
Button("@\(viewModel.status.account.username)") { Button("@\(viewModel.status.account.username)") {
routerPath.navigate(to: .accountDetail(id: viewModel.status.account.id)) viewModel.routerPath.navigate(to: .accountDetail(id: viewModel.status.account.id))
} }
contextMenu contextMenu
@ -187,7 +184,7 @@ public struct StatusRowView: View {
.foregroundColor(.gray) .foregroundColor(.gray)
.fontWeight(.semibold) .fontWeight(.semibold)
.onTapGesture { .onTapGesture {
viewModel.navigateToAccountDetail(account: viewModel.status.account, routerPath: routerPath) viewModel.navigateToAccountDetail(account: viewModel.status.account)
} }
} }
} }
@ -206,7 +203,7 @@ public struct StatusRowView: View {
.foregroundColor(.gray) .foregroundColor(.gray)
.fontWeight(.semibold) .fontWeight(.semibold)
.onTapGesture { .onTapGesture {
viewModel.navigateToMention(mention: mention, routerPath: routerPath) viewModel.navigateToMention(mention: mention)
} }
} }
} }
@ -217,7 +214,7 @@ public struct StatusRowView: View {
if !viewModel.isCompact { if !viewModel.isCompact {
HStack(alignment: .center) { HStack(alignment: .center) {
Button { Button {
viewModel.navigateToAccountDetail(account: status.account, routerPath: routerPath) viewModel.navigateToAccountDetail(account: status.account)
} label: { } label: {
accountView(status: status) accountView(status: status)
} }
@ -232,13 +229,13 @@ public struct StatusRowView: View {
makeStatusContentView(status: status) makeStatusContentView(status: status)
.contentShape(Rectangle()) .contentShape(Rectangle())
.onTapGesture { .onTapGesture {
viewModel.navigateToDetail(routerPath: routerPath) viewModel.navigateToDetail()
} }
} }
} }
.accessibilityElement(children: viewModel.isFocused ? .contain : .combine) .accessibilityElement(children: viewModel.isFocused ? .contain : .combine)
.accessibilityAction { .accessibilityAction {
viewModel.navigateToDetail(routerPath: routerPath) viewModel.navigateToDetail()
} }
} }
@ -278,7 +275,7 @@ public struct StatusRowView: View {
EmojiTextApp(status.content, emojis: status.emojis, language: status.language) EmojiTextApp(status.content, emojis: status.emojis, language: status.language)
.font(.scaledBody) .font(.scaledBody)
.environment(\.openURL, OpenURLAction { url in .environment(\.openURL, OpenURLAction { url in
routerPath.handleStatus(status: status, url: url) viewModel.routerPath.handleStatus(status: status, url: url)
}) })
Spacer() Spacer()
} }
@ -437,10 +434,10 @@ public struct StatusRowView: View {
if !viewModel.isCompact, !viewModel.isEmbedLoading, if !viewModel.isCompact, !viewModel.isEmbedLoading,
let embed = viewModel.embeddedStatus let embed = viewModel.embeddedStatus
{ {
StatusEmbeddedView(status: embed) StatusEmbeddedView(status: embed, client: viewModel.client, routerPath: viewModel.routerPath)
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
} else if viewModel.isEmbedLoading, !viewModel.isCompact { } else if viewModel.isEmbedLoading, !viewModel.isCompact {
StatusEmbeddedView(status: .placeholder()) StatusEmbeddedView(status: .placeholder(), client: viewModel.client, routerPath: viewModel.routerPath)
.redacted(reason: .placeholder) .redacted(reason: .placeholder)
.shimmering() .shimmering()
} }
@ -528,7 +525,7 @@ public struct StatusRowView: View {
private func makeSwipeButtonForRouterPath(action: StatusAction, destination: SheetDestinations) -> some View { private func makeSwipeButtonForRouterPath(action: StatusAction, destination: SheetDestinations) -> some View {
Button { Button {
HapticManager.shared.fireHaptic(of: .notification(.success)) HapticManager.shared.fireHaptic(of: .notification(.success))
routerPath.presentedSheet = destination viewModel.routerPath.presentedSheet = destination
} label: { } label: {
makeSwipeLabel(action: action, style: preferences.swipeActionsIconStyle) makeSwipeLabel(action: action, style: preferences.swipeActionsIconStyle)
} }

View file

@ -55,15 +55,20 @@ public class StatusRowViewModel: ObservableObject {
} }
} }
var client: Client? let client: Client
let routerPath: RouterPath
public init(status: Status, public init(status: Status,
client: Client,
routerPath: RouterPath,
isCompact: Bool = false, isCompact: Bool = false,
isFocused: Bool = false, isFocused: Bool = false,
isRemote: Bool = false, isRemote: Bool = false,
showActions: Bool = true) showActions: Bool = true)
{ {
self.status = status self.status = status
self.client = client
self.routerPath = routerPath
self.isCompact = isCompact self.isCompact = isCompact
self.isFocused = isFocused self.isFocused = isFocused
self.isRemote = isRemote self.isRemote = isRemote
@ -95,7 +100,7 @@ public class StatusRowViewModel: ObservableObject {
} }
} }
func navigateToDetail(routerPath: RouterPath) { func navigateToDetail() {
guard !isFocused else { return } guard !isFocused else { return }
if isRemote, let url = URL(string: status.reblog?.url ?? status.url ?? "") { if isRemote, let url = URL(string: status.reblog?.url ?? status.url ?? "") {
routerPath.navigate(to: .remoteStatusDetail(url: url)) routerPath.navigate(to: .remoteStatusDetail(url: url))
@ -104,7 +109,7 @@ public class StatusRowViewModel: ObservableObject {
} }
} }
func navigateToAccountDetail(account: Account, routerPath: RouterPath) { func navigateToAccountDetail(account: Account) {
if isRemote, let url = account.url { if isRemote, let url = account.url {
withAnimation { withAnimation {
isLoadingRemoteContent = true isLoadingRemoteContent = true
@ -118,7 +123,7 @@ public class StatusRowViewModel: ObservableObject {
} }
} }
func navigateToMention(mention: Mention, routerPath: RouterPath) { func navigateToMention(mention: Mention) {
if isRemote { if isRemote {
withAnimation { withAnimation {
isLoadingRemoteContent = true isLoadingRemoteContent = true
@ -133,8 +138,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func loadEmbeddedStatus() async { func loadEmbeddedStatus() async {
guard let client, guard embeddedStatus == nil,
embeddedStatus == nil,
!status.content.statusesURLs.isEmpty, !status.content.statusesURLs.isEmpty,
let url = status.content.statusesURLs.first, let url = status.content.statusesURLs.first,
client.hasConnection(with: url) client.hasConnection(with: url)
@ -167,7 +171,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func favorite() async { func favorite() async {
guard let client, client.isAuth else { return } guard client.isAuth else { return }
isFavorited = true isFavorited = true
favoritesCount += 1 favoritesCount += 1
do { do {
@ -180,7 +184,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func unFavorite() async { func unFavorite() async {
guard let client, client.isAuth else { return } guard client.isAuth else { return }
isFavorited = false isFavorited = false
favoritesCount -= 1 favoritesCount -= 1
do { do {
@ -193,7 +197,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func reblog() async { func reblog() async {
guard let client, client.isAuth else { return } guard client.isAuth else { return }
isReblogged = true isReblogged = true
reblogsCount += 1 reblogsCount += 1
do { do {
@ -206,7 +210,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func unReblog() async { func unReblog() async {
guard let client, client.isAuth else { return } guard client.isAuth else { return }
isReblogged = false isReblogged = false
reblogsCount -= 1 reblogsCount -= 1
do { do {
@ -219,7 +223,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func pin() async { func pin() async {
guard let client, client.isAuth else { return } guard client.isAuth else { return }
isPinned = true isPinned = true
do { do {
let status: Status = try await client.post(endpoint: Statuses.pin(id: status.reblog?.id ?? status.id)) let status: Status = try await client.post(endpoint: Statuses.pin(id: status.reblog?.id ?? status.id))
@ -230,7 +234,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func unPin() async { func unPin() async {
guard let client, client.isAuth else { return } guard client.isAuth else { return }
isPinned = false isPinned = false
do { do {
let status: Status = try await client.post(endpoint: Statuses.unpin(id: status.reblog?.id ?? status.id)) let status: Status = try await client.post(endpoint: Statuses.unpin(id: status.reblog?.id ?? status.id))
@ -241,7 +245,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func bookmark() async { func bookmark() async {
guard let client, client.isAuth else { return } guard client.isAuth else { return }
isBookmarked = true isBookmarked = true
do { do {
let status: Status = try await client.post(endpoint: Statuses.bookmark(id: localStatusId ?? status.reblog?.id ?? status.id)) let status: Status = try await client.post(endpoint: Statuses.bookmark(id: localStatusId ?? status.reblog?.id ?? status.id))
@ -252,7 +256,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func unbookmark() async { func unbookmark() async {
guard let client, client.isAuth else { return } guard client.isAuth else { return }
isBookmarked = false isBookmarked = false
do { do {
let status: Status = try await client.post(endpoint: Statuses.unbookmark(id: localStatusId ?? status.reblog?.id ?? status.id)) let status: Status = try await client.post(endpoint: Statuses.unbookmark(id: localStatusId ?? status.reblog?.id ?? status.id))
@ -263,14 +267,12 @@ public class StatusRowViewModel: ObservableObject {
} }
func delete() async { func delete() async {
guard let client else { return }
do { do {
_ = try await client.delete(endpoint: Statuses.status(id: status.id)) _ = try await client.delete(endpoint: Statuses.status(id: status.id))
} catch {} } catch {}
} }
func fetchActionsAccounts() async { func fetchActionsAccounts() async {
guard let client else { return }
do { do {
favoriters = try await client.get(endpoint: Statuses.favoritedBy(id: status.id, maxId: nil)) favoriters = try await client.get(endpoint: Statuses.favoritedBy(id: status.id, maxId: nil))
rebloggers = try await client.get(endpoint: Statuses.rebloggedBy(id: status.id, maxId: nil)) rebloggers = try await client.get(endpoint: Statuses.rebloggedBy(id: status.id, maxId: nil))
@ -303,7 +305,6 @@ public class StatusRowViewModel: ObservableObject {
} }
private func translate(userLang: String, sourceLang _: String?) async { private func translate(userLang: String, sourceLang _: String?) async {
guard let client else { return }
do { do {
withAnimation { withAnimation {
isLoadingTranslation = true isLoadingTranslation = true
@ -329,7 +330,7 @@ public class StatusRowViewModel: ObservableObject {
} }
func fetchRemoteStatus() async -> Bool { func fetchRemoteStatus() async -> Bool {
guard isRemote, let client, let remoteStatusURL = URL(string: status.reblog?.url ?? status.url ?? "") else { return false } guard isRemote, let remoteStatusURL = URL(string: status.reblog?.url ?? status.url ?? "") else { return false }
isLoadingRemoteContent = true isLoadingRemoteContent = true
let results: SearchResults? = try? await client.get(endpoint: Search.search(query: remoteStatusURL.absoluteString, let results: SearchResults? = try? await client.get(endpoint: Search.search(query: remoteStatusURL.absoluteString,
type: "statuses", type: "statuses",

View file

@ -43,9 +43,9 @@ public struct TimelineView: View {
} }
switch viewModel.timeline { switch viewModel.timeline {
case .remoteLocal: case .remoteLocal:
StatusesListView(fetcher: viewModel, isRemote: true) StatusesListView(fetcher: viewModel, client: client, routerPath: routerPath, isRemote: true)
default: default:
StatusesListView(fetcher: viewModel) StatusesListView(fetcher: viewModel, client: client, routerPath: routerPath)
} }
} }
.id(client.id) .id(client.id)