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
6557738b
Commit
6557738b
authored
Sep 18, 2018
by
Leonardo Aramaki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement emoji shortnames autocompletion
parent
1912e21d
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
173 additions
and
47 deletions
+173
-47
EmojiSuggestionsAdapter.kt
...ocket/android/chatroom/adapter/EmojiSuggestionsAdapter.kt
+38
-0
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+25
-13
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+4
-0
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+20
-15
EmojiSuggestionUiModel.kt
...oid/chatroom/uimodel/suggestion/EmojiSuggestionUiModel.kt
+15
-0
suggestion_emoji_item.xml
app/src/main/res/layout/suggestion_emoji_item.xml
+48
-0
EmojiRepository.kt
...rc/main/java/chat/rocket/android/emoji/EmojiRepository.kt
+1
-1
SuggestionModel.kt
.../chat/rocket/android/suggestions/model/SuggestionModel.kt
+6
-3
SuggestionsAdapter.kt
.../chat/rocket/android/suggestions/ui/SuggestionsAdapter.kt
+14
-12
SuggestionsView.kt
...ava/chat/rocket/android/suggestions/ui/SuggestionsView.kt
+2
-3
No files found.
app/src/main/java/chat/rocket/android/chatroom/adapter/EmojiSuggestionsAdapter.kt
0 → 100644
View file @
6557738b
package
chat.rocket.android.chatroom.adapter
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.EmojiSuggestionsAdapter.EmojiSuggestionViewHolder
import
chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel
import
chat.rocket.android.suggestions.model.SuggestionModel
import
chat.rocket.android.suggestions.strategy.trie.TrieCompletionStrategy
import
chat.rocket.android.suggestions.ui.BaseSuggestionViewHolder
import
chat.rocket.android.suggestions.ui.SuggestionsAdapter
import
kotlinx.android.synthetic.main.suggestion_emoji_item.view.*
class
EmojiSuggestionsAdapter
:
SuggestionsAdapter
<
EmojiSuggestionViewHolder
>(
token
=
":"
,
completionStrategy
=
TrieCompletionStrategy
()
)
{
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
EmojiSuggestionViewHolder
{
val
inflater
=
LayoutInflater
.
from
(
parent
.
context
)
val
view
=
inflater
.
inflate
(
R
.
layout
.
suggestion_emoji_item
,
parent
,
false
)
return
EmojiSuggestionViewHolder
(
view
)
}
class
EmojiSuggestionViewHolder
(
view
:
View
)
:
BaseSuggestionViewHolder
(
view
)
{
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
item
as
EmojiSuggestionUiModel
with
(
itemView
)
{
text_emoji_shortname
.
text
=
":${item.text}"
setOnClickListener
{
itemClickListener
?.
onClick
(
item
)
}
}
}
}
}
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
6557738b
...
...
@@ -13,10 +13,12 @@ import chat.rocket.android.chatroom.uimodel.RoomUiModel
import
chat.rocket.android.chatroom.uimodel.UiModelMapper
import
chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import
chat.rocket.android.core.behaviours.showMessage
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.db.DatabaseManager
import
chat.rocket.android.emoji.EmojiRepository
import
chat.rocket.android.helper.MessageHelper
import
chat.rocket.android.helper.UserHelper
import
chat.rocket.android.infrastructure.LocalRepository
...
...
@@ -34,7 +36,6 @@ import chat.rocket.android.server.domain.useRealName
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.state
import
chat.rocket.android.util.extension.compressImageAndGetByteArray
import
chat.rocket.android.util.extension.compressImageAndGetInputStream
import
chat.rocket.android.util.extension.launchUI
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.retryIO
...
...
@@ -80,9 +81,7 @@ import kotlinx.coroutines.experimental.launch
import
kotlinx.coroutines.experimental.withContext
import
org.threeten.bp.Instant
import
timber.log.Timber
import
java.io.InputStream
import
java.util.*
import
java.util.zip.DeflaterInputStream
import
javax.inject.Inject
class
ChatRoomPresenter
@Inject
constructor
(
...
...
@@ -180,10 +179,10 @@ class ChatRoomPresenter @Inject constructor(
val
localMessages
=
messagesRepository
.
getByRoomId
(
chatRoomId
)
val
oldMessages
=
mapper
.
map
(
localMessages
,
RoomUiModel
(
roles
=
chatRoles
,
// FIXME: Why are we fixing isRoom attribute to true here?
isBroadcast
=
chatIsBroadcast
,
isRoom
=
true
)
roles
=
chatRoles
,
// FIXME: Why are we fixing isRoom attribute to true here?
isBroadcast
=
chatIsBroadcast
,
isRoom
=
true
)
)
val
lastSyncDate
=
messagesRepository
.
getLastSyncDate
(
chatRoomId
)
if
(
oldMessages
.
isNotEmpty
()
&&
lastSyncDate
!=
null
)
{
...
...
@@ -597,9 +596,9 @@ class ChatRoomPresenter @Inject constructor(
replyMarkdown
=
"[ ]($currentServer/$chatRoomType/$room?msg=$id) $mention "
,
quotedMessage
=
mapper
.
map
(
message
,
RoomUiModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
)
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
)
).
last
().
preview
?.
message
?:
""
)
}
...
...
@@ -868,7 +867,7 @@ class ChatRoomPresenter @Inject constructor(
}
it
.
chatRoom
.
name
==
name
||
it
.
chatRoom
.
fullname
==
name
}.
map
{
with
(
it
.
chatRoom
)
{
with
(
it
.
chatRoom
)
{
ChatRoom
(
id
=
id
,
subscriptionId
=
subscriptionId
,
...
...
@@ -1008,6 +1007,19 @@ class ChatRoomPresenter @Inject constructor(
}
}
fun
loadEmojis
()
{
launchUI
(
strategy
)
{
val
emojiSuggestionUiModels
=
EmojiRepository
.
getAll
().
map
{
EmojiSuggestionUiModel
(
text
=
it
.
shortname
.
replaceFirst
(
":"
,
""
),
pinned
=
false
,
searchList
=
listOf
(
it
.
shortname
)
)
}
view
.
populateEmojiSuggestions
(
emojis
=
emojiSuggestionUiModels
)
}
}
fun
runCommand
(
text
:
String
,
roomId
:
String
)
{
launchUI
(
strategy
)
{
try
{
...
...
@@ -1103,8 +1115,8 @@ class ChatRoomPresenter @Inject constructor(
launchUI
(
strategy
)
{
val
viewModelStreamedMessage
=
mapper
.
map
(
streamedMessage
,
RoomUiModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
,
isRoom
=
true
)
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
,
isRoom
=
true
)
)
val
roomMessages
=
messagesRepository
.
getByRoomId
(
streamedMessage
.
roomId
)
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
6557738b
...
...
@@ -3,6 +3,7 @@ package chat.rocket.android.chatroom.presentation
import
chat.rocket.android.chatroom.uimodel.BaseUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import
chat.rocket.android.core.behaviours.LoadingView
import
chat.rocket.android.core.behaviours.MessageView
...
...
@@ -127,6 +128,9 @@ interface ChatRoomView : LoadingView, MessageView {
fun
populatePeopleSuggestions
(
members
:
List
<
PeopleSuggestionUiModel
>)
fun
populateRoomSuggestions
(
chatRooms
:
List
<
ChatRoomSuggestionUiModel
>)
fun
populateEmojiSuggestions
(
emojis
:
List
<
EmojiSuggestionUiModel
>)
/**
* This user has joined the chat callback.
*
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
6557738b
...
...
@@ -37,6 +37,7 @@ import chat.rocket.android.analytics.AnalyticsManager
import
chat.rocket.android.analytics.event.ScreenViewEvent
import
chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import
chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter
import
chat.rocket.android.chatroom.adapter.EmojiSuggestionsAdapter
import
chat.rocket.android.chatroom.adapter.PEOPLE
import
chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter
import
chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter
...
...
@@ -47,6 +48,7 @@ import chat.rocket.android.chatroom.uimodel.BaseUiModel
import
chat.rocket.android.chatroom.uimodel.MessageUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.EmojiSuggestionUiModel
import
chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import
chat.rocket.android.draw.main.ui.DRAWING_BYTE_ARRAY_EXTRA_DATA
import
chat.rocket.android.draw.main.ui.DrawingActivity
...
...
@@ -563,11 +565,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
override
fun
showReplyingAction
(
username
:
String
,
replyMarkdown
:
String
,
quotedMessage
:
String
)
{
override
fun
showReplyingAction
(
username
:
String
,
replyMarkdown
:
String
,
quotedMessage
:
String
)
{
ui
{
citation
=
replyMarkdown
actionSnackbar
.
title
=
username
...
...
@@ -617,6 +615,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
override
fun
populateEmojiSuggestions
(
emojis
:
List
<
EmojiSuggestionUiModel
>)
{
ui
{
suggestions_view
.
addItems
(
":"
,
emojis
)
}
}
override
fun
copyToClipboard
(
message
:
String
)
{
ui
{
val
clipboard
=
it
.
getSystemService
(
Context
.
CLIPBOARD_SERVICE
)
as
ClipboardManager
...
...
@@ -776,10 +780,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_show_attachment_options
.
alpha
=
1f
button_show_attachment_options
.
isVisible
=
true
activity
?.
supportFragmentManager
?.
addOnBackStackChangedListener
{
println
(
"attach"
)
}
activity
?.
supportFragmentManager
?.
registerFragmentLifecycleCallbacks
(
object
:
FragmentManager
.
FragmentLifecycleCallbacks
()
{
override
fun
onFragmentAttached
(
...
...
@@ -843,16 +843,16 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
},
400
)
}
button_add_reaction
.
setOnClickListener
{
view
->
button_add_reaction
.
setOnClickListener
{
_
->
openEmojiKeyboardPopup
()
}
button_drawing
.
setOnClickListener
{
activity
?.
let
{
if
(!
ImageHelper
.
canWriteToExternalStorage
(
it
))
{
ImageHelper
.
checkWritingPermission
(
it
)
activity
?.
let
{
fragmentActivity
->
if
(!
ImageHelper
.
canWriteToExternalStorage
(
fragmentActivity
))
{
ImageHelper
.
checkWritingPermission
(
fragmentActivity
)
}
else
{
val
intent
=
Intent
(
it
,
DrawingActivity
::
class
.
java
)
val
intent
=
Intent
(
fragmentActivity
,
DrawingActivity
::
class
.
java
)
startActivityForResult
(
intent
,
REQUEST_CODE_FOR_DRAW
)
}
}
...
...
@@ -870,6 +870,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
.
addTokenAdapter
(
PeopleSuggestionsAdapter
(
context
!!
))
.
addTokenAdapter
(
CommandSuggestionsAdapter
())
.
addTokenAdapter
(
RoomSuggestionsAdapter
())
.
addTokenAdapter
(
EmojiSuggestionsAdapter
())
.
addSuggestionProviderAction
(
"@"
)
{
query
->
if
(
query
.
isNotEmpty
())
{
presenter
.
spotlight
(
query
,
PEOPLE
,
true
)
...
...
@@ -880,10 +881,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
presenter
.
loadChatRooms
()
}
}
.
addSuggestionProviderAction
(
"/"
)
{
_
->
.
addSuggestionProviderAction
(
"/"
)
{
presenter
.
loadCommands
()
}
.
addSuggestionProviderAction
(
":"
)
{
presenter
.
loadEmojis
()
}
presenter
.
loadEmojis
()
presenter
.
loadCommands
()
}
...
...
app/src/main/java/chat/rocket/android/chatroom/uimodel/suggestion/EmojiSuggestionUiModel.kt
0 → 100644
View file @
6557738b
package
chat.rocket.android.chatroom.uimodel.suggestion
import
chat.rocket.android.suggestions.model.SuggestionModel
import
chat.rocket.common.model.UserStatus
class
EmojiSuggestionUiModel
(
text
:
String
,
pinned
:
Boolean
=
false
,
searchList
:
List
<
String
>
)
:
SuggestionModel
(
text
,
searchList
,
pinned
)
{
override
fun
toString
():
String
{
return
"EmojiSuggestionUiModel(text='$text', searchList='$searchList', pinned=$pinned)"
}
}
app/src/main/res/layout/suggestion_emoji_item.xml
0 → 100644
View file @
6557738b
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:layout_marginTop=
"2dp"
android:layout_marginEnd=
"2dp"
android:layout_marginBottom=
"2dp"
android:background=
"@color/suggestion_background_color"
>
<ViewFlipper
android:id=
"@+id/view_flipper_emoji"
android:layout_width=
"24dp"
android:layout_height=
"24dp"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
>
<TextView
android:id=
"@+id/text_emoji"
android:layout_width=
"24dp"
android:layout_height=
"24dp"
tools:text=
":)"
/>
<ImageView
android:id=
"@+id/image_emoji"
android:layout_width=
"24dp"
android:layout_height=
"24dp"
tools:src=
"@tools:sample/avatars"
/>
</ViewFlipper>
<TextView
android:id=
"@+id/text_emoji_shortname"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"5dp"
android:maxLines=
"1"
android:textColor=
"@color/colorBlack"
android:textSize=
"16sp"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintStart_toEndOf=
"@+id/view_flipper_emoji"
app:layout_constraintTop_toTopOf=
"parent"
tools:text=
":grinning:"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
emoji/src/main/java/chat/rocket/android/emoji/EmojiRepository.kt
View file @
6557738b
...
...
@@ -146,7 +146,7 @@ object EmojiRepository {
*
* @return All emojis for all categories.
*/
internal
suspend
fun
getAll
():
List
<
Emoji
>
=
withContext
(
CommonPool
)
{
suspend
fun
getAll
():
List
<
Emoji
>
=
withContext
(
CommonPool
)
{
return
@withContext
db
.
emojiDao
().
loadAllEmojis
()
}
...
...
suggestions/src/main/java/chat/rocket/android/suggestions/model/SuggestionModel.kt
View file @
6557738b
package
chat.rocket.android.suggestions.model
abstract
class
SuggestionModel
(
val
text
:
String
,
// This is the text key for searches, must be unique.
val
searchList
:
List
<
String
>
=
emptyList
(),
// Where to search for matches.
val
pinned
:
Boolean
=
false
/* If pinned item will have priority to show */
)
{
abstract
class
SuggestionModel
(
val
text
:
String
,
// This is the text key for searches, must be unique.
val
searchList
:
List
<
String
>
=
emptyList
(),
// Where to search for matches.
val
pinned
:
Boolean
=
false
/* If pinned item will have priority to show */
)
{
override
fun
equals
(
other
:
Any
?):
Boolean
{
if
(
this
===
other
)
return
true
if
(
other
!
is
SuggestionModel
)
return
false
...
...
suggestions/src/main/java/chat/rocket/android/suggestions/ui/SuggestionsAdapter.kt
View file @
6557738b
...
...
@@ -10,17 +10,8 @@ import kotlin.properties.Delegates
abstract
class
SuggestionsAdapter
<
VH
:
BaseSuggestionViewHolder
>(
val
token
:
String
,
val
constraint
:
Int
=
CONSTRAINT_UNBOUND
,
completionStrategy
:
CompletionStrategy
?
=
null
,
threshold
:
Int
=
MAX_RESULT_COUNT
)
:
RecyclerView
.
Adapter
<
VH
>()
{
companion
object
{
// Any number of results.
const
val
RESULT_COUNT_UNLIMITED
=
-
1
// Trigger suggestions only if on the line start.
const
val
CONSTRAINT_BOUND_TO_START
=
0
// Trigger suggestions from anywhere.
const
val
CONSTRAINT_UNBOUND
=
1
// Maximum number of results to display by default.
private
const
val
MAX_RESULT_COUNT
=
5
}
private
var
itemType
:
Type
?
=
null
private
var
itemClickListener
:
ItemClickListener
?
=
null
...
...
@@ -30,7 +21,7 @@ abstract class SuggestionsAdapter<VH : BaseSuggestionViewHolder>(
// Maximum number of results/suggestions to display.
private
var
resultsThreshold
:
Int
=
if
(
threshold
>
0
)
threshold
else
RESULT_COUNT_UNLIMITED
// The strategy used for suggesting completions.
private
val
strategy
:
CompletionStrategy
=
StringMatchingCompletionStrategy
(
resultsThreshold
)
private
val
strategy
:
CompletionStrategy
=
completionStrategy
?:
StringMatchingCompletionStrategy
(
resultsThreshold
)
// Current input term to look up for suggestions.
private
var
currentTerm
:
String
by
Delegates
.
observable
(
""
)
{
_
,
_
,
newTerm
->
val
items
=
strategy
.
autocompleteItems
(
newTerm
)
...
...
@@ -105,4 +96,15 @@ abstract class SuggestionsAdapter<VH : BaseSuggestionViewHolder>(
interface
ItemClickListener
{
fun
onClick
(
item
:
SuggestionModel
)
}
}
\ No newline at end of file
companion
object
{
// Any number of results.
const
val
RESULT_COUNT_UNLIMITED
=
-
1
// Trigger suggestions only if on the line start.
const
val
CONSTRAINT_BOUND_TO_START
=
0
// Trigger suggestions from anywhere.
const
val
CONSTRAINT_UNBOUND
=
1
// Maximum number of results to display by default.
private
const
val
MAX_RESULT_COUNT
=
5
}
}
suggestions/src/main/java/chat/rocket/android/suggestions/ui/SuggestionsView.kt
View file @
6557738b
...
...
@@ -149,15 +149,14 @@ class SuggestionsView : FrameLayout, TextWatcher {
}
fun
addTokenAdapter
(
adapter
:
SuggestionsAdapter
<
*
>):
SuggestionsView
{
adaptersByToken
.
getOrPut
(
adapter
.
token
,
{
adapter
})
adaptersByToken
.
getOrPut
(
adapter
.
token
)
{
adapter
}
return
this
}
fun
addItems
(
token
:
String
,
list
:
List
<
SuggestionModel
>):
SuggestionsView
{
if
(
list
.
isNotEmpty
())
{
val
adapter
=
adapter
(
token
)
localProvidersByToken
.
getOrPut
(
token
,
{
hashMapOf
()
})
.
put
(
adapter
.
term
(),
list
)
localProvidersByToken
.
getOrPut
(
token
)
{
hashMapOf
()
}.
put
(
adapter
.
term
(),
list
)
if
(
completionOffset
.
get
()
>
NO_STATE_INDEX
&&
adapter
.
itemCount
==
0
)
expand
()
adapter
.
addItems
(
list
)
}
...
...
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