mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-23 20:55:02 +01:00
Allow replies to maintain state on orientation change
Signed-off-by: rapterjet2004 <juliuslinus1@gmail.com>
This commit is contained in:
parent
7e72032738
commit
71bd381828
@ -35,7 +35,6 @@ import android.widget.LinearLayout
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.RelativeLayout
|
||||
import android.widget.SeekBar
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.content.res.AppCompatResources
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.content.ContextCompat
|
||||
@ -81,15 +80,15 @@ import com.nextcloud.talk.utils.database.user.CurrentUserProviderNew
|
||||
import com.nextcloud.talk.utils.message.MessageUtils
|
||||
import com.nextcloud.talk.utils.text.Spans
|
||||
import com.otaliastudios.autocomplete.Autocomplete
|
||||
import com.stfalcon.chatkit.commons.models.IMessage
|
||||
import com.vanniktech.emoji.EmojiPopup
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.util.Objects
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("LongParameterList", "TooManyFunctions")
|
||||
@Suppress("LongParameterList", "TooManyFunctions", "LargeClass", "LongMethod")
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class MessageInputFragment : Fragment() {
|
||||
|
||||
@ -112,6 +111,10 @@ class MessageInputFragment : Fragment() {
|
||||
private const val CONNECTION_ESTABLISHED_ANIM_DURATION: Long = 3000
|
||||
private const val FULLY_OPAQUE: Float = 1.0f
|
||||
private const val FULLY_TRANSPARENT: Float = 0.0f
|
||||
const val QUOTED_MESSAGE_TEXT = "QUOTED_MESSAGE_TEXT"
|
||||
const val QUOTED_MESSAGE_ID = "QUOTED_MESSAGE_ID"
|
||||
const val QUOTED_MESSAGE_URL = "QUOTED_MESSAGE_URL"
|
||||
const val QUOTED_MESSAGE_NAME = "QUOTED_MESSAGE_NAME"
|
||||
}
|
||||
|
||||
@Inject
|
||||
@ -163,7 +166,6 @@ class MessageInputFragment : Fragment() {
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
saveState()
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
@ -172,7 +174,6 @@ class MessageInputFragment : Fragment() {
|
||||
mentionAutocomplete?.dismissPopup()
|
||||
}
|
||||
clearEditUI()
|
||||
cancelReply()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
@ -183,7 +184,13 @@ class MessageInputFragment : Fragment() {
|
||||
private fun initObservers() {
|
||||
Log.d(TAG, "LifeCyclerOwner is: ${viewLifecycleOwner.lifecycle}")
|
||||
chatActivity.messageInputViewModel.getReplyChatMessage.observe(viewLifecycleOwner) { message ->
|
||||
message?.let { replyToMessage(message) }
|
||||
(message as ChatMessage?)?.let {
|
||||
chatActivity.chatViewModel.messageDraft.quotedMessageText = message.text
|
||||
chatActivity.chatViewModel.messageDraft.quotedDisplayName = message.actorDisplayName
|
||||
chatActivity.chatViewModel.messageDraft.quotedImageUrl = message.imageUrl
|
||||
chatActivity.chatViewModel.messageDraft.quotedJsonId = message.jsonMessageId
|
||||
replyToMessage(message.text, message.actorDisplayName, message.imageUrl, message.jsonMessageId)
|
||||
}
|
||||
}
|
||||
|
||||
chatActivity.messageInputViewModel.getEditChatMessage.observe(viewLifecycleOwner) { message ->
|
||||
@ -299,34 +306,24 @@ class MessageInputFragment : Fragment() {
|
||||
}
|
||||
|
||||
private fun restoreState() {
|
||||
if (binding.fragmentMessageInputView.inputEditText.text.isEmpty()) {
|
||||
requireContext().getSharedPreferences(chatActivity.localClassName, AppCompatActivity.MODE_PRIVATE).apply {
|
||||
val text = getString(chatActivity.roomToken, "")
|
||||
val cursor = getInt(chatActivity.roomToken + CURSOR_KEY, 0)
|
||||
binding.fragmentMessageInputView.messageInput.setText(text)
|
||||
binding.fragmentMessageInputView.messageInput.setSelection(cursor)
|
||||
}
|
||||
runBlocking {
|
||||
chatActivity.chatViewModel.updateMessageDraft()
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveState() {
|
||||
val text = binding.fragmentMessageInputView.messageInput.text.toString()
|
||||
val cursor = binding.fragmentMessageInputView.messageInput.selectionStart
|
||||
val previous = requireContext().getSharedPreferences(
|
||||
chatActivity.localClassName,
|
||||
AppCompatActivity
|
||||
.MODE_PRIVATE
|
||||
).getString(chatActivity.roomToken, "null")
|
||||
val draft = chatActivity.chatViewModel.messageDraft
|
||||
binding.fragmentMessageInputView.messageInput.setText(draft.messageText)
|
||||
binding.fragmentMessageInputView.messageInput.setSelection(draft.messageCursor)
|
||||
if (draft.messageText != "") {
|
||||
binding.fragmentMessageInputView.messageInput.requestFocus()
|
||||
}
|
||||
|
||||
if (text != previous) {
|
||||
requireContext().getSharedPreferences(
|
||||
chatActivity.localClassName,
|
||||
AppCompatActivity.MODE_PRIVATE
|
||||
).edit().apply {
|
||||
putString(chatActivity.roomToken, text)
|
||||
putInt(chatActivity.roomToken + CURSOR_KEY, cursor)
|
||||
apply()
|
||||
}
|
||||
if (isInReplyState()) {
|
||||
replyToMessage(
|
||||
chatActivity.chatViewModel.messageDraft.quotedMessageText,
|
||||
chatActivity.chatViewModel.messageDraft.quotedDisplayName,
|
||||
chatActivity.chatViewModel.messageDraft.quotedImageUrl,
|
||||
chatActivity.chatViewModel.messageDraft.quotedJsonId ?: 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,7 +385,10 @@ class MessageInputFragment : Fragment() {
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable) {
|
||||
// unused atm
|
||||
val cursor = binding.fragmentMessageInputView.messageInput.selectionStart
|
||||
val text = binding.fragmentMessageInputView.messageInput.text.toString()
|
||||
chatActivity.chatViewModel.messageDraft.messageCursor = cursor
|
||||
chatActivity.chatViewModel.messageDraft.messageText = text
|
||||
}
|
||||
})
|
||||
|
||||
@ -615,7 +615,7 @@ class MessageInputFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
}
|
||||
v?.onTouchEvent(event) ?: true
|
||||
v?.onTouchEvent(event) != false
|
||||
}
|
||||
}
|
||||
|
||||
@ -717,52 +717,54 @@ class MessageInputFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun replyToMessage(message: IMessage?) {
|
||||
private fun replyToMessage(
|
||||
quotedMessageText: String?,
|
||||
quotedActorDisplayName: String?,
|
||||
quotedImageUrl: String?,
|
||||
quotedJsonId: Int
|
||||
) {
|
||||
Log.d(TAG, "Reply")
|
||||
val chatMessage = message as ChatMessage?
|
||||
chatMessage?.let {
|
||||
val view = binding.fragmentMessageInputView
|
||||
view.findViewById<ImageButton>(R.id.attachmentButton)?.visibility =
|
||||
View.GONE
|
||||
view.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility =
|
||||
View.VISIBLE
|
||||
val view = binding.fragmentMessageInputView
|
||||
view.findViewById<ImageButton>(R.id.attachmentButton)?.visibility =
|
||||
View.GONE
|
||||
view.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility =
|
||||
View.VISIBLE
|
||||
|
||||
val quotedMessage = view.findViewById<EmojiTextView>(R.id.quotedMessage)
|
||||
val quotedMessage = view.findViewById<EmojiTextView>(R.id.quotedMessage)
|
||||
|
||||
quotedMessage?.maxLines = 2
|
||||
quotedMessage?.ellipsize = TextUtils.TruncateAt.END
|
||||
quotedMessage?.text = it.text
|
||||
view.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text =
|
||||
it.actorDisplayName ?: requireContext().getText(R.string.nc_nick_guest)
|
||||
quotedMessage?.maxLines = 2
|
||||
quotedMessage?.ellipsize = TextUtils.TruncateAt.END
|
||||
quotedMessage?.text = quotedMessageText
|
||||
view.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text =
|
||||
quotedActorDisplayName ?: requireContext().getText(R.string.nc_nick_guest)
|
||||
|
||||
chatActivity.conversationUser?.let {
|
||||
val quotedMessageImage = view.findViewById<ImageView>(R.id.quotedMessageImage)
|
||||
chatMessage.imageUrl?.let { previewImageUrl ->
|
||||
quotedMessageImage?.visibility = View.VISIBLE
|
||||
chatActivity.conversationUser?.let {
|
||||
val quotedMessageImage = view.findViewById<ImageView>(R.id.quotedMessageImage)
|
||||
quotedImageUrl?.let { previewImageUrl ->
|
||||
quotedMessageImage?.visibility = View.VISIBLE
|
||||
|
||||
val px = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
QUOTED_MESSAGE_IMAGE_MAX_HEIGHT,
|
||||
resources.displayMetrics
|
||||
)
|
||||
val px = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
QUOTED_MESSAGE_IMAGE_MAX_HEIGHT,
|
||||
resources.displayMetrics
|
||||
)
|
||||
|
||||
quotedMessageImage?.maxHeight = px.toInt()
|
||||
val layoutParams = quotedMessageImage?.layoutParams as FlexboxLayout.LayoutParams
|
||||
layoutParams.flexGrow = 0f
|
||||
quotedMessageImage.layoutParams = layoutParams
|
||||
quotedMessageImage.load(previewImageUrl) {
|
||||
addHeader("Authorization", chatActivity.credentials!!)
|
||||
}
|
||||
} ?: run {
|
||||
view.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.GONE
|
||||
quotedMessageImage?.maxHeight = px.toInt()
|
||||
val layoutParams = quotedMessageImage?.layoutParams as FlexboxLayout.LayoutParams
|
||||
layoutParams.flexGrow = 0f
|
||||
quotedMessageImage.layoutParams = layoutParams
|
||||
quotedMessageImage.load(previewImageUrl) {
|
||||
addHeader("Authorization", chatActivity.credentials!!)
|
||||
}
|
||||
} ?: run {
|
||||
view.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.GONE
|
||||
}
|
||||
|
||||
val quotedChatMessageView =
|
||||
view.findViewById<RelativeLayout>(R.id.quotedChatMessageView)
|
||||
quotedChatMessageView?.tag = message?.jsonMessageId
|
||||
quotedChatMessageView?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
val quotedChatMessageView =
|
||||
view.findViewById<RelativeLayout>(R.id.quotedChatMessageView)
|
||||
quotedChatMessageView?.tag = quotedJsonId
|
||||
quotedChatMessageView?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
fun updateOwnTypingStatus(typedText: CharSequence) {
|
||||
@ -1051,5 +1053,15 @@ class MessageInputFragment : Fragment() {
|
||||
quote.tag = null
|
||||
binding.fragmentMessageInputView.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.VISIBLE
|
||||
chatActivity.messageInputViewModel.reply(null)
|
||||
|
||||
chatActivity.chatViewModel.messageDraft.quotedMessageText = null
|
||||
chatActivity.chatViewModel.messageDraft.quotedDisplayName = null
|
||||
chatActivity.chatViewModel.messageDraft.quotedImageUrl = null
|
||||
chatActivity.chatViewModel.messageDraft.quotedJsonId = null
|
||||
}
|
||||
|
||||
private fun isInReplyState(): Boolean {
|
||||
val jsonId = chatActivity.chatViewModel.messageDraft.quotedJsonId
|
||||
return jsonId != null
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import com.nextcloud.talk.conversationlist.data.OfflineConversationsRepository
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.extensions.toIntOrZero
|
||||
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
|
||||
import com.nextcloud.talk.models.MessageDraft
|
||||
import com.nextcloud.talk.models.domain.ConversationModel
|
||||
import com.nextcloud.talk.models.domain.ReactionAddedModel
|
||||
import com.nextcloud.talk.models.domain.ReactionDeletedModel
|
||||
@ -60,6 +61,7 @@ import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -89,6 +91,8 @@ class ChatViewModel @Inject constructor(
|
||||
val disposableSet = mutableSetOf<Disposable>()
|
||||
var mediaPlayerDuration = mediaPlayerManager.mediaPlayerDuration
|
||||
val mediaPlayerPosition = mediaPlayerManager.mediaPlayerPosition
|
||||
var chatRoomToken: String = ""
|
||||
var messageDraft: MessageDraft = MessageDraft()
|
||||
|
||||
fun getChatRepository(): ChatMessageRepository = chatRepository
|
||||
|
||||
@ -108,6 +112,14 @@ class ChatViewModel @Inject constructor(
|
||||
mediaRecorderManager.handleOnPause()
|
||||
chatRepository.handleOnPause()
|
||||
mediaPlayerManager.handleOnPause()
|
||||
|
||||
runBlocking {
|
||||
val model = conversationRepository.getLocallyStoredConversation(chatRoomToken)
|
||||
model?.let {
|
||||
it.messageDraft = messageDraft
|
||||
conversationRepository.updateConversation(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStop(owner: LifecycleOwner) {
|
||||
@ -889,6 +901,11 @@ class ChatViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun updateMessageDraft() {
|
||||
val model = conversationRepository.getLocallyStoredConversation(chatRoomToken)
|
||||
messageDraft = model?.messageDraft!!
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = ChatViewModel::class.simpleName
|
||||
const val JOIN_ROOM_RETRY_COUNT: Long = 3
|
||||
|
@ -307,6 +307,16 @@ class ConversationsListActivity :
|
||||
showNotificationWarning()
|
||||
|
||||
showShareToScreen = hasActivityActionSendIntent()
|
||||
// context.getSharedPreferences(
|
||||
// CHAT_ACTIVITY_LOCAL_NAME,
|
||||
// MODE_PRIVATE
|
||||
// ).edit().apply {
|
||||
// putInt(QUOTED_MESSAGE_ID, -1)
|
||||
// putString(QUOTED_MESSAGE_NAME, null)
|
||||
// putString(QUOTED_MESSAGE_TEXT, "")
|
||||
// putString(QUOTED_MESSAGE_URL, null)
|
||||
// apply()
|
||||
// }
|
||||
|
||||
if (!eventBus.isRegistered(this)) {
|
||||
eventBus.register(this)
|
||||
@ -2216,6 +2226,7 @@ class ConversationsListActivity :
|
||||
const val UNREAD_BUBBLE_DELAY = 2500
|
||||
const val BOTTOM_SHEET_DELAY: Long = 2500
|
||||
private const val KEY_SEARCH_QUERY = "ConversationsListActivity.searchQuery"
|
||||
private const val CHAT_ACTIVITY_LOCAL_NAME = "com.nextcloud.talk.chat.ChatActivity"
|
||||
const val SEARCH_DEBOUNCE_INTERVAL_MS = 300
|
||||
const val SEARCH_MIN_CHARS = 1
|
||||
const val HTTP_UNAUTHORIZED = 401
|
||||
|
@ -36,4 +36,8 @@ interface OfflineConversationsRepository {
|
||||
* to be handled asynchronously.
|
||||
*/
|
||||
fun getRoom(roomToken: String): Job
|
||||
|
||||
suspend fun updateConversation(conversationModel: ConversationModel)
|
||||
|
||||
suspend fun getLocallyStoredConversation(roomToken: String): ConversationModel?
|
||||
}
|
||||
|
@ -98,12 +98,22 @@ class OfflineFirstConversationsRepository @Inject constructor(
|
||||
runBlocking {
|
||||
_conversationFlow.emit(model)
|
||||
val entityList = listOf(model.asEntity())
|
||||
dao.upsertConversations(entityList)
|
||||
dao.upsertConversations(user.id!!, entityList)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override suspend fun updateConversation(conversationModel: ConversationModel) {
|
||||
val entity = conversationModel.asEntity()
|
||||
dao.updateConversation(entity)
|
||||
}
|
||||
|
||||
override suspend fun getLocallyStoredConversation(roomToken: String): ConversationModel? {
|
||||
val id = user.id!!
|
||||
return getConversation(id, roomToken)
|
||||
}
|
||||
|
||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
||||
private suspend fun getRoomsFromServer(): List<ConversationEntity>? {
|
||||
var conversationsFromSync: List<ConversationEntity>? = null
|
||||
@ -126,7 +136,7 @@ class OfflineFirstConversationsRepository @Inject constructor(
|
||||
}
|
||||
|
||||
deleteLeftConversations(conversationsFromSync)
|
||||
dao.upsertConversations(conversationsFromSync)
|
||||
dao.upsertConversations(user.id!!, conversationsFromSync)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "Something went wrong when fetching conversations", e)
|
||||
}
|
||||
|
@ -8,11 +8,15 @@
|
||||
package com.nextcloud.talk.data.database.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy.Companion.REPLACE
|
||||
import androidx.room.Query
|
||||
import androidx.room.Transaction
|
||||
import androidx.room.Update
|
||||
import androidx.room.Upsert
|
||||
import com.nextcloud.talk.data.database.model.ConversationEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
@Dao
|
||||
interface ConversationsDao {
|
||||
@ -22,9 +26,27 @@ interface ConversationsDao {
|
||||
@Query("SELECT * FROM Conversations where accountId = :accountId AND token = :token")
|
||||
fun getConversationForUser(accountId: Long, token: String): Flow<ConversationEntity?>
|
||||
|
||||
@Upsert
|
||||
@Upsert()
|
||||
fun upsertConversations(conversationEntities: List<ConversationEntity>)
|
||||
|
||||
@Insert(onConflict = REPLACE)
|
||||
suspend fun insertOrUpdate(item: ConversationEntity)
|
||||
|
||||
@Transaction
|
||||
suspend fun upsertConversations(accountId: Long, serverItems: List<ConversationEntity>) {
|
||||
serverItems.forEach { serverItem ->
|
||||
val existingItem = getConversationForUser(accountId, serverItem.token).first()
|
||||
if (existingItem != null) {
|
||||
val mergedItem = serverItem
|
||||
mergedItem.messageDraft = existingItem.messageDraft
|
||||
insertOrUpdate(mergedItem)
|
||||
} else {
|
||||
// Insert new item directly (local-only fields will be default)
|
||||
insertOrUpdate(serverItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes rows in the db matching the specified [conversationIds]
|
||||
*/
|
||||
@ -36,7 +58,7 @@ interface ConversationsDao {
|
||||
)
|
||||
fun deleteConversations(conversationIds: List<String>)
|
||||
|
||||
@Update
|
||||
@Update(onConflict = REPLACE)
|
||||
fun updateConversation(conversationEntity: ConversationEntity)
|
||||
|
||||
@Query(
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2024 Your Name <your@email.com>
|
||||
* SPDX-FileCopyrightText: 2024 Julius Linus <juliuslinus1@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
@ -63,7 +63,8 @@ fun ConversationModel.asEntity() =
|
||||
remoteToken = remoteToken,
|
||||
hasArchived = hasArchived,
|
||||
hasSensitive = hasSensitive,
|
||||
hasImportant = hasImportant
|
||||
hasImportant = hasImportant,
|
||||
messageDraft = messageDraft
|
||||
)
|
||||
|
||||
fun ConversationEntity.asModel() =
|
||||
@ -117,7 +118,8 @@ fun ConversationEntity.asModel() =
|
||||
remoteToken = remoteToken,
|
||||
hasArchived = hasArchived,
|
||||
hasSensitive = hasSensitive,
|
||||
hasImportant = hasImportant
|
||||
hasImportant = hasImportant,
|
||||
messageDraft = messageDraft
|
||||
)
|
||||
|
||||
fun Conversation.asEntity(accountId: Long) =
|
||||
|
@ -13,6 +13,7 @@ import androidx.room.ForeignKey
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
import com.nextcloud.talk.data.user.model.UserEntity
|
||||
import com.nextcloud.talk.models.MessageDraft
|
||||
import com.nextcloud.talk.models.json.conversations.ConversationEnums
|
||||
import com.nextcloud.talk.models.json.participants.Participant
|
||||
|
||||
@ -96,7 +97,8 @@ data class ConversationEntity(
|
||||
@ColumnInfo(name = "unreadMessages") var unreadMessages: Int = 0,
|
||||
@ColumnInfo(name = "hasArchived") var hasArchived: Boolean = false,
|
||||
@ColumnInfo(name = "hasSensitive") var hasSensitive: Boolean = false,
|
||||
@ColumnInfo(name = "hasImportant") var hasImportant: Boolean = false
|
||||
@ColumnInfo(name = "hasImportant") var hasImportant: Boolean = false,
|
||||
@ColumnInfo(name = "messageDraft") var messageDraft: MessageDraft? = MessageDraft()
|
||||
// missing/not needed: attendeeId
|
||||
// missing/not needed: attendeePin
|
||||
// missing/not needed: attendeePermissions
|
||||
|
57
app/src/main/java/com/nextcloud/talk/models/MessageDraft.kt
Normal file
57
app/src/main/java/com/nextcloud/talk/models/MessageDraft.kt
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Nextcloud Talk - Android Client
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2025 Julius Linus <juliuslinus1@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.models
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.room.TypeConverter
|
||||
import com.bluelinelabs.logansquare.LoganSquare
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Parcelize
|
||||
@JsonObject
|
||||
@Serializable
|
||||
data class MessageDraft(
|
||||
@JsonField(name = ["messageText"])
|
||||
var messageText: String = "",
|
||||
@JsonField(name = ["messageCursor"])
|
||||
var messageCursor: Int = 0,
|
||||
@JsonField(name = ["quotedJsonId"])
|
||||
var quotedJsonId: Int? = null,
|
||||
@JsonField(name = ["quotedDisplayName"])
|
||||
var quotedDisplayName: String? = null,
|
||||
@JsonField(name = ["quotedMessageText"])
|
||||
var quotedMessageText: String? = null,
|
||||
@JsonField(name = ["quoteImageUrl"])
|
||||
var quotedImageUrl: String? = null
|
||||
) : Parcelable {
|
||||
constructor() : this("", 0, null, null, null, null)
|
||||
}
|
||||
|
||||
class MessageDraftConverter {
|
||||
|
||||
@TypeConverter
|
||||
fun fromMessageDraftToString(messageDraft: MessageDraft?): String {
|
||||
return if (messageDraft == null) {
|
||||
""
|
||||
} else {
|
||||
LoganSquare.serialize(messageDraft)
|
||||
}
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromStringToMessageDraft(value: String): MessageDraft? {
|
||||
return if (value.isBlank()) {
|
||||
null
|
||||
} else {
|
||||
return LoganSquare.parse(value, MessageDraft::class.java)
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@
|
||||
package com.nextcloud.talk.models.domain
|
||||
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.models.MessageDraft
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessageJson
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||
import com.nextcloud.talk.models.json.conversations.ConversationEnums
|
||||
@ -65,7 +66,8 @@ class ConversationModel(
|
||||
var hasImportant: Boolean = false,
|
||||
|
||||
// attributes that don't come from API. This should be changed?!
|
||||
var password: String? = null
|
||||
var password: String? = null,
|
||||
var messageDraft: MessageDraft? = MessageDraft()
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
@ -194,6 +194,10 @@ class DummyConversationDaoImpl : ConversationsDao {
|
||||
|
||||
override fun upsertConversations(conversationEntities: List<ConversationEntity>) { /* */ }
|
||||
|
||||
override suspend fun insertOrUpdate(item: ConversationEntity) {
|
||||
/**/
|
||||
}
|
||||
|
||||
override fun deleteConversations(conversationIds: List<String>) { /* */ }
|
||||
|
||||
override fun updateConversation(conversationEntity: ConversationEntity) { /* */ }
|
||||
|
Loading…
Reference in New Issue
Block a user