Commit c113af7b authored by Leonardo Aramaki's avatar Leonardo Aramaki

Implement backspace from emoji keyboard

parent c79c635d
......@@ -45,7 +45,7 @@
<activity
android:name=".chatroom.ui.ChatRoomActivity"
android:windowSoftInputMode="adjustNothing"
android:windowSoftInputMode="adjustPan"
android:theme="@style/AppTheme" />
<activity
......
......@@ -15,7 +15,7 @@ import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.realtime.State
import chat.rocket.core.internal.realtime.connect
import chat.rocket.core.internal.realtime.subscribeRoomMessages
import chat.rocket.core.internal.realtime.unsubscibre
import chat.rocket.core.internal.realtime.unsubscribe
import chat.rocket.core.internal.rest.*
import chat.rocket.core.model.Message
import chat.rocket.core.model.Value
......@@ -47,7 +47,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
view.showLoading()
try {
val messages =
client.messages(chatRoomId, roomTypeOf(chatRoomType), offset, 30).result
client.messages(chatRoomId, roomTypeOf(chatRoomType), offset, 30).result
messagesRepository.saveAll(messages)
val messagesViewModels = mapper.mapToViewModelList(messages, settings)
......@@ -180,7 +180,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
launch(CommonPool) {
client.removeStateChannel(stateChannel)
subId?.let { subscriptionId ->
client.unsubscibre(subscriptionId)
client.unsubscribe(subscriptionId)
}
}
}
......@@ -239,9 +239,9 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
is RoomType.Custom -> "custom" //TODO: put appropriate callback string here.
}
view.showReplyingAction(
user,
"[ ](${serverUrl}/${room}/${roomName}?msg=${id}) ${mention} ",
m.message
user,
"[ ](${serverUrl}/${room}/${roomName}?msg=${id}) ${mention} ",
m.message
)
}
}
......
......@@ -247,6 +247,17 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.EmojiKeyboardLi
}
}
override fun onKeyPressed(keyCode: Int) {
when (keyCode) {
KeyEvent.KEYCODE_BACK -> with(text_message) {
if (selectionStart > 0) {
text.delete(selectionStart - 1, selectionStart)
}
}
else -> throw IllegalArgumentException("pressed key not expected")
}
}
private fun setReactionButtonIcon(@DrawableRes drawableId: Int) {
button_add_reaction.setImageResource(drawableId)
button_add_reaction.setTag(drawableId)
......
......@@ -202,7 +202,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
room.readonly,
room.updatedAt ?: updatedAt,
timestamp,
lastModified,
lastSeen,
room.topic,
room.announcement,
default,
......@@ -232,7 +232,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
subscription.readonly ?: readonly,
subscription.updatedAt ?: updatedAt,
subscription.timestamp ?: timestamp,
subscription.lastModified ?: lastModified,
subscription.lastModified ?: lastSeen,
topic,
announcement,
subscription.isDefault,
......
......@@ -6,16 +6,16 @@ import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.core.internal.SettingsAdapter
import chat.rocket.core.model.Value
class SharedPreferencesSettingsRepository(private val localRespository: LocalRepository) : SettingsRepository {
class SharedPreferencesSettingsRepository(private val localRepository: LocalRepository) : SettingsRepository {
private val adapter = SettingsAdapter()
private val adapter = SettingsAdapter().lenient()
override fun save(url: String, settings: Map<String, Value<Any>>) {
localRespository.save("$SETTINGS_KEY$url", adapter.toJson(settings))
localRepository.save("$SETTINGS_KEY$url", adapter.toJson(settings))
}
override fun get(url: String): Map<String, Value<Any>>? {
val settings = localRespository.get("$SETTINGS_KEY$url")
val settings = localRepository.get("$SETTINGS_KEY$url")
settings?.let {
return adapter.fromJson(it)
}
......
......@@ -9,10 +9,7 @@ import android.support.v4.app.FragmentActivity
import android.support.v4.view.ViewPager
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.*
import android.widget.EditText
import android.widget.ImageView
import chat.rocket.android.R
......@@ -22,6 +19,8 @@ import chat.rocket.android.util.extensions.setVisible
class EmojiFragment : Fragment() {
private lateinit var viewPager: ViewPager
private lateinit var tabLayout: TabLayout
private lateinit var searchView: View
private lateinit var backspaceView: View
private lateinit var parentContainer: ViewGroup
private var editor: View? = null
private var decorLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null
......@@ -55,6 +54,8 @@ class EmojiFragment : Fragment() {
val view = inflater.inflate(R.layout.emoji_popup_layout, container, false)
parentContainer = view.findViewById(R.id.emoji_keyboard_container)
viewPager = view.findViewById(R.id.pager_categories)
searchView = view.findViewById(R.id.emoji_search)
backspaceView = view.findViewById(R.id.emoji_backspace)
tabLayout = view.findViewById(R.id.tabs)
tabLayout.setupWithViewPager(viewPager)
return view
......@@ -68,17 +69,12 @@ class EmojiFragment : Fragment() {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val callback = when (activity) {
is EmojiKeyboardListener -> activity as EmojiKeyboardListener
else -> {
val fragments = activity?.supportFragmentManager?.fragments
if (fragments == null || fragments.size == 0 || !(fragments[0] is EmojiKeyboardListener)) {
throw IllegalStateException("activity/fragment should implement EmojiKeyboardListener interface")
}
fragments[0] as EmojiKeyboardListener
}
}
setupLayout()
setupViewPager()
setupBottomBar()
}
private fun setupLayout() {
activity?.let {
val decorView = it.getWindow().decorView
decorLayoutListener = object : ViewTreeObserver.OnGlobalLayoutListener {
......@@ -119,25 +115,53 @@ class EmojiFragment : Fragment() {
if (storedHeight > 0) {
setKeyboardHeight(storedHeight)
}
}
private fun setupBottomBar() {
searchView.setOnClickListener {
viewPager.adapter = CategoryPagerAdapter(object : EmojiKeyboardListener {
override fun onEmojiAdded(emoji: Emoji) {
EmojiRepository.addToRecents(emoji)
callback.onEmojiAdded(emoji)
}
})
for (category in EmojiCategory.values()) {
val tab = tabLayout.getTabAt(category.ordinal)
val tabView = layoutInflater.inflate(R.layout.emoji_picker_tab, null)
tab?.setCustomView(tabView)
val textView = tabView.findViewById(R.id.image_category) as ImageView
textView.setImageResource(category.resourceIcon())
}
val currentTab = if (EmojiRepository.getRecents().isEmpty()) EmojiCategory.PEOPLE.ordinal else
EmojiCategory.RECENTS.ordinal
viewPager.setCurrentItem(currentTab)
backspaceView.setOnClickListener {
listener?.onKeyPressed(KeyEvent.KEYCODE_BACK)
}
}
private fun setupViewPager() {
activity?.let {
val callback = when (it) {
is EmojiKeyboardListener -> it as EmojiKeyboardListener
else -> {
val fragments = it.supportFragmentManager.fragments
if (fragments == null || fragments.size == 0 || !(fragments[0] is EmojiKeyboardListener)) {
throw IllegalStateException("activity/fragment should implement EmojiKeyboardListener interface")
}
fragments[0] as EmojiKeyboardListener
}
}
viewPager.adapter = CategoryPagerAdapter(object : EmojiKeyboardListener {
override fun onKeyPressed(keyCode: Int) {
// do nothing
}
override fun onEmojiAdded(emoji: Emoji) {
EmojiRepository.addToRecents(emoji)
callback.onEmojiAdded(emoji)
}
})
for (category in EmojiCategory.values()) {
val tab = tabLayout.getTabAt(category.ordinal)
val tabView = layoutInflater.inflate(R.layout.emoji_picker_tab, null)
tab?.setCustomView(tabView)
val textView = tabView.findViewById(R.id.image_category) as ImageView
textView.setImageResource(category.resourceIcon())
}
val currentTab = if (EmojiRepository.getRecents().isEmpty()) EmojiCategory.PEOPLE.ordinal else
EmojiCategory.RECENTS.ordinal
viewPager.setCurrentItem(currentTab)
}
}
private fun setKeyboardHeight(height: Int) {
......@@ -229,10 +253,19 @@ class EmojiFragment : Fragment() {
interface EmojiKeyboardListener {
/**
* Callback after an emoji is selected on the picker.
* When an emoji is selected on the picker.
*
* @param emoji The selected emoji
*/
fun onEmojiAdded(emoji: Emoji)
/**
* When backspace key is clicked.
*
* @param keyCode The key code pressed as defined
*
* @see android.view.KeyEvent
*/
fun onKeyPressed(keyCode: Int)
}
}
\ No newline at end of file
......@@ -7,7 +7,7 @@
<path android:pathData="M0,0 L24,0 L24,24 L0,24 Z" />
<path
android:fillColor="#000000"
android:fillColor="@color/colorEmojiIcon"
android:pathData="M22,3 L7,3 C6.31,3,5.77,3.35,5.41,3.88 L0,12 L5.41,20.11
C5.77,20.64,6.31,21,7,21 L22,21 C23.1,21,24,20.1,24,19 L24,5 C24,3.9,23.1,3,22,3
Z M19,15.59 L17.59,17 L14,13.41 L10.41,17 L9,15.59 L12.59,12 L9,8.41 L10.41,7
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="@color/colorEmojiIcon"
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
</vector>
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:autoMirrored="true"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFFFFF"
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
</vector>
......@@ -5,8 +5,6 @@
android:layout_height="wrap_content">
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/emojiRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"
......
......@@ -37,9 +37,44 @@
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintBottom_toTopOf="@+id/emoji_actions_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tabs" />
<RelativeLayout
android:id="@+id/emoji_actions_container"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@color/whitesmoke"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<ImageView
android:id="@+id/emoji_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
android:background="@color/whitesmoke"
android:clickable="true"
android:focusable="true"
android:padding="8dp"
android:src="@drawable/ic_search_gray_24px" />
<ImageView
android:id="@+id/emoji_backspace"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@color/whitesmoke"
android:clickable="true"
android:focusable="true"
android:padding="8dp"
android:src="@drawable/ic_backspace_gray_24dp" />
</RelativeLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
......@@ -31,5 +31,6 @@
<color name="linkTextColor">#FF074481</color>
<color name="linkBackgroundColor">#30074481</color>
<color name="colorEmojiIcon">#FF767676</color>
</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