Commit 7ecb475c authored by Leonardo Aramaki's avatar Leonardo Aramaki

Redesign reaction username summary dialog

parent d5d544c1
...@@ -62,8 +62,8 @@ abstract class BaseViewHolder<T : BaseUiModel<*>>( ...@@ -62,8 +62,8 @@ abstract class BaseViewHolder<T : BaseUiModel<*>>(
} }
} }
override fun onReactionLongClicked(emojiShortname: String, usernames: List<String>) { override fun onReactionLongClicked(shortname: String, isCustom: Boolean, url: String?, usernames: List<String>) {
reactionListener?.onReactionLongClicked(emojiShortname, usernames) reactionListener?.onReactionLongClicked(shortname, isCustom,url, usernames)
} }
} }
......
...@@ -136,7 +136,7 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() ...@@ -136,7 +136,7 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
} }
override fun onLongClick(v: View?): Boolean { override fun onLongClick(v: View?): Boolean {
listener?.onReactionLongClicked(reaction.shortname, reaction.usernames) listener?.onReactionLongClicked(reaction.shortname, reaction.isCustom, reaction.url, reaction.usernames)
return true return true
} }
} }
......
...@@ -22,7 +22,6 @@ import android.widget.EditText ...@@ -22,7 +22,6 @@ import android.widget.EditText
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import android.widget.Toast
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.text.bold import androidx.core.text.bold
import androidx.core.view.isVisible import androidx.core.view.isVisible
...@@ -58,6 +57,7 @@ import chat.rocket.android.emoji.EmojiKeyboardPopup ...@@ -58,6 +57,7 @@ import chat.rocket.android.emoji.EmojiKeyboardPopup
import chat.rocket.android.emoji.EmojiParser import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiPickerPopup import chat.rocket.android.emoji.EmojiPickerPopup
import chat.rocket.android.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.emoji.internal.GlideApp
import chat.rocket.android.emoji.internal.isCustom import chat.rocket.android.emoji.internal.isCustom
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.ImageHelper import chat.rocket.android.helper.ImageHelper
...@@ -80,10 +80,13 @@ import dagger.android.support.AndroidSupportInjection ...@@ -80,10 +80,13 @@ import dagger.android.support.AndroidSupportInjection
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import kotlinx.android.synthetic.main.emoji_image_row_item.*
import kotlinx.android.synthetic.main.emoji_row_item.*
import kotlinx.android.synthetic.main.fragment_chat_room.* import kotlinx.android.synthetic.main.fragment_chat_room.*
import kotlinx.android.synthetic.main.message_attachment_options.* import kotlinx.android.synthetic.main.message_attachment_options.*
import kotlinx.android.synthetic.main.message_composer.* import kotlinx.android.synthetic.main.message_composer.*
import kotlinx.android.synthetic.main.message_list.* import kotlinx.android.synthetic.main.message_list.*
import kotlinx.android.synthetic.main.reaction_praises_list_item.*
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject import javax.inject.Inject
...@@ -595,7 +598,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -595,7 +598,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun showGenericErrorMessage(){ override fun showGenericErrorMessage() {
ui { ui {
showMessage(getString(R.string.msg_generic_error)) showMessage(getString(R.string.msg_generic_error))
} }
...@@ -672,12 +675,42 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -672,12 +675,42 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
presenter.react(messageId, emoji.shortname) presenter.react(messageId, emoji.shortname)
} }
override fun onReactionLongClicked(emojiShortname: String, usernames: List<String>) { override fun onReactionLongClicked(shortname: String, isCustom: Boolean, url: String?, usernames: List<String>) {
AlertDialog.Builder(requireContext()) val layout = LayoutInflater.from(requireContext()).inflate(R.layout.reaction_praises_list_item, null)
.setTitle(EmojiParser.parse(requireContext(), getString(R.string.alert_title_reactions_by, emojiShortname))) val dialog = AlertDialog.Builder(requireContext())
.setItems(usernames.toTypedArray(), null) .setView(layout)
.setPositiveButton(R.string.msg_ok, null) .setCancelable(true)
.show()
with(layout) {
view_flipper.displayedChild = if (isCustom) 1 else 0
if (isCustom && url != null) {
val glideRequest = if (url.endsWith("gif", true)) {
GlideApp.with(requireContext()).asGif()
} else {
GlideApp.with(requireContext()).asBitmap()
}
glideRequest.load(url).into(emoji_image_view)
} else {
emoji_view.text = EmojiParser.parse(requireContext(), shortname)
}
var listing = ""
if (usernames.size == 1) {
listing = usernames.first()
} else {
usernames.forEachIndexed { index, username ->
listing += if (index == usernames.size - 1) "|$username" else "$username, "
}
listing = listing.replace(", |", " ${requireContext().getString(R.string.msg_and)} ")
}
text_view_usernames.text = requireContext().resources.getQuantityString(
R.plurals.msg_reacted_with_, usernames.size, listing, shortname)
dialog.show()
}
} }
override fun showReactionsPopup(messageId: String) { override fun showReactionsPopup(messageId: String) {
......
...@@ -6,5 +6,6 @@ data class ReactionUiModel( ...@@ -6,5 +6,6 @@ data class ReactionUiModel(
val unicode: CharSequence, val unicode: CharSequence,
val count: Int, val count: Int,
val usernames: List<String> = emptyList(), val usernames: List<String> = emptyList(),
var url: String? = null var url: String? = null,
val isCustom: Boolean = false
) )
...@@ -19,6 +19,7 @@ import chat.rocket.android.dagger.scope.PerFragment ...@@ -19,6 +19,7 @@ import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.emoji.EmojiParser import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiRepository import chat.rocket.android.emoji.EmojiRepository
import chat.rocket.android.emoji.internal.isCustom
import chat.rocket.android.helper.MessageHelper import chat.rocket.android.helper.MessageHelper
import chat.rocket.android.helper.MessageParser import chat.rocket.android.helper.MessageParser
import chat.rocket.android.helper.UserHelper import chat.rocket.android.helper.UserHelper
...@@ -31,6 +32,7 @@ import chat.rocket.android.server.domain.messageReadReceiptEnabled ...@@ -31,6 +32,7 @@ import chat.rocket.android.server.domain.messageReadReceiptEnabled
import chat.rocket.android.server.domain.messageReadReceiptStoreUsers import chat.rocket.android.server.domain.messageReadReceiptStoreUsers
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.orFalse
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.ifNotNullNorEmpty import chat.rocket.android.util.extensions.ifNotNullNorEmpty
import chat.rocket.android.util.extensions.isNotNullNorEmpty import chat.rocket.android.util.extensions.isNotNullNorEmpty
...@@ -469,7 +471,7 @@ class UiModelMapper @Inject constructor( ...@@ -469,7 +471,7 @@ class UiModelMapper @Inject constructor(
val list = mutableListOf<ReactionUiModel>() val list = mutableListOf<ReactionUiModel>()
val customEmojis = EmojiRepository.getCustomEmojis() val customEmojis = EmojiRepository.getCustomEmojis()
it.getShortNames().forEach { shortname -> it.getShortNames().forEach { shortname ->
val usernames = it.getUsernames(shortname) ?: emptyList() val usernames = it.getUsernames(shortname).orEmpty()
val count = usernames.size val count = usernames.size
val custom = customEmojis.firstOrNull { emoji -> emoji.shortname == shortname } val custom = customEmojis.firstOrNull { emoji -> emoji.shortname == shortname }
list.add( list.add(
...@@ -478,7 +480,8 @@ class UiModelMapper @Inject constructor( ...@@ -478,7 +480,8 @@ class UiModelMapper @Inject constructor(
unicode = EmojiParser.parse(context, shortname), unicode = EmojiParser.parse(context, shortname),
count = count, count = count,
usernames = usernames, usernames = usernames,
url = custom?.url) url = custom?.url,
isCustom = custom != null)
) )
} }
list list
......
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center">
<ImageView
android:id="@+id/emoji_image_view"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_gravity="center"
tools:src="@tools:sample/avatars" />
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/emoji_view"
android:layout_width="48dp"
android:layout_height="48dp"
android:foreground="?selectableItemBackground"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#000000"
android:textSize="24sp"
tools:text="😀" />
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorWhite"
android:padding="16dp">
<ViewFlipper
android:id="@+id/view_flipper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foregroundGravity="center"
app:layout_constraintTop_toTopOf="parent">
<include layout="@layout/emoji_row_item" />
<include layout="@layout/emoji_image_row_item" />
</ViewFlipper>
<TextView
android:id="@+id/text_view_usernames"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:fontFamily="sans-serif-light"
android:textColor="@color/darkGray"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="@+id/view_flipper"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/view_flipper"
app:layout_constraintTop_toTopOf="@+id/view_flipper"
tools:text="Ann reacted with :grin:" />
</androidx.constraintlayout.widget.ConstraintLayout>
...@@ -152,6 +152,11 @@ ...@@ -152,6 +152,11 @@
<string name="msg__your_2fa_code">What’s your 2FA code?</string> <!-- TODO Add translation --> <string name="msg__your_2fa_code">What’s your 2FA code?</string> <!-- TODO Add translation -->
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string> <string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Privat</string> <string name="msg_private_channel">Privat</string>
......
...@@ -170,6 +170,11 @@ ...@@ -170,6 +170,11 @@
<string name="msg_permalink_copied">Permalink copied</string> <string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string> <string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Preferences messages --> <!-- Preferences messages -->
<string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation --> <string name="msg_analytics_tracking">Analytics tracking</string> <!-- TODO Add translation -->
......
...@@ -162,6 +162,11 @@ ...@@ -162,6 +162,11 @@
<string name="msg_permalink_copied">Permalink copied</string> <string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string> <string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Privé</string> <string name="msg_private_channel">Privé</string>
......
...@@ -174,6 +174,11 @@ ...@@ -174,6 +174,11 @@
<string name="msg_permalink_copied">Permalink copied</string> <string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string> <string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Preferences messages --> <!-- Preferences messages -->
<string name="msg_analytics_tracking">एनालिटिक्स ट्रैकिंग</string> <string name="msg_analytics_tracking">एनालिटिक्स ट्रैकिंग</string>
......
...@@ -161,7 +161,11 @@ ...@@ -161,7 +161,11 @@
<string name="msg_view_more">更に表示</string> <string name="msg_view_more">更に表示</string>
<string name="msg_view_less">隠す</string> <string name="msg_view_less">隠す</string>
<string name="msg_muted_on_this_channel">あなたはこのチャンネルでミュートされています</string> <string name="msg_muted_on_this_channel">あなたはこのチャンネルでミュートされています</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">プライベート</string> <string name="msg_private_channel">プライベート</string>
......
...@@ -160,6 +160,10 @@ ...@@ -160,6 +160,10 @@
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_permalink_copied">Permalink copiado</string> <string name="msg_permalink_copied">Permalink copiado</string>
<string name="msg_muted_on_this_channel">Você está silenciado neste canal</string> <string name="msg_muted_on_this_channel">Você está silenciado neste canal</string>
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reagiu com %2$s</item>
<item quantity="other">%1$s reagiram com %2$s</item>
</plurals>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Privado</string> <string name="msg_private_channel">Privado</string>
......
...@@ -158,6 +158,12 @@ ...@@ -158,6 +158,12 @@
<string name="msg_permalink_copied">Ссылка скопирована</string> <string name="msg_permalink_copied">Ссылка скопирована</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string> <string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="few">%1$s reacted with %2$s</item>
<item quantity="many">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Приватный</string> <string name="msg_private_channel">Приватный</string>
......
...@@ -175,6 +175,11 @@ ...@@ -175,6 +175,11 @@
<string name="msg_permalink_copied">Permalink copied</string> <string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string> <string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Preferences messages --> <!-- Preferences messages -->
<string name="msg_analytics_tracking">İstatistik takibi</string> <string name="msg_analytics_tracking">İstatistik takibi</string>
......
...@@ -160,6 +160,12 @@ ...@@ -160,6 +160,12 @@
<string name="msg_permalink_copied">Permalink copied</string> <string name="msg_permalink_copied">Permalink copied</string>
<!-- TODO - Add proper translation --> <!-- TODO - Add proper translation -->
<string name="msg_muted_on_this_channel">You are muted on this channel</string> <string name="msg_muted_on_this_channel">You are muted on this channel</string>
<!-- TODO - Add proper translation -->
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="few">%1$s reacted with %2$s</item>
<item quantity="many">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Приватний</string> <string name="msg_private_channel">Приватний</string>
......
...@@ -168,6 +168,10 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin ...@@ -168,6 +168,10 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string name="msg_two_factor_authentication">Two-factor Authentication</string> <string name="msg_two_factor_authentication">Two-factor Authentication</string>
<string name="msg__your_2fa_code">What’s your 2FA code?</string> <string name="msg__your_2fa_code">What’s your 2FA code?</string>
<string name="msg_permalink_copied">Permalink copied</string> <string name="msg_permalink_copied">Permalink copied</string>
<plurals name="msg_reacted_with_">
<item quantity="one">%1$s reacted with %2$s</item>
<item quantity="other">%1$s reacted with %2$s</item>
</plurals>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Private</string> <string name="msg_private_channel">Private</string>
...@@ -302,7 +306,6 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin ...@@ -302,7 +306,6 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<!-- Emoji message--> <!-- Emoji message-->
<string name="msg_no_recent_emoji">No recent emojis</string> <string name="msg_no_recent_emoji">No recent emojis</string>
<string name="alert_title_default_skin_tone">Default skin tone</string> <string name="alert_title_default_skin_tone">Default skin tone</string>
<string name="alert_title_reactions_by">%1$s reactions by</string>
<!-- Sorting and grouping--> <!-- Sorting and grouping-->
<string name="menu_chatroom_sort">Sort</string> <string name="menu_chatroom_sort">Sort</string>
......
...@@ -20,8 +20,10 @@ interface EmojiReactionListener { ...@@ -20,8 +20,10 @@ interface EmojiReactionListener {
/** /**
* Callback when an added reaction is long-clicked. * Callback when an added reaction is long-clicked.
* *
* @param emojiShortname The shortname of the emoji (:grin:, :smiley:, etc). * @param shortname The shortname of the emoji (:grin:, :smiley:, etc).
* @param isCustom Whether the reaction is custom or one of the defaults.
* @param url In case of a custom emoji, this is the url to find it. Can be null if not a custom.
* @param usernames The list of usernames of users who added the reaction. * @param usernames The list of usernames of users who added the reaction.
*/ */
fun onReactionLongClicked(emojiShortname: String, usernames: List<String>) fun onReactionLongClicked(shortname: String, isCustom: Boolean, url: String?, usernames: List<String>)
} }
<resources> <resources>
<string name="msg_no_recent_emoji">No recent emoji</string> <string name="msg_no_recent_emoji">No recent emoji</string>
<string name="alert_title_default_skin_tone">Default skin tone</string> <string name="alert_title_default_skin_tone">Default skin tone</string>
<string name="msg_reactions" translatable="false">Reactions</string>
</resources> </resources>
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