mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-26 18:21:00 +00:00
StatusRowViewModel: Cleanup
This commit is contained in:
parent
d2d297f019
commit
15b7954705
8 changed files with 51 additions and 49 deletions
|
@ -128,11 +128,13 @@ public final class StatusDataController: StatusDataControlling {
|
|||
isBookmarked.toggle()
|
||||
let id = remoteStatus ?? status.id
|
||||
let endpoint = isBookmarked ? Statuses.bookmark(id: id) : Statuses.unbookmark(id: id)
|
||||
objectWillChange.send()
|
||||
do {
|
||||
let status: Status = try await client.post(endpoint: endpoint)
|
||||
updateFrom(status: status, publishUpdate: true)
|
||||
} catch {
|
||||
isBookmarked.toggle()
|
||||
objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ public struct StatusRowView: View {
|
|||
|
||||
public var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
let status: AnyStatus = viewModel.status.reblog ?? viewModel.status
|
||||
if viewModel.isFiltered, let filter = viewModel.filter {
|
||||
switch filter.filter.filterAction {
|
||||
case .warn:
|
||||
|
@ -45,9 +44,9 @@ public struct StatusRowView: View {
|
|||
theme.avatarPosition == .leading
|
||||
{
|
||||
Button {
|
||||
viewModel.routerPath.navigate(to: .accountDetailWithAccount(account: status.account))
|
||||
viewModel.routerPath.navigate(to: .accountDetailWithAccount(account: viewModel.finalStatus.account))
|
||||
} label: {
|
||||
AvatarView(url: status.account.avatar, size: .status)
|
||||
AvatarView(url: viewModel.finalStatus.account.avatar, size: .status)
|
||||
}
|
||||
}
|
||||
VStack(alignment: .leading) {
|
||||
|
@ -56,11 +55,10 @@ public struct StatusRowView: View {
|
|||
StatusRowReplyView(viewModel: viewModel)
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
let status: AnyStatus = viewModel.status.reblog ?? viewModel.status
|
||||
if !isCompact {
|
||||
StatusRowHeaderView(status: status, viewModel: viewModel)
|
||||
StatusRowHeaderView(viewModel: viewModel)
|
||||
}
|
||||
StatusRowContentView(status: status, viewModel: viewModel)
|
||||
StatusRowContentView(viewModel: viewModel)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
viewModel.navigateToDetail()
|
||||
|
|
|
@ -12,6 +12,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
let isFocused: Bool
|
||||
let isRemote: Bool
|
||||
let showActions: Bool
|
||||
let finalStatus: AnyStatus
|
||||
|
||||
@Published var isPinned: Bool
|
||||
@Published var embeddedStatus: Status?
|
||||
|
@ -49,7 +50,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
private func recalcCollapse() {
|
||||
let hasContentWarning = !status.spoilerText.asRawText.isEmpty
|
||||
let showCollapseButton = collapseLongPosts && isCollapsed && !hasContentWarning
|
||||
&& (status.reblog?.content ?? status.content).asRawText.unicodeScalars.count > collapseThresholdLength
|
||||
&& finalStatus.content.asRawText.unicodeScalars.count > collapseThresholdLength
|
||||
let newlineLimit = showCollapseButton && isCollapsed ? collapsedLines : nil
|
||||
if newlineLimit != lineLimit {
|
||||
lineLimit = newlineLimit
|
||||
|
@ -62,7 +63,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
private var seen = false
|
||||
|
||||
var filter: Filtered? {
|
||||
status.reblog?.filtered?.first ?? status.filtered?.first
|
||||
finalStatus.filtered?.first
|
||||
}
|
||||
|
||||
var isThread: Bool {
|
||||
|
@ -91,6 +92,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
showActions: Bool = true)
|
||||
{
|
||||
self.status = status
|
||||
self.finalStatus = status.reblog ?? status
|
||||
self.client = client
|
||||
self.routerPath = routerPath
|
||||
self.isFocused = isFocused
|
||||
|
@ -104,7 +106,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
if UserPreferences.shared.autoExpandSpoilers {
|
||||
displaySpoiler = false
|
||||
} else {
|
||||
displaySpoiler = !(status.reblog?.spoilerText.asRawText ?? status.spoilerText.asRawText).isEmpty
|
||||
displaySpoiler = !finalStatus.spoilerText.asRawText.isEmpty
|
||||
}
|
||||
|
||||
|
||||
|
@ -142,7 +144,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
|
||||
func navigateToDetail() {
|
||||
guard !isFocused else { return }
|
||||
if isRemote, let url = URL(string: status.reblog?.url ?? status.url ?? "") {
|
||||
if isRemote, let url = URL(string: finalStatus.url ?? "") {
|
||||
routerPath.navigate(to: .remoteStatusDetail(url: url))
|
||||
} else {
|
||||
routerPath.navigate(to: .statusDetailWithStatus(status: status.reblogAsAsStatus ?? status))
|
||||
|
@ -178,7 +180,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
}
|
||||
|
||||
private func embededStatusURL() -> URL? {
|
||||
let content = status.reblog?.content ?? status.content
|
||||
let content = finalStatus.content
|
||||
if !content.statusesURLs.isEmpty,
|
||||
let url = content.statusesURLs.first,
|
||||
!StatusEmbedCache.shared.badStatusesURLs.contains(url),
|
||||
|
@ -237,7 +239,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
guard client.isAuth else { return }
|
||||
isPinned = true
|
||||
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: finalStatus.id))
|
||||
updateFromStatus(status: status)
|
||||
} catch {
|
||||
isPinned = false
|
||||
|
@ -248,7 +250,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
guard client.isAuth else { return }
|
||||
isPinned = false
|
||||
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: finalStatus.id))
|
||||
updateFromStatus(status: status)
|
||||
} catch {
|
||||
isPinned = true
|
||||
|
@ -279,7 +281,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
}
|
||||
|
||||
func getStatusLang() -> String? {
|
||||
status.reblog?.language ?? status.language
|
||||
finalStatus.language
|
||||
}
|
||||
|
||||
func translate(userLang: String) async {
|
||||
|
@ -288,7 +290,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
isLoadingTranslation = true
|
||||
}
|
||||
// We first use instance translation API if available.
|
||||
let translation: StatusTranslation = try await client.post(endpoint: Statuses.translate(id: status.reblog?.id ?? status.id,
|
||||
let translation: StatusTranslation = try await client.post(endpoint: Statuses.translate(id: finalStatus.id,
|
||||
lang: userLang))
|
||||
withAnimation {
|
||||
self.translation = translation
|
||||
|
@ -298,8 +300,8 @@ public class StatusRowViewModel: ObservableObject {
|
|||
// If not or fail we use Ice Cubes own DeepL client.
|
||||
let deepLClient = DeepLClient()
|
||||
let translation = try? await deepLClient.request(target: userLang,
|
||||
source: status.language,
|
||||
text: status.reblog?.content.asRawText ?? status.content.asRawText)
|
||||
source: finalStatus.language,
|
||||
text: finalStatus.content.asRawText)
|
||||
withAnimation {
|
||||
self.translation = translation
|
||||
isLoadingTranslation = false
|
||||
|
@ -308,7 +310,7 @@ public class StatusRowViewModel: ObservableObject {
|
|||
}
|
||||
|
||||
func fetchRemoteStatus() async -> Bool {
|
||||
guard isRemote, let remoteStatusURL = URL(string: status.reblog?.url ?? status.url ?? "") else { return false }
|
||||
guard isRemote, let remoteStatusURL = URL(string: finalStatus.url ?? "") else { return false }
|
||||
isLoadingRemoteContent = true
|
||||
let results: SearchResults? = try? await client.get(endpoint: Search.search(query: remoteStatusURL.absoluteString,
|
||||
type: "statuses",
|
||||
|
|
|
@ -94,12 +94,12 @@ struct StatusRowActionsView: View {
|
|||
HStack {
|
||||
ForEach(Action.allCases, id: \.self) { action in
|
||||
if action == .share {
|
||||
if let urlString = viewModel.status.reblog?.url ?? viewModel.status.url,
|
||||
if let urlString = viewModel.finalStatus.url,
|
||||
let url = URL(string: urlString)
|
||||
{
|
||||
ShareLink(item: url,
|
||||
subject: Text(viewModel.status.reblog?.account.safeDisplayName ?? viewModel.status.account.safeDisplayName),
|
||||
message: Text(viewModel.status.reblog?.content.asRawText ?? viewModel.status.content.asRawText)) {
|
||||
subject: Text(viewModel.finalStatus.account.safeDisplayName),
|
||||
message: Text(viewModel.finalStatus.content.asRawText)) {
|
||||
action.image(dataController: statusDataController)
|
||||
}
|
||||
.buttonStyle(.statusAction())
|
||||
|
|
|
@ -9,19 +9,18 @@ struct StatusRowContentView: View {
|
|||
|
||||
@EnvironmentObject private var theme: Theme
|
||||
|
||||
let status: AnyStatus
|
||||
@ObservedObject var viewModel: StatusRowViewModel
|
||||
|
||||
var body: some View {
|
||||
if !status.spoilerText.asRawText.isEmpty {
|
||||
StatusRowSpoilerView(status: status, displaySpoiler: $viewModel.displaySpoiler)
|
||||
if !viewModel.finalStatus.spoilerText.asRawText.isEmpty {
|
||||
StatusRowSpoilerView(status: viewModel.finalStatus, displaySpoiler: $viewModel.displaySpoiler)
|
||||
}
|
||||
|
||||
if !viewModel.displaySpoiler {
|
||||
StatusRowTextView(status: status, viewModel: viewModel)
|
||||
StatusRowTranslateView(status: status, viewModel: viewModel)
|
||||
if let poll = status.poll {
|
||||
StatusPollView(poll: poll, status: status)
|
||||
StatusRowTextView(viewModel: viewModel)
|
||||
StatusRowTranslateView(viewModel: viewModel)
|
||||
if let poll = viewModel.finalStatus.poll {
|
||||
StatusPollView(poll: poll, status: viewModel.finalStatus)
|
||||
}
|
||||
|
||||
if !reasons.contains(.placeholder),
|
||||
|
@ -37,10 +36,10 @@ struct StatusRowContentView: View {
|
|||
.transition(.opacity)
|
||||
}
|
||||
|
||||
if !status.mediaAttachments.isEmpty {
|
||||
if !viewModel.finalStatus.mediaAttachments.isEmpty {
|
||||
HStack {
|
||||
StatusRowMediaPreviewView(attachments: status.mediaAttachments,
|
||||
sensitive: status.sensitive,
|
||||
StatusRowMediaPreviewView(attachments: viewModel.finalStatus.mediaAttachments,
|
||||
sensitive: viewModel.finalStatus.sensitive,
|
||||
isNotifications: isCompact)
|
||||
if theme.statusDisplayStyle == .compact {
|
||||
Spacer()
|
||||
|
@ -49,12 +48,12 @@ struct StatusRowContentView: View {
|
|||
.padding(.vertical, 4)
|
||||
}
|
||||
|
||||
if let card = status.card,
|
||||
if let card = viewModel.finalStatus.card,
|
||||
!viewModel.isEmbedLoading,
|
||||
!isCompact,
|
||||
theme.statusDisplayStyle != .compact,
|
||||
status.content.statusesURLs.isEmpty,
|
||||
status.mediaAttachments.isEmpty
|
||||
viewModel.finalStatus.content.statusesURLs.isEmpty,
|
||||
viewModel.finalStatus.mediaAttachments.isEmpty
|
||||
{
|
||||
StatusRowCardView(card: card)
|
||||
}
|
||||
|
|
|
@ -7,15 +7,14 @@ struct StatusRowHeaderView: View {
|
|||
@Environment(\.isInCaptureMode) private var isInCaptureMode: Bool
|
||||
@EnvironmentObject private var theme: Theme
|
||||
|
||||
let status: AnyStatus
|
||||
let viewModel: StatusRowViewModel
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center) {
|
||||
Button {
|
||||
viewModel.navigateToAccountDetail(account: status.account)
|
||||
viewModel.navigateToAccountDetail(account: viewModel.finalStatus.account)
|
||||
} label: {
|
||||
accountView(status: status)
|
||||
accountView
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
Spacer()
|
||||
|
@ -25,19 +24,20 @@ struct StatusRowHeaderView: View {
|
|||
}
|
||||
}
|
||||
.accessibilityElement()
|
||||
.accessibilityLabel(Text("\(status.account.displayName)"))
|
||||
.accessibilityLabel(Text("\(viewModel.finalStatus.account.displayName)"))
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func accountView(status: AnyStatus) -> some View {
|
||||
private var accountView: some View {
|
||||
HStack(alignment: .center) {
|
||||
if theme.avatarPosition == .top {
|
||||
AvatarView(url: status.account.avatar, size: .status)
|
||||
AvatarView(url: viewModel.finalStatus.account.avatar, size: .status)
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
HStack(alignment: .firstTextBaseline, spacing: 2) {
|
||||
Group {
|
||||
EmojiTextApp(.init(stringValue: status.account.safeDisplayName), emojis: status.account.emojis)
|
||||
EmojiTextApp(.init(stringValue: viewModel.finalStatus.account.safeDisplayName),
|
||||
emojis: viewModel.finalStatus.account.emojis)
|
||||
.font(.scaledSubheadline)
|
||||
.emojiSize(Font.scaledSubheadlinePointSize)
|
||||
.fontWeight(.semibold)
|
||||
|
@ -52,7 +52,7 @@ struct StatusRowHeaderView: View {
|
|||
.foregroundColor(.gray)
|
||||
.lineLimit(1)
|
||||
} else {
|
||||
Text("@\(theme.displayFullUsername ? status.account.acct : status.account.username)")
|
||||
Text("@\(theme.displayFullUsername ? viewModel.finalStatus.account.acct : viewModel.finalStatus.account.username)")
|
||||
.font(.scaledFootnote)
|
||||
.foregroundColor(.gray)
|
||||
.lineLimit(1)
|
||||
|
@ -64,7 +64,7 @@ struct StatusRowHeaderView: View {
|
|||
.foregroundColor(.gray)
|
||||
.lineLimit(1)
|
||||
} else if theme.displayFullUsername, theme.avatarPosition == .leading {
|
||||
Text("@\(status.account.acct)")
|
||||
Text("@\(viewModel.finalStatus.account.acct)")
|
||||
.font(.scaledFootnote)
|
||||
.foregroundColor(.gray)
|
||||
.lineLimit(1)
|
||||
|
@ -84,7 +84,7 @@ struct StatusRowHeaderView: View {
|
|||
}
|
||||
|
||||
private var dateView: Text {
|
||||
Text(status.createdAt.relativeFormatted) +
|
||||
Text(viewModel.finalStatus.createdAt.relativeFormatted) +
|
||||
Text(" ⸱ ") +
|
||||
Text(Image(systemName: viewModel.status.visibility.iconName))
|
||||
}
|
||||
|
|
|
@ -7,17 +7,19 @@ struct StatusRowTextView: View {
|
|||
@EnvironmentObject private var theme: Theme
|
||||
@EnvironmentObject private var preferences: UserPreferences
|
||||
|
||||
let status: AnyStatus
|
||||
@ObservedObject var viewModel: StatusRowViewModel
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
EmojiTextApp(status.content, emojis: status.emojis, language: status.language, lineLimit: viewModel.lineLimit)
|
||||
EmojiTextApp(viewModel.finalStatus.content,
|
||||
emojis: viewModel.finalStatus.emojis,
|
||||
language: viewModel.finalStatus.language,
|
||||
lineLimit: viewModel.lineLimit)
|
||||
.font(.scaledBody)
|
||||
.emojiSize(Font.scaledBodyPointSize)
|
||||
.environment(\.openURL, OpenURLAction { url in
|
||||
viewModel.routerPath.handleStatus(status: status, url: url)
|
||||
viewModel.routerPath.handleStatus(status: viewModel.finalStatus, url: url)
|
||||
})
|
||||
Spacer()
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ struct StatusRowTranslateView: View {
|
|||
|
||||
@EnvironmentObject private var preferences: UserPreferences
|
||||
|
||||
let status: AnyStatus
|
||||
@ObservedObject var viewModel: StatusRowViewModel
|
||||
|
||||
private var shouldShowTranslateButton: Bool {
|
||||
|
@ -16,7 +15,7 @@ struct StatusRowTranslateView: View {
|
|||
|
||||
if let userLang = preferences.serverPreferences?.postLanguage,
|
||||
preferences.showTranslateButton,
|
||||
!status.content.asRawText.isEmpty,
|
||||
!viewModel.finalStatus.content.asRawText.isEmpty,
|
||||
viewModel.translation == nil
|
||||
{
|
||||
return userLang != statusLang
|
||||
|
|
Loading…
Reference in a new issue