Commit 677a5eec authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Merge branch 'develop-2.x' of https://github.com/RocketChat/Rocket.Chat.Android into fix/logout

parents 95ba6ac3 61cb7b9e
......@@ -8,14 +8,15 @@ import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.viewmodel.*
import chat.rocket.android.util.extensions.inflate
import chat.rocket.core.model.Message
import chat.rocket.core.model.isSystemMessage
import timber.log.Timber
import java.security.InvalidParameterException
class ChatRoomAdapter(
private val roomType: String,
private val roomName: String,
private val presenter: ChatRoomPresenter?,
private val enableActions: Boolean = true
private val roomType: String,
private val roomName: String,
private val presenter: ChatRoomPresenter?,
private val enableActions: Boolean = true
) : RecyclerView.Adapter<BaseViewHolder<*>>() {
private val dataSet = ArrayList<BaseViewModel<*>>()
......@@ -25,7 +26,7 @@ class ChatRoomAdapter(
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<*> {
return when(viewType.toViewType()) {
return when (viewType.toViewType()) {
BaseViewModel.ViewType.MESSAGE -> {
val view = parent.inflate(R.layout.item_message)
MessageViewHolder(view, actionsListener)
......@@ -86,16 +87,27 @@ class ChatRoomAdapter(
}
fun prependData(dataSet: List<BaseViewModel<*>>) {
this.dataSet.addAll(0, dataSet)
notifyItemRangeInserted(0, dataSet.size)
val item = dataSet.firstOrNull { newItem ->
this.dataSet.indexOfFirst { it.messageId == newItem.messageId && it.viewType == newItem.viewType } > -1
}
if (item == null) {
this.dataSet.addAll(0, dataSet)
notifyItemRangeInserted(0, dataSet.size)
}
}
fun updateItem(message: BaseViewModel<*>) {
val index = dataSet.indexOfLast { it.messageId == message.messageId }
val indexOfFirst = dataSet.indexOfFirst { it.messageId == message.messageId }
Timber.d("index: $index")
if (index > -1) {
dataSet[index] = message
notifyItemChanged(index)
// Delete message only if current is a system message update, i.e.: Message Removed
if (message.message.isSystemMessage() && indexOfFirst > -1 && indexOfFirst != index) {
dataSet.removeAt(indexOfFirst)
notifyItemRemoved(indexOfFirst)
}
}
}
......
......@@ -20,6 +20,9 @@ class MessageViewHolder(
override fun bindViews(data: MessageViewModel) {
with(itemView) {
if (data.isFirstUnread) new_messages_notif.visibility = View.VISIBLE
else new_messages_notif.visibility = View.GONE
text_message_time.text = data.time
text_sender.text = data.senderName
text_content.text = data.content
......
......@@ -20,14 +20,16 @@ import dagger.android.DispatchingAndroidInjector
import dagger.android.support.HasSupportFragmentInjector
import kotlinx.android.synthetic.main.app_bar_chat_room.*
import javax.inject.Inject
import timber.log.Timber
fun Context.chatRoomIntent(chatRoomId: String, chatRoomName: String, chatRoomType: String, isChatRoomReadOnly: Boolean): Intent {
fun Context.chatRoomIntent(chatRoomId: String, chatRoomName: String, chatRoomType: String, isChatRoomReadOnly: Boolean, chatRoomLastSeen: Long): Intent {
return Intent(this, ChatRoomActivity::class.java).apply {
putExtra(INTENT_CHAT_ROOM_ID, chatRoomId)
putExtra(INTENT_CHAT_ROOM_NAME, chatRoomName)
putExtra(INTENT_CHAT_ROOM_TYPE, chatRoomType)
putExtra(INTENT_IS_CHAT_ROOM_READ_ONLY, isChatRoomReadOnly)
putExtra(INTENT_CHAT_ROOM_LAST_SEEN, chatRoomLastSeen)
}
}
......@@ -35,6 +37,7 @@ private const val INTENT_CHAT_ROOM_ID = "chat_room_id"
private const val INTENT_CHAT_ROOM_NAME = "chat_room_name"
private const val INTENT_CHAT_ROOM_TYPE = "chat_room_type"
private const val INTENT_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only"
private const val INTENT_CHAT_ROOM_LAST_SEEN = "chat_room_last_seen"
class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
@Inject lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
......@@ -47,6 +50,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
private lateinit var chatRoomName: String
private lateinit var chatRoomType: String
private var isChatRoomReadOnly: Boolean = false
private var chatRoomLastSeen: Long = -1L
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
......@@ -70,8 +74,10 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
setupToolbar()
chatRoomLastSeen = intent.getLongExtra(INTENT_CHAT_ROOM_LAST_SEEN, -1)
addFragment("ChatRoomFragment", R.id.fragment_container) {
newInstance(chatRoomId, chatRoomName, chatRoomType, isChatRoomReadOnly)
newInstance(chatRoomId, chatRoomName, chatRoomType, isChatRoomReadOnly, chatRoomLastSeen)
}
}
......
......@@ -19,6 +19,7 @@ import chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.presentation.ChatRoomView
import chat.rocket.android.chatroom.viewmodel.BaseViewModel
import chat.rocket.android.chatroom.viewmodel.MessageViewModel
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.MessageParser
......@@ -28,22 +29,25 @@ import chat.rocket.android.widget.emoji.Emoji
import chat.rocket.android.widget.emoji.EmojiKeyboardPopup
import chat.rocket.android.widget.emoji.EmojiParser
import chat.rocket.core.internal.realtime.State
import chat.rocket.core.model.Message
import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.fragment_chat_room.*
import kotlinx.android.synthetic.main.message_attachment_options.*
import kotlinx.android.synthetic.main.item_chat.*
import kotlinx.android.synthetic.main.message_composer.*
import kotlinx.android.synthetic.main.message_list.*
import timber.log.Timber
import javax.inject.Inject
fun newInstance(chatRoomId: String, chatRoomName: String, chatRoomType: String, isChatRoomReadOnly: Boolean): Fragment {
fun newInstance(chatRoomId: String, chatRoomName: String, chatRoomType: String, isChatRoomReadOnly: Boolean, chatRoomLastSeen: Long): Fragment {
return ChatRoomFragment().apply {
arguments = Bundle(1).apply {
putString(BUNDLE_CHAT_ROOM_ID, chatRoomId)
putString(BUNDLE_CHAT_ROOM_NAME, chatRoomName)
putString(BUNDLE_CHAT_ROOM_TYPE, chatRoomType)
putBoolean(BUNDLE_IS_CHAT_ROOM_READ_ONLY, isChatRoomReadOnly)
putLong(BUNDLE_CHAT_ROOM_LAST_SEEN, chatRoomLastSeen)
}
}
}
......@@ -53,18 +57,18 @@ private const val BUNDLE_CHAT_ROOM_NAME = "chat_room_name"
private const val BUNDLE_CHAT_ROOM_TYPE = "chat_room_type"
private const val BUNDLE_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only"
private const val REQUEST_CODE_FOR_PERFORM_SAF = 42
private const val BUNDLE_CHAT_ROOM_LAST_SEEN = "chat_room_last_seen"
class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
@Inject lateinit var presenter: ChatRoomPresenter
@Inject lateinit var parser: MessageParser
private lateinit var adapter: ChatRoomAdapter
private lateinit var chatRoomId: String
private lateinit var chatRoomName: String
private lateinit var chatRoomType: String
private lateinit var emojiKeyboardPopup: EmojiKeyboardPopup
private var isChatRoomReadOnly: Boolean = false
private var chatRoomLastSeen: Long = -1
private lateinit var actionSnackbar: ActionSnackbar
private var citation: String? = null
private var editingMessageId: String? = null
......@@ -89,6 +93,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
chatRoomName = bundle.getString(BUNDLE_CHAT_ROOM_NAME)
chatRoomType = bundle.getString(BUNDLE_CHAT_ROOM_TYPE)
isChatRoomReadOnly = bundle.getBoolean(BUNDLE_IS_CHAT_ROOM_READ_ONLY)
chatRoomLastSeen = bundle.getLong(BUNDLE_CHAT_ROOM_LAST_SEEN)
} else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
}
......@@ -152,6 +157,27 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
}
override fun showMessages(dataSet: List<BaseViewModel<*>>) {
// track the message sent immediately after the current message
var prevMessageViewModel : MessageViewModel? = null
// Loop over received messages to determine first unread
for (i in dataSet.indices) {
val msgModel = dataSet[i]
if (msgModel is MessageViewModel){
val msg = msgModel.rawData
if (msg.timestamp < chatRoomLastSeen) {
// This message was sent before the last seen of the room. Hence, it was seen.
// if there is a message after (below) this, mark it firstUnread.
if (prevMessageViewModel != null) {
prevMessageViewModel.isFirstUnread = true
}
break
}
prevMessageViewModel = msgModel
}
}
activity?.apply {
if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(chatRoomType, chatRoomName, presenter)
......@@ -214,6 +240,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
override fun dispatchUpdateMessage(index: Int, message: List<BaseViewModel<*>>) {
adapter.updateItem(message.last())
if (message.size > 1) {
adapter.updateItem(message.last())
adapter.prependData(listOf(message.first()))
}
}
override fun dispatchDeleteMessage(msgId: String) {
......
......@@ -11,7 +11,8 @@ data class MessageViewModel(
override val time: CharSequence,
override val senderName: CharSequence,
override val content: CharSequence,
override val isPinned: Boolean
override val isPinned: Boolean,
var isFirstUnread: Boolean
) : BaseMessageViewModel<Message> {
override val viewType: Int
get() = BaseViewModel.ViewType.MESSAGE.viewType
......
......@@ -138,16 +138,25 @@ class ViewModelMapper @Inject constructor(private val context: Context,
val quoteUrl = HttpUrl.parse(url.url)
val serverUrl = HttpUrl.parse(baseUrl)
if (quoteUrl != null && serverUrl != null) {
quote = makeQuote(quoteUrl, serverUrl)
quote = makeQuote(quoteUrl, serverUrl)?.let {
getMessageWithoutQuoteMarkdown(it)
}
}
}
}
}
val content = getContent(context, message, quote)
MessageViewModel(message = message, rawData = message, messageId = message.id,
avatar = avatar!!, time = time, senderName = sender,
content = content, isPinned = message.pinned)
val content = getContent(context, getMessageWithoutQuoteMarkdown(message), quote)
MessageViewModel(message = getMessageWithoutQuoteMarkdown(message), rawData = message,
messageId = message.id, avatar = avatar!!, time = time, senderName = sender,
content = content, isPinned = message.pinned, isFirstUnread = false)
}
private fun getMessageWithoutQuoteMarkdown(message: Message): Message {
val baseUrl = settings.baseUrl()
return message.copy(
message = message.message.replace("\\[\\s\\]\\($baseUrl.*\\)".toRegex(), "").trim()
)
}
private fun getSenderName(message: Message): CharSequence {
......@@ -194,7 +203,7 @@ class ViewModelMapper @Inject constructor(private val context: Context,
var quoteViewModel: MessageViewModel? = null
if (quote != null) {
val quoteMessage: Message = quote
quoteViewModel = map(quoteMessage).first { it is MessageViewModel } as MessageViewModel
quoteViewModel = mapMessage(quoteMessage)
}
return parser.renderMarkdown(message.message, quoteViewModel, currentUsername)
}
......
......@@ -69,7 +69,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
}
navigator.toChatRoom(chatRoom.id, roomName,
chatRoom.type.toString(), chatRoom.readonly ?: false)
chatRoom.type.toString(), chatRoom.readonly ?: false, chatRoom.lastSeen ?: -1)
}
/**
......
......@@ -59,6 +59,7 @@ class MessageParser @Inject constructor(val context: Application, private val co
parentNode.appendChild(quoteNode)
quoteNode.accept(QuoteMessageSenderVisitor(context, configuration, builder, senderName.length))
quoteNode = parser.parse("> ${toLenientMarkdown(quote.rawData.message)}")
quoteNode.accept(EmojiVisitor(builder))
quoteNode.accept(QuoteMessageBodyVisitor(context, configuration, builder))
}
parentNode.accept(LinkVisitor(builder))
......
......@@ -29,8 +29,8 @@ class MainNavigator(internal val activity: MainActivity, internal val context: C
}
}
fun toChatRoom(chatRoomId: String, chatRoomName: String, chatRoomType: String, isChatRoomReadOnly: Boolean) {
activity.startActivity(context.chatRoomIntent(chatRoomId, chatRoomName, chatRoomType, isChatRoomReadOnly))
fun toChatRoom(chatRoomId: String, chatRoomName: String, chatRoomType: String, isChatRoomReadOnly: Boolean, chatRoomLastSeen: Long) {
activity.startActivity(context.chatRoomIntent(chatRoomId, chatRoomName, chatRoomType, isChatRoomReadOnly, chatRoomLastSeen))
activity.overridePendingTransition(R.anim.open_enter, R.anim.open_exit)
}
}
\ No newline at end of file
......@@ -4,10 +4,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_marginTop="12dp">
android:background="?android:attr/selectableItemBackground"
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/chat_item_top_and_bottom_padding"
android:paddingBottom="@dimen/chat_item_top_and_bottom_padding">
<include
android:id="@+id/layout_avatar"
......
......@@ -4,10 +4,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_marginTop="6dp">
android:background="?android:attr/selectableItemBackground"
android:paddingBottom="@dimen/member_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/member_item_top_and_bottom_padding">
<include
android:id="@+id/layout_avatar"
......
......@@ -4,10 +4,13 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_marginTop="6dp">
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/message_item_top_and_bottom_padding"
android:paddingBottom="@dimen/message_item_top_and_bottom_padding"
android:focusable="true">
<include
android:id="@+id/layout_avatar"
......@@ -16,7 +19,30 @@
android:layout_height="40dp"
android:layout_marginTop="5dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toBottomOf="@id/new_messages_notif" />
<LinearLayout
android:id="@+id/new_messages_notif"
tools:visibility="visible"
android:visibility="gone"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<View
android:layout_gravity="center"
android:layout_height="1dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_marginRight="4dp"
android:background="@color/red"/>
<TextView
android:layout_width="wrap_content"
android:text="@string/msg_unread_messages"
android:layout_height="wrap_content"
android:textColor="@color/red" />
</LinearLayout>
<LinearLayout
android:id="@+id/top_container"
......@@ -24,6 +50,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:orientation="horizontal"
app:layout_constraintTop_toBottomOf="@id/new_messages_notif"
app:layout_constraintLeft_toRightOf="@+id/layout_avatar">
<TextView
......
......@@ -5,6 +5,7 @@
android:id="@+id/attachment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:paddingStart="72dp"
android:paddingEnd="@dimen/screen_edge_left_and_right_margins"
android:orientation="vertical">
......
......@@ -6,6 +6,7 @@
android:id="@+id/url_preview_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:paddingStart="72dp"
android:paddingEnd="24dp">
......
......@@ -66,6 +66,7 @@
<string name="msg_utc_offset">Deslocamento de UTC</string>
<string name="msg_new_password">Informe a nova senha</string>
<string name="msg_confirm_password">Confirme a nova senha</string>
<string name="msg_unread_messages">Mensagens não lidas</string>
<!-- System messages -->
<string name="message_room_name_changed">Nome da sala alterado para: %1$s por %2$s</string>
......
......@@ -4,6 +4,11 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="screen_edge_left_and_right_margins">16dp</dimen>
<dimen name="screen_edge_left_and_right_padding">16dp</dimen>
<dimen name="chat_item_top_and_bottom_padding">12dp</dimen>
<dimen name="message_item_top_and_bottom_padding">6dp</dimen>
<dimen name="member_item_top_and_bottom_padding">6dp</dimen>
<dimen name="edit_text_margin">10dp</dimen>
<dimen name="edit_text_drawable_padding">16dp</dimen>
......
......@@ -68,6 +68,7 @@
<string name="msg_utc_offset">UTC offset</string>
<string name="msg_new_password">Enter New Password</string>
<string name="msg_confirm_password">Confirm New Password</string>
<string name="msg_unread_messages">Unread messages</string>
<!-- System messages -->
<string name="message_room_name_changed">Room name changed to: %1$s by %2$s</string>
......
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