From d1dde3d0c8674c33b81e709aca1e29dfc2525873 Mon Sep 17 00:00:00 2001 From: spaced4ndy <8711996+spaced4ndy@users.noreply.github.com> Date: Thu, 16 May 2024 14:12:58 +0400 Subject: [PATCH] ui: support message forwarding with custom ttl (#4192) --- apps/ios/Shared/Model/SimpleXAPI.swift | 4 ++-- .../Views/Chat/ComposeMessage/ComposeView.swift | 9 +++++---- .../Views/Chat/ComposeMessage/SendMessageView.swift | 3 +-- apps/ios/SimpleXChat/APITypes.swift | 6 ++++-- .../kotlin/chat/simplex/common/model/SimpleXAPI.kt | 11 +++++++---- .../chat/simplex/common/views/chat/ComposeView.kt | 9 +++++---- .../chat/simplex/common/views/chat/SendMsgView.kt | 2 +- 7 files changed, 25 insertions(+), 19 deletions(-) diff --git a/apps/ios/Shared/Model/SimpleXAPI.swift b/apps/ios/Shared/Model/SimpleXAPI.swift index 4a982e18bb..b270b939c4 100644 --- a/apps/ios/Shared/Model/SimpleXAPI.swift +++ b/apps/ios/Shared/Model/SimpleXAPI.swift @@ -341,8 +341,8 @@ func apiGetChatItemInfo(type: ChatType, id: Int64, itemId: Int64) async throws - throw r } -func apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64) async -> ChatItem? { - let cmd: ChatCommand = .apiForwardChatItem(toChatType: toChatType, toChatId: toChatId, fromChatType: fromChatType, fromChatId: fromChatId, itemId: itemId) +func apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64, ttl: Int?) async -> ChatItem? { + let cmd: ChatCommand = .apiForwardChatItem(toChatType: toChatType, toChatId: toChatId, fromChatType: fromChatType, fromChatId: fromChatId, itemId: itemId, ttl: ttl) return await processSendMessageCmd(toChatType: toChatType, cmd: cmd) } diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift index 6cf9df782b..3f1824cd6a 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/ComposeView.swift @@ -712,9 +712,9 @@ struct ComposeView: View { if chat.chatInfo.contact?.nextSendGrpInv ?? false { await sendMemberContactInvitation() } else if case let .forwardingItem(ci, fromChatInfo) = composeState.contextItem { - sent = await forwardItem(ci, fromChatInfo) + sent = await forwardItem(ci, fromChatInfo, ttl) if !composeState.message.isEmpty { - sent = await send(checkLinkPreview(), quoted: sent?.id, live: false, ttl: nil) + sent = await send(checkLinkPreview(), quoted: sent?.id, live: false, ttl: ttl) } } else if case let .editingItem(ci) = composeState.contextItem { sent = await updateMessage(ci, live: live) @@ -890,13 +890,14 @@ struct ComposeView: View { return nil } - func forwardItem(_ forwardedItem: ChatItem, _ fromChatInfo: ChatInfo) async -> ChatItem? { + func forwardItem(_ forwardedItem: ChatItem, _ fromChatInfo: ChatInfo, _ ttl: Int?) async -> ChatItem? { if let chatItem = await apiForwardChatItem( toChatType: chat.chatInfo.chatType, toChatId: chat.chatInfo.apiId, fromChatType: fromChatInfo.chatType, fromChatId: fromChatInfo.apiId, - itemId: forwardedItem.id + itemId: forwardedItem.id, + ttl: ttl ) { await MainActor.run { chatModel.addChatItem(chat.chatInfo, chatItem) diff --git a/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift b/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift index 8b528a201c..a180efbd28 100644 --- a/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift +++ b/apps/ios/Shared/Views/Chat/ComposeMessage/SendMessageView.swift @@ -224,8 +224,7 @@ struct SendMessageView: View { @ViewBuilder private func sendButtonContextMenuItems() -> some View { if composeState.liveMessage == nil, - !composeState.editing, - !composeState.forwarding { + !composeState.editing { if case .noContextItem = composeState.contextItem, !composeState.voicePreview, let send = sendLiveMessage, diff --git a/apps/ios/SimpleXChat/APITypes.swift b/apps/ios/SimpleXChat/APITypes.swift index 6a4340ea40..980a474c17 100644 --- a/apps/ios/SimpleXChat/APITypes.swift +++ b/apps/ios/SimpleXChat/APITypes.swift @@ -48,7 +48,7 @@ public enum ChatCommand { case apiDeleteChatItem(type: ChatType, id: Int64, itemId: Int64, mode: CIDeleteMode) case apiDeleteMemberChatItem(groupId: Int64, groupMemberId: Int64, itemId: Int64) case apiChatItemReaction(type: ChatType, id: Int64, itemId: Int64, add: Bool, reaction: MsgReaction) - case apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64) + case apiForwardChatItem(toChatType: ChatType, toChatId: Int64, fromChatType: ChatType, fromChatId: Int64, itemId: Int64, ttl: Int?) case apiGetNtfToken case apiRegisterToken(token: DeviceToken, notificationMode: NotificationsMode) case apiVerifyToken(token: DeviceToken, nonce: String, code: String) @@ -192,7 +192,9 @@ public enum ChatCommand { case let .apiDeleteChatItem(type, id, itemId, mode): return "/_delete item \(ref(type, id)) \(itemId) \(mode.rawValue)" case let .apiDeleteMemberChatItem(groupId, groupMemberId, itemId): return "/_delete member item #\(groupId) \(groupMemberId) \(itemId)" case let .apiChatItemReaction(type, id, itemId, add, reaction): return "/_reaction \(ref(type, id)) \(itemId) \(onOff(add)) \(encodeJSON(reaction))" - case let .apiForwardChatItem(toChatType, toChatId, fromChatType, fromChatId, itemId): return "/_forward \(ref(toChatType, toChatId)) \(ref(fromChatType, fromChatId)) \(itemId)" + case let .apiForwardChatItem(toChatType, toChatId, fromChatType, fromChatId, itemId, ttl): + let ttlStr = ttl != nil ? "\(ttl!)" : "default" + return "/_forward \(ref(toChatType, toChatId)) \(ref(fromChatType, fromChatId)) \(itemId) ttl=\(ttlStr)" case .apiGetNtfToken: return "/_ntf get " case let .apiRegisterToken(token, notificationMode): return "/_ntf register \(token.cmdString) \(notificationMode.rawValue)" case let .apiVerifyToken(token, nonce, code): return "/_ntf verify \(token.cmdString) \(nonce) \(code)" diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt index e548ac3e6e..57b26f4bc1 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/model/SimpleXAPI.kt @@ -782,8 +782,8 @@ object ChatController { } } - suspend fun apiForwardChatItem(rh: Long?, toChatType: ChatType, toChatId: Long, fromChatType: ChatType, fromChatId: Long, itemId: Long): ChatItem? { - val cmd = CC.ApiForwardChatItem(toChatType, toChatId, fromChatType, fromChatId, itemId) + suspend fun apiForwardChatItem(rh: Long?, toChatType: ChatType, toChatId: Long, fromChatType: ChatType, fromChatId: Long, itemId: Long, ttl: Int?): ChatItem? { + val cmd = CC.ApiForwardChatItem(toChatType, toChatId, fromChatType, fromChatId, itemId, ttl) return processSendMessageCmd(rh, cmd)?.chatItem } @@ -2428,7 +2428,7 @@ sealed class CC { class ApiDeleteChatItem(val type: ChatType, val id: Long, val itemId: Long, val mode: CIDeleteMode): CC() class ApiDeleteMemberChatItem(val groupId: Long, val groupMemberId: Long, val itemId: Long): CC() class ApiChatItemReaction(val type: ChatType, val id: Long, val itemId: Long, val add: Boolean, val reaction: MsgReaction): CC() - class ApiForwardChatItem(val toChatType: ChatType, val toChatId: Long, val fromChatType: ChatType, val fromChatId: Long, val itemId: Long): CC() + class ApiForwardChatItem(val toChatType: ChatType, val toChatId: Long, val fromChatType: ChatType, val fromChatId: Long, val itemId: Long, val ttl: Int?): CC() class ApiNewGroup(val userId: Long, val incognito: Boolean, val groupProfile: GroupProfile): CC() class ApiAddMember(val groupId: Long, val contactId: Long, val memberRole: GroupMemberRole): CC() class ApiJoinGroup(val groupId: Long): CC() @@ -2570,7 +2570,10 @@ sealed class CC { is ApiDeleteChatItem -> "/_delete item ${chatRef(type, id)} $itemId ${mode.deleteMode}" is ApiDeleteMemberChatItem -> "/_delete member item #$groupId $groupMemberId $itemId" is ApiChatItemReaction -> "/_reaction ${chatRef(type, id)} $itemId ${onOff(add)} ${json.encodeToString(reaction)}" - is ApiForwardChatItem -> "/_forward ${chatRef(toChatType, toChatId)} ${chatRef(fromChatType, fromChatId)} $itemId" + is ApiForwardChatItem -> { + val ttlStr = if (ttl != null) "$ttl" else "default" + "/_forward ${chatRef(toChatType, toChatId)} ${chatRef(fromChatType, fromChatId)} $itemId ttl=${ttlStr}" + } is ApiNewGroup -> "/_group $userId incognito=${onOff(incognito)} ${json.encodeToString(groupProfile)}" is ApiAddMember -> "/_add #$groupId $contactId ${memberRole.memberRole}" is ApiJoinGroup -> "/_join #$groupId" diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt index 26ff8796d4..d9ea35096b 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/ComposeView.kt @@ -408,14 +408,15 @@ fun ComposeView( composeState.value = composeState.value.copy(inProgress = true) } - suspend fun forwardItem(rhId: Long?, forwardedItem: ChatItem, fromChatInfo: ChatInfo): ChatItem? { + suspend fun forwardItem(rhId: Long?, forwardedItem: ChatItem, fromChatInfo: ChatInfo, ttl: Int?): ChatItem? { val chatItem = controller.apiForwardChatItem( rh = rhId, toChatType = chat.chatInfo.chatType, toChatId = chat.chatInfo.apiId, fromChatType = fromChatInfo.chatType, fromChatId = fromChatInfo.apiId, - itemId = forwardedItem.id + itemId = forwardedItem.id, + ttl = ttl ) if (chatItem != null) { chatModel.addChatItem(rhId, chat.chatInfo, chatItem) @@ -490,9 +491,9 @@ fun ComposeView( sendMemberContactInvitation() sent = null } else if (cs.contextItem is ComposeContextItem.ForwardingItem) { - sent = forwardItem(chat.remoteHostId, cs.contextItem.chatItem, cs.contextItem.fromChatInfo) + sent = forwardItem(chat.remoteHostId, cs.contextItem.chatItem, cs.contextItem.fromChatInfo, ttl = ttl) if (cs.message.isNotEmpty()) { - sent = send(chat, checkLinkPreview(), quoted = sent?.id, live = false, ttl = null) + sent = send(chat, checkLinkPreview(), quoted = sent?.id, live = false, ttl = ttl) } } else if (cs.contextItem is ComposeContextItem.EditingItem) { val ei = cs.contextItem.chatItem diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt index 58705bd00a..779371a07c 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chat/SendMsgView.kt @@ -157,7 +157,7 @@ fun SendMsgView( fun MenuItems(): List<@Composable () -> Unit> { val menuItems = mutableListOf<@Composable () -> Unit>() - if (cs.liveMessage == null && !cs.editing && !cs.forwarding && !nextSendGrpInv || sendMsgEnabled) { + if (cs.liveMessage == null && !cs.editing && !nextSendGrpInv || sendMsgEnabled) { if ( cs.preview !is ComposePreview.VoicePreview && cs.contextItem is ComposeContextItem.NoContextItem &&