This commit is contained in:
spaced4ndy
2026-07-03 14:33:12 +04:00
parent c4f83eeb6d
commit 371ee6dcdf
8 changed files with 76 additions and 13 deletions
@@ -1096,8 +1096,8 @@ object ChatController {
suspend fun apiReorderChatTags(rh: Long?, tagIds: List<Long>) = sendCommandOkResp(rh, CC.ApiReorderChatTags(tagIds))
suspend fun apiSendMessages(rh: Long?, type: ChatType, id: Long, scope: GroupChatScope?, sendAsGroup: Boolean = false, live: Boolean = false, ttl: Int? = null, composedMessages: List<ComposedMessage>): List<AChatItem>? {
val cmd = CC.ApiSendMessages(type, id, scope, sendAsGroup, live, ttl, composedMessages)
suspend fun apiSendMessages(rh: Long?, type: ChatType, id: Long, scope: GroupChatScope?, sendAsGroup: Boolean = false, live: Boolean = false, ttl: Int? = null, sign: Boolean = false, composedMessages: List<ComposedMessage>): List<AChatItem>? {
val cmd = CC.ApiSendMessages(type, id, scope, sendAsGroup, live, ttl, sign, composedMessages)
return processSendMessageCmd(rh, cmd)
}
@@ -3782,7 +3782,7 @@ sealed class CC {
class ApiGetChat(val type: ChatType, val id: Long, val scope: GroupChatScope?, val contentTag: MsgContentTag?, val pagination: ChatPagination, val search: String = ""): CC()
class ApiGetChatContentTypes(val type: ChatType, val id: Long, val scope: GroupChatScope?): CC()
class ApiGetChatItemInfo(val type: ChatType, val id: Long, val scope: GroupChatScope?, val itemId: Long): CC()
class ApiSendMessages(val type: ChatType, val id: Long, val scope: GroupChatScope?, val sendAsGroup: Boolean, val live: Boolean, val ttl: Int?, val composedMessages: List<ComposedMessage>): CC()
class ApiSendMessages(val type: ChatType, val id: Long, val scope: GroupChatScope?, val sendAsGroup: Boolean, val live: Boolean, val ttl: Int?, val sign: Boolean, val composedMessages: List<ComposedMessage>): CC()
class ApiCreateChatTag(val tag: ChatTagData): CC()
class ApiSetChatTags(val type: ChatType, val id: Long, val tagIds: List<Long>): CC()
class ApiDeleteChatTag(val tagId: Long): CC()
@@ -3980,7 +3980,7 @@ sealed class CC {
is ApiSendMessages -> {
val msgs = json.encodeToString(composedMessages)
val ttlStr = if (ttl != null) "$ttl" else "default"
"/_send ${chatRef(type, id, scope)}${if (sendAsGroup) "(as_group=on)" else ""} live=${onOff(live)} ttl=${ttlStr} json $msgs"
"/_send ${chatRef(type, id, scope)}${if (sendAsGroup) "(as_group=on)" else ""} live=${onOff(live)} ttl=${ttlStr} sign=${onOff(sign)} json $msgs"
}
is ApiCreateChatTag -> "/_create tag ${json.encodeToString(tag)}"
is ApiSetChatTags -> "/_tags ${chatRef(type, id, scope = null)} ${tagIds.joinToString(",")}"
@@ -115,7 +115,9 @@ data class ComposeState(
val useLinkPreviews: Boolean,
val mentions: MentionedMembers = emptyMap(),
// the max file size the user may attach, raised by their active badge unless the chat is incognito; kept in sync on chat switch
val maxFileSize: Long = getMaxFileSize(FileProtocol.XFTP)
val maxFileSize: Long = getMaxFileSize(FileProtocol.XFTP),
// per-send opt-in to sign the message (relay channels only); resets on send/chat change, not persisted
val sign: Boolean = false
) {
constructor(editingItem: ChatItem, liveMessage: LiveMessage? = null, useLinkPreviews: Boolean): this(
ComposeMessage(
@@ -559,6 +561,7 @@ fun ComposeView(
sendAsGroup = cInfo.sendAsGroup,
live = live,
ttl = ttl,
sign = composeState.value.sign,
composedMessages = listOf(ComposedMessage(file, quoted, mc, mentions))
)
if (!chatItems.isNullOrEmpty()) {
@@ -1390,6 +1393,8 @@ fun ComposeView(
allowVoiceToContact = ::allowVoiceToContact,
sendButtonColor = sendButtonColor,
timedMessageAllowed = timedMessageAllowed,
showSign = (chat.chatInfo as? ChatInfo.Group)?.groupInfo?.useRelays == true,
sendAsGroup = chat.chatInfo.sendAsGroup,
customDisappearingMessageTimePref = chatModel.controller.appPrefs.customDisappearingMessageTime,
placeholder = if (userCantSendReason.value != null) "" else placeholder ?: composeState.value.placeholder,
sendMessage = { ttl ->
@@ -49,6 +49,8 @@ fun SendMsgView(
sendButtonColor: Color = MaterialTheme.colors.primary,
allowVoiceToContact: () -> Unit,
timedMessageAllowed: Boolean = false,
showSign: Boolean = false,
sendAsGroup: Boolean = false,
customDisappearingMessageTimePref: SharedPreference<Int>? = null,
placeholder: String,
sendMessage: (Int?) -> Unit,
@@ -207,6 +209,25 @@ fun SendMsgView(
)
}
}
if (showSign && !cs.editing) {
menuItems.add {
ItemAction(
generalGetString(if (cs.sign) MR.strings.signing_message else MR.strings.sign_message),
painterResource(MR.images.ic_verified),
onClick = {
val nowOn = !composeState.value.sign
composeState.value = composeState.value.copy(sign = nowOn)
if (nowOn) {
AlertManager.shared.showAlertMsg(
title = generalGetString(MR.strings.sign_message),
text = generalGetString(if (sendAsGroup) MR.strings.sign_message_as_channel_desc else MR.strings.sign_message_desc)
)
}
showDropdown.value = false
}
)
}
}
}
return menuItems
@@ -752,6 +752,10 @@
<string name="send_disappearing_message_5_minutes">5 minutes</string>
<string name="send_disappearing_message_custom_time">Custom time</string>
<string name="send_disappearing_message_send">Send</string>
<string name="sign_message">Sign message</string>
<string name="signing_message">Signing message</string>
<string name="sign_message_desc">A signature is transferable, non-repudiable proof that you authored this message — it confirms authorship and integrity, not timing, order, or completeness.</string>
<string name="sign_message_as_channel_desc">A signature is transferable, non-repudiable proof that you authored this message — it confirms authorship and integrity, not timing, order, or completeness. Signing a post sent as the channel also reveals you as its author.</string>
<string name="live_message">Live message!</string>
<string name="send_live_message_desc">Send a live message - it will update for the recipient(s) as you type it</string>
<string name="send_verb">Send</string>