mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-19 19:49:33 +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 {
|
android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 29
|
||||||
buildToolsVersion '28.0.3'
|
buildToolsVersion '28.0.3'
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "com.nextcloud.talk2"
|
applicationId "com.nextcloud.talk2"
|
||||||
versionName version
|
versionName version
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 28
|
targetSdkVersion 29
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
versionCode 115
|
versionCode 115
|
||||||
@ -213,7 +213,7 @@ dependencies {
|
|||||||
implementation 'me.zhanghai.android.effortlesspermissions:library:1.1.0'
|
implementation 'me.zhanghai.android.effortlesspermissions:library:1.1.0'
|
||||||
implementation 'org.apache.commons:commons-lang3:3.9'
|
implementation 'org.apache.commons:commons-lang3:3.9'
|
||||||
implementation 'com.github.wooplr:Spotlight:1.3'
|
implementation 'com.github.wooplr:Spotlight:1.3'
|
||||||
implementation('com.github.mario:chatkit:a183142049', {
|
implementation('com.github.mario:chatkit:c6a61767291ddb212a2f4f792a2b6aaf295e69a5', {
|
||||||
exclude group: 'com.facebook.fresco'
|
exclude group: 'com.facebook.fresco'
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -223,7 +223,9 @@ dependencies {
|
|||||||
implementation 'com.github.mario.fresco:animated-gif:111'
|
implementation 'com.github.mario.fresco:animated-gif:111'
|
||||||
implementation 'com.github.mario.fresco:imagepipeline-okhttp3:111'
|
implementation 'com.github.mario.fresco:imagepipeline-okhttp3:111'
|
||||||
implementation group: 'joda-time', name: 'joda-time', version: '2.10.3'
|
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.natario1:Autocomplete:v1.1.0'
|
||||||
|
|
||||||
implementation 'com.github.cotechde.hwsecurity:hwsecurity-fido:2.4.5'
|
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.h3xstream.findsecbugs:findsecbugs-plugin:1.9.0'
|
||||||
findbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:7.4.6'
|
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()
|
DraweeController draweeController = Fresco.newDraweeControllerBuilder()
|
||||||
.setOldController(holder.dialogAvatar.getController())
|
.setOldController(holder.dialogAvatar.getController())
|
||||||
.setAutoPlayAnimations(true)
|
.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();
|
.build();
|
||||||
holder.dialogAvatar.setController(draweeController);
|
holder.dialogAvatar.setController(draweeController);
|
||||||
} else {
|
} else {
|
||||||
|
@ -283,7 +283,8 @@ public interface NcApi {
|
|||||||
@POST
|
@POST
|
||||||
Observable<GenericOverall> sendChatMessage(@Header("Authorization") String authorization, @Url String url,
|
Observable<GenericOverall> sendChatMessage(@Header("Authorization") String authorization, @Url String url,
|
||||||
@Field("message") CharSequence message,
|
@Field("message") CharSequence message,
|
||||||
@Field("actorDisplayName") String actorDisplayName);
|
@Field("actorDisplayName") String actorDisplayName,
|
||||||
|
@Field("replyTo") Integer replyTo);
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
Observable<MentionOverall> getMentionAutocompleteSuggestions(@Header("Authorization") String authorization,
|
Observable<MentionOverall> getMentionAutocompleteSuggestions(@Header("Authorization") String authorization,
|
||||||
|
@ -22,6 +22,8 @@ package com.nextcloud.talk.application
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.os.Build.VERSION.SDK_INT
|
||||||
|
import android.os.Build.VERSION_CODES.P
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.emoji.bundled.BundledEmojiCompatConfig
|
import androidx.emoji.bundled.BundledEmojiCompatConfig
|
||||||
import androidx.emoji.text.EmojiCompat
|
import androidx.emoji.text.EmojiCompat
|
||||||
@ -36,6 +38,11 @@ import androidx.work.PeriodicWorkRequest
|
|||||||
import androidx.work.WorkManager
|
import androidx.work.WorkManager
|
||||||
import autodagger.AutoComponent
|
import autodagger.AutoComponent
|
||||||
import autodagger.AutoInjector
|
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.cache.disk.DiskCacheConfig
|
||||||
import com.facebook.drawee.backends.pipeline.Fresco
|
import com.facebook.drawee.backends.pipeline.Fresco
|
||||||
import com.facebook.imagepipeline.core.ImagePipelineConfig
|
import com.facebook.imagepipeline.core.ImagePipelineConfig
|
||||||
@ -130,6 +137,7 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
|||||||
|
|
||||||
componentApplication.inject(this)
|
componentApplication.inject(this)
|
||||||
|
|
||||||
|
Coil.setDefaultImageLoader(::buildDefaultImageLoader)
|
||||||
setAppTheme(appPreferences.theme)
|
setAppTheme(appPreferences.theme)
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
|
||||||
@ -192,6 +200,21 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
|||||||
MultiDex.install(this)
|
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 {
|
companion object {
|
||||||
private val TAG = NextcloudTalkApplication::class.java.simpleName
|
private val TAG = NextcloudTalkApplication::class.java.simpleName
|
||||||
//region Singleton
|
//region Singleton
|
||||||
|
@ -20,13 +20,15 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.controllers
|
package com.nextcloud.talk.controllers
|
||||||
|
|
||||||
|
import android.content.ClipData
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
@ -35,16 +37,20 @@ import android.text.InputFilter
|
|||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.text.TextWatcher
|
import android.text.TextWatcher
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
|
||||||
import androidx.emoji.text.EmojiCompat
|
import androidx.emoji.text.EmojiCompat
|
||||||
import androidx.emoji.widget.EmojiEditText
|
import androidx.emoji.widget.EmojiEditText
|
||||||
|
import androidx.emoji.widget.EmojiTextView
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import autodagger.AutoInjector
|
import autodagger.AutoInjector
|
||||||
import butterknife.BindView
|
import butterknife.BindView
|
||||||
import butterknife.OnClick
|
import butterknife.OnClick
|
||||||
|
import coil.api.load
|
||||||
|
import coil.transform.CircleCropTransformation
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||||
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
|
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.drawee.backends.pipeline.Fresco
|
||||||
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
import com.facebook.imagepipeline.datasource.BaseBitmapDataSubscriber
|
||||||
import com.facebook.imagepipeline.image.CloseableImage
|
import com.facebook.imagepipeline.image.CloseableImage
|
||||||
|
import com.google.android.flexbox.FlexboxLayout
|
||||||
import com.nextcloud.talk.R
|
import com.nextcloud.talk.R
|
||||||
import com.nextcloud.talk.activities.MagicCallActivity
|
import com.nextcloud.talk.activities.MagicCallActivity
|
||||||
import com.nextcloud.talk.adapters.messages.*
|
import com.nextcloud.talk.adapters.messages.*
|
||||||
@ -108,7 +115,7 @@ import javax.inject.Inject
|
|||||||
@AutoInjector(NextcloudTalkApplication::class)
|
@AutoInjector(NextcloudTalkApplication::class)
|
||||||
class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
||||||
.OnLoadMoreListener, MessagesListAdapter.Formatter<Date>, MessagesListAdapter
|
.OnLoadMoreListener, MessagesListAdapter.Formatter<Date>, MessagesListAdapter
|
||||||
.OnMessageLongClickListener<IMessage>, MessageHolders.ContentChecker<IMessage> {
|
.OnMessageViewLongClickListener<IMessage>, MessageHolders.ContentChecker<IMessage> {
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@JvmField
|
@JvmField
|
||||||
@ -150,6 +157,9 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
|||||||
@JvmField
|
@JvmField
|
||||||
var conversationLobbyText: TextView? = null
|
var conversationLobbyText: TextView? = null
|
||||||
val disposableList = ArrayList<Disposable>()
|
val disposableList = ArrayList<Disposable>()
|
||||||
|
@JvmField
|
||||||
|
@BindView(R.id.quotedChatMessageView)
|
||||||
|
var quotedChatMessageView: RelativeLayout? = null
|
||||||
var roomToken: String? = null
|
var roomToken: String? = null
|
||||||
val conversationUser: UserEntity?
|
val conversationUser: UserEntity?
|
||||||
val roomPassword: String
|
val roomPassword: String
|
||||||
@ -202,7 +212,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
|||||||
if (conversationUser?.userId == "?") {
|
if (conversationUser?.userId == "?") {
|
||||||
credentials = null
|
credentials = null
|
||||||
} else {
|
} else {
|
||||||
credentials = ApiUtils.getCredentials(conversationUser.username, conversationUser.token)
|
credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser!!.token)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.containsKey(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
|
if (args.containsKey(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) {
|
||||||
@ -300,7 +310,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
|||||||
.intrinsicWidth.toFloat(), activity).toInt()
|
.intrinsicWidth.toFloat(), activity).toInt()
|
||||||
|
|
||||||
val imageRequest = DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(conversationUser?.baseUrl,
|
val imageRequest = DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithNameAndPixels(conversationUser?.baseUrl,
|
||||||
currentConversation?.name, avatarSize / 2), null)
|
currentConversation?.name, avatarSize / 2), conversationUser!!)
|
||||||
|
|
||||||
val imagePipeline = Fresco.getImagePipeline()
|
val imagePipeline = Fresco.getImagePipeline()
|
||||||
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
val dataSource = imagePipeline.fetchDecodedImage(imageRequest, null)
|
||||||
@ -362,7 +372,7 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
|||||||
messagesListView?.setAdapter(adapter)
|
messagesListView?.setAdapter(adapter)
|
||||||
adapter?.setLoadMoreListener(this)
|
adapter?.setLoadMoreListener(this)
|
||||||
adapter?.setDateHeadersFormatter { format(it) }
|
adapter?.setDateHeadersFormatter { format(it) }
|
||||||
adapter?.setOnMessageLongClickListener { onMessageLongClick(it) }
|
adapter?.setOnMessageViewLongClickListener { view, message -> onMessageViewLongClick(view, message)}
|
||||||
|
|
||||||
layoutManager = messagesListView?.layoutManager as LinearLayoutManager?
|
layoutManager = messagesListView?.layoutManager as LinearLayoutManager?
|
||||||
|
|
||||||
@ -403,7 +413,6 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
|||||||
val filters = arrayOfNulls<InputFilter>(1)
|
val filters = arrayOfNulls<InputFilter>(1)
|
||||||
val lengthFilter = conversationUser?.messageMaxLength ?: 1000
|
val lengthFilter = conversationUser?.messageMaxLength ?: 1000
|
||||||
|
|
||||||
|
|
||||||
filters[0] = InputFilter.LengthFilter(lengthFilter)
|
filters[0] = InputFilter.LengthFilter(lengthFilter)
|
||||||
messageInput?.filters = filters
|
messageInput?.filters = filters
|
||||||
|
|
||||||
@ -831,16 +840,22 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
|||||||
}
|
}
|
||||||
|
|
||||||
messageInput?.setText("")
|
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) {
|
if (conversationUser != null) {
|
||||||
ncApi?.sendChatMessage(credentials, ApiUtils.getUrlForChat(conversationUser?.baseUrl,
|
ncApi!!.sendChatMessage(
|
||||||
roomToken),
|
credentials, ApiUtils.getUrlForChat(
|
||||||
message, conversationUser.displayName)
|
conversationUser.baseUrl,
|
||||||
|
roomToken
|
||||||
|
),
|
||||||
|
message, conversationUser.displayName, replyTo
|
||||||
|
)
|
||||||
?.subscribeOn(Schedulers.io())
|
?.subscribeOn(Schedulers.io())
|
||||||
?.observeOn(AndroidSchedulers.mainThread())
|
?.observeOn(AndroidSchedulers.mainThread())
|
||||||
?.subscribe(object : Observer<GenericOverall> {
|
?.subscribe(object : Observer<GenericOverall> {
|
||||||
@ -1240,12 +1255,71 @@ class ChatController(args: Bundle) : BaseController(args), MessagesListAdapter
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onMessageLongClick(message: IMessage) {
|
@OnClick(R.id.cancelReplyButton)
|
||||||
if (activity != null) {
|
fun cancelReply() {
|
||||||
val clipboardManager = activity?.getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
|
quotedChatMessageView?.visibility = View.GONE
|
||||||
val clipData = android.content.ClipData.newPlainText(
|
messageInputView?.findViewById<ImageButton>(R.id.attachmentButton)?.visibility = View.VISIBLE
|
||||||
resources?.getString(R.string.nc_app_name), message.text)
|
messageInputView?.findViewById<Space>(R.id.attachmentButtonSpace)?.visibility = View.VISIBLE
|
||||||
clipboardManager.primaryClip = clipData
|
}
|
||||||
|
|
||||||
|
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)
|
.setOldController(conversationAvatarImageView.controller)
|
||||||
.setAutoPlayAnimations(true)
|
.setAutoPlayAnimations(true)
|
||||||
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser!!.baseUrl,
|
.setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser!!.baseUrl,
|
||||||
conversation!!.name, R.dimen.avatar_size_big), null))
|
conversation!!.name, R.dimen.avatar_size_big), conversationUser))
|
||||||
.build()
|
.build()
|
||||||
conversationAvatarImageView.controller = draweeController
|
conversationAvatarImageView.controller = draweeController
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ public class DisplayUtils {
|
|||||||
|
|
||||||
public static ImageRequest getImageRequestForUrl(String url, @Nullable UserEntity userEntity) {
|
public static ImageRequest getImageRequestForUrl(String url, @Nullable UserEntity userEntity) {
|
||||||
Map<String, String> headers = new HashMap<>();
|
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()));
|
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"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:keepScreenOn="true">
|
android:keepScreenOn="true"
|
||||||
|
android:animateLayoutChanges="true">
|
||||||
|
|
||||||
<include layout="@layout/lobby_view"
|
<include layout="@layout/lobby_view"
|
||||||
android:visibility="gone"/>
|
android:visibility="gone"/>
|
||||||
@ -52,6 +53,7 @@
|
|||||||
|
|
||||||
<com.stfalcon.chatkit.messages.MessageInput
|
<com.stfalcon.chatkit.messages.MessageInput
|
||||||
android:id="@+id/messageInputView"
|
android:id="@+id/messageInputView"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentBottom="true"
|
android:layout_alignParentBottom="true"
|
||||||
|
@ -89,8 +89,10 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom|end"
|
android:layout_gravity="bottom|end"
|
||||||
|
android:backgroundTint="@color/colorPrimary"
|
||||||
android:layout_margin="16dp"
|
android:layout_margin="16dp"
|
||||||
app:srcCompat="@drawable/ic_add_white_24px" />
|
app:tint="@color/white"
|
||||||
|
app:srcCompat="@drawable/ic_add_white_24px"/>
|
||||||
|
|
||||||
<include layout="@layout/fast_scroller" />
|
<include layout="@layout/fast_scroller" />
|
||||||
|
|
||||||
|
@ -20,57 +20,68 @@
|
|||||||
|
|
||||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<androidx.emoji.widget.EmojiEditText
|
<RelativeLayout android:layout_height="wrap_content" android:layout_width="match_parent">
|
||||||
android:id="@id/messageInput"
|
<include layout="@layout/item_message_quote"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_marginBottom="4dp"
|
||||||
android:layout_toStartOf="@id/sendButtonSpace"
|
android:visibility="gone"/>
|
||||||
android:layout_toEndOf="@id/attachmentButtonSpace"
|
|
||||||
android:imeOptions="actionDone"
|
|
||||||
android:inputType="textAutoCorrect|textMultiLine|textCapSentences"
|
|
||||||
android:lineSpacingMultiplier="1.2" />
|
|
||||||
|
|
||||||
<ImageButton
|
<androidx.emoji.widget.EmojiEditText
|
||||||
android:id="@id/attachmentButton"
|
android:id="@id/messageInput"
|
||||||
android:layout_width="36dp"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="36dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_centerVertical="true"
|
android:layout_below="@+id/quotedChatMessageView"
|
||||||
android:scaleType="centerInside" />
|
android:layout_centerHorizontal="true"
|
||||||
|
android:layout_toStartOf="@id/sendButtonSpace"
|
||||||
|
android:layout_toEndOf="@id/attachmentButtonSpace"
|
||||||
|
android:imeOptions="actionDone"
|
||||||
|
android:inputType="textAutoCorrect|textMultiLine|textCapSentences"
|
||||||
|
android:lineSpacingMultiplier="1.2" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/smileyButton"
|
android:id="@id/attachmentButton"
|
||||||
android:layout_width="36dp"
|
android:layout_width="36dp"
|
||||||
android:layout_height="36dp"
|
android:layout_height="36dp"
|
||||||
android:layout_centerVertical="true"
|
android:layout_below="@id/quotedChatMessageView"
|
||||||
android:layout_toStartOf="@id/messageSendButton"
|
android:scaleType="centerInside" />
|
||||||
android:background="@color/transparent"
|
|
||||||
android:src="@drawable/ic_insert_emoticon_black_24dp"
|
|
||||||
android:tint="@color/emoji_icons" />
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@id/messageSendButton"
|
android:id="@+id/smileyButton"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="36dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="36dp"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_below="@id/quotedChatMessageView"
|
||||||
android:layout_centerVertical="true"
|
android:layout_toStartOf="@id/messageSendButton"
|
||||||
android:adjustViewBounds="true"
|
android:background="@color/transparent"
|
||||||
android:padding="4dp"
|
android:src="@drawable/ic_insert_emoticon_black_24dp"
|
||||||
android:scaleType="centerInside" />
|
android:tint="@color/emoji_icons" />
|
||||||
|
|
||||||
<androidx.legacy.widget.Space
|
<ImageButton
|
||||||
android:id="@id/attachmentButtonSpace"
|
android:id="@id/messageSendButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_toEndOf="@id/attachmentButton" />
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_below="@id/quotedChatMessageView"
|
||||||
|
android:adjustViewBounds="true"
|
||||||
|
android:padding="4dp"
|
||||||
|
android:scaleType="centerInside" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:id="@id/attachmentButtonSpace"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_below="@id/quotedChatMessageView"
|
||||||
|
android:layout_toEndOf="@id/attachmentButton" />
|
||||||
|
|
||||||
|
<Space
|
||||||
|
android:id="@id/sendButtonSpace"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_below="@id/quotedChatMessageView"
|
||||||
|
android:layout_toStartOf="@id/smileyButton" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
<androidx.legacy.widget.Space
|
|
||||||
android:id="@id/sendButtonSpace"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:layout_toStartOf="@id/smileyButton" />
|
|
||||||
|
|
||||||
</merge>
|
</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">You are currently waiting in the lobby.</string>
|
||||||
<string name="nc_lobby_waiting_with_date">You are currently waiting in the lobby.\n This
|
<string name="nc_lobby_waiting_with_date">You are currently waiting in the lobby.\n This
|
||||||
meeting is scheduled for %1$s.</string>
|
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>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user