Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
AloqaIM-Android
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
AloqaIM-Android
Commits
18800044
Commit
18800044
authored
Feb 22, 2018
by
Leonardo Aramaki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Keyboard backpressing closes also the emoji keyboard
parent
2e563131
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
246 additions
and
60 deletions
+246
-60
ChatRoomActivity.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
+3
-0
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+90
-29
KeyboardHelper.kt
...rc/main/java/chat/rocket/android/helper/KeyboardHelper.kt
+7
-0
Text.kt
...src/main/java/chat/rocket/android/util/extensions/Text.kt
+12
-1
CategoryPagerAdapter.kt
.../chat/rocket/android/widget/emoji/CategoryPagerAdapter.kt
+8
-8
ComposerEditText.kt
...java/chat/rocket/android/widget/emoji/ComposerEditText.kt
+35
-0
EmojiFragment.kt
...in/java/chat/rocket/android/widget/emoji/EmojiFragment.kt
+86
-17
ic_keyboard_black_24dp.xml
app/src/main/res/drawable/ic_keyboard_black_24dp.xml
+0
-0
message_composer.xml
app/src/main/res/layout/message_composer.xml
+5
-5
No files found.
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
View file @
18800044
...
@@ -6,6 +6,7 @@ import android.os.Bundle
...
@@ -6,6 +6,7 @@ import android.os.Bundle
import
android.support.v4.app.Fragment
import
android.support.v4.app.Fragment
import
android.support.v7.app.AppCompatActivity
import
android.support.v7.app.AppCompatActivity
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.util.extensions.addFragment
import
chat.rocket.android.util.extensions.addFragment
import
chat.rocket.android.util.extensions.textContent
import
chat.rocket.android.util.extensions.textContent
import
chat.rocket.android.widget.emoji.EmojiFragment
import
chat.rocket.android.widget.emoji.EmojiFragment
...
@@ -63,10 +64,12 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
...
@@ -63,10 +64,12 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
}
}
override
fun
onBackPressed
()
{
override
fun
onBackPressed
()
{
super
.
onBackPressed
()
val
frag
=
supportFragmentManager
.
findFragmentByTag
(
EmojiFragment
.
TAG
)
as
EmojiFragment
?
val
frag
=
supportFragmentManager
.
findFragmentByTag
(
EmojiFragment
.
TAG
)
as
EmojiFragment
?
if
(
frag
!=
null
&&
frag
.
isShown
())
{
if
(
frag
!=
null
&&
frag
.
isShown
())
{
frag
.
hide
()
frag
.
hide
()
}
else
{
}
else
{
KeyboardHelper
.
hideSoftKeyboard
(
this
)
finishActivity
()
finishActivity
()
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
18800044
...
@@ -8,13 +8,13 @@ import android.content.Intent
...
@@ -8,13 +8,13 @@ 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.support.annotation.DrawableRes
import
android.support.v4.app.Fragment
import
android.support.v4.app.Fragment
import
android.support.v7.widget.DefaultItemAnimator
import
android.support.v7.widget.DefaultItemAnimator
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.RecyclerView
import
android.support.v7.widget.RecyclerView
import
android.text.method.ScrollingMovementMethod
import
android.text.method.ScrollingMovementMethod
import
android.view.*
import
android.view.*
import
android.widget.ImageButton
import
chat.rocket.android.R
import
chat.rocket.android.R
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
...
@@ -23,9 +23,11 @@ import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
...
@@ -23,9 +23,11 @@ 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
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.widget.emoji.ComposerEditText
import
chat.rocket.android.widget.emoji.Emoji
import
chat.rocket.android.widget.emoji.Emoji
import
chat.rocket.android.widget.emoji.EmojiFragment
import
chat.rocket.android.widget.emoji.EmojiFragment
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.common.util.ifNull
import
dagger.android.support.AndroidSupportInjection
import
dagger.android.support.AndroidSupportInjection
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.*
...
@@ -49,7 +51,7 @@ private const val BUNDLE_CHAT_ROOM_TYPE = "chat_room_type"
...
@@ -49,7 +51,7 @@ private const val BUNDLE_CHAT_ROOM_TYPE = "chat_room_type"
private
const
val
BUNDLE_IS_CHAT_ROOM_READ_ONLY
=
"is_chat_room_read_only"
private
const
val
BUNDLE_IS_CHAT_ROOM_READ_ONLY
=
"is_chat_room_read_only"
private
const
val
REQUEST_CODE_FOR_PERFORM_SAF
=
42
private
const
val
REQUEST_CODE_FOR_PERFORM_SAF
=
42
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiFragment
.
OnEmojiClickCallback
{
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiFragment
.
EmojiKeyboardListener
{
@Inject
lateinit
var
presenter
:
ChatRoomPresenter
@Inject
lateinit
var
presenter
:
ChatRoomPresenter
@Inject
lateinit
var
parser
:
MessageParser
@Inject
lateinit
var
parser
:
MessageParser
private
lateinit
var
adapter
:
ChatRoomAdapter
private
lateinit
var
adapter
:
ChatRoomAdapter
...
@@ -95,12 +97,24 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -95,12 +97,24 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
setupActionSnackbar
()
setupActionSnackbar
()
}
}
override
fun
onActivityCreated
(
savedInstanceState
:
Bundle
?)
{
super
.
onActivityCreated
(
savedInstanceState
)
attachOrGetEmojiFragment
()
text_message
.
addTextChangedListener
(
EmojiFragment
.
EmojiTextWatcher
(
text_message
))
text_message
.
requestFocus
()
}
override
fun
onDestroyView
()
{
override
fun
onDestroyView
()
{
presenter
.
unsubscribeMessages
()
presenter
.
unsubscribeMessages
()
handler
.
removeCallbacksAndMessages
(
null
)
handler
.
removeCallbacksAndMessages
(
null
)
super
.
onDestroyView
()
super
.
onDestroyView
()
}
}
override
fun
onStop
()
{
super
.
onStop
()
hideAllKeyboards
()
}
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
resultData
:
Intent
?)
{
override
fun
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
resultData
:
Intent
?)
{
if
(
requestCode
==
REQUEST_CODE_FOR_PERFORM_SAF
&&
resultCode
==
Activity
.
RESULT_OK
)
{
if
(
requestCode
==
REQUEST_CODE_FOR_PERFORM_SAF
&&
resultCode
==
Activity
.
RESULT_OK
)
{
if
(
resultData
!=
null
)
{
if
(
resultData
!=
null
)
{
...
@@ -134,6 +148,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -134,6 +148,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
presenter
)
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
presenter
)
recycler_view
.
adapter
=
adapter
recycler_view
.
adapter
=
adapter
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
true
)
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
true
)
linearLayoutManager
.
stackFromEnd
=
true
recycler_view
.
layoutManager
=
linearLayoutManager
recycler_view
.
layoutManager
=
linearLayoutManager
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
if
(
dataSet
.
size
>=
30
)
{
if
(
dataSet
.
size
>=
30
)
{
...
@@ -145,6 +160,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -145,6 +160,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
}
}
}
}
adapter
.
addDataSet
(
dataSet
)
adapter
.
addDataSet
(
dataSet
)
if
(
adapter
.
itemCount
>
0
)
{
recycler_view
.
scrollToPosition
(
0
)
}
}
}
}
}
...
@@ -162,7 +180,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -162,7 +180,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
override
fun
showInvalidFileMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_invalid_file
))
override
fun
showInvalidFileMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_invalid_file
))
override
fun
showNewMessage
(
message
:
MessageViewModel
)
{
override
fun
showNewMessage
(
message
:
MessageViewModel
)
{
text_message
.
textContent
=
""
adapter
.
addItem
(
message
)
adapter
.
addItem
(
message
)
recycler_view
.
smoothScrollToPosition
(
0
)
recycler_view
.
smoothScrollToPosition
(
0
)
}
}
...
@@ -175,7 +192,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -175,7 +192,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
override
fun
enableMessageInput
(
clear
:
Boolean
)
{
override
fun
enableMessageInput
(
clear
:
Boolean
)
{
button_send
.
isEnabled
=
true
button_send
.
isEnabled
=
true
text_message
.
isEnabled
=
true
text_message
.
isEnabled
=
true
if
(
clear
)
text_message
.
textContent
=
""
if
(
clear
)
text_message
.
erase
()
}
}
override
fun
dispatchUpdateMessage
(
index
:
Int
,
message
:
MessageViewModel
)
{
override
fun
dispatchUpdateMessage
(
index
:
Int
,
message
:
MessageViewModel
)
{
...
@@ -220,13 +237,45 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -220,13 +237,45 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
text_message
.
textContent
=
text
text_message
.
textContent
=
text
editingMessageId
=
messageId
editingMessageId
=
messageId
}
}
}
}
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
val
cursorPosition
=
text_message
.
selectionStart
val
cursorPosition
=
text_message
.
selectionStart
text_message
.
text
.
insert
(
cursorPosition
,
EmojiParser
.
parse
(
emoji
.
shortname
))
if
(
cursorPosition
>
-
1
)
{
text_message
.
setSelection
(
cursorPosition
+
emoji
.
unicode
.
length
)
text_message
.
text
.
insert
(
cursorPosition
,
EmojiParser
.
parse
(
emoji
.
shortname
))
text_message
.
setSelection
(
cursorPosition
+
emoji
.
unicode
.
length
)
}
}
override
fun
onSoftKeyboardHidden
()
{
setReactionButtonIcon
(
R
.
drawable
.
ic_keyboard_black_24dp
)
}
override
fun
onSoftKeyboardShown
()
{
setReactionButtonIcon
(
R
.
drawable
.
ic_reaction_24dp
)
recycler_view
.
scrollToPosition
(
0
)
}
override
fun
onEmojiKeyboardHidden
()
{
setReactionButtonIcon
(
R
.
drawable
.
ic_reaction_24dp
)
}
override
fun
onEmojiKeyboardShown
()
{
setReactionButtonIcon
(
R
.
drawable
.
ic_keyboard_black_24dp
)
recycler_view
.
scrollToPosition
(
0
)
}
private
fun
setReactionButtonIcon
(
@DrawableRes
drawableId
:
Int
)
{
button_add_reaction
.
setImageResource
(
drawableId
)
button_add_reaction
.
setTag
(
drawableId
)
}
private
fun
hideAllKeyboards
()
{
activity
?.
let
{
KeyboardHelper
.
hideSoftKeyboard
(
it
)
attachOrGetEmojiFragment
()
?.
hide
()
setReactionButtonIcon
(
R
.
drawable
.
ic_reaction_24dp
)
}
}
}
private
fun
setupComposer
()
{
private
fun
setupComposer
()
{
...
@@ -251,10 +300,28 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -251,10 +300,28 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
}
}
})
})
text_message
.
listener
=
object
:
ComposerEditText
.
ComposerEditTextListener
{
override
fun
onKeyboardClose
()
{
activity
?.
let
{
val
fragment
=
EmojiFragment
.
getOrAttach
(
it
,
R
.
id
.
emoji_fragment_placeholder
,
composer
)
if
(
fragment
.
isCollapsed
())
{
it
.
onBackPressed
()
}
else
{
hideAllKeyboards
()
}
}
}
}
button_send
.
setOnClickListener
{
button_send
.
setOnClickListener
{
var
textMessage
=
citation
?:
""
var
textMessage
=
citation
?:
""
textMessage
+=
text_message
.
textContent
textMessage
+=
text_message
.
textContent
sendMessage
(
textMessage
)
sendMessage
(
textMessage
)
attachOrGetEmojiFragment
()
?.
let
{
if
(
it
.
softKeyboardVisible
)
{
it
.
hide
()
}
}
clearActionMessage
()
clearActionMessage
()
}
}
...
@@ -263,6 +330,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -263,6 +330,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
if
(
layout_message_attachment_options
.
isShown
)
{
if
(
layout_message_attachment_options
.
isShown
)
{
hideAttachmentOptions
()
hideAttachmentOptions
()
}
else
{
}
else
{
hideAllKeyboards
()
showAttachmentOptions
()
showAttachmentOptions
()
}
}
}
}
...
@@ -282,28 +350,27 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -282,28 +350,27 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
button_add_reaction
.
setOnClickListener
{
view
->
button_add_reaction
.
setOnClickListener
{
view
->
activity
?.
let
{
activity
?.
let
{
val
editor
=
text_message
val
editor
=
text_message
val
emojiFragment
=
EmojiFragment
.
getOrAttach
(
it
,
R
.
id
.
emoji_fragment_placeholder
,
composer
)
val
emojiFragment
=
attachOrGetEmojiFragment
()
!!
with
(
emojiFragment
)
{
val
tag
=
if
(
view
.
tag
==
null
)
R
.
drawable
.
ic_reaction_24dp
else
view
.
tag
as
Int
if
(!
isShown
())
{
when
(
tag
)
{
show
()
R
.
drawable
.
ic_reaction_24dp
->
{
}
else
{
KeyboardHelper
.
hideSoftKeyboard
(
it
)
val
button
=
view
as
ImageButton
if
(!
emojiFragment
.
isShown
())
{
val
resourceId
:
Int
emojiFragment
.
show
()
if
(
softKeyboardVisible
)
{
resourceId
=
R
.
drawable
.
ic_keyboard_black_24px
KeyboardHelper
.
hideSoftKeyboard
(
it
)
}
else
{
resourceId
=
R
.
drawable
.
ic_reaction_24dp
KeyboardHelper
.
showSoftKeyboard
(
editor
)
}
}
button
.
setImageResource
(
resourceId
)
}
}
R
.
drawable
.
ic_keyboard_black_24dp
->
KeyboardHelper
.
showSoftKeyboard
(
editor
)
}
}
}
}
}
}
}
}
addEmojiFragment
()
private
fun
attachOrGetEmojiFragment
():
EmojiFragment
?
{
text_message
.
addTextChangedListener
(
EmojiFragment
.
EmojiTextWatcher
(
text_message
))
return
activity
?.
let
{
val
frag
=
EmojiFragment
.
getOrAttach
(
it
,
R
.
id
.
emoji_fragment_placeholder
,
composer
)
frag
.
listener
=
this
frag
}
}
}
}
...
@@ -314,12 +381,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
...
@@ -314,12 +381,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiFragment.OnEmojiClickCal
})
})
}
}
private
fun
addEmojiFragment
()
{
activity
?.
let
{
EmojiFragment
.
getOrAttach
(
it
,
R
.
id
.
emoji_fragment_placeholder
,
composer
)
}
}
private
fun
clearActionMessage
()
{
private
fun
clearActionMessage
()
{
citation
=
null
citation
=
null
editingMessageId
=
null
editingMessageId
=
null
...
...
app/src/main/java/chat/rocket/android/helper/KeyboardHelper.kt
View file @
18800044
...
@@ -51,4 +51,11 @@ object KeyboardHelper {
...
@@ -51,4 +51,11 @@ object KeyboardHelper {
inputMethodManager
.
toggleSoftInput
(
InputMethodManager
.
SHOW_FORCED
,
0
)
inputMethodManager
.
toggleSoftInput
(
InputMethodManager
.
SHOW_FORCED
,
0
)
}
}
}
}
fun
restart
(
view
:
View
)
{
if
(
view
.
requestFocus
())
{
val
inputMethodManager
=
view
.
context
.
getSystemService
(
Context
.
INPUT_METHOD_SERVICE
)
as
InputMethodManager
inputMethodManager
.
restartInput
(
view
)
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/util/extensions/Text.kt
View file @
18800044
...
@@ -10,7 +10,9 @@ import android.provider.MediaStore
...
@@ -10,7 +10,9 @@ import android.provider.MediaStore
import
android.text.Spannable
import
android.text.Spannable
import
android.text.Spanned
import
android.text.Spanned
import
android.text.TextUtils
import
android.text.TextUtils
import
android.widget.EditText
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.android.widget.emoji.EmojiTypefaceSpan
import
ru.noties.markwon.Markwon
import
ru.noties.markwon.Markwon
fun
String
.
ifEmpty
(
value
:
String
):
String
{
fun
String
.
ifEmpty
(
value
:
String
):
String
{
...
@@ -27,6 +29,14 @@ fun CharSequence.ifEmpty(value: String): CharSequence {
...
@@ -27,6 +29,14 @@ fun CharSequence.ifEmpty(value: String): CharSequence {
return
this
return
this
}
}
fun
EditText
.
erase
()
{
this
.
text
.
clear
()
val
spans
=
this
.
text
.
getSpans
(
0
,
text
.
length
,
EmojiTypefaceSpan
::
class
.
java
)
spans
.
forEach
{
text
.
removeSpan
(
it
)
}
}
var
TextView
.
textContent
:
String
var
TextView
.
textContent
:
String
get
()
=
text
.
toString
()
get
()
=
text
.
toString
()
set
(
value
)
{
set
(
value
)
{
...
@@ -46,7 +56,8 @@ var TextView.content: CharSequence
...
@@ -46,7 +56,8 @@ var TextView.content: CharSequence
Markwon
.
unscheduleTableRows
(
this
)
Markwon
.
unscheduleTableRows
(
this
)
if
(
value
is
Spanned
)
{
if
(
value
is
Spanned
)
{
val
result
=
EmojiParser
.
parse
(
value
.
toString
())
as
Spannable
val
result
=
EmojiParser
.
parse
(
value
.
toString
())
as
Spannable
TextUtils
.
copySpansFrom
(
value
,
0
,
value
.
length
,
Any
::
class
.
java
,
result
,
0
)
val
end
=
if
(
value
.
length
>
result
.
length
)
result
.
length
else
value
.
length
TextUtils
.
copySpansFrom
(
value
,
0
,
end
,
Any
::
class
.
java
,
result
,
0
)
text
=
result
text
=
result
}
else
{
}
else
{
val
result
=
EmojiParser
.
parse
(
value
.
toString
())
as
Spannable
val
result
=
EmojiParser
.
parse
(
value
.
toString
())
as
Spannable
...
...
app/src/main/java/chat/rocket/android/widget/emoji/CategoryPagerAdapter.kt
View file @
18800044
...
@@ -9,10 +9,10 @@ import android.view.View
...
@@ -9,10 +9,10 @@ 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
chat.rocket.android.R
import
chat.rocket.android.widget.emoji.EmojiFragment.
OnEmojiClickCallback
import
chat.rocket.android.widget.emoji.EmojiFragment.
EmojiKeyboardListener
import
java.util.*
import
java.util.*
class
CategoryPagerAdapter
(
val
callback
:
OnEmojiClickCallback
)
:
PagerAdapter
()
{
class
CategoryPagerAdapter
(
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,9 +20,9 @@ class CategoryPagerAdapter(val callback: OnEmojiClickCallback) : PagerAdapter()
...
@@ -20,9 +20,9 @@ class CategoryPagerAdapter(val callback: OnEmojiClickCallback) : 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
,
5
)
val
layoutManager
=
GridLayoutManager
(
view
.
context
,
8
)
val
recycler
=
view
.
findViewById
(
R
.
id
.
emojiRecyclerView
)
as
RecyclerView
val
recycler
=
view
.
findViewById
(
R
.
id
.
emojiRecyclerView
)
as
RecyclerView
val
adapter
=
EmojiAdapter
(
layoutManager
.
spanCount
,
callback
)
val
adapter
=
EmojiAdapter
(
layoutManager
.
spanCount
,
listener
)
val
category
=
EmojiCategory
.
values
().
get
(
position
)
val
category
=
EmojiCategory
.
values
().
get
(
position
)
val
emojis
=
if
(
category
!=
EmojiCategory
.
RECENTS
)
val
emojis
=
if
(
category
!=
EmojiCategory
.
RECENTS
)
EmojiRepository
.
getEmojisByCategory
(
category
)
EmojiRepository
.
getEmojisByCategory
(
category
)
...
@@ -46,7 +46,7 @@ class CategoryPagerAdapter(val callback: OnEmojiClickCallback) : PagerAdapter()
...
@@ -46,7 +46,7 @@ class CategoryPagerAdapter(val callback: OnEmojiClickCallback) : PagerAdapter()
override
fun
getPageTitle
(
position
:
Int
)
=
EmojiCategory
.
values
()[
position
].
icon
()
override
fun
getPageTitle
(
position
:
Int
)
=
EmojiCategory
.
values
()[
position
].
icon
()
class
EmojiAdapter
(
val
spanCount
:
Int
,
val
callback
:
OnEmojiClickCallback
)
:
RecyclerView
.
Adapter
<
EmojiRowViewHolder
>()
{
class
EmojiAdapter
(
val
spanCount
:
Int
,
val
listener
:
EmojiKeyboardListener
)
:
RecyclerView
.
Adapter
<
EmojiRowViewHolder
>()
{
private
var
emojis
:
List
<
Emoji
>
=
Collections
.
emptyList
()
private
var
emojis
:
List
<
Emoji
>
=
Collections
.
emptyList
()
fun
addEmojis
(
emojis
:
List
<
Emoji
>)
{
fun
addEmojis
(
emojis
:
List
<
Emoji
>)
{
...
@@ -60,13 +60,13 @@ class CategoryPagerAdapter(val callback: OnEmojiClickCallback) : PagerAdapter()
...
@@ -60,13 +60,13 @@ class CategoryPagerAdapter(val callback: OnEmojiClickCallback) : PagerAdapter()
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
EmojiRowViewHolder
{
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
EmojiRowViewHolder
{
val
view
=
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
emoji_row_item
,
parent
,
false
)
val
view
=
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
emoji_row_item
,
parent
,
false
)
return
EmojiRowViewHolder
(
view
,
itemCount
,
spanCount
,
callback
)
return
EmojiRowViewHolder
(
view
,
itemCount
,
spanCount
,
listener
)
}
}
override
fun
getItemCount
():
Int
=
emojis
.
size
override
fun
getItemCount
():
Int
=
emojis
.
size
}
}
class
EmojiRowViewHolder
(
itemView
:
View
,
val
itemCount
:
Int
,
val
spanCount
:
Int
,
val
callback
:
OnEmojiClickCallback
)
:
RecyclerView
.
ViewHolder
(
itemView
)
{
class
EmojiRowViewHolder
(
itemView
:
View
,
val
itemCount
:
Int
,
val
spanCount
:
Int
,
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
)
{
...
@@ -79,7 +79,7 @@ class CategoryPagerAdapter(val callback: OnEmojiClickCallback) : PagerAdapter()
...
@@ -79,7 +79,7 @@ class CategoryPagerAdapter(val callback: OnEmojiClickCallback) : PagerAdapter()
itemView
.
setPadding
(
0
,
0
,
0
,
paddingBottom
)
itemView
.
setPadding
(
0
,
0
,
0
,
paddingBottom
)
}
}
itemView
.
setOnClickListener
{
itemView
.
setOnClickListener
{
callback
.
onEmojiAdded
(
emoji
)
listener
.
onEmojiAdded
(
emoji
)
}
}
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/widget/emoji/ComposerEditText.kt
0 → 100644
View file @
18800044
package
chat.rocket.android.widget.emoji
import
android.content.Context
import
android.support.v7.widget.AppCompatEditText
import
android.util.AttributeSet
import
android.view.KeyEvent
class
ComposerEditText
:
AppCompatEditText
{
var
listener
:
ComposerEditTextListener
?
=
null
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?,
defStyleAttr
:
Int
)
:
super
(
context
,
attrs
,
defStyleAttr
)
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?)
:
this
(
context
,
attrs
,
android
.
support
.
v7
.
appcompat
.
R
.
attr
.
editTextStyle
)
constructor
(
context
:
Context
)
:
this
(
context
,
null
)
override
fun
dispatchKeyEventPreIme
(
event
:
KeyEvent
):
Boolean
{
if
(
event
.
keyCode
==
KeyEvent
.
KEYCODE_BACK
)
{
val
state
=
getKeyDispatcherState
()
if
(
state
!=
null
)
{
if
(
event
.
action
==
KeyEvent
.
ACTION_DOWN
)
{
state
.
startTracking
(
event
,
this
)
listener
?.
onKeyboardClose
()
}
return
true
}
}
return
super
.
dispatchKeyEventPreIme
(
event
)
}
interface
ComposerEditTextListener
{
fun
onKeyboardClose
()
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/emoji/EmojiFragment.kt
View file @
18800044
...
@@ -22,13 +22,16 @@ import chat.rocket.android.util.extensions.setVisible
...
@@ -22,13 +22,16 @@ import chat.rocket.android.util.extensions.setVisible
class
EmojiFragment
:
Fragment
()
{
class
EmojiFragment
:
Fragment
()
{
private
lateinit
var
viewPager
:
ViewPager
private
lateinit
var
viewPager
:
ViewPager
private
lateinit
var
tabLayout
:
TabLayout
private
lateinit
var
tabLayout
:
TabLayout
private
lateinit
var
editor
:
View
private
lateinit
var
parentContainer
:
ViewGroup
internal
lateinit
var
parentContainer
:
ViewGroup
private
var
editor
:
View
?
=
null
private
var
decorLayoutListener
:
ViewTreeObserver
.
OnGlobalLayoutListener
?
=
null
var
softKeyboardVisible
=
false
var
softKeyboardVisible
=
false
var
listener
:
EmojiKeyboardListener
?
=
null
companion
object
{
companion
object
{
const
val
PREF_EMOJI_RECENTS
=
"PREF_EMOJI_RECENTS"
const
val
PREF_EMOJI_RECENTS
=
"PREF_EMOJI_RECENTS"
const
val
PREF_KEYBOARD_HEIGHT
=
"PREF_KEYBOARD_HEIGHT"
const
val
PREF_KEYBOARD_HEIGHT
=
"PREF_KEYBOARD_HEIGHT"
const
val
MIN_KEYBOARD_HEIGHT_PX
=
150
val
TAG
:
String
=
EmojiFragment
::
class
.
java
.
simpleName
val
TAG
:
String
=
EmojiFragment
::
class
.
java
.
simpleName
fun
newInstance
(
editor
:
View
)
=
EmojiFragment
().
apply
{
this
.
editor
=
editor
}
fun
newInstance
(
editor
:
View
)
=
EmojiFragment
().
apply
{
this
.
editor
=
editor
}
...
@@ -57,40 +60,51 @@ class EmojiFragment : Fragment() {
...
@@ -57,40 +60,51 @@ class EmojiFragment : Fragment() {
return
view
return
view
}
}
override
fun
onDetach
()
{
super
.
onDetach
()
activity
?.
getWindow
()
?.
decorView
?.
viewTreeObserver
?.
removeOnGlobalLayoutListener
(
decorLayoutListener
)
listener
=
null
editor
=
null
}
override
fun
onViewCreated
(
view
:
View
,
savedInstanceState
:
Bundle
?)
{
override
fun
onViewCreated
(
view
:
View
,
savedInstanceState
:
Bundle
?)
{
val
callback
=
when
(
activity
)
{
val
callback
=
when
(
activity
)
{
is
OnEmojiClickCallback
->
activity
as
OnEmojiClickCallback
is
EmojiKeyboardListener
->
activity
as
EmojiKeyboardListener
else
->
{
else
->
{
val
fragments
=
activity
?.
supportFragmentManager
?.
fragments
val
fragments
=
activity
?.
supportFragmentManager
?.
fragments
if
(
fragments
==
null
||
fragments
.
size
==
0
||
!(
fragments
[
0
]
is
OnEmojiClickCallback
))
{
if
(
fragments
==
null
||
fragments
.
size
==
0
||
!(
fragments
[
0
]
is
EmojiKeyboardListener
))
{
throw
IllegalStateException
(
"activity/fragment should implement
OnEmojiClickCallback
interface"
)
throw
IllegalStateException
(
"activity/fragment should implement
EmojiKeyboardListener
interface"
)
}
}
fragments
[
0
]
as
OnEmojiClickCallback
fragments
[
0
]
as
EmojiKeyboardListener
}
}
}
}
activity
?.
let
{
activity
?.
let
{
val
decorView
=
it
.
getWindow
().
decorView
val
decorView
=
it
.
getWindow
().
decorView
decor
View
.
viewTreeObserver
.
addOnGlobalLayoutListener
(
object
:
ViewTreeObserver
.
OnGlobalLayoutListener
{
decor
LayoutListener
=
object
:
ViewTreeObserver
.
OnGlobalLayoutListener
{
private
val
windowVisibleDisplayFrame
=
Rect
()
private
val
windowVisibleDisplayFrame
=
Rect
()
private
var
lastVisibleDecorViewHeight
:
Int
=
0
private
var
lastVisibleDecorViewHeight
:
Int
=
0
override
fun
onGlobalLayout
()
{
override
fun
onGlobalLayout
()
{
if
(
editor
==
null
)
{
return
}
// Retrieve visible rectangle inside window.
// Retrieve visible rectangle inside window.
decorView
.
getWindowVisibleDisplayFrame
(
windowVisibleDisplayFrame
)
decorView
.
getWindowVisibleDisplayFrame
(
windowVisibleDisplayFrame
)
val
visibleDecorViewHeight
=
windowVisibleDisplayFrame
.
height
()
val
visibleDecorViewHeight
=
windowVisibleDisplayFrame
.
height
()
// Decide whether keyboard is visible from changing decor view height.
// Decide whether keyboard is visible from changing decor view height.
if
(
lastVisibleDecorViewHeight
!=
0
)
{
if
(
lastVisibleDecorViewHeight
!=
0
)
{
if
(
lastVisibleDecorViewHeight
>
visibleDecorViewHeight
+
150
)
{
if
(
lastVisibleDecorViewHeight
>
visibleDecorViewHeight
+
MIN_KEYBOARD_HEIGHT_PX
)
{
// Calculate current keyboard height (this includes also navigation bar height when in fullscreen mode).
// Calculate current keyboard height (this includes also navigation bar height when in fullscreen mode).
val
currentKeyboardHeight
=
decorView
.
height
-
windowVisibleDisplayFrame
.
bottom
-
editor
.
measuredHeight
val
currentKeyboardHeight
=
decorView
.
height
-
windowVisibleDisplayFrame
.
bottom
-
editor
!!
.
measuredHeight
// Notify listener about keyboard being shown.
// Notify listener about keyboard being shown.
EmojiRepository
.
saveKeyboardHeight
(
currentKeyboardHeight
)
EmojiRepository
.
saveKeyboardHeight
(
currentKeyboardHeight
)
setKeyboardHeight
(
currentKeyboardHeight
)
setKeyboardHeight
(
currentKeyboardHeight
)
softKeyboardVisible
=
true
softKeyboardVisible
=
true
show
()
openHidden
()
}
else
if
(
lastVisibleDecorViewHeight
+
150
<
visibleDecorViewHeight
)
{
listener
?.
onSoftKeyboardShown
()
}
else
if
(
lastVisibleDecorViewHeight
+
MIN_KEYBOARD_HEIGHT_PX
<
visibleDecorViewHeight
)
{
// Notify listener about keyboard being hidden.
// Notify listener about keyboard being hidden.
softKeyboardVisible
=
false
softKeyboardVisible
=
false
}
}
...
@@ -98,7 +112,8 @@ class EmojiFragment : Fragment() {
...
@@ -98,7 +112,8 @@ class EmojiFragment : Fragment() {
// Save current decor view height for the next call.
// Save current decor view height for the next call.
lastVisibleDecorViewHeight
=
visibleDecorViewHeight
lastVisibleDecorViewHeight
=
visibleDecorViewHeight
}
}
})
}
decorView
.
viewTreeObserver
.
addOnGlobalLayoutListener
(
decorLayoutListener
)
}
}
val
storedHeight
=
EmojiRepository
.
getKeyboardHeight
()
val
storedHeight
=
EmojiRepository
.
getKeyboardHeight
()
...
@@ -106,7 +121,23 @@ class EmojiFragment : Fragment() {
...
@@ -106,7 +121,23 @@ class EmojiFragment : Fragment() {
setKeyboardHeight
(
storedHeight
)
setKeyboardHeight
(
storedHeight
)
}
}
viewPager
.
adapter
=
CategoryPagerAdapter
(
object
:
OnEmojiClickCallback
{
viewPager
.
adapter
=
CategoryPagerAdapter
(
object
:
EmojiKeyboardListener
{
override
fun
onEmojiKeyboardShown
()
{
// Do nothing here.
}
override
fun
onEmojiKeyboardHidden
()
{
// Do nothing here.
}
override
fun
onSoftKeyboardHidden
()
{
// Do nothing here.
}
override
fun
onSoftKeyboardShown
()
{
// Do nothing here.
}
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
EmojiRepository
.
addToRecents
(
emoji
)
EmojiRepository
.
addToRecents
(
emoji
)
callback
.
onEmojiAdded
(
emoji
)
callback
.
onEmojiAdded
(
emoji
)
...
@@ -127,8 +158,11 @@ class EmojiFragment : Fragment() {
...
@@ -127,8 +158,11 @@ class EmojiFragment : Fragment() {
}
}
private
fun
setKeyboardHeight
(
height
:
Int
)
{
private
fun
setKeyboardHeight
(
height
:
Int
)
{
parentContainer
.
layoutParams
.
height
=
height
val
oldHeight
=
parentContainer
.
layoutParams
.
height
parentContainer
.
requestLayout
()
if
(
oldHeight
!=
height
)
{
parentContainer
.
layoutParams
.
height
=
height
parentContainer
.
requestLayout
()
}
}
}
class
EmojiTextWatcher
(
val
editor
:
EditText
)
:
TextWatcher
{
class
EmojiTextWatcher
(
val
editor
:
EditText
)
:
TextWatcher
{
...
@@ -175,22 +209,57 @@ class EmojiFragment : Fragment() {
...
@@ -175,22 +209,57 @@ class EmojiFragment : Fragment() {
}
}
}
}
/**
* Show the emoji keyboard.
*/
fun
show
()
{
fun
show
()
{
parentContainer
.
setVisible
(
true
)
parentContainer
.
setVisible
(
true
)
listener
?.
onEmojiKeyboardShown
()
}
fun
openHidden
()
{
parentContainer
.
visibility
=
View
.
INVISIBLE
}
}
/**
* Hide the emoji keyboard.
*/
fun
hide
()
{
fun
hide
()
{
// Since the emoji keyboard is always behind the soft keyboard assume it's also dismissed
// when the emoji one is about to get close. Hence we should invoke our listener to update
// the UI as if the soft keyboard is hidden.
parentContainer
.
setVisible
(
false
)
parentContainer
.
setVisible
(
false
)
listener
?.
onEmojiKeyboardHidden
()
}
}
/**
* Whether the emoji keyboard is visible.
*
* @return <code>true</code> if opened.
*/
fun
isShown
()
=
parentContainer
.
visibility
==
View
.
VISIBLE
fun
isShown
()
=
parentContainer
.
visibility
==
View
.
VISIBLE
interface
OnEmojiClickCallback
{
/**
* Whether the emoji keyboard is collapsed.
*
* @return false if the emoji keyboard is visible and not obscured
*/
fun
isCollapsed
()
=
parentContainer
.
visibility
==
View
.
GONE
interface
EmojiKeyboardListener
{
/**
/**
* Callback
triggered
after an emoji is selected on the picker.
* Callback after an emoji is selected on the picker.
*
*
* @param emoji The selected emoji
* @param emoji The selected emoji
*/
*/
fun
onEmojiAdded
(
emoji
:
Emoji
)
fun
onEmojiAdded
(
emoji
:
Emoji
)
fun
onSoftKeyboardHidden
()
fun
onSoftKeyboardShown
()
fun
onEmojiKeyboardHidden
()
fun
onEmojiKeyboardShown
()
}
}
}
}
\ No newline at end of file
app/src/main/res/drawable/ic_keyboard_black_24
px
.xml
→
app/src/main/res/drawable/ic_keyboard_black_24
dp
.xml
View file @
18800044
File moved
app/src/main/res/layout/message_composer.xml
View file @
18800044
...
@@ -41,18 +41,18 @@
...
@@ -41,18 +41,18 @@
<ImageButton
<ImageButton
android:id=
"@+id/button_add_reaction"
android:id=
"@+id/button_add_reaction"
android:layout_width=
"
wrap_content
"
android:layout_width=
"
24dp
"
android:layout_height=
"
wrap_content
"
android:layout_height=
"
24dp
"
android:layout_marginEnd=
"16dp"
android:layout_marginEnd=
"16dp"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:background=
"?attr/selectableItemBackgroundBorderless"
android:contentDescription=
"@string/msg_content_description_show_attachment_options"
android:clickable=
"false"
android:clickable=
"false"
android:contentDescription=
"@string/msg_content_description_show_attachment_options"
android:src=
"@drawable/ic_reaction_24dp"
/>
android:src=
"@drawable/ic_reaction_24dp"
/>
<EditText
<
chat.rocket.android.widget.emoji.Composer
EditText
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=
"
24dp
"
android:layout_marginEnd=
"16dp"
android:layout_marginEnd=
"16dp"
android:layout_weight=
"1"
android:layout_weight=
"1"
android:background=
"@android:color/transparent"
android:background=
"@android:color/transparent"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment