Commit c3307c64 authored by Leonardo Aramaki's avatar Leonardo Aramaki

Add editing action to message menu; still needs proper permission checker

parent 1dd6ad10
......@@ -6,7 +6,10 @@ import android.os.Build
import android.os.Bundle
import android.support.v4.app.Fragment
import android.text.style.ClickableSpan
import android.view.*
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.ImageButton
import android.widget.ScrollView
import android.widget.Toast
......@@ -167,8 +170,9 @@ class LoginFragment : Fragment(), LoginView {
enableUserInput(true)
}
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showMessage(resId: Int) = showMessage(getString(resId))
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
......@@ -216,7 +220,7 @@ class LoginFragment : Fragment(), LoginView {
}
// Returns true if *all* EditTexts are empty.
private fun isEditTextEmpty(): Boolean = text_username_or_email.textContent.isBlank() && text_password.textContent.isEmpty()
private fun isEditTextEmpty(): Boolean = text_username_or_email.textContent.isBlank() && text_password.textContent.isEmpty()
private fun showRemainingSocialAccountsView() {
social_accounts_container.postDelayed({
......
package chat.rocket.android.authentication.server.ui
import android.os.Bundle
import android.support.annotation.StringRes
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
......@@ -56,6 +57,8 @@ class ServerFragment : Fragment(), ServerView {
enableUserInput(true)
}
override fun showMessage(resId: Int) = showMessage(getString(resId))
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
......
......@@ -100,6 +100,8 @@ class SignupFragment : Fragment(), SignupView {
enableUserInput(true)
}
override fun showMessage(resId: Int) = showMessage(getString(resId))
override fun showMessage(message: String) {
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
}
......
......@@ -83,6 +83,8 @@ class TwoFAFragment : Fragment(), TwoFAView {
enableUserInput(true)
}
override fun showMessage(resId: Int) = showMessage(getString(resId))
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
......
package chat.rocket.android.chatroom.presentation
import chat.rocket.android.R
import chat.rocket.android.chatroom.viewmodel.MessageViewModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.*
......@@ -13,10 +14,7 @@ import chat.rocket.core.internal.realtime.State
import chat.rocket.core.internal.realtime.connect
import chat.rocket.core.internal.realtime.subscribeRoomMessages
import chat.rocket.core.internal.realtime.unsubscibre
import chat.rocket.core.internal.rest.deleteMessage
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.messages
import chat.rocket.core.internal.rest.sendMessage
import chat.rocket.core.internal.rest.*
import chat.rocket.core.model.Message
import chat.rocket.core.model.Value
import kotlinx.coroutines.experimental.CommonPool
......@@ -67,11 +65,16 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
}
fun sendMessage(chatRoomId: String, text: String) {
fun sendMessage(chatRoomId: String, text: String, messageId: String?) {
launchUI(strategy) {
view.disableMessageInput()
try {
val message = client.sendMessage(chatRoomId, text)
val message: Message
if (messageId == null) {
message = client.sendMessage(chatRoomId, text)
} else {
message = client.updateMessage(chatRoomId, messageId, text)
}
// ignore message for now, will receive it on the stream
view.enableMessageInput(clear = true)
} catch (ex: Exception) {
......@@ -79,8 +82,8 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
view.showGenericErrorMessage()
}
view.enableMessageInput()
}
......@@ -192,7 +195,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
is RoomType.Livechat -> "livechat"
is RoomType.Custom -> "custom" //TODO: put appropriate callback string here.
}
view.showReplyStatus("[ ](${serverUrl}/${room}/${roomName}?msg=${id}) ${mention} ", m.message)
view.showReplyingAction(user, "[ ](${serverUrl}/${room}/${roomName}?msg=${id}) ${mention} ", m.message)
}
}
}
......@@ -214,6 +217,24 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
}
/**
* Update message identified by given id with given text.
*
* @param roomId The id of the room of the message.
* @param messageId The id of the message to update.
* @param text The updated text.
*/
fun editMessage(roomId: String, messageId: String, text: String) {
launchUI(strategy) {
if (!getPermissionsInteractor.isMessageEditingAllowed()) {
coroutineContext.cancel()
view.showMessage(R.string.permission_editing_not_allowed)
return@launchUI
}
view.showEditingAction(roomId, messageId, text)
}
}
private suspend fun listenMessages(roomId: String) {
launch(CommonPool + strategy.jobs) {
for (message in client.messagesChannel) {
......
......@@ -45,10 +45,11 @@ interface ChatRoomView : LoadingView, MessageView {
/**
* Show reply status above the message composer.
*
* @param username The username or name of the user to reply/quote to.
* @param replyMarkdown The markdown of the message reply.
* @param quotedMessage The message to quote.
*/
fun showReplyStatus(replyMarkdown: String, quotedMessage: String)
fun showReplyingAction(username: String, replyMarkdown: String, quotedMessage: String)
/**
* Copy message to clipboard.
......@@ -57,6 +58,11 @@ interface ChatRoomView : LoadingView, MessageView {
*/
fun copyToClipboard(message: String)
/**
* Show edit status above the message composer.
*/
fun showEditingAction(roomId: String, messageId: String, text: String)
fun disableMessageInput()
fun enableMessageInput(clear: Boolean = false)
}
\ No newline at end of file
......@@ -15,38 +15,49 @@ import chat.rocket.android.helper.MessageParser
import chat.rocket.android.util.content
import ru.noties.markwon.Markwon
class CitationSnackbar : BaseTransientBottomBar<CitationSnackbar> {
class ActionSnackbar : BaseTransientBottomBar<ActionSnackbar> {
companion object {
fun make(parentViewGroup: ViewGroup, content: String): CitationSnackbar {
fun make(parentViewGroup: ViewGroup, content: String): ActionSnackbar {
val context = parentViewGroup.context
val view = LayoutInflater.from(context).inflate(R.layout.message_action_bar, parentViewGroup, false)
val citationSnackbar = CitationSnackbar(parentViewGroup, view, CallbackImpl(view))
citationSnackbar.textView = view.findViewById(R.id.text_view_action_text) as TextView
val citationSnackbar = ActionSnackbar(parentViewGroup, view, CallbackImpl(view))
citationSnackbar.messageTextView = view.findViewById(R.id.text_view_action_text) as TextView
citationSnackbar.titleTextView = view.findViewById(R.id.text_view_action_title) as TextView
citationSnackbar.cancelView = view.findViewById(R.id.image_view_action_cancel_quote) as ImageView
citationSnackbar.duration = BaseTransientBottomBar.LENGTH_INDEFINITE
val spannable = SpannableString(content)
citationSnackbar.marginDrawable = context.getDrawable(R.drawable.quote)
spannable.setSpan(MessageParser.QuoteMarginSpan(citationSnackbar.marginDrawable, 10), 0, content.length, 0)
citationSnackbar.textView.content = spannable
citationSnackbar.messageTextView.content = spannable
return citationSnackbar
}
}
lateinit var cancelView: View
private lateinit var textView: TextView
private lateinit var messageTextView: TextView
private lateinit var titleTextView: TextView
private lateinit var marginDrawable: Drawable
var text: String = ""
set(value) {
val spannable = Markwon.markdown(this.context, value) as Spannable
spannable.setSpan(MessageParser.QuoteMarginSpan(marginDrawable, 10), 0, spannable.length, 0)
textView.content = spannable
messageTextView.content = spannable
}
var title: String = ""
set(value) {
val spannable = Markwon.markdown(this.context, value) as Spannable
spannable.setSpan(MessageParser.QuoteMarginSpan(marginDrawable, 10), 0, spannable.length, 0)
titleTextView.content = spannable
}
override fun dismiss() {
super.dismiss()
text = ""
title = ""
}
private constructor(parentViewGroup: ViewGroup, content: View, contentViewCallback: BaseTransientBottomBar.ContentViewCallback) :
......
......@@ -114,6 +114,7 @@ class ChatRoomAdapter(private val serverUrl: String,
R.id.action_menu_msg_quote -> presenter.citeMessage(serverUrl, roomType, roomName, id, "", false)
R.id.action_menu_msg_reply -> presenter.citeMessage(serverUrl, roomType, roomName, id, "", true)
R.id.action_menu_msg_copy -> presenter.copyMessage(id)
R.id.action_menu_msg_edit -> presenter.editMessage(roomId, id, getOriginalMessage())
else -> TODO("Not implemented")
}
}
......
......@@ -49,8 +49,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
private lateinit var chatRoomType: String
private var isChatRoomReadOnly: Boolean = false
private lateinit var adapter: ChatRoomAdapter
private lateinit var citationSnackbar: CitationSnackbar
private lateinit var actionSnackbar: ActionSnackbar
private var citation: String? = null
private var editingMessageId: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -73,7 +74,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
super.onViewCreated(view, savedInstanceState)
presenter.loadMessages(chatRoomId, chatRoomType)
setupComposer()
setupCitationSnackbar()
setupActionSnackbar()
}
override fun onDestroyView() {
......@@ -104,7 +105,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
override fun sendMessage(text: String) {
if (!text.isBlank()) {
presenter.sendMessage(chatRoomId, text)
presenter.sendMessage(chatRoomId, text, editingMessageId)
}
}
......@@ -133,11 +134,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
adapter.removeItem(msgId)
}
override fun showReplyStatus(replyMarkdown: String, quotedMessage: String) {
override fun showReplyingAction(username: String, replyMarkdown: String, quotedMessage: String) {
activity?.apply {
citation = replyMarkdown
citationSnackbar.text = quotedMessage
citationSnackbar.show()
actionSnackbar.title = username
actionSnackbar.text = quotedMessage
actionSnackbar.show()
}
}
......@@ -147,6 +149,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showMessage(resId: Int) = showMessage(getString(resId))
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun copyToClipboard(message: String) {
......@@ -156,6 +160,17 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
}
}
override fun showEditingAction(roomId: String, messageId: String, text: String) {
activity?.apply {
actionSnackbar.title = getString(R.string.action_title_editing)
actionSnackbar.text = text
actionSnackbar.show()
text_message.textContent = text
editingMessageId = messageId
}
}
private fun setupComposer() {
if (isChatRoomReadOnly) {
text_room_is_read_only.setVisible(true)
......@@ -165,20 +180,22 @@ class ChatRoomFragment : Fragment(), ChatRoomView {
var textMessage = citation ?: ""
textMessage = textMessage + text_message.textContent
sendMessage(textMessage)
clearCitation()
clearActionMessage()
}
}
}
private fun setupCitationSnackbar() {
citationSnackbar = CitationSnackbar.make(message_list_container, "")
citationSnackbar.cancelView.setOnClickListener({
clearCitation()
private fun setupActionSnackbar() {
actionSnackbar = ActionSnackbar.make(message_list_container, "")
actionSnackbar.cancelView.setOnClickListener({
clearActionMessage()
})
}
private fun clearCitation() {
private fun clearActionMessage() {
citation = null
citationSnackbar.dismiss()
editingMessageId = null
text_message.text.clear()
actionSnackbar.dismiss()
}
}
\ No newline at end of file
......@@ -99,6 +99,8 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
override fun hideLoading() = view_loading.setVisible(false)
override fun showMessage(resId: Int) = showMessage(getString(resId))
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
......
package chat.rocket.android.core.behaviours
import android.support.annotation.StringRes
interface MessageView {
/**
* Show message given by resource id.
*
* @param resId The resource id on strings.xml of the message.
*/
fun showMessage(@StringRes resId: Int)
fun showMessage(message: String)
fun showGenericErrorMessage()
......
......@@ -79,6 +79,8 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
enableUserInput(true)
}
override fun showMessage(resId: Int) = showMessage(getString(resId))
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
......
......@@ -3,7 +3,6 @@
android:shape="rectangle">
<solid android:color="@color/darkGray" />
<corners android:radius="2dp" />
<size
android:width="4dp"
android:height="4dp" />
......
......@@ -7,13 +7,12 @@
android:background="@color/colorPrimary">
<TextView
android:id="@+id/text_view_quote"
android:id="@+id/text_view_action_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/white"
......@@ -21,12 +20,12 @@
android:typeface="normal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_view_cancel_quote"
app:layout_constraintTop_toTopOf="parent"
tools:text="quoted message" />
app:layout_constraintStart_toEndOf="@+id/image_view_action_cancel_quote"
app:layout_constraintTop_toBottomOf="@+id/text_view_action_title"
tools:text="action text" />
<ImageView
android:id="@+id/image_view_cancel_quote"
android:id="@+id/image_view_action_cancel_quote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
......@@ -36,4 +35,19 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_close_white_24dp" />
<TextView
android:id="@+id/text_view_action_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:textColor="@color/colorAccent"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/text_view_action_text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_view_action_cancel_quote"
app:layout_constraintTop_toTopOf="parent"
tools:text="Edit message" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
......@@ -12,9 +12,10 @@
android:icon="@drawable/ic_quote_black_24px"
android:title="@string/action_msg_quote" />
<!--<item-->
<!--android:id="@+id/action_menu_msg_edit"-->
<!--android:title="@string/action_msg_edit" />-->
<item
android:id="@+id/action_menu_msg_edit"
android:icon="@drawable/ic_edit_black_24px"
android:title="@string/action_msg_edit" />
<item
android:id="@+id/action_menu_msg_copy"
......@@ -22,19 +23,19 @@
android:title="@string/action_msg_copy" />
<!--<item-->
<!--android:id="@+id/action_menu_msg_share"-->
<!--android:icon="@drawable/ic_share_black_24px"-->
<!--android:title="@string/action_msg_share" />-->
<!--android:id="@+id/action_menu_msg_share"-->
<!--android:icon="@drawable/ic_share_black_24px"-->
<!--android:title="@string/action_msg_share" />-->
<!--<item-->
<!--android:id="@+id/action_menu_msg_pin"-->
<!--android:icon="@drawable/ic_pin_black_24dp"-->
<!--android:title="@string/action_msg_pin" />-->
<!--android:id="@+id/action_menu_msg_pin"-->
<!--android:icon="@drawable/ic_pin_black_24dp"-->
<!--android:title="@string/action_msg_pin" />-->
<!--<item-->
<!--android:id="@+id/action_menu_msg_star"-->
<!--android:icon="@drawable/ic_star_black_24px"-->
<!--android:title="@string/action_msg_star" />-->
<!--android:id="@+id/action_menu_msg_star"-->
<!--android:icon="@drawable/ic_star_black_24px"-->
<!--android:title="@string/action_msg_star" />-->
</group>
<group android:id="@+id/dangerous_actions">
......
......@@ -65,5 +65,9 @@
<string name="action_msg_pin">Pinar Mensagem</string>
<string name="action_msg_star">Favoritar Mensagem</string>
<string name="action_msg_share">Compartilhar</string>
<string name="action_title_editing">Editando Mensagem</string>
<!-- Permission messages -->
<string name="permission_editing_not_allowed">Edição não permitida</string>
</resources>
\ No newline at end of file
......@@ -67,5 +67,9 @@
<string name="action_msg_pin">Pin Message</string>
<string name="action_msg_star">Star Message</string>
<string name="action_msg_share">Share</string>
<string name="action_title_editing">Editing Message</string>
<!-- Permission messages -->
<string name="permission_editing_not_allowed">Editing not allowed</string>
</resources>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment