mobile: send live message when there is any content (#1721)
* ios: send live message when there is any content * android: improve live message logic * fix, refactor * prohibit live messages with quotes
This commit is contained in:
committed by
GitHub
parent
9e3573fc76
commit
a6d7604d21
@@ -259,16 +259,13 @@ class ChatModel(val controller: ChatController) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addLiveChatItemDummy(quotedCItem: ChatItem?, chatInfo: ChatInfo): ChatItem {
|
fun addLiveDummy(chatInfo: ChatInfo): ChatItem {
|
||||||
val quoted = if (quotedCItem?.content?.msgContent != null) {
|
val cItem = ChatItem.liveDummy(chatInfo is ChatInfo.Direct)
|
||||||
CIQuote(chatDir = quotedCItem.chatDir, itemId = quotedCItem.id, sentAt = quotedCItem.meta.createdAt, content = quotedCItem.content.msgContent!!)
|
|
||||||
} else null
|
|
||||||
val cItem = ChatItem.liveChatItemDummy(chatInfo is ChatInfo.Direct, quoted)
|
|
||||||
chatItems.add(cItem)
|
chatItems.add(cItem)
|
||||||
return cItem
|
return cItem
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeLiveChatItemDummy() {
|
fun removeLiveDummy() {
|
||||||
if (chatItems.lastOrNull()?.id == ChatItem.TEMP_LIVE_CHAT_ITEM_ID) {
|
if (chatItems.lastOrNull()?.id == ChatItem.TEMP_LIVE_CHAT_ITEM_ID) {
|
||||||
chatItems.removeLast()
|
chatItems.removeLast()
|
||||||
}
|
}
|
||||||
@@ -1320,7 +1317,7 @@ data class ChatItem (
|
|||||||
file = null
|
file = null
|
||||||
)
|
)
|
||||||
|
|
||||||
fun liveChatItemDummy(direct: Boolean, quoted: CIQuote?): ChatItem = ChatItem(
|
fun liveDummy(direct: Boolean): ChatItem = ChatItem(
|
||||||
chatDir = if (direct) CIDirection.DirectSnd() else CIDirection.GroupSnd(),
|
chatDir = if (direct) CIDirection.DirectSnd() else CIDirection.GroupSnd(),
|
||||||
meta = CIMeta(
|
meta = CIMeta(
|
||||||
itemId = TEMP_LIVE_CHAT_ITEM_ID,
|
itemId = TEMP_LIVE_CHAT_ITEM_ID,
|
||||||
@@ -1336,7 +1333,7 @@ data class ChatItem (
|
|||||||
editable = false
|
editable = false
|
||||||
),
|
),
|
||||||
content = CIContent.SndMsgContent(MsgContent.MCText("")),
|
content = CIContent.SndMsgContent(MsgContent.MCText("")),
|
||||||
quotedItem = quoted,
|
quotedItem = null,
|
||||||
file = null
|
file = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ import chat.simplex.app.ui.theme.HighOrLowlight
|
|||||||
import chat.simplex.app.views.chat.item.*
|
import chat.simplex.app.views.chat.item.*
|
||||||
import chat.simplex.app.views.helpers.*
|
import chat.simplex.app.views.helpers.*
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
@@ -105,6 +104,9 @@ data class ComposeState(
|
|||||||
}
|
}
|
||||||
hasContent && !inProgress
|
hasContent && !inProgress
|
||||||
}
|
}
|
||||||
|
val endLiveDisabled: Boolean
|
||||||
|
get() = liveMessage != null && message.isEmpty() && preview is ComposePreview.NoPreview && contextItem is ComposeContextItem.NoContextItem
|
||||||
|
|
||||||
val linkPreviewAllowed: Boolean
|
val linkPreviewAllowed: Boolean
|
||||||
get() =
|
get() =
|
||||||
when (preview) {
|
when (preview) {
|
||||||
@@ -354,7 +356,7 @@ fun ComposeView(
|
|||||||
chosenContent.value = emptyList()
|
chosenContent.value = emptyList()
|
||||||
chosenAudio.value = null
|
chosenAudio.value = null
|
||||||
chosenFile.value = null
|
chosenFile.value = null
|
||||||
chatModel.removeLiveChatItemDummy()
|
chatModel.removeLiveDummy()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun send(cInfo: ChatInfo, mc: MsgContent, quoted: Long?, file: String? = null, live: Boolean = false): ChatItem? {
|
suspend fun send(cInfo: ChatInfo, mc: MsgContent, quoted: Long?, file: String? = null, live: Boolean = false): ChatItem? {
|
||||||
@@ -572,16 +574,16 @@ fun ComposeView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendLiveMessage() {
|
suspend fun sendLiveMessage() {
|
||||||
val typedMsg = composeState.value.message
|
val cs = composeState.value
|
||||||
val sentMsg = truncateToWords(typedMsg)
|
val typedMsg = cs.message
|
||||||
if (sentMsg.isNotEmpty() && (composeState.value.liveMessage == null || composeState.value.liveMessage?.sent == false)) {
|
if ((cs.sendEnabled() || cs.contextItem is ComposeContextItem.QuotedItem) && (cs.liveMessage == null || !cs.liveMessage?.sent)) {
|
||||||
val ci = sendMessageAsync(sentMsg, live = true)
|
val ci = sendMessageAsync(typedMsg, live = true)
|
||||||
if (ci != null) {
|
if (ci != null) {
|
||||||
composeState.value = composeState.value.copy(liveMessage = LiveMessage(ci, typedMsg = typedMsg, sentMsg = sentMsg, sent = true))
|
composeState.value = composeState.value.copy(liveMessage = LiveMessage(ci, typedMsg = typedMsg, sentMsg = typedMsg, sent = true))
|
||||||
}
|
}
|
||||||
} else if (composeState.value.liveMessage == null) {
|
} else if (cs.liveMessage == null) {
|
||||||
val cItem = chatModel.addLiveChatItemDummy((composeState.value.contextItem as? ComposeContextItem.QuotedItem)?.chatItem, chat.chatInfo)
|
val cItem = chatModel.addLiveDummy(chat.chatInfo)
|
||||||
composeState.value = composeState.value.copy(liveMessage = LiveMessage(cItem, typedMsg = typedMsg, sentMsg = sentMsg, sent = false))
|
composeState.value = composeState.value.copy(liveMessage = LiveMessage(cItem, typedMsg = typedMsg, sentMsg = typedMsg, sent = false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -702,16 +704,6 @@ fun ComposeView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
snapshotFlow { composeState.value.contextItem }
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.collect {
|
|
||||||
if (composeState.value.liveMessage?.sent == false) {
|
|
||||||
chatModel.removeLiveChatItemDummy()
|
|
||||||
chatModel.addLiveChatItemDummy((it as? ComposeContextItem.QuotedItem)?.chatItem, chat.chatInfo)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val activity = LocalContext.current as Activity
|
val activity = LocalContext.current as Activity
|
||||||
DisposableEffect(Unit) {
|
DisposableEffect(Unit) {
|
||||||
@@ -723,7 +715,7 @@ fun ComposeView(
|
|||||||
sendMessage()
|
sendMessage()
|
||||||
resetLinkPreview()
|
resetLinkPreview()
|
||||||
}
|
}
|
||||||
chatModel.removeLiveChatItemDummy()
|
chatModel.removeLiveDummy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -745,7 +737,7 @@ fun ComposeView(
|
|||||||
updateLiveMessage = ::updateLiveMessage,
|
updateLiveMessage = ::updateLiveMessage,
|
||||||
cancelLiveMessage = {
|
cancelLiveMessage = {
|
||||||
composeState.value = composeState.value.copy(liveMessage = null)
|
composeState.value = composeState.value.copy(liveMessage = null)
|
||||||
chatModel.removeLiveChatItemDummy()
|
chatModel.removeLiveDummy()
|
||||||
},
|
},
|
||||||
onMessageChange = ::onMessageChange,
|
onMessageChange = ::onMessageChange,
|
||||||
textStyle = textStyle
|
textStyle = textStyle
|
||||||
|
|||||||
@@ -109,7 +109,10 @@ fun SendMsgView(
|
|||||||
else ->
|
else ->
|
||||||
RecordVoiceView(recState, stopRecOnNextClick)
|
RecordVoiceView(recState, stopRecOnNextClick)
|
||||||
}
|
}
|
||||||
if (sendLiveMessage != null && updateLiveMessage != null && (cs.preview !is ComposePreview.VoicePreview || !stopRecOnNextClick.value)) {
|
if (sendLiveMessage != null
|
||||||
|
&& updateLiveMessage != null
|
||||||
|
&& (cs.preview !is ComposePreview.VoicePreview || !stopRecOnNextClick.value)
|
||||||
|
&& cs.contextItem is ComposeContextItem.NoContextItem) {
|
||||||
Spacer(Modifier.width(10.dp))
|
Spacer(Modifier.width(10.dp))
|
||||||
StartLiveMessageButton {
|
StartLiveMessageButton {
|
||||||
if (composeState.value.preview is ComposePreview.NoPreview) {
|
if (composeState.value.preview is ComposePreview.NoPreview) {
|
||||||
@@ -125,14 +128,18 @@ fun SendMsgView(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
val cs = composeState.value
|
||||||
val icon = if (cs.editing || cs.liveMessage != null) Icons.Filled.Check else Icons.Outlined.ArrowUpward
|
val icon = if (cs.editing || cs.liveMessage != null) Icons.Filled.Check else Icons.Outlined.ArrowUpward
|
||||||
val color = if (cs.sendEnabled()) MaterialTheme.colors.primary else HighOrLowlight
|
val disabled = !cs.sendEnabled() ||
|
||||||
if (composeState.value.liveMessage == null &&
|
(!allowedVoiceByPrefs && cs.preview is ComposePreview.VoicePreview) ||
|
||||||
|
cs.endLiveDisabled
|
||||||
|
if (cs.liveMessage == null &&
|
||||||
cs.preview !is ComposePreview.VoicePreview && !cs.editing &&
|
cs.preview !is ComposePreview.VoicePreview && !cs.editing &&
|
||||||
|
cs.contextItem is ComposeContextItem.NoContextItem &&
|
||||||
sendLiveMessage != null && updateLiveMessage != null
|
sendLiveMessage != null && updateLiveMessage != null
|
||||||
) {
|
) {
|
||||||
var showDropdown by rememberSaveable { mutableStateOf(false) }
|
var showDropdown by rememberSaveable { mutableStateOf(false) }
|
||||||
SendMsgButton(icon, color, sendButtonSize, sendButtonAlpha, cs.sendEnabled(), sendMessage) { showDropdown = true }
|
SendMsgButton(icon, sendButtonSize, sendButtonAlpha, !disabled, sendMessage) { showDropdown = true }
|
||||||
|
|
||||||
DropdownMenu(
|
DropdownMenu(
|
||||||
expanded = showDropdown,
|
expanded = showDropdown,
|
||||||
@@ -149,7 +156,7 @@ fun SendMsgView(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
SendMsgButton(icon, color, sendButtonSize, sendButtonAlpha, cs.sendEnabled(), sendMessage)
|
SendMsgButton(icon, sendButtonSize, sendButtonAlpha, !disabled, sendMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -396,7 +403,6 @@ private fun CancelLiveMessageButton(
|
|||||||
@Composable
|
@Composable
|
||||||
private fun SendMsgButton(
|
private fun SendMsgButton(
|
||||||
icon: ImageVector,
|
icon: ImageVector,
|
||||||
backgroundColor: Color,
|
|
||||||
sizeDp: Animatable<Float, AnimationVector1D>,
|
sizeDp: Animatable<Float, AnimationVector1D>,
|
||||||
alpha: Animatable<Float, AnimationVector1D>,
|
alpha: Animatable<Float, AnimationVector1D>,
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
@@ -425,7 +431,7 @@ private fun SendMsgButton(
|
|||||||
.padding(4.dp)
|
.padding(4.dp)
|
||||||
.alpha(alpha.value)
|
.alpha(alpha.value)
|
||||||
.clip(CircleShape)
|
.clip(CircleShape)
|
||||||
.background(backgroundColor)
|
.background(if (enabled) MaterialTheme.colors.primary else HighOrLowlight)
|
||||||
.padding(3.dp)
|
.padding(3.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ fun ChatItemView(
|
|||||||
val fullDeleteAllowed = remember(cInfo) { cInfo.featureEnabled(ChatFeature.FullDelete) }
|
val fullDeleteAllowed = remember(cInfo) { cInfo.featureEnabled(ChatFeature.FullDelete) }
|
||||||
val saveFileLauncher = rememberSaveFileLauncher(cxt = context, ciFile = cItem.file)
|
val saveFileLauncher = rememberSaveFileLauncher(cxt = context, ciFile = cItem.file)
|
||||||
val onLinkLongClick = { _: String -> showMenu.value = true }
|
val onLinkLongClick = { _: String -> showMenu.value = true }
|
||||||
|
val live = composeState.value.liveMessage != null
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -97,7 +98,7 @@ fun ChatItemView(
|
|||||||
onDismissRequest = { showMenu.value = false },
|
onDismissRequest = { showMenu.value = false },
|
||||||
Modifier.width(220.dp)
|
Modifier.width(220.dp)
|
||||||
) {
|
) {
|
||||||
if (!cItem.meta.itemDeleted) {
|
if (!cItem.meta.itemDeleted && !live) {
|
||||||
ItemAction(stringResource(R.string.reply_verb), Icons.Outlined.Reply, onClick = {
|
ItemAction(stringResource(R.string.reply_verb), Icons.Outlined.Reply, onClick = {
|
||||||
if (composeState.value.editing) {
|
if (composeState.value.editing) {
|
||||||
composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem), useLinkPreviews = useLinkPreviews)
|
composeState.value = ComposeState(contextItem = ComposeContextItem.QuotedItem(cItem), useLinkPreviews = useLinkPreviews)
|
||||||
@@ -133,7 +134,7 @@ fun ChatItemView(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice) {
|
if (cItem.meta.editable && cItem.content.msgContent !is MsgContent.MCVoice && !live) {
|
||||||
ItemAction(stringResource(R.string.edit_verb), Icons.Filled.Edit, onClick = {
|
ItemAction(stringResource(R.string.edit_verb), Icons.Filled.Edit, onClick = {
|
||||||
composeState.value = ComposeState(editingItem = cItem, useLinkPreviews = useLinkPreviews)
|
composeState.value = ComposeState(editingItem = cItem, useLinkPreviews = useLinkPreviews)
|
||||||
showMenu.value = false
|
showMenu.value = false
|
||||||
@@ -149,7 +150,9 @@ fun ChatItemView(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
DeleteItemAction(cItem, showMenu, questionText = deleteMessageQuestionText(), deleteMessage)
|
if (!(live && cItem.meta.isLive)) {
|
||||||
|
DeleteItemAction(cItem, showMenu, questionText = deleteMessageQuestionText(), deleteMessage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -283,12 +283,8 @@ final class ChatModel: ObservableObject {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func addLiveDummy(_ quotedCItem: ChatItem?, _ chatInfo: ChatInfo) -> ChatItem {
|
func addLiveDummy(_ chatInfo: ChatInfo) -> ChatItem {
|
||||||
var quoted: CIQuote? = nil
|
let cItem = ChatItem.liveDummy(chatInfo.chatType)
|
||||||
if let quotedItem = quotedCItem, let msgContent = quotedItem.content.msgContent {
|
|
||||||
quoted = CIQuote.getSampleWithMsgContent(itemId: quotedItem.id, sentAt: quotedItem.meta.updatedAt, msgContent: msgContent, chatDir: quotedItem.chatDir)
|
|
||||||
}
|
|
||||||
let cItem = ChatItem.liveChatItemDummy(chatInfo.chatType, quoted)
|
|
||||||
withAnimation {
|
withAnimation {
|
||||||
reversedChatItems.insert(cItem, at: 0)
|
reversedChatItems.insert(cItem, at: 0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,13 @@ struct ComposeState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var quoting: Bool {
|
||||||
|
switch contextItem {
|
||||||
|
case .quotedItem: return true
|
||||||
|
default: return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var sendEnabled: Bool {
|
var sendEnabled: Bool {
|
||||||
switch preview {
|
switch preview {
|
||||||
case .imagePreviews: return true
|
case .imagePreviews: return true
|
||||||
@@ -105,6 +112,10 @@ struct ComposeState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var endLiveDisabled: Bool {
|
||||||
|
liveMessage != nil && message.isEmpty && noPreview && !quoting
|
||||||
|
}
|
||||||
|
|
||||||
var linkPreviewAllowed: Bool {
|
var linkPreviewAllowed: Bool {
|
||||||
switch preview {
|
switch preview {
|
||||||
case .imagePreviews: return false
|
case .imagePreviews: return false
|
||||||
@@ -400,18 +411,15 @@ struct ComposeView: View {
|
|||||||
|
|
||||||
private func sendLiveMessage() async {
|
private func sendLiveMessage() async {
|
||||||
let typedMsg = composeState.message
|
let typedMsg = composeState.message
|
||||||
let sentMsg = truncateToWords(typedMsg)
|
let lm = composeState.liveMessage
|
||||||
if !sentMsg.isEmpty && (composeState.liveMessage == nil || composeState.liveMessage?.sentMsg == nil),
|
if (composeState.sendEnabled || composeState.quoting)
|
||||||
let ci = await sendMessageAsync(sentMsg, live: true) {
|
&& (lm == nil || lm?.sentMsg == nil),
|
||||||
|
let ci = await sendMessageAsync(typedMsg, live: true) {
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
composeState = composeState.copy(liveMessage: LiveMessage(chatItem: ci, typedMsg: typedMsg, sentMsg: sentMsg))
|
composeState = composeState.copy(liveMessage: LiveMessage(chatItem: ci, typedMsg: typedMsg, sentMsg: typedMsg))
|
||||||
}
|
}
|
||||||
} else if composeState.liveMessage == nil {
|
} else if lm == nil {
|
||||||
var quoted: ChatItem? = nil
|
let cItem = chatModel.addLiveDummy(chat.chatInfo)
|
||||||
if case let .quotedItem(item) = composeState.contextItem {
|
|
||||||
quoted = item
|
|
||||||
}
|
|
||||||
let cItem = chatModel.addLiveDummy(quoted, chat.chatInfo)
|
|
||||||
await MainActor.run {
|
await MainActor.run {
|
||||||
composeState = composeState.copy(liveMessage: LiveMessage(chatItem: cItem, typedMsg: typedMsg, sentMsg: nil))
|
composeState = composeState.copy(liveMessage: LiveMessage(chatItem: cItem, typedMsg: typedMsg, sentMsg: nil))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,7 +100,9 @@ struct SendMessageView: View {
|
|||||||
} else {
|
} else {
|
||||||
voiceMessageNotAllowedButton()
|
voiceMessageNotAllowedButton()
|
||||||
}
|
}
|
||||||
if let send = sendLiveMessage, let update = updateLiveMessage {
|
if let send = sendLiveMessage,
|
||||||
|
let update = updateLiveMessage,
|
||||||
|
case .noContextItem = composeState.contextItem {
|
||||||
startLiveMessageButton(send: send, update: update)
|
startLiveMessageButton(send: send, update: update)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,11 +139,12 @@ struct SendMessageView: View {
|
|||||||
!composeState.sendEnabled ||
|
!composeState.sendEnabled ||
|
||||||
composeState.disabled ||
|
composeState.disabled ||
|
||||||
(!voiceMessageAllowed && composeState.voicePreview) ||
|
(!voiceMessageAllowed && composeState.voicePreview) ||
|
||||||
(composeState.liveMessage != nil && composeState.message.isEmpty)
|
composeState.endLiveDisabled
|
||||||
)
|
)
|
||||||
.frame(width: 29, height: 29)
|
.frame(width: 29, height: 29)
|
||||||
|
|
||||||
if composeState.liveMessage == nil,
|
if composeState.liveMessage == nil,
|
||||||
|
case .noContextItem = composeState.contextItem,
|
||||||
!composeState.voicePreview && !composeState.editing,
|
!composeState.voicePreview && !composeState.editing,
|
||||||
let send = sendLiveMessage,
|
let send = sendLiveMessage,
|
||||||
let update = updateLiveMessage {
|
let update = updateLiveMessage {
|
||||||
|
|||||||
@@ -1863,7 +1863,7 @@ public struct ChatItem: Identifiable, Decodable {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func liveChatItemDummy(_ chatType: ChatType, _ quoted: CIQuote?) -> ChatItem {
|
public static func liveDummy(_ chatType: ChatType) -> ChatItem {
|
||||||
var item = ChatItem(
|
var item = ChatItem(
|
||||||
chatDir: chatType == ChatType.direct ? CIDirection.directSnd : CIDirection.groupSnd,
|
chatDir: chatType == ChatType.direct ? CIDirection.directSnd : CIDirection.groupSnd,
|
||||||
meta: CIMeta(
|
meta: CIMeta(
|
||||||
@@ -1879,7 +1879,7 @@ public struct ChatItem: Identifiable, Decodable {
|
|||||||
editable: false
|
editable: false
|
||||||
),
|
),
|
||||||
content: .sndMsgContent(msgContent: .text("")),
|
content: .sndMsgContent(msgContent: .text("")),
|
||||||
quotedItem: quoted,
|
quotedItem: nil,
|
||||||
file: nil
|
file: nil
|
||||||
)
|
)
|
||||||
item.isLiveDummy = true
|
item.isLiveDummy = true
|
||||||
@@ -2135,10 +2135,6 @@ public struct CIQuote: Decodable, ItemContent {
|
|||||||
}
|
}
|
||||||
return CIQuote(chatDir: chatDir, itemId: itemId, sentAt: sentAt, content: mc)
|
return CIQuote(chatDir: chatDir, itemId: itemId, sentAt: sentAt, content: mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func getSampleWithMsgContent(itemId: Int64?, sentAt: Date, msgContent: MsgContent, chatDir: CIDirection) -> CIQuote {
|
|
||||||
return CIQuote(chatDir: chatDir, itemId: itemId, sentAt: sentAt, content: msgContent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct CIFile: Decodable {
|
public struct CIFile: Decodable {
|
||||||
|
|||||||
Reference in New Issue
Block a user