diff --git a/sphinx/application/common/wrappers/wrapper-message/src/main/java/chat/sphinx/wrapper_message/ErrorMessage.kt b/sphinx/application/common/wrappers/wrapper-message/src/main/java/chat/sphinx/wrapper_message/ErrorMessage.kt new file mode 100644 index 0000000000..a4d46fa04d --- /dev/null +++ b/sphinx/application/common/wrappers/wrapper-message/src/main/java/chat/sphinx/wrapper_message/ErrorMessage.kt @@ -0,0 +1,18 @@ +package chat.sphinx.wrapper_message + +@Suppress("NOTHING_TO_INLINE") +inline fun String.toErrorMessage(): ErrorMessage? = + try { + ErrorMessage(this) + } catch (e: IllegalArgumentException) { + null + } + +@JvmInline +value class ErrorMessage(val value: String) { + init { + require(value.isNotEmpty()) { + "ErrorMessage cannot be empty" + } + } +} \ No newline at end of file diff --git a/sphinx/application/common/wrappers/wrapper-message/src/main/java/chat/sphinx/wrapper_message/Message.kt b/sphinx/application/common/wrappers/wrapper-message/src/main/java/chat/sphinx/wrapper_message/Message.kt index f82fd7a119..8d232c07c7 100644 --- a/sphinx/application/common/wrappers/wrapper-message/src/main/java/chat/sphinx/wrapper_message/Message.kt +++ b/sphinx/application/common/wrappers/wrapper-message/src/main/java/chat/sphinx/wrapper_message/Message.kt @@ -357,6 +357,7 @@ abstract class Message { abstract val recipientPic: PhotoUrl? abstract val person: MessagePerson? abstract val threadUUID: ThreadUUID? + abstract val errorMessage: ErrorMessage? abstract val isPinned: Boolean abstract val messageContentDecrypted: MessageContentDecrypted? @@ -405,6 +406,7 @@ abstract class Message { other.recipientPic == recipientPic && other.person == person && other.threadUUID == threadUUID && + other.errorMessage == errorMessage && other.isPinned == isPinned && other.reactions.let { a -> reactions.let { b -> @@ -461,6 +463,7 @@ abstract class Message { result = _31 * result + recipientPic.hashCode() result = _31 * result + person.hashCode() result = _31 * result + threadUUID.hashCode() + result = _31 * result + errorMessage.hashCode() result = _31 * result + isPinned.hashCode() reactions?.forEach { result = _31 * result + it.hashCode() } purchaseItems?.forEach { result = _31 * result + it.hashCode() } @@ -482,7 +485,8 @@ abstract class Message { "giphyData=$giphyData,reactions=$reactions,purchaseItems=$purchaseItems," + "replyMessage=$replyMessage),recipientAlias=$recipientAlias," + "recipientPic=$recipientPic,person=$person,threadUUID=$threadUUID," + - "callLink=$callLinkMessage" + + "errorMessage=$errorMessage," + + "callLink=$callLinkMessage," + "isPinned=$isPinned" } } diff --git a/sphinx/application/data/concepts/concept-coredb/src/main/sqldelight/chat/sphinx/concept_coredb/SphinxDatabase.sq b/sphinx/application/data/concepts/concept-coredb/src/main/sqldelight/chat/sphinx/concept_coredb/SphinxDatabase.sq index ddc6b7a646..ff5b60d828 100644 --- a/sphinx/application/data/concepts/concept-coredb/src/main/sqldelight/chat/sphinx/concept_coredb/SphinxDatabase.sq +++ b/sphinx/application/data/concepts/concept-coredb/src/main/sqldelight/chat/sphinx/concept_coredb/SphinxDatabase.sq @@ -63,6 +63,7 @@ import chat.sphinx.wrapper_feed.FeedModelType; import chat.sphinx.wrapper_feed.FeedPlayerSpeed; import chat.sphinx.wrapper_feed.FeedTitle; import chat.sphinx.wrapper_invite.InviteString; +import chat.sphinx.wrapper_message.ErrorMessage; import chat.sphinx.wrapper_message.Flagged; import chat.sphinx.wrapper_message.MessageContent; import chat.sphinx.wrapper_message.MessageContentDecrypted; @@ -602,7 +603,8 @@ CREATE TABLE messageDbo( recipient_pic TEXT AS PhotoUrl, push INTEGER AS Push DEFAULT 0, person TEXT AS MessagePerson, - thread_uuid TEXT AS ThreadUUID + thread_uuid TEXT AS ThreadUUID, + error_message TEXT AS ErrorMessage ); messageGetAllReactionsByUUID: @@ -803,7 +805,8 @@ messageUpsert { recipient_pic = :recipient_pic, push = :push, person = :person, - thread_uuid = :thread_uuid + thread_uuid = :thread_uuid, + error_message = :error_message WHERE id = :id; INSERT OR IGNORE INTO messageDbo( @@ -832,7 +835,8 @@ messageUpsert { recipient_pic, push, person, - thread_uuid + thread_uuid, + error_message ) VALUES ( :id, @@ -860,7 +864,8 @@ messageUpsert { :recipient_pic, :push, :person, - :thread_uuid + :thread_uuid, + :error_message ); } diff --git a/sphinx/application/data/concepts/concept-coredb/src/main/sqldelight/migrations/18.sqm b/sphinx/application/data/concepts/concept-coredb/src/main/sqldelight/migrations/18.sqm new file mode 100644 index 0000000000..55c6d8aff7 --- /dev/null +++ b/sphinx/application/data/concepts/concept-coredb/src/main/sqldelight/migrations/18.sqm @@ -0,0 +1,3 @@ +import chat.sphinx.wrapper_message.ErrorMessage; + +ALTER TABLE messageDbo ADD COLUMN error_message TEXT AS ErrorMessage DEFAULT NULL; diff --git a/sphinx/application/data/features/feature-coredb/src/main/java/chat/sphinx/feature_coredb/CoreDBImpl.kt b/sphinx/application/data/features/feature-coredb/src/main/java/chat/sphinx/feature_coredb/CoreDBImpl.kt index f61097b1a4..99a2dfb20f 100644 --- a/sphinx/application/data/features/feature-coredb/src/main/java/chat/sphinx/feature_coredb/CoreDBImpl.kt +++ b/sphinx/application/data/features/feature-coredb/src/main/java/chat/sphinx/feature_coredb/CoreDBImpl.kt @@ -154,7 +154,8 @@ abstract class CoreDBImpl(private val moshi: Moshi): CoreDB() { recipient_picAdapter = PhotoUrlAdapter.getInstance(), pushAdapter = PushAdapter(), personAdapter = PersonAdapter(), - thread_uuidAdapter = ThreadUUIDAdapter() + thread_uuidAdapter = ThreadUUIDAdapter(), + error_messageAdapter = ErrorMessageAdapter() ), messageMediaDboAdapter = MessageMediaDbo.Adapter( idAdapter = MessageIdAdapter.getInstance(), diff --git a/sphinx/application/data/features/feature-coredb/src/main/java/chat/sphinx/feature_coredb/adapters/message/MessageAdapters.kt b/sphinx/application/data/features/feature-coredb/src/main/java/chat/sphinx/feature_coredb/adapters/message/MessageAdapters.kt index c5dee0a70d..831646b40c 100644 --- a/sphinx/application/data/features/feature-coredb/src/main/java/chat/sphinx/feature_coredb/adapters/message/MessageAdapters.kt +++ b/sphinx/application/data/features/feature-coredb/src/main/java/chat/sphinx/feature_coredb/adapters/message/MessageAdapters.kt @@ -162,3 +162,13 @@ internal class ThreadUUIDAdapter: ColumnAdapter { } } +internal class ErrorMessageAdapter: ColumnAdapter { + override fun decode(databaseValue: String): ErrorMessage { + return ErrorMessage(databaseValue) + } + + override fun encode(value: ErrorMessage): String { + return value.value + } +} + diff --git a/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/SphinxRepository.kt b/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/SphinxRepository.kt index 0412fc55bc..90935fbd0b 100644 --- a/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/SphinxRepository.kt +++ b/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/SphinxRepository.kt @@ -2662,6 +2662,7 @@ abstract class SphinxRepository( Push.False, null, threadUUID, + null, provisionalId, null, chatDbo.id, diff --git a/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/model/message/MessageDboWrapper.kt b/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/model/message/MessageDboWrapper.kt index f7a1d991cd..792ebbf750 100644 --- a/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/model/message/MessageDboWrapper.kt +++ b/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/model/message/MessageDboWrapper.kt @@ -64,7 +64,8 @@ class MessageDboWrapper( get() = messageDbo.person override val threadUUID: ThreadUUID? get() = messageDbo.thread_uuid - + override val errorMessage: ErrorMessage? + get() = messageDbo.error_message @Volatile @Suppress("PropertyName") diff --git a/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/util/Extensions.kt b/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/util/Extensions.kt index 0b811a0dff..ba492c4043 100644 --- a/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/util/Extensions.kt +++ b/sphinx/application/data/features/feature-repository/src/main/java/chat/sphinx/feature_repository/util/Extensions.kt @@ -395,6 +395,7 @@ fun TransactionCallbacks.upsertMessage( dto.pushActual.toPush(), dto.person?.toMessagePerson(), dto.thread_uuid?.toThreadUUID(), + dto.error_message?.toErrorMessage(), MessageId(dto.id), dto.uuid?.toMessageUUID(), chatId, diff --git a/sphinx/application/network/concepts/queries/concept-network-query-message/src/main/java/chat/sphinx/concept_network_query_message/model/MessageDto.kt b/sphinx/application/network/concepts/queries/concept-network-query-message/src/main/java/chat/sphinx/concept_network_query_message/model/MessageDto.kt index 8e3822a5a3..09b13cc4e1 100644 --- a/sphinx/application/network/concepts/queries/concept-network-query-message/src/main/java/chat/sphinx/concept_network_query_message/model/MessageDto.kt +++ b/sphinx/application/network/concepts/queries/concept-network-query-message/src/main/java/chat/sphinx/concept_network_query_message/model/MessageDto.kt @@ -42,7 +42,8 @@ data class MessageDto( val recipient_pic: String?, val push: Any?, val person: String?, - val thread_uuid: String? + val thread_uuid: String?, + val error_message: String? ) { @Transient val seenActual: Boolean = diff --git a/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/HolderBindingExtensions.kt b/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/HolderBindingExtensions.kt index ba7c0cba60..3ef27119a0 100644 --- a/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/HolderBindingExtensions.kt +++ b/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/HolderBindingExtensions.kt @@ -844,6 +844,11 @@ internal inline fun LayoutMessageHolderBinding.setStatusHeader( progressBarMessageStatusSending.goneIfFalse(statusHeader.showSendingIcon) textViewMessageStatusSentBoltIcon.goneIfFalse(statusHeader.showBoltIcon) layoutConstraintMessageStatusSentFailedContainer.goneIfFalse(statusHeader.showFailedContainer) + + if (statusHeader.errorMessage?.isNotEmpty() == true) { + textViewMessageStatusSentFailedText.text = statusHeader.errorMessage + } + } else { textViewMessageStatusReceivedTimestamp.text = statusHeader.timestamp textViewMessageStatusReceivedLockIcon.goneIfFalse(statusHeader.showLockIcon) diff --git a/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/LayoutState.kt b/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/LayoutState.kt index 6d8d916da6..6bb4d896b7 100644 --- a/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/LayoutState.kt +++ b/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/LayoutState.kt @@ -36,6 +36,7 @@ sealed class LayoutState private constructor() { val showFailedContainer: Boolean, val showLockIcon: Boolean, val timestamp: String, + val errorMessage: String? ): LayoutState() { val showReceived: Boolean get() = !showSent diff --git a/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/MessageHolderViewState.kt b/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/MessageHolderViewState.kt index e3acd2daa7..a968c5219a 100644 --- a/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/MessageHolderViewState.kt +++ b/sphinx/screens/chats/chat-common/chat-common/src/main/java/chat/sphinx/chat_common/ui/viewstate/messageholder/MessageHolderViewState.kt @@ -117,6 +117,7 @@ internal sealed class MessageHolderViewState( this is Sent && message.status.isFailed(), message.messageContentDecrypted != null || message.messageMedia?.mediaKeyDecrypted != null, message.date.messageTimeFormat(), + message.errorMessage?.value?.trim() ) } else { null diff --git a/sphinx/screens/chats/chat-common/chat-common/src/main/res/layout/layout_message_status_header.xml b/sphinx/screens/chats/chat-common/chat-common/src/main/res/layout/layout_message_status_header.xml index 1321623f11..b3a13b4093 100644 --- a/sphinx/screens/chats/chat-common/chat-common/src/main/res/layout/layout_message_status_header.xml +++ b/sphinx/screens/chats/chat-common/chat-common/src/main/res/layout/layout_message_status_header.xml @@ -156,7 +156,7 @@ android:id="@+id/layout_constraint_message_status_sent_failed_container" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/default_double_layout_margin" + android:layout_marginEnd="@dimen/default_layout_margin" android:visibility="gone" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" @@ -178,9 +178,9 @@ android:id="@+id/text_view_message_status_sent_failed_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:fontFamily="@font/roboto_regular" + android:fontFamily="@font/roboto_italic" android:text="@string/failed_message" - android:textColor="@color/secondaryText" + android:textColor="@color/primaryRed" android:textSize="@dimen/default_text_size_caption1" android:layout_marginStart="@dimen/default_small_layout_margin" app:layout_constraintBottom_toBottomOf="parent"