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
e89bc7cc
Commit
e89bc7cc
authored
Sep 27, 2018
by
Filipe de Lima Brito
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'v3.0.0' into new/redesign-authentication-views
parents
d85b30af
123d05d2
Changes
60
Hide whitespace changes
Inline
Side-by-side
Showing
60 changed files
with
764 additions
and
248 deletions
+764
-248
build.gradle
app/build.gradle
+3
-2
BaseViewHolder.kt
...va/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt
+3
-1
CommandSuggestionsAdapter.kt
...ket/android/chatroom/adapter/CommandSuggestionsAdapter.kt
+3
-3
EmojiSuggestionsAdapter.kt
...ocket/android/chatroom/adapter/EmojiSuggestionsAdapter.kt
+53
-0
MessageAttachmentViewHolder.kt
...t/android/chatroom/adapter/MessageAttachmentViewHolder.kt
+77
-3
MessageReactionsAdapter.kt
...ocket/android/chatroom/adapter/MessageReactionsAdapter.kt
+38
-19
MessageReplyViewHolder.kt
...rocket/android/chatroom/adapter/MessageReplyViewHolder.kt
+1
-3
PeopleSuggestionsAdapter.kt
...cket/android/chatroom/adapter/PeopleSuggestionsAdapter.kt
+3
-3
RoomSuggestionsAdapter.kt
...rocket/android/chatroom/adapter/RoomSuggestionsAdapter.kt
+3
-3
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+62
-19
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+4
-0
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+44
-32
StrikethroughDelimiterProcessor.kt
...et/android/chatroom/ui/StrikethroughDelimiterProcessor.kt
+45
-0
ReactionUiModel.kt
...a/chat/rocket/android/chatroom/uimodel/ReactionUiModel.kt
+2
-1
UiModelMapper.kt
...ava/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
+5
-1
ChatRoomSuggestionUiModel.kt
.../chatroom/uimodel/suggestion/ChatRoomSuggestionUiModel.kt
+1
-1
CommandSuggestionUiModel.kt
...d/chatroom/uimodel/suggestion/CommandSuggestionUiModel.kt
+1
-1
EmojiSuggestionUiModel.kt
...oid/chatroom/uimodel/suggestion/EmojiSuggestionUiModel.kt
+17
-0
PeopleSuggestionUiModel.kt
...id/chatroom/uimodel/suggestion/PeopleSuggestionUiModel.kt
+1
-1
KeyboardHelper.kt
...rc/main/java/chat/rocket/android/helper/KeyboardHelper.kt
+2
-1
MessageParser.kt
...src/main/java/chat/rocket/android/helper/MessageParser.kt
+62
-23
LocalRepository.kt
...ava/chat/rocket/android/infrastructure/LocalRepository.kt
+1
-0
rounded_background.xml
app/src/main/res/drawable/rounded_background.xml
+2
-2
fragment_chat_room.xml
app/src/main/res/layout/fragment_chat_room.xml
+1
-1
item_message_attachment.xml
app/src/main/res/layout/item_message_attachment.xml
+24
-12
item_reaction.xml
app/src/main/res/layout/item_reaction.xml
+39
-21
suggestion_emoji_item.xml
app/src/main/res/layout/suggestion_emoji_item.xml
+49
-0
strings.xml
app/src/main/res/values-de/strings.xml
+4
-0
strings.xml
app/src/main/res/values-es/strings.xml
+4
-0
strings.xml
app/src/main/res/values-fr/strings.xml
+4
-0
strings.xml
app/src/main/res/values-hi-rIN/strings.xml
+4
-0
strings.xml
app/src/main/res/values-ja/strings.xml
+4
-0
strings.xml
app/src/main/res/values-pt-rBR/strings.xml
+4
-2
strings.xml
app/src/main/res/values-ru-rRU/strings.xml
+3
-0
strings.xml
app/src/main/res/values-uk/strings.xml
+4
-0
dimens.xml
app/src/main/res/values/dimens.xml
+2
-4
strings.xml
app/src/main/res/values/strings.xml
+2
-0
build.gradle
build.gradle
+1
-1
dependencies.gradle
dependencies.gradle
+1
-1
EmojiKeyboardPopup.kt
...main/java/chat/rocket/android/emoji/EmojiKeyboardPopup.kt
+7
-4
EmojiRepository.kt
...rc/main/java/chat/rocket/android/emoji/EmojiRepository.kt
+2
-2
settings.gradle
settings.gradle
+1
-1
.gitignore
suggestions/.gitignore
+1
-0
build.gradle
suggestions/build.gradle
+34
-0
proguard-rules.pro
suggestions/proguard-rules.pro
+21
-0
AndroidManifest.xml
suggestions/src/main/AndroidManifest.xml
+2
-0
SuggestionModel.kt
.../chat/rocket/android/suggestions/model/SuggestionModel.kt
+21
-0
LocalSuggestionProvider.kt
...android/suggestions/repository/LocalSuggestionProvider.kt
+1
-1
CompletionStrategy.kt
...rocket/android/suggestions/strategy/CompletionStrategy.kt
+3
-3
StringMatchingCompletionStrategy.kt
...stions/strategy/regex/StringMatchingCompletionStrategy.kt
+5
-5
TrieCompletionStrategy.kt
...droid/suggestions/strategy/trie/TrieCompletionStrategy.kt
+8
-7
Trie.kt
...hat/rocket/android/suggestions/strategy/trie/data/Trie.kt
+5
-8
TrieNode.kt
...rocket/android/suggestions/strategy/trie/data/TrieNode.kt
+15
-13
BaseSuggestionViewHolder.kt
...rocket/android/suggestions/ui/BaseSuggestionViewHolder.kt
+4
-4
PopupRecyclerView.kt
...a/chat/rocket/android/suggestions/ui/PopupRecyclerView.kt
+3
-3
SuggestionsAdapter.kt
.../chat/rocket/android/suggestions/ui/SuggestionsAdapter.kt
+22
-19
SuggestionsView.kt
...ava/chat/rocket/android/suggestions/ui/SuggestionsView.kt
+17
-16
suggestions_menu_decorator.xml
...ions/src/main/res/drawable/suggestions_menu_decorator.xml
+1
-1
dimens.xml
suggestions/src/main/res/values/dimens.xml
+5
-0
strings.xml
suggestions/src/main/res/values/strings.xml
+3
-0
No files found.
app/build.gradle
View file @
e89bc7cc
...
...
@@ -16,8 +16,8 @@ android {
applicationId
"chat.rocket.android"
minSdkVersion
versions
.
minSdk
targetSdkVersion
versions
.
targetSdk
versionCode
204
2
versionName
"2.6.
0
"
versionCode
204
3
versionName
"2.6.
1
"
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled
true
...
...
@@ -93,6 +93,7 @@ dependencies {
implementation
project
(
':draw'
)
implementation
project
(
':util'
)
implementation
project
(
':core'
)
implementation
project
(
':suggestions'
)
implementation
libraries
.
kotlin
implementation
libraries
.
coroutines
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt
View file @
e89bc7cc
...
...
@@ -65,7 +65,9 @@ abstract class BaseViewHolder<T : BaseUiModel<*>>(
val
manager
=
FlexboxLayoutManager
(
context
,
FlexDirection
.
ROW
)
recyclerView
.
layoutManager
=
manager
recyclerView
.
adapter
=
adapter
adapter
.
addReactions
(
it
.
reactions
.
filterNot
{
it
.
unicode
.
startsWith
(
":"
)
})
adapter
.
addReactions
(
it
.
reactions
.
filterNot
{
reactionUiModel
->
reactionUiModel
.
unicode
.
startsWith
(
":"
)
&&
reactionUiModel
.
url
.
isNullOrEmpty
()
})
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/CommandSuggestionsAdapter.kt
View file @
e89bc7cc
...
...
@@ -7,9 +7,9 @@ import android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter.CommandSuggestionsViewHolder
import
chat.rocket.android.chatroom.uimodel.suggestion.CommandSuggestionUiModel
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
widget.autocompletion
.ui.BaseSuggestionViewHolder
import
chat.rocket.android.
widget.autocompletion
.ui.SuggestionsAdapter
import
chat.rocket.android.
suggestions
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.ui.BaseSuggestionViewHolder
import
chat.rocket.android.
suggestions
.ui.SuggestionsAdapter
class
CommandSuggestionsAdapter
:
SuggestionsAdapter
<
CommandSuggestionsViewHolder
>(
token
=
"/"
,
constraint
=
CONSTRAINT_BOUND_TO_START
,
threshold
=
RESULT_COUNT_UNLIMITED
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/EmojiSuggestionsAdapter.kt
0 → 100644
View file @
e89bc7cc
package
chat.rocket.android.chatroom.adapter
import
android.annotation.SuppressLint
import
android.text.SpannableStringBuilder
import
android.text.style.ImageSpan
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.emoji.EmojiParser
import
chat.rocket.android.emoji.internal.isCustom
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
com.bumptech.glide.Glide
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
)
{
@SuppressLint
(
"SetTextI18n"
)
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
item
as
EmojiSuggestionUiModel
with
(
itemView
)
{
text_emoji_shortname
.
text
=
":${item.text}"
if
(
item
.
emoji
.
isCustom
())
{
view_flipper_emoji
.
displayedChild
=
1
val
sp
=
SpannableStringBuilder
().
append
(
item
.
emoji
.
shortname
)
Glide
.
with
(
context
).
asDrawable
().
load
(
item
.
emoji
.
url
).
into
(
image_emoji
)
}
else
{
text_emoji
.
text
=
EmojiParser
.
parse
(
context
,
item
.
emoji
.
unicode
)
view_flipper_emoji
.
displayedChild
=
0
}
setOnClickListener
{
itemClickListener
?.
onClick
(
item
)
}
}
}
}
}
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageAttachmentViewHolder.kt
View file @
e89bc7cc
package
chat.rocket.android.chatroom.adapter
import
android.animation.ValueAnimator
import
android.text.method.LinkMovementMethod
import
android.view.View
import
android.view.animation.LinearInterpolator
import
androidx.core.view.isVisible
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.uimodel.MessageAttachmentUiModel
import
chat.rocket.android.emoji.EmojiReactionListener
import
kotlinx.android.synthetic.main.item_message_attachment.view.*
class
MessageAttachmentViewHolder
(
itemView
:
View
,
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
itemView
:
View
,
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
MessageAttachmentUiModel
>(
itemView
,
listener
,
reactionListener
)
{
private
var
expanded
=
true
init
{
with
(
itemView
)
{
setupActionMenu
(
attachment_container
)
...
...
@@ -21,9 +27,77 @@ class MessageAttachmentViewHolder(
override
fun
bindViews
(
data
:
MessageAttachmentUiModel
)
{
with
(
itemView
)
{
val
collapsedHeight
=
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
quote_collapsed_height
)
val
viewMore
=
context
.
getString
(
R
.
string
.
msg_view_more
)
val
viewLess
=
context
.
getString
(
R
.
string
.
msg_view_less
)
text_message_time
.
text
=
data
.
time
text_sender
.
text
=
data
.
senderName
text_content
.
text
=
data
.
content
text_view_more
.
text
=
viewLess
text_content
.
addOnLayoutChangeListener
(
object
:
View
.
OnLayoutChangeListener
{
override
fun
onLayoutChange
(
v
:
View
,
left
:
Int
,
top
:
Int
,
right
:
Int
,
bottom
:
Int
,
oldLeft
:
Int
,
oldTop
:
Int
,
oldRight
:
Int
,
oldBottom
:
Int
)
{
val
textMeasuredHeight
=
bottom
-
top
if
(
collapsedHeight
>=
textMeasuredHeight
)
{
text_view_more
.
isVisible
=
false
text_content
.
removeOnLayoutChangeListener
(
this
)
return
}
text_view_more
.
isVisible
=
true
val
expandAnimation
=
ValueAnimator
.
ofInt
(
collapsedHeight
,
textMeasuredHeight
)
.
setDuration
(
300
)
expandAnimation
.
interpolator
=
LinearInterpolator
()
val
collapseAnimation
=
ValueAnimator
.
ofInt
(
textMeasuredHeight
,
collapsedHeight
)
.
setDuration
(
300
)
collapseAnimation
.
interpolator
=
LinearInterpolator
()
val
lp
=
text_content
.
layoutParams
expandAnimation
.
addUpdateListener
{
val
value
=
it
.
animatedValue
as
Int
lp
.
height
=
value
text_content
.
layoutParams
=
lp
expanded
=
if
(
value
==
textMeasuredHeight
)
{
text_view_more
.
text
=
viewLess
true
}
else
{
text_view_more
.
text
=
viewMore
false
}
}
collapseAnimation
.
addUpdateListener
{
val
value
=
it
.
animatedValue
as
Int
lp
.
height
=
value
text_content
.
layoutParams
=
lp
expanded
=
if
(
value
==
textMeasuredHeight
)
{
text_view_more
.
text
=
viewLess
true
}
else
{
text_view_more
.
text
=
viewMore
false
}
}
text_view_more
.
setOnClickListener
{
if
(
expandAnimation
.
isRunning
)
return
@setOnClickListener
if
(
expanded
)
{
collapseAnimation
.
start
()
}
else
{
expandAnimation
.
start
()
}
}
text_content
.
removeOnLayoutChangeListener
(
this
)
}
})
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageReactionsAdapter.kt
View file @
e89bc7cc
...
...
@@ -5,6 +5,7 @@ import android.view.View
import
android.view.ViewGroup
import
android.widget.ImageView
import
android.widget.TextView
import
androidx.core.content.ContextCompat
import
androidx.recyclerview.widget.RecyclerView
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.uimodel.ReactionUiModel
...
...
@@ -13,15 +14,13 @@ 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.emoji.internal.GlideApp
import
chat.rocket.android.infrastructure.LocalRepository
import
kotlinx.android.synthetic.main.item_reaction.view.*
import
java.util.concurrent.CopyOnWriteArrayList
import
javax.inject.Inject
class
MessageReactionsAdapter
:
RecyclerView
.
Adapter
<
RecyclerView
.
ViewHolder
>()
{
companion
object
{
private
const
val
REACTION_VIEW_TYPE
=
0
private
const
val
ADD_REACTION_VIEW_TYPE
=
1
}
private
val
reactions
=
CopyOnWriteArrayList
<
ReactionUiModel
>()
var
listener
:
EmojiReactionListener
?
=
null
...
...
@@ -74,9 +73,11 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
fun
contains
(
reactionShortname
:
String
)
=
reactions
.
firstOrNull
{
it
.
shortname
==
reactionShortname
}
!=
null
class
SingleReactionViewHolder
(
view
:
View
,
private
val
listener
:
EmojiReactionListener
?)
:
RecyclerView
.
ViewHolder
(
view
),
View
.
OnClickListener
{
class
SingleReactionViewHolder
(
view
:
View
,
private
val
listener
:
EmojiReactionListener
?
)
:
RecyclerView
.
ViewHolder
(
view
),
View
.
OnClickListener
{
@Inject
lateinit
var
localRepository
:
LocalRepository
@Volatile
...
...
@@ -95,23 +96,33 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
clickHandled
=
false
this
.
reaction
=
reaction
with
(
itemView
)
{
val
emojiTextView
=
findViewById
<
TextView
>(
R
.
id
.
text_emoji
)
val
countTextView
=
findViewById
<
TextView
>(
R
.
id
.
text_count
)
emojiTextView
.
text
=
reaction
.
unicode
countTextView
.
text
=
reaction
.
count
.
toString
()
if
(
reaction
.
url
.
isNullOrEmpty
())
{
text_emoji
.
text
=
reaction
.
unicode
view_flipper_reaction
.
displayedChild
=
0
}
else
{
view_flipper_reaction
.
displayedChild
=
1
val
glideRequest
=
if
(
reaction
.
url
!!
.
endsWith
(
"gif"
,
true
))
{
GlideApp
.
with
(
context
).
asGif
()
}
else
{
GlideApp
.
with
(
context
).
asBitmap
()
}
glideRequest
.
load
(
reaction
.
url
).
into
(
image_emoji
)
}
text_count
.
text
=
reaction
.
count
.
toString
()
val
myself
=
localRepository
.
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
if
(
reaction
.
usernames
.
contains
(
myself
))
{
val
context
=
itemView
.
context
val
resources
=
context
.
resources
countTextView
.
setTextColor
(
resources
.
getColor
(
R
.
color
.
colorAccent
))
text_count
.
setTextColor
(
ContextCompat
.
getColor
(
context
,
R
.
color
.
colorAccent
))
}
emojiTextView
.
setOnClickListener
(
this
@SingleReactionViewHolder
)
countTextView
.
setOnClickListener
(
this
@SingleReactionViewHolder
)
view_flipper_reaction
.
setOnClickListener
(
this
@SingleReactionViewHolder
)
text_count
.
setOnClickListener
(
this
@SingleReactionViewHolder
)
}
}
override
fun
onClick
(
v
:
View
?
)
{
override
fun
onClick
(
v
:
View
)
{
synchronized
(
this
)
{
if
(!
clickHandled
)
{
clickHandled
=
true
...
...
@@ -121,8 +132,11 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
}
}
class
AddReactionViewHolder
(
view
:
View
,
private
val
listener
:
EmojiReactionListener
?)
:
RecyclerView
.
ViewHolder
(
view
)
{
class
AddReactionViewHolder
(
view
:
View
,
private
val
listener
:
EmojiReactionListener
?
)
:
RecyclerView
.
ViewHolder
(
view
)
{
fun
bind
(
messageId
:
String
)
{
itemView
as
ImageView
itemView
.
setOnClickListener
{
...
...
@@ -136,4 +150,9 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
}
}
}
}
\ No newline at end of file
companion
object
{
private
const
val
REACTION_VIEW_TYPE
=
0
private
const
val
ADD_REACTION_VIEW_TYPE
=
1
}
}
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageReplyViewHolder.kt
View file @
e89bc7cc
...
...
@@ -13,9 +13,7 @@ class MessageReplyViewHolder(
)
:
BaseViewHolder
<
MessageReplyUiModel
>(
itemView
,
listener
,
reactionListener
)
{
init
{
with
(
itemView
)
{
setupActionMenu
(
itemView
)
}
setupActionMenu
(
itemView
)
}
override
fun
bindViews
(
data
:
MessageReplyUiModel
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/PeopleSuggestionsAdapter.kt
View file @
e89bc7cc
...
...
@@ -11,9 +11,9 @@ import chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter.PeopleSuggestionViewHolder
import
chat.rocket.android.chatroom.uimodel.suggestion.PeopleSuggestionUiModel
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
widget.autocompletion
.ui.BaseSuggestionViewHolder
import
chat.rocket.android.
widget.autocompletion
.ui.SuggestionsAdapter
import
chat.rocket.android.
suggestions
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.ui.BaseSuggestionViewHolder
import
chat.rocket.android.
suggestions
.ui.SuggestionsAdapter
import
com.facebook.drawee.view.SimpleDraweeView
class
PeopleSuggestionsAdapter
(
context
:
Context
)
:
SuggestionsAdapter
<
PeopleSuggestionViewHolder
>(
"@"
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/RoomSuggestionsAdapter.kt
View file @
e89bc7cc
...
...
@@ -7,9 +7,9 @@ import android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter.RoomSuggestionsViewHolder
import
chat.rocket.android.chatroom.uimodel.suggestion.ChatRoomSuggestionUiModel
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
widget.autocompletion
.ui.BaseSuggestionViewHolder
import
chat.rocket.android.
widget.autocompletion
.ui.SuggestionsAdapter
import
chat.rocket.android.
suggestions
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.ui.BaseSuggestionViewHolder
import
chat.rocket.android.
suggestions
.ui.SuggestionsAdapter
class
RoomSuggestionsAdapter
:
SuggestionsAdapter
<
RoomSuggestionsViewHolder
>(
"#"
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
e89bc7cc
...
...
@@ -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
)
{
...
...
@@ -419,11 +418,12 @@ class ChatRoomPresenter @Inject constructor(
}
}
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error uploading file"
)
when
(
ex
)
{
is
RocketChatException
->
view
.
showMessage
(
ex
)
else
->
view
.
showGenericErrorMessage
()
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
d
(
ex
)
ex
.
message
?.
let
{
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
}
finally
{
view
.
hideLoading
()
...
...
@@ -597,9 +597,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 +868,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 +1008,20 @@ class ChatRoomPresenter @Inject constructor(
}
}
fun
loadEmojis
()
{
launchUI
(
strategy
)
{
val
emojiSuggestionUiModels
=
EmojiRepository
.
getAll
().
map
{
EmojiSuggestionUiModel
(
text
=
it
.
shortname
.
replaceFirst
(
":"
,
""
),
pinned
=
false
,
emoji
=
it
,
searchList
=
listOf
(
it
.
shortname
)
)
}
view
.
populateEmojiSuggestions
(
emojis
=
emojiSuggestionUiModels
)
}
}
fun
runCommand
(
text
:
String
,
roomId
:
String
)
{
launchUI
(
strategy
)
{
try
{
...
...
@@ -1103,8 +1117,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
)
...
...
@@ -1126,4 +1140,33 @@ class ChatRoomPresenter @Inject constructor(
navigator
.
toMessageInformation
(
messageId
=
messageId
)
}
}
}
\ No newline at end of file
/**
* Save unfinished message, when user left chat room without sending a message. It also clears
* saved message from local repository when unfinishedMessage is blank.
*
* @param chatRoomId Chat room Id.
* @param unfinishedMessage The unfinished message to save.
*/
fun
saveUnfinishedMessage
(
chatRoomId
:
String
,
unfinishedMessage
:
String
)
{
val
key
=
"${currentServer}_${LocalRepository.UNFINISHED_MSG_KEY}$chatRoomId"
if
(
unfinishedMessage
.
isNotBlank
())
{
localRepository
.
save
(
key
,
unfinishedMessage
)
}
else
{
localRepository
.
clear
(
key
)
}
}
/**
* Get unfinished message from local repository, when user left chat room without
* sending a message and now the user is back.
*
* @param chatRoomId Chat room Id.
*
* @return Returns the unfinished message.
*/
fun
getUnfinishedMessage
(
chatRoomId
:
String
):
String
{
val
key
=
"${currentServer}_${LocalRepository.UNFINISHED_MSG_KEY}$chatRoomId"
return
localRepository
.
get
(
key
)
?:
""
}
}
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
e89bc7cc
...
...
@@ -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 @
e89bc7cc
...
...
@@ -6,13 +6,11 @@ import android.content.ClipData
import
android.content.ClipboardManager
import
android.content.Context
import
android.content.Intent
import
android.content.res.Configuration
import
android.graphics.drawable.Drawable
import
android.os.Bundle
import
android.os.Handler
import
android.os.SystemClock
import
android.text.Spannable
import
android.text.SpannableStringBuilder
import
android.text.style.ImageSpan
import
android.view.KeyEvent
import
android.view.LayoutInflater
import
android.view.Menu
...
...
@@ -37,6 +35,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 +46,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
...
...
@@ -63,7 +63,6 @@ import chat.rocket.android.helper.ImageHelper
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.util.extension.asObservable
import
chat.rocket.android.util.extension.launchUI
import
chat.rocket.android.util.extensions.circularRevealOrUnreveal
import
chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeOut
...
...
@@ -76,8 +75,6 @@ import chat.rocket.android.util.extensions.ui
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.model.ChatRoom
import
com.bumptech.glide.load.resource.gif.GifDrawable
import
dagger.android.support.AndroidSupportInjection
import
io.reactivex.Observable
import
io.reactivex.disposables.CompositeDisposable
...
...
@@ -86,8 +83,6 @@ import kotlinx.android.synthetic.main.fragment_chat_room.*
import
kotlinx.android.synthetic.main.message_attachment_options.*
import
kotlinx.android.synthetic.main.message_composer.*
import
kotlinx.android.synthetic.main.message_list.*
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.launch
import
java.util.concurrent.TimeUnit
import
java.util.concurrent.atomic.AtomicInteger
import
javax.inject.Inject
...
...
@@ -258,6 +253,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
recycler_view
.
removeOnLayoutChangeListener
(
layoutChangeListener
)
presenter
.
disconnect
()
presenter
.
saveUnfinishedMessage
(
chatRoomId
,
text_message
.
text
.
toString
())
handler
.
removeCallbacksAndMessages
(
null
)
unsubscribeComposeTextMessage
()
...
...
@@ -334,7 +330,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
val
currentDayMarkerText
=
msgModel
.
currentDayMarkerText
val
previousDayMarkerText
=
prevMsgModel
.
currentDayMarkerText
println
(
"$previousDayMarkerText then $currentDayMarkerText"
)
if
(
previousDayMarkerText
!=
currentDayMarkerText
)
{
prevMsgModel
.
showDayMarker
=
true
}
...
...
@@ -477,15 +472,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
ui
{
when
(
usernameList
.
size
)
{
1
->
text_typing_status
.
text
=
SpannableStringBuilder
()
.
bold
{
append
(
usernameList
[
0
])
}
.
append
(
getString
(
R
.
string
.
msg_is_typing
))
SpannableStringBuilder
()
.
bold
{
append
(
usernameList
[
0
])
}
.
append
(
getString
(
R
.
string
.
msg_is_typing
))
2
->
text_typing_status
.
text
=
SpannableStringBuilder
()
.
bold
{
append
(
usernameList
[
0
])
}
.
append
(
getString
(
R
.
string
.
msg_and
))
.
bold
{
append
(
usernameList
[
1
])
}
.
append
(
getString
(
R
.
string
.
msg_are_typing
))
SpannableStringBuilder
()
.
bold
{
append
(
usernameList
[
0
])
}
.
append
(
getString
(
R
.
string
.
msg_and
))
.
bold
{
append
(
usernameList
[
1
])
}
.
append
(
getString
(
R
.
string
.
msg_are_typing
))
else
->
text_typing_status
.
text
=
getString
(
R
.
string
.
msg_several_users_are_typing
)
}
...
...
@@ -563,11 +558,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 +608,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 +773,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
(
...
...
@@ -797,6 +790,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
)
subscribeComposeTextMessage
()
getUnfinishedMessage
()
emojiKeyboardPopup
=
EmojiKeyboardPopup
(
activity
!!
,
activity
!!
.
findViewById
(
R
.
id
.
fragment_container
))
emojiKeyboardPopup
.
listener
=
this
text_message
.
listener
=
object
:
ComposerEditText
.
ComposerEditTextListener
{
...
...
@@ -843,16 +837,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
)
}
}
...
...
@@ -864,12 +858,26 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
private
fun
getUnfinishedMessage
()
{
val
unfinishedMessage
=
presenter
.
getUnfinishedMessage
(
chatRoomId
)
if
(
unfinishedMessage
.
isNotBlank
())
{
text_message
.
setText
(
unfinishedMessage
)
val
orientation
=
resources
.
configuration
.
orientation
if
(
orientation
==
Configuration
.
ORIENTATION_PORTRAIT
)
{
KeyboardHelper
.
showSoftKeyboard
(
text_message
)
}
else
{
//TODO show keyboard in full screen mode when landscape orientation
}
}
}
private
fun
setupSuggestionsView
()
{
suggestions_view
.
anchorTo
(
text_message
)
.
setMaximumHeight
(
resources
.
getDimensionPixelSize
(
R
.
dimen
.
suggestions_box_max_height
))
.
addTokenAdapter
(
PeopleSuggestionsAdapter
(
context
!!
))
.
addTokenAdapter
(
CommandSuggestionsAdapter
())
.
addTokenAdapter
(
RoomSuggestionsAdapter
())
.
addTokenAdapter
(
EmojiSuggestionsAdapter
())
.
addSuggestionProviderAction
(
"@"
)
{
query
->
if
(
query
.
isNotEmpty
())
{
presenter
.
spotlight
(
query
,
PEOPLE
,
true
)
...
...
@@ -880,10 +888,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/ui/StrikethroughDelimiterProcessor.kt
0 → 100644
View file @
e89bc7cc
package
chat.rocket.android.chatroom.ui
import
org.commonmark.ext.gfm.strikethrough.Strikethrough
import
org.commonmark.node.Node
import
org.commonmark.node.Text
import
org.commonmark.parser.delimiter.DelimiterProcessor
import
org.commonmark.parser.delimiter.DelimiterRun
class
StrikethroughDelimiterProcessor
:
DelimiterProcessor
{
override
fun
getOpeningCharacter
():
Char
{
return
'~'
}
override
fun
getClosingCharacter
():
Char
{
return
'~'
}
override
fun
getMinLength
():
Int
{
return
1
}
override
fun
getDelimiterUse
(
opener
:
DelimiterRun
,
closer
:
DelimiterRun
):
Int
{
return
if
(
opener
.
length
()
>=
2
&&
closer
.
length
()
>=
2
)
{
// Use exactly two delimiters even if we have more, and don't care about internal openers/closers.
2
}
else
{
1
}
}
override
fun
process
(
opener
:
Text
,
closer
:
Text
,
delimiterCount
:
Int
)
{
// Wrap nodes between delimiters in strikethrough.
val
strikethrough
=
Strikethrough
()
var
tmp
:
Node
?
=
opener
.
next
while
(
tmp
!=
null
&&
tmp
!==
closer
)
{
val
next
=
tmp
.
next
strikethrough
.
appendChild
(
tmp
)
tmp
=
next
}
opener
.
insertAfter
(
strikethrough
)
}
}
app/src/main/java/chat/rocket/android/chatroom/uimodel/ReactionUiModel.kt
View file @
e89bc7cc
...
...
@@ -5,5 +5,6 @@ data class ReactionUiModel(
val
shortname
:
String
,
val
unicode
:
CharSequence
,
val
count
:
Int
,
val
usernames
:
List
<
String
>
=
emptyList
()
val
usernames
:
List
<
String
>
=
emptyList
(),
var
url
:
String
?
=
null
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
View file @
e89bc7cc
...
...
@@ -18,6 +18,7 @@ import chat.rocket.android.chatroom.domain.MessageReply
import
chat.rocket.android.dagger.scope.PerFragment
import
chat.rocket.android.db.DatabaseManager
import
chat.rocket.android.emoji.EmojiParser
import
chat.rocket.android.emoji.EmojiRepository
import
chat.rocket.android.helper.MessageHelper
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.helper.UserHelper
...
...
@@ -504,15 +505,18 @@ class UiModelMapper @Inject constructor(
private
fun
getReactions
(
message
:
Message
):
List
<
ReactionUiModel
>
{
val
reactions
=
message
.
reactions
?.
let
{
val
list
=
mutableListOf
<
ReactionUiModel
>()
val
customEmojis
=
EmojiRepository
.
getCustomEmojis
()
it
.
getShortNames
().
forEach
{
shortname
->
val
usernames
=
it
.
getUsernames
(
shortname
)
?:
emptyList
()
val
count
=
usernames
.
size
val
custom
=
customEmojis
.
firstOrNull
{
emoji
->
emoji
.
shortname
==
shortname
}
list
.
add
(
ReactionUiModel
(
messageId
=
message
.
id
,
shortname
=
shortname
,
unicode
=
EmojiParser
.
parse
(
context
,
shortname
),
count
=
count
,
usernames
=
usernames
)
usernames
=
usernames
,
url
=
custom
?.
url
)
)
}
list
...
...
app/src/main/java/chat/rocket/android/chatroom/uimodel/suggestion/ChatRoomSuggestionUiModel.kt
View file @
e89bc7cc
package
chat.rocket.android.chatroom.uimodel.suggestion
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.model.SuggestionModel
class
ChatRoomSuggestionUiModel
(
text
:
String
,
val
fullName
:
String
,
...
...
app/src/main/java/chat/rocket/android/chatroom/uimodel/suggestion/CommandSuggestionUiModel.kt
View file @
e89bc7cc
package
chat.rocket.android.chatroom.uimodel.suggestion
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.model.SuggestionModel
class
CommandSuggestionUiModel
(
text
:
String
,
val
description
:
String
,
...
...
app/src/main/java/chat/rocket/android/chatroom/uimodel/suggestion/EmojiSuggestionUiModel.kt
0 → 100644
View file @
e89bc7cc
package
chat.rocket.android.chatroom.uimodel.suggestion
import
chat.rocket.android.emoji.Emoji
import
chat.rocket.android.suggestions.model.SuggestionModel
import
chat.rocket.common.model.UserStatus
class
EmojiSuggestionUiModel
(
text
:
String
,
pinned
:
Boolean
=
false
,
val
emoji
:
Emoji
,
searchList
:
List
<
String
>
)
:
SuggestionModel
(
text
,
searchList
,
pinned
)
{
override
fun
toString
():
String
{
return
"EmojiSuggestionUiModel(text='$text', searchList='$searchList', pinned=$pinned)"
}
}
app/src/main/java/chat/rocket/android/chatroom/uimodel/suggestion/PeopleSuggestionUiModel.kt
View file @
e89bc7cc
package
chat.rocket.android.chatroom.uimodel.suggestion
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.model.SuggestionModel
import
chat.rocket.common.model.UserStatus
class
PeopleSuggestionUiModel
(
val
imageUri
:
String
?,
...
...
app/src/main/java/chat/rocket/android/helper/KeyboardHelper.kt
View file @
e89bc7cc
...
...
@@ -4,6 +4,7 @@ import android.app.Activity
import
android.content.Context
import
android.graphics.Rect
import
android.view.View
import
android.view.WindowManager
import
android.view.inputmethod.InputMethodManager
...
...
@@ -50,4 +51,4 @@ object KeyboardHelper {
inputMethodManager
.
toggleSoftInput
(
InputMethodManager
.
SHOW_IMPLICIT
,
InputMethodManager
.
SHOW_IMPLICIT
)
}
}
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/helper/MessageParser.kt
View file @
e89bc7cc
...
...
@@ -5,6 +5,7 @@ import android.content.Context
import
android.graphics.Canvas
import
android.graphics.Paint
import
android.graphics.RectF
import
android.text.Spannable
import
android.text.Spanned
import
android.text.style.ClickableSpan
import
android.text.style.ImageSpan
...
...
@@ -13,6 +14,7 @@ import android.util.Patterns
import
android.view.View
import
androidx.core.content.res.ResourcesCompat
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.ui.StrikethroughDelimiterProcessor
import
chat.rocket.android.emoji.EmojiParser
import
chat.rocket.android.emoji.EmojiRepository
import
chat.rocket.android.emoji.EmojiTypefaceSpan
...
...
@@ -21,16 +23,23 @@ import chat.rocket.android.server.domain.useRealName
import
chat.rocket.android.util.extensions.openTabbedUrl
import
chat.rocket.common.model.SimpleUser
import
chat.rocket.core.model.Message
import
org.commonmark.Extension
import
org.commonmark.ext.gfm.strikethrough.StrikethroughExtension
import
org.commonmark.ext.gfm.tables.TablesExtension
import
org.commonmark.node.AbstractVisitor
import
org.commonmark.node.Document
import
org.commonmark.node.Emphasis
import
org.commonmark.node.ListItem
import
org.commonmark.node.Node
import
org.commonmark.node.OrderedList
import
org.commonmark.node.StrongEmphasis
import
org.commonmark.node.Text
import
ru.noties.markwon.Markwon
import
org.commonmark.parser.Parser
import
ru.noties.markwon.SpannableBuilder
import
ru.noties.markwon.SpannableConfiguration
import
ru.noties.markwon.renderer.SpannableMarkdownVisitor
import
ru.noties.markwon.tasklist.TaskListExtension
import
java.util.*
import
javax.inject.Inject
class
MessageParser
@Inject
constructor
(
...
...
@@ -39,8 +48,6 @@ class MessageParser @Inject constructor(
private
val
settings
:
PublicSettings
)
{
private
val
parser
=
Markwon
.
createParser
()
/**
* Render markdown and other rules on message to rich text with spans.
*
...
...
@@ -52,6 +59,16 @@ class MessageParser @Inject constructor(
fun
render
(
message
:
Message
,
selfUsername
:
String
?
=
null
):
CharSequence
{
var
text
:
String
=
message
.
message
val
mentions
=
mutableListOf
<
String
>()
val
parser
=
Parser
.
Builder
()
.
extensions
(
Arrays
.
asList
<
Extension
>(
StrikethroughExtension
.
create
(),
TablesExtension
.
create
(),
TaskListExtension
.
create
()
))
.
customDelimiterProcessor
(
StrikethroughDelimiterProcessor
())
.
build
()
message
.
mentions
?.
forEach
{
val
mention
=
getMention
(
it
)
mentions
.
add
(
mention
)
...
...
@@ -59,12 +76,17 @@ class MessageParser @Inject constructor(
text
=
text
.
replace
(
"@${it.username}"
,
mention
)
}
}
val
builder
=
SpannableBuilder
()
val
content
=
EmojiRepository
.
shortnameToUnicode
(
text
)
val
parentNode
=
parser
.
parse
(
toLenientMarkdown
(
content
))
val
parentNode
=
parser
.
parse
(
content
)
parentNode
.
accept
(
EmphasisVisitor
())
parentNode
.
accept
(
StrongEmphasisVisitor
())
parentNode
.
accept
(
MarkdownVisitor
(
configuration
,
builder
))
parentNode
.
accept
(
LinkVisitor
(
builder
))
parentNode
.
accept
(
EmojiVisitor
(
context
,
configuration
,
builder
))
message
.
mentions
?.
let
{
parentNode
.
accept
(
MentionVisitor
(
context
,
builder
,
mentions
,
selfUsername
))
}
...
...
@@ -72,13 +94,6 @@ class MessageParser @Inject constructor(
return
builder
.
text
()
}
// Convert to a lenient markdown consistent with Rocket.Chat web markdown instead of the official specs.
private
fun
toLenientMarkdown
(
text
:
String
):
String
{
return
text
.
trim
().
replace
(
"\\*(.+)\\*"
.
toRegex
())
{
"**${it.groupValues[1].trim()}**"
}
.
replace
(
"\\~(.+)\\~"
.
toRegex
())
{
"~~${it.groupValues[1].trim()}~~"
}
.
replace
(
"\\_(.+)\\_"
.
toRegex
())
{
"_${it.groupValues[1].trim()}_"
}
}
private
fun
getMention
(
user
:
SimpleUser
):
String
{
return
if
(
settings
.
useRealName
())
{
user
.
name
?:
"@${user.username}"
...
...
@@ -87,6 +102,31 @@ class MessageParser @Inject constructor(
}
}
class
EmphasisVisitor
:
AbstractVisitor
()
{
override
fun
visit
(
emphasis
:
Emphasis
)
{
if
(
emphasis
.
openingDelimiter
==
"*"
&&
emphasis
.
firstChild
!=
null
)
{
val
child
=
emphasis
.
firstChild
val
strongEmphasis
=
StrongEmphasis
()
strongEmphasis
.
appendChild
(
child
)
emphasis
.
insertBefore
(
strongEmphasis
)
emphasis
.
unlink
()
}
}
}
class
StrongEmphasisVisitor
:
AbstractVisitor
()
{
override
fun
visit
(
strongEmphasis
:
StrongEmphasis
)
{
if
(
strongEmphasis
.
openingDelimiter
==
"__"
&&
strongEmphasis
.
firstChild
!=
null
)
{
val
child
=
strongEmphasis
.
firstChild
val
emphasis
=
Emphasis
()
emphasis
.
appendChild
(
child
)
strongEmphasis
.
insertBefore
(
emphasis
)
strongEmphasis
.
unlink
()
}
}
}
class
MentionVisitor
(
context
:
Context
,
private
val
builder
:
SpannableBuilder
,
...
...
@@ -98,28 +138,28 @@ class MessageParser @Inject constructor(
private
val
othersBackgroundColor
=
ResourcesCompat
.
getColor
(
context
.
resources
,
android
.
R
.
color
.
transparent
,
context
.
theme
)
private
val
myselfTextColor
=
ResourcesCompat
.
getColor
(
context
.
resources
,
R
.
color
.
colorWhite
,
context
.
theme
)
private
val
myselfBackgroundColor
=
ResourcesCompat
.
getColor
(
context
.
resources
,
R
.
color
.
colorAccent
,
context
.
theme
)
private
val
mentionP
adding
=
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
padding_mention
).
toFloat
()
private
val
mentionR
adius
=
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
radius_mention
).
toFloat
()
private
val
p
adding
=
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
padding_mention
).
toFloat
()
private
val
r
adius
=
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
radius_mention
).
toFloat
()
override
fun
visit
(
t
:
Tex
t
)
{
val
text
=
t
.
literal
override
fun
visit
(
document
:
Documen
t
)
{
val
text
=
builder
.
text
()
val
mentionsList
=
mentions
.
toMutableList
().
also
{
it
.
add
(
"@all"
)
it
.
add
(
"@here"
)
}.
toLis
t
()
}.
distinc
t
()
mentionsList
.
forEach
{
val
mentionMe
=
it
==
currentUser
||
it
==
"@all"
||
it
==
"@here"
var
offset
=
text
.
indexOf
(
it
,
0
,
tru
e
)
var
offset
=
text
.
indexOf
(
string
=
it
,
startIndex
=
0
,
ignoreCase
=
fals
e
)
while
(
offset
>
-
1
)
{
val
textColor
=
if
(
mentionMe
)
myselfTextColor
else
othersTextColor
val
backgroundColor
=
if
(
mentionMe
)
myselfBackgroundColor
else
othersBackgroundColor
val
usernameSpan
=
MentionSpan
(
backgroundColor
,
textColor
,
mentionRadius
,
mentionP
adding
,
val
usernameSpan
=
MentionSpan
(
backgroundColor
,
textColor
,
radius
,
p
adding
,
mentionMe
)
// Add 1 to end offset to include the @.
val
end
=
offset
+
it
.
length
+
1
builder
.
setSpan
(
usernameSpan
,
offset
,
end
,
0
)
offset
=
text
.
indexOf
(
"@$it"
,
end
,
tru
e
)
val
end
=
offset
+
it
.
length
builder
.
setSpan
(
usernameSpan
,
offset
,
end
,
Spannable
.
SPAN_EXCLUSIVE_EXCLUSIVE
)
offset
=
text
.
indexOf
(
string
=
"@$it"
,
startIndex
=
end
,
ignoreCase
=
fals
e
)
}
}
}
...
...
@@ -179,7 +219,7 @@ class MessageParser @Inject constructor(
}
private
fun
newLine
()
{
if
(
builder
.
length
()
>
0
&&
'\n'
!=
builder
.
lastChar
())
{
if
(
builder
.
isNotEmpty
()
&&
'\n'
!=
builder
.
lastChar
())
{
builder
.
append
(
'\n'
)
}
}
...
...
@@ -204,7 +244,6 @@ class MessageParser @Inject constructor(
consumed
.
add
(
link
)
}
}
visitChildren
(
text
)
}
}
...
...
app/src/main/java/chat/rocket/android/infrastructure/LocalRepository.kt
View file @
e89bc7cc
...
...
@@ -27,6 +27,7 @@ interface LocalRepository {
const
val
SETTINGS_KEY
=
"settings_"
const
val
PERMISSIONS_KEY
=
"permissions_"
const
val
USER_KEY
=
"user_"
const
val
UNFINISHED_MSG_KEY
=
"unfinished_msg_"
const
val
CURRENT_USERNAME_KEY
=
"username_"
const
val
LAST_CHATROOMS_REFRESH
=
"_chatrooms_refresh"
}
...
...
app/src/main/res/drawable/rounded_background.xml
View file @
e89bc7cc
...
...
@@ -5,5 +5,5 @@
android:width=
"24dp"
android:height=
"24dp"
/>
<solid
android:color=
"#efeeee"
/>
<corners
android:radius=
"4dp"
/>
</shape>
\ No newline at end of file
<corners
android:radius=
"4dp"
/>
</shape>
app/src/main/res/layout/fragment_chat_room.xml
View file @
e89bc7cc
...
...
@@ -74,7 +74,7 @@
app:layout_constraintTop_toTopOf=
"parent"
tools:visibility=
"visible"
/>
<chat.rocket.android.
widget.autocompletion
.ui.SuggestionsView
<chat.rocket.android.
suggestions
.ui.SuggestionsView
android:id=
"@+id/suggestions_view"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
...
...
app/src/main/res/layout/item_message_attachment.xml
View file @
e89bc7cc
...
...
@@ -5,13 +5,14 @@
android:id=
"@+id/attachment_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:animateLayoutChanges=
"true"
android:background=
"?android:attr/selectableItemBackground"
android:clickable=
"true"
android:focusable=
"true"
android:paddingBottom=
"@dimen/message_item_top_and_bottom_padding"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_padding"
android:paddingStart=
"@dimen/screen_edge_left_and_right_padding"
android:paddingTop=
"@dimen/message_item_top_and_bottom_padding"
>
android:paddingTop=
"@dimen/message_item_top_and_bottom_padding"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_padding"
android:paddingBottom=
"@dimen/message_item_top_and_bottom_padding"
>
<View
android:id=
"@+id/quote_bar"
...
...
@@ -19,7 +20,7 @@
android:layout_height=
"0dp"
android:layout_marginStart=
"56dp"
android:background=
"@drawable/quote_vertical_gray_bar"
app:layout_constraintBottom_toTopOf=
"@+id/
recycler_view_reactions
"
app:layout_constraintBottom_toTopOf=
"@+id/
text_view_more
"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
/>
...
...
@@ -28,11 +29,11 @@
style=
"@style/Sender.Name.TextView"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:textColor=
"@color/colorPrimary"
tools:text=
"Ronald Perkins"
app:layout_constraintStart_toEndOf=
"@+id/quote_bar"
app:layout_constraintTop_toTopOf=
"parent"
android:layout_marginStart=
"8dp
"
/>
tools:text=
"Ronald Perkins
"
/>
<TextView
android:id=
"@+id/text_message_time"
...
...
@@ -40,28 +41,39 @@
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"10dp"
tools:text=
"11:45 PM
"
app:layout_constraintBottom_toBottomOf=
"@+id/text_sender
"
app:layout_constraintStart_toEndOf=
"@+id/text_sender"
app:layout_constraintTop_toTopOf=
"@+id/text_sender"
app:layout_constraintBottom_toBottomOf=
"@+id/text_sender"
/>
tools:text=
"11:45 PM"
/>
<TextView
android:id=
"@+id/text_content"
style=
"@style/Message.Quote.TextView"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:ellipsize=
"end"
android:singleLine=
"true"
app:layout_constraintBottom_toTopOf=
"@id/text_view_more"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"@+id/text_sender"
app:layout_constraintTop_toBottomOf=
"@+id/text_sender"
tools:text=
"This is a multiline chat message from Bertie that will take more than just one line of text. I have sure that everything is amazing!"
/>
<TextView
android:id=
"@+id/text_view_more"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:gravity=
"end"
android:textColor=
"@color/darkGray"
android:textSize=
"14sp"
app:layout_constraintEnd_toEndOf=
"@+id/text_content"
app:layout_constraintStart_toStartOf=
"@+id/quote_bar"
app:layout_constraintTop_toBottomOf=
"@+id/text_content"
tools:text=
"Visualizar mais"
/>
<include
layout=
"@layout/layout_reactions"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
app:layout_constraintStart_toStartOf=
"@+id/quote_bar"
app:layout_constraintTop_toBottomOf=
"@+id/text_
content
"
/>
app:layout_constraintTop_toBottomOf=
"@+id/text_
view_more
"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
</androidx.constraintlayout.widget.ConstraintLayout>
app/src/main/res/layout/item_reaction.xml
View file @
e89bc7cc
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
<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=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"2dp"
android:layout_marginRight=
"2dp"
android:layout_marginTop=
"2dp"
android:layout_marginBottom=
"2dp"
android:descendantFocusability=
"beforeDescendants"
android:background=
"@drawable/rounded_background"
android:orientation=
"horizontal"
>
android:background=
"@drawable/rounded_background"
>
<
TextView
android:id=
"@+id/
text_emoji
"
<
ViewFlipper
android:id=
"@+id/
view_flipper_reaction
"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:ellipsize=
"end"
android:maxLines=
"1"
android:paddingLeft=
"4dp"
android:paddingStart=
"4dp"
android:textColor=
"#868585"
android:textSize=
"16sp"
tools:text=
":)"
/>
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toStartOf=
"@+id/text_count"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
>
<TextView
android:id=
"@+id/text_emoji"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:ellipsize=
"end"
android:maxLines=
"1"
android:paddingStart=
"4dp"
android:paddingLeft=
"4dp"
android:textColor=
"#868585"
android:textSize=
"16sp"
tools:text=
":)"
/>
<ImageView
android:id=
"@+id/image_emoji"
android:layout_width=
"@dimen/custom_emoji_small"
android:layout_height=
"@dimen/custom_emoji_small"
android:layout_gravity=
"center"
tools:src=
"@tools:sample/avatars"
/>
</ViewFlipper>
<TextView
android:id=
"@+id/text_count"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:gravity=
"center"
android:paddingBottom=
"4dp"
android:paddingEnd=
"4dp"
android:paddingLeft=
"4dp"
android:paddingRight=
"4dp"
android:paddingStart=
"4dp"
android:paddingLeft=
"4dp"
android:paddingTop=
"4dp"
android:paddingEnd=
"4dp"
android:paddingRight=
"4dp"
android:paddingBottom=
"4dp"
android:textColor=
"#868585"
android:textSize=
"16sp"
android:textStyle=
"bold"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toEndOf=
"@+id/view_flipper_reaction"
app:layout_constraintTop_toTopOf=
"parent"
tools:text=
"12"
/>
</
Linear
Layout>
</
androidx.constraintlayout.widget.Constraint
Layout>
app/src/main/res/layout/suggestion_emoji_item.xml
0 → 100644
View file @
e89bc7cc
<?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"
android:textColor=
"@android:color/black"
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>
app/src/main/res/values-de/strings.xml
View file @
e89bc7cc
...
...
@@ -157,6 +157,10 @@
<string
name=
"msg_message_copied"
>
Nachricht kopiert
</string>
<string
name=
"msg_delete_message"
>
Lösche Nachricht
</string>
<string
name=
"msg_delete_description"
>
Sind Sie sicher, dass Sie diese Nachricht löschen wollen?
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_more"
>
view more
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_less"
>
view less
</string>
<!-- Preferences messages -->
<string
name=
"msg_analytics_tracking"
>
Analytics tracking
</string>
<!-- TODO Add translation -->
...
...
app/src/main/res/values-es/strings.xml
View file @
e89bc7cc
...
...
@@ -154,6 +154,10 @@
<string
name=
"msg_member_already_added"
>
Ya has seleccionado este usuario
</string>
<string
name=
"msg_member_not_found"
>
Miembro no encontrado
</string>
<string
name=
"msg_channel_created_successfully"
>
Canal creado con éxito
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_more"
>
view more
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_less"
>
view less
</string>
<!-- Preferences messages -->
<string
name=
"msg_analytics_tracking"
>
Analytics tracking
</string>
<!-- TODO Add translation -->
...
...
app/src/main/res/values-fr/strings.xml
View file @
e89bc7cc
...
...
@@ -147,6 +147,10 @@
<string
name=
"msg_continue_with_wordpress"
>
Continue with
<b>
WordPress
</b></string>
<!-- TODO Add translation -->
<string
name=
"msg_two_factor_authentication"
>
Two-factor Authentication
</string>
<!-- TODO Add translation -->
<string
name=
"msg__your_2fa_code"
>
What’s your 2FA code?
</string>
<!-- TODO Add translation -->
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_more"
>
view more
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_less"
>
view less
</string>
<!-- Create channel messages -->
<string
name=
"msg_private_channel"
>
Privé
</string>
...
...
app/src/main/res/values-hi-rIN/strings.xml
View file @
e89bc7cc
...
...
@@ -160,6 +160,10 @@
<string
name=
"msg_member_already_added"
>
आपने पहले से ही इस यूजर को चुन चुके है।
</string>
<string
name=
"msg_member_not_found"
>
सदस्य नहीं मिला
</string>
<string
name=
"msg_channel_created_successfully"
>
चैनल सफलतापूर्वक बनाया गया
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_more"
>
view more
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_less"
>
view less
</string>
<!-- Preferences messages -->
<string
name=
"msg_analytics_tracking"
>
एनालिटिक्स ट्रैकिंग
</string>
...
...
app/src/main/res/values-ja/strings.xml
View file @
e89bc7cc
...
...
@@ -147,6 +147,10 @@
<string
name=
"msg_continue_with_wordpress"
>
Continue with
<b>
WordPress
</b></string>
<!-- TODO Add translation -->
<string
name=
"msg_two_factor_authentication"
>
Two-factor Authentication
</string>
<!-- TODO Add translation -->
<string
name=
"msg__your_2fa_code"
>
What’s your 2FA code?
</string>
<!-- TODO Add translation -->
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_more"
>
view more
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_less"
>
view less
</string>
<!-- Create channel messages -->
<string
name=
"msg_private_channel"
>
プライベート
</string>
...
...
app/src/main/res/values-pt-rBR/strings.xml
View file @
e89bc7cc
...
...
@@ -133,8 +133,8 @@
<string
name=
"msg_upload_file"
>
Subir arquivo
</string>
<string
name=
"msg_file_description"
>
Descrição do arquivo
</string>
<string
name=
"msg_send"
>
Enviar
</string>
<string
name=
"msg_delete_message"
>
Delete Message
</string>
<!-- TODO Add translation --
>
<string
name=
"msg_delete_description"
>
Are you sure you want to delete this message
</string>
<!-- TODO Add translation --
>
<string
name=
"msg_delete_message"
>
Remove mensagem
</string
>
<string
name=
"msg_delete_description"
>
Tem certeza que quer apagar esta mensagem?
</string
>
<string
name=
"msg_welcome_to_rocket_chat"
>
Welcome to Rocket.Chat
</string>
<!-- TODO Add translation -->
<string
name=
"msg_team_communication"
>
Open Source Communication
</string>
<!-- TODO Add translation -->
<string
name=
"msg_login_with_email"
>
Login with
<b>
e-mail
</b></string>
<!-- TODO Add translation -->
...
...
@@ -147,6 +147,8 @@
<string
name=
"msg_continue_with_wordpress"
>
Continue with
<b>
WordPress
</b></string>
<!-- TODO Add translation -->
<string
name=
"msg_two_factor_authentication"
>
Two-factor Authentication
</string>
<!-- TODO Add translation -->
<string
name=
"msg__your_2fa_code"
>
What’s your 2FA code?
</string>
<!-- TODO Add translation -->
<string
name=
"msg_view_more"
>
visualizar mais
</string>
<string
name=
"msg_view_less"
>
visualizar menos
</string>
<!-- Create channel messages -->
<string
name=
"msg_private_channel"
>
Privado
</string>
...
...
app/src/main/res/values-ru-rRU/strings.xml
View file @
e89bc7cc
...
...
@@ -145,6 +145,9 @@
<string
name=
"msg_continue_with_wordpress"
>
Continue with
<b>
WordPress
</b></string>
<!-- TODO Add translation -->
<string
name=
"msg_two_factor_authentication"
>
Two-factor Authentication
</string>
<!-- TODO Add translation -->
<string
name=
"msg__your_2fa_code"
>
What’s your 2FA code?
</string>
<!-- TODO Add translation -->
<string
name=
"msg_view_more"
>
view more
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_less"
>
view less
</string>
<!-- Create channel messages -->
<string
name=
"msg_private_channel"
>
Приватный
</string>
...
...
app/src/main/res/values-uk/strings.xml
View file @
e89bc7cc
...
...
@@ -144,6 +144,10 @@
<string
name=
"msg_continue_with_wordpress"
>
Continue with
<b>
WordPress
</b></string>
<!-- TODO Add translation -->
<string
name=
"msg_two_factor_authentication"
>
Two-factor Authentication
</string>
<!-- TODO Add translation -->
<string
name=
"msg__your_2fa_code"
>
What’s your 2FA code?
</string>
<!-- TODO Add translation -->
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_more"
>
view more
</string>
<!-- TODO - Add proper translation -->
<string
name=
"msg_view_less"
>
view less
</string>
<!-- Create channel messages -->
<string
name=
"msg_private_channel"
>
Приватний
</string>
...
...
app/src/main/res/values/dimens.xml
View file @
e89bc7cc
...
...
@@ -43,11 +43,9 @@
<dimen
name=
"padding_mention"
>
4dp
</dimen>
<dimen
name=
"radius_mention"
>
6dp
</dimen>
<!-- Autocomplete Popup -->
<dimen
name=
"popup_max_height"
>
150dp
</dimen>
<dimen
name=
"suggestions_box_max_height"
>
250dp
</dimen>
<dimen
name=
"viewer_toolbar_padding"
>
16dp
</dimen>
<dimen
name=
"viewer_toolbar_title"
>
16sp
</dimen>
<dimen
name=
"quote_collapsed_height"
>
32dp
</dimen>
</resources>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
e89bc7cc
...
...
@@ -174,6 +174,8 @@ https://github.com/RocketChat/java-code-styles/blob/master/CODING_STYLE.md#strin
<string
name=
"msg_message_copied"
>
Message copied
</string>
<string
name=
"msg_delete_message"
>
Delete Message
</string>
<string
name=
"msg_delete_description"
>
Are you sure you want to delete this message
</string>
<string
name=
"msg_view_more"
>
view more
</string>
<string
name=
"msg_view_less"
>
view less
</string>
<!-- Preferences messages -->
<string
name=
"msg_analytics_tracking"
>
Analytics tracking
</string>
...
...
build.gradle
View file @
e89bc7cc
...
...
@@ -10,7 +10,7 @@ buildscript {
}
dependencies
{
classpath
'com.android.tools.build:gradle:3.2.0-rc0
2
'
classpath
'com.android.tools.build:gradle:3.2.0-rc0
3
'
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath
"org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath
'com.google.gms:google-services:4.0.2'
...
...
dependencies.gradle
View file @
e89bc7cc
...
...
@@ -48,7 +48,7 @@ ext {
kotshi
:
'1.0.4'
,
frescoImageViewer
:
'0.5.1'
,
markwon
:
'
1.1.1
'
,
markwon
:
'
2.0.0
'
,
aVLoadingIndicatorView:
'2.1.3'
,
glide
:
'4.8.0'
,
...
...
emoji/src/main/java/chat/rocket/android/emoji/EmojiKeyboardPopup.kt
View file @
e89bc7cc
...
...
@@ -156,21 +156,24 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
private
suspend
fun
setupViewPager
()
{
context
.
let
{
val
callback
=
when
(
it
)
{
val
callback
:
EmojiKeyboardListener
?
=
when
(
it
)
{
is
EmojiKeyboardListener
->
it
else
->
{
val
fragments
=
(
it
as
AppCompatActivity
).
supportFragmentManager
.
fragments
if
(
fragments
.
size
==
0
||
!(
fragments
[
0
]
is
EmojiKeyboardListener
))
{
throw
IllegalStateException
(
"activity/fragment should implement Listener interface"
)
// Since the app can arrive in an inconsistent state at this point, do not throw
// throw IllegalStateException("activity/fragment should implement Listener interface")
null
}
else
{
fragments
[
0
]
as
EmojiKeyboardListener
}
fragments
[
0
]
as
EmojiKeyboardListener
}
}
adapter
=
EmojiPagerAdapter
(
object
:
EmojiKeyboardListener
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
EmojiRepository
.
addToRecents
(
emoji
)
callback
.
onEmojiAdded
(
emoji
)
callback
?
.
onEmojiAdded
(
emoji
)
}
})
...
...
emoji/src/main/java/chat/rocket/android/emoji/EmojiRepository.kt
View file @
e89bc7cc
...
...
@@ -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
()
}
...
...
@@ -210,7 +210,7 @@ object EmojiRepository {
}
}
internal
fun
getCustomEmojis
():
List
<
Emoji
>
=
customEmojis
fun
getCustomEmojis
():
List
<
Emoji
>
=
customEmojis
/**
* Get all recently used emojis ordered by usage count.
...
...
settings.gradle
View file @
e89bc7cc
include
':app'
,
':player'
,
':emoji'
,
':draw'
,
':util'
,
':core'
//, ':wear'
\ No newline at end of file
include
':app'
,
':player'
,
':emoji'
,
':draw'
,
':util'
,
':core'
,
':suggestions'
//, ':wear'
\ No newline at end of file
suggestions/.gitignore
0 → 100644
View file @
e89bc7cc
/build
suggestions/build.gradle
0 → 100644
View file @
e89bc7cc
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
"1.0.0"
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
}
buildTypes
{
release
{
minifyEnabled
false
proguardFiles
getDefaultProguardFile
(
'proguard-android.txt'
),
'proguard-rules.pro'
}
}
}
dependencies
{
implementation
libraries
.
kotlin
implementation
libraries
.
recyclerview
implementation
libraries
.
appCompat
implementation
libraries
.
material
}
androidExtensions
{
experimental
=
true
}
suggestions/proguard-rules.pro
0 → 100644
View file @
e89bc7cc
# 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
suggestions/src/main/AndroidManifest.xml
0 → 100644
View file @
e89bc7cc
<manifest
xmlns:android=
"http://schemas.android.com/apk/res/android"
package=
"chat.rocket.android.suggestions"
/>
app/src/main/java/chat/rocket/android/widget/autocompletion
/model/SuggestionModel.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/model/SuggestionModel.kt
View file @
e89bc7cc
package
chat.rocket.android.widget.autocompletion.model
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
...
...
@@ -15,4 +18,4 @@ abstract class SuggestionModel(val text: String, // This is the text key for sea
override
fun
hashCode
():
Int
{
return
text
.
hashCode
()
}
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/repository/LocalSuggestionProvider.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/repository/LocalSuggestionProvider.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.repository
package
chat.rocket.android.
suggestions
.repository
interface
LocalSuggestionProvider
{
fun
find
(
prefix
:
String
)
...
...
app/src/main/java/chat/rocket/android/widget/autocompletion
/strategy/CompletionStrategy.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/strategy/CompletionStrategy.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.strategy
package
chat.rocket.android.
suggestions
.strategy
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.model.SuggestionModel
interface
CompletionStrategy
{
fun
getItem
(
prefix
:
String
,
position
:
Int
):
SuggestionModel
...
...
@@ -8,4 +8,4 @@ interface CompletionStrategy {
fun
addAll
(
list
:
List
<
SuggestionModel
>)
fun
addPinned
(
list
:
List
<
SuggestionModel
>)
fun
size
():
Int
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/strategy/regex/StringMatchingCompletionStrategy.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/strategy/regex/StringMatchingCompletionStrategy.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.strategy.regex
package
chat.rocket.android.
suggestions
.strategy.regex
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
widget.autocompletion
.strategy.CompletionStrategy
import
chat.rocket.android.
widget.autocompletion
.ui.SuggestionsAdapter.Companion.RESULT_COUNT_UNLIMITED
import
chat.rocket.android.
suggestions
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.strategy.CompletionStrategy
import
chat.rocket.android.
suggestions
.ui.SuggestionsAdapter.Companion.RESULT_COUNT_UNLIMITED
import
java.util.concurrent.CopyOnWriteArrayList
internal
class
StringMatchingCompletionStrategy
(
private
val
threshold
:
Int
=
RESULT_COUNT_UNLIMITED
)
:
CompletionStrategy
{
...
...
@@ -46,4 +46,4 @@ internal class StringMatchingCompletionStrategy(private val threshold: Int = RES
override
fun
size
():
Int
{
return
list
.
size
}
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/strategy/trie/TrieCompletionStrategy.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/strategy/trie/TrieCompletionStrategy.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.strategy.trie
package
chat.rocket.android.
suggestions
.strategy.trie
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
widget.autocompletion
.strategy.CompletionStrategy
import
chat.rocket.android.
widget.autocompletion
.strategy.trie.data.Trie
import
chat.rocket.android.
suggestions
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.strategy.CompletionStrategy
import
chat.rocket.android.
suggestions
.strategy.trie.data.Trie
class
TrieCompletionStrategy
:
CompletionStrategy
{
private
val
items
=
mutableListOf
<
SuggestionModel
>()
...
...
@@ -18,7 +18,9 @@ class TrieCompletionStrategy : CompletionStrategy {
return
item
}
override
fun
autocompleteItems
(
prefix
:
String
)
=
trie
.
autocompleteItems
(
prefix
)
override
fun
autocompleteItems
(
prefix
:
String
):
List
<
SuggestionModel
>
{
return
trie
.
autocompleteItems
(
prefix
)
}
override
fun
addAll
(
list
:
List
<
SuggestionModel
>)
{
items
.
addAll
(
list
)
...
...
@@ -28,8 +30,7 @@ class TrieCompletionStrategy : CompletionStrategy {
}
override
fun
addPinned
(
list
:
List
<
SuggestionModel
>)
{
}
override
fun
size
()
=
items
.
size
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/strategy/trie/data/Trie.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/strategy/trie/data/Trie.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.strategy.trie.data
package
chat.rocket.android.
suggestions
.strategy.trie.data
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.model.SuggestionModel
internal
class
Trie
{
private
val
root
=
TrieNode
(
' '
)
...
...
@@ -34,10 +34,7 @@ internal class Trie {
val
sanitizedWord
=
word
.
trim
().
toLowerCase
()
var
current
=
root
sanitizedWord
.
forEach
{
ch
->
val
child
=
current
.
getChild
(
ch
)
if
(
child
==
null
)
{
return
false
}
val
child
=
current
.
getChild
(
ch
)
?:
return
false
current
=
child
}
if
(
current
.
isLeaf
)
{
...
...
@@ -63,8 +60,8 @@ internal class Trie {
lastNode
=
lastNode
?.
getChild
(
ch
)
if
(
lastNode
==
null
)
return
emptyList
()
}
return
lastNode
!!
.
getItems
()
return
lastNode
!!
.
getItems
()
.
take
(
5
).
toList
()
}
fun
getCount
()
=
count
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/strategy/trie/data/TrieNode.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/strategy/trie/data/TrieNode.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.strategy.trie.data
package
chat.rocket.android.
suggestions
.strategy.trie.data
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.suggestions.model.SuggestionModel
import
kotlin.coroutines.experimental.buildSequence
internal
class
TrieNode
(
internal
var
data
:
Char
,
internal
var
parent
:
TrieNode
?
=
null
,
internal
var
isLeaf
:
Boolean
=
false
,
internal
var
item
:
SuggestionModel
?
=
null
)
{
internal
class
TrieNode
(
internal
var
data
:
Char
,
internal
var
parent
:
TrieNode
?
=
null
,
internal
var
isLeaf
:
Boolean
=
false
,
internal
var
item
:
SuggestionModel
?
=
null
)
{
val
children
=
hashMapOf
<
Char
,
TrieNode
>()
fun
getChild
(
c
:
Char
):
TrieNode
?
{
...
...
@@ -28,20 +32,18 @@ internal class TrieNode(internal var data: Char,
return
list
}
class
X
:
SuggestionModel
(
""
)
fun
getItems
():
Sequence
<
SuggestionModel
>
=
buildSequence
{
fun
getItems
():
List
<
SuggestionModel
>
{
val
list
=
arrayListOf
<
SuggestionModel
>()
if
(
isLeaf
)
{
list
.
ad
d
(
item
!!
)
yiel
d
(
item
!!
)
}
children
.
forEach
{
node
->
node
.
value
.
let
{
list
.
ad
dAll
(
it
.
getItems
())
yiel
dAll
(
it
.
getItems
())
}
}
return
list
}
override
fun
toString
():
String
=
if
(
parent
==
null
)
""
else
"${parent.toString()}$data"
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/ui/BaseSuggestionViewHolder.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/ui/BaseSuggestionViewHolder.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.ui
package
chat.rocket.android.
suggestions
.ui
import
androidx.recyclerview.widget.RecyclerView
import
android.view.View
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
androidx.recyclerview.widget.RecyclerView
import
chat.rocket.android.suggestions.model.SuggestionModel
abstract
class
BaseSuggestionViewHolder
(
view
:
View
)
:
RecyclerView
.
ViewHolder
(
view
)
{
abstract
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/ui/PopupRecyclerView.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/ui/PopupRecyclerView.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.ui
package
chat.rocket.android.
suggestions
.ui
import
android.content.Context
import
android.util.AttributeSet
import
android.util.DisplayMetrics
import
android.view.WindowManager
import
androidx.recyclerview.widget.RecyclerView
import
chat.rocket.android.R
import
chat.rocket.android.
suggestions.
R
internal
class
PopupRecyclerView
:
RecyclerView
{
private
var
displayWidth
:
Int
=
0
...
...
@@ -38,4 +38,4 @@ internal class PopupRecyclerView : RecyclerView {
override
fun
onLayout
(
changed
:
Boolean
,
l
:
Int
,
t
:
Int
,
r
:
Int
,
b
:
Int
)
{
super
.
onLayout
(
changed
,
l
+
40
,
t
,
r
-
40
,
b
)
}
}
\ No newline at end of file
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/ui/SuggestionsAdapter.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/ui/SuggestionsAdapter.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.ui
package
chat.rocket.android.
suggestions
.ui
import
androidx.recyclerview.widget.RecyclerView
import
chat.rocket.android.
widget.autocompletion
.model.SuggestionModel
import
chat.rocket.android.
widget.autocompletion
.strategy.CompletionStrategy
import
chat.rocket.android.
widget.autocompletion
.strategy.regex.StringMatchingCompletionStrategy
import
chat.rocket.android.
suggestions
.model.SuggestionModel
import
chat.rocket.android.
suggestions
.strategy.CompletionStrategy
import
chat.rocket.android.
suggestions
.strategy.regex.StringMatchingCompletionStrategy
import
java.lang.reflect.Type
import
kotlin.properties.Delegates
abstract
class
SuggestionsAdapter
<
VH
:
BaseSuggestionViewHolder
>(
val
token
:
String
,
val
constraint
:
Int
=
CONSTRAINT_UNBOUND
,
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
}
completionStrategy
:
CompletionStrategy
?
=
null
,
threshold
:
Int
=
MAX_RESULT_COUNT
)
:
RecyclerView
.
Adapter
<
VH
>()
{
private
var
itemType
:
Type
?
=
null
private
var
itemClickListener
:
ItemClickListener
?
=
null
...
...
@@ -30,12 +22,12 @@ 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
->
private
var
currentTerm
:
String
by
Delegates
.
observable
(
""
)
{
_
,
_
,
newTerm
->
val
items
=
strategy
.
autocompleteItems
(
newTerm
)
notifyDataSetChanged
()
}
)
}
init
{
setHasStableIds
(
true
)
...
...
@@ -105,4 +97,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
}
}
app/src/main/java/chat/rocket/android/widget/autocompletion
/ui/SuggestionsView.kt
→
suggestions/src/main/java/chat/rocket/android/suggestions
/ui/SuggestionsView.kt
View file @
e89bc7cc
package
chat.rocket.android.
widget.autocompletion
.ui
package
chat.rocket.android.
suggestions
.ui
import
android.content.Context
import
android.graphics.Canvas
import
android.graphics.Rect
import
android.graphics.drawable.Drawable
import
androidx.annotation.DrawableRes
import
androidx.transition.Slide
import
androidx.transition.TransitionManager
import
androidx.core.content.ContextCompat
import
androidx.recyclerview.widget.DefaultItemAnimator
import
androidx.recyclerview.widget.LinearLayoutManager
import
androidx.recyclerview.widget.RecyclerView
import
android.text.Editable
import
android.text.InputType
import
android.text.TextWatcher
import
android.transition.Slide
import
android.transition.TransitionManager
import
android.util.AttributeSet
import
android.view.Gravity
import
android.view.View
import
android.widget.EditText
import
android.widget.FrameLayout
import
chat.rocket.android.R
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter.Companion.CONSTRAINT_BOUND_TO_START
import
androidx.annotation.DrawableRes
import
androidx.core.content.ContextCompat
import
androidx.recyclerview.widget.DefaultItemAnimator
import
androidx.recyclerview.widget.LinearLayoutManager
import
androidx.recyclerview.widget.RecyclerView
import
chat.rocket.android.suggestions.R
import
chat.rocket.android.suggestions.model.SuggestionModel
import
chat.rocket.android.suggestions.ui.SuggestionsAdapter.Companion.CONSTRAINT_BOUND_TO_START
import
java.lang.ref.WeakReference
import
java.util.concurrent.atomic.AtomicInteger
...
...
@@ -103,7 +103,8 @@ class SuggestionsView : FrameLayout, TextWatcher {
val
prefixEndIndex
=
this
.
editor
?.
get
()
?.
selectionStart
?:
NO_STATE_INDEX
if
(
prefixEndIndex
==
NO_STATE_INDEX
||
prefixEndIndex
<
completionOffset
.
get
())
return
val
prefix
=
s
.
subSequence
(
completionOffset
.
get
(),
this
.
editor
?.
get
()
?.
selectionStart
?:
completionOffset
.
get
()).
toString
()
val
prefix
=
s
.
subSequence
(
completionOffset
.
get
(),
this
.
editor
?.
get
()
?.
selectionStart
?:
completionOffset
.
get
()).
toString
()
recyclerView
.
adapter
?.
let
{
it
as
SuggestionsAdapter
// we need to look up only after the '@'
...
...
@@ -148,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
)
}
...
...
@@ -192,7 +192,8 @@ class SuggestionsView : FrameLayout, TextWatcher {
}
private
fun
adapter
(
token
:
String
):
SuggestionsAdapter
<
*
>
{
return
adaptersByToken
[
token
]
?:
throw
IllegalStateException
(
"no adapter binds to token \"$token\""
)
return
adaptersByToken
[
token
]
?:
throw
IllegalStateException
(
"no adapter binds to token \"$token\""
)
}
private
fun
cancelSuggestions
(
haltCompletion
:
Boolean
)
{
...
...
app
/src/main/res/drawable/suggestions_menu_decorator.xml
→
suggestions
/src/main/res/drawable/suggestions_menu_decorator.xml
View file @
e89bc7cc
...
...
@@ -8,4 +8,4 @@
<size
android:height=
"2dp"
/>
</shape>
\ No newline at end of file
</shape>
suggestions/src/main/res/values/dimens.xml
0 → 100644
View file @
e89bc7cc
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen
name=
"popup_max_height"
>
150dp
</dimen>
<dimen
name=
"suggestions_box_max_height"
>
250dp
</dimen>
</resources>
\ No newline at end of file
suggestions/src/main/res/values/strings.xml
0 → 100644
View file @
e89bc7cc
<resources>
<string
name=
"app_name"
>
suggestions
</string>
</resources>
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