mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 11:39:42 +01:00
Implemented most of message replies
# Conflicts: # app/src/main/java/com/nextcloud/talk/controllers/ChatController.kt # app/src/main/res/layout/view_message_input.xml # app/src/main/res/values/strings.xml
This commit is contained in:
parent
2613c1f074
commit
d21d5f51b4
@ -30,13 +30,13 @@ if (taskRequest.contains("Gplay") || taskRequest.contains("findbugs") || taskReq
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion '28.0.3'
|
||||
defaultConfig {
|
||||
applicationId "com.nextcloud.talk2"
|
||||
versionName version
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 29
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
versionCode 115
|
||||
@ -213,7 +213,7 @@ dependencies {
|
||||
implementation 'me.zhanghai.android.effortlesspermissions:library:1.1.0'
|
||||
implementation 'org.apache.commons:commons-lang3:3.9'
|
||||
implementation 'com.github.wooplr:Spotlight:1.3'
|
||||
implementation('com.github.mario:chatkit:a183142049', {
|
||||
implementation('com.github.mario:chatkit:c6a61767291ddb212a2f4f792a2b6aaf295e69a5', {
|
||||
exclude group: 'com.facebook.fresco'
|
||||
})
|
||||
|
||||
@ -223,7 +223,9 @@ dependencies {
|
||||
implementation 'com.github.mario.fresco:animated-gif:111'
|
||||
implementation 'com.github.mario.fresco:imagepipeline-okhttp3:111'
|
||||
implementation group: 'joda-time', name: 'joda-time', version: '2.10.3'
|
||||
|
||||
implementation 'io.coil-kt:coil:0.9.1'
|
||||
implementation("io.coil-kt:coil-gif:0.9.1")
|
||||
implementation("io.coil-kt:coil-svg:0.9.1")
|
||||
implementation 'com.github.natario1:Autocomplete:v1.1.0'
|
||||
|
||||
implementation 'com.github.cotechde.hwsecurity:hwsecurity-fido:2.4.5'
|
||||
@ -252,3 +254,9 @@ dependencies {
|
||||
findbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.9.0'
|
||||
findbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.4.6'
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
@ -217,7 +217,7 @@ public class ConversationItem extends AbstractFlexibleItem<ConversationItem.Conv
|
||||
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(holder.dialogAvatar.getController())
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), conversation.getName(), R.dimen.avatar_size), null))
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(userEntity.getBaseUrl(), conversation.getName(), R.dimen.avatar_size), userEntity))
|
||||
.build();
|
||||
holder.dialogAvatar.setController(draweeController);
|
||||
} else {
|
||||
|
@ -283,7 +283,8 @@ public interface NcApi {
|
||||
@POST
|
||||
Observable<GenericOverall> sendChatMessage(@Header("Authorization") String authorization, @Url String url,
|
||||
@Field("message") CharSequence message,
|
||||
@Field("actorDisplayName") String actorDisplayName);
|
||||
@Field("actorDisplayName") String actorDisplayName,
|
||||
@Field("replyTo") Integer replyTo);
|
||||
|
||||
@GET
|
||||
Observable<MentionOverall> getMentionAutocompleteSuggestions(@Header("Authorization") String authorization,
|
||||
|
@ -22,6 +22,8 @@ package com.nextcloud.talk.application
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Build.VERSION_CODES.P
|
||||
import android.util.Log
|
||||
import androidx.emoji.bundled.BundledEmojiCompatConfig
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
@ -36,6 +38,11 @@ import androidx.work.PeriodicWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import autodagger.AutoComponent
|
||||
import autodagger.AutoInjector
|
||||
import coil.Coil
|
||||
import coil.ImageLoader
|
||||
import coil.decode.GifDecoder
|
||||
import coil.decode.ImageDecoderDecoder
|
||||
import coil.decode.SvgDecoder
|
||||
import com.facebook.cache.disk.DiskCacheConfig
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.core.ImagePipelineConfig
|
||||
@ -130,6 +137,7 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
|
||||
componentApplication.inject(this)
|
||||
|
||||
Coil.setDefaultImageLoader(::buildDefaultImageLoader)
|
||||
setAppTheme(appPreferences.theme)
|
||||
super.onCreate()
|
||||
|
||||
@ -192,6 +200,21 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
MultiDex.install(this)
|
||||
}
|
||||
|
||||
private fun buildDefaultImageLoader(): ImageLoader {
|
||||
return ImageLoader(applicationContext) {
|
||||
availableMemoryPercentage(0.5) // Use 50% of the application's available memory.
|
||||
crossfade(true) // Show a short crossfade when loading images from network or disk into an ImageView.
|
||||
componentRegistry {
|
||||
if (SDK_INT >= P) {
|
||||
add(ImageDecoderDecoder())
|
||||
} else {
|
||||
add(GifDecoder())
|
||||
}
|
||||
add(SvgDecoder(applicationContext))
|
||||
}
|
||||
okHttpClient(okHttpClient)
|
||||
}
|
||||
}
|
||||
companion object {
|
||||
private val TAG = NextcloudTalkApplication::class.java.simpleName
|
||||
//region Singleton
|
||||
|
@ -20,13 +20,15 @@
|
||||
|
||||
package com.nextcloud.talk.controllers
|
||||
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Parcelable
|
||||
@ -35,16 +37,20 @@ import android.text.InputFilter
|
||||
import android.text.TextUtils
|
||||
import android.text.TextWatcher
|
||||
import android.util.Log
|
||||
import android.util.TypedValue
|
||||
import android.view.*
|
||||
import android.widget.*
|
||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||
import androidx.emoji.text.EmojiCompat
|
||||
import androidx.emoji.widget.EmojiEditText
|
||||
import androidx.emoji.widget.EmojiTextView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import autodagger.AutoInjector
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import coil.api.load
|
||||
import coil.transform.CircleCropTransformation
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
|
||||
@ -54,6 +60,7 @@ import com.facebook.datasource.DataSource
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
||||
import com.facebook.imagepipeline.image.CloseableImage
|
||||
import com.google.android.flexbox.FlexboxLayout
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.MagicCallActivity
|
||||
import com.nextcloud.talk.adapters.messages.*
|
||||
@ -108,7 +115,7 @@ import javax.inject.Inject
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
.OnLoadMoreListener, MessagesListAdapter.Formatter<Date>, MessagesListAdapter
|
||||
.OnMessageLongClickListener<IMessage>, MessageHolders.ContentChecker<IMessage> {
|
||||
.OnMessageViewLongClickListener<IMessage>, MessageHolders.ContentChecker<IMessage> {
|
||||
|
||||
@Inject
|
||||
@JvmField
|
||||
@ -150,6 +157,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
@JvmField
|
||||
var conversationLobbyText: TextView? = null
|
||||
val disposableList = ArrayList<Disposable>()
|
||||
@JvmField
|
||||
@BindView(R.id.quotedChatMessageView)
|
||||
var quotedChatMessageView: RelativeLayout? = null
|
||||
var roomToken: String? = null
|
||||
val conversationUser: UserEntity?
|
||||
val roomPassword: String
|
||||
@ -202,7 +212,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
if (conversationUser?.userId == "?") {
|
||||
credentials = null
|
||||
} else {
|
||||
credentials = ApiUtils.getCredentials(conversationUser.username, conversationUser.token)
|
||||
credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)
|
||||
}
|
||||
|
||||
if (args.containsKey(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
|
||||
@ -300,7 +310,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
.intrinsicWidth.toFloat(), activity).toInt()
|
||||
|
||||
val imageRequest = DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(conversationUser?.baseUrl,
|
||||
currentConversation?.name, avatarSize / 2), null)
|
||||
currentConversation?.name, avatarSize / 2), conversationUser!!)
|
||||
|
||||
val imagePipeline = Fresco.getImagePipeline()
|
||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
||||
@ -362,7 +372,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
messagesListView?.setAdapter(adapter)
|
||||
adapter?.setLoadMoreListener(this)
|
||||
adapter?.setDateHeadersFormatter { format(it) }
|
||||
adapter?.setOnMessageLongClickListener { onMessageLongClick(it) }
|
||||
adapter?.setOnMessageViewLongClickListener { view, message -> onMessageViewLongClick(view, message)}
|
||||
|
||||
layoutManager = messagesListView?.layoutManager as LinearLayoutManager?
|
||||
|
||||
@ -403,7 +413,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
val filters = arrayOfNulls<InputFilter>(1)
|
||||
val lengthFilter = conversationUser?.messageMaxLength ?: 1000
|
||||
|
||||
|
||||
filters[0] = InputFilter.LengthFilter(lengthFilter)
|
||||
messageInput?.filters = filters
|
||||
|
||||
@ -831,16 +840,22 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
|
||||
messageInput?.setText("")
|
||||
sendMessage(editable)
|
||||
val replyMessageId: Long? = view?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.tag as Long?
|
||||
sendMessage(editable, if (view?.findViewById<RelativeLayout>(R.id.quotedChatMessageView)?.visibility == View.VISIBLE) replyMessageId?.toInt() else null )
|
||||
cancelReply()
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendMessage(message: CharSequence) {
|
||||
private fun sendMessage(message: CharSequence, replyTo: Int?) {
|
||||
|
||||
if (conversationUser != null) {
|
||||
ncApi?.sendChatMessage(credentials, ApiUtils.getUrlForChat(conversationUser?.baseUrl,
|
||||
roomToken),
|
||||
message, conversationUser.displayName)
|
||||
ncApi!!.sendChatMessage(
|
||||
credentials, ApiUtils.getUrlForChat(
|
||||
conversationUser.baseUrl,
|
||||
roomToken
|
||||
),
|
||||
message, conversationUser.displayName, replyTo
|
||||
)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<GenericOverall> {
|
||||
@ -1240,12 +1255,71 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMessageLongClick(message: IMessage) {
|
||||
if (activity != null) {
|
||||
val clipboardManager = activity?.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
|
||||
val clipData = android.content.ClipData.newPlainText(
|
||||
resources?.getString(R.string.nc_app_name), message.text)
|
||||
clipboardManager.primaryClip = clipData
|
||||
@OnClick(R.id.cancelReplyButton)
|
||||
fun cancelReply() {
|
||||
quotedChatMessageView?.visibility = View.GONE
|
||||
messageInputView?.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.VISIBLE
|
||||
messageInputView?.findViewById<Space>(R.id.attachmentButtonSpace)?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
override fun onMessageViewLongClick(view: View?, message: IMessage?) {
|
||||
PopupMenu(this.context, view, if (message?.user?.id == conversationUser?.userId) Gravity.END else Gravity.START).apply {
|
||||
setOnMenuItemClickListener { item ->
|
||||
when (item?.itemId) {
|
||||
|
||||
R.id.action_copy_message -> {
|
||||
val clipboardManager =
|
||||
activity?.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
|
||||
val clipData = ClipData.newPlainText(resources?.getString(R.string.nc_app_name), message?.text)
|
||||
clipboardManager.setPrimaryClip(clipData)
|
||||
true
|
||||
}
|
||||
R.id.action_reply_to_message -> {
|
||||
val chatMessage = message as ChatMessage?
|
||||
chatMessage?.let {
|
||||
messageInputView?.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.GONE
|
||||
messageInputView?.findViewById<Space>(R.id.attachmentButtonSpace)?.visibility = View.GONE
|
||||
messageInputView?.findViewById<ImageButton>(R.id.cancelReplyButton)?.visibility = View.VISIBLE
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage)?.maxLines = 2
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage)?.ellipsize = TextUtils.TruncateAt.END
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessage)?.text = it.text
|
||||
messageInputView?.findViewById<TextView>(R.id.quotedMessageTime)?.text = DateFormatter.format(it.createdAt, DateFormatter.Template.TIME)
|
||||
messageInputView?.findViewById<EmojiTextView>(R.id.quotedMessageAuthor)?.text = it.actorDisplayName ?: context!!.getText(R.string.nc_nick_guest)
|
||||
|
||||
conversationUser?.let { currentUser ->
|
||||
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedUserAvatar)?.load(it.user.avatar) {
|
||||
addHeader("Authorization", credentials!!)
|
||||
transformations(CircleCropTransformation())
|
||||
}
|
||||
|
||||
chatMessage.imageUrl?.let{ previewImageUrl ->
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.VISIBLE
|
||||
|
||||
val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 96f, resources?.displayMetrics)
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.maxHeight = px.toInt()
|
||||
val layoutParams = messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.layoutParams as FlexboxLayout.LayoutParams
|
||||
layoutParams.flexGrow = 0f
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.layoutParams = layoutParams
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.load(previewImageUrl) {
|
||||
addHeader("Authorization", credentials!!)
|
||||
}
|
||||
} ?: run {
|
||||
messageInputView?.findViewById<ImageView>(R.id.quotedMessageImage)?.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
quotedChatMessageView?.tag = message?.jsonMessageId
|
||||
quotedChatMessageView?.visibility = View.VISIBLE
|
||||
}
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
inflate(R.menu.chat_message_menu)
|
||||
menu.findItem(R.id.action_reply_to_message).isVisible = (message as ChatMessage).replyable
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,7 +574,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
.setOldController(conversationAvatarImageView.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser!!.baseUrl,
|
||||
conversation!!.name, R.dimen.avatar_size_big), null))
|
||||
conversation!!.name, R.dimen.avatar_size_big), conversationUser))
|
||||
.build()
|
||||
conversationAvatarImageView.controller = draweeController
|
||||
}
|
||||
|
@ -161,7 +161,7 @@ public class DisplayUtils {
|
||||
|
||||
public static ImageRequest getImageRequestForUrl(String url, @Nullable UserEntity userEntity) {
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
if (userEntity != null && url.startsWith(userEntity.getBaseUrl()) && url.contains("index.php/core/preview?fileId=")) {
|
||||
if (userEntity != null && url.startsWith(userEntity.getBaseUrl()) && (url.contains("index.php/core/preview?fileId=") || url.contains("/avatar/"))) {
|
||||
headers.put("Authorization", ApiUtils.getCredentials(userEntity.getUsername(), userEntity.getToken()));
|
||||
}
|
||||
|
||||
|
5
app/src/main/res/drawable/ic_content_copy_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_content_copy_white_24dp.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="#FFFFFF" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_reply_white_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_reply_white_24dp.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<vector android:autoMirrored="true" android:height="24dp"
|
||||
android:tint="#FFFFFF" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M10,9V5l-7,7 7,7v-4.1c5,0 8.5,1.6 11,5.1 -1,-5 -4,-10 -11,-11z"/>
|
||||
</vector>
|
@ -22,7 +22,8 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:keepScreenOn="true">
|
||||
android:keepScreenOn="true"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<include layout="@layout/lobby_view"
|
||||
android:visibility="gone"/>
|
||||
@ -52,6 +53,7 @@
|
||||
|
||||
<com.stfalcon.chatkit.messages.MessageInput
|
||||
android:id="@+id/messageInputView"
|
||||
android:animateLayoutChanges="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
|
@ -89,7 +89,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:backgroundTint="@color/colorPrimary"
|
||||
android:layout_margin="16dp"
|
||||
app:tint="@color/white"
|
||||
app:srcCompat="@drawable/ic_add_white_24px"/>
|
||||
|
||||
<include layout="@layout/fast_scroller" />
|
||||
|
@ -19,15 +19,22 @@
|
||||
-->
|
||||
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RelativeLayout android:layout_height="wrap_content" android:layout_width="match_parent">
|
||||
<include layout="@layout/item_message_quote"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:layout_marginBottom="4dp"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<androidx.emoji.widget.EmojiEditText
|
||||
android:id="@id/messageInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_below="@+id/quotedChatMessageView"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_toStartOf="@id/sendButtonSpace"
|
||||
android:layout_toEndOf="@id/attachmentButtonSpace"
|
||||
android:imeOptions="actionDone"
|
||||
@ -38,14 +45,14 @@
|
||||
android:id="@id/attachmentButton"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_below="@id/quotedChatMessageView"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/smileyButton"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_below="@id/quotedChatMessageView"
|
||||
android:layout_toStartOf="@id/messageSendButton"
|
||||
android:background="@color/transparent"
|
||||
android:src="@drawable/ic_insert_emoticon_black_24dp"
|
||||
@ -56,21 +63,25 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_below="@id/quotedChatMessageView"
|
||||
android:adjustViewBounds="true"
|
||||
android:padding="4dp"
|
||||
android:scaleType="centerInside" />
|
||||
|
||||
<androidx.legacy.widget.Space
|
||||
<Space
|
||||
android:id="@id/attachmentButtonSpace"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_below="@id/quotedChatMessageView"
|
||||
android:layout_toEndOf="@id/attachmentButton" />
|
||||
|
||||
<androidx.legacy.widget.Space
|
||||
<Space
|
||||
android:id="@id/sendButtonSpace"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_below="@id/quotedChatMessageView"
|
||||
android:layout_toStartOf="@id/smileyButton" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</merge>
|
||||
|
17
app/src/main/res/menu/chat_message_menu.xml
Normal file
17
app/src/main/res/menu/chat_message_menu.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_copy_message"
|
||||
android:icon="@drawable/ic_content_copy_white_24dp"
|
||||
android:title="@string/nc_copy_message"
|
||||
app:showAsAction="always"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_reply_to_message"
|
||||
android:icon="@drawable/ic_reply_white_24dp"
|
||||
android:title="@string/nc_reply"
|
||||
app:showAsAction="always"
|
||||
/>
|
||||
</menu>
|
@ -298,5 +298,28 @@
|
||||
<string name="nc_lobby_waiting">You are currently waiting in the lobby.</string>
|
||||
<string name="nc_lobby_waiting_with_date">You are currently waiting in the lobby.\n This
|
||||
meeting is scheduled for %1$s.</string>
|
||||
<string name="nc_manual">Manual</string>
|
||||
<string name="nc_manual">Not set</string>
|
||||
|
||||
<!-- Errors -->
|
||||
<string name="nc_no_connection_error">No connection</string>
|
||||
<string name="nc_bad_response_error">Bad response</string>
|
||||
<string name="nc_timeout_error">Timeout</string>
|
||||
<string name="nc_empty_response_error">Empty response</string>
|
||||
<string name="nc_not_defined_error">Unknown error</string>
|
||||
<string name="nc_unauthorized_error">Unauthorized</string>
|
||||
|
||||
<string name="nc_general_settings">General</string>
|
||||
<string name="nc_allow_guests">Allow guests</string>
|
||||
<string name="nc_last_moderator_title">Could not leave conversation</string>
|
||||
<string name="nc_last_moderator">You need to promote a new moderator before you can leave %1$s.</string>
|
||||
|
||||
<!-- Chat -->
|
||||
<string name="nc_99_plus">99+</string>
|
||||
<string name="nc_copy_message">Copy</string>
|
||||
<string name="nc_reply">Reply</string>
|
||||
|
||||
<!-- Non-translatable strings -->
|
||||
|
||||
<string name="path_password_strike_through" translatable="false"
|
||||
tools:override="true">M3.27,4.27L19.74,20.74</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user