mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-04-27 02:14:45 +00:00
Enhance the context menu for private messages (#1053)
* Enhance the message context menu A direct message can now directly be bookmarked, the author can be publicly mentioned and reported. Signed-off-by: Paul Schuetz <pa.schuetz@web.de> * Add options to the conversation list context menu Since the latest message is shown in the conversation list, the user can now interact with this message via the context menu similar to the messages in the conversation history. The "conversation" class had to be modified since bookmarking and liking a message would have led to a race condition (depending on the server) when fetching the conversations afterwards, so the only affected the message is now immediately updated. Signed-off-by: Paul Schuetz <pa.schuetz@web.de> * Remove child view models The child views models are removed, and the list row now only uses the conversation object managed by the list view model. Signed-off-by: Paul Schuetz <pa.schuetz@web.de> * Make unmodified var let The last state-var of a conversation isn't modified, instead, a new conversation is created. Therefore, the var is now a let. Signed-off-by: Paul Schuetz <pa.schuetz@web.de> --------- Signed-off-by: Paul Schuetz <pa.schuetz@web.de>
This commit is contained in:
parent
2ba2675ae4
commit
06629cc397
23 changed files with 171 additions and 26 deletions
|
@ -296,6 +296,7 @@
|
||||||
"conversations.error.title" = "Памылка падчас загрузкі вашых паведамленняў";
|
"conversations.error.title" = "Памылка падчас загрузкі вашых паведамленняў";
|
||||||
"conversations.navigation-title" = "Непасрэдныя паведамленні";
|
"conversations.navigation-title" = "Непасрэдныя паведамленні";
|
||||||
"conversations.new.message.placeholder" = "Новае паведамленне";
|
"conversations.new.message.placeholder" = "Новае паведамленне";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld допісы ад %lld удзельнікаў";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld допісы ад %lld удзельнікаў";
|
||||||
|
|
|
@ -290,6 +290,7 @@
|
||||||
"conversations.error.title" = "S'ha produït un error";
|
"conversations.error.title" = "S'ha produït un error";
|
||||||
"conversations.navigation-title" = "Missatges directes";
|
"conversations.navigation-title" = "Missatges directes";
|
||||||
"conversations.new.message.placeholder" = "Missatge nou";
|
"conversations.new.message.placeholder" = "Missatge nou";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld publicacions de %lld participants";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld publicacions de %lld participants";
|
||||||
|
|
|
@ -292,6 +292,7 @@
|
||||||
"conversations.error.title" = "Ein Fehler ist aufgetreten";
|
"conversations.error.title" = "Ein Fehler ist aufgetreten";
|
||||||
"conversations.navigation-title" = "Direkte Nachrichten";
|
"conversations.navigation-title" = "Direkte Nachrichten";
|
||||||
"conversations.new.message.placeholder" = "Neue Nachricht";
|
"conversations.new.message.placeholder" = "Neue Nachricht";
|
||||||
|
"conversations.latest.message" = "Letzte Nachricht";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld Beiträge von %lld Teilnehmenden";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld Beiträge von %lld Teilnehmenden";
|
||||||
|
|
|
@ -293,6 +293,7 @@
|
||||||
"conversations.error.title" = "An error occurred";
|
"conversations.error.title" = "An error occurred";
|
||||||
"conversations.navigation-title" = "Direct Messages";
|
"conversations.navigation-title" = "Direct Messages";
|
||||||
"conversations.new.message.placeholder" = "New Message";
|
"conversations.new.message.placeholder" = "New Message";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld posts from %lld participants";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld posts from %lld participants";
|
||||||
|
|
|
@ -292,6 +292,7 @@
|
||||||
"conversations.error.title" = "An error occurred";
|
"conversations.error.title" = "An error occurred";
|
||||||
"conversations.navigation-title" = "Direct Messages";
|
"conversations.navigation-title" = "Direct Messages";
|
||||||
"conversations.new.message.placeholder" = "New Message";
|
"conversations.new.message.placeholder" = "New Message";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld posts from %lld participants";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld posts from %lld participants";
|
||||||
|
|
|
@ -292,6 +292,7 @@
|
||||||
"conversations.error.title" = "Ha ocurrido un error";
|
"conversations.error.title" = "Ha ocurrido un error";
|
||||||
"conversations.navigation-title" = "Mensajes directos";
|
"conversations.navigation-title" = "Mensajes directos";
|
||||||
"conversations.new.message.placeholder" = "Mensajes nuevos";
|
"conversations.new.message.placeholder" = "Mensajes nuevos";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld publicaciones de %lld participantes";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld publicaciones de %lld participantes";
|
||||||
|
|
|
@ -292,6 +292,7 @@
|
||||||
"conversations.error.title" = "Errorea gertatu da";
|
"conversations.error.title" = "Errorea gertatu da";
|
||||||
"conversations.navigation-title" = "Mezu zuzenak";
|
"conversations.navigation-title" = "Mezu zuzenak";
|
||||||
"conversations.new.message.placeholder" = "Mezu berria";
|
"conversations.new.message.placeholder" = "Mezu berria";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.theme.navigation-title" = "Gai hautatzailea";
|
"design.theme.navigation-title" = "Gai hautatzailea";
|
||||||
|
|
|
@ -291,6 +291,7 @@
|
||||||
"conversations.error.title" = "Une erreur est survenue";
|
"conversations.error.title" = "Une erreur est survenue";
|
||||||
"conversations.navigation-title" = "Messages directs";
|
"conversations.navigation-title" = "Messages directs";
|
||||||
"conversations.new.message.placeholder" = "Nouveau message";
|
"conversations.new.message.placeholder" = "Nouveau message";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld publications de %lld participants";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld publications de %lld participants";
|
||||||
|
|
|
@ -292,6 +292,7 @@
|
||||||
"conversations.error.title" = "Si è verificato in errore";
|
"conversations.error.title" = "Si è verificato in errore";
|
||||||
"conversations.navigation-title" = "Messaggi diretti";
|
"conversations.navigation-title" = "Messaggi diretti";
|
||||||
"conversations.new.message.placeholder" = "Nuovo messaggio";
|
"conversations.new.message.placeholder" = "Nuovo messaggio";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld post da %lld partecipanti";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld post da %lld partecipanti";
|
||||||
|
|
|
@ -291,6 +291,7 @@
|
||||||
"conversations.error.title" = "エラーが発生しました";
|
"conversations.error.title" = "エラーが発生しました";
|
||||||
"conversations.navigation-title" = "ダイレクトメッセージ";
|
"conversations.navigation-title" = "ダイレクトメッセージ";
|
||||||
"conversations.new.message.placeholder" = "新しいメッセージ";
|
"conversations.new.message.placeholder" = "新しいメッセージ";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld トゥートの投稿 %lld 人が投稿している";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld トゥートの投稿 %lld 人が投稿している";
|
||||||
|
|
|
@ -292,6 +292,7 @@
|
||||||
"conversations.error.title" = "오류";
|
"conversations.error.title" = "오류";
|
||||||
"conversations.navigation-title" = "다이렉트 메시지";
|
"conversations.navigation-title" = "다이렉트 메시지";
|
||||||
"conversations.new.message.placeholder" = "새 메시지";
|
"conversations.new.message.placeholder" = "새 메시지";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld개 글 (%lld명이 이야기 중)";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld개 글 (%lld명이 이야기 중)";
|
||||||
|
|
|
@ -291,6 +291,7 @@
|
||||||
"conversations.error.title" = "En feil oppstod";
|
"conversations.error.title" = "En feil oppstod";
|
||||||
"conversations.navigation-title" = "Direktemeldinger";
|
"conversations.navigation-title" = "Direktemeldinger";
|
||||||
"conversations.new.message.placeholder" = "Ny melding";
|
"conversations.new.message.placeholder" = "Ny melding";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld innlegg fra %lld deltakere";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld innlegg fra %lld deltakere";
|
||||||
|
|
|
@ -289,6 +289,7 @@
|
||||||
"conversations.error.title" = "Er heeft zich een fout voorgedaan";
|
"conversations.error.title" = "Er heeft zich een fout voorgedaan";
|
||||||
"conversations.navigation-title" = "Directe berichten";
|
"conversations.navigation-title" = "Directe berichten";
|
||||||
"conversations.new.message.placeholder" = "Nieuw bericht";
|
"conversations.new.message.placeholder" = "Nieuw bericht";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld posts van %lld deelnemers";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld posts van %lld deelnemers";
|
||||||
|
|
|
@ -289,6 +289,7 @@
|
||||||
"conversations.error.title" = "Wystąpił błąd";
|
"conversations.error.title" = "Wystąpił błąd";
|
||||||
"conversations.navigation-title" = "Wiadomości bezpośrednie";
|
"conversations.navigation-title" = "Wiadomości bezpośrednie";
|
||||||
"conversations.new.message.placeholder" = "Nowa wiadomość";
|
"conversations.new.message.placeholder" = "Nowa wiadomość";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.theme.navigation-title" = "Wybór motywu";
|
"design.theme.navigation-title" = "Wybór motywu";
|
||||||
|
|
|
@ -291,6 +291,7 @@
|
||||||
"conversations.error.title" = "Ocorreu um erro";
|
"conversations.error.title" = "Ocorreu um erro";
|
||||||
"conversations.navigation-title" = "Mensagens diretas";
|
"conversations.navigation-title" = "Mensagens diretas";
|
||||||
"conversations.new.message.placeholder" = "Nova mensagem";
|
"conversations.new.message.placeholder" = "Nova mensagem";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld postagens de %lld participantes";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld postagens de %lld participantes";
|
||||||
|
|
|
@ -287,6 +287,7 @@
|
||||||
"conversations.error.title" = "Bir hata oluştu";
|
"conversations.error.title" = "Bir hata oluştu";
|
||||||
"conversations.navigation-title" = "Direkt Mesajlar";
|
"conversations.navigation-title" = "Direkt Mesajlar";
|
||||||
"conversations.new.message.placeholder" = "Yeni Mesaj";
|
"conversations.new.message.placeholder" = "Yeni Mesaj";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld katılımcılar tarafından %lld gönderi";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld katılımcılar tarafından %lld gönderi";
|
||||||
|
|
|
@ -292,6 +292,7 @@
|
||||||
"conversations.error.title" = "Виникла халепа";
|
"conversations.error.title" = "Виникла халепа";
|
||||||
"conversations.navigation-title" = "Особисті повідомлення";
|
"conversations.navigation-title" = "Особисті повідомлення";
|
||||||
"conversations.new.message.placeholder" = "Нове повідомлення";
|
"conversations.new.message.placeholder" = "Нове повідомлення";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld дописів від %lld учасників";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld дописів від %lld учасників";
|
||||||
|
|
|
@ -290,6 +290,7 @@
|
||||||
"conversations.error.title" = "出错啦";
|
"conversations.error.title" = "出错啦";
|
||||||
"conversations.navigation-title" = "私信";
|
"conversations.navigation-title" = "私信";
|
||||||
"conversations.new.message.placeholder" = "新消息";
|
"conversations.new.message.placeholder" = "新消息";
|
||||||
|
"conversations.latest.message" = "Latest Message";
|
||||||
|
|
||||||
// MARK: Package: DesignSystem
|
// MARK: Package: DesignSystem
|
||||||
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld 条嘟文来自 %lld 个参与者";
|
"design.tag.n-posts-from-n-participants %lld %lld" = "%lld 条嘟文来自 %lld 个参与者";
|
||||||
|
|
|
@ -16,6 +16,7 @@ struct ConversationMessageView: View {
|
||||||
let conversation: Conversation
|
let conversation: Conversation
|
||||||
|
|
||||||
@State private var isLiked: Bool = false
|
@State private var isLiked: Bool = false
|
||||||
|
@State private var isBookmarked: Bool = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
let isOwnMessage = message.account.id == currentAccount.account?.id
|
let isOwnMessage = message.account.id == currentAccount.account?.id
|
||||||
|
@ -82,6 +83,7 @@ struct ConversationMessageView: View {
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
isLiked = message.favourited == true
|
isLiked = message.favourited == true
|
||||||
|
isBookmarked = message.bookmarked == true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,6 +117,22 @@ struct ConversationMessageView: View {
|
||||||
Label(isLiked ? "status.action.unfavorite" : "status.action.favorite",
|
Label(isLiked ? "status.action.unfavorite" : "status.action.favorite",
|
||||||
systemImage: isLiked ? "star.fill" : "star")
|
systemImage: isLiked ? "star.fill" : "star")
|
||||||
}
|
}
|
||||||
|
Button { Task {
|
||||||
|
do {
|
||||||
|
let status: Status
|
||||||
|
if isBookmarked {
|
||||||
|
status = try await client.post(endpoint: Statuses.unbookmark(id: message.id))
|
||||||
|
} else {
|
||||||
|
status = try await client.post(endpoint: Statuses.bookmark(id: message.id))
|
||||||
|
}
|
||||||
|
withAnimation {
|
||||||
|
isBookmarked = status.bookmarked == true
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
} } label: {
|
||||||
|
Label(isBookmarked ? "status.action.unbookmark" : "status.action.bookmark",
|
||||||
|
systemImage: isBookmarked ? "bookmark.fill" : "bookmark")
|
||||||
|
}
|
||||||
Divider()
|
Divider()
|
||||||
if message.account.id == currentAccount.account?.id {
|
if message.account.id == currentAccount.account?.id {
|
||||||
Button("status.action.delete", role: .destructive) {
|
Button("status.action.delete", role: .destructive) {
|
||||||
|
@ -122,6 +140,21 @@ struct ConversationMessageView: View {
|
||||||
_ = try await client.delete(endpoint: Statuses.status(id: message.id))
|
_ = try await client.delete(endpoint: Statuses.status(id: message.id))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Section(message.reblog?.account.acct ?? message.account.acct) {
|
||||||
|
Button {
|
||||||
|
routerPath.presentedSheet = .mentionStatusEditor(account: message.reblog?.account ?? message.account, visibility: .pub)
|
||||||
|
} label: {
|
||||||
|
Label("status.action.mention", systemImage: "at")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Section {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
routerPath.presentedSheet = .report(status: message.reblogAsAsStatus ?? message)
|
||||||
|
} label: {
|
||||||
|
Label("status.action.report", systemImage: "exclamationmark.bubble")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,9 @@ struct ConversationsListRow: View {
|
||||||
@EnvironmentObject private var client: Client
|
@EnvironmentObject private var client: Client
|
||||||
@EnvironmentObject private var routerPath: RouterPath
|
@EnvironmentObject private var routerPath: RouterPath
|
||||||
@EnvironmentObject private var theme: Theme
|
@EnvironmentObject private var theme: Theme
|
||||||
|
@EnvironmentObject private var currentAccount: CurrentAccount
|
||||||
let conversation: Conversation
|
|
||||||
|
@Binding var conversation: Conversation
|
||||||
@ObservedObject var viewModel: ConversationsListViewModel
|
@ObservedObject var viewModel: ConversationsListViewModel
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
@ -32,8 +33,8 @@ struct ConversationsListRow: View {
|
||||||
.foregroundColor(theme.tintColor)
|
.foregroundColor(theme.tintColor)
|
||||||
.frame(width: 10, height: 10)
|
.frame(width: 10, height: 10)
|
||||||
}
|
}
|
||||||
if conversation.lastStatus != nil {
|
if let message = conversation.lastStatus {
|
||||||
Text(conversation.lastStatus!.createdAt.relativeFormatted)
|
Text(message.createdAt.relativeFormatted)
|
||||||
.font(.scaledFootnote)
|
.font(.scaledFootnote)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +92,34 @@ struct ConversationsListRow: View {
|
||||||
Label("conversations.action.mark-read", systemImage: "eye")
|
Label("conversations.action.mark-read", systemImage: "eye")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let message = conversation.lastStatus {
|
||||||
|
Section("conversations.latest.message") {
|
||||||
|
Button {
|
||||||
|
UIPasteboard.general.string = message.content.asRawText
|
||||||
|
} label: {
|
||||||
|
Label("status.action.copy-text", systemImage: "doc.on.doc")
|
||||||
|
}
|
||||||
|
likeAndBookmark
|
||||||
|
}
|
||||||
|
Divider()
|
||||||
|
if message.account.id != currentAccount.account?.id {
|
||||||
|
Section(message.reblog?.account.acct ?? message.account.acct) {
|
||||||
|
Button {
|
||||||
|
routerPath.presentedSheet = .mentionStatusEditor(account: message.reblog?.account ?? message.account, visibility: .pub)
|
||||||
|
} label: {
|
||||||
|
Label("status.action.mention", systemImage: "at")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Section {
|
||||||
|
Button(role: .destructive) {
|
||||||
|
routerPath.presentedSheet = .report(status: message.reblogAsAsStatus ?? message)
|
||||||
|
} label: {
|
||||||
|
Label("status.action.report", systemImage: "exclamationmark.bubble")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Button(role: .destructive) {
|
Button(role: .destructive) {
|
||||||
Task {
|
Task {
|
||||||
await viewModel.delete(conversation: conversation)
|
await viewModel.delete(conversation: conversation)
|
||||||
|
@ -99,4 +128,24 @@ struct ConversationsListRow: View {
|
||||||
Label("conversations.action.delete", systemImage: "trash")
|
Label("conversations.action.delete", systemImage: "trash")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var likeAndBookmark: some View {
|
||||||
|
Button {
|
||||||
|
Task {
|
||||||
|
await viewModel.favorite(conversation: conversation)
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Label(conversation.lastStatus?.favourited ?? false ? "status.action.unfavorite" : "status.action.favorite",
|
||||||
|
systemImage: conversation.lastStatus?.favourited ?? false ? "star.fill" : "star")
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
Task {
|
||||||
|
await viewModel.bookmark(conversation: conversation)
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Label(conversation.lastStatus?.bookmarked ?? false ? "status.action.unbookmark" : "status.action.bookmark",
|
||||||
|
systemImage: conversation.lastStatus?.bookmarked ?? false ? "bookmark.fill" : "bookmark")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,29 +16,30 @@ public struct ConversationsListView: View {
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
|
||||||
private var conversations: [Conversation] {
|
private var conversations: Binding<[Conversation]> {
|
||||||
if viewModel.isLoadingFirstPage {
|
if viewModel.isLoadingFirstPage {
|
||||||
return Conversation.placeholders()
|
return Binding.constant(Conversation.placeholders())
|
||||||
|
} else {
|
||||||
|
return $viewModel.conversations
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return viewModel.conversations
|
|
||||||
}
|
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack {
|
LazyVStack {
|
||||||
Group {
|
Group {
|
||||||
if !conversations.isEmpty || viewModel.isLoadingFirstPage {
|
if !conversations.isEmpty || viewModel.isLoadingFirstPage {
|
||||||
ForEach(conversations) { conversation in
|
ForEach(conversations) { $conversation in
|
||||||
if viewModel.isLoadingFirstPage {
|
if viewModel.isLoadingFirstPage {
|
||||||
ConversationsListRow(conversation: conversation, viewModel: viewModel)
|
ConversationsListRow(conversation: $conversation, viewModel: viewModel)
|
||||||
.padding(.horizontal, .layoutPadding)
|
.padding(.horizontal, .layoutPadding)
|
||||||
.redacted(reason: .placeholder)
|
.redacted(reason: .placeholder)
|
||||||
} else {
|
} else {
|
||||||
ConversationsListRow(conversation: conversation, viewModel: viewModel)
|
ConversationsListRow(conversation: $conversation, viewModel: viewModel)
|
||||||
.padding(.horizontal, .layoutPadding)
|
.padding(.horizontal, .layoutPadding)
|
||||||
}
|
}
|
||||||
Divider()
|
Divider()
|
||||||
}
|
}
|
||||||
} else if conversations.isEmpty && !viewModel.isLoadingFirstPage && !viewModel.isError {
|
} else if conversations.isEmpty && !viewModel.isLoadingFirstPage && !viewModel.isError {
|
||||||
EmptyView(iconName: "tray",
|
EmptyView(iconName: "tray",
|
||||||
title: "conversations.empty.title",
|
title: "conversations.empty.title",
|
||||||
|
|
|
@ -58,13 +58,50 @@ class ConversationsListViewModel: ObservableObject {
|
||||||
await fetchConversations()
|
await fetchConversations()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func favorite(conversation: Conversation) async {
|
||||||
|
guard let client, let message = conversation.lastStatus else { return }
|
||||||
|
let endpoint: Endpoint
|
||||||
|
if message.favourited ?? false {
|
||||||
|
endpoint = Statuses.unfavorite(id: message.id)
|
||||||
|
} else {
|
||||||
|
endpoint = Statuses.favorite(id: message.id)
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
let status: Status = try await client.post(endpoint: endpoint)
|
||||||
|
updateConversationWithNewLastStatus(conversation: conversation, newLastStatus: status)
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
func bookmark(conversation: Conversation) async {
|
||||||
|
guard let client, let message = conversation.lastStatus else { return }
|
||||||
|
let endpoint: Endpoint
|
||||||
|
if message.bookmarked ?? false {
|
||||||
|
endpoint = Statuses.unbookmark(id: message.id)
|
||||||
|
} else {
|
||||||
|
endpoint = Statuses.bookmark(id: message.id)
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
let status: Status = try await client.post(endpoint: endpoint)
|
||||||
|
updateConversationWithNewLastStatus(conversation: conversation, newLastStatus: status)
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateConversationWithNewLastStatus(conversation: Conversation, newLastStatus: Status) {
|
||||||
|
let newConversation = Conversation(id: conversation.id, unread: conversation.unread, lastStatus: newLastStatus, accounts: conversation.accounts)
|
||||||
|
updateConversations(conversation: newConversation)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateConversations(conversation: Conversation) {
|
||||||
|
if let index = conversations.firstIndex(where: { $0.id == conversation.id }) {
|
||||||
|
conversations.remove(at: index)
|
||||||
|
}
|
||||||
|
conversations.insert(conversation, at: 0)
|
||||||
|
conversations = conversations.sorted(by: { ($0.lastStatus?.createdAt.asDate ?? Date.now) > ($1.lastStatus?.createdAt.asDate ?? Date.now) })
|
||||||
|
}
|
||||||
|
|
||||||
func handleEvent(event: any StreamEvent) {
|
func handleEvent(event: any StreamEvent) {
|
||||||
if let event = event as? StreamEventConversation {
|
if let event = event as? StreamEventConversation {
|
||||||
if let index = conversations.firstIndex(where: { $0.id == event.conversation.id }) {
|
updateConversations(conversation: event.conversation)
|
||||||
conversations.remove(at: index)
|
|
||||||
}
|
|
||||||
conversations.insert(event.conversation, at: 0)
|
|
||||||
conversations = conversations.sorted(by: { ($0.lastStatus?.createdAt.asDate ?? Date.now) > ($1.lastStatus?.createdAt.asDate ?? Date.now) })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,13 @@ public struct Conversation: Identifiable, Decodable, Hashable, Equatable {
|
||||||
public let lastStatus: Status?
|
public let lastStatus: Status?
|
||||||
public let accounts: [Account]
|
public let accounts: [Account]
|
||||||
|
|
||||||
|
public init(id: String, unread: Bool, lastStatus: Status? = nil, accounts: [Account]) {
|
||||||
|
self.id = id
|
||||||
|
self.unread = unread
|
||||||
|
self.lastStatus = lastStatus
|
||||||
|
self.accounts = accounts
|
||||||
|
}
|
||||||
|
|
||||||
public static func placeholder() -> Conversation {
|
public static func placeholder() -> Conversation {
|
||||||
.init(id: UUID().uuidString, unread: false, lastStatus: .placeholder(), accounts: [.placeholder()])
|
.init(id: UUID().uuidString, unread: false, lastStatus: .placeholder(), accounts: [.placeholder()])
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue