Merge pull request #3406 from nextcloud/issue-3290-file-caption

File Captions 🏷️
This commit is contained in:
Marcel Hibbe 2023-11-16 15:48:00 +01:00 committed by GitHub
commit f6f9f35901
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 436 additions and 74 deletions

View file

@ -24,6 +24,8 @@
package com.nextcloud.talk.adapters.messages;
import android.text.Spanned;
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
@ -33,6 +35,10 @@ import com.nextcloud.talk.R;
import com.nextcloud.talk.databinding.ItemCustomIncomingPreviewMessageBinding;
import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding;
import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.nextcloud.talk.utils.TextMatchers;
import java.util.HashMap;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
@ -49,7 +55,49 @@ public class IncomingPreviewMessageViewHolder extends PreviewMessageViewHolder {
@Override
public void onBind(@NonNull ChatMessage message) {
super.onBind(message);
if(!message.isVoiceMessage()
&& !Objects.equals(message.getMessage(), "{file}")
) {
Spanned processedMessageText = null;
binding.incomingPreviewMessageBubble.setBackgroundResource(R.drawable.shape_grouped_incoming_message);
binding.incomingPreviewMessageBubble.setOnClickListener(null);
if (viewThemeUtils != null ) {
processedMessageText = messageUtils.enrichChatMessageText(
binding.messageCaption.getContext(),
message,
true,
viewThemeUtils);
viewThemeUtils.talk.themeIncomingMessageBubble(binding.incomingPreviewMessageBubble, true, false);
}
if (processedMessageText != null) {
processedMessageText = messageUtils.processMessageParameters(
binding.messageCaption.getContext(),
viewThemeUtils,
processedMessageText,
message,
itemView);
}
float textSize = 0;
if (context != null) {
textSize = context.getResources().getDimension(R.dimen.chat_text_size);
}
HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters();
if (
(messageParameters == null || messageParameters.size() <= 0) &&
TextMatchers.isMessageWithSingleEmoticonOnly(message.getText())
) {
textSize = (float) (textSize * IncomingTextMessageViewHolder.TEXT_SIZE_MULTIPLIER);
itemView.setSelected(true);
}
binding.messageCaption.setVisibility(View.VISIBLE);
binding.messageCaption.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
binding.messageCaption.setText(processedMessageText);
} else {
binding.incomingPreviewMessageBubble.setBackground(null);
binding.messageCaption.setVisibility(View.GONE);
}
binding.messageAuthor.setText(message.getActorDisplayName());
binding.messageText.setTextColor(ContextCompat.getColor(binding.messageText.getContext(),
R.color.no_emphasis_text));
@ -63,6 +111,12 @@ public class IncomingPreviewMessageViewHolder extends PreviewMessageViewHolder {
return binding.messageText;
}
@NonNull
@Override
public EmojiTextView getMessageCaption() {
return binding.messageCaption;
}
@Override
public ProgressBar getProgressBar() {
return binding.progressBar;
@ -99,5 +153,4 @@ public class IncomingPreviewMessageViewHolder extends PreviewMessageViewHolder {
@Override
public ReactionsInsideMessageBinding getReactionsBinding(){ return binding.reactions; }
}

View file

@ -22,6 +22,9 @@
package com.nextcloud.talk.adapters.messages;
import android.text.Spanned;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.widget.ImageView;
import android.widget.ProgressBar;
@ -31,7 +34,12 @@ import com.nextcloud.talk.R;
import com.nextcloud.talk.databinding.ItemCustomOutcomingPreviewMessageBinding;
import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding;
import com.nextcloud.talk.models.json.chat.ChatMessage;
import com.nextcloud.talk.utils.TextMatchers;
import java.util.HashMap;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.emoji2.widget.EmojiTextView;
@ -45,8 +53,51 @@ public class OutcomingPreviewMessageViewHolder extends PreviewMessageViewHolder
}
@Override
public void onBind(ChatMessage message) {
public void onBind(@NonNull ChatMessage message) {
super.onBind(message);
if(!message.isVoiceMessage()
&& !Objects.equals(message.getMessage(), "{file}")
) {
Spanned processedMessageText = null;
binding.outgoingPreviewMessageBubble.setBackgroundResource(R.drawable.shape_grouped_outcoming_message);
binding.outgoingPreviewMessageBubble.setOnClickListener(null);
if (viewThemeUtils != null) {
processedMessageText = messageUtils.enrichChatMessageText(
binding.messageCaption.getContext(),
message,
false,
viewThemeUtils);
viewThemeUtils.talk.themeOutgoingMessageBubble(binding.outgoingPreviewMessageBubble, true, false);
}
if (processedMessageText != null) {
processedMessageText = messageUtils.processMessageParameters(
binding.messageCaption.getContext(),
viewThemeUtils,
processedMessageText,
message,
itemView);
}
float textSize = 0;
if (context != null) {
textSize = context.getResources().getDimension(R.dimen.chat_text_size);
}
HashMap<String, HashMap<String, String>> messageParameters = message.getMessageParameters();
if (
(messageParameters == null || messageParameters.size() <= 0) &&
TextMatchers.isMessageWithSingleEmoticonOnly(message.getText())
) {
textSize = (float)(textSize * IncomingTextMessageViewHolder.TEXT_SIZE_MULTIPLIER);
itemView.setSelected(true);
}
binding.messageCaption.setVisibility(View.VISIBLE);
binding.messageCaption.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
binding.messageCaption.setText(processedMessageText);
} else {
binding.outgoingPreviewMessageBubble.setBackground(null);
binding.messageCaption.setVisibility(View.GONE);
}
binding.messageText.setTextColor(ContextCompat.getColor(binding.messageText.getContext(),
R.color.no_emphasis_text));
@ -54,6 +105,7 @@ public class OutcomingPreviewMessageViewHolder extends PreviewMessageViewHolder
R.color.no_emphasis_text));
}
@NonNull
@Override
public EmojiTextView getMessageText() {
return binding.messageText;
@ -64,21 +116,25 @@ public class OutcomingPreviewMessageViewHolder extends PreviewMessageViewHolder
return binding.progressBar;
}
@NonNull
@Override
public View getPreviewContainer() {
return binding.previewContainer;
}
@NonNull
@Override
public MaterialCardView getPreviewContactContainer() {
return binding.contactContainer;
}
@NonNull
@Override
public ImageView getPreviewContactPhoto() {
return binding.contactPhoto;
}
@NonNull
@Override
public EmojiTextView getPreviewContactName() {
return binding.contactName;
@ -91,4 +147,8 @@ public class OutcomingPreviewMessageViewHolder extends PreviewMessageViewHolder
@Override
public ReactionsInsideMessageBinding getReactionsBinding() { return binding.reactions; }
@NonNull
@Override
public EmojiTextView getMessageCaption() { return binding.messageCaption; }
}

View file

@ -51,11 +51,13 @@ import com.nextcloud.talk.databinding.ReactionsInsideMessageBinding
import com.nextcloud.talk.extensions.loadChangelogBotAvatar
import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.DateUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.DrawableUtils.getDrawableResourceIdForMimeType
import com.nextcloud.talk.utils.FileViewerUtils
import com.nextcloud.talk.utils.FileViewerUtils.ProgressUi
import com.nextcloud.talk.utils.message.MessageUtils
import com.stfalcon.chatkit.messages.MessageHolders.IncomingImageMessageViewHolder
import io.reactivex.Single
import io.reactivex.SingleObserver
@ -80,6 +82,12 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
@Inject
lateinit var dateUtils: DateUtils
@Inject
lateinit var messageUtils: MessageUtils
@Inject
lateinit var userManager: UserManager
@JvmField
@Inject
var okHttpClient: OkHttpClient? = null
@ -111,6 +119,7 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
if (message.getCalculateMessageType() === ChatMessage.MessageType.SINGLE_NC_ATTACHMENT_MESSAGE) {
fileViewerUtils = FileViewerUtils(context!!, message.activeUser!!)
val fileName = message.selectedIndividualHashMap!![KEY_NAME]
messageText.text = fileName
if (message.activeUser != null &&
@ -123,7 +132,7 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
ProgressUi(progressBar, messageText, image)
)
}
clickView!!.setOnLongClickListener { l: View? ->
clickView!!.setOnLongClickListener {
previewMessageInterface!!.onPreviewMessageLongClick(message)
true
}
@ -188,6 +197,12 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
}
}
}
messageCaption.setOnClickListener(null)
messageCaption.setOnLongClickListener {
previewMessageInterface!!.onPreviewMessageLongClick(message)
true
}
}
private fun longClickOnReaction(chatMessage: ChatMessage) {
@ -312,6 +327,7 @@ abstract class PreviewMessageViewHolder(itemView: View?, payload: Any?) :
}
abstract val messageText: EmojiTextView
abstract val messageCaption: EmojiTextView
abstract val previewContainer: View
abstract val previewContactContainer: MaterialCardView
abstract val previewContactPhoto: ImageView

