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
2e7a0037
Unverified
Commit
2e7a0037
authored
Mar 19, 2018
by
Leonardo Aramaki
Committed by
GitHub
Mar 19, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #918 from RocketChat/new/commands
[NEW] Commands
parents
d5fde6a3
f4f34ec5
Changes
18
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
359 additions
and
98 deletions
+359
-98
CommandSuggestionsAdapter.kt
...ket/android/chatroom/adapter/CommandSuggestionsAdapter.kt
+41
-0
PeopleSuggestionsAdapter.kt
...cket/android/chatroom/adapter/PeopleSuggestionsAdapter.kt
+2
-2
RoomSuggestionsAdapter.kt
...rocket/android/chatroom/adapter/RoomSuggestionsAdapter.kt
+2
-2
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+76
-30
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+12
-4
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+25
-12
ChatRoomViewModel.kt
...at/rocket/android/chatroom/viewmodel/ChatRoomViewModel.kt
+0
-9
PeopleViewModel.kt
...chat/rocket/android/chatroom/viewmodel/PeopleViewModel.kt
+0
-17
ChatRoomSuggestionViewModel.kt
...troom/viewmodel/suggestion/ChatRoomSuggestionViewModel.kt
+9
-0
CommandSuggestionViewModel.kt
...atroom/viewmodel/suggestion/CommandSuggestionViewModel.kt
+7
-0
PeopleSuggestionViewModel.kt
...hatroom/viewmodel/suggestion/PeopleSuggestionViewModel.kt
+17
-0
StringMatchingCompletionStrategy.kt
...letion/strategy/regex/StringMatchingCompletionStrategy.kt
+5
-4
SuggestionsAdapter.kt
...et/android/widget/autocompletion/ui/SuggestionsAdapter.kt
+44
-13
SuggestionsView.kt
...ocket/android/widget/autocompletion/ui/SuggestionsView.kt
+32
-5
suggestion_command_item.xml
app/src/main/res/layout/suggestion_command_item.xml
+39
-0
strings.xml
app/src/main/res/values-pt-rBR/strings.xml
+24
-0
dimens.xml
app/src/main/res/values/dimens.xml
+1
-0
strings.xml
app/src/main/res/values/strings.xml
+23
-0
No files found.
app/src/main/java/chat/rocket/android/chatroom/adapter/CommandSuggestionsAdapter.kt
0 → 100644
View file @
2e7a0037
package
chat.rocket.android.chatroom.adapter
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter.CommandSuggestionsViewHolder
import
chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder
import
chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter
class
CommandSuggestionsAdapter
:
SuggestionsAdapter
<
CommandSuggestionsViewHolder
>(
token
=
"/"
,
constraint
=
CONSTRAINT_BOUND_TO_START
,
threshold
=
UNLIMITED_RESULT_COUNT
)
{
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
CommandSuggestionsViewHolder
{
val
view
=
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
suggestion_command_item
,
parent
,
false
)
return
CommandSuggestionsViewHolder
(
view
)
}
class
CommandSuggestionsViewHolder
(
view
:
View
)
:
BaseSuggestionViewHolder
(
view
)
{
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
item
as
CommandSuggestionViewModel
with
(
itemView
)
{
val
nameTextView
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_command_name
)
val
descriptionTextView
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_command_description
)
nameTextView
.
text
=
"/${item.text}"
val
res
=
context
.
resources
val
id
=
res
.
getIdentifier
(
item
.
description
,
"string"
,
context
.
packageName
)
val
description
=
if
(
id
>
0
)
res
.
getString
(
id
)
else
""
descriptionTextView
.
text
=
description
.
toLowerCase
()
setOnClickListener
{
itemClickListener
?.
onClick
(
item
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/PeopleSuggestionsAdapter.kt
View file @
2e7a0037
...
@@ -8,7 +8,7 @@ import android.widget.ImageView
...
@@ -8,7 +8,7 @@ import android.widget.ImageView
import
android.widget.TextView
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter.PeopleSuggestionViewHolder
import
chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter.PeopleSuggestionViewHolder
import
chat.rocket.android.chatroom.viewmodel.
People
ViewModel
import
chat.rocket.android.chatroom.viewmodel.
suggestion.PeopleSuggestion
ViewModel
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder
import
chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder
...
@@ -26,7 +26,7 @@ class PeopleSuggestionsAdapter : SuggestionsAdapter<PeopleSuggestionViewHolder>(
...
@@ -26,7 +26,7 @@ class PeopleSuggestionsAdapter : SuggestionsAdapter<PeopleSuggestionViewHolder>(
class
PeopleSuggestionViewHolder
(
view
:
View
)
:
BaseSuggestionViewHolder
(
view
)
{
class
PeopleSuggestionViewHolder
(
view
:
View
)
:
BaseSuggestionViewHolder
(
view
)
{
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
item
as
PeopleViewModel
item
as
People
Suggestion
ViewModel
with
(
itemView
)
{
with
(
itemView
)
{
val
username
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_username
)
val
username
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_username
)
val
name
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_name
)
val
name
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_name
)
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/RoomSuggestionsAdapter.kt
View file @
2e7a0037
...
@@ -6,7 +6,7 @@ import android.view.ViewGroup
...
@@ -6,7 +6,7 @@ import android.view.ViewGroup
import
android.widget.TextView
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter.RoomSuggestionsViewHolder
import
chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter.RoomSuggestionsViewHolder
import
chat.rocket.android.chatroom.viewmodel.
ChatRoom
ViewModel
import
chat.rocket.android.chatroom.viewmodel.
suggestion.ChatRoomSuggestion
ViewModel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder
import
chat.rocket.android.widget.autocompletion.ui.BaseSuggestionViewHolder
import
chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter
import
chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter
...
@@ -22,7 +22,7 @@ class RoomSuggestionsAdapter : SuggestionsAdapter<RoomSuggestionsViewHolder>("#"
...
@@ -22,7 +22,7 @@ class RoomSuggestionsAdapter : SuggestionsAdapter<RoomSuggestionsViewHolder>("#"
class
RoomSuggestionsViewHolder
(
view
:
View
)
:
BaseSuggestionViewHolder
(
view
)
{
class
RoomSuggestionsViewHolder
(
view
:
View
)
:
BaseSuggestionViewHolder
(
view
)
{
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
item
as
ChatRoomViewModel
item
as
ChatRoom
Suggestion
ViewModel
with
(
itemView
)
{
with
(
itemView
)
{
val
fullname
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_fullname
)
val
fullname
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_fullname
)
val
name
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_name
)
val
name
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_name
)
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
2e7a0037
This diff is collapsed.
Click to expand it.
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
2e7a0037
...
@@ -2,8 +2,9 @@ package chat.rocket.android.chatroom.presentation
...
@@ -2,8 +2,9 @@ package chat.rocket.android.chatroom.presentation
import
android.net.Uri
import
android.net.Uri
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.chatroom.viewmodel.ChatRoomViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.PeopleViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import
chat.rocket.android.core.behaviours.LoadingView
import
chat.rocket.android.core.behaviours.LoadingView
import
chat.rocket.android.core.behaviours.MessageView
import
chat.rocket.android.core.behaviours.MessageView
import
chat.rocket.core.internal.realtime.State
import
chat.rocket.core.internal.realtime.State
...
@@ -102,12 +103,19 @@ interface ChatRoomView : LoadingView, MessageView {
...
@@ -102,12 +103,19 @@ interface ChatRoomView : LoadingView, MessageView {
fun
showInvalidFileSize
(
fileSize
:
Int
,
maxFileSize
:
Int
)
fun
showInvalidFileSize
(
fileSize
:
Int
,
maxFileSize
:
Int
)
fun
showConnectionState
(
state
:
State
)
fun
showConnectionState
(
state
:
State
)
fun
populate
Members
(
members
:
List
<
People
ViewModel
>)
fun
populate
PeopleSuggestions
(
members
:
List
<
PeopleSuggestion
ViewModel
>)
fun
populateRoom
s
(
chatRooms
:
List
<
ChatRoom
ViewModel
>)
fun
populateRoom
Suggestions
(
chatRooms
:
List
<
ChatRoomSuggestion
ViewModel
>)
/**
/**
* This user has joined the chat callback.
* This user has joined the chat callback.
*/
*/
fun
onJoined
()
fun
onJoined
()
fun
showReactionsPopup
(
messageId
:
String
)
fun
showReactionsPopup
(
messageId
:
String
)
/**
* Show list of commands.
*
* @param commands The list of available commands.
*/
fun
populateCommandSuggestions
(
commands
:
List
<
CommandSuggestionViewModel
>)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
2e7a0037
...
@@ -15,16 +15,14 @@ import android.support.v7.widget.LinearLayoutManager
...
@@ -15,16 +15,14 @@ import android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.RecyclerView
import
android.support.v7.widget.RecyclerView
import
android.view.*
import
android.view.*
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import
chat.rocket.android.chatroom.adapter.*
import
chat.rocket.android.chatroom.adapter.PEOPLE
import
chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter
import
chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.presentation.ChatRoomView
import
chat.rocket.android.chatroom.presentation.ChatRoomView
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.chatroom.viewmodel.ChatRoomViewModel
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.chatroom.viewmodel.PeopleViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import
chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import
chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.helper.MessageParser
...
@@ -218,7 +216,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -218,7 +216,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
sendMessage
(
text
:
String
)
{
override
fun
sendMessage
(
text
:
String
)
{
if
(!
text
.
isBlank
())
{
if
(!
text
.
isBlank
())
{
presenter
.
sendMessage
(
chatRoomId
,
text
,
editingMessageId
)
if
(!
text
.
startsWith
(
"/"
))
{
presenter
.
sendMessage
(
chatRoomId
,
text
,
editingMessageId
)
}
else
{
presenter
.
runCommand
(
text
,
chatRoomId
)
}
}
}
}
}
...
@@ -287,14 +289,18 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -287,14 +289,18 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
populate
Members
(
members
:
List
<
People
ViewModel
>)
{
override
fun
populate
PeopleSuggestions
(
members
:
List
<
PeopleSuggestion
ViewModel
>)
{
suggestions_view
.
addItems
(
"@"
,
members
)
suggestions_view
.
addItems
(
"@"
,
members
)
}
}
override
fun
populateRoom
s
(
chatRooms
:
List
<
ChatRoom
ViewModel
>)
{
override
fun
populateRoom
Suggestions
(
chatRooms
:
List
<
ChatRoomSuggestion
ViewModel
>)
{
suggestions_view
.
addItems
(
"#"
,
chatRooms
)
suggestions_view
.
addItems
(
"#"
,
chatRooms
)
}
}
override
fun
populateCommandSuggestions
(
commands
:
List
<
CommandSuggestionViewModel
>)
{
suggestions_view
.
addItems
(
"/"
,
commands
)
}
override
fun
copyToClipboard
(
message
:
String
)
{
override
fun
copyToClipboard
(
message
:
String
)
{
activity
?.
apply
{
activity
?.
apply
{
val
clipboard
=
getSystemService
(
Context
.
CLIPBOARD_SERVICE
)
as
ClipboardManager
val
clipboard
=
getSystemService
(
Context
.
CLIPBOARD_SERVICE
)
as
ClipboardManager
...
@@ -492,9 +498,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -492,9 +498,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
private
fun
setupSuggestionsView
()
{
private
fun
setupSuggestionsView
()
{
suggestions_view
.
anchor
(
text_message
)
suggestions_view
.
anchorTo
(
text_message
)
.
bindTokenAdapter
(
PeopleSuggestionsAdapter
())
.
setMaximumHeight
(
resources
.
getDimensionPixelSize
(
R
.
dimen
.
suggestions_box_max_height
))
.
bindTokenAdapter
(
RoomSuggestionsAdapter
())
.
addTokenAdapter
(
PeopleSuggestionsAdapter
())
.
addTokenAdapter
(
CommandSuggestionsAdapter
())
.
addTokenAdapter
(
RoomSuggestionsAdapter
())
.
addSuggestionProviderAction
(
"@"
)
{
query
->
.
addSuggestionProviderAction
(
"@"
)
{
query
->
if
(
query
.
isNotEmpty
())
{
if
(
query
.
isNotEmpty
())
{
presenter
.
spotlight
(
query
,
PEOPLE
,
true
)
presenter
.
spotlight
(
query
,
PEOPLE
,
true
)
...
@@ -505,6 +513,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -505,6 +513,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
presenter
.
loadChatRooms
()
presenter
.
loadChatRooms
()
}
}
}
}
.
addSuggestionProviderAction
(
"/"
)
{
_
->
presenter
.
loadCommands
()
}
presenter
.
loadCommands
()
}
}
private
fun
openEmojiKeyboardPopup
()
{
private
fun
openEmojiKeyboardPopup
()
{
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ChatRoomViewModel.kt
deleted
100644 → 0
View file @
d5fde6a3
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
class
ChatRoomViewModel
(
text
:
String
,
val
fullName
:
String
,
val
name
:
String
,
searchList
:
List
<
String
>)
:
SuggestionModel
(
text
,
searchList
,
false
)
{
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/PeopleViewModel.kt
deleted
100644 → 0
View file @
d5fde6a3
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.common.model.UserStatus
class
PeopleViewModel
(
val
imageUri
:
String
,
text
:
String
,
val
username
:
String
,
val
name
:
String
,
val
status
:
UserStatus
?,
pinned
:
Boolean
=
false
,
searchList
:
List
<
String
>)
:
SuggestionModel
(
text
,
searchList
,
pinned
)
{
override
fun
toString
():
String
{
return
"PeopleViewModel(imageUri='$imageUri', username='$username', name='$name', status=$status, pinned=$pinned)"
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/suggestion/ChatRoomSuggestionViewModel.kt
0 → 100644
View file @
2e7a0037
package
chat.rocket.android.chatroom.viewmodel.suggestion
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
class
ChatRoomSuggestionViewModel
(
text
:
String
,
val
fullName
:
String
,
val
name
:
String
,
searchList
:
List
<
String
>)
:
SuggestionModel
(
text
,
searchList
,
false
)
{
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/suggestion/CommandSuggestionViewModel.kt
0 → 100644
View file @
2e7a0037
package
chat.rocket.android.chatroom.viewmodel.suggestion
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
class
CommandSuggestionViewModel
(
text
:
String
,
val
description
:
String
,
searchList
:
List
<
String
>)
:
SuggestionModel
(
text
,
searchList
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/suggestion/PeopleSuggestionViewModel.kt
0 → 100644
View file @
2e7a0037
package
chat.rocket.android.chatroom.viewmodel.suggestion
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.common.model.UserStatus
class
PeopleSuggestionViewModel
(
val
imageUri
:
String
,
text
:
String
,
val
username
:
String
,
val
name
:
String
,
val
status
:
UserStatus
?,
pinned
:
Boolean
=
false
,
searchList
:
List
<
String
>)
:
SuggestionModel
(
text
,
searchList
,
pinned
)
{
override
fun
toString
():
String
{
return
"PeopleSuggestionViewModel(imageUri='$imageUri', username='$username', name='$name', status=$status, pinned=$pinned)"
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/autocompletion/strategy/regex/StringMatchingCompletionStrategy.kt
View file @
2e7a0037
...
@@ -2,24 +2,25 @@ package chat.rocket.android.widget.autocompletion.strategy.regex
...
@@ -2,24 +2,25 @@ package chat.rocket.android.widget.autocompletion.strategy.regex
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.strategy.CompletionStrategy
import
chat.rocket.android.widget.autocompletion.strategy.CompletionStrategy
import
chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter
import
java.util.concurrent.CopyOnWriteArrayList
import
java.util.concurrent.CopyOnWriteArrayList
internal
class
StringMatchingCompletionStrategy
:
CompletionStrategy
{
internal
class
StringMatchingCompletionStrategy
(
private
val
threshold
:
Int
=
-
1
)
:
CompletionStrategy
{
private
val
list
=
CopyOnWriteArrayList
<
SuggestionModel
>()
private
val
list
=
CopyOnWriteArrayList
<
SuggestionModel
>()
override
fun
autocompleteItems
(
prefix
:
String
):
List
<
SuggestionModel
>
{
override
fun
autocompleteItems
(
prefix
:
String
):
List
<
SuggestionModel
>
{
return
list
.
filter
{
val
result
=
list
.
filter
{
it
.
searchList
.
forEach
{
word
->
it
.
searchList
.
forEach
{
word
->
if
(
word
.
contains
(
prefix
,
ignoreCase
=
true
))
{
if
(
word
.
contains
(
prefix
,
ignoreCase
=
true
))
{
return
@filter
true
return
@filter
true
}
}
}
}
false
false
}.
sortedByDescending
{
it
.
pinned
}.
take
(
5
)
}.
sortedByDescending
{
it
.
pinned
}
return
if
(
threshold
==
SuggestionsAdapter
.
UNLIMITED_RESULT_COUNT
)
result
else
result
.
take
(
threshold
)
}
}
override
fun
addAll
(
list
:
List
<
SuggestionModel
>)
{
override
fun
addAll
(
list
:
List
<
SuggestionModel
>)
{
// this.list.removeAll { !it.pinned }
this
.
list
.
addAllAbsent
(
list
)
this
.
list
.
addAllAbsent
(
list
)
}
}
...
...
app/src/main/java/chat/rocket/android/widget/autocompletion/ui/SuggestionsAdapter.kt
View file @
2e7a0037
...
@@ -7,14 +7,32 @@ import chat.rocket.android.widget.autocompletion.strategy.regex.StringMatchingCo
...
@@ -7,14 +7,32 @@ import chat.rocket.android.widget.autocompletion.strategy.regex.StringMatchingCo
import
java.lang.reflect.Type
import
java.lang.reflect.Type
import
kotlin.properties.Delegates
import
kotlin.properties.Delegates
abstract
class
SuggestionsAdapter
<
VH
:
BaseSuggestionViewHolder
>(
val
token
:
String
)
:
RecyclerView
.
Adapter
<
VH
>()
{
abstract
class
SuggestionsAdapter
<
VH
:
BaseSuggestionViewHolder
>(
private
val
strategy
:
CompletionStrategy
=
StringMatchingCompletionStrategy
()
val
token
:
String
,
val
constraint
:
Int
=
CONSTRAINT_UNBOUND
,
threshold
:
Int
=
MAX_RESULT_COUNT
)
:
RecyclerView
.
Adapter
<
VH
>()
{
companion
object
{
// Any number of results.
const
val
UNLIMITED_RESULT_COUNT
=
-
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
itemType
:
Type
?
=
null
private
var
itemClickListener
:
ItemClickListener
?
=
null
private
var
itemClickListener
:
ItemClickListener
?
=
null
// Called to gather results when no results have previously matched.
private
var
providerExternal
:
((
query
:
String
)
->
Unit
)?
=
null
private
var
providerExternal
:
((
query
:
String
)
->
Unit
)?
=
null
private
var
prefix
:
String
by
Delegates
.
observable
(
""
,
{
_
,
_
,
_
->
// Maximum number of results/suggestions to display.
strategy
.
autocompleteItems
(
prefix
)
private
var
resultsThreshold
:
Int
=
if
(
threshold
>
0
)
threshold
else
UNLIMITED_RESULT_COUNT
notifyItemRangeChanged
(
0
,
5
)
// The strategy used for suggesting completions.
private
val
strategy
:
CompletionStrategy
=
StringMatchingCompletionStrategy
(
resultsThreshold
)
// Current input term to look up for suggestions.
private
var
currentTerm
:
String
by
Delegates
.
observable
(
""
,
{
_
,
_
,
newTerm
->
val
items
=
strategy
.
autocompleteItems
(
newTerm
)
notifyDataSetChanged
()
})
})
init
{
init
{
...
@@ -29,21 +47,21 @@ abstract class SuggestionsAdapter<VH : BaseSuggestionViewHolder>(val token: Stri
...
@@ -29,21 +47,21 @@ abstract class SuggestionsAdapter<VH : BaseSuggestionViewHolder>(val token: Stri
holder
.
bind
(
getItem
(
position
),
itemClickListener
)
holder
.
bind
(
getItem
(
position
),
itemClickListener
)
}
}
override
fun
getItemCount
()
=
strategy
.
autocompleteItems
(
prefix
).
size
override
fun
getItemCount
()
=
strategy
.
autocompleteItems
(
currentTerm
).
size
private
fun
getItem
(
position
:
Int
):
SuggestionModel
{
private
fun
getItem
(
position
:
Int
):
SuggestionModel
{
return
strategy
.
autocompleteItems
(
prefix
)[
position
]
return
strategy
.
autocompleteItems
(
currentTerm
)[
position
]
}
}
fun
autocomplete
(
prefix
:
String
)
{
fun
autocomplete
(
newTerm
:
String
)
{
this
.
prefix
=
prefix
.
toLowerCase
().
trim
()
this
.
currentTerm
=
newTerm
.
toLowerCase
().
trim
()
}
}
fun
addItems
(
list
:
List
<
SuggestionModel
>)
{
fun
addItems
(
list
:
List
<
SuggestionModel
>)
{
strategy
.
addAll
(
list
)
strategy
.
addAll
(
list
)
// Since we've just added new items we should check for possible new completion suggestions.
// Since we've just added new items we should check for possible new completion suggestions.
strategy
.
autocompleteItems
(
prefix
)
strategy
.
autocompleteItems
(
currentTerm
)
notify
ItemRangeChanged
(
0
,
5
)
notify
DataSetChanged
(
)
}
}
fun
setOnClickListener
(
clickListener
:
ItemClickListener
)
{
fun
setOnClickListener
(
clickListener
:
ItemClickListener
)
{
...
@@ -52,11 +70,24 @@ abstract class SuggestionsAdapter<VH : BaseSuggestionViewHolder>(val token: Stri
...
@@ -52,11 +70,24 @@ abstract class SuggestionsAdapter<VH : BaseSuggestionViewHolder>(val token: Stri
fun
hasItemClickListener
()
=
itemClickListener
!=
null
fun
hasItemClickListener
()
=
itemClickListener
!=
null
fun
prefix
()
=
prefix
/**
* Return the current searched term.
*/
fun
term
()
=
this
.
currentTerm
/**
* Set the maximum number of results to show.
*
* @param threshold The maximum number of suggestions to display.
*/
fun
setResultsThreshold
(
threshold
:
Int
)
{
check
(
threshold
>
0
)
resultsThreshold
=
threshold
}
fun
cancel
()
{
fun
cancel
()
{
strategy
.
addAll
(
emptyList
())
strategy
.
addAll
(
emptyList
())
strategy
.
autocompleteItems
(
prefix
)
strategy
.
autocompleteItems
(
currentTerm
)
notifyDataSetChanged
()
notifyDataSetChanged
()
}
}
...
...
app/src/main/java/chat/rocket/android/widget/autocompletion/ui/SuggestionsView.kt
View file @
2e7a0037
...
@@ -21,7 +21,9 @@ import android.widget.EditText
...
@@ -21,7 +21,9 @@ import android.widget.EditText
import
android.widget.FrameLayout
import
android.widget.FrameLayout
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.ui.SuggestionsAdapter.Companion.CONSTRAINT_BOUND_TO_START
import
java.lang.ref.WeakReference
import
java.lang.ref.WeakReference
import
java.util.concurrent.CopyOnWriteArrayList
import
java.util.concurrent.atomic.AtomicInteger
import
java.util.concurrent.atomic.AtomicInteger
/**
/**
...
@@ -31,12 +33,14 @@ private const val NO_STATE_INDEX = 0
...
@@ -31,12 +33,14 @@ private const val NO_STATE_INDEX = 0
class
SuggestionsView
:
FrameLayout
,
TextWatcher
{
class
SuggestionsView
:
FrameLayout
,
TextWatcher
{
private
val
recyclerView
:
RecyclerView
private
val
recyclerView
:
RecyclerView
private
val
registeredTokens
=
CopyOnWriteArrayList
<
String
>()
// Maps tokens to their respective adapters.
// Maps tokens to their respective adapters.
private
val
adaptersByToken
=
hashMapOf
<
String
,
SuggestionsAdapter
<
out
BaseSuggestionViewHolder
>>()
private
val
adaptersByToken
=
hashMapOf
<
String
,
SuggestionsAdapter
<
out
BaseSuggestionViewHolder
>>()
private
val
externalProvidersByToken
=
hashMapOf
<
String
,
((
query
:
String
)
->
Unit
)>()
private
val
externalProvidersByToken
=
hashMapOf
<
String
,
((
query
:
String
)
->
Unit
)>()
private
val
localProvidersByToken
=
hashMapOf
<
String
,
HashMap
<
String
,
List
<
SuggestionModel
>>>()
private
val
localProvidersByToken
=
hashMapOf
<
String
,
HashMap
<
String
,
List
<
SuggestionModel
>>>()
private
var
editor
:
WeakReference
<
EditText
>?
=
null
private
var
editor
:
WeakReference
<
EditText
>?
=
null
private
var
completionStartIndex
=
AtomicInteger
(
NO_STATE_INDEX
)
private
var
completionStartIndex
=
AtomicInteger
(
NO_STATE_INDEX
)
private
var
maxHeight
:
Int
=
0
companion
object
{
companion
object
{
private
val
SLIDE_TRANSITION
=
Slide
(
Gravity
.
BOTTOM
).
setDuration
(
200
)
private
val
SLIDE_TRANSITION
=
Slide
(
Gravity
.
BOTTOM
).
setDuration
(
200
)
...
@@ -75,6 +79,10 @@ class SuggestionsView : FrameLayout, TextWatcher {
...
@@ -75,6 +79,10 @@ class SuggestionsView : FrameLayout, TextWatcher {
val
new
=
s
.
subSequence
(
start
,
start
+
count
).
toString
()
val
new
=
s
.
subSequence
(
start
,
start
+
count
).
toString
()
if
(
adaptersByToken
.
containsKey
(
new
))
{
if
(
adaptersByToken
.
containsKey
(
new
))
{
val
constraint
=
adapter
(
new
).
constraint
if
(
constraint
==
CONSTRAINT_BOUND_TO_START
&&
start
!=
0
)
{
return
}
swapAdapter
(
getAdapterForToken
(
new
)
!!
)
swapAdapter
(
getAdapterForToken
(
new
)
!!
)
completionStartIndex
.
compareAndSet
(
NO_STATE_INDEX
,
start
+
1
)
completionStartIndex
.
compareAndSet
(
NO_STATE_INDEX
,
start
+
1
)
editor
?.
let
{
editor
?.
let
{
...
@@ -110,9 +118,18 @@ class SuggestionsView : FrameLayout, TextWatcher {
...
@@ -110,9 +118,18 @@ class SuggestionsView : FrameLayout, TextWatcher {
}
}
}
}
override
fun
onMeasure
(
widthMeasureSpec
:
Int
,
heightMeasureSpec
:
Int
)
{
if
(
maxHeight
>
0
)
{
val
hSpec
=
MeasureSpec
.
makeMeasureSpec
(
maxHeight
,
MeasureSpec
.
AT_MOST
)
super
.
onMeasure
(
widthMeasureSpec
,
hSpec
)
}
else
{
super
.
onMeasure
(
widthMeasureSpec
,
heightMeasureSpec
)
}
}
private
fun
swapAdapter
(
adapter
:
SuggestionsAdapter
<
*
>):
SuggestionsView
{
private
fun
swapAdapter
(
adapter
:
SuggestionsAdapter
<
*
>):
SuggestionsView
{
recyclerView
.
adapter
=
adapter
recyclerView
.
adapter
=
adapter
// Don't override if user
set an item click listener already/
// Don't override if user
has set an item click listener already
if
(!
adapter
.
hasItemClickListener
())
{
if
(!
adapter
.
hasItemClickListener
())
{
setOnItemClickListener
(
adapter
)
{
setOnItemClickListener
(
adapter
)
{
// set default item click behavior
// set default item click behavior
...
@@ -121,16 +138,16 @@ class SuggestionsView : FrameLayout, TextWatcher {
...
@@ -121,16 +138,16 @@ class SuggestionsView : FrameLayout, TextWatcher {
return
this
return
this
}
}
fun
getAdapterForToken
(
token
:
String
):
SuggestionsAdapter
<
*
>?
=
adaptersByToken
.
get
(
token
)
private
fun
getAdapterForToken
(
token
:
String
):
SuggestionsAdapter
<
*
>?
=
adaptersByToken
.
get
(
token
)
fun
anchor
(
editText
:
EditText
):
SuggestionsView
{
fun
anchor
To
(
editText
:
EditText
):
SuggestionsView
{
editText
.
removeTextChangedListener
(
this
)
editText
.
removeTextChangedListener
(
this
)
editText
.
addTextChangedListener
(
this
)
editText
.
addTextChangedListener
(
this
)
editor
=
WeakReference
(
editText
)
editor
=
WeakReference
(
editText
)
return
this
return
this
}
}
fun
bin
dTokenAdapter
(
adapter
:
SuggestionsAdapter
<
*
>):
SuggestionsView
{
fun
ad
dTokenAdapter
(
adapter
:
SuggestionsAdapter
<
*
>):
SuggestionsView
{
adaptersByToken
.
getOrPut
(
adapter
.
token
,
{
adapter
})
adaptersByToken
.
getOrPut
(
adapter
.
token
,
{
adapter
})
return
this
return
this
}
}
...
@@ -139,13 +156,20 @@ class SuggestionsView : FrameLayout, TextWatcher {
...
@@ -139,13 +156,20 @@ class SuggestionsView : FrameLayout, TextWatcher {
if
(
list
.
isNotEmpty
())
{
if
(
list
.
isNotEmpty
())
{
val
adapter
=
adapter
(
token
)
val
adapter
=
adapter
(
token
)
localProvidersByToken
.
getOrPut
(
token
,
{
hashMapOf
()
})
localProvidersByToken
.
getOrPut
(
token
,
{
hashMapOf
()
})
.
put
(
adapter
.
prefix
(),
list
)
.
put
(
adapter
.
term
(),
list
)
if
(
completionStartIndex
.
get
()
>
NO_STATE_INDEX
&&
adapter
.
itemCount
==
0
)
expand
()
if
(
completionStartIndex
.
get
()
>
NO_STATE_INDEX
&&
adapter
.
itemCount
==
0
)
expand
()
adapter
.
addItems
(
list
)
adapter
.
addItems
(
list
)
}
}
return
this
return
this
}
}
fun
setMaximumHeight
(
height
:
Int
):
SuggestionsView
{
check
(
height
>
0
)
this
.
maxHeight
=
height
requestLayout
()
return
this
}
fun
setOnItemClickListener
(
tokenAdapter
:
SuggestionsAdapter
<
*
>,
fun
setOnItemClickListener
(
tokenAdapter
:
SuggestionsAdapter
<
*
>,
clickListener
:
(
item
:
SuggestionModel
)
->
Unit
):
SuggestionsView
{
clickListener
:
(
item
:
SuggestionModel
)
->
Unit
):
SuggestionsView
{
tokenAdapter
.
setOnClickListener
(
object
:
SuggestionsAdapter
.
ItemClickListener
{
tokenAdapter
.
setOnClickListener
(
object
:
SuggestionsAdapter
.
ItemClickListener
{
...
@@ -160,6 +184,9 @@ class SuggestionsView : FrameLayout, TextWatcher {
...
@@ -160,6 +184,9 @@ class SuggestionsView : FrameLayout, TextWatcher {
}
}
fun
addSuggestionProviderAction
(
token
:
String
,
provider
:
(
query
:
String
)
->
Unit
):
SuggestionsView
{
fun
addSuggestionProviderAction
(
token
:
String
,
provider
:
(
query
:
String
)
->
Unit
):
SuggestionsView
{
if
(
adaptersByToken
[
token
]
==
null
)
{
throw
IllegalStateException
(
"token \"$token\" suggestion provider added without adapter"
)
}
externalProvidersByToken
.
getOrPut
(
token
,
{
provider
})
externalProvidersByToken
.
getOrPut
(
token
,
{
provider
})
return
this
return
this
}
}
...
...
app/src/main/res/layout/suggestion_command_item.xml
0 → 100644
View file @
2e7a0037
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"4dp"
android:layout_marginTop=
"4dp"
android:background=
"@color/suggestion_background_color"
android:orientation=
"horizontal"
android:paddingTop=
"2dp"
>
<TextView
android:id=
"@+id/text_command_name"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_alignParentLeft=
"true"
android:layout_alignParentStart=
"true"
android:layout_marginStart=
"8dp"
android:ellipsize=
"end"
android:maxLines=
"1"
android:textColor=
"@color/black"
android:textSize=
"14sp"
tools:text=
"/leave"
/>
<TextView
android:id=
"@+id/text_command_description"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"8dp"
android:layout_marginStart=
"16dp"
android:layout_toRightOf=
"@id/text_command_name"
android:ellipsize=
"end"
android:gravity=
"start"
android:maxLines=
"1"
android:textColor=
"@color/gray_material"
android:textSize=
"14sp"
tools:text=
"Leave a channel"
/>
</RelativeLayout>
\ No newline at end of file
app/src/main/res/values-pt-rBR/strings.xml
View file @
2e7a0037
...
@@ -114,4 +114,28 @@
...
@@ -114,4 +114,28 @@
<string
name=
"status_authenticating"
>
autenticando
</string>
<string
name=
"status_authenticating"
>
autenticando
</string>
<string
name=
"status_disconnecting"
>
desconectando
</string>
<string
name=
"status_disconnecting"
>
desconectando
</string>
<string
name=
"status_waiting"
>
conectando em %d segundos
</string>
<string
name=
"status_waiting"
>
conectando em %d segundos
</string>
<!-- Slash Commands -->
<string
name=
"Slash_Gimme_Description"
>
Exibir ༼ つ ◕_◕ ༽つ antes de sua mensagem
</string>
<string
name=
"Slash_LennyFace_Description"
>
Exibir ( ͡° ͜ʖ ͡°) depois de sua mensagem
</string>
<string
name=
"Slash_Shrug_Description"
>
Exibir ¯\_(ツ)_/¯ depois de sua mensagem
</string>
<string
name=
"Slash_Tableflip_Description"
>
Exibir (╯°□°)╯︵ ┻━┻
</string>
<string
name=
"Slash_TableUnflip_Description"
>
Exibir ┬─┬ ノ( ゜-゜ノ)
</string>
<string
name=
"Create_A_New_Channel"
>
Criar um novo canal
</string>
<string
name=
"Show_the_keyboard_shortcut_list"
>
Show the keyboard shortcut list
</string>
<string
name=
"Invite_user_to_join_channel_all_from"
>
do [#canal] para entrar neste
</string>
<string
name=
"Invite_user_to_join_channel_all_to"
>
Convidar todos os usuários deste canal para entrar no [#canal]
</string>
<string
name=
"Archive"
>
Arquivar
</string>
<string
name=
"Remove_someone_from_room"
>
Remover alguém do canal
</string>
<string
name=
"Leave_the_current_channel"
>
Sair do canal atual
</string>
<string
name=
"Displays_action_text"
>
Exibir texto de ação
</string>
<string
name=
"Direct_message_someone"
>
Enviar DM para alguém
</string>
<string
name=
"Mute_someone_in_room"
>
Mutar alguém
</string>
<string
name=
"Unmute_someone_in_room"
>
Desmutar alguém na sala
</string>
<string
name=
"Invite_user_to_join_channel"
>
Convidar algum usuário para entrar neste canal
</string>
<string
name=
"Unarchive"
>
Desarquivar
</string>
<string
name=
"Join_the_given_channel"
>
Entrar no canal especificado
</string>
<string
name=
"Guggy_Command_Description"
>
Gera um gif baseado no texto dado
</string>
<string
name=
"Slash_Topic_Description"
>
Definir tópico
</string>
</resources>
</resources>
\ No newline at end of file
app/src/main/res/values/dimens.xml
View file @
2e7a0037
...
@@ -34,5 +34,6 @@
...
@@ -34,5 +34,6 @@
<!-- Autocomplete Popup -->
<!-- Autocomplete Popup -->
<dimen
name=
"popup_max_height"
>
150dp
</dimen>
<dimen
name=
"popup_max_height"
>
150dp
</dimen>
<dimen
name=
"suggestions_box_max_height"
>
250dp
</dimen>
</resources>
</resources>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
2e7a0037
...
@@ -116,4 +116,27 @@
...
@@ -116,4 +116,27 @@
<string
name=
"status_disconnecting"
>
disconnecting
</string>
<string
name=
"status_disconnecting"
>
disconnecting
</string>
<string
name=
"status_waiting"
>
connecting in %d seconds
</string>
<string
name=
"status_waiting"
>
connecting in %d seconds
</string>
<!-- Slash Commands -->
<string
name=
"Slash_Gimme_Description"
>
Displays ༼ つ ◕_◕ ༽つ before your message
</string>
<string
name=
"Slash_LennyFace_Description"
>
Displays ( ͡° ͜ʖ ͡°) after your message
</string>
<string
name=
"Slash_Shrug_Description"
>
Displays ¯\_(ツ)_/¯ after your message
</string>
<string
name=
"Slash_Tableflip_Description"
>
Displays (╯°□°)╯︵ ┻━┻
</string>
<string
name=
"Slash_TableUnflip_Description"
>
Displays ┬─┬ ノ( ゜-゜ノ)
</string>
<string
name=
"Create_A_New_Channel"
>
Create a new channel
</string>
<string
name=
"Show_the_keyboard_shortcut_list"
>
Show the keyboard shortcut list
</string>
<string
name=
"Invite_user_to_join_channel_all_from"
>
Invite all users from [#channel] to join this channel
</string>
<string
name=
"Invite_user_to_join_channel_all_to"
>
Invite all users from this channel to join [#channel]
</string>
<string
name=
"Archive"
>
Archive
</string>
<string
name=
"Remove_someone_from_room"
>
Remove someone from the room
</string>
<string
name=
"Leave_the_current_channel"
>
Leave the current channel
</string>
<string
name=
"Displays_action_text"
>
Displays action text
</string>
<string
name=
"Direct_message_someone"
>
Direct message someone
</string>
<string
name=
"Mute_someone_in_room"
>
Mute someone in the room
</string>
<string
name=
"Unmute_someone_in_room"
>
Unmute someone in the room
</string>
<string
name=
"Invite_user_to_join_channel"
>
Invite one user to join this channel
</string>
<string
name=
"Unarchive"
>
Unarchive
</string>
<string
name=
"Join_the_given_channel"
>
Join the given channel
</string>
<string
name=
"Guggy_Command_Description"
>
Generates a gif based upon the provided text
</string>
<string
name=
"Slash_Topic_Description"
>
Set topic
</string>
</resources>
</resources>
\ No newline at end of file
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