Unverified Commit 847d6e6f authored by Leonardo Aramaki's avatar Leonardo Aramaki Committed by GitHub

Merge pull request #1406 from RocketChat/project/emoji-as-a-module

[PROJECT] Move out whole emoji codebase to a separate module
parents cedc1254 0326e6cd
...@@ -10,7 +10,7 @@ android { ...@@ -10,7 +10,7 @@ android {
defaultConfig { defaultConfig {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion 21 minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk targetSdkVersion versions.targetSdk
versionCode 2030 versionCode 2030
versionName "2.4.0" versionName "2.4.0"
...@@ -61,6 +61,7 @@ dependencies { ...@@ -61,6 +61,7 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation project(':player') implementation project(':player')
implementation project(':emoji')
implementation libraries.kotlin implementation libraries.kotlin
implementation libraries.coroutines implementation libraries.coroutines
......
...@@ -19,7 +19,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor ...@@ -19,7 +19,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.SITE_URL import chat.rocket.android.server.domain.SITE_URL
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.widget.emoji.EmojiRepository import chat.rocket.android.emoji.EmojiRepository
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.crashlytics.android.core.CrashlyticsCore import com.crashlytics.android.core.CrashlyticsCore
import com.facebook.drawee.backends.pipeline.DraweeConfig import com.facebook.drawee.backends.pipeline.DraweeConfig
......
package chat.rocket.android.chatroom.adapter package chat.rocket.android.chatroom.adapter
import android.view.View import android.view.View
import androidx.core.view.isVisible
import chat.rocket.android.chatroom.uimodel.AudioAttachmentUiModel import chat.rocket.android.chatroom.uimodel.AudioAttachmentUiModel
import chat.rocket.android.player.PlayerActivity import chat.rocket.android.player.PlayerActivity
import chat.rocket.android.util.extensions.setVisible import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.widget.emoji.EmojiReactionListener
import kotlinx.android.synthetic.main.message_attachment.view.* import kotlinx.android.synthetic.main.message_attachment.view.*
class AudioAttachmentViewHolder(itemView: View, class AudioAttachmentViewHolder(itemView: View,
...@@ -15,8 +15,8 @@ class AudioAttachmentViewHolder(itemView: View, ...@@ -15,8 +15,8 @@ class AudioAttachmentViewHolder(itemView: View,
init { init {
with(itemView) { with(itemView) {
setupActionMenu(attachment_container) setupActionMenu(attachment_container)
image_attachment.setVisible(false) image_attachment.isVisible = false
audio_video_attachment.setVisible(true) audio_video_attachment.isVisible = true
} }
} }
......
...@@ -6,8 +6,8 @@ import android.view.View ...@@ -6,8 +6,8 @@ import android.view.View
import androidx.core.view.isGone import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import chat.rocket.android.chatroom.uimodel.AuthorAttachmentUiModel import chat.rocket.android.chatroom.uimodel.AuthorAttachmentUiModel
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.util.extensions.content import chat.rocket.android.util.extensions.content
import chat.rocket.android.widget.emoji.EmojiReactionListener
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import kotlinx.android.synthetic.main.item_author_attachment.view.* import kotlinx.android.synthetic.main.item_author_attachment.view.*
......
...@@ -9,8 +9,8 @@ import chat.rocket.android.R ...@@ -9,8 +9,8 @@ import chat.rocket.android.R
import chat.rocket.android.chatroom.ui.bottomsheet.BottomSheetMenu import chat.rocket.android.chatroom.ui.bottomsheet.BottomSheetMenu
import chat.rocket.android.chatroom.ui.bottomsheet.adapter.ActionListAdapter import chat.rocket.android.chatroom.ui.bottomsheet.adapter.ActionListAdapter
import chat.rocket.android.chatroom.uimodel.BaseUiModel import chat.rocket.android.chatroom.uimodel.BaseUiModel
import chat.rocket.android.widget.emoji.Emoji import chat.rocket.android.emoji.Emoji
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import chat.rocket.core.model.isSystemMessage import chat.rocket.core.model.isSystemMessage
import com.google.android.flexbox.FlexDirection import com.google.android.flexbox.FlexDirection
......
...@@ -9,7 +9,7 @@ import chat.rocket.android.R ...@@ -9,7 +9,7 @@ import chat.rocket.android.R
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.uimodel.* import chat.rocket.android.chatroom.uimodel.*
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import chat.rocket.core.model.isSystemMessage import chat.rocket.core.model.isSystemMessage
import timber.log.Timber import timber.log.Timber
......
...@@ -6,7 +6,7 @@ import android.text.method.LinkMovementMethod ...@@ -6,7 +6,7 @@ import android.text.method.LinkMovementMethod
import android.view.View import android.view.View
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.uimodel.ColorAttachmentUiModel import chat.rocket.android.chatroom.uimodel.ColorAttachmentUiModel
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import kotlinx.android.synthetic.main.item_color_attachment.view.* import kotlinx.android.synthetic.main.item_color_attachment.view.*
......
...@@ -4,8 +4,8 @@ import android.content.Intent ...@@ -4,8 +4,8 @@ import android.content.Intent
import android.view.View import android.view.View
import androidx.core.net.toUri import androidx.core.net.toUri
import chat.rocket.android.chatroom.uimodel.GenericFileAttachmentUiModel import chat.rocket.android.chatroom.uimodel.GenericFileAttachmentUiModel
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.util.extensions.content import chat.rocket.android.util.extensions.content
import chat.rocket.android.widget.emoji.EmojiReactionListener
import kotlinx.android.synthetic.main.item_file_attachment.view.* import kotlinx.android.synthetic.main.item_file_attachment.view.*
class GenericFileAttachmentViewHolder(itemView: View, class GenericFileAttachmentViewHolder(itemView: View,
......
...@@ -3,7 +3,7 @@ package chat.rocket.android.chatroom.adapter ...@@ -3,7 +3,7 @@ package chat.rocket.android.chatroom.adapter
import android.view.View import android.view.View
import chat.rocket.android.chatroom.uimodel.ImageAttachmentUiModel import chat.rocket.android.chatroom.uimodel.ImageAttachmentUiModel
import chat.rocket.android.helper.ImageHelper import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.backends.pipeline.Fresco
import kotlinx.android.synthetic.main.message_attachment.view.* import kotlinx.android.synthetic.main.message_attachment.view.*
......
...@@ -3,7 +3,7 @@ package chat.rocket.android.chatroom.adapter ...@@ -3,7 +3,7 @@ package chat.rocket.android.chatroom.adapter
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.view.View import android.view.View
import chat.rocket.android.chatroom.uimodel.MessageAttachmentUiModel import chat.rocket.android.chatroom.uimodel.MessageAttachmentUiModel
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import kotlinx.android.synthetic.main.item_message_attachment.view.* import kotlinx.android.synthetic.main.item_message_attachment.view.*
class MessageAttachmentViewHolder( class MessageAttachmentViewHolder(
......
package chat.rocket.android.chatroom.adapter package chat.rocket.android.chatroom.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.uimodel.ReactionUiModel import chat.rocket.android.chatroom.uimodel.ReactionUiModel
import chat.rocket.android.dagger.DaggerLocalComponent import chat.rocket.android.dagger.DaggerLocalComponent
import chat.rocket.android.emoji.Emoji
import chat.rocket.android.emoji.EmojiKeyboardListener
import chat.rocket.android.emoji.EmojiPickerPopup
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.widget.emoji.Emoji
import chat.rocket.android.widget.emoji.EmojiListenerAdapter
import chat.rocket.android.widget.emoji.EmojiPickerPopup
import chat.rocket.android.widget.emoji.EmojiReactionListener
import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.CopyOnWriteArrayList
import javax.inject.Inject import javax.inject.Inject
...@@ -72,21 +72,23 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() ...@@ -72,21 +72,23 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
} }
fun contains(reactionShortname: String) = fun contains(reactionShortname: String) =
reactions.firstOrNull { it.shortname == reactionShortname} != null reactions.firstOrNull { it.shortname == reactionShortname } != null
class SingleReactionViewHolder(view: View, class SingleReactionViewHolder(view: View,
private val listener: EmojiReactionListener?) private val listener: EmojiReactionListener?)
: RecyclerView.ViewHolder(view), View.OnClickListener { : RecyclerView.ViewHolder(view), View.OnClickListener {
@Inject lateinit var localRepository: LocalRepository @Inject
@Volatile lateinit var reaction: ReactionUiModel lateinit var localRepository: LocalRepository
@Volatile
lateinit var reaction: ReactionUiModel
@Volatile @Volatile
var clickHandled = false var clickHandled = false
init { init {
DaggerLocalComponent.builder() DaggerLocalComponent.builder()
.context(itemView.context) .context(itemView.context)
.build() .build()
.inject(this) .inject(this)
} }
fun bind(reaction: ReactionUiModel) { fun bind(reaction: ReactionUiModel) {
...@@ -125,7 +127,7 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() ...@@ -125,7 +127,7 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
itemView as ImageView itemView as ImageView
itemView.setOnClickListener { itemView.setOnClickListener {
val emojiPickerPopup = EmojiPickerPopup(itemView.context) val emojiPickerPopup = EmojiPickerPopup(itemView.context)
emojiPickerPopup.listener = object : EmojiListenerAdapter() { emojiPickerPopup.listener = object : EmojiKeyboardListener {
override fun onEmojiAdded(emoji: Emoji) { override fun onEmojiAdded(emoji: Emoji) {
listener?.onReactionAdded(messageId, emoji) listener?.onReactionAdded(messageId, emoji)
} }
......
...@@ -2,7 +2,7 @@ package chat.rocket.android.chatroom.adapter ...@@ -2,7 +2,7 @@ package chat.rocket.android.chatroom.adapter
import android.view.View import android.view.View
import chat.rocket.android.chatroom.uimodel.MessageReplyUiModel import chat.rocket.android.chatroom.uimodel.MessageReplyUiModel
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import kotlinx.android.synthetic.main.item_message_reply.view.* import kotlinx.android.synthetic.main.item_message_reply.view.*
class MessageReplyViewHolder( class MessageReplyViewHolder(
......
...@@ -5,7 +5,7 @@ import android.text.method.LinkMovementMethod ...@@ -5,7 +5,7 @@ import android.text.method.LinkMovementMethod
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import chat.rocket.android.chatroom.uimodel.MessageUiModel import chat.rocket.android.chatroom.uimodel.MessageUiModel
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.core.model.isSystemMessage import chat.rocket.core.model.isSystemMessage
import kotlinx.android.synthetic.main.avatar.view.* import kotlinx.android.synthetic.main.avatar.view.*
import kotlinx.android.synthetic.main.item_message.view.* import kotlinx.android.synthetic.main.item_message.view.*
......
...@@ -2,11 +2,11 @@ package chat.rocket.android.chatroom.adapter ...@@ -2,11 +2,11 @@ package chat.rocket.android.chatroom.adapter
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import androidx.core.view.isVisible
import chat.rocket.android.chatroom.uimodel.UrlPreviewUiModel import chat.rocket.android.chatroom.uimodel.UrlPreviewUiModel
import chat.rocket.android.util.extensions.content
import chat.rocket.android.util.extensions.openTabbedUrl import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.android.util.extensions.setVisible import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.widget.emoji.EmojiReactionListener import chat.rocket.android.util.extensions.content
import kotlinx.android.synthetic.main.message_url_preview.view.* import kotlinx.android.synthetic.main.message_url_preview.view.*
class UrlPreviewViewHolder(itemView: View, class UrlPreviewViewHolder(itemView: View,
...@@ -23,10 +23,10 @@ class UrlPreviewViewHolder(itemView: View, ...@@ -23,10 +23,10 @@ class UrlPreviewViewHolder(itemView: View,
override fun bindViews(data: UrlPreviewUiModel) { override fun bindViews(data: UrlPreviewUiModel) {
with(itemView) { with(itemView) {
if (data.thumbUrl.isNullOrEmpty()) { if (data.thumbUrl.isNullOrEmpty()) {
image_preview.setVisible(false) image_preview.isVisible = false
} else { } else {
image_preview.setImageURI(data.thumbUrl) image_preview.setImageURI(data.thumbUrl)
image_preview.setVisible(true) image_preview.isVisible = true
} }
text_host.content = data.hostname text_host.content = data.hostname
text_title.content = data.title text_title.content = data.title
......
package chat.rocket.android.chatroom.adapter package chat.rocket.android.chatroom.adapter
import android.view.View import android.view.View
import androidx.core.view.isVisible
import chat.rocket.android.chatroom.uimodel.VideoAttachmentUiModel import chat.rocket.android.chatroom.uimodel.VideoAttachmentUiModel
import chat.rocket.android.player.PlayerActivity import chat.rocket.android.player.PlayerActivity
import chat.rocket.android.util.extensions.setVisible import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.widget.emoji.EmojiReactionListener
import kotlinx.android.synthetic.main.message_attachment.view.* import kotlinx.android.synthetic.main.message_attachment.view.*
class VideoAttachmentViewHolder(itemView: View, class VideoAttachmentViewHolder(itemView: View,
...@@ -15,8 +15,8 @@ class VideoAttachmentViewHolder(itemView: View, ...@@ -15,8 +15,8 @@ class VideoAttachmentViewHolder(itemView: View,
init { init {
with(itemView) { with(itemView) {
setupActionMenu(attachment_container) setupActionMenu(attachment_container)
image_attachment.setVisible(false) image_attachment.isVisible = false
audio_video_attachment.setVisible(true) audio_video_attachment.isVisible = true
} }
} }
......
...@@ -8,17 +8,27 @@ import android.content.Intent ...@@ -8,17 +8,27 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.text.SpannableStringBuilder
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.text.bold
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.text.SpannableStringBuilder
import android.view.*
import androidx.core.text.bold
import androidx.core.view.isVisible
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.* import chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter
import chat.rocket.android.chatroom.adapter.PEOPLE
import chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter
import chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter
import chat.rocket.android.chatroom.presentation.ChatRoomPresenter import chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import chat.rocket.android.chatroom.presentation.ChatRoomView import chat.rocket.android.chatroom.presentation.ChatRoomView
import chat.rocket.android.chatroom.uimodel.BaseUiModel import chat.rocket.android.chatroom.uimodel.BaseUiModel
...@@ -26,6 +36,13 @@ import chat.rocket.android.chatroom.uimodel.MessageUiModel ...@@ -26,6 +36,13 @@ import chat.rocket.android.chatroom.uimodel.MessageUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel import chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import chat.rocket.android.emoji.ComposerEditText
import chat.rocket.android.emoji.Emoji
import chat.rocket.android.emoji.EmojiKeyboardListener
import chat.rocket.android.emoji.EmojiKeyboardPopup
import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiPickerPopup
import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.KeyboardHelper import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.MessageParser import chat.rocket.android.helper.MessageParser
...@@ -39,7 +56,6 @@ import chat.rocket.android.util.extensions.rotateBy ...@@ -39,7 +56,6 @@ import chat.rocket.android.util.extensions.rotateBy
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
import chat.rocket.android.widget.emoji.*
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.model.State
...@@ -556,7 +572,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -556,7 +572,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun showReactionsPopup(messageId: String) { override fun showReactionsPopup(messageId: String) {
ui { ui {
val emojiPickerPopup = EmojiPickerPopup(it) val emojiPickerPopup = EmojiPickerPopup(it)
emojiPickerPopup.listener = object : EmojiListenerAdapter() { emojiPickerPopup.listener = object : EmojiKeyboardListener {
override fun onEmojiAdded(emoji: Emoji) { override fun onEmojiAdded(emoji: Emoji) {
onReactionAdded(messageId, emoji) onReactionAdded(messageId, emoji)
} }
...@@ -600,15 +616,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -600,15 +616,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
handler.postDelayed(dismissStatus, 2000) handler.postDelayed(dismissStatus, 2000)
} }
is State.Disconnected -> connection_status_text.text = is State.Disconnected -> connection_status_text.text =
getString(R.string.status_disconnected) getString(R.string.status_disconnected)
is State.Connecting -> connection_status_text.text = is State.Connecting -> connection_status_text.text =
getString(R.string.status_connecting) getString(R.string.status_connecting)
is State.Authenticating -> connection_status_text.text = is State.Authenticating -> connection_status_text.text =
getString(R.string.status_authenticating) getString(R.string.status_authenticating)
is State.Disconnecting -> connection_status_text.text = is State.Disconnecting -> connection_status_text.text =
getString(R.string.status_disconnecting) getString(R.string.status_disconnecting)
is State.Waiting -> connection_status_text.text = is State.Waiting -> connection_status_text.text =
getString(R.string.status_waiting, state.seconds) getString(R.string.status_waiting, state.seconds)
} }
} }
} }
...@@ -664,7 +680,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -664,7 +680,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
subscribeComposeTextMessage() subscribeComposeTextMessage()
emojiKeyboardPopup = emojiKeyboardPopup =
EmojiKeyboardPopup(activity!!, activity!!.findViewById(R.id.fragment_container)) EmojiKeyboardPopup(activity!!, activity!!.findViewById(R.id.fragment_container))
emojiKeyboardPopup.listener = this emojiKeyboardPopup.listener = this
text_message.listener = object : ComposerEditText.ComposerEditTextListener { text_message.listener = object : ComposerEditText.ComposerEditTextListener {
override fun onKeyboardOpened() { override fun onKeyboardOpened() {
......
...@@ -26,7 +26,7 @@ import chat.rocket.android.server.domain.baseUrl ...@@ -26,7 +26,7 @@ import chat.rocket.android.server.domain.baseUrl
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isNotNullNorEmpty import chat.rocket.android.util.extensions.isNotNullNorEmpty
import chat.rocket.android.widget.emoji.EmojiParser import chat.rocket.android.emoji.EmojiParser
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import chat.rocket.core.model.MessageType import chat.rocket.core.model.MessageType
......
...@@ -13,6 +13,7 @@ import android.widget.CheckBox ...@@ -13,6 +13,7 @@ import android.widget.CheckBox
import android.widget.RadioGroup import android.widget.RadioGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders import androidx.lifecycle.ViewModelProviders
...@@ -29,12 +30,11 @@ import chat.rocket.android.db.DatabaseManager ...@@ -29,12 +30,11 @@ import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.helper.ChatRoomsSortOrder import chat.rocket.android.helper.ChatRoomsSortOrder
import chat.rocket.android.helper.Constants import chat.rocket.android.helper.Constants
import chat.rocket.android.helper.SharedPreferenceHelper import chat.rocket.android.helper.SharedPreferenceHelper
import chat.rocket.android.util.extensions.fadeIn
import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.extensions.fadeIn
import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.widget.DividerItemDecoration import chat.rocket.android.widget.DividerItemDecoration
import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.model.State
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
...@@ -242,16 +242,16 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -242,16 +242,16 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
override suspend fun updateChatRooms(newDataSet: List<ChatRoom>) {} override suspend fun updateChatRooms(newDataSet: List<ChatRoom>) {}
override fun showNoChatRoomsToDisplay() { override fun showNoChatRoomsToDisplay() {
ui { text_no_data_to_display.setVisible(true) } ui { text_no_data_to_display.isVisible = true }
} }
override fun showLoading() { override fun showLoading() {
ui { view_loading.setVisible(true) } ui { view_loading.isVisible = true }
} }
override fun hideLoading() { override fun hideLoading() {
ui { ui {
view_loading.setVisible(false) view_loading.isVisible = false
} }
} }
......
package chat.rocket.android.createchannel.ui package chat.rocket.android.createchannel.ui
import android.os.Bundle import android.os.Bundle
import android.view.* import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.postDelayed import androidx.core.view.postDelayed
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.createchannel.presentation.CreateChannelPresenter import chat.rocket.android.createchannel.presentation.CreateChannelPresenter
import chat.rocket.android.createchannel.presentation.CreateChannelView import chat.rocket.android.createchannel.presentation.CreateChannelView
...@@ -18,7 +24,6 @@ import chat.rocket.android.util.extensions.asObservable ...@@ -18,7 +24,6 @@ import chat.rocket.android.util.extensions.asObservable
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
import chat.rocket.android.widget.DividerItemDecoration
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import com.google.android.material.chip.Chip import com.google.android.material.chip.Chip
...@@ -181,7 +186,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -181,7 +186,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
private fun setupToolBar() { private fun setupToolBar() {
(activity as AppCompatActivity?)?.supportActionBar?.title = (activity as AppCompatActivity?)?.supportActionBar?.title =
getString(R.string.title_create_channel) getString(R.string.title_create_channel)
} }
private fun setupViewListeners() { private fun setupViewListeners() {
...@@ -189,7 +194,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -189,7 +194,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
if (isChecked) { if (isChecked) {
text_channel_type.text = getString(R.string.msg_private_channel) text_channel_type.text = getString(R.string.msg_private_channel)
text_channel_type_description.text = text_channel_type_description.text =
getString(R.string.msg_private_channel_description) getString(R.string.msg_private_channel_description)
image_channel_icon.setImageDrawable( image_channel_icon.setImageDrawable(
context?.getDrawable(R.drawable.ic_lock_black_12_dp) context?.getDrawable(R.drawable.ic_lock_black_12_dp)
) )
...@@ -197,7 +202,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -197,7 +202,7 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
} else { } else {
text_channel_type.text = getString(R.string.msg_public_channel) text_channel_type.text = getString(R.string.msg_public_channel)
text_channel_type_description.text = text_channel_type_description.text =
getString(R.string.msg_public_channel_description) getString(R.string.msg_public_channel_description)
image_channel_icon.setImageDrawable( image_channel_icon.setImageDrawable(
context?.getDrawable(R.drawable.ic_hashtag_black_12dp) context?.getDrawable(R.drawable.ic_hashtag_black_12dp)
) )
...@@ -213,8 +218,8 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback ...@@ -213,8 +218,8 @@ class CreateChannelFragment : Fragment(), CreateChannelView, ActionMode.Callback
private fun setupRecyclerView() { private fun setupRecyclerView() {
ui { ui {
recycler_view.layoutManager = recycler_view.layoutManager =
LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) LinearLayoutManager(context, RecyclerView.VERTICAL, false)
recycler_view.addItemDecoration(DividerItemDecoration(it)) recycler_view.addItemDecoration(DividerItemDecoration(it, DividerItemDecoration.HORIZONTAL))
recycler_view.adapter = adapter recycler_view.adapter = adapter
} }
......
...@@ -2,7 +2,6 @@ package chat.rocket.android.db ...@@ -2,7 +2,6 @@ package chat.rocket.android.db
import android.app.Application import android.app.Application
import chat.rocket.android.db.model.BaseUserEntity import chat.rocket.android.db.model.BaseUserEntity
import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.db.model.ChatRoomEntity import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.UserEntity import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.db.model.UserStatus import chat.rocket.android.db.model.UserStatus
......
...@@ -8,6 +8,8 @@ import android.view.View ...@@ -8,6 +8,8 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.DividerItemDecoration.HORIZONTAL
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R import chat.rocket.android.R
...@@ -22,7 +24,6 @@ import chat.rocket.android.player.PlayerActivity ...@@ -22,7 +24,6 @@ import chat.rocket.android.player.PlayerActivity
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
import chat.rocket.android.widget.DividerItemDecoration
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_files.* import kotlinx.android.synthetic.main.fragment_files.*
import javax.inject.Inject import javax.inject.Inject
...@@ -137,7 +138,7 @@ class FilesFragment : Fragment(), FilesView { ...@@ -137,7 +138,7 @@ class FilesFragment : Fragment(), FilesView {
private fun setupRecyclerView() { private fun setupRecyclerView() {
ui { ui {
recycler_view.layoutManager = linearLayoutManager recycler_view.layoutManager = linearLayoutManager
recycler_view.addItemDecoration(DividerItemDecoration(it)) recycler_view.addItemDecoration(DividerItemDecoration(it, HORIZONTAL))
recycler_view.adapter = adapter recycler_view.adapter = adapter
} }
} }
......
...@@ -16,9 +16,9 @@ import chat.rocket.android.R ...@@ -16,9 +16,9 @@ import chat.rocket.android.R
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.openTabbedUrl import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.android.widget.emoji.EmojiParser import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.widget.emoji.EmojiRepository import chat.rocket.android.emoji.EmojiRepository
import chat.rocket.android.widget.emoji.EmojiTypefaceSpan import chat.rocket.android.emoji.EmojiTypefaceSpan
import chat.rocket.common.model.SimpleUser import chat.rocket.common.model.SimpleUser
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import org.commonmark.node.AbstractVisitor import org.commonmark.node.AbstractVisitor
......
...@@ -5,9 +5,9 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment ...@@ -5,9 +5,9 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.util.extensions.content import chat.rocket.android.util.extensions.content
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.textContent import chat.rocket.android.util.extensions.textContent
import kotlinx.android.synthetic.main.fragment_member_bottom_sheet.* import kotlinx.android.synthetic.main.fragment_member_bottom_sheet.*
...@@ -70,15 +70,15 @@ class MemberBottomSheetFragment: BottomSheetDialogFragment() { ...@@ -70,15 +70,15 @@ class MemberBottomSheetFragment: BottomSheetDialogFragment() {
if (email.isNotEmpty()) { if (email.isNotEmpty()) {
text_member_email_address.textContent = email text_member_email_address.textContent = email
} else { } else {
text_email_address.setVisible(false) text_email_address.isVisible = false
text_member_email_address.setVisible(false) text_member_email_address.isVisible = false
} }
if (utcOffset.isNotEmpty()){ if (utcOffset.isNotEmpty()){
text_member_utc.content = utcOffset text_member_utc.content = utcOffset
} else { } else {
text_utc.setVisible(false) text_utc.isVisible = false
text_member_utc.setVisible(false) text_member_utc.isVisible = false
} }
} }
} }
\ No newline at end of file
...@@ -7,6 +7,8 @@ import androidx.recyclerview.widget.RecyclerView ...@@ -7,6 +7,8 @@ import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DividerItemDecoration
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.ui.ChatRoomActivity import chat.rocket.android.chatroom.ui.ChatRoomActivity
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
...@@ -15,10 +17,8 @@ import chat.rocket.android.members.presentation.MembersPresenter ...@@ -15,10 +17,8 @@ import chat.rocket.android.members.presentation.MembersPresenter
import chat.rocket.android.members.presentation.MembersView import chat.rocket.android.members.presentation.MembersView
import chat.rocket.android.members.uimodel.MemberUiModel import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.setVisible
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
import chat.rocket.android.widget.DividerItemDecoration
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_members.* import kotlinx.android.synthetic.main.fragment_members.*
import javax.inject.Inject import javax.inject.Inject
...@@ -89,11 +89,11 @@ class MembersFragment : Fragment(), MembersView { ...@@ -89,11 +89,11 @@ class MembersFragment : Fragment(), MembersView {
} }
override fun showLoading() { override fun showLoading() {
ui { view_loading.setVisible(true) } ui { view_loading.isVisible = true }
} }
override fun hideLoading() { override fun hideLoading() {
ui { view_loading.setVisible(false) } ui { view_loading.isVisible = false }
} }
override fun showMessage(resId: Int) { override fun showMessage(resId: Int) {
...@@ -113,7 +113,7 @@ class MembersFragment : Fragment(), MembersView { ...@@ -113,7 +113,7 @@ class MembersFragment : Fragment(), MembersView {
private fun setupRecyclerView() { private fun setupRecyclerView() {
ui { ui {
recycler_view.layoutManager = linearLayoutManager recycler_view.layoutManager = linearLayoutManager
recycler_view.addItemDecoration(DividerItemDecoration(it)) recycler_view.addItemDecoration(DividerItemDecoration(it, DividerItemDecoration.HORIZONTAL))
recycler_view.adapter = adapter recycler_view.adapter = adapter
} }
} }
......
...@@ -7,10 +7,10 @@ import android.widget.Toast ...@@ -7,10 +7,10 @@ import android.widget.Toast
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.settings.password.presentation.PasswordPresenter import chat.rocket.android.settings.password.presentation.PasswordPresenter
import chat.rocket.android.settings.password.presentation.PasswordView import chat.rocket.android.settings.password.presentation.PasswordView
import chat.rocket.android.util.extensions.asObservable
import chat.rocket.android.util.extensions.inflate import chat.rocket.android.util.extensions.inflate
import chat.rocket.android.util.extensions.textContent
import androidx.appcompat.view.ActionMode import androidx.appcompat.view.ActionMode
import chat.rocket.android.util.extensions.asObservable
import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
......
...@@ -7,8 +7,8 @@ import android.util.Base64 ...@@ -7,8 +7,8 @@ import android.util.Base64
import android.util.Patterns import android.util.Patterns
import android.widget.EditText import android.widget.EditText
import android.widget.TextView import android.widget.TextView
import chat.rocket.android.widget.emoji.EmojiParser import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.widget.emoji.EmojiTypefaceSpan import chat.rocket.android.emoji.EmojiTypefaceSpan
import org.json.JSONObject import org.json.JSONObject
import ru.noties.markwon.Markwon import ru.noties.markwon.Markwon
import java.net.URLDecoder import java.net.URLDecoder
......
package chat.rocket.android.widget.emoji
data class Emoji(
val shortname: String,
val shortnameAlternates: List<String>,
val unicode: String,
val keywords: List<String>,
val category: String,
val count: Int = 0
)
\ No newline at end of file
package chat.rocket.android.widget.emoji
abstract class EmojiListenerAdapter : EmojiKeyboardListener {
override fun onEmojiAdded(emoji: Emoji) {
// this space is for rent
}
override fun onNonEmojiKeyPressed(keyCode: Int) {
// this space is for rent
}
}
\ No newline at end of file
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
android:contentDescription="@string/msg_content_description_show_attachment_options" android:contentDescription="@string/msg_content_description_show_attachment_options"
android:src="@drawable/ic_reaction_24dp" /> android:src="@drawable/ic_reaction_24dp" />
<chat.rocket.android.widget.emoji.ComposerEditText <chat.rocket.android.emoji.ComposerEditText
android:id="@+id/text_message" android:id="@+id/text_message"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:app="http://schemas.android.com/apk/res-auto">
<item <item
android:id="@+id/action_members_list" android:id="@+id/action_members_list"
android:title="@string/title_members_list" android:title="@string/title_members_list"
app:showAsAction="never" /> android:showAsAction="never" />
<item <item
android:id="@+id/action_mentions" android:id="@+id/action_mentions"
...@@ -15,15 +14,15 @@ ...@@ -15,15 +14,15 @@
<item <item
android:id="@+id/action_pinned_messages" android:id="@+id/action_pinned_messages"
android:title="@string/title_pinned_messages" android:title="@string/title_pinned_messages"
app:showAsAction="never" /> android:showAsAction="never" />
<item <item
android:id="@+id/action_favorite_messages" android:id="@+id/action_favorite_messages"
android:title="@string/title_favorite_messages" android:title="@string/title_favorite_messages"
app:showAsAction="never" /> android:showAsAction="never" />
<item <item
android:id="@+id/action_files" android:id="@+id/action_files"
android:title="@string/msg_files" android:title="@string/msg_files"
app:showAsAction="never" /> android:showAsAction="never" />
</menu> </menu>
\ No newline at end of file
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
android:id="@+id/action_search" android:id="@+id/action_search"
android:icon="@drawable/ic_search_white_24px" android:icon="@drawable/ic_search_white_24px"
android:title="@string/action_search" android:title="@string/action_search"
app:actionViewClass="androidx.appcompat.widget.SearchView" android:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="ifRoom|collapseActionView" /> android:showAsAction="ifRoom|collapseActionView" />
<item <item
android:id="@+id/action_sort" android:id="@+id/action_sort"
android:icon="@drawable/ic_sort" android:icon="@drawable/ic_sort"
android:title="@string/menu_chatroom_sort" android:title="@string/menu_chatroom_sort"
app:showAsAction="always" /> android:showAsAction="always" />
</menu> </menu>
...@@ -6,5 +6,5 @@ ...@@ -6,5 +6,5 @@
android:id="@+id/action_save_image" android:id="@+id/action_save_image"
android:icon="@drawable/ic_file_download_white_24dp" android:icon="@drawable/ic_file_download_white_24dp"
android:title="@string/action_save_to_gallery" android:title="@string/action_save_to_gallery"
app:showAsAction="always" /> android:showAsAction="always" />
</menu> </menu>
\ No newline at end of file
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
<string name="Slash_Topic_Description">Set topic</string> <string name="Slash_Topic_Description">Set topic</string>
<!-- Emoji message--> <!-- Emoji message-->
<string name="msg_no_recent_emoji">No recent emoji</string> <string name="msg_no_recent_emoji">No recent emojis</string>
<!-- Sorting and grouping--> <!-- Sorting and grouping-->
<string name="menu_chatroom_sort">Sort</string> <string name="menu_chatroom_sort">Sort</string>
......
...@@ -3,6 +3,7 @@ ext { ...@@ -3,6 +3,7 @@ ext {
java : JavaVersion.VERSION_1_8, java : JavaVersion.VERSION_1_8,
compileSdk : 28, compileSdk : 28,
targetSdk : 28, targetSdk : 28,
minSdk : 21,
buildTools : '28.0.0-rc2', buildTools : '28.0.0-rc2',
kotlin : '1.2.50', kotlin : '1.2.50',
coroutine : '0.23.1', coroutine : '0.23.1',
......
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk
versionCode 1
versionName "0.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation libraries.androidKtx
implementation libraries.appCompat
implementation libraries.kotlin
implementation libraries.constraintlayout
implementation libraries.recyclerview
implementation libraries.material
}
kotlin {
experimental {
coroutines "enable"
}
}
androidExtensions {
experimental = true
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="chat.rocket.android.emoji" />
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import androidx.viewpager.widget.PagerAdapter
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.TextView import android.widget.TextView
import chat.rocket.android.R import androidx.core.view.isVisible
import chat.rocket.android.util.extensions.setVisible import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager.widget.PagerAdapter
import kotlinx.android.synthetic.main.emoji_category_layout.view.*
import java.util.* import java.util.*
class CategoryPagerAdapter(val listener: EmojiKeyboardListener) : PagerAdapter() { internal class CategoryPagerAdapter(private val listener: EmojiKeyboardListener) : PagerAdapter() {
override fun isViewFromObject(view: View, obj: Any): Boolean { override fun isViewFromObject(view: View, obj: Any): Boolean {
return view == obj return view == obj
...@@ -20,29 +20,25 @@ class CategoryPagerAdapter(val listener: EmojiKeyboardListener) : PagerAdapter() ...@@ -20,29 +20,25 @@ class CategoryPagerAdapter(val listener: EmojiKeyboardListener) : PagerAdapter()
override fun instantiateItem(container: ViewGroup, position: Int): Any { override fun instantiateItem(container: ViewGroup, position: Int): Any {
val view = LayoutInflater.from(container.context) val view = LayoutInflater.from(container.context)
.inflate(R.layout.emoji_category_layout, container, false) .inflate(R.layout.emoji_category_layout, container, false)
val layoutManager = GridLayoutManager(view.context, 8) with(view) {
val recycler = view.findViewById(R.id.emojiRecyclerView) as RecyclerView val layoutManager = GridLayoutManager(context, 8)
val adapter = EmojiAdapter(layoutManager.spanCount, listener) val adapter = EmojiAdapter(layoutManager.spanCount, listener)
val category = EmojiCategory.values().get(position) val category = EmojiCategory.values()[position]
val emojiNoRecentText : TextView = view.findViewById(R.id.text_no_recent_emoji) val emojis = if (category != EmojiCategory.RECENTS) {
val emojis = if (category != EmojiCategory.RECENTS) { EmojiRepository.getEmojisByCategory(category)
EmojiRepository.getEmojisByCategory(category) } else {
} else { EmojiRepository.getRecents()
EmojiRepository.getRecents() }
} val recentEmojiSize = EmojiRepository.getRecents().size
val recentEmojiSize = EmojiRepository.getRecents().size text_no_recent_emoji.isVisible = category == EmojiCategory.RECENTS && recentEmojiSize == 0
if (category == EmojiCategory.RECENTS && recentEmojiSize == 0){ adapter.addEmojis(emojis)
emojiNoRecentText.setVisible(true) emoji_recycler_view.layoutManager = layoutManager
}else{ emoji_recycler_view.itemAnimator = DefaultItemAnimator()
emojiNoRecentText.setVisible(false) emoji_recycler_view.adapter = adapter
emoji_recycler_view.isNestedScrollingEnabled = false
container.addView(view)
} }
adapter.addEmojis(emojis)
recycler.layoutManager = layoutManager
recycler.itemAnimator = DefaultItemAnimator()
recycler.adapter = adapter
recycler.isNestedScrollingEnabled = false
container.addView(view)
return view return view
} }
...@@ -54,7 +50,11 @@ class CategoryPagerAdapter(val listener: EmojiKeyboardListener) : PagerAdapter() ...@@ -54,7 +50,11 @@ class CategoryPagerAdapter(val listener: EmojiKeyboardListener) : PagerAdapter()
override fun getPageTitle(position: Int) = EmojiCategory.values()[position].textIcon() override fun getPageTitle(position: Int) = EmojiCategory.values()[position].textIcon()
class EmojiAdapter(val spanCount: Int, val listener: EmojiKeyboardListener) : RecyclerView.Adapter<EmojiRowViewHolder>() { class EmojiAdapter(
private val spanCount: Int,
private val listener: EmojiKeyboardListener
) : RecyclerView.Adapter<EmojiRowViewHolder>() {
private var emojis = Collections.emptyList<Emoji>() private var emojis = Collections.emptyList<Emoji>()
fun addEmojis(emojis: List<Emoji>) { fun addEmojis(emojis: List<Emoji>) {
...@@ -74,7 +74,13 @@ class CategoryPagerAdapter(val listener: EmojiKeyboardListener) : PagerAdapter() ...@@ -74,7 +74,13 @@ class CategoryPagerAdapter(val listener: EmojiKeyboardListener) : PagerAdapter()
override fun getItemCount(): Int = emojis.size override fun getItemCount(): Int = emojis.size
} }
class EmojiRowViewHolder(itemView: View, val itemCount: Int, val spanCount: Int, val listener: EmojiKeyboardListener) : RecyclerView.ViewHolder(itemView) { class EmojiRowViewHolder(
itemView: View,
private val itemCount: Int,
private val spanCount: Int,
private val listener: EmojiKeyboardListener
) : RecyclerView.ViewHolder(itemView) {
private val emojiView: TextView = itemView.findViewById(R.id.emoji) private val emojiView: TextView = itemView.findViewById(R.id.emoji)
fun bind(emoji: Emoji) { fun bind(emoji: Emoji) {
......
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import android.content.Context import android.content.Context
import androidx.appcompat.widget.AppCompatEditText import androidx.appcompat.widget.AppCompatEditText
......
package chat.rocket.android.emoji
data class Emoji(
val shortname: String,
val shortnameAlternates: List<String>,
val unicode: String,
val keywords: List<String>,
val category: String,
val count: Int = 0
)
\ No newline at end of file
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import androidx.annotation.DrawableRes
import android.text.SpannableString import android.text.SpannableString
import android.text.Spanned import android.text.Spanned
import chat.rocket.android.R import androidx.annotation.DrawableRes
enum class EmojiCategory { enum class EmojiCategory {
RECENTS { RECENTS {
......
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
interface EmojiKeyboardListener { interface EmojiKeyboardListener {
/** /**
* When an emoji is selected on the picker. * Callback when an emoji is selected on the picker (optional operation).
* *
* @param emoji The selected emoji * @param emoji The selected emoji
*/ */
fun onEmojiAdded(emoji: Emoji) fun onEmojiAdded(emoji: Emoji) {}
/** /**
* When backspace key is clicked. * Callback when backspace key is clicked (optional operation).
* *
* @param keyCode The key code pressed as defined * @param keyCode The key code pressed as defined
* *
* @see android.view.KeyEvent * @see android.view.KeyEvent
*/ */
fun onNonEmojiKeyPressed(keyCode: Int) fun onNonEmojiKeyPressed(keyCode: Int) {}
} }
\ No newline at end of file
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import android.content.Context import android.content.Context
import com.google.android.material.tabs.TabLayout
import androidx.viewpager.widget.ViewPager
import androidx.appcompat.app.AppCompatActivity
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.view.KeyEvent import android.view.KeyEvent
...@@ -12,10 +9,16 @@ import android.view.View ...@@ -12,10 +9,16 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText import android.widget.EditText
import android.widget.ImageView import android.widget.ImageView
import chat.rocket.android.R import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager.widget.ViewPager
import com.google.android.material.tabs.TabLayout
class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow(context, view) { class EmojiKeyboardPopup(
context: Context,
view: View
) : OverKeyboardPopupWindow(context, view) {
private lateinit var viewPager: ViewPager private lateinit var viewPager: ViewPager
private lateinit var tabLayout: TabLayout private lateinit var tabLayout: TabLayout
private lateinit var searchView: View private lateinit var searchView: View
...@@ -23,10 +26,6 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow ...@@ -23,10 +26,6 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
private lateinit var parentContainer: ViewGroup private lateinit var parentContainer: ViewGroup
var listener: EmojiKeyboardListener? = null var listener: EmojiKeyboardListener? = null
companion object {
const val PREF_EMOJI_RECENTS = "PREF_EMOJI_RECENTS"
}
override fun onCreateView(inflater: LayoutInflater): View { override fun onCreateView(inflater: LayoutInflater): View {
val view = inflater.inflate(R.layout.emoji_keyboard, null) val view = inflater.inflate(R.layout.emoji_keyboard, null)
parentContainer = view.findViewById(R.id.emoji_keyboard_container) parentContainer = view.findViewById(R.id.emoji_keyboard_container)
...@@ -58,14 +57,14 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow ...@@ -58,14 +57,14 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
is EmojiKeyboardListener -> it is EmojiKeyboardListener -> it
else -> { else -> {
val fragments = (it as AppCompatActivity).supportFragmentManager.fragments val fragments = (it as AppCompatActivity).supportFragmentManager.fragments
if (fragments == null || fragments.size == 0 || !(fragments[0] is EmojiKeyboardListener)) { if (fragments.size == 0 || !(fragments[0] is EmojiKeyboardListener)) {
throw IllegalStateException("activity/fragment should implement Listener interface") throw IllegalStateException("activity/fragment should implement Listener interface")
} }
fragments[0] as EmojiKeyboardListener fragments[0] as EmojiKeyboardListener
} }
} }
viewPager.adapter = CategoryPagerAdapter(object : EmojiListenerAdapter() { viewPager.adapter = CategoryPagerAdapter(object : EmojiKeyboardListener {
override fun onEmojiAdded(emoji: Emoji) { override fun onEmojiAdded(emoji: Emoji) {
EmojiRepository.addToRecents(emoji) EmojiRepository.addToRecents(emoji)
callback.onEmojiAdded(emoji) callback.onEmojiAdded(emoji)
...@@ -86,11 +85,11 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow ...@@ -86,11 +85,11 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
} }
} }
class EmojiTextWatcher(val editor: EditText) : TextWatcher { class EmojiTextWatcher(private val editor: EditText) : TextWatcher {
@Volatile private var emojiToRemove = mutableListOf<EmojiTypefaceSpan>() @Volatile private var emojiToRemove = mutableListOf<EmojiTypefaceSpan>()
override fun afterTextChanged(s: Editable) { override fun afterTextChanged(s: Editable) {
val message = editor.getEditableText() val message = editor.editableText
// Commit the emoticons to be removed. // Commit the emoticons to be removed.
for (span in emojiToRemove.toList()) { for (span in emojiToRemove.toList()) {
...@@ -112,7 +111,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow ...@@ -112,7 +111,7 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
if (after < count) { if (after < count) {
val end = start + count val end = start + count
val message = editor.getEditableText() val message = editor.editableText
val list = message.getSpans(start, end, EmojiTypefaceSpan::class.java) val list = message.getSpans(start, end, EmojiTypefaceSpan::class.java)
for (span in list) { for (span in list) {
...@@ -129,4 +128,8 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow ...@@ -129,4 +128,8 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
} }
} }
companion object {
const val PREF_EMOJI_RECENTS = "PREF_EMOJI_RECENTS"
}
} }
\ No newline at end of file
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import android.text.SpannableString import android.text.SpannableString
import android.text.Spanned import android.text.Spanned
class EmojiParser { class EmojiParser {
companion object { companion object {
/** /**
* Parses a text string containing unicode characters and/or shortnames to a rendered * Parses a text string containing unicode characters and/or shortnames to a rendered
...@@ -14,7 +15,7 @@ class EmojiParser { ...@@ -14,7 +15,7 @@ class EmojiParser {
*/ */
fun parse(text: CharSequence): CharSequence { fun parse(text: CharSequence): CharSequence {
val unicodedText = EmojiRepository.shortnameToUnicode(text, true) val unicodedText = EmojiRepository.shortnameToUnicode(text, true)
var spannable = SpannableString.valueOf(unicodedText) val spannable = SpannableString.valueOf(unicodedText)
val typeface = EmojiRepository.cachedTypeface val typeface = EmojiRepository.cachedTypeface
// Look for groups of emojis, set a EmojiTypefaceSpan with the emojione font. // Look for groups of emojis, set a EmojiTypefaceSpan with the emojione font.
val length = spannable.length val length = spannable.length
...@@ -49,12 +50,5 @@ class EmojiParser { ...@@ -49,12 +50,5 @@ class EmojiParser {
} }
return spannable return spannable
} }
private fun calculateSurrogatePairs(scalar: Int): Pair<Int, Int> {
val temp: Int = (scalar - 0x10000) / 0x400
val s1: Int = Math.floor(temp.toDouble()).toInt() + 0xD800
val s2: Int = ((scalar - 0x10000) % 0x400) + 0xDC00
return Pair(s1, s2)
}
} }
} }
\ No newline at end of file
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import android.app.Dialog import android.app.Dialog
import android.content.Context import android.content.Context
...@@ -9,12 +9,11 @@ import android.view.LayoutInflater ...@@ -9,12 +9,11 @@ import android.view.LayoutInflater
import android.view.Window import android.view.Window
import android.view.WindowManager import android.view.WindowManager
import android.widget.ImageView import android.widget.ImageView
import chat.rocket.android.R import kotlinx.android.synthetic.main.emoji_picker.*
class EmojiPickerPopup(context: Context) : Dialog(context) { class EmojiPickerPopup(context: Context) : Dialog(context) {
private lateinit var viewPager: ViewPager
private lateinit var tabLayout: TabLayout
var listener: EmojiKeyboardListener? = null var listener: EmojiKeyboardListener? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
...@@ -22,9 +21,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) { ...@@ -22,9 +21,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
requestWindowFeature(Window.FEATURE_NO_TITLE) requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.emoji_picker) setContentView(R.layout.emoji_picker)
viewPager = findViewById(R.id.pager_categories) tabs.setupWithViewPager(pager_categories)
tabLayout = findViewById(R.id.tabs)
tabLayout.setupWithViewPager(viewPager)
setupViewPager() setupViewPager()
setSize() setSize()
} }
...@@ -38,7 +35,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) { ...@@ -38,7 +35,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
} }
private fun setupViewPager() { private fun setupViewPager() {
viewPager.adapter = CategoryPagerAdapter(object : EmojiListenerAdapter() { pager_categories.adapter = CategoryPagerAdapter(object : EmojiKeyboardListener {
override fun onEmojiAdded(emoji: Emoji) { override fun onEmojiAdded(emoji: Emoji) {
EmojiRepository.addToRecents(emoji) EmojiRepository.addToRecents(emoji)
dismiss() dismiss()
...@@ -47,7 +44,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) { ...@@ -47,7 +44,7 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
}) })
for (category in EmojiCategory.values()) { for (category in EmojiCategory.values()) {
val tab = tabLayout.getTabAt(category.ordinal) val tab = tabs.getTabAt(category.ordinal)
val tabView = LayoutInflater.from(context).inflate(R.layout.emoji_picker_tab, null) val tabView = LayoutInflater.from(context).inflate(R.layout.emoji_picker_tab, null)
tab?.customView = tabView tab?.customView = tabView
val textView = tabView.findViewById(R.id.image_category) as ImageView val textView = tabView.findViewById(R.id.image_category) as ImageView
...@@ -56,6 +53,6 @@ class EmojiPickerPopup(context: Context) : Dialog(context) { ...@@ -56,6 +53,6 @@ class EmojiPickerPopup(context: Context) : Dialog(context) {
val currentTab = if (EmojiRepository.getRecents().isEmpty()) EmojiCategory.PEOPLE.ordinal else val currentTab = if (EmojiRepository.getRecents().isEmpty()) EmojiCategory.PEOPLE.ordinal else
EmojiCategory.RECENTS.ordinal EmojiCategory.RECENTS.ordinal
viewPager.currentItem = currentTab pager_categories.currentItem = currentTab
} }
} }
\ No newline at end of file
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
interface EmojiReactionListener { interface EmojiReactionListener {
/** /**
......
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.graphics.Typeface import android.graphics.Typeface
import android.os.Build
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.io.BufferedReader import java.io.BufferedReader
...@@ -54,10 +53,6 @@ object EmojiRepository { ...@@ -54,10 +53,6 @@ object EmojiRepository {
*/ */
fun getAll() = ALL_EMOJIS fun getAll() = ALL_EMOJIS
// fun findEmojiByUnicode(unicode: Int) {
// ALL_EMOJIS.find { it.unicode == }
// }
/** /**
* Get all emojis for a given category. * Get all emojis for a given category.
* *
...@@ -108,7 +103,7 @@ object EmojiRepository { ...@@ -108,7 +103,7 @@ object EmojiRepository {
list.add(it.copy(count = useCount)) list.add(it.copy(count = useCount))
} }
} }
Collections.sort(list, { o1, o2 -> list.sortWith(Comparator { o1, o2 ->
o2.count - o1.count o2.count - o1.count
}) })
return list return list
...@@ -147,10 +142,10 @@ object EmojiRepository { ...@@ -147,10 +142,10 @@ object EmojiRepository {
return null return null
} }
return Emoji(shortname = json.getString("shortname"), return Emoji(shortname = json.getString("shortname"),
unicode = json.getString("unicode"), unicode = json.getString("unicode"),
shortnameAlternates = buildStringListFromJsonArray(json.getJSONArray("shortnameAlternates")), shortnameAlternates = buildStringListFromJsonArray(json.getJSONArray("shortnameAlternates")),
category = json.getString("category"), category = json.getString("category"),
keywords = buildStringListFromJsonArray(json.getJSONArray("keywords"))) keywords = buildStringListFromJsonArray(json.getJSONArray("keywords")))
} }
private fun buildStringListFromJsonArray(array: JSONArray): List<String> { private fun buildStringListFromJsonArray(array: JSONArray): List<String> {
......
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import android.graphics.Paint import android.graphics.Paint
import android.graphics.Typeface import android.graphics.Typeface
......
...@@ -16,21 +16,26 @@ ...@@ -16,21 +16,26 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package chat.rocket.android.widget.emoji package chat.rocket.android.emoji
import android.content.Context import android.content.Context
import android.graphics.Point import android.graphics.Point
import android.graphics.Rect import android.graphics.Rect
import android.os.Build import android.os.Build
import android.view.* import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewTreeObserver
import android.view.WindowManager
import android.widget.PopupWindow import android.widget.PopupWindow
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
/** /**
* Base class to create popup window that appears over software keyboard. * Base class to create popup window that appears over software keyboard.
*/ */
abstract class OverKeyboardPopupWindow(val context: Context, private val rootView: View) : PopupWindow(context), ViewTreeObserver.OnGlobalLayoutListener { abstract class OverKeyboardPopupWindow(
val context: Context,
private val rootView: View
) : PopupWindow(context), ViewTreeObserver.OnGlobalLayoutListener {
/** /**
* @return keyboard height in pixels * @return keyboard height in pixels
...@@ -154,6 +159,4 @@ abstract class OverKeyboardPopupWindow(val context: Context, private val rootVie ...@@ -154,6 +159,4 @@ abstract class OverKeyboardPopupWindow(val context: Context, private val rootVie
abstract fun onCreateView(inflater: LayoutInflater): View abstract fun onCreateView(inflater: LayoutInflater): View
abstract fun onViewCreated(view: View) abstract fun onViewCreated(view: View)
} }
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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