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
00ac09d2
Commit
00ac09d2
authored
Mar 01, 2018
by
Leonardo Aramaki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Implement autocompletion for users
parent
1cb3f896
Changes
38
Show whitespace changes
Inline
Side-by-side
Showing
38 changed files
with
1124 additions
and
39 deletions
+1124
-39
DrawableHelper.kt
app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
+7
-6
User.kt
app/src/main/java/chat/rocket/android/app/User.kt
+0
-7
SignupFragment.kt
...rocket/android/authentication/signup/ui/SignupFragment.kt
+5
-5
AutoCompleteType.kt
.../chat/rocket/android/chatroom/adapter/AutoCompleteType.kt
+10
-0
PeopleSuggestionsAdapter.kt
...cket/android/chatroom/adapter/PeopleSuggestionsAdapter.kt
+52
-0
RoomSuggestionsAdapter.kt
...rocket/android/chatroom/adapter/RoomSuggestionsAdapter.kt
+37
-0
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+93
-2
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+4
-0
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+30
-5
PeopleViewModel.kt
...chat/rocket/android/chatroom/viewmodel/PeopleViewModel.kt
+17
-0
RoomViewModel.kt
...a/chat/rocket/android/chatroom/viewmodel/RoomViewModel.kt
+9
-0
AppModule.kt
.../main/java/chat/rocket/android/dagger/module/AppModule.kt
+13
-1
ProfileFragment.kt
...in/java/chat/rocket/android/profile/ui/ProfileFragment.kt
+5
-6
MessagesRepository.kt
...a/chat/rocket/android/server/domain/MessagesRepository.kt
+12
-0
RoomRepository.kt
.../java/chat/rocket/android/server/domain/RoomRepository.kt
+41
-0
UsersRepository.kt
...java/chat/rocket/android/server/domain/UsersRepository.kt
+42
-0
MemoryMessagesRepository.kt
...ndroid/server/infraestructure/MemoryMessagesRepository.kt
+5
-0
MemoryRoomRepository.kt
...et/android/server/infraestructure/MemoryRoomRepository.kt
+38
-0
MemoryUsersRepository.kt
...t/android/server/infraestructure/MemoryUsersRepository.kt
+39
-0
SuggestionModel.kt
...et/android/widget/autocompletion/model/SuggestionModel.kt
+18
-0
LocalSuggestionProvider.kt
...dget/autocompletion/repository/LocalSuggestionProvider.kt
+5
-0
CompletionStrategy.kt
...roid/widget/autocompletion/strategy/CompletionStrategy.kt
+10
-0
StringMatchingCompletionStrategy.kt
...letion/strategy/regex/StringMatchingCompletionStrategy.kt
+33
-0
TrieCompletionStrategy.kt
...et/autocompletion/strategy/trie/TrieCompletionStrategy.kt
+31
-0
Trie.kt
.../android/widget/autocompletion/strategy/trie/data/Trie.kt
+70
-0
TrieNode.kt
...roid/widget/autocompletion/strategy/trie/data/TrieNode.kt
+47
-0
BaseSuggestionViewHolder.kt
...roid/widget/autocompletion/ui/BaseSuggestionViewHolder.kt
+9
-0
PopupRecyclerView.kt
...ket/android/widget/autocompletion/ui/PopupRecyclerView.kt
+35
-0
SuggestionsAdapter.kt
...et/android/widget/autocompletion/ui/SuggestionsAdapter.kt
+66
-0
SuggestionsView.kt
...ocket/android/widget/autocompletion/ui/SuggestionsView.kt
+194
-0
user_status_white.xml
app/src/main/res/drawable/user_status_white.xml
+12
-0
fragment_authentication_sign_up.xml
app/src/main/res/layout/fragment_authentication_sign_up.xml
+2
-2
fragment_chat_room.xml
app/src/main/res/layout/fragment_chat_room.xml
+12
-4
fragment_profile.xml
app/src/main/res/layout/fragment_profile.xml
+1
-1
suggestion_member_item.xml
app/src/main/res/layout/suggestion_member_item.xml
+69
-0
suggestion_room_item.xml
app/src/main/res/layout/suggestion_room_item.xml
+45
-0
colors.xml
app/src/main/res/values/colors.xml
+3
-0
dimens.xml
app/src/main/res/values/dimens.xml
+3
-0
No files found.
app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
View file @
00ac09d2
...
@@ -5,6 +5,7 @@ import android.support.v4.graphics.drawable.DrawableCompat
...
@@ -5,6 +5,7 @@ import android.support.v4.graphics.drawable.DrawableCompat
import
android.widget.EditText
import
android.widget.EditText
import
android.widget.TextView
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.common.model.UserStatus
object
DrawableHelper
{
object
DrawableHelper
{
...
@@ -104,15 +105,15 @@ object DrawableHelper {
...
@@ -104,15 +105,15 @@ object DrawableHelper {
* @param context The context.
* @param context The context.
* @return The user status drawable.
* @return The user status drawable.
*/
*/
fun
getUserStatusDrawable
(
userStatus
:
String
,
context
:
Context
):
Drawable
{
fun
getUserStatusDrawable
(
userStatus
:
UserStatus
,
context
:
Context
):
Drawable
{
val
userStatusDrawable
=
getDrawableFromId
(
R
.
drawable
.
ic_user_status_black
,
context
).
mutate
()
val
userStatusDrawable
=
getDrawableFromId
(
R
.
drawable
.
ic_user_status_black
,
context
).
mutate
()
wrapDrawable
(
userStatusDrawable
)
wrapDrawable
(
userStatusDrawable
)
when
(
userStatus
)
{
when
(
userStatus
)
{
// TODO: create a enum or check if it will come from the SDK
is
UserStatus
.
Online
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusOnline
)
"online"
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusOnline
)
is
UserStatus
.
Busy
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusBusy
)
"busy"
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusBus
y
)
is
UserStatus
.
Away
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusAwa
y
)
"away"
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusAway
)
is
UserStatus
.
Offline
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusOffline
)
"offline"
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusOffline
)
else
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusOffline
)
}
}
return
userStatusDrawable
return
userStatusDrawable
}
}
...
...
app/src/main/java/chat/rocket/android/app/User.kt
deleted
100644 → 0
View file @
1cb3f896
package
chat.rocket.android.app
data class
User
(
val
id
:
String
,
val
name
:
String
,
val
username
:
String
,
val
status
:
String
,
val
avatarUri
:
String
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/signup/ui/SignupFragment.kt
View file @
00ac09d2
...
@@ -58,7 +58,7 @@ class SignupFragment : Fragment(), SignupView {
...
@@ -58,7 +58,7 @@ class SignupFragment : Fragment(), SignupView {
setUpNewUserAgreementListener
()
setUpNewUserAgreementListener
()
button_sign_up
.
setOnClickListener
{
button_sign_up
.
setOnClickListener
{
presenter
.
signup
(
text_name
.
textContent
,
text_username
.
textContent
,
text_password
.
textContent
,
text_email
.
textContent
)
presenter
.
signup
(
text_
user
name
.
textContent
,
text_username
.
textContent
,
text_password
.
textContent
,
text_email
.
textContent
)
}
}
}
}
...
@@ -69,8 +69,8 @@ class SignupFragment : Fragment(), SignupView {
...
@@ -69,8 +69,8 @@ class SignupFragment : Fragment(), SignupView {
override
fun
alertBlankName
()
{
override
fun
alertBlankName
()
{
AnimationHelper
.
vibrateSmartPhone
(
appContext
)
AnimationHelper
.
vibrateSmartPhone
(
appContext
)
AnimationHelper
.
shakeView
(
text_name
)
AnimationHelper
.
shakeView
(
text_
user
name
)
text_name
.
requestFocus
()
text_
user
name
.
requestFocus
()
}
}
override
fun
alertBlankUsername
()
{
override
fun
alertBlankUsername
()
{
...
@@ -122,7 +122,7 @@ class SignupFragment : Fragment(), SignupView {
...
@@ -122,7 +122,7 @@ class SignupFragment : Fragment(), SignupView {
val
drawables
=
arrayOf
(
personDrawable
,
atDrawable
,
lockDrawable
,
emailDrawable
)
val
drawables
=
arrayOf
(
personDrawable
,
atDrawable
,
lockDrawable
,
emailDrawable
)
DrawableHelper
.
wrapDrawables
(
drawables
)
DrawableHelper
.
wrapDrawables
(
drawables
)
DrawableHelper
.
tintDrawables
(
drawables
,
appContext
,
R
.
color
.
colorDrawableTintGrey
)
DrawableHelper
.
tintDrawables
(
drawables
,
appContext
,
R
.
color
.
colorDrawableTintGrey
)
DrawableHelper
.
compoundDrawables
(
arrayOf
(
text_name
,
text_username
,
text_password
,
text_email
),
drawables
)
DrawableHelper
.
compoundDrawables
(
arrayOf
(
text_
user
name
,
text_username
,
text_password
,
text_email
),
drawables
)
}
}
private
fun
setUpNewUserAgreementListener
()
{
private
fun
setUpNewUserAgreementListener
()
{
...
@@ -149,7 +149,7 @@ class SignupFragment : Fragment(), SignupView {
...
@@ -149,7 +149,7 @@ class SignupFragment : Fragment(), SignupView {
private
fun
enableUserInput
(
value
:
Boolean
)
{
private
fun
enableUserInput
(
value
:
Boolean
)
{
button_sign_up
.
isEnabled
=
value
button_sign_up
.
isEnabled
=
value
text_name
.
isEnabled
=
value
text_
user
name
.
isEnabled
=
value
text_username
.
isEnabled
=
value
text_username
.
isEnabled
=
value
text_password
.
isEnabled
=
value
text_password
.
isEnabled
=
value
text_email
.
isEnabled
=
value
text_email
.
isEnabled
=
value
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/AutoCompleteType.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.chatroom.adapter
import
android.support.annotation.IntDef
const
val
PEOPLE
=
0L
const
val
ROOMS
=
1L
@Retention
(
AnnotationRetention
.
SOURCE
)
@IntDef
(
value
=
[
PEOPLE
,
ROOMS
])
annotation
class
AutoCompleteType
app/src/main/java/chat/rocket/android/chatroom/adapter/PeopleSuggestionsAdapter.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.chatroom.adapter
import
DrawableHelper
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
android.widget.ImageView
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter.PeopleSuggestionViewHolder
import
chat.rocket.android.chatroom.viewmodel.PeopleViewModel
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.common.model.UserStatus
import
com.facebook.drawee.view.SimpleDraweeView
class
PeopleSuggestionsAdapter
:
SuggestionsAdapter
<
PeopleSuggestionViewHolder
>(
"@"
)
{
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
PeopleSuggestionViewHolder
{
val
view
=
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
suggestion_member_item
,
parent
,
false
)
return
PeopleSuggestionViewHolder
(
view
)
}
class
PeopleSuggestionViewHolder
(
view
:
View
)
:
BaseSuggestionViewHolder
(
view
)
{
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
item
as
PeopleViewModel
with
(
itemView
)
{
val
username
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_username
)
val
name
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_name
)
val
avatar
=
itemView
.
findViewById
<
SimpleDraweeView
>(
R
.
id
.
image_avatar
)
val
statusView
=
itemView
.
findViewById
<
ImageView
>(
R
.
id
.
image_status
)
username
.
text
=
item
.
username
name
.
text
=
item
.
name
if
(
item
.
imageUri
.
isEmpty
())
{
avatar
.
setVisible
(
false
)
}
else
{
avatar
.
setVisible
(
true
)
avatar
.
setImageURI
(
item
.
imageUri
)
}
val
status
=
item
.
status
?:
UserStatus
.
Offline
()
val
statusDrawable
=
DrawableHelper
.
getUserStatusDrawable
(
status
,
itemView
.
context
)
statusView
.
setImageDrawable
(
statusDrawable
)
setOnClickListener
{
itemClickListener
?.
onClick
(
item
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/RoomSuggestionsAdapter.kt
0 → 100644
View file @
00ac09d2
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.RoomSuggestionsAdapter.RoomSuggestionsViewHolder
import
chat.rocket.android.chatroom.viewmodel.RoomViewModel
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
RoomSuggestionsAdapter
:
SuggestionsAdapter
<
RoomSuggestionsViewHolder
>(
"#"
)
{
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
RoomSuggestionsViewHolder
{
val
view
=
LayoutInflater
.
from
(
parent
.
context
).
inflate
(
R
.
layout
.
suggestion_room_item
,
parent
,
false
)
return
RoomSuggestionsViewHolder
(
view
)
}
class
RoomSuggestionsViewHolder
(
view
:
View
)
:
BaseSuggestionViewHolder
(
view
)
{
override
fun
bind
(
item
:
SuggestionModel
,
itemClickListener
:
SuggestionsAdapter
.
ItemClickListener
?)
{
item
as
RoomViewModel
with
(
itemView
)
{
val
fullname
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_fullname
)
val
name
=
itemView
.
findViewById
<
TextView
>(
R
.
id
.
text_name
)
name
.
text
=
item
.
name
fullname
.
text
=
item
.
fullName
setOnClickListener
{
itemClickListener
?.
onClick
(
item
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
00ac09d2
...
@@ -2,15 +2,23 @@ package chat.rocket.android.chatroom.presentation
...
@@ -2,15 +2,23 @@ package chat.rocket.android.chatroom.presentation
import
android.net.Uri
import
android.net.Uri
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.AutoCompleteType
import
chat.rocket.android.chatroom.adapter.PEOPLE
import
chat.rocket.android.chatroom.adapter.ROOMS
import
chat.rocket.android.chatroom.domain.UriInteractor
import
chat.rocket.android.chatroom.domain.UriInteractor
import
chat.rocket.android.chatroom.viewmodel.PeopleViewModel
import
chat.rocket.android.chatroom.viewmodel.RoomViewModel
import
chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import
chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.state
import
chat.rocket.android.server.infraestructure.state
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.UserStatus
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.common.util.ifNull
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.internal.realtime.State
import
chat.rocket.core.internal.realtime.State
...
@@ -33,6 +41,9 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
...
@@ -33,6 +41,9 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private
val
permissions
:
GetPermissionsInteractor
,
private
val
permissions
:
GetPermissionsInteractor
,
private
val
uriInteractor
:
UriInteractor
,
private
val
uriInteractor
:
UriInteractor
,
private
val
messagesRepository
:
MessagesRepository
,
private
val
messagesRepository
:
MessagesRepository
,
private
val
usersRepository
:
UsersRepository
,
private
val
roomsRepository
:
RoomRepository
,
private
val
localRepository
:
LocalRepository
,
factory
:
ConnectionManagerFactory
,
factory
:
ConnectionManagerFactory
,
private
val
mapper
:
ViewModelMapper
)
{
private
val
mapper
:
ViewModelMapper
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
currentServer
=
serverInteractor
.
get
()
!!
...
@@ -339,6 +350,86 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
...
@@ -339,6 +350,86 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
}
}
}
fun
loadActiveMembers
(
chatRoomId
:
String
,
chatRoomType
:
String
,
offset
:
Long
=
0
,
filterSelfOut
:
Boolean
=
false
)
{
launchUI
(
strategy
)
{
try
{
val
members
=
client
.
getMembers
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
50
).
result
usersRepository
.
saveAll
(
members
)
val
self
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
// Take at most the 100 most recent messages distinguished by user. Can return less.
val
recentMessages
=
messagesRepository
.
getRecentMessages
(
chatRoomId
,
100
)
.
filterNot
{
filterSelfOut
&&
it
.
sender
?.
username
==
self
}
val
activeUsers
=
mutableListOf
<
PeopleViewModel
>()
recentMessages
.
forEach
{
val
sender
=
it
.
sender
!!
val
username
=
sender
.
username
?:
""
val
name
=
sender
.
name
?:
""
val
avatarUrl
=
UrlHelper
.
getAvatarUrl
(
currentServer
,
username
)
val
found
=
members
.
firstOrNull
{
member
->
member
.
username
==
username
}
val
status
=
if
(
found
!=
null
)
found
.
status
else
UserStatus
.
Offline
()
val
searchList
=
mutableListOf
(
username
,
name
)
activeUsers
.
add
(
PeopleViewModel
(
avatarUrl
,
username
,
username
,
name
,
status
,
true
,
searchList
))
}
// Filter out from members list the active users.
val
others
=
members
.
filterNot
{
member
->
activeUsers
.
firstOrNull
{
it
.
username
==
member
.
username
}
!=
null
}
// Add found room members who're not active enough and add them in without pinning.
activeUsers
.
addAll
(
others
.
map
{
val
username
=
it
.
username
?:
""
val
name
=
it
.
name
?:
""
val
avatarUrl
=
UrlHelper
.
getAvatarUrl
(
currentServer
,
username
)
val
searchList
=
mutableListOf
(
username
,
name
)
PeopleViewModel
(
avatarUrl
,
username
,
username
,
name
,
it
.
status
,
true
,
searchList
)
})
view
.
populateMembers
(
activeUsers
)
}
catch
(
e
:
RocketChatException
)
{
Timber
.
e
(
e
)
}
}
}
fun
spotlight
(
query
:
String
,
@AutoCompleteType
type
:
Long
,
filterSelfOut
:
Boolean
=
false
)
{
launchUI
(
strategy
)
{
try
{
val
(
users
,
rooms
)
=
client
.
spotlight
(
query
)
when
(
type
)
{
PEOPLE
->
{
if
(
users
.
isNotEmpty
())
{
usersRepository
.
saveAll
(
users
)
}
val
self
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
view
.
populateMembers
(
users
.
map
{
val
username
=
it
.
username
?:
""
val
name
=
it
.
name
?:
""
val
searchList
=
mutableListOf
(
username
,
name
)
it
.
emails
?.
forEach
{
email
->
searchList
.
add
(
email
.
address
)
}
PeopleViewModel
(
UrlHelper
.
getAvatarUrl
(
currentServer
,
username
),
username
,
username
,
name
,
it
.
status
,
false
,
searchList
)
}.
filterNot
{
filterSelfOut
&&
self
!=
null
&&
self
==
it
.
text
})
}
ROOMS
->
{
if
(
rooms
.
isNotEmpty
())
{
roomsRepository
.
saveAll
(
rooms
)
}
view
.
populateRooms
(
rooms
.
map
{
val
fullName
=
it
.
fullName
?:
""
val
name
=
it
.
name
?:
""
val
searchList
=
mutableListOf
(
fullName
,
name
)
RoomViewModel
(
name
,
fullName
,
name
,
searchList
)
})
}
}
}
catch
(
e
:
RocketChatException
)
{
Timber
.
e
(
e
)
}
}
}
private
fun
updateMessage
(
streamedMessage
:
Message
)
{
private
fun
updateMessage
(
streamedMessage
:
Message
)
{
launchUI
(
strategy
)
{
launchUI
(
strategy
)
{
val
viewModelStreamedMessage
=
mapper
.
map
(
streamedMessage
)
val
viewModelStreamedMessage
=
mapper
.
map
(
streamedMessage
)
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
00ac09d2
...
@@ -2,6 +2,8 @@ package chat.rocket.android.chatroom.presentation
...
@@ -2,6 +2,8 @@ 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.PeopleViewModel
import
chat.rocket.android.chatroom.viewmodel.RoomViewModel
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
...
@@ -100,4 +102,6 @@ interface ChatRoomView : LoadingView, MessageView {
...
@@ -100,4 +102,6 @@ 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
populateMembers
(
members
:
List
<
PeopleViewModel
>)
fun
populateRooms
(
rooms
:
List
<
RoomViewModel
>)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
00ac09d2
...
@@ -15,10 +15,12 @@ import android.support.v7.widget.LinearLayoutManager
...
@@ -15,10 +15,12 @@ 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.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.PeopleViewModel
import
chat.rocket.android.chatroom.viewmodel.RoomViewModel
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
...
@@ -62,9 +64,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
...
@@ -62,9 +64,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
private
lateinit
var
chatRoomId
:
String
private
lateinit
var
chatRoomId
:
String
private
lateinit
var
chatRoomName
:
String
private
lateinit
var
chatRoomName
:
String
private
lateinit
var
chatRoomType
:
String
private
lateinit
var
chatRoomType
:
String
private
lateinit
var
emojiKeyboardPopup
:
EmojiKeyboardPopup
private
var
isChatRoomReadOnly
:
Boolean
=
false
private
var
isChatRoomReadOnly
:
Boolean
=
false
private
lateinit
var
emojiKeyboardPopup
:
EmojiKeyboardPopup
private
lateinit
var
actionSnackbar
:
ActionSnackbar
private
lateinit
var
actionSnackbar
:
ActionSnackbar
private
var
citation
:
String
?
=
null
private
var
citation
:
String
?
=
null
private
var
editingMessageId
:
String
?
=
null
private
var
editingMessageId
:
String
?
=
null
...
@@ -100,7 +103,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
...
@@ -100,7 +103,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
override
fun
onViewCreated
(
view
:
View
,
savedInstanceState
:
Bundle
?)
{
override
fun
onViewCreated
(
view
:
View
,
savedInstanceState
:
Bundle
?)
{
super
.
onViewCreated
(
view
,
savedInstanceState
)
super
.
onViewCreated
(
view
,
savedInstanceState
)
presenter
.
loadMessages
(
chatRoomId
,
chatRoomType
)
presenter
.
loadMessages
(
chatRoomId
,
chatRoomType
)
setupRecyclerView
()
setupRecyclerView
()
setupFab
()
setupFab
()
setupMessageComposer
()
setupMessageComposer
()
...
@@ -169,6 +171,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
...
@@ -169,6 +171,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
if
(
oldMessagesCount
==
0
&&
dataSet
.
isNotEmpty
())
{
if
(
oldMessagesCount
==
0
&&
dataSet
.
isNotEmpty
())
{
recycler_view
.
scrollToPosition
(
0
)
recycler_view
.
scrollToPosition
(
0
)
}
}
presenter
.
loadActiveMembers
(
chatRoomId
,
chatRoomType
,
filterSelfOut
=
true
)
}
}
}
}
...
@@ -240,6 +243,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
...
@@ -240,6 +243,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
populateMembers
(
members
:
List
<
PeopleViewModel
>)
{
suggestions_view
.
addItems
(
"@"
,
members
)
}
override
fun
populateRooms
(
rooms
:
List
<
RoomViewModel
>)
{
suggestions_view
.
addItems
(
"#"
,
rooms
)
}
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
...
@@ -398,16 +409,30 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
...
@@ -398,16 +409,30 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
openEmojiKeyboardPopup
()
openEmojiKeyboardPopup
()
}
}
}
}
suggestions_view
.
anchor
(
text_message
)
.
bindTokenAdapter
(
PeopleSuggestionsAdapter
())
.
bindTokenAdapter
(
RoomSuggestionsAdapter
())
.
addSuggestionProviderAction
(
"@"
)
{
query
->
if
(
query
.
isNotEmpty
())
{
presenter
.
spotlight
(
query
,
PEOPLE
,
true
)
}
}
.
addSuggestionProviderAction
(
"#"
)
{
query
->
if
(
query
.
isNotEmpty
())
{
presenter
.
spotlight
(
query
,
ROOMS
)
}
}
}
}
private
fun
openEmojiKeyboardPopup
()
{
private
fun
openEmojiKeyboardPopup
()
{
if
(!
emojiKeyboardPopup
.
isShowing
()
)
{
if
(!
emojiKeyboardPopup
.
isShowing
)
{
// If keyboard is visible, simply show the popup
// If keyboard is visible, simply show the popup
if
(
emojiKeyboardPopup
.
isKeyboardOpen
)
{
if
(
emojiKeyboardPopup
.
isKeyboardOpen
)
{
emojiKeyboardPopup
.
showAtBottom
()
emojiKeyboardPopup
.
showAtBottom
()
}
else
{
}
else
{
// Open the text keyboard first and immediately after that show the emoji popup
// Open the text keyboard first and immediately after that show the emoji popup
text_message
.
setFocusableInTouchMode
(
true
)
text_message
.
isFocusableInTouchMode
=
true
text_message
.
requestFocus
()
text_message
.
requestFocus
()
emojiKeyboardPopup
.
showAtBottomPending
()
emojiKeyboardPopup
.
showAtBottomPending
()
KeyboardHelper
.
showSoftKeyboard
(
text_message
)
KeyboardHelper
.
showSoftKeyboard
(
text_message
)
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/PeopleViewModel.kt
0 → 100644
View file @
00ac09d2
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/RoomViewModel.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
class
RoomViewModel
(
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/dagger/module/AppModule.kt
View file @
00ac09d2
...
@@ -185,7 +185,13 @@ class AppModule {
...
@@ -185,7 +185,13 @@ class AppModule {
@Provides
@Provides
@Singleton
@Singleton
fun
provideChatRoomsRepository
():
ChatRoomsRepository
{
fun
provideRoomRepository
():
RoomRepository
{
return
MemoryRoomRepository
()
}
@Provides
@Singleton
fun
provideChatRoomRepository
():
ChatRoomsRepository
{
return
MemoryChatRoomsRepository
()
return
MemoryChatRoomsRepository
()
}
}
...
@@ -207,6 +213,12 @@ class AppModule {
...
@@ -207,6 +213,12 @@ class AppModule {
return
MemoryMessagesRepository
()
return
MemoryMessagesRepository
()
}
}
@Provides
@Singleton
fun
provideUserRepository
():
UsersRepository
{
return
MemoryUsersRepository
()
}
@Provides
@Provides
@Singleton
@Singleton
fun
provideConfiguration
(
context
:
Application
,
client
:
OkHttpClient
):
SpannableConfiguration
{
fun
provideConfiguration
(
context
:
Application
,
client
:
OkHttpClient
):
SpannableConfiguration
{
...
...
app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt
View file @
00ac09d2
...
@@ -6,7 +6,6 @@ import android.os.Bundle
...
@@ -6,7 +6,6 @@ import android.os.Bundle
import
android.support.v4.app.Fragment
import
android.support.v4.app.Fragment
import
android.support.v7.view.ActionMode
import
android.support.v7.view.ActionMode
import
android.view.*
import
android.view.*
import
android.widget.Toast
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.profile.presentation.ProfilePresenter
import
chat.rocket.android.profile.presentation.ProfilePresenter
...
@@ -51,7 +50,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -51,7 +50,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override
fun
showProfile
(
avatarUrl
:
String
,
name
:
String
,
username
:
String
,
email
:
String
)
{
override
fun
showProfile
(
avatarUrl
:
String
,
name
:
String
,
username
:
String
,
email
:
String
)
{
image_avatar
.
setImageURI
(
avatarUrl
)
image_avatar
.
setImageURI
(
avatarUrl
)
text_name
.
textContent
=
name
text_
user
name
.
textContent
=
name
text_username
.
textContent
=
username
text_username
.
textContent
=
username
text_email
.
textContent
=
email
text_email
.
textContent
=
email
...
@@ -93,7 +92,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -93,7 +92,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override
fun
onActionItemClicked
(
mode
:
ActionMode
,
menuItem
:
MenuItem
):
Boolean
{
override
fun
onActionItemClicked
(
mode
:
ActionMode
,
menuItem
:
MenuItem
):
Boolean
{
return
when
(
menuItem
.
itemId
)
{
return
when
(
menuItem
.
itemId
)
{
R
.
id
.
action_profile
->
{
R
.
id
.
action_profile
->
{
presenter
.
updateUserProfile
(
text_email
.
textContent
,
text_name
.
textContent
,
text_username
.
textContent
)
presenter
.
updateUserProfile
(
text_email
.
textContent
,
text_
user
name
.
textContent
,
text_username
.
textContent
)
mode
.
finish
()
mode
.
finish
()
true
true
}
}
...
@@ -120,12 +119,12 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -120,12 +119,12 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
val
drawables
=
arrayOf
(
personDrawable
,
atDrawable
,
emailDrawable
)
val
drawables
=
arrayOf
(
personDrawable
,
atDrawable
,
emailDrawable
)
DrawableHelper
.
wrapDrawables
(
drawables
)
DrawableHelper
.
wrapDrawables
(
drawables
)
DrawableHelper
.
tintDrawables
(
drawables
,
this
,
R
.
color
.
colorDrawableTintGrey
)
DrawableHelper
.
tintDrawables
(
drawables
,
this
,
R
.
color
.
colorDrawableTintGrey
)
DrawableHelper
.
compoundDrawables
(
arrayOf
(
text_name
,
text_username
,
text_email
),
drawables
)
DrawableHelper
.
compoundDrawables
(
arrayOf
(
text_
user
name
,
text_username
,
text_email
),
drawables
)
}
}
}
}
private
fun
listenToChanges
()
{
private
fun
listenToChanges
()
{
Observables
.
combineLatest
(
text_name
.
asObservable
(),
text_username
.
asObservable
(),
text_email
.
asObservable
()).
subscribe
({
t
->
Observables
.
combineLatest
(
text_
user
name
.
asObservable
(),
text_username
.
asObservable
(),
text_email
.
asObservable
()).
subscribe
({
t
->
if
(
t
.
first
.
toString
()
!=
currentName
||
t
.
second
.
toString
()
!=
currentUsername
||
t
.
third
.
toString
()
!=
currentEmail
)
{
if
(
t
.
first
.
toString
()
!=
currentName
||
t
.
second
.
toString
()
!=
currentUsername
||
t
.
third
.
toString
()
!=
currentEmail
)
{
startActionMode
()
startActionMode
()
}
else
{
}
else
{
...
@@ -143,7 +142,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -143,7 +142,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
private
fun
finishActionMode
()
=
actionMode
?.
finish
()
private
fun
finishActionMode
()
=
actionMode
?.
finish
()
private
fun
enableUserInput
(
value
:
Boolean
)
{
private
fun
enableUserInput
(
value
:
Boolean
)
{
text_name
.
isEnabled
=
value
text_
user
name
.
isEnabled
=
value
text_username
.
isEnabled
=
value
text_username
.
isEnabled
=
value
text_email
.
isEnabled
=
value
text_email
.
isEnabled
=
value
}
}
...
...
app/src/main/java/chat/rocket/android/server/domain/MessagesRepository.kt
View file @
00ac09d2
...
@@ -8,6 +8,7 @@ interface MessagesRepository {
...
@@ -8,6 +8,7 @@ interface MessagesRepository {
* Get message by its message id.
* Get message by its message id.
*
*
* @param id The id of the message to get.
* @param id The id of the message to get.
*
* @return The Message object given by the id or null if message wasn't found.
* @return The Message object given by the id or null if message wasn't found.
*/
*/
fun
getById
(
id
:
String
):
Message
?
fun
getById
(
id
:
String
):
Message
?
...
@@ -20,8 +21,19 @@ interface MessagesRepository {
...
@@ -20,8 +21,19 @@ interface MessagesRepository {
*/
*/
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
/**
* Get most recent messages up to count different users.
*
* @param rid The id of the room the messages are.
* @param count The count last messages to get.
*
* @return List of last count messages.
*/
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
/**
/**
* Get all messages. Use carefully!
* Get all messages. Use carefully!
*
* @return All messages or an empty list.
* @return All messages or an empty list.
*/
*/
fun
getAll
():
List
<
Message
>
fun
getAll
():
List
<
Message
>
...
...
app/src/main/java/chat/rocket/android/server/domain/RoomRepository.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.server.domain
import
chat.rocket.common.model.RoomType
import
chat.rocket.core.model.Room
interface
RoomRepository
{
/**
* Get all rooms. Use carefully!
*
* @return All rooms or an empty list.
*/
fun
getAll
():
List
<
Room
>
fun
get
(
query
:
Query
.()
->
Unit
):
List
<
Room
>
/**
* Save a single room object.
*
* @param room The room object to save.
*/
fun
save
(
room
:
Room
)
/**
* Save a list of rooms.
*
* @param roomList The list of rooms to save.
*/
fun
saveAll
(
roomList
:
List
<
Room
>)
/**
* Removes all rooms.
*/
fun
clear
()
data class
Query
(
var
id
:
String
?
=
null
,
var
name
:
String
?
=
null
,
var
fullName
:
String
?
=
null
,
var
type
:
RoomType
?
=
null
,
var
readonly
:
Boolean
?
=
null
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/domain/UsersRepository.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.server.domain
import
chat.rocket.common.model.Email
import
chat.rocket.common.model.User
import
chat.rocket.common.model.UserStatus
interface
UsersRepository
{
/**
* Get all users. Use carefully!
*
* @return All users or an empty list.
*/
fun
getAll
():
List
<
User
>
fun
get
(
query
:
Query
.()
->
Unit
):
List
<
User
>
/**
* Save a single user object.
*
* @param user The user object to save.
*/
fun
save
(
user
:
User
)
/**
* Save a list of users.
*
* @param users The list of users to save.
*/
fun
saveAll
(
userList
:
List
<
User
>)
/**
* Removes all users.
*/
fun
clear
()
data class
Query
(
var
id
:
String
?
=
null
,
var
name
:
String
?
=
null
,
var
username
:
String
?
=
null
,
var
emails
:
List
<
Email
>?
=
null
,
var
utfOffset
:
Float
?
=
null
,
var
status
:
UserStatus
?
=
null
,
var
limit
:
Long
=
0L
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/infraestructure/MemoryMessagesRepository.kt
View file @
00ac09d2
...
@@ -15,6 +15,11 @@ class MemoryMessagesRepository : MessagesRepository {
...
@@ -15,6 +15,11 @@ class MemoryMessagesRepository : MessagesRepository {
return
messages
.
filter
{
it
.
value
.
roomId
==
rid
}.
values
.
toList
()
return
messages
.
filter
{
it
.
value
.
roomId
==
rid
}.
values
.
toList
()
}
}
override
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
{
return
getByRoomId
(
rid
).
sortedByDescending
{
it
.
timestamp
}
.
distinctBy
{
it
.
sender
}.
take
(
count
.
toInt
())
}
override
fun
getAll
():
List
<
Message
>
=
messages
.
values
.
toList
()
override
fun
getAll
():
List
<
Message
>
=
messages
.
values
.
toList
()
override
fun
save
(
message
:
Message
)
{
override
fun
save
(
message
:
Message
)
{
...
...
app/src/main/java/chat/rocket/android/server/infraestructure/MemoryRoomRepository.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.server.infraestructure
import
chat.rocket.android.server.domain.RoomRepository
import
chat.rocket.android.server.domain.RoomRepository.Query
import
chat.rocket.core.model.Room
import
java.util.concurrent.CopyOnWriteArrayList
class
MemoryRoomRepository
:
RoomRepository
{
private
val
rooms
=
CopyOnWriteArrayList
<
Room
>()
override
fun
getAll
()
=
rooms
.
toList
()
override
fun
get
(
query
:
Query
.()
->
Unit
):
List
<
Room
>
{
val
q
=
Query
().
apply
(
query
)
return
rooms
.
filter
{
with
(
q
)
{
if
(
name
!=
null
&&
it
.
name
?.
contains
(
name
!!
.
toRegex
())
==
true
)
return
@filter
false
if
(
fullName
!=
null
&&
it
.
fullName
?.
contains
(
fullName
!!
.
toRegex
())
==
true
)
return
@filter
false
if
(
id
!=
null
&&
id
==
it
.
id
)
return
@filter
false
if
(
readonly
!=
null
&&
readonly
==
it
.
readonly
)
return
@filter
false
if
(
type
!=
null
&&
type
==
it
.
type
)
return
@filter
false
return
@filter
true
}
}
}
override
fun
save
(
room
:
Room
)
{
rooms
.
addIfAbsent
(
room
)
}
override
fun
saveAll
(
roomList
:
List
<
Room
>)
{
rooms
.
addAllAbsent
(
roomList
)
}
override
fun
clear
()
{
rooms
.
clear
()
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/infraestructure/MemoryUsersRepository.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.server.infraestructure
import
chat.rocket.android.server.domain.UsersRepository
import
chat.rocket.android.server.domain.UsersRepository.Query
import
chat.rocket.common.model.User
import
java.util.concurrent.CopyOnWriteArrayList
class
MemoryUsersRepository
:
UsersRepository
{
private
val
users
=
CopyOnWriteArrayList
<
User
>()
override
fun
getAll
():
List
<
User
>
{
return
users
.
toList
()
}
override
fun
get
(
query
:
Query
.()
->
Unit
):
List
<
User
>
{
val
q
=
Query
().
apply
(
query
)
return
users
.
filter
{
with
(
q
)
{
if
(
name
!=
null
&&
it
.
name
?.
contains
(
name
!!
.
toRegex
())
==
true
)
return
@filter
false
if
(
username
!=
null
&&
it
.
username
?.
contains
(
username
!!
.
toRegex
())
==
true
)
return
@filter
false
if
(
id
!=
null
&&
id
==
it
.
id
)
return
@filter
false
if
(
status
!=
null
&&
status
==
it
.
status
)
return
@filter
false
return
@filter
true
}
}
}
override
fun
save
(
user
:
User
)
{
users
.
addIfAbsent
(
user
)
}
override
fun
saveAll
(
userList
:
List
<
User
>)
{
users
.
addAllAbsent
(
userList
)
}
override
fun
clear
()
{
this
.
users
.
clear
()
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/autocompletion/model/SuggestionModel.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.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 */
)
{
override
fun
equals
(
other
:
Any
?):
Boolean
{
if
(
this
===
other
)
return
true
if
(
other
!
is
SuggestionModel
)
return
false
if
(
text
!=
other
.
text
)
return
false
return
true
}
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
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.repository
interface
LocalSuggestionProvider
{
fun
find
(
prefix
:
String
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/autocompletion/strategy/CompletionStrategy.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.strategy
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
interface
CompletionStrategy
{
fun
getItem
(
prefix
:
String
,
position
:
Int
):
SuggestionModel
fun
autocompleteItems
(
prefix
:
String
):
List
<
SuggestionModel
>
fun
addAll
(
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
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.strategy.regex
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
chat.rocket.android.widget.autocompletion.strategy.CompletionStrategy
import
java.util.concurrent.CopyOnWriteArrayList
internal
class
StringMatchingCompletionStrategy
:
CompletionStrategy
{
private
val
list
=
CopyOnWriteArrayList
<
SuggestionModel
>()
override
fun
autocompleteItems
(
prefix
:
String
):
List
<
SuggestionModel
>
{
return
list
.
filter
{
it
.
searchList
.
forEach
{
word
->
if
(
word
.
contains
(
prefix
,
ignoreCase
=
true
))
{
return
@filter
true
}
}
false
}.
sortedByDescending
{
it
.
pinned
}.
take
(
5
)
}
override
fun
addAll
(
list
:
List
<
SuggestionModel
>)
{
// this.list.removeAll { !it.pinned }
this
.
list
.
addAllAbsent
(
list
)
}
override
fun
getItem
(
prefix
:
String
,
position
:
Int
):
SuggestionModel
{
return
list
[
position
]
}
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
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.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
class
TrieCompletionStrategy
:
CompletionStrategy
{
private
val
items
=
mutableListOf
<
SuggestionModel
>()
private
val
trie
=
Trie
()
override
fun
getItem
(
prefix
:
String
,
position
:
Int
):
SuggestionModel
{
val
item
:
SuggestionModel
if
(
prefix
.
isEmpty
())
{
item
=
items
[
position
]
}
else
{
item
=
autocompleteItems
(
prefix
)[
position
]
}
return
item
}
override
fun
autocompleteItems
(
prefix
:
String
)
=
trie
.
autocompleteItems
(
prefix
)
override
fun
addAll
(
list
:
List
<
SuggestionModel
>)
{
items
.
addAll
(
list
)
list
.
forEach
{
trie
.
insert
(
it
)
}
}
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
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.strategy.trie.data
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
internal
class
Trie
{
private
val
root
=
TrieNode
(
' '
)
private
var
count
=
0
fun
insert
(
item
:
SuggestionModel
)
{
val
sanitizedWord
=
item
.
text
.
trim
().
toLowerCase
()
// Word exists, bail out.
if
(
search
(
sanitizedWord
))
return
var
current
=
root
sanitizedWord
.
forEach
{
ch
->
val
child
=
current
.
getChild
(
ch
)
if
(
child
==
null
)
{
val
node
=
TrieNode
(
ch
,
current
)
current
.
children
[
ch
]
=
node
current
=
node
count
++
}
else
{
current
=
child
}
}
// Set last node as leaf.
if
(
current
!=
root
)
{
current
.
isLeaf
=
true
current
.
item
=
item
}
}
fun
search
(
word
:
String
):
Boolean
{
val
sanitizedWord
=
word
.
trim
().
toLowerCase
()
var
current
=
root
sanitizedWord
.
forEach
{
ch
->
val
child
=
current
.
getChild
(
ch
)
if
(
child
==
null
)
{
return
false
}
current
=
child
}
if
(
current
.
isLeaf
)
{
return
true
}
return
false
}
fun
autocomplete
(
prefix
:
String
):
List
<
String
>
{
val
sanitizedPrefix
=
prefix
.
trim
().
toLowerCase
()
var
lastNode
:
TrieNode
?
=
root
sanitizedPrefix
.
forEach
{
ch
->
lastNode
=
lastNode
?.
getChild
(
ch
)
if
(
lastNode
==
null
)
return
emptyList
()
}
return
lastNode
!!
.
getWords
()
}
fun
autocompleteItems
(
prefix
:
String
):
List
<
SuggestionModel
>
{
val
sanitizedPrefix
=
prefix
.
trim
().
toLowerCase
()
var
lastNode
:
TrieNode
?
=
root
sanitizedPrefix
.
forEach
{
ch
->
lastNode
=
lastNode
?.
getChild
(
ch
)
if
(
lastNode
==
null
)
return
emptyList
()
}
return
lastNode
!!
.
getItems
()
}
fun
getCount
()
=
count
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/autocompletion/strategy/trie/data/TrieNode.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.strategy.trie.data
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
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
?
{
children
.
forEach
{
if
(
it
.
key
==
c
)
return
it
.
value
}
return
null
}
fun
getWords
():
List
<
String
>
{
val
list
=
arrayListOf
<
String
>()
if
(
isLeaf
)
{
list
.
add
(
toString
())
}
children
.
forEach
{
node
->
node
.
value
.
let
{
list
.
addAll
(
it
.
getWords
())
}
}
return
list
}
class
X
:
SuggestionModel
(
""
)
fun
getItems
():
List
<
SuggestionModel
>
{
val
list
=
arrayListOf
<
SuggestionModel
>()
if
(
isLeaf
)
{
list
.
add
(
item
!!
)
}
children
.
forEach
{
node
->
node
.
value
.
let
{
list
.
addAll
(
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
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.ui
import
android.support.v7.widget.RecyclerView
import
android.view.View
import
chat.rocket.android.widget.autocompletion.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
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.ui
import
android.content.Context
import
android.support.v7.widget.RecyclerView
import
android.util.AttributeSet
import
android.util.DisplayMetrics
import
android.view.WindowManager
import
chat.rocket.android.R
internal
class
PopupRecyclerView
:
RecyclerView
{
private
var
displayWidth
:
Int
=
0
constructor
(
context
:
Context
?)
:
this
(
context
,
null
)
constructor
(
context
:
Context
?,
attrs
:
AttributeSet
?)
:
this
(
context
,
attrs
,
0
)
constructor
(
context
:
Context
?,
attrs
:
AttributeSet
?,
defStyle
:
Int
)
:
super
(
context
,
attrs
,
defStyle
)
{
val
wm
=
context
!!
.
getSystemService
(
Context
.
WINDOW_SERVICE
)
as
WindowManager
val
display
=
wm
.
defaultDisplay
val
size
=
DisplayMetrics
()
display
.
getMetrics
(
size
)
val
screenWidth
=
size
.
widthPixels
displayWidth
=
screenWidth
}
override
fun
onMeasure
(
widthSpec
:
Int
,
heightSpec
:
Int
)
{
val
hSpec
=
MeasureSpec
.
makeMeasureSpec
(
resources
.
getDimensionPixelSize
(
R
.
dimen
.
popup_max_height
),
MeasureSpec
.
AT_MOST
)
val
wSpec
=
MeasureSpec
.
makeMeasureSpec
(
displayWidth
,
MeasureSpec
.
EXACTLY
)
super
.
onMeasure
(
wSpec
,
hSpec
)
}
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
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.ui
import
android.support.v7.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
java.lang.reflect.Type
import
kotlin.properties.Delegates
abstract
class
SuggestionsAdapter
<
VH
:
BaseSuggestionViewHolder
>(
val
token
:
String
)
:
RecyclerView
.
Adapter
<
VH
>()
{
private
val
strategy
:
CompletionStrategy
=
StringMatchingCompletionStrategy
()
private
var
itemType
:
Type
?
=
null
private
var
itemClickListener
:
ItemClickListener
?
=
null
private
var
providerExternal
:
((
query
:
String
)
->
Unit
)?
=
null
private
var
prefix
:
String
by
Delegates
.
observable
(
""
,
{
_
,
_
,
_
->
strategy
.
autocompleteItems
(
prefix
)
notifyItemRangeChanged
(
0
,
5
)
})
init
{
setHasStableIds
(
true
)
}
override
fun
getItemId
(
position
:
Int
):
Long
{
return
getItem
(
position
).
text
.
hashCode
().
toLong
()
}
override
fun
onBindViewHolder
(
holder
:
VH
,
position
:
Int
)
{
holder
.
bind
(
getItem
(
position
),
itemClickListener
)
}
override
fun
getItemCount
()
=
strategy
.
autocompleteItems
(
prefix
).
size
private
fun
getItem
(
position
:
Int
):
SuggestionModel
{
return
strategy
.
autocompleteItems
(
prefix
)[
position
]
}
fun
autocomplete
(
prefix
:
String
)
{
this
.
prefix
=
prefix
.
toLowerCase
().
trim
()
}
fun
addItems
(
list
:
List
<
SuggestionModel
>)
{
strategy
.
addAll
(
list
)
// Since we've just added new items we should check for possible new completion suggestions.
strategy
.
autocompleteItems
(
prefix
)
notifyItemRangeChanged
(
0
,
5
)
}
fun
setOnClickListener
(
clickListener
:
ItemClickListener
)
{
this
.
itemClickListener
=
clickListener
}
fun
hasItemClickListener
()
=
itemClickListener
!=
null
fun
prefix
()
=
prefix
fun
cancel
()
{
strategy
.
addAll
(
emptyList
())
strategy
.
autocompleteItems
(
prefix
)
notifyDataSetChanged
()
}
interface
ItemClickListener
{
fun
onClick
(
item
:
SuggestionModel
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/autocompletion/ui/SuggestionsView.kt
0 → 100644
View file @
00ac09d2
package
chat.rocket.android.widget.autocompletion.ui
import
android.content.Context
import
android.support.transition.Slide
import
android.support.transition.TransitionManager
import
android.support.v7.widget.DefaultItemAnimator
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.RecyclerView
import
android.text.Editable
import
android.text.InputType
import
android.text.TextWatcher
import
android.util.AttributeSet
import
android.view.Gravity
import
android.view.View
import
android.widget.EditText
import
android.widget.FrameLayout
import
chat.rocket.android.widget.autocompletion.model.SuggestionModel
import
java.lang.ref.WeakReference
import
java.util.concurrent.atomic.AtomicInteger
/**
* This is a special index that means we're not at an autocompleting state.
*/
private
const
val
NO_STATE_INDEX
=
0
class
SuggestionsView
:
FrameLayout
,
TextWatcher
{
private
val
recyclerView
:
RecyclerView
// Maps tokens to their respecive adapters.
private
val
adaptersByToken
=
hashMapOf
<
String
,
SuggestionsAdapter
<
out
BaseSuggestionViewHolder
>>()
private
val
externalProvidersByToken
=
hashMapOf
<
String
,
((
query
:
String
)
->
Unit
)>()
private
val
localProvidersByToken
=
hashMapOf
<
String
,
HashMap
<
String
,
List
<
SuggestionModel
>>>()
private
var
editor
:
WeakReference
<
EditText
>?
=
null
private
var
completionStartIndex
=
AtomicInteger
(
NO_STATE_INDEX
)
companion
object
{
private
val
SLIDE_TRANSITION
=
Slide
(
Gravity
.
BOTTOM
).
setDuration
(
200
)
}
constructor
(
context
:
Context
)
:
this
(
context
,
null
)
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?)
:
this
(
context
,
attrs
,
0
)
constructor
(
context
:
Context
,
attrs
:
AttributeSet
?,
defStyleAttr
:
Int
)
:
super
(
context
,
attrs
,
defStyleAttr
,
0
)
{
recyclerView
=
RecyclerView
(
context
)
val
layoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
recyclerView
.
itemAnimator
=
DefaultItemAnimator
()
recyclerView
.
layoutManager
=
layoutManager
recyclerView
.
visibility
=
View
.
GONE
addView
(
recyclerView
)
}
override
fun
afterTextChanged
(
s
:
Editable
)
{
}
override
fun
beforeTextChanged
(
s
:
CharSequence
,
start
:
Int
,
count
:
Int
,
after
:
Int
)
{
// If we have a deletion.
if
(
after
==
0
)
{
val
deleted
=
s
.
subSequence
(
start
,
start
+
count
).
toString
()
if
(
adaptersByToken
.
containsKey
(
deleted
)
&&
completionStartIndex
.
get
()
>
NO_STATE_INDEX
)
{
// We have removed the '@', '#' or any other action token so halt completion.
cancelSuggestions
(
true
)
}
}
}
override
fun
onTextChanged
(
s
:
CharSequence
,
start
:
Int
,
before
:
Int
,
count
:
Int
)
{
// If we don't have any adapter bound to any token bail out.
if
(
adaptersByToken
.
isEmpty
())
return
val
new
=
s
.
subSequence
(
start
,
start
+
count
).
toString
()
if
(
adaptersByToken
.
containsKey
(
new
))
{
swapAdapter
(
getAdapterForToken
(
new
)
!!
)
completionStartIndex
.
compareAndSet
(
NO_STATE_INDEX
,
start
+
1
)
editor
?.
let
{
// Disable keyboard suggestions when autocompleting.
val
editText
=
it
.
get
()
if
(
editText
!=
null
)
{
editText
.
inputType
=
editText
.
inputType
or
InputType
.
TYPE_TEXT_VARIATION_FILTER
expand
()
}
}
}
if
(
new
.
startsWith
(
" "
))
{
// just halts the completion execution
cancelSuggestions
(
false
)
return
}
val
prefixEndIndex
=
editor
?.
get
()
?.
selectionStart
?:
NO_STATE_INDEX
if
(
prefixEndIndex
==
NO_STATE_INDEX
||
prefixEndIndex
<
completionStartIndex
.
get
())
return
val
prefix
=
s
.
subSequence
(
completionStartIndex
.
get
(),
editor
?.
get
()
?.
selectionStart
?:
completionStartIndex
.
get
()).
toString
()
recyclerView
.
adapter
?.
let
{
it
as
SuggestionsAdapter
// we need to look up only after the '@'
it
.
autocomplete
(
prefix
)
val
cacheMap
=
localProvidersByToken
[
it
.
token
]
if
(
cacheMap
!=
null
&&
cacheMap
[
prefix
]
!=
null
)
{
it
.
addItems
(
cacheMap
[
prefix
]
!!
)
}
else
{
// fetch more suggestions from an external source if any
externalProvidersByToken
[
it
.
token
]
?.
invoke
(
prefix
)
}
}
}
private
fun
swapAdapter
(
adapter
:
SuggestionsAdapter
<
*
>):
SuggestionsView
{
recyclerView
.
adapter
=
adapter
// Don't override if user set an item click listener already/
if
(!
adapter
.
hasItemClickListener
())
{
setOnItemClickListener
(
adapter
)
{
// set default item click behavior
}
}
return
this
}
fun
getAdapterForToken
(
token
:
String
):
SuggestionsAdapter
<
*
>?
=
adaptersByToken
.
get
(
token
)
fun
anchor
(
editText
:
EditText
):
SuggestionsView
{
editText
.
removeTextChangedListener
(
this
)
editText
.
addTextChangedListener
(
this
)
editor
=
WeakReference
(
editText
)
return
this
}
fun
bindTokenAdapter
(
adapter
:
SuggestionsAdapter
<
*
>):
SuggestionsView
{
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
.
prefix
(),
list
)
if
(
completionStartIndex
.
get
()
>
NO_STATE_INDEX
&&
adapter
.
itemCount
==
0
)
expand
()
adapter
.
addItems
(
list
)
}
return
this
}
fun
setOnItemClickListener
(
tokenAdapter
:
SuggestionsAdapter
<
*
>,
clickListener
:
(
item
:
SuggestionModel
)
->
Unit
):
SuggestionsView
{
tokenAdapter
.
setOnClickListener
(
object
:
SuggestionsAdapter
.
ItemClickListener
{
override
fun
onClick
(
item
:
SuggestionModel
)
{
insertSuggestionOnEditor
(
item
)
clickListener
.
invoke
(
item
)
cancelSuggestions
(
true
)
collapse
()
}
})
return
this
}
fun
addSuggestionProviderAction
(
token
:
String
,
provider
:
(
query
:
String
)
->
Unit
):
SuggestionsView
{
externalProvidersByToken
.
getOrPut
(
token
,
{
provider
})
return
this
}
private
fun
adapter
(
token
:
String
):
SuggestionsAdapter
<
*
>
{
return
adaptersByToken
[
token
]
?:
throw
IllegalStateException
(
"no adapter binds to token \"$token\""
)
}
private
fun
cancelSuggestions
(
haltCompletion
:
Boolean
)
{
// Reset completion start index only if we've deleted the token that triggered completion or
// we finished the completion process.
if
(
haltCompletion
)
{
completionStartIndex
.
set
(
NO_STATE_INDEX
)
}
collapse
()
// Re-enable keyboard suggestions.
val
editText
=
editor
?.
get
()
if
(
editText
!=
null
)
{
editText
.
inputType
=
editText
.
inputType
and
InputType
.
TYPE_TEXT_VARIATION_FILTER
.
inv
()
}
}
private
fun
insertSuggestionOnEditor
(
item
:
SuggestionModel
)
{
editor
?.
get
()
?.
let
{
val
suggestionText
=
item
.
text
it
.
text
.
replace
(
completionStartIndex
.
get
(),
it
.
selectionStart
,
"$suggestionText "
)
}
}
private
fun
collapse
()
{
TransitionManager
.
beginDelayedTransition
(
this
,
SLIDE_TRANSITION
)
recyclerView
.
visibility
=
View
.
GONE
}
private
fun
expand
()
{
TransitionManager
.
beginDelayedTransition
(
this
,
SLIDE_TRANSITION
)
recyclerView
.
visibility
=
View
.
VISIBLE
}
}
\ No newline at end of file
app/src/main/res/drawable/user_status_white.xml
0 → 100644
View file @
00ac09d2
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"10dp"
android:height=
"10dp"
android:viewportWidth=
"10.0"
android:viewportHeight=
"10.0"
>
<path
android:pathData=
"M5,5m-5,0a5,5 0,1 1,10 0a5,5 0,1 1,-10 0"
android:fillType=
"evenOdd"
android:fillColor=
"#FFFFFF"
android:strokeWidth=
"1"
/>
</vector>
\ No newline at end of file
app/src/main/res/layout/fragment_authentication_sign_up.xml
View file @
00ac09d2
...
@@ -16,7 +16,7 @@
...
@@ -16,7 +16,7 @@
app:layout_constraintTop_toTopOf=
"parent"
/>
app:layout_constraintTop_toTopOf=
"parent"
/>
<EditText
<EditText
android:id=
"@+id/text_name"
android:id=
"@+id/text_
user
name"
style=
"@style/Authentication.EditText"
style=
"@style/Authentication.EditText"
android:layout_marginTop=
"32dp"
android:layout_marginTop=
"32dp"
android:drawableStart=
"@drawable/ic_person_black_24dp"
android:drawableStart=
"@drawable/ic_person_black_24dp"
...
@@ -37,7 +37,7 @@
...
@@ -37,7 +37,7 @@
android:inputType=
"text"
android:inputType=
"text"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/text_name"
/>
app:layout_constraintTop_toBottomOf=
"@+id/text_
user
name"
/>
<EditText
<EditText
android:id=
"@+id/text_password"
android:id=
"@+id/text_password"
...
...
app/src/main/res/layout/fragment_chat_room.xml
View file @
00ac09d2
...
@@ -27,8 +27,16 @@
...
@@ -27,8 +27,16 @@
layout=
"@layout/message_list"
layout=
"@layout/message_list"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
/>
android:layout_height=
"match_parent"
/>
</FrameLayout>
</FrameLayout>
<chat.rocket.android.widget.autocompletion.ui.SuggestionsView
android:id=
"@+id/suggestions_view"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_above=
"@+id/layout_message_composer"
android:background=
"@color/whitesmoke"
/>
<include
<include
android:id=
"@+id/layout_message_composer"
android:id=
"@+id/layout_message_composer"
layout=
"@layout/message_composer"
layout=
"@layout/message_composer"
...
@@ -57,15 +65,15 @@
...
@@ -57,15 +65,15 @@
android:id=
"@+id/connection_status_text"
android:id=
"@+id/connection_status_text"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"32dp"
android:layout_height=
"32dp"
android:alpha=
"0"
android:background=
"@color/colorPrimary"
android:background=
"@color/colorPrimary"
android:elevation=
"4dp"
android:elevation=
"4dp"
android:textColor=
"@color/white"
android:gravity=
"center"
android:gravity=
"center"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body2"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body2"
android:textColor=
"@color/white"
android:visibility=
"gone"
android:visibility=
"gone"
android:alpha=
"0"
tools:alpha=
"1"
tools:alpha=
"1"
tools:
visibility=
"visible
"
tools:
text=
"connected
"
tools:
text=
"connected"
/>
tools:
visibility=
"visible"
/>
</RelativeLayout>
</RelativeLayout>
app/src/main/res/layout/fragment_profile.xml
View file @
00ac09d2
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
android:layout_marginTop=
"32dp"
/>
android:layout_marginTop=
"32dp"
/>
<EditText
<EditText
android:id=
"@+id/text_name"
android:id=
"@+id/text_
user
name"
style=
"@style/Profile.EditText"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"32dp"
android:layout_marginTop=
"32dp"
android:drawableStart=
"@drawable/ic_person_black_24dp"
android:drawableStart=
"@drawable/ic_person_black_24dp"
...
...
app/src/main/res/layout/suggestion_member_item.xml
0 → 100644
View file @
00ac09d2
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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_margin=
"2dp"
android:background=
"@color/whitesmoke"
>
<FrameLayout
android:id=
"@+id/image_avatar_container"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_centerVertical=
"true"
>
<com.facebook.drawee.view.SimpleDraweeView
android:id=
"@+id/image_avatar"
android:layout_width=
"24dp"
android:layout_height=
"24dp"
android:layout_margin=
"4dp"
app:roundedCornerRadius=
"3dp"
tools:src=
"@tools:sample/avatars"
/>
<ImageView
android:id=
"@+id/image_status"
android:layout_width=
"12dp"
android:layout_height=
"12dp"
android:layout_gravity=
"bottom|end"
android:background=
"@drawable/user_status_white"
android:padding=
"2dp"
/>
</FrameLayout>
<RelativeLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_centerVertical=
"true"
android:layout_toEndOf=
"@id/image_avatar_container"
android:layout_toRightOf=
"@id/image_avatar_container"
android:background=
"@color/whitesmoke"
>
<TextView
android:id=
"@+id/text_username"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_centerVertical=
"true"
android:maxLines=
"1"
android:textColor=
"@color/black"
android:textSize=
"16sp"
tools:text=
"@tools:sample/full_names"
/>
<TextView
android:id=
"@+id/text_name"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_alignParentEnd=
"true"
android:layout_alignParentRight=
"true"
android:layout_centerVertical=
"true"
android:layout_toEndOf=
"@+id/text_username"
android:layout_toRightOf=
"@+id/text_username"
android:maxLines=
"1"
android:paddingLeft=
"8dp"
android:paddingStart=
"8dp"
android:textColor=
"@color/gray_material"
android:textSize=
"16sp"
tools:text=
"@tools:sample/full_names"
/>
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
app/src/main/res/layout/suggestion_room_item.xml
0 → 100644
View file @
00ac09d2
<?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_margin=
"2dp"
android:background=
"@color/whitesmoke"
>
<RelativeLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_centerVertical=
"true"
android:layout_toEndOf=
"@id/image_avatar_container"
android:layout_toRightOf=
"@id/image_avatar_container"
android:background=
"@color/whitesmoke"
>
<TextView
android:id=
"@+id/text_name"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_centerVertical=
"true"
android:maxLines=
"1"
android:textColor=
"@color/black"
android:textSize=
"16sp"
tools:text=
"@tools:sample/full_names"
/>
<TextView
android:id=
"@+id/text_fullname"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_alignParentEnd=
"true"
android:layout_alignParentRight=
"true"
android:layout_centerVertical=
"true"
android:layout_toEndOf=
"@+id/text_name"
android:layout_toRightOf=
"@+id/text_name"
android:maxLines=
"1"
android:paddingLeft=
"8dp"
android:paddingStart=
"8dp"
android:textColor=
"@color/gray_material"
android:textSize=
"16sp"
tools:text=
"@tools:sample/full_names"
/>
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
app/src/main/res/values/colors.xml
View file @
00ac09d2
...
@@ -34,4 +34,7 @@
...
@@ -34,4 +34,7 @@
<color
name=
"colorEmojiIcon"
>
#FF767676
</color>
<color
name=
"colorEmojiIcon"
>
#FF767676
</color>
<color
name=
"default_popup_background_color"
>
#ffffffff
</color>
<color
name=
"default_popup_item_color"
>
#ff000000
</color>
</resources>
</resources>
app/src/main/res/values/dimens.xml
View file @
00ac09d2
...
@@ -23,4 +23,7 @@
...
@@ -23,4 +23,7 @@
<dimen
name=
"padding_mention"
>
4dp
</dimen>
<dimen
name=
"padding_mention"
>
4dp
</dimen>
<dimen
name=
"radius_mention"
>
6dp
</dimen>
<dimen
name=
"radius_mention"
>
6dp
</dimen>
<!-- Autocomplete Popup -->
<dimen
name=
"popup_max_height"
>
150dp
</dimen>
</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