Basic Edit feature

Signed-off-by: Sowjanya Kota <101803542+sowjanyakch@users.noreply.github.com>
This commit is contained in:
sowjanyakch 2024-01-24 14:00:27 +01:00
parent d8d1de2f35
commit 337f07abfe
6 changed files with 195 additions and 21 deletions

View File

@ -332,6 +332,7 @@ public interface NcApi {
@POST
Observable<GenericOverall> sendChatMessage(@Header("Authorization") String authorization, @Url String url, @Field("message") CharSequence message, @Field("actorDisplayName") String actorDisplayName, @Field("replyTo") Integer replyTo, @Field("silent") Boolean sendWithoutNotification);
@FormUrlEncoded
@PUT
Observable<ChatOCSSingleMessage> editChatMessage(@Header("Authorization") String authorization, @Url String url, @Field("message") String message);

View File

@ -66,6 +66,7 @@ import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.view.View.GONE
import android.view.View.OnTouchListener
import android.view.animation.AccelerateDecelerateInterpolator
import android.view.animation.AccelerateInterpolator
@ -166,6 +167,7 @@ import com.nextcloud.talk.models.domain.ObjectType
import com.nextcloud.talk.models.domain.ReactionAddedModel
import com.nextcloud.talk.models.domain.ReactionDeletedModel
import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.models.json.chat.ChatOCSSingleMessage
import com.nextcloud.talk.models.json.chat.ChatOverall
import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage
import com.nextcloud.talk.models.json.chat.ReadStatus
@ -240,6 +242,7 @@ import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.BehaviorSubject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -299,6 +302,8 @@ class ChatActivity :
lateinit var chatViewModel: ChatViewModel
val editableBehaviorSubject = BehaviorSubject.createDefault(false)
override val view: View
get() = binding.root
@ -348,6 +353,9 @@ class ChatActivity :
private var recorder: MediaRecorder? = null
private lateinit var originalMessage:ChatMessage
private enum class MediaRecorderState {
INITIAL,
INITIALIZED,
@ -756,12 +764,18 @@ class ChatActivity :
val filters = arrayOfNulls<InputFilter>(1)
val lengthFilter = CapabilitiesUtilNew.getMessageMaxLength(conversationUser)
if(!editableBehaviorSubject.value!!){
binding.messageInputView.editMessageButton.visibility = View.GONE
binding.messageInputView.messageSendButton.visibility = View.VISIBLE
}
filters[0] = InputFilter.LengthFilter(lengthFilter)
binding.messageInputView.inputEditText?.filters = filters
binding.messageInputView.inputEditText?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// unused atm
}
@Suppress("Detekt.TooGenericExceptionCaught")
@ -778,6 +792,111 @@ class ChatActivity :
}
val editable = binding.messageInputView.inputEditText?.editableText
if (editable != null && binding.messageInputView.inputEditText != null) {
val mentionSpans = editable.getSpans(
0,
binding.messageInputView.inputEditText!!.length(),
Spans.MentionChipSpan::class.java
)
var mentionSpan: Spans.MentionChipSpan
for (i in mentionSpans.indices) {
mentionSpan = mentionSpans[i]
if (start >= editable.getSpanStart(mentionSpan) &&
start < editable.getSpanEnd(mentionSpan)
) {
if (editable.subSequence(
editable.getSpanStart(mentionSpan),
editable.getSpanEnd(mentionSpan)
).toString().trim { it <= ' ' } != mentionSpan.label
) {
editable.removeSpan(mentionSpan)
}
}
}
}
}
override fun afterTextChanged(s: Editable) {
// unused atm
}
})
// Image keyboard support
// See: https://developer.android.com/guide/topics/text/image-keyboard
(binding.messageInputView.inputEditText as ImageEmojiEditText).onCommitContentListener = {
uploadFile(it.toString(), false)
}
initVoiceRecordButton()
if (sharedText.isNotEmpty()) {
binding.messageInputView.inputEditText?.setText(sharedText)
}
binding.messageInputView.setAttachmentsListener {
AttachmentDialog(this, this).show()
}
binding.messageInputView.button?.setOnClickListener {
submitMessage(false)
}
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-send")) {
binding.messageInputView.button?.setOnLongClickListener {
showSendButtonMenu()
true
}
}
binding.messageInputView.button?.contentDescription =
resources?.getString(R.string.nc_description_send_message_button)
}
private fun editMessageInputView(message:ChatMessage) {
editableBehaviorSubject.onNext(true)
val filters = arrayOfNulls<InputFilter>(1)
val lengthFilter = CapabilitiesUtilNew.getMessageMaxLength(conversationUser)
var editText = ""
filters[0] = InputFilter.LengthFilter(lengthFilter)
binding.messageInputView.inputEditText?.filters = filters
val editableText = Editable.Factory.getInstance().newEditable(message.message)
binding.messageInputView.inputEditText.text = editableText
if(editableBehaviorSubject.value!!){
binding.messageInputView.editMessageButton.visibility = View.VISIBLE
binding.messageInputView.messageSendButton.visibility = View.GONE
binding.messageInputView.button.visibility = GONE
}
binding.messageInputView.inputEditText?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// unused atm
}
@Suppress("Detekt.TooGenericExceptionCaught")
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
updateOwnTypingStatus(s)
if (s.length >= lengthFilter) {
binding.messageInputView.inputEditText?.error = String.format(
Objects.requireNonNull<Resources>(resources).getString(R.string.nc_limit_hit),
lengthFilter.toString()
)
} else {
binding.messageInputView.inputEditText?.error = null
}
val editable = binding.messageInputView.inputEditText?.editableText
editText = editable.toString()
if (editable != null && binding.messageInputView.inputEditText != null) {
val mentionSpans = editable.getSpans(
0,
@ -804,35 +923,57 @@ class ChatActivity :
override fun afterTextChanged(s: Editable) {
// unused atm
binding.messageInputView.messageSendButton.visibility = GONE
}
})
// Image keyboard support
// See: https://developer.android.com/guide/topics/text/image-keyboard
(binding.messageInputView.inputEditText as ImageEmojiEditText).onCommitContentListener = {
uploadFile(it.toString(), false)
}
initVoiceRecordButton()
if (sharedText.isNotEmpty()) {
binding.messageInputView.inputEditText?.setText(sharedText)
}
binding.messageInputView.setAttachmentsListener {
AttachmentDialog(this, this).show()
}
binding.messageInputView.button?.setOnClickListener { submitMessage(false) }
if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-send")) {
binding.messageInputView.button?.setOnLongClickListener {
showSendButtonMenu()
true
}
binding.messageInputView.editMessageButton.setOnClickListener {
editMessageAPI(message, editedMessage = editText)
}
binding.messageInputView.button?.contentDescription =
resources?.getString(R.string.nc_description_send_message_button)
}
private fun editMessageAPI(message:ChatMessage, editedMessage:String){
var apiVersion = 1
// FIXME Fix API checking with guests?
if (conversationUser != null) {
apiVersion = ApiUtils.getChatApiVersion(conversationUser, intArrayOf(1))
}
ncApi.editChatMessage(
credentials,
ApiUtils.getUrlForChatMessage(
apiVersion,
conversationUser?.baseUrl,
roomToken,
message?.id
),editedMessage
)?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : Observer<ChatOCSSingleMessage> {
override fun onSubscribe(d: Disposable) {
// unused atm
}
override fun onNext(t: ChatOCSSingleMessage) {
//unused atm
}
override fun onError(e: Throwable) {
}
override fun onComplete() {
binding.messageInputView.editMessageButton.visibility = GONE
binding.messageInputView.messageSendButton.visibility = View.VISIBLE
editableBehaviorSubject.onNext(false)
binding.messageInputView.inputEditText.setText("")
}
})
}
private fun themeMessageInputView() {
@ -4534,7 +4675,13 @@ class ChatActivity :
startActivity(shareIntent)
}
fun editMessage(message: ChatMessage) {
editMessageInputView(message)
}
companion object {

View File

@ -43,6 +43,7 @@ class MessageInput : MessageInput {
lateinit var sendVoiceRecording: ImageView
lateinit var micInputCloud: MicInputCloud
lateinit var playPauseBtn: MaterialButton
lateinit var editMessageButton:ImageButton
lateinit var seekBar: SeekBar
constructor(context: Context?) : super(context) {
@ -69,6 +70,7 @@ class MessageInput : MessageInput {
micInputCloud = findViewById(R.id.micInputCloud)
playPauseBtn = findViewById(R.id.playPauseBtn)
seekBar = findViewById(R.id.seekbar)
editMessageButton = findViewById(R.id.editMessageButton)
}
var messageInput: EmojiEditText

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
</vector>

View File

@ -229,6 +229,8 @@
android:scaleType="centerInside"
android:contentDescription="@string/nc_description_send_message_button" />
<ImageButton
android:id="@+id/recordAudioButton"
android:layout_width="48dp"
@ -239,6 +241,18 @@
android:src="@drawable/ic_baseline_mic_24"
android:contentDescription="@string/nc_description_record_voice" />
<ImageButton
android:id="@+id/editMessageButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_below="@id/quotedChatMessageView"
android:layout_alignParentEnd="true"
android:background="@color/transparent"
android:src="@drawable/ic_check_24"
android:visibility = "visible"
android:contentDescription="@string/nc_description_record_voice" />
<Space
android:id="@id/attachmentButtonSpace"
android:layout_width="0dp"