View file

@ -84,7 +84,6 @@ import android.widget.RelativeLayout.LayoutParams
import android.widget.SeekBar
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
@ -113,7 +112,6 @@ import coil.target.Target
import coil.transform.CircleCropTransformation
import com.google.android.flexbox.FlexboxLayout
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.nextcloud.android.common.ui.theme.utils.ColorRole
import com.nextcloud.talk.BuildConfig
@ -188,6 +186,7 @@ import com.nextcloud.talk.ui.StatusDrawable
import com.nextcloud.talk.ui.bottom.sheet.ProfileBottomSheet
import com.nextcloud.talk.ui.dialog.AttachmentDialog
import com.nextcloud.talk.ui.dialog.DateTimePickerFragment
import com.nextcloud.talk.ui.dialog.FileAttachmentPreviewFragment
import com.nextcloud.talk.ui.dialog.MessageActionsDialog
import com.nextcloud.talk.ui.dialog.SaveToStorageDialogFragment
import com.nextcloud.talk.ui.dialog.ShowReactionsDialog
@ -2412,40 +2411,12 @@ class ChatActivity :
filenamesWithLineBreaks.append(filename).append("\n")
}
val confirmationQuestion = when (filesToUpload.size) {
1 -> context.resources?.getString(R.string.nc_upload_confirm_send_single)?.let {
String.format(it, title.trim())
}
else -> context.resources?.getString(R.string.nc_upload_confirm_send_multiple)?.let {
String.format(it, title.trim())
}
}
binding.messageInputView.context?.let {
val materialAlertDialogBuilder = MaterialAlertDialogBuilder(it)
.setTitle(confirmationQuestion)
.setMessage(filenamesWithLineBreaks.toString())
.setPositiveButton(R.string.nc_yes) { _, _ ->
if (permissionUtil.isFilesPermissionGranted()) {
uploadFiles(filesToUpload)
} else {
UploadAndShareFilesWorker.requestStoragePermission(this)
}
}
.setNegativeButton(R.string.nc_no) { _, _ ->
// unused atm
}
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it, materialAlertDialogBuilder)
val dialog = materialAlertDialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
}
val newFragment: DialogFragment = FileAttachmentPreviewFragment.newInstance(
filenamesWithLineBreaks.toString(),
filesToUpload,
this::uploadFiles
)
newFragment.show(supportFragmentManager, FileAttachmentPreviewFragment.TAG)
} catch (e: IllegalStateException) {
context.resources?.getString(R.string.nc_upload_failed)?.let {
Snackbar.make(
@ -2507,7 +2478,19 @@ class ChatActivity :
}
if (permissionUtil.isFilesPermissionGranted()) {
uploadFiles(filesToUpload)
val filenamesWithLineBreaks = StringBuilder("\n")
for (file in filesToUpload) {
val filename = FileUtils.getFileName(Uri.parse(file), context)
filenamesWithLineBreaks.append(filename).append("\n")
}
val newFragment: DialogFragment = FileAttachmentPreviewFragment.newInstance(
filenamesWithLineBreaks.toString(),
filesToUpload,
this::uploadFiles
)
newFragment.show(supportFragmentManager, FileAttachmentPreviewFragment.TAG)
} else {
UploadAndShareFilesWorker.requestStoragePermission(this)
}
@ -2631,13 +2614,17 @@ class ChatActivity :
}
}
private fun uploadFiles(files: MutableList<String>) {
for (file in files) {
uploadFile(file, false)
private fun uploadFiles(files: MutableList<String>, caption: String = "") {
for (i in 0 until files.size) {
if (i == files.size - 1) {
uploadFile(files[i], false, caption)
} else {
uploadFile(files[i], false)
}
}
}
private fun uploadFile(fileUri: String, isVoiceMessage: Boolean) {
private fun uploadFile(fileUri: String, isVoiceMessage: Boolean, caption: String = "") {
var metaData = ""
if (!participantPermissions.hasChatPermission()) {
@ -2649,6 +2636,10 @@ class ChatActivity :
metaData = VOICE_MESSAGE_META_DATA
}
if (caption != "") {
metaData = "{\"caption\":\"$caption\"}"
}
try {
require(fileUri.isNotEmpty())
UploadAndShareFilesWorker.upload(
@ -3211,30 +3202,7 @@ class ChatActivity :
Integer.parseInt(it)
}
try {
val mostRecentCallSystemMessage = adapter?.items?.first {
it.item is ChatMessage &&
(it.item as ChatMessage).systemMessageType in
listOf(
ChatMessage.SystemMessageType.CALL_STARTED,
ChatMessage.SystemMessageType.CALL_JOINED,
ChatMessage.SystemMessageType.CALL_LEFT,
ChatMessage.SystemMessageType.CALL_ENDED,
ChatMessage.SystemMessageType.CALL_TRIED,
ChatMessage.SystemMessageType.CALL_ENDED_EVERYONE,
ChatMessage.SystemMessageType.CALL_MISSED
)
}?.item
if (mostRecentCallSystemMessage != null) {
processMostRecentMessage(
mostRecentCallSystemMessage as ChatMessage,
chatMessageList
)
}
} catch (e: java.util.NoSuchElementException) {
Log.d(TAG, "No System messages found $e")
}
processCallStartedMessages(chatMessageList)
updateReadStatusOfAllMessages(newXChatLastCommonRead)
adapter?.notifyDataSetChanged()
@ -3269,6 +3237,33 @@ class ChatActivity :
})
}
private fun processCallStartedMessages(chatMessageList: List<ChatMessage>) {
try {
val mostRecentCallSystemMessage = adapter?.items?.first {
it.item is ChatMessage &&
(it.item as ChatMessage).systemMessageType in
listOf(
ChatMessage.SystemMessageType.CALL_STARTED,
ChatMessage.SystemMessageType.CALL_JOINED,
ChatMessage.SystemMessageType.CALL_LEFT,
ChatMessage.SystemMessageType.CALL_ENDED,
ChatMessage.SystemMessageType.CALL_TRIED,
ChatMessage.SystemMessageType.CALL_ENDED_EVERYONE,
ChatMessage.SystemMessageType.CALL_MISSED
)
}?.item
if (mostRecentCallSystemMessage != null) {
processMostRecentMessage(
mostRecentCallSystemMessage as ChatMessage,
chatMessageList
)
}
} catch (e: NoSuchElementException) {
Log.d(TAG, "No System messages found $e")
}
}
private fun setupFieldsForPullChatMessages(
lookIntoFuture: Boolean,
xChatLastCommonRead: Int?,

View file

@ -285,6 +285,7 @@ data class ChatMessage(
""
}
}
val lastMessageDisplayText: String
get() {
if (getCalculateMessageType() == MessageType.REGULAR_TEXT_MESSAGE ||

View file

@ -138,6 +138,8 @@ class RemoteFileBrowserActivity : AppCompatActivity(), SelectionInterface, Swipe
is RemoteFileBrowserItemsViewModel.FinishState -> {
finishWithResult(state.selectedPaths)
}
else -> {}
}
}

View file

@ -0,0 +1,100 @@
/*
* Nextcloud Talk application
*
* @author Julius Linus
* Copyright (C) 2023 Julius Linus <julius.linus@nextcloud.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.ui.dialog
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import autodagger.AutoInjector
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.databinding.DialogFileAttachmentPreviewBinding
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker
import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil
import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class)
class FileAttachmentPreviewFragment(
filenames: String,
filesToUpload: MutableList<String>,
functionToCall: (files: MutableList<String>, caption: String) -> Unit
) : DialogFragment() {
private val files = filenames
private val filesList = filesToUpload
private val uploadFiles = functionToCall
lateinit var binding: DialogFileAttachmentPreviewBinding
@Inject
lateinit var permissionUtil: PlatformPermissionUtil
@Inject
lateinit var viewThemeUtils: ViewThemeUtils
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
binding = DialogFileAttachmentPreviewBinding.inflate(LayoutInflater.from(context))
return MaterialAlertDialogBuilder(requireContext()).setView(binding.root).create()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
setUpViews()
setUpListeners()
return inflater.inflate(R.layout.dialog_file_attachment_preview, container, false)
}
private fun setUpViews() {
binding.dialogFileAttachmentPreviewFilenames.text = files
viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(binding.buttonClose)
viewThemeUtils.material.colorMaterialButtonPrimaryBorderless(binding.buttonSend)
viewThemeUtils.platform.colorViewBackground(binding.root)
viewThemeUtils.material.colorTextInputLayout(binding.dialogFileAttachmentPreviewLayout)
}
private fun setUpListeners() {
binding.buttonClose.setOnClickListener {
dismiss()
}
binding.buttonSend.setOnClickListener {
if (permissionUtil.isFilesPermissionGranted()) {
val caption: String = binding.dialogFileAttachmentPreviewCaption.text.toString()
uploadFiles(filesList, caption)
} else {
UploadAndShareFilesWorker.requestStoragePermission(requireActivity())
}
dismiss()
}
}
companion object {
@JvmStatic
fun newInstance(
filenames: String,
filesToUpload: MutableList<String>,
functionToCall: (files: MutableList<String>, caption: String) -> Unit
) =
FileAttachmentPreviewFragment(filenames, filesToUpload, functionToCall)
val TAG: String = FilterConversationFragment::class.java.simpleName
}
}

View file

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Nextcloud Talk application
~
~ @author Julius Linus
~ Copyright (C) 2023 Julius Linus <julius.linus@nextcloud.com>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:background="@color/white"
tools:visibility="visible">
<com.google.android.material.textview.MaterialTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/standard_margin"
android:text="@string/nc_add_file"
android:textSize="@dimen/md_title_textsize" />
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="100dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/dialog_file_attachment_preview_filenames"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/standard_margin"
android:textSize="@dimen/headline_text_size"
tools:text="a.png\nb.png\nc.png"/>
</ScrollView>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/dialog_file_attachment_preview_layout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/standard_margin">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/dialog_file_attachment_preview_caption"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/nc_caption"
android:maxLines="3"
tools:text="a.png\nb.png\nc.png"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.divider.MaterialDivider
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/standard_half_margin"
android:gravity="end"
android:orientation="horizontal"
android:paddingStart="@dimen/dialog_padding"
android:paddingEnd="@dimen/dialog_padding"
android:paddingBottom="@dimen/dialog_padding_top_bottom">
<com.google.android.material.button.MaterialButton
android:id="@+id/button_close"
style="@style/Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="@dimen/min_size_clickable_area"
android:text="@string/nc_no" />
<com.google.android.material.button.MaterialButton
android:id="@+id/button_send"
style="@style/Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="@dimen/min_size_clickable_area"
android:text="@string/nc_yes" />
</LinearLayout>
</LinearLayout>

View file

@ -41,6 +41,7 @@
android:contentDescription="@string/avatar" />
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/incoming_preview_message_bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
@ -69,8 +70,6 @@
android:id="@+id/preview_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:adjustViewBounds="true"
app:layout_alignSelf="flex_start"
app:layout_flexGrow="1"
@ -163,6 +162,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:paddingHorizontal="@dimen/standard_half_padding"
android:alpha="0.6"
android:autoLink="none"
android:textAlignment="viewStart"
@ -180,6 +180,7 @@
android:id="@id/messageTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/standard_half_padding"
android:layout_alignParentEnd="true"
android:layout_marginStart="8dp"
android:layout_marginEnd="2dp"
@ -190,6 +191,21 @@
tools:ignore="TextContrastCheck"
tools:text="12:38" />
<androidx.emoji2.widget.EmojiTextView
android:id="@+id/messageCaption"
android:padding="@dimen/standard_half_padding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="4dp"
android:textColor="@color/high_emphasis_text"
android:textIsSelectable="false"
android:textSize="@dimen/chat_text_size"
android:visibility="gone"
tools:visibility="visible"
tools:ignore="TextContrastCheck"
tools:text="This is my caption" />
<include
android:id="@+id/reactions"
layout="@layout/reactions_inside_message" />

View file

@ -33,6 +33,7 @@
android:layout_marginBottom="2dp">
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/outgoing_preview_message_bubble"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
@ -48,8 +49,6 @@
android:id="@+id/preview_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:adjustViewBounds="true"
app:layout_alignSelf="flex_start"
app:layout_flexGrow="1"
@ -81,7 +80,8 @@
app:layout_alignSelf="flex_start"
app:layout_flexGrow="1"
app:layout_wrapBefore="true"
app:strokeWidth="0dp">
app:strokeWidth="0dp"
tools:visibility="gone">
<LinearLayout
android:layout_width="wrap_content"
@ -139,7 +139,7 @@
android:id="@id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="2dp"
android:paddingHorizontal="@dimen/standard_half_padding"
android:alpha="0.6"
android:autoLink="none"
android:textColor="@color/no_emphasis_text"
@ -156,6 +156,7 @@
android:id="@id/messageTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/standard_half_padding"
android:layout_alignParentEnd="true"
android:layout_marginStart="8dp"
android:layout_marginEnd="2dp"
@ -165,6 +166,21 @@
app:layout_alignSelf="center"
tools:text="12:34" />
<androidx.emoji2.widget.EmojiTextView
android:id="@+id/messageCaption"
android:padding="@dimen/standard_half_padding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="4dp"
android:textColor="@color/high_emphasis_text"
android:textIsSelectable="false"
android:textSize="@dimen/chat_text_size"
android:visibility="gone"
tools:visibility="visible"
tools:ignore="TextContrastCheck"
tools:text="This is my caption" />
<include
android:id="@+id/reactions"
layout="@layout/reactions_inside_message" />

View file

@ -721,4 +721,5 @@ How to translate with transifex:
<string name="audio_call">Audio Call</string>
<string name="started_a_call">started a call</string>
<string name="nc_settings_phone_book_integration_phone_number_dialog_429">Error 429 Too Many Requests</string>
<string name="nc_caption">Caption</string>
</resources>