瀏覽代碼

Basic Edit feature

sowjanyakch 1 年之前
父節點
當前提交
5ecfd3cd3b

+ 1 - 0
app/src/main/java/com/nextcloud/talk/api/NcApi.java

@@ -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);
 

+ 162 - 15
app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt

@@ -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,7 @@ class ChatActivity :
                 }
 
                 val editable = binding.messageInputView.inputEditText?.editableText
+
                 if (editable != null && binding.messageInputView.inputEditText != null) {
                     val mentionSpans = editable.getSpans(
                         0,
@@ -800,6 +815,7 @@ class ChatActivity :
                         }
                     }
                 }
+
             }
 
             override fun afterTextChanged(s: Editable) {
@@ -809,30 +825,155 @@ class ChatActivity :
 
         // Image keyboard support
         // See: https://developer.android.com/guide/topics/text/image-keyboard
-        (binding.messageInputView.inputEditText as ImageEmojiEditText).onCommitContentListener = {
-            uploadFile(it.toString(), false)
-        }
+            (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)
+               }
 
-        initVoiceRecordButton()
+            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)
+    }
 
-        if (sharedText.isNotEmpty()) {
-            binding.messageInputView.inputEditText?.setText(sharedText)
+
+    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,
+                        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
+                binding.messageInputView.messageSendButton.visibility = GONE
+            }
+        })
+
         binding.messageInputView.setAttachmentsListener {
             AttachmentDialog(this, this).show()
         }
 
-        binding.messageInputView.button?.setOnClickListener { submitMessage(false) }
+        binding.messageInputView.editMessageButton.setOnClickListener {
+            editMessageAPI(message, editedMessage = editText)
+        }
 
-        if (CapabilitiesUtilNew.hasSpreedFeatureCapability(conversationUser, "silent-send")) {
-            binding.messageInputView.button?.setOnLongClickListener {
-                showSendButtonMenu()
-                true
-            }
+    }
+
+    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))
         }
 
-        binding.messageInputView.button?.contentDescription =
-            resources?.getString(R.string.nc_description_send_message_button)
+        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 {

+ 2 - 0
app/src/main/java/com/nextcloud/talk/ui/MessageInput.kt

@@ -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

+ 5 - 0
app/src/main/res/drawable/ic_check_24.xml

@@ -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>

+ 5 - 0
app/src/main/res/drawable/ic_edit_24.xml

@@ -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>

+ 14 - 0
app/src/main/res/layout/view_message_input.xml

@@ -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"