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
009cade1
Unverified
Commit
009cade1
authored
Mar 13, 2018
by
Lucio Maciel
Committed by
GitHub
Mar 13, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop-2.x' into guggy-gifs
parents
717824a7
619d60b7
Changes
94
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
94 changed files
with
2063 additions
and
284 deletions
+2063
-284
build.gradle
app/build.gradle
+1
-0
DrawableHelper.kt
app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
+8
-7
User.kt
app/src/main/java/chat/rocket/android/app/User.kt
+0
-7
SignupFragment.kt
...rocket/android/authentication/signup/ui/SignupFragment.kt
+2
-2
AudioAttachmentViewHolder.kt
...ket/android/chatroom/adapter/AudioAttachmentViewHolder.kt
+5
-2
AutoCompleteType.kt
.../chat/rocket/android/chatroom/adapter/AutoCompleteType.kt
+10
-0
BaseViewHolder.kt
...va/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt
+42
-3
ChatRoomAdapter.kt
...a/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
+32
-7
ImageAttachmentViewHolder.kt
...ket/android/chatroom/adapter/ImageAttachmentViewHolder.kt
+5
-2
MessageReactionsAdapter.kt
...ocket/android/chatroom/adapter/MessageReactionsAdapter.kt
+137
-0
MessageViewHolder.kt
...chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
+4
-2
PeopleSuggestionsAdapter.kt
...cket/android/chatroom/adapter/PeopleSuggestionsAdapter.kt
+52
-0
RoomSuggestionsAdapter.kt
...rocket/android/chatroom/adapter/RoomSuggestionsAdapter.kt
+37
-0
UrlPreviewViewHolder.kt
...t/rocket/android/chatroom/adapter/UrlPreviewViewHolder.kt
+5
-2
VideoAttachmentViewHolder.kt
...ket/android/chatroom/adapter/VideoAttachmentViewHolder.kt
+5
-2
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+146
-2
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+10
-0
ChatRoomActivity.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
+13
-2
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+83
-16
AudioAttachmentViewModel.kt
...et/android/chatroom/viewmodel/AudioAttachmentViewModel.kt
+4
-2
BaseViewModel.kt
...a/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
+2
-0
ChatRoomViewModel.kt
...at/rocket/android/chatroom/viewmodel/ChatRoomViewModel.kt
+9
-0
ImageAttachmentViewModel.kt
...et/android/chatroom/viewmodel/ImageAttachmentViewModel.kt
+3
-1
MessageViewModel.kt
...hat/rocket/android/chatroom/viewmodel/MessageViewModel.kt
+2
-0
PeopleViewModel.kt
...chat/rocket/android/chatroom/viewmodel/PeopleViewModel.kt
+17
-0
ReactionViewModel.kt
...at/rocket/android/chatroom/viewmodel/ReactionViewModel.kt
+9
-0
UrlPreviewViewModel.kt
.../rocket/android/chatroom/viewmodel/UrlPreviewViewModel.kt
+9
-7
VideoAttachmentViewModel.kt
...et/android/chatroom/viewmodel/VideoAttachmentViewModel.kt
+3
-1
ViewModelMapper.kt
...chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
+27
-5
ChatRoomsFragmentModule.kt
...at/rocket/android/chatrooms/di/ChatRoomsFragmentModule.kt
+0
-7
ChatRoomsModule.kt
.../java/chat/rocket/android/chatrooms/di/ChatRoomsModule.kt
+0
-16
ChatRoomsNavigator.kt
...cket/android/chatrooms/presentation/ChatRoomsNavigator.kt
+0
-14
ChatRoomsPresenter.kt
...cket/android/chatrooms/presentation/ChatRoomsPresenter.kt
+38
-5
ChatRoomsFragment.kt
...ava/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
+3
-1
LocalComponent.kt
...rc/main/java/chat/rocket/android/dagger/LocalComponent.kt
+27
-0
ActivityBuilder.kt
...java/chat/rocket/android/dagger/module/ActivityBuilder.kt
+0
-4
AppModule.kt
.../main/java/chat/rocket/android/dagger/module/AppModule.kt
+13
-1
LocalModule.kt
...ain/java/chat/rocket/android/dagger/module/LocalModule.kt
+24
-0
MainActivityModule.kt
...in/java/chat/rocket/android/main/di/MainActivityModule.kt
+0
-23
MainActivityProvider.kt
.../java/chat/rocket/android/main/di/MainActivityProvider.kt
+0
-12
MainModule.kt
app/src/main/java/chat/rocket/android/main/di/MainModule.kt
+13
-0
MainNavigator.kt
...va/chat/rocket/android/main/presentation/MainNavigator.kt
+12
-0
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+18
-11
MainActivity.kt
...src/main/java/chat/rocket/android/main/ui/MainActivity.kt
+6
-7
ProfileFragmentModule.kt
...a/chat/rocket/android/profile/di/ProfileFragmentModule.kt
+0
-7
ProfilePresenter.kt
...t/rocket/android/profile/presentation/ProfilePresenter.kt
+8
-8
ProfileFragment.kt
...in/java/chat/rocket/android/profile/ui/ProfileFragment.kt
+16
-16
GetChatRoomsInteractor.kt
...at/rocket/android/server/domain/GetChatRoomsInteractor.kt
+8
-0
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
+226
-0
CategoryPagerAdapter.kt
.../chat/rocket/android/widget/emoji/CategoryPagerAdapter.kt
+4
-4
EmojiKeyboardListener.kt
...chat/rocket/android/widget/emoji/EmojiKeyboardListener.kt
+19
-0
EmojiKeyboardPopup.kt
...va/chat/rocket/android/widget/emoji/EmojiKeyboardPopup.kt
+8
-29
EmojiListenerAdapter.kt
.../chat/rocket/android/widget/emoji/EmojiListenerAdapter.kt
+12
-0
EmojiPickerPopup.kt
...java/chat/rocket/android/widget/emoji/EmojiPickerPopup.kt
+61
-0
EmojiReactionListener.kt
...chat/rocket/android/widget/emoji/EmojiReactionListener.kt
+19
-0
ic_add_reaction.xml
app/src/main/res/drawable/ic_add_reaction.xml
+25
-0
rounded_background.xml
app/src/main/res/drawable/rounded_background.xml
+9
-0
suggestions_menu_decorator.xml
app/src/main/res/drawable/suggestions_menu_decorator.xml
+7
-0
user_status_white.xml
app/src/main/res/drawable/user_status_white.xml
+12
-0
emoji_keyboard.xml
app/src/main/res/layout/emoji_keyboard.xml
+7
-24
emoji_picker.xml
app/src/main/res/layout/emoji_picker.xml
+27
-0
fragment_chat_room.xml
app/src/main/res/layout/fragment_chat_room.xml
+12
-4
item_add_reaction.xml
app/src/main/res/layout/item_add_reaction.xml
+11
-0
item_message.xml
app/src/main/res/layout/item_message.xml
+8
-1
item_reaction.xml
app/src/main/res/layout/item_reaction.xml
+42
-0
layout_reactions.xml
app/src/main/res/layout/layout_reactions.xml
+5
-0
message_attachment.xml
app/src/main/res/layout/message_attachment.xml
+7
-2
message_composer.xml
app/src/main/res/layout/message_composer.xml
+12
-0
message_url_preview.xml
app/src/main/res/layout/message_url_preview.xml
+18
-12
suggestion_member_item.xml
app/src/main/res/layout/suggestion_member_item.xml
+74
-0
suggestion_room_item.xml
app/src/main/res/layout/suggestion_room_item.xml
+45
-0
message_actions.xml
app/src/main/res/menu/message_actions.xml
+5
-0
strings.xml
app/src/main/res/values-pt-rBR/strings.xml
+4
-1
colors.xml
app/src/main/res/values/colors.xml
+4
-1
dimens.xml
app/src/main/res/values/dimens.xml
+5
-0
strings.xml
app/src/main/res/values/strings.xml
+2
-0
build.gradle
build.gradle
+1
-1
dependencies.gradle
dependencies.gradle
+3
-1
No files found.
app/build.gradle
View file @
009cade1
...
@@ -59,6 +59,7 @@ dependencies {
...
@@ -59,6 +59,7 @@ dependencies {
implementation
libraries
.
design
implementation
libraries
.
design
implementation
libraries
.
constraintLayout
implementation
libraries
.
constraintLayout
implementation
libraries
.
cardView
implementation
libraries
.
cardView
implementation
libraries
.
flexbox
implementation
libraries
.
androidKtx
implementation
libraries
.
androidKtx
...
...
app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
View file @
009cade1
...
@@ -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
{
...
@@ -78,7 +79,7 @@ object DrawableHelper {
...
@@ -78,7 +79,7 @@ object DrawableHelper {
* @param drawables The array of Drawable.
* @param drawables The array of Drawable.
* @see compoundDrawable
* @see compoundDrawable
*/
*/
fun
compoundDrawables
(
textView
:
Array
<
EditText
>,
drawables
:
Array
<
Drawable
>)
{
fun
compoundDrawables
(
textView
:
Array
<
TextView
>,
drawables
:
Array
<
Drawable
>)
{
if
(
textView
.
size
!=
drawables
.
size
)
{
if
(
textView
.
size
!=
drawables
.
size
)
{
return
return
}
else
{
}
else
{
...
@@ -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 @
717824a7
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 @
009cade1
...
@@ -53,7 +53,7 @@ class SignupFragment : Fragment(), SignupView {
...
@@ -53,7 +53,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
)
}
}
}
}
...
@@ -146,7 +146,7 @@ class SignupFragment : Fragment(), SignupView {
...
@@ -146,7 +146,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/AudioAttachmentViewHolder.kt
View file @
009cade1
...
@@ -4,10 +4,13 @@ import android.view.View
...
@@ -4,10 +4,13 @@ import android.view.View
import
chat.rocket.android.chatroom.viewmodel.AudioAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.AudioAttachmentViewModel
import
chat.rocket.android.player.PlayerActivity
import
chat.rocket.android.player.PlayerActivity
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
kotlinx.android.synthetic.main.message_attachment.view.*
import
kotlinx.android.synthetic.main.message_attachment.view.*
class
AudioAttachmentViewHolder
(
itemView
:
View
,
listener
:
ActionsListener
)
class
AudioAttachmentViewHolder
(
itemView
:
View
,
:
BaseViewHolder
<
AudioAttachmentViewModel
>(
itemView
,
listener
)
{
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
AudioAttachmentViewModel
>(
itemView
,
listener
,
reactionListener
)
{
init
{
init
{
with
(
itemView
)
{
with
(
itemView
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/AutoCompleteType.kt
0 → 100644
View file @
009cade1
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/BaseViewHolder.kt
View file @
009cade1
...
@@ -7,14 +7,20 @@ import chat.rocket.android.R
...
@@ -7,14 +7,20 @@ import chat.rocket.android.R
import
chat.rocket.android.chatroom.ui.bottomsheet.BottomSheetMenu
import
chat.rocket.android.chatroom.ui.bottomsheet.BottomSheetMenu
import
chat.rocket.android.chatroom.ui.bottomsheet.adapter.ActionListAdapter
import
chat.rocket.android.chatroom.ui.bottomsheet.adapter.ActionListAdapter
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.widget.emoji.Emoji
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.isSystemMessage
import
chat.rocket.core.model.isSystemMessage
import
com.google.android.flexbox.FlexDirection
import
com.google.android.flexbox.FlexboxLayoutManager
import
ru.whalemare.sheetmenu.extension.inflate
import
ru.whalemare.sheetmenu.extension.inflate
import
ru.whalemare.sheetmenu.extension.toList
import
ru.whalemare.sheetmenu.extension.toList
abstract
class
BaseViewHolder
<
T
:
BaseViewModel
<*>>(
abstract
class
BaseViewHolder
<
T
:
BaseViewModel
<*>>(
itemView
:
View
,
itemView
:
View
,
private
val
listener
:
ActionsListener
private
val
listener
:
ActionsListener
,
var
reactionListener
:
EmojiReactionListener
?
=
null
)
:
RecyclerView
.
ViewHolder
(
itemView
),
)
:
RecyclerView
.
ViewHolder
(
itemView
),
MenuItem
.
OnMenuItemClickListener
{
MenuItem
.
OnMenuItemClickListener
{
var
data
:
T
?
=
null
var
data
:
T
?
=
null
...
@@ -26,6 +32,39 @@ abstract class BaseViewHolder<T : BaseViewModel<*>>(
...
@@ -26,6 +32,39 @@ abstract class BaseViewHolder<T : BaseViewModel<*>>(
fun
bind
(
data
:
T
)
{
fun
bind
(
data
:
T
)
{
this
.
data
=
data
this
.
data
=
data
bindViews
(
data
)
bindViews
(
data
)
bindReactions
()
}
private
fun
bindReactions
()
{
data
?.
let
{
val
recyclerView
=
itemView
.
findViewById
(
R
.
id
.
recycler_view_reactions
)
as
RecyclerView
val
adapter
:
MessageReactionsAdapter
if
(
recyclerView
.
adapter
==
null
)
{
adapter
=
MessageReactionsAdapter
()
}
else
{
adapter
=
recyclerView
.
adapter
as
MessageReactionsAdapter
adapter
.
clear
()
}
if
(
it
.
nextDownStreamMessage
==
null
)
{
adapter
.
listener
=
object
:
EmojiReactionListener
{
override
fun
onReactionTouched
(
messageId
:
String
,
emojiShortname
:
String
)
{
reactionListener
?.
onReactionTouched
(
messageId
,
emojiShortname
)
}
override
fun
onReactionAdded
(
messageId
:
String
,
emoji
:
Emoji
)
{
if
(!
adapter
.
contains
(
emoji
.
shortname
))
{
reactionListener
?.
onReactionAdded
(
messageId
,
emoji
)
}
}
}
val
context
=
itemView
.
context
val
manager
=
FlexboxLayoutManager
(
context
,
FlexDirection
.
ROW
)
recyclerView
.
layoutManager
=
manager
recyclerView
.
adapter
=
adapter
adapter
.
addReactions
(
it
.
reactions
.
filterNot
{
it
.
unicode
.
startsWith
(
":"
)
})
}
}
}
}
abstract
fun
bindViews
(
data
:
T
)
abstract
fun
bindViews
(
data
:
T
)
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
View file @
009cade1
...
@@ -7,6 +7,7 @@ import chat.rocket.android.R
...
@@ -7,6 +7,7 @@ import chat.rocket.android.R
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.viewmodel.*
import
chat.rocket.android.chatroom.viewmodel.*
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.isSystemMessage
import
chat.rocket.core.model.isSystemMessage
import
timber.log.Timber
import
timber.log.Timber
...
@@ -16,7 +17,8 @@ class ChatRoomAdapter(
...
@@ -16,7 +17,8 @@ class ChatRoomAdapter(
private
val
roomType
:
String
,
private
val
roomType
:
String
,
private
val
roomName
:
String
,
private
val
roomName
:
String
,
private
val
presenter
:
ChatRoomPresenter
?,
private
val
presenter
:
ChatRoomPresenter
?,
private
val
enableActions
:
Boolean
=
true
private
val
enableActions
:
Boolean
=
true
,
private
val
reactionListener
:
EmojiReactionListener
?
=
null
)
:
RecyclerView
.
Adapter
<
BaseViewHolder
<*>>()
{
)
:
RecyclerView
.
Adapter
<
BaseViewHolder
<*>>()
{
private
val
dataSet
=
ArrayList
<
BaseViewModel
<*>>()
private
val
dataSet
=
ArrayList
<
BaseViewModel
<*>>()
...
@@ -29,23 +31,23 @@ class ChatRoomAdapter(
...
@@ -29,23 +31,23 @@ class ChatRoomAdapter(
return
when
(
viewType
.
toViewType
())
{
return
when
(
viewType
.
toViewType
())
{
BaseViewModel
.
ViewType
.
MESSAGE
->
{
BaseViewModel
.
ViewType
.
MESSAGE
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
item_message
)
val
view
=
parent
.
inflate
(
R
.
layout
.
item_message
)
MessageViewHolder
(
view
,
actionsListener
)
MessageViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
}
BaseViewModel
.
ViewType
.
IMAGE_ATTACHMENT
->
{
BaseViewModel
.
ViewType
.
IMAGE_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
ImageAttachmentViewHolder
(
view
,
actionsListener
)
ImageAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
}
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
->
{
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
AudioAttachmentViewHolder
(
view
,
actionsListener
)
AudioAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
}
BaseViewModel
.
ViewType
.
VIDEO_ATTACHMENT
->
{
BaseViewModel
.
ViewType
.
VIDEO_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
VideoAttachmentViewHolder
(
view
,
actionsListener
)
VideoAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
}
BaseViewModel
.
ViewType
.
URL_PREVIEW
->
{
BaseViewModel
.
ViewType
.
URL_PREVIEW
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
message_url_preview
)
val
view
=
parent
.
inflate
(
R
.
layout
.
message_url_preview
)
UrlPreviewViewHolder
(
view
,
actionsListener
)
UrlPreviewViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
}
else
->
{
else
->
{
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
...
@@ -62,6 +64,23 @@ class ChatRoomAdapter(
...
@@ -62,6 +64,23 @@ class ChatRoomAdapter(
}
}
override
fun
onBindViewHolder
(
holder
:
BaseViewHolder
<
*
>,
position
:
Int
)
{
override
fun
onBindViewHolder
(
holder
:
BaseViewHolder
<
*
>,
position
:
Int
)
{
if
(
holder
!
is
MessageViewHolder
)
{
if
(
position
+
1
<
itemCount
)
{
val
messageAbove
=
dataSet
[
position
+
1
]
if
(
messageAbove
.
messageId
==
dataSet
[
position
].
messageId
)
{
messageAbove
.
nextDownStreamMessage
=
dataSet
[
position
]
}
}
}
else
{
if
(
position
==
0
)
{
dataSet
[
0
].
nextDownStreamMessage
=
null
}
else
if
(
position
-
1
>
0
)
{
if
(
dataSet
[
position
-
1
].
messageId
!=
dataSet
[
position
].
messageId
)
{
dataSet
[
position
].
nextDownStreamMessage
=
null
}
}
}
when
(
holder
)
{
when
(
holder
)
{
is
MessageViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageViewModel
)
is
MessageViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageViewModel
)
is
ImageAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
ImageAttachmentViewModel
)
is
ImageAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
ImageAttachmentViewModel
)
...
@@ -97,12 +116,17 @@ class ChatRoomAdapter(
...
@@ -97,12 +116,17 @@ class ChatRoomAdapter(
}
}
fun
updateItem
(
message
:
BaseViewModel
<
*
>)
{
fun
updateItem
(
message
:
BaseViewModel
<
*
>)
{
va
l
index
=
dataSet
.
indexOfLast
{
it
.
messageId
==
message
.
messageId
}
va
r
index
=
dataSet
.
indexOfLast
{
it
.
messageId
==
message
.
messageId
}
val
indexOfFirst
=
dataSet
.
indexOfFirst
{
it
.
messageId
==
message
.
messageId
}
val
indexOfFirst
=
dataSet
.
indexOfFirst
{
it
.
messageId
==
message
.
messageId
}
Timber
.
d
(
"index: $index"
)
Timber
.
d
(
"index: $index"
)
if
(
index
>
-
1
)
{
if
(
index
>
-
1
)
{
message
.
nextDownStreamMessage
=
dataSet
[
index
].
nextDownStreamMessage
dataSet
[
index
]
=
message
dataSet
[
index
]
=
message
notifyItemChanged
(
index
)
notifyItemChanged
(
index
)
while
(
dataSet
[
index
].
nextDownStreamMessage
!=
null
)
{
dataSet
[
index
].
nextDownStreamMessage
!!
.
reactions
=
message
.
reactions
notifyItemChanged
(--
index
)
}
// Delete message only if current is a system message update, i.e.: Message Removed
// Delete message only if current is a system message update, i.e.: Message Removed
if
(
message
.
message
.
isSystemMessage
()
&&
indexOfFirst
>
-
1
&&
indexOfFirst
!=
index
)
{
if
(
message
.
message
.
isSystemMessage
()
&&
indexOfFirst
>
-
1
&&
indexOfFirst
!=
index
)
{
dataSet
.
removeAt
(
indexOfFirst
)
dataSet
.
removeAt
(
indexOfFirst
)
...
@@ -143,6 +167,7 @@ class ChatRoomAdapter(
...
@@ -143,6 +167,7 @@ class ChatRoomAdapter(
}
}
}
}
}
}
R
.
id
.
action_menu_msg_react
->
presenter
?.
showReactions
(
id
)
else
->
TODO
(
"Not implemented"
)
else
->
TODO
(
"Not implemented"
)
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ImageAttachmentViewHolder.kt
View file @
009cade1
...
@@ -4,11 +4,14 @@ import android.view.View
...
@@ -4,11 +4,14 @@ import android.view.View
import
chat.rocket.android.chatroom.viewmodel.ImageAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.ImageAttachmentViewModel
import
com.facebook.drawee.backends.pipeline.Fresco
import
com.facebook.drawee.backends.pipeline.Fresco
import
com.facebook.drawee.interfaces.DraweeController
import
com.facebook.drawee.interfaces.DraweeController
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
com.stfalcon.frescoimageviewer.ImageViewer
import
com.stfalcon.frescoimageviewer.ImageViewer
import
kotlinx.android.synthetic.main.message_attachment.view.*
import
kotlinx.android.synthetic.main.message_attachment.view.*
class
ImageAttachmentViewHolder
(
itemView
:
View
,
listener
:
ActionsListener
)
class
ImageAttachmentViewHolder
(
itemView
:
View
,
:
BaseViewHolder
<
ImageAttachmentViewModel
>(
itemView
,
listener
)
{
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
ImageAttachmentViewModel
>(
itemView
,
listener
,
reactionListener
)
{
init
{
init
{
with
(
itemView
)
{
with
(
itemView
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageReactionsAdapter.kt
0 → 100644
View file @
009cade1
package
chat.rocket.android.chatroom.adapter
import
android.support.v7.widget.RecyclerView
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.viewmodel.ReactionViewModel
import
chat.rocket.android.dagger.DaggerLocalComponent
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.widget.emoji.Emoji
import
chat.rocket.android.widget.emoji.EmojiListenerAdapter
import
chat.rocket.android.widget.emoji.EmojiPickerPopup
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
java.util.concurrent.CopyOnWriteArrayList
import
javax.inject.Inject
class
MessageReactionsAdapter
:
RecyclerView
.
Adapter
<
RecyclerView
.
ViewHolder
>()
{
companion
object
{
private
const
val
REACTION_VIEW_TYPE
=
0
private
const
val
ADD_REACTION_VIEW_TYPE
=
1
}
private
val
reactions
=
CopyOnWriteArrayList
<
ReactionViewModel
>()
var
listener
:
EmojiReactionListener
?
=
null
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
RecyclerView
.
ViewHolder
{
val
inflater
=
LayoutInflater
.
from
(
parent
.
context
)
val
view
:
View
return
when
(
viewType
)
{
ADD_REACTION_VIEW_TYPE
->
{
view
=
inflater
.
inflate
(
R
.
layout
.
item_add_reaction
,
parent
,
false
)
AddReactionViewHolder
(
view
,
listener
)
}
else
->
{
view
=
inflater
.
inflate
(
R
.
layout
.
item_reaction
,
parent
,
false
)
SingleReactionViewHolder
(
view
,
listener
)
}
}
}
override
fun
onBindViewHolder
(
holder
:
RecyclerView
.
ViewHolder
,
position
:
Int
)
{
if
(
holder
is
SingleReactionViewHolder
)
{
holder
.
bind
(
reactions
[
position
])
}
else
{
holder
as
AddReactionViewHolder
holder
.
bind
(
reactions
[
0
].
messageId
)
}
}
override
fun
getItemCount
()
=
if
(
reactions
.
isEmpty
())
0
else
reactions
.
size
+
1
override
fun
getItemViewType
(
position
:
Int
):
Int
{
if
(
position
==
reactions
.
size
)
{
return
ADD_REACTION_VIEW_TYPE
}
return
REACTION_VIEW_TYPE
}
fun
addReactions
(
reactions
:
List
<
ReactionViewModel
>)
{
this
.
reactions
.
clear
()
this
.
reactions
.
addAllAbsent
(
reactions
)
notifyItemRangeInserted
(
0
,
reactions
.
size
)
}
fun
clear
()
{
val
oldSize
=
reactions
.
size
reactions
.
clear
()
notifyItemRangeRemoved
(
0
,
oldSize
)
}
fun
contains
(
reactionShortname
:
String
)
=
reactions
.
firstOrNull
{
it
.
shortname
==
reactionShortname
}
!=
null
class
SingleReactionViewHolder
(
view
:
View
,
private
val
listener
:
EmojiReactionListener
?)
:
RecyclerView
.
ViewHolder
(
view
),
View
.
OnClickListener
{
@Inject
lateinit
var
localRepository
:
LocalRepository
@Volatile
lateinit
var
reaction
:
ReactionViewModel
@Volatile
var
clickHandled
=
false
init
{
DaggerLocalComponent
.
builder
()
.
context
(
itemView
.
context
)
.
build
()
.
inject
(
this
)
}
fun
bind
(
reaction
:
ReactionViewModel
)
{
clickHandled
=
false
this
.
reaction
=
reaction
with
(
itemView
)
{
val
emojiTextView
=
findViewById
<
TextView
>(
R
.
id
.
text_emoji
)
val
countTextView
=
findViewById
<
TextView
>(
R
.
id
.
text_count
)
emojiTextView
.
text
=
reaction
.
unicode
countTextView
.
text
=
reaction
.
count
.
toString
()
val
myself
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
if
(
reaction
.
usernames
.
contains
(
myself
))
{
val
context
=
itemView
.
context
val
resources
=
context
.
resources
countTextView
.
setTextColor
(
resources
.
getColor
(
R
.
color
.
colorAccent
))
}
emojiTextView
.
setOnClickListener
(
this
@SingleReactionViewHolder
)
countTextView
.
setOnClickListener
(
this
@SingleReactionViewHolder
)
}
}
override
fun
onClick
(
v
:
View
?)
{
synchronized
(
this
)
{
if
(!
clickHandled
)
{
clickHandled
=
true
listener
?.
onReactionTouched
(
reaction
.
messageId
,
reaction
.
shortname
)
}
}
}
}
class
AddReactionViewHolder
(
view
:
View
,
private
val
listener
:
EmojiReactionListener
?)
:
RecyclerView
.
ViewHolder
(
view
)
{
fun
bind
(
messageId
:
String
)
{
itemView
as
ImageView
itemView
.
setOnClickListener
{
val
emojiPickerPopup
=
EmojiPickerPopup
(
itemView
.
context
)
emojiPickerPopup
.
listener
=
object
:
EmojiListenerAdapter
()
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
listener
?.
onReactionAdded
(
messageId
,
emoji
)
}
}
emojiPickerPopup
.
show
()
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
View file @
009cade1
...
@@ -3,13 +3,15 @@ package chat.rocket.android.chatroom.adapter
...
@@ -3,13 +3,15 @@ package chat.rocket.android.chatroom.adapter
import
android.text.method.LinkMovementMethod
import
android.text.method.LinkMovementMethod
import
android.view.View
import
android.view.View
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
kotlinx.android.synthetic.main.avatar.view.*
import
kotlinx.android.synthetic.main.avatar.view.*
import
kotlinx.android.synthetic.main.item_message.view.*
import
kotlinx.android.synthetic.main.item_message.view.*
class
MessageViewHolder
(
class
MessageViewHolder
(
itemView
:
View
,
itemView
:
View
,
listener
:
ActionsListener
listener
:
ActionsListener
,
)
:
BaseViewHolder
<
MessageViewModel
>(
itemView
,
listener
)
{
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
MessageViewModel
>(
itemView
,
listener
,
reactionListener
)
{
init
{
init
{
with
(
itemView
)
{
with
(
itemView
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/PeopleSuggestionsAdapter.kt
0 → 100644
View file @
009cade1
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 @
009cade1
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.ChatRoomViewModel
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
ChatRoomViewModel
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/adapter/UrlPreviewViewHolder.kt
View file @
009cade1
...
@@ -6,10 +6,13 @@ import android.view.View
...
@@ -6,10 +6,13 @@ import android.view.View
import
chat.rocket.android.chatroom.viewmodel.UrlPreviewViewModel
import
chat.rocket.android.chatroom.viewmodel.UrlPreviewViewModel
import
chat.rocket.android.util.extensions.content
import
chat.rocket.android.util.extensions.content
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
kotlinx.android.synthetic.main.message_url_preview.view.*
import
kotlinx.android.synthetic.main.message_url_preview.view.*
class
UrlPreviewViewHolder
(
itemView
:
View
,
listener
:
ActionsListener
)
class
UrlPreviewViewHolder
(
itemView
:
View
,
:
BaseViewHolder
<
UrlPreviewViewModel
>(
itemView
,
listener
)
{
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
UrlPreviewViewModel
>(
itemView
,
listener
,
reactionListener
)
{
init
{
init
{
with
(
itemView
)
{
with
(
itemView
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/VideoAttachmentViewHolder.kt
View file @
009cade1
...
@@ -4,10 +4,13 @@ import android.view.View
...
@@ -4,10 +4,13 @@ import android.view.View
import
chat.rocket.android.chatroom.viewmodel.VideoAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.VideoAttachmentViewModel
import
chat.rocket.android.player.PlayerActivity
import
chat.rocket.android.player.PlayerActivity
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
kotlinx.android.synthetic.main.message_attachment.view.*
import
kotlinx.android.synthetic.main.message_attachment.view.*
class
VideoAttachmentViewHolder
(
itemView
:
View
,
listener
:
ActionsListener
)
class
VideoAttachmentViewHolder
(
itemView
:
View
,
:
BaseViewHolder
<
VideoAttachmentViewModel
>(
itemView
,
listener
)
{
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
VideoAttachmentViewModel
>(
itemView
,
listener
,
reactionListener
)
{
init
{
init
{
with
(
itemView
)
{
with
(
itemView
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
009cade1
...
@@ -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.ChatRoomViewModel
import
chat.rocket.android.chatroom.viewmodel.PeopleViewModel
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
...
@@ -31,9 +39,13 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
...
@@ -31,9 +39,13 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private
val
strategy
:
CancelStrategy
,
private
val
strategy
:
CancelStrategy
,
getSettingsInteractor
:
GetSettingsInteractor
,
getSettingsInteractor
:
GetSettingsInteractor
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
getChatRoomsInteractor
:
GetChatRoomsInteractor
,
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
()
!!
...
@@ -342,8 +354,140 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
...
@@ -342,8 +354,140 @@ 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
)
ChatRoomViewModel
(
name
,
fullName
,
name
,
searchList
)
})
}
}
}
catch
(
e
:
RocketChatException
)
{
Timber
.
e
(
e
)
}
}
}
fun
toMembersList
(
chatRoomId
:
String
,
chatRoomType
:
String
)
=
navigator
.
toMembersList
(
chatRoomId
,
chatRoomType
)
fun
toMembersList
(
chatRoomId
:
String
,
chatRoomType
:
String
)
=
navigator
.
toMembersList
(
chatRoomId
,
chatRoomType
)
fun
loadChatRooms
()
{
launchUI
(
strategy
)
{
try
{
val
chatRooms
=
getChatRoomsInteractor
.
get
(
currentServer
)
.
filterNot
{
it
.
type
is
RoomType
.
DirectMessage
||
it
.
type
is
RoomType
.
Livechat
}
.
map
{
chatRoom
->
val
name
=
chatRoom
.
name
val
fullName
=
chatRoom
.
fullName
?:
""
ChatRoomViewModel
(
text
=
name
,
name
=
name
,
fullName
=
fullName
,
searchList
=
listOf
(
name
,
fullName
)
)
}
view
.
populateRooms
(
chatRooms
)
}
catch
(
e
:
RocketChatException
)
{
Timber
.
e
(
e
)
}
}
}
fun
joinChat
(
chatRoomId
:
String
)
{
launchUI
(
strategy
)
{
try
{
client
.
joinChat
(
chatRoomId
)
view
.
onJoined
()
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
}
}
}
/**
* Send an emoji reaction to a message.
*/
fun
react
(
messageId
:
String
,
emoji
:
String
)
{
launchUI
(
strategy
)
{
try
{
client
.
toggleReaction
(
messageId
,
emoji
.
removeSurrounding
(
":"
))
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
}
}
}
fun
showReactions
(
messageId
:
String
)
{
view
.
showReactionsPopup
(
messageId
)
}
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 @
009cade1
...
@@ -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.ChatRoomViewModel
import
chat.rocket.android.chatroom.viewmodel.PeopleViewModel
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,12 @@ interface ChatRoomView : LoadingView, MessageView {
...
@@ -100,4 +102,12 @@ 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
(
chatRooms
:
List
<
ChatRoomViewModel
>)
/**
* This user has joined the chat callback.
*/
fun
onJoined
()
fun
showReactionsPopup
(
messageId
:
String
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
View file @
009cade1
...
@@ -23,13 +23,19 @@ import javax.inject.Inject
...
@@ -23,13 +23,19 @@ import javax.inject.Inject
import
timber.log.Timber
import
timber.log.Timber
fun
Context
.
chatRoomIntent
(
chatRoomId
:
String
,
chatRoomName
:
String
,
chatRoomType
:
String
,
isChatRoomReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
):
Intent
{
fun
Context
.
chatRoomIntent
(
chatRoomId
:
String
,
chatRoomName
:
String
,
chatRoomType
:
String
,
isChatRoomReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
,
isChatRoomSubscribed
:
Boolean
=
true
):
Intent
{
return
Intent
(
this
,
ChatRoomActivity
::
class
.
java
).
apply
{
return
Intent
(
this
,
ChatRoomActivity
::
class
.
java
).
apply
{
putExtra
(
INTENT_CHAT_ROOM_ID
,
chatRoomId
)
putExtra
(
INTENT_CHAT_ROOM_ID
,
chatRoomId
)
putExtra
(
INTENT_CHAT_ROOM_NAME
,
chatRoomName
)
putExtra
(
INTENT_CHAT_ROOM_NAME
,
chatRoomName
)
putExtra
(
INTENT_CHAT_ROOM_TYPE
,
chatRoomType
)
putExtra
(
INTENT_CHAT_ROOM_TYPE
,
chatRoomType
)
putExtra
(
INTENT_IS_CHAT_ROOM_READ_ONLY
,
isChatRoomReadOnly
)
putExtra
(
INTENT_IS_CHAT_ROOM_READ_ONLY
,
isChatRoomReadOnly
)
putExtra
(
INTENT_CHAT_ROOM_LAST_SEEN
,
chatRoomLastSeen
)
putExtra
(
INTENT_CHAT_ROOM_LAST_SEEN
,
chatRoomLastSeen
)
putExtra
(
INTENT_CHAT_IS_SUBSCRIBED
,
isChatRoomSubscribed
)
}
}
}
}
...
@@ -38,6 +44,7 @@ private const val INTENT_CHAT_ROOM_NAME = "chat_room_name"
...
@@ -38,6 +44,7 @@ private const val INTENT_CHAT_ROOM_NAME = "chat_room_name"
private
const
val
INTENT_CHAT_ROOM_TYPE
=
"chat_room_type"
private
const
val
INTENT_CHAT_ROOM_TYPE
=
"chat_room_type"
private
const
val
INTENT_IS_CHAT_ROOM_READ_ONLY
=
"is_chat_room_read_only"
private
const
val
INTENT_IS_CHAT_ROOM_READ_ONLY
=
"is_chat_room_read_only"
private
const
val
INTENT_CHAT_ROOM_LAST_SEEN
=
"chat_room_last_seen"
private
const
val
INTENT_CHAT_ROOM_LAST_SEEN
=
"chat_room_last_seen"
private
const
val
INTENT_CHAT_IS_SUBSCRIBED
=
"is_chat_room_subscribed"
class
ChatRoomActivity
:
AppCompatActivity
(),
HasSupportFragmentInjector
{
class
ChatRoomActivity
:
AppCompatActivity
(),
HasSupportFragmentInjector
{
@Inject
lateinit
var
fragmentDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Fragment
>
@Inject
lateinit
var
fragmentDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Fragment
>
...
@@ -50,6 +57,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
...
@@ -50,6 +57,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
private
lateinit
var
chatRoomName
:
String
private
lateinit
var
chatRoomName
:
String
private
lateinit
var
chatRoomType
:
String
private
lateinit
var
chatRoomType
:
String
private
var
isChatRoomReadOnly
:
Boolean
=
false
private
var
isChatRoomReadOnly
:
Boolean
=
false
private
var
isChatRoomSubscribed
:
Boolean
=
true
private
var
chatRoomLastSeen
:
Long
=
-
1L
private
var
chatRoomLastSeen
:
Long
=
-
1L
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
...
@@ -76,8 +84,11 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
...
@@ -76,8 +84,11 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
chatRoomLastSeen
=
intent
.
getLongExtra
(
INTENT_CHAT_ROOM_LAST_SEEN
,
-
1
)
chatRoomLastSeen
=
intent
.
getLongExtra
(
INTENT_CHAT_ROOM_LAST_SEEN
,
-
1
)
isChatRoomSubscribed
=
intent
.
getBooleanExtra
(
INTENT_CHAT_IS_SUBSCRIBED
,
true
)
addFragment
(
"ChatRoomFragment"
,
R
.
id
.
fragment_container
)
{
addFragment
(
"ChatRoomFragment"
,
R
.
id
.
fragment_container
)
{
newInstance
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
isChatRoomReadOnly
,
chatRoomLastSeen
)
newInstance
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
isChatRoomReadOnly
,
chatRoomLastSeen
,
isChatRoomSubscribed
)
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
009cade1
This diff is collapsed.
Click to expand it.
app/src/main/java/chat/rocket/android/chatroom/viewmodel/AudioAttachmentViewModel.kt
View file @
009cade1
...
@@ -10,8 +10,10 @@ data class AudioAttachmentViewModel(
...
@@ -10,8 +10,10 @@ data class AudioAttachmentViewModel(
override
val
messageId
:
String
,
override
val
messageId
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentTitle
:
CharSequence
,
override
val
attachmentTitle
:
CharSequence
,
override
val
id
:
Long
override
val
id
:
Long
,
)
:
BaseFileAttachmentViewModel
<
AudioAttachment
>
{
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
)
:
BaseFileAttachmentViewModel
<
AudioAttachment
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
.
viewType
get
()
=
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
.
viewType
override
val
layoutId
:
Int
override
val
layoutId
:
Int
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
View file @
009cade1
...
@@ -9,6 +9,8 @@ interface BaseViewModel<out T> {
...
@@ -9,6 +9,8 @@ interface BaseViewModel<out T> {
val
messageId
:
String
val
messageId
:
String
val
viewType
:
Int
val
viewType
:
Int
val
layoutId
:
Int
val
layoutId
:
Int
var
reactions
:
List
<
ReactionViewModel
>
var
nextDownStreamMessage
:
BaseViewModel
<*>?
enum
class
ViewType
(
val
viewType
:
Int
)
{
enum
class
ViewType
(
val
viewType
:
Int
)
{
MESSAGE
(
0
),
MESSAGE
(
0
),
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ChatRoomViewModel.kt
0 → 100644
View file @
009cade1
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/ImageAttachmentViewModel.kt
View file @
009cade1
...
@@ -10,7 +10,9 @@ data class ImageAttachmentViewModel(
...
@@ -10,7 +10,9 @@ data class ImageAttachmentViewModel(
override
val
messageId
:
String
,
override
val
messageId
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentTitle
:
CharSequence
,
override
val
attachmentTitle
:
CharSequence
,
override
val
id
:
Long
override
val
id
:
Long
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
)
:
BaseFileAttachmentViewModel
<
ImageAttachment
>
{
)
:
BaseFileAttachmentViewModel
<
ImageAttachment
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
IMAGE_ATTACHMENT
.
viewType
get
()
=
BaseViewModel
.
ViewType
.
IMAGE_ATTACHMENT
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/MessageViewModel.kt
View file @
009cade1
...
@@ -12,6 +12,8 @@ data class MessageViewModel(
...
@@ -12,6 +12,8 @@ data class MessageViewModel(
override
val
senderName
:
CharSequence
,
override
val
senderName
:
CharSequence
,
override
val
content
:
CharSequence
,
override
val
content
:
CharSequence
,
override
val
isPinned
:
Boolean
,
override
val
isPinned
:
Boolean
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
var
isFirstUnread
:
Boolean
var
isFirstUnread
:
Boolean
)
:
BaseMessageViewModel
<
Message
>
{
)
:
BaseMessageViewModel
<
Message
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/PeopleViewModel.kt
0 → 100644
View file @
009cade1
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/ReactionViewModel.kt
0 → 100644
View file @
009cade1
package
chat.rocket.android.chatroom.viewmodel
data class
ReactionViewModel
(
val
messageId
:
String
,
val
shortname
:
String
,
val
unicode
:
CharSequence
,
val
count
:
Int
,
val
usernames
:
List
<
String
>
=
emptyList
()
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/UrlPreviewViewModel.kt
View file @
009cade1
...
@@ -11,7 +11,9 @@ data class UrlPreviewViewModel(
...
@@ -11,7 +11,9 @@ data class UrlPreviewViewModel(
val
title
:
CharSequence
?,
val
title
:
CharSequence
?,
val
hostname
:
String
,
val
hostname
:
String
,
val
description
:
CharSequence
?,
val
description
:
CharSequence
?,
val
thumbUrl
:
String
?
val
thumbUrl
:
String
?,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
)
:
BaseViewModel
<
Url
>
{
)
:
BaseViewModel
<
Url
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
URL_PREVIEW
.
viewType
get
()
=
BaseViewModel
.
ViewType
.
URL_PREVIEW
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/VideoAttachmentViewModel.kt
View file @
009cade1
...
@@ -10,7 +10,9 @@ data class VideoAttachmentViewModel(
...
@@ -10,7 +10,9 @@ data class VideoAttachmentViewModel(
override
val
messageId
:
String
,
override
val
messageId
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentTitle
:
CharSequence
,
override
val
attachmentTitle
:
CharSequence
,
override
val
id
:
Long
override
val
id
:
Long
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
)
:
BaseFileAttachmentViewModel
<
VideoAttachment
>
{
)
:
BaseFileAttachmentViewModel
<
VideoAttachment
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
VIDEO_ATTACHMENT
.
viewType
get
()
=
BaseViewModel
.
ViewType
.
VIDEO_ATTACHMENT
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
View file @
009cade1
...
@@ -14,6 +14,7 @@ import chat.rocket.android.helper.MessageParser
...
@@ -14,6 +14,7 @@ import chat.rocket.android.helper.MessageParser
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.core.TokenRepository
import
chat.rocket.core.TokenRepository
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.MessageType
import
chat.rocket.core.model.MessageType
...
@@ -83,7 +84,8 @@ class ViewModelMapper @Inject constructor(private val context: Context,
...
@@ -83,7 +84,8 @@ class ViewModelMapper @Inject constructor(private val context: Context,
val
title
=
url
.
meta
?.
title
val
title
=
url
.
meta
?.
title
val
description
=
url
.
meta
?.
description
val
description
=
url
.
meta
?.
description
return
UrlPreviewViewModel
(
message
,
url
,
message
.
id
,
title
,
hostname
,
description
,
thumb
)
return
UrlPreviewViewModel
(
message
,
url
,
message
.
id
,
title
,
hostname
,
description
,
thumb
,
getReactions
(
message
))
}
}
private
fun
mapAttachment
(
message
:
Message
,
attachment
:
Attachment
):
BaseViewModel
<
*
>?
{
private
fun
mapAttachment
(
message
:
Message
,
attachment
:
Attachment
):
BaseViewModel
<
*
>?
{
...
@@ -103,11 +105,11 @@ class ViewModelMapper @Inject constructor(private val context: Context,
...
@@ -103,11 +105,11 @@ class ViewModelMapper @Inject constructor(private val context: Context,
val
id
=
"${message.id}_${attachment.url}"
.
hashCode
().
toLong
()
val
id
=
"${message.id}_${attachment.url}"
.
hashCode
().
toLong
()
return
when
(
attachment
)
{
return
when
(
attachment
)
{
is
ImageAttachment
->
ImageAttachmentViewModel
(
message
,
attachment
,
message
.
id
,
is
ImageAttachment
->
ImageAttachmentViewModel
(
message
,
attachment
,
message
.
id
,
attachmentUrl
,
attachmentTitle
,
id
)
attachmentUrl
,
attachmentTitle
,
id
,
getReactions
(
message
)
)
is
VideoAttachment
->
VideoAttachmentViewModel
(
message
,
attachment
,
message
.
id
,
is
VideoAttachment
->
VideoAttachmentViewModel
(
message
,
attachment
,
message
.
id
,
attachmentUrl
,
attachmentTitle
,
id
)
attachmentUrl
,
attachmentTitle
,
id
,
getReactions
(
message
)
)
is
AudioAttachment
->
AudioAttachmentViewModel
(
message
,
attachment
,
message
.
id
,
is
AudioAttachment
->
AudioAttachmentViewModel
(
message
,
attachment
,
message
.
id
,
attachmentUrl
,
attachmentTitle
,
id
)
attachmentUrl
,
attachmentTitle
,
id
,
getReactions
(
message
)
)
else
->
null
else
->
null
}
}
}
}
...
@@ -153,7 +155,27 @@ class ViewModelMapper @Inject constructor(private val context: Context,
...
@@ -153,7 +155,27 @@ class ViewModelMapper @Inject constructor(private val context: Context,
val
content
=
getContent
(
context
,
getMessageWithoutQuoteMarkdown
(
message
),
quote
)
val
content
=
getContent
(
context
,
getMessageWithoutQuoteMarkdown
(
message
),
quote
)
MessageViewModel
(
message
=
getMessageWithoutQuoteMarkdown
(
message
),
rawData
=
message
,
MessageViewModel
(
message
=
getMessageWithoutQuoteMarkdown
(
message
),
rawData
=
message
,
messageId
=
message
.
id
,
avatar
=
avatar
!!
,
time
=
time
,
senderName
=
sender
,
messageId
=
message
.
id
,
avatar
=
avatar
!!
,
time
=
time
,
senderName
=
sender
,
content
=
content
,
isPinned
=
message
.
pinned
,
isFirstUnread
=
false
)
content
=
content
,
isPinned
=
message
.
pinned
,
reactions
=
getReactions
(
message
),
isFirstUnread
=
false
)
}
private
fun
getReactions
(
message
:
Message
):
List
<
ReactionViewModel
>
{
val
reactions
=
message
.
reactions
?.
let
{
val
list
=
mutableListOf
<
ReactionViewModel
>()
it
.
getShortNames
().
forEach
{
shortname
->
val
usernames
=
it
.
getUsernames
(
shortname
)
?:
emptyList
()
val
count
=
usernames
.
size
list
.
add
(
ReactionViewModel
(
messageId
=
message
.
id
,
shortname
=
shortname
,
unicode
=
EmojiParser
.
parse
(
shortname
),
count
=
count
,
usernames
=
usernames
)
)
}
list
}
return
reactions
?:
emptyList
()
}
}
private
fun
getMessageWithoutQuoteMarkdown
(
message
:
Message
):
Message
{
private
fun
getMessageWithoutQuoteMarkdown
(
message
:
Message
):
Message
{
...
...
app/src/main/java/chat/rocket/android/chatrooms/di/ChatRoomsFragmentModule.kt
View file @
009cade1
...
@@ -3,11 +3,9 @@ package chat.rocket.android.chatrooms.di
...
@@ -3,11 +3,9 @@ package chat.rocket.android.chatrooms.di
import
android.arch.lifecycle.LifecycleOwner
import
android.arch.lifecycle.LifecycleOwner
import
chat.rocket.android.chatrooms.presentation.ChatRoomsView
import
chat.rocket.android.chatrooms.presentation.ChatRoomsView
import
chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import
chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.dagger.scope.PerFragment
import
chat.rocket.android.dagger.scope.PerFragment
import
dagger.Module
import
dagger.Module
import
dagger.Provides
import
dagger.Provides
import
kotlinx.coroutines.experimental.Job
@Module
@Module
@PerFragment
@PerFragment
...
@@ -22,9 +20,4 @@ class ChatRoomsFragmentModule {
...
@@ -22,9 +20,4 @@ class ChatRoomsFragmentModule {
fun
provideLifecycleOwner
(
frag
:
ChatRoomsFragment
):
LifecycleOwner
{
fun
provideLifecycleOwner
(
frag
:
ChatRoomsFragment
):
LifecycleOwner
{
return
frag
return
frag
}
}
@Provides
fun
provideCancelStrategy
(
owner
:
LifecycleOwner
,
jobs
:
Job
):
CancelStrategy
{
return
CancelStrategy
(
owner
,
jobs
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatrooms/di/ChatRoomsModule.kt
deleted
100644 → 0
View file @
717824a7
package
chat.rocket.android.chatrooms.di
import
android.content.Context
import
chat.rocket.android.chatrooms.presentation.ChatRoomsNavigator
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.dagger.scope.PerActivity
import
dagger.Module
import
dagger.Provides
@Module
class
ChatRoomsModule
{
@Provides
@PerActivity
fun
provideChatRoomsNavigator
(
activity
:
MainActivity
,
context
:
Context
)
=
ChatRoomsNavigator
(
activity
,
context
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsNavigator.kt
deleted
100644 → 0
View file @
717824a7
package
chat.rocket.android.chatrooms.presentation
import
android.content.Context
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.ui.chatRoomIntent
import
chat.rocket.android.main.ui.MainActivity
class
ChatRoomsNavigator
(
private
val
activity
:
MainActivity
,
private
val
context
:
Context
)
{
fun
toChatRoom
(
chatRoomId
:
String
,
chatRoomName
:
String
,
chatRoomType
:
String
,
isChatRoomReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
)
{
activity
.
startActivity
(
context
.
chatRoomIntent
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
isChatRoomReadOnly
,
chatRoomLastSeen
))
activity
.
overridePendingTransition
(
R
.
anim
.
open_enter
,
R
.
anim
.
open_exit
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
View file @
009cade1
package
chat.rocket.android.chatrooms.presentation
package
chat.rocket.android.chatrooms.presentation
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.main.presentation.MainNavigator
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.ConnectionManager
import
chat.rocket.android.server.infraestructure.ConnectionManager
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
...
@@ -8,12 +9,12 @@ import chat.rocket.android.server.infraestructure.chatRooms
...
@@ -8,12 +9,12 @@ import chat.rocket.android.server.infraestructure.chatRooms
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.BaseRoom
import
chat.rocket.common.model.*
import
chat.rocket.common.model.RoomType
import
chat.rocket.core.internal.model.Subscription
import
chat.rocket.core.internal.model.Subscription
import
chat.rocket.core.internal.realtime.State
import
chat.rocket.core.internal.realtime.State
import
chat.rocket.core.internal.realtime.StreamMessage
import
chat.rocket.core.internal.realtime.StreamMessage
import
chat.rocket.core.internal.realtime.Type
import
chat.rocket.core.internal.realtime.Type
import
chat.rocket.core.internal.rest.spotlight
import
chat.rocket.core.model.ChatRoom
import
chat.rocket.core.model.ChatRoom
import
chat.rocket.core.model.Room
import
chat.rocket.core.model.Room
import
kotlinx.coroutines.experimental.*
import
kotlinx.coroutines.experimental.*
...
@@ -24,7 +25,7 @@ import javax.inject.Inject
...
@@ -24,7 +25,7 @@ import javax.inject.Inject
class
ChatRoomsPresenter
@Inject
constructor
(
private
val
view
:
ChatRoomsView
,
class
ChatRoomsPresenter
@Inject
constructor
(
private
val
view
:
ChatRoomsView
,
private
val
strategy
:
CancelStrategy
,
private
val
strategy
:
CancelStrategy
,
private
val
navigator
:
ChatRooms
Navigator
,
private
val
navigator
:
Main
Navigator
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
getChatRoomsInteractor
:
GetChatRoomsInteractor
,
private
val
getChatRoomsInteractor
:
GetChatRoomsInteractor
,
private
val
saveChatRoomsInteractor
:
SaveChatRoomsInteractor
,
private
val
saveChatRoomsInteractor
:
SaveChatRoomsInteractor
,
...
@@ -33,6 +34,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
...
@@ -33,6 +34,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
factory
:
ConnectionManagerFactory
)
{
factory
:
ConnectionManagerFactory
)
{
private
val
manager
:
ConnectionManager
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
private
val
manager
:
ConnectionManager
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
client
=
manager
.
client
private
var
reloadJob
:
Deferred
<
List
<
ChatRoom
>>?
=
null
private
var
reloadJob
:
Deferred
<
List
<
ChatRoom
>>?
=
null
private
val
settings
=
settingsRepository
.
get
(
currentServer
)
!!
private
val
settings
=
settingsRepository
.
get
(
currentServer
)
!!
...
@@ -68,7 +70,9 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
...
@@ -68,7 +70,9 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
}
}
navigator
.
toChatRoom
(
chatRoom
.
id
,
roomName
,
navigator
.
toChatRoom
(
chatRoom
.
id
,
roomName
,
chatRoom
.
type
.
toString
(),
chatRoom
.
readonly
?:
false
,
chatRoom
.
lastSeen
?:
-
1
)
chatRoom
.
type
.
toString
(),
chatRoom
.
readonly
?:
false
,
chatRoom
.
lastSeen
?:
-
1
,
chatRoom
.
open
)
}
}
/**
/**
...
@@ -79,9 +83,38 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
...
@@ -79,9 +83,38 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
val
currentServer
=
serverInteractor
.
get
()
!!
val
currentServer
=
serverInteractor
.
get
()
!!
launchUI
(
strategy
)
{
launchUI
(
strategy
)
{
val
roomList
=
getChatRoomsInteractor
.
getByName
(
currentServer
,
name
)
val
roomList
=
getChatRoomsInteractor
.
getByName
(
currentServer
,
name
)
if
(
roomList
.
isEmpty
())
{
val
(
users
,
rooms
)
=
client
.
spotlight
(
name
)
val
chatRoomsCombined
=
mutableListOf
<
ChatRoom
>()
chatRoomsCombined
.
addAll
(
usersToChatRooms
(
users
))
chatRoomsCombined
.
addAll
(
roomsToChatRooms
(
rooms
))
view
.
updateChatRooms
(
chatRoomsCombined
)
}
else
{
view
.
updateChatRooms
(
roomList
)
view
.
updateChatRooms
(
roomList
)
}
}
}
}
}
private
suspend
fun
usersToChatRooms
(
users
:
List
<
User
>):
List
<
ChatRoom
>
{
return
users
.
map
{
ChatRoom
(
it
.
id
,
RoomType
.
DIRECT_MESSAGE
,
SimpleUser
(
username
=
it
.
username
,
name
=
it
.
name
,
id
=
null
),
it
.
name
?:
""
,
it
.
name
,
false
,
null
,
null
,
null
,
null
,
null
,
false
,
false
,
false
,
0L
,
null
,
0L
,
null
,
client
)
}
}
private
suspend
fun
roomsToChatRooms
(
rooms
:
List
<
Room
>):
List
<
ChatRoom
>
{
return
rooms
.
map
{
ChatRoom
(
it
.
id
,
it
.
type
,
it
.
user
,
it
.
name
?:
""
,
it
.
fullName
,
it
.
readonly
,
it
.
updatedAt
,
null
,
null
,
it
.
topic
,
it
.
announcement
,
false
,
false
,
false
,
0L
,
null
,
0L
,
it
.
lastMessage
,
client
)
}
}
private
suspend
fun
loadRooms
():
List
<
ChatRoom
>
{
private
suspend
fun
loadRooms
():
List
<
ChatRoom
>
{
val
chatRooms
=
manager
.
chatRooms
().
update
val
chatRooms
=
manager
.
chatRooms
().
update
...
...
app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
View file @
009cade1
...
@@ -134,8 +134,10 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
...
@@ -134,8 +134,10 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}
}
private
val
dismissStatus
=
{
private
val
dismissStatus
=
{
if
(
connection_status_text
!=
null
)
{
connection_status_text
.
fadeOut
()
connection_status_text
.
fadeOut
()
}
}
}
private
fun
setupToolbar
()
{
private
fun
setupToolbar
()
{
(
activity
as
AppCompatActivity
).
supportActionBar
?.
title
=
getString
(
R
.
string
.
title_chats
)
(
activity
as
AppCompatActivity
).
supportActionBar
?.
title
=
getString
(
R
.
string
.
title_chats
)
...
...
app/src/main/java/chat/rocket/android/dagger/LocalComponent.kt
0 → 100644
View file @
009cade1
package
chat.rocket.android.dagger
import
android.content.Context
import
chat.rocket.android.chatroom.adapter.MessageReactionsAdapter
import
chat.rocket.android.dagger.module.LocalModule
import
dagger.BindsInstance
import
dagger.Component
import
javax.inject.Singleton
@Singleton
@Component
(
modules
=
[
LocalModule
::
class
])
interface
LocalComponent
{
@Component
.
Builder
interface
Builder
{
@BindsInstance
fun
context
(
applicationContext
:
Context
):
Builder
fun
build
():
LocalComponent
}
fun
inject
(
adapter
:
MessageReactionsAdapter
.
SingleReactionViewHolder
)
fun
inject
(
adapter
:
MessageReactionsAdapter
.
AddReactionViewHolder
)
/*@Component.Builder
abstract class Builder : AndroidInjector.Builder<RocketChatApplication>()*/
}
app/src/main/java/chat/rocket/android/dagger/module/ActivityBuilder.kt
View file @
009cade1
...
@@ -11,9 +11,7 @@ import chat.rocket.android.chatroom.di.PinnedMessagesFragmentProvider
...
@@ -11,9 +11,7 @@ import chat.rocket.android.chatroom.di.PinnedMessagesFragmentProvider
import
chat.rocket.android.chatroom.ui.ChatRoomActivity
import
chat.rocket.android.chatroom.ui.ChatRoomActivity
import
chat.rocket.android.chatroom.ui.PinnedMessagesActivity
import
chat.rocket.android.chatroom.ui.PinnedMessagesActivity
import
chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider
import
chat.rocket.android.chatrooms.di.ChatRoomsFragmentProvider
import
chat.rocket.android.chatrooms.di.ChatRoomsModule
import
chat.rocket.android.dagger.scope.PerActivity
import
chat.rocket.android.dagger.scope.PerActivity
import
chat.rocket.android.main.di.MainActivityProvider
import
chat.rocket.android.main.di.MainModule
import
chat.rocket.android.main.di.MainModule
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.members.di.MembersFragmentProvider
import
chat.rocket.android.members.di.MembersFragmentProvider
...
@@ -37,8 +35,6 @@ abstract class ActivityBuilder {
...
@@ -37,8 +35,6 @@ abstract class ActivityBuilder {
@PerActivity
@PerActivity
@ContributesAndroidInjector
(
modules
=
[
MainModule
::
class
,
@ContributesAndroidInjector
(
modules
=
[
MainModule
::
class
,
MainActivityProvider
::
class
,
ChatRoomsModule
::
class
,
ChatRoomsFragmentProvider
::
class
,
ChatRoomsFragmentProvider
::
class
,
ProfileFragmentProvider
::
class
ProfileFragmentProvider
::
class
])
])
...
...
app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt
View file @
009cade1
...
@@ -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/dagger/module/LocalModule.kt
0 → 100644
View file @
009cade1
package
chat.rocket.android.dagger.module
import
android.content.Context
import
android.content.SharedPreferences
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.SharedPrefsLocalRepository
import
dagger.Module
import
dagger.Provides
import
javax.inject.Singleton
@Module
class
LocalModule
{
@Provides
fun
provideSharedPreferences
(
context
:
Context
):
SharedPreferences
{
return
context
.
getSharedPreferences
(
"rocket.chat"
,
Context
.
MODE_PRIVATE
)
}
@Provides
@Singleton
fun
provideLocalRepository
(
prefs
:
SharedPreferences
):
LocalRepository
{
return
SharedPrefsLocalRepository
(
prefs
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/di/MainActivityModule.kt
deleted
100644 → 0
View file @
717824a7
package
chat.rocket.android.main.di
import
android.arch.lifecycle.LifecycleOwner
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.main.presentation.MainView
import
chat.rocket.android.main.ui.MainActivity
import
dagger.Module
import
dagger.Provides
import
kotlinx.coroutines.experimental.Job
@Module
class
MainActivityModule
{
// @Provides
// fun provideMainView(activity: MainActivity): MainView = activity
@Provides
fun
provideLifecycleOwner
(
activity
:
MainActivity
):
LifecycleOwner
=
activity
@Provides
fun
provideCancelStrategy
(
owner
:
LifecycleOwner
,
jobs
:
Job
):
CancelStrategy
=
CancelStrategy
(
owner
,
jobs
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/di/MainActivityProvider.kt
deleted
100644 → 0
View file @
717824a7
package
chat.rocket.android.main.di
import
chat.rocket.android.main.ui.MainActivity
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
@Module
abstract
class
MainActivityProvider
{
@ContributesAndroidInjector
(
modules
=
[
MainActivityModule
::
class
])
abstract
fun
provideMainActivity
():
MainActivity
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/di/MainModule.kt
View file @
009cade1
package
chat.rocket.android.main.di
package
chat.rocket.android.main.di
import
android.arch.lifecycle.LifecycleOwner
import
android.content.Context
import
android.content.Context
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.dagger.scope.PerActivity
import
chat.rocket.android.dagger.scope.PerActivity
import
chat.rocket.android.main.presentation.MainNavigator
import
chat.rocket.android.main.presentation.MainNavigator
import
chat.rocket.android.main.presentation.MainView
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.main.ui.MainActivity
import
dagger.Module
import
dagger.Module
import
dagger.Provides
import
dagger.Provides
import
kotlinx.coroutines.experimental.Job
@Module
@Module
class
MainModule
{
class
MainModule
{
...
@@ -13,4 +17,13 @@ class MainModule {
...
@@ -13,4 +17,13 @@ class MainModule {
@Provides
@Provides
@PerActivity
@PerActivity
fun
provideMainNavigator
(
activity
:
MainActivity
,
context
:
Context
)
=
MainNavigator
(
activity
,
context
)
fun
provideMainNavigator
(
activity
:
MainActivity
,
context
:
Context
)
=
MainNavigator
(
activity
,
context
)
@Provides
fun
provideMainView
(
activity
:
MainActivity
):
MainView
=
activity
@Provides
fun
provideLifecycleOwner
(
activity
:
MainActivity
):
LifecycleOwner
=
activity
@Provides
fun
provideCancelStrategy
(
owner
:
LifecycleOwner
,
jobs
:
Job
):
CancelStrategy
=
CancelStrategy
(
owner
,
jobs
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt
View file @
009cade1
...
@@ -2,6 +2,7 @@ package chat.rocket.android.main.presentation
...
@@ -2,6 +2,7 @@ package chat.rocket.android.main.presentation
import
android.content.Context
import
android.content.Context
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.ui.chatRoomIntent
import
chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import
chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.profile.ui.ProfileFragment
import
chat.rocket.android.profile.ui.ProfileFragment
...
@@ -27,4 +28,15 @@ class MainNavigator(internal val activity: MainActivity, internal val context: C
...
@@ -27,4 +28,15 @@ class MainNavigator(internal val activity: MainActivity, internal val context: C
SettingsFragment
.
newInstance
()
SettingsFragment
.
newInstance
()
}
}
}
}
fun
toChatRoom
(
chatRoomId
:
String
,
chatRoomName
:
String
,
chatRoomType
:
String
,
isChatRoomReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
,
isChatRoomSubscribed
:
Boolean
)
{
activity
.
startActivity
(
context
.
chatRoomIntent
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
isChatRoomReadOnly
,
chatRoomLastSeen
,
isChatRoomSubscribed
))
activity
.
overridePendingTransition
(
R
.
anim
.
open_enter
,
R
.
anim
.
open_exit
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
009cade1
package
chat.rocket.android.main.presentation
package
chat.rocket.android.main.presentation
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.realtime.disconnect
import
chat.rocket.core.internal.realtime.disconnect
import
chat.rocket.core.internal.rest.logout
import
chat.rocket.core.internal.rest.unregisterPushToken
import
chat.rocket.core.internal.rest.unregisterPushToken
import
timber.log.Timber
import
javax.inject.Inject
import
javax.inject.Inject
class
MainPresenter
@Inject
constructor
(
private
val
navigator
:
MainNavigator
,
class
MainPresenter
@Inject
constructor
(
private
val
view
:
MainView
,
private
val
strategy
:
CancelStrategy
,
private
val
navigator
:
MainNavigator
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
localRepository
:
LocalRepository
,
private
val
localRepository
:
LocalRepository
,
managerFactory
:
ConnectionManagerFactory
,
managerFactory
:
ConnectionManagerFactory
,
...
@@ -30,19 +35,21 @@ class MainPresenter @Inject constructor(private val navigator: MainNavigator,
...
@@ -30,19 +35,21 @@ class MainPresenter @Inject constructor(private val navigator: MainNavigator,
* Logout from current server.
* Logout from current server.
*/
*/
fun
logout
()
{
fun
logout
()
{
// TODO: inject CancelStrategy, and MainView.
launchUI
(
strategy
)
{
// launchUI(strategy) {
try
{
try
{
//
clearTokens()
clearTokens
()
//
client.logout()
client
.
logout
()
//TODO: Add the code to unsubscribe to all subscriptions.
//TODO: Add the code to unsubscribe to all subscriptions.
client
.
disconnect
()
client
.
disconnect
()
// view.onLogout()
view
.
onLogout
()
}
catch
(
e
:
RocketChatException
)
{
}
catch
(
exception
:
RocketChatException
)
{
Timber
.
e
(
e
)
exception
.
message
?.
let
{
// view.showMessage(e.message!!)
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
}
}
}
// }
}
}
private
suspend
fun
clearTokens
()
{
private
suspend
fun
clearTokens
()
{
...
...
app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
View file @
009cade1
package
chat.rocket.android.main.ui
package
chat.rocket.android.main.ui
import
android.app.Activity
import
android.content.Intent
import
android.content.Intent
import
android.os.Bundle
import
android.os.Bundle
import
android.support.v4.app.Fragment
import
android.support.v4.app.Fragment
...
@@ -7,25 +8,21 @@ import android.support.v7.app.AppCompatActivity
...
@@ -7,25 +8,21 @@ import android.support.v7.app.AppCompatActivity
import
android.view.Gravity
import
android.view.Gravity
import
android.view.MenuItem
import
android.view.MenuItem
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatrooms.ui.ChatRoomsFragment
import
chat.rocket.android.profile.ui.ProfileFragment
import
chat.rocket.android.settings.ui.SettingsFragment
import
chat.rocket.android.util.extensions.addFragment
import
chat.rocket.android.authentication.ui.AuthenticationActivity
import
chat.rocket.android.authentication.ui.AuthenticationActivity
import
chat.rocket.android.main.presentation.MainPresenter
import
chat.rocket.android.main.presentation.MainPresenter
import
chat.rocket.android.main.presentation.MainView
import
chat.rocket.android.main.presentation.MainView
import
chat.rocket.android.util.extensions.showToast
import
chat.rocket.android.util.extensions.showToast
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjector
import
dagger.android.AndroidInjector
import
dagger.android.DispatchingAndroidInjector
import
dagger.android.DispatchingAndroidInjector
import
dagger.android.HasActivityInjector
import
dagger.android.support.HasSupportFragmentInjector
import
dagger.android.support.HasSupportFragmentInjector
import
kotlinx.android.synthetic.main.activity_main.*
import
kotlinx.android.synthetic.main.activity_main.*
import
kotlinx.android.synthetic.main.app_bar.*
import
kotlinx.android.synthetic.main.app_bar.*
import
javax.inject.Inject
import
javax.inject.Inject
class
MainActivity
:
AppCompatActivity
(),
MainView
,
HasSupportFragmentInjector
{
class
MainActivity
:
AppCompatActivity
(),
MainView
,
HasActivityInjector
,
HasSupportFragmentInjector
{
@Inject
lateinit
var
activityDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Activity
>
@Inject
lateinit
var
fragmentDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Fragment
>
@Inject
lateinit
var
fragmentDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Fragment
>
@Inject
lateinit
var
presenter
:
MainPresenter
@Inject
lateinit
var
presenter
:
MainPresenter
private
var
isFragmentAdded
:
Boolean
=
false
private
var
isFragmentAdded
:
Boolean
=
false
...
@@ -68,6 +65,8 @@ class MainActivity : AppCompatActivity(), MainView, HasSupportFragmentInjector {
...
@@ -68,6 +65,8 @@ class MainActivity : AppCompatActivity(), MainView, HasSupportFragmentInjector {
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
activityInjector
():
AndroidInjector
<
Activity
>
=
activityDispatchingAndroidInjector
override
fun
supportFragmentInjector
():
AndroidInjector
<
Fragment
>
=
fragmentDispatchingAndroidInjector
override
fun
supportFragmentInjector
():
AndroidInjector
<
Fragment
>
=
fragmentDispatchingAndroidInjector
private
fun
setupToolbar
()
{
private
fun
setupToolbar
()
{
...
...
app/src/main/java/chat/rocket/android/profile/di/ProfileFragmentModule.kt
View file @
009cade1
package
chat.rocket.android.profile.di
package
chat.rocket.android.profile.di
import
android.arch.lifecycle.LifecycleOwner
import
android.arch.lifecycle.LifecycleOwner
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.dagger.scope.PerFragment
import
chat.rocket.android.dagger.scope.PerFragment
import
chat.rocket.android.profile.presentation.ProfileView
import
chat.rocket.android.profile.presentation.ProfileView
import
chat.rocket.android.profile.ui.ProfileFragment
import
chat.rocket.android.profile.ui.ProfileFragment
import
dagger.Module
import
dagger.Module
import
dagger.Provides
import
dagger.Provides
import
kotlinx.coroutines.experimental.Job
@Module
@Module
@PerFragment
@PerFragment
...
@@ -22,9 +20,4 @@ class ProfileFragmentModule {
...
@@ -22,9 +20,4 @@ class ProfileFragmentModule {
fun
provideLifecycleOwner
(
frag
:
ProfileFragment
):
LifecycleOwner
{
fun
provideLifecycleOwner
(
frag
:
ProfileFragment
):
LifecycleOwner
{
return
frag
return
frag
}
}
@Provides
fun
provideCancelStrategy
(
owner
:
LifecycleOwner
,
jobs
:
Job
):
CancelStrategy
{
return
CancelStrategy
(
owner
,
jobs
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt
View file @
009cade1
...
@@ -13,7 +13,7 @@ import chat.rocket.core.internal.rest.setAvatar
...
@@ -13,7 +13,7 @@ import chat.rocket.core.internal.rest.setAvatar
import
chat.rocket.core.internal.rest.updateProfile
import
chat.rocket.core.internal.rest.updateProfile
import
javax.inject.Inject
import
javax.inject.Inject
class
ProfilePresenter
@Inject
constructor
(
private
val
view
:
ProfileView
,
class
ProfilePresenter
@Inject
constructor
(
private
val
view
:
ProfileView
,
private
val
strategy
:
CancelStrategy
,
private
val
strategy
:
CancelStrategy
,
serverInteractor
:
GetCurrentServerInteractor
,
serverInteractor
:
GetCurrentServerInteractor
,
factory
:
RocketChatClientFactory
)
{
factory
:
RocketChatClientFactory
)
{
...
@@ -30,8 +30,8 @@ class ProfilePresenter @Inject constructor (private val view: ProfileView,
...
@@ -30,8 +30,8 @@ class ProfilePresenter @Inject constructor (private val view: ProfileView,
val
avatarUrl
=
UrlHelper
.
getAvatarUrl
(
serverUrl
,
myself
.
username
!!
)
val
avatarUrl
=
UrlHelper
.
getAvatarUrl
(
serverUrl
,
myself
.
username
!!
)
view
.
showProfile
(
view
.
showProfile
(
avatarUrl
,
avatarUrl
,
myself
.
name
!!
,
myself
.
name
?:
""
,
myself
.
username
!!
,
myself
.
username
?:
""
,
myself
.
emails
?.
get
(
0
)
?.
address
!!
myself
.
emails
?.
get
(
0
)
?.
address
!!
)
)
}
catch
(
exception
:
RocketChatException
)
{
}
catch
(
exception
:
RocketChatException
)
{
...
...
app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt
View file @
009cade1
...
@@ -56,8 +56,8 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -56,8 +56,8 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
text_email
.
textContent
=
email
text_email
.
textContent
=
email
text_avatar_url
.
textContent
=
""
text_avatar_url
.
textContent
=
""
currentName
=
name
currentName
=
user
name
currentUsername
=
user
name
currentUsername
=
name
currentEmail
=
email
currentEmail
=
email
currentAvatar
=
avatarUrl
currentAvatar
=
avatarUrl
...
@@ -133,10 +133,10 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -133,10 +133,10 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
text_email
.
asObservable
(),
text_email
.
asObservable
(),
text_avatar_url
.
asObservable
())
{
text_name
,
text_username
,
text_email
,
text_avatar_url
->
text_avatar_url
.
asObservable
())
{
text_name
,
text_username
,
text_email
,
text_avatar_url
->
return
@combineLatest
(
text_name
.
toString
()
!=
currentName
||
return
@combineLatest
(
text_name
.
toString
()
!=
currentName
||
text_username
.
toString
()
!=
currentUsername
||
text_username
.
toString
()
!=
currentUsername
||
text_email
.
toString
()
!=
currentEmail
||
text_email
.
toString
()
!=
currentEmail
||
(
text_avatar_url
.
toString
()
!=
""
&&
text_avatar_url
.
toString
()!=
currentAvatar
))
(
text_avatar_url
.
toString
()
!=
""
&&
text_avatar_url
.
toString
()
!=
currentAvatar
))
}.
subscribe
({
isValid
->
}.
subscribe
({
isValid
->
if
(
isValid
)
{
if
(
isValid
)
{
startActionMode
()
startActionMode
()
}
else
{
}
else
{
...
@@ -154,7 +154,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -154,7 +154,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
text_avatar_url
.
isEnabled
=
value
text_avatar_url
.
isEnabled
=
value
...
...
app/src/main/java/chat/rocket/android/server/domain/GetChatRoomsInteractor.kt
View file @
009cade1
...
@@ -6,6 +6,14 @@ import kotlinx.coroutines.experimental.withContext
...
@@ -6,6 +6,14 @@ import kotlinx.coroutines.experimental.withContext
import
javax.inject.Inject
import
javax.inject.Inject
class
GetChatRoomsInteractor
@Inject
constructor
(
private
val
repository
:
ChatRoomsRepository
)
{
class
GetChatRoomsInteractor
@Inject
constructor
(
private
val
repository
:
ChatRoomsRepository
)
{
/**
* Get all ChatRoom objects.
*
* @param url The server url.
*
* @return All the ChatRoom objects.
*/
fun
get
(
url
:
String
)
=
repository
.
get
(
url
)
fun
get
(
url
:
String
)
=
repository
.
get
(
url
)
/**
/**
...
...
app/src/main/java/chat/rocket/android/server/domain/MessagesRepository.kt
View file @
009cade1
...
@@ -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 @
009cade1
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 @
009cade1
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 @
009cade1
...
@@ -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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
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 @
009cade1
package
chat.rocket.android.widget.autocompletion.ui
import
android.content.Context
import
android.graphics.Canvas
import
android.graphics.Rect
import
android.graphics.drawable.Drawable
import
android.support.annotation.DrawableRes
import
android.support.transition.Slide
import
android.support.transition.TransitionManager
import
android.support.v4.content.ContextCompat
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.R
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 respective 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
.
addItemDecoration
(
TopItemDecoration
(
context
,
R
.
drawable
.
suggestions_menu_decorator
))
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
}
private
class
TopItemDecoration
()
:
RecyclerView
.
ItemDecoration
()
{
private
lateinit
var
divider
:
Drawable
private
val
padding
=
Rect
()
// Custom divider will be used.
constructor
(
context
:
Context
,
@DrawableRes
drawableResId
:
Int
)
:
this
()
{
val
customDrawable
=
ContextCompat
.
getDrawable
(
context
,
drawableResId
)
if
(
customDrawable
!=
null
)
{
divider
=
customDrawable
}
}
override
fun
onDrawOver
(
c
:
Canvas
,
parent
:
RecyclerView
,
state
:
RecyclerView
.
State
)
{
val
left
=
parent
.
paddingLeft
val
right
=
(
parent
.
width
-
parent
.
paddingRight
)
val
parentParams
=
parent
.
layoutParams
as
FrameLayout
.
LayoutParams
val
top
=
parent
.
top
-
parentParams
.
topMargin
-
parent
.
paddingTop
val
bottom
=
top
+
divider
.
intrinsicHeight
divider
.
setBounds
(
left
,
top
,
right
,
bottom
)
divider
.
draw
(
c
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/emoji/CategoryPagerAdapter.kt
View file @
009cade1
...
@@ -9,10 +9,10 @@ import android.view.View
...
@@ -9,10 +9,10 @@ import android.view.View
import
android.view.ViewGroup
import
android.view.ViewGroup
import
android.widget.TextView
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.widget.emoji.EmojiKeyboardPopup.Listener
import
java.util.*
import
java.util.*
class
CategoryPagerAdapter
(
val
listener
:
Listener
)
:
PagerAdapter
()
{
class
CategoryPagerAdapter
(
val
listener
:
EmojiKeyboardListener
)
:
PagerAdapter
()
{
override
fun
isViewFromObject
(
view
:
View
,
obj
:
Any
):
Boolean
{
override
fun
isViewFromObject
(
view
:
View
,
obj
:
Any
):
Boolean
{
return
view
==
obj
return
view
==
obj
}
}
...
@@ -46,7 +46,7 @@ class CategoryPagerAdapter(val listener: Listener) : PagerAdapter() {
...
@@ -46,7 +46,7 @@ class CategoryPagerAdapter(val listener: Listener) : PagerAdapter() {
override
fun
getPageTitle
(
position
:
Int
)
=
EmojiCategory
.
values
()[
position
].
textIcon
()
override
fun
getPageTitle
(
position
:
Int
)
=
EmojiCategory
.
values
()[
position
].
textIcon
()
class
EmojiAdapter
(
val
spanCount
:
Int
,
val
listener
:
Listener
)
:
RecyclerView
.
Adapter
<
EmojiRowViewHolder
>()
{
class
EmojiAdapter
(
val
spanCount
:
Int
,
val
listener
:
EmojiKeyboard
Listener
)
:
RecyclerView
.
Adapter
<
EmojiRowViewHolder
>()
{
private
var
emojis
=
Collections
.
emptyList
<
Emoji
>()
private
var
emojis
=
Collections
.
emptyList
<
Emoji
>()
fun
addEmojis
(
emojis
:
List
<
Emoji
>)
{
fun
addEmojis
(
emojis
:
List
<
Emoji
>)
{
...
@@ -66,7 +66,7 @@ class CategoryPagerAdapter(val listener: Listener) : PagerAdapter() {
...
@@ -66,7 +66,7 @@ class CategoryPagerAdapter(val listener: Listener) : PagerAdapter() {
override
fun
getItemCount
():
Int
=
emojis
.
size
override
fun
getItemCount
():
Int
=
emojis
.
size
}
}
class
EmojiRowViewHolder
(
itemView
:
View
,
val
itemCount
:
Int
,
val
spanCount
:
Int
,
val
listener
:
Listener
)
:
RecyclerView
.
ViewHolder
(
itemView
)
{
class
EmojiRowViewHolder
(
itemView
:
View
,
val
itemCount
:
Int
,
val
spanCount
:
Int
,
val
listener
:
EmojiKeyboard
Listener
)
:
RecyclerView
.
ViewHolder
(
itemView
)
{
private
val
emojiView
:
TextView
=
itemView
.
findViewById
(
R
.
id
.
emoji
)
private
val
emojiView
:
TextView
=
itemView
.
findViewById
(
R
.
id
.
emoji
)
fun
bind
(
emoji
:
Emoji
)
{
fun
bind
(
emoji
:
Emoji
)
{
...
...
app/src/main/java/chat/rocket/android/widget/emoji/EmojiKeyboardListener.kt
0 → 100644
View file @
009cade1
package
chat.rocket.android.widget.emoji
interface
EmojiKeyboardListener
{
/**
* When an emoji is selected on the picker.
*
* @param emoji The selected emoji
*/
fun
onEmojiAdded
(
emoji
:
Emoji
)
/**
* When backspace key is clicked.
*
* @param keyCode The key code pressed as defined
*
* @see android.view.KeyEvent
*/
fun
onNonEmojiKeyPressed
(
keyCode
:
Int
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/emoji/EmojiKeyboardPopup.kt
View file @
009cade1
...
@@ -21,14 +21,14 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -21,14 +21,14 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
private
lateinit
var
searchView
:
View
private
lateinit
var
searchView
:
View
private
lateinit
var
backspaceView
:
View
private
lateinit
var
backspaceView
:
View
private
lateinit
var
parentContainer
:
ViewGroup
private
lateinit
var
parentContainer
:
ViewGroup
var
listener
:
Listener
?
=
null
var
listener
:
EmojiKeyboard
Listener
?
=
null
companion
object
{
companion
object
{
const
val
PREF_EMOJI_RECENTS
=
"PREF_EMOJI_RECENTS"
const
val
PREF_EMOJI_RECENTS
=
"PREF_EMOJI_RECENTS"
}
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
):
View
{
override
fun
onCreateView
(
inflater
:
LayoutInflater
):
View
{
val
view
=
inflater
.
inflate
(
R
.
layout
.
emoji_
popup_layout
,
null
,
false
)
val
view
=
inflater
.
inflate
(
R
.
layout
.
emoji_
keyboard
,
null
)
parentContainer
=
view
.
findViewById
(
R
.
id
.
emoji_keyboard_container
)
parentContainer
=
view
.
findViewById
(
R
.
id
.
emoji_keyboard_container
)
viewPager
=
view
.
findViewById
(
R
.
id
.
pager_categories
)
viewPager
=
view
.
findViewById
(
R
.
id
.
pager_categories
)
searchView
=
view
.
findViewById
(
R
.
id
.
emoji_search
)
searchView
=
view
.
findViewById
(
R
.
id
.
emoji_search
)
...
@@ -55,20 +55,17 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -55,20 +55,17 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
private
fun
setupViewPager
()
{
private
fun
setupViewPager
()
{
context
.
let
{
context
.
let
{
val
callback
=
when
(
it
)
{
val
callback
=
when
(
it
)
{
is
Listener
->
it
is
EmojiKeyboard
Listener
->
it
else
->
{
else
->
{
val
fragments
=
(
it
as
AppCompatActivity
).
supportFragmentManager
.
fragments
val
fragments
=
(
it
as
AppCompatActivity
).
supportFragmentManager
.
fragments
if
(
fragments
==
null
||
fragments
.
size
==
0
||
!(
fragments
[
0
]
is
Listener
))
{
if
(
fragments
==
null
||
fragments
.
size
==
0
||
!(
fragments
[
0
]
is
EmojiKeyboard
Listener
))
{
throw
IllegalStateException
(
"activity/fragment should implement Listener interface"
)
throw
IllegalStateException
(
"activity/fragment should implement Listener interface"
)
}
}
fragments
[
0
]
as
Listener
fragments
[
0
]
as
EmojiKeyboard
Listener
}
}
}
}
viewPager
.
adapter
=
CategoryPagerAdapter
(
object
:
Listener
{
override
fun
onNonEmojiKeyPressed
(
keyCode
:
Int
)
{
// do nothing
}
viewPager
.
adapter
=
CategoryPagerAdapter
(
object
:
EmojiListenerAdapter
()
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
EmojiRepository
.
addToRecents
(
emoji
)
EmojiRepository
.
addToRecents
(
emoji
)
callback
.
onEmojiAdded
(
emoji
)
callback
.
onEmojiAdded
(
emoji
)
...
@@ -78,14 +75,14 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -78,14 +75,14 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
for
(
category
in
EmojiCategory
.
values
())
{
for
(
category
in
EmojiCategory
.
values
())
{
val
tab
=
tabLayout
.
getTabAt
(
category
.
ordinal
)
val
tab
=
tabLayout
.
getTabAt
(
category
.
ordinal
)
val
tabView
=
LayoutInflater
.
from
(
context
).
inflate
(
R
.
layout
.
emoji_picker_tab
,
null
)
val
tabView
=
LayoutInflater
.
from
(
context
).
inflate
(
R
.
layout
.
emoji_picker_tab
,
null
)
tab
?.
setCustomView
(
tabView
)
tab
?.
customView
=
tabView
val
textView
=
tabView
.
findViewById
(
R
.
id
.
image_category
)
as
ImageView
val
textView
=
tabView
.
findViewById
(
R
.
id
.
image_category
)
as
ImageView
textView
.
setImageResource
(
category
.
resourceIcon
())
textView
.
setImageResource
(
category
.
resourceIcon
())
}
}
val
currentTab
=
if
(
EmojiRepository
.
getRecents
().
isEmpty
())
EmojiCategory
.
PEOPLE
.
ordinal
else
val
currentTab
=
if
(
EmojiRepository
.
getRecents
().
isEmpty
())
EmojiCategory
.
PEOPLE
.
ordinal
else
EmojiCategory
.
RECENTS
.
ordinal
EmojiCategory
.
RECENTS
.
ordinal
viewPager
.
setCurrentItem
(
currentTab
)
viewPager
.
currentItem
=
currentTab
}
}
}
}
...
@@ -132,22 +129,4 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
...
@@ -132,22 +129,4 @@ class EmojiKeyboardPopup(context: Context, view: View) : OverKeyboardPopupWindow
override
fun
onTextChanged
(
s
:
CharSequence
,
start
:
Int
,
before
:
Int
,
count
:
Int
)
{
override
fun
onTextChanged
(
s
:
CharSequence
,
start
:
Int
,
before
:
Int
,
count
:
Int
)
{
}
}
}
}
interface
Listener
{
/**
* When an emoji is selected on the picker.
*
* @param emoji The selected emoji
*/
fun
onEmojiAdded
(
emoji
:
Emoji
)
/**
* When backspace key is clicked.
*
* @param keyCode The key code pressed as defined
*
* @see android.view.KeyEvent
*/
fun
onNonEmojiKeyPressed
(
keyCode
:
Int
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/emoji/EmojiListenerAdapter.kt
0 → 100644
View file @
009cade1
package
chat.rocket.android.widget.emoji
abstract
class
EmojiListenerAdapter
:
EmojiKeyboardListener
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
// this space is for rent
}
override
fun
onNonEmojiKeyPressed
(
keyCode
:
Int
)
{
// this space is for rent
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/emoji/EmojiPickerPopup.kt
0 → 100644
View file @
009cade1
package
chat.rocket.android.widget.emoji
import
android.app.Dialog
import
android.content.Context
import
android.os.Bundle
import
android.support.design.widget.TabLayout
import
android.support.v4.view.ViewPager
import
android.view.LayoutInflater
import
android.view.Window
import
android.view.WindowManager
import
android.widget.ImageView
import
chat.rocket.android.R
class
EmojiPickerPopup
(
context
:
Context
)
:
Dialog
(
context
)
{
private
lateinit
var
viewPager
:
ViewPager
private
lateinit
var
tabLayout
:
TabLayout
var
listener
:
EmojiKeyboardListener
?
=
null
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
requestWindowFeature
(
Window
.
FEATURE_NO_TITLE
)
setContentView
(
R
.
layout
.
emoji_picker
)
viewPager
=
findViewById
(
R
.
id
.
pager_categories
)
tabLayout
=
findViewById
(
R
.
id
.
tabs
)
tabLayout
.
setupWithViewPager
(
viewPager
)
setupViewPager
()
setSize
()
}
private
fun
setSize
()
{
val
lp
=
WindowManager
.
LayoutParams
()
lp
.
copyFrom
(
window
.
attributes
)
val
dialogWidth
=
lp
.
width
val
dialogHeight
=
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
picker_popup_height
)
window
.
setLayout
(
dialogWidth
,
dialogHeight
)
}
private
fun
setupViewPager
()
{
viewPager
.
adapter
=
CategoryPagerAdapter
(
object
:
EmojiListenerAdapter
()
{
override
fun
onEmojiAdded
(
emoji
:
Emoji
)
{
EmojiRepository
.
addToRecents
(
emoji
)
dismiss
()
listener
?.
onEmojiAdded
(
emoji
)
}
})
for
(
category
in
EmojiCategory
.
values
())
{
val
tab
=
tabLayout
.
getTabAt
(
category
.
ordinal
)
val
tabView
=
LayoutInflater
.
from
(
context
).
inflate
(
R
.
layout
.
emoji_picker_tab
,
null
)
tab
?.
customView
=
tabView
val
textView
=
tabView
.
findViewById
(
R
.
id
.
image_category
)
as
ImageView
textView
.
setImageResource
(
category
.
resourceIcon
())
}
val
currentTab
=
if
(
EmojiRepository
.
getRecents
().
isEmpty
())
EmojiCategory
.
PEOPLE
.
ordinal
else
EmojiCategory
.
RECENTS
.
ordinal
viewPager
.
currentItem
=
currentTab
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/widget/emoji/EmojiReactionListener.kt
0 → 100644
View file @
009cade1
package
chat.rocket.android.widget.emoji
interface
EmojiReactionListener
{
/**
* Callback when an emoji is picked in respect to message by the given id.
*
* @param messageId The id of the message being reacted.
* @param emoji The emoji used to react.
*/
fun
onReactionAdded
(
messageId
:
String
,
emoji
:
Emoji
)
/**
* Callback when an added reaction is touched.
*
* @param messageId The id of the message with the reaction.
* @param emojiShortname The shortname of the emoji (:grin:, :smiley:, etc).
*/
fun
onReactionTouched
(
messageId
:
String
,
emojiShortname
:
String
)
}
\ No newline at end of file
app/src/main/res/drawable/ic_add_reaction.xml
0 → 100644
View file @
009cade1
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportHeight=
"20.0"
android:viewportWidth=
"20.0"
>
<path
android:fillColor=
"#868585"
android:fillType=
"evenOdd"
android:pathData=
"M12,8m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
/>
<path
android:fillColor=
"#868585"
android:fillType=
"evenOdd"
android:pathData=
"M8,8m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"
/>
<path
android:fillType=
"evenOdd"
android:pathData=
"M10,3a7,7 0,1 0,0 14,7 7,0 0,0 7,-7M7.172,12.328a4,4 0,0 0,5.656 0"
android:strokeColor=
"#868585"
android:strokeWidth=
"1.5"
/>
<path
android:fillType=
"evenOdd"
android:pathData=
"M16.2,1.2v5.2m-2.6,-2.6h5.2"
android:strokeColor=
"#868585"
android:strokeLineCap=
"square"
android:strokeWidth=
"1.5"
/>
</vector>
app/src/main/res/drawable/rounded_background.xml
0 → 100644
View file @
009cade1
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:shape=
"rectangle"
>
<size
android:width=
"24dp"
android:height=
"24dp"
/>
<solid
android:color=
"#efeeee"
/>
<corners
android:radius=
"4dp"
/>
</shape>
\ No newline at end of file
app/src/main/res/drawable/suggestions_menu_decorator.xml
0 → 100644
View file @
009cade1
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:shape=
"rectangle"
>
<solid
android:color=
"#10000000"
/>
<corners
android:radius=
"5dp"
/>
<size
android:height=
"2dp"
/>
</shape>
\ No newline at end of file
app/src/main/res/drawable/user_status_white.xml
0 → 100644
View file @
009cade1
<?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/emoji_
popup_layout
.xml
→
app/src/main/res/layout/emoji_
keyboard
.xml
View file @
009cade1
...
@@ -11,35 +11,18 @@
...
@@ -11,35 +11,18 @@
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"1dp"
android:layout_height=
"1dp"
android:background=
"@color/colorDividerMessageComposer"
android:background=
"@color/colorDividerMessageComposer"
app:layout_constraintBottom_toTopOf=
"@+id/
tabs
"
app:layout_constraintBottom_toTopOf=
"@+id/
picker_container
"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
/>
app:layout_constraintTop_toTopOf=
"parent"
/>
<android.support.design.widget.TabLayout
<include
android:id=
"@+id/tabs"
android:id=
"@+id/picker_container"
android:layout_width=
"0dp"
layout=
"@layout/emoji_picker"
android:layout_height=
"wrap_content"
app:layout_constraintBottom_toTopOf=
"@+id/pager_categories"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
app:tabBackground=
"@color/whitesmoke"
app:tabGravity=
"fill"
app:tabMaxWidth=
"48dp"
app:tabMode=
"scrollable"
/>
<android.support.v4.view.ViewPager
android:id=
"@+id/pager_categories"
android:layout_width=
"0dp"
android:layout_height=
"0dp"
android:layout_marginEnd=
"8dp"
android:layout_marginStart=
"8dp"
android:background=
"@color/white"
app:layout_constraintBottom_toTopOf=
"@+id/emoji_actions_container"
app:layout_constraintBottom_toTopOf=
"@+id/emoji_actions_container"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_to
BottomOf=
"@+id/tabs
"
/>
app:layout_constraintTop_to
TopOf=
"parent
"
/>
<RelativeLayout
<RelativeLayout
android:id=
"@+id/emoji_actions_container"
android:id=
"@+id/emoji_actions_container"
...
@@ -60,8 +43,8 @@
...
@@ -60,8 +43,8 @@
android:clickable=
"true"
android:clickable=
"true"
android:focusable=
"true"
android:focusable=
"true"
android:padding=
"8dp"
android:padding=
"8dp"
android:
visibility=
"invisible
"
android:
src=
"@drawable/ic_search_gray_24px
"
android:
src=
"@drawable/ic_search_gray_24px
"
/>
android:
visibility=
"invisible
"
/>
<ImageView
<ImageView
android:id=
"@+id/emoji_backspace"
android:id=
"@+id/emoji_backspace"
...
...
app/src/main/res/layout/emoji_picker.xml
0 → 100644
View file @
009cade1
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:id=
"@+id/picker_container"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"@color/white"
android:orientation=
"vertical"
>
<android.support.design.widget.TabLayout
android:id=
"@+id/tabs"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
app:tabBackground=
"@color/whitesmoke"
app:tabGravity=
"fill"
app:tabMaxWidth=
"48dp"
app:tabMode=
"scrollable"
/>
<android.support.v4.view.ViewPager
android:id=
"@+id/pager_categories"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_marginEnd=
"8dp"
android:layout_marginStart=
"8dp"
android:background=
"@color/white"
/>
</LinearLayout>
\ No newline at end of file
app/src/main/res/layout/fragment_chat_room.xml
View file @
009cade1
...
@@ -28,8 +28,16 @@
...
@@ -28,8 +28,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/suggestion_background_color"
/>
<include
<include
android:id=
"@+id/layout_message_composer"
android:id=
"@+id/layout_message_composer"
layout=
"@layout/message_composer"
layout=
"@layout/message_composer"
...
@@ -58,15 +66,15 @@
...
@@ -58,15 +66,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/item_add_reaction.xml
0 → 100644
View file @
009cade1
<?xml version="1.0" encoding="utf-8"?>
<ImageView
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"32dp"
android:layout_height=
"32dp"
android:paddingBottom=
"2dp"
android:paddingEnd=
"4dp"
android:paddingLeft=
"4dp"
android:paddingRight=
"4dp"
android:paddingStart=
"4dp"
android:paddingTop=
"2dp"
android:src=
"@drawable/ic_add_reaction"
/>
\ No newline at end of file
app/src/main/res/layout/item_message.xml
View file @
009cade1
...
@@ -74,11 +74,18 @@
...
@@ -74,11 +74,18 @@
style=
"@style/Message.TextView"
style=
"@style/Message.TextView"
android:layout_width=
"0dp"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"5dp"
android:layout_marginBottom=
"2dp"
android:layout_marginBottom=
"2dp"
android:layout_marginTop=
"5dp"
app:layout_constraintLeft_toLeftOf=
"@id/top_container"
app:layout_constraintLeft_toLeftOf=
"@id/top_container"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/top_container"
app:layout_constraintTop_toBottomOf=
"@+id/top_container"
tools:text=
"This is a multiline chat message from Bertie that will take more than just one line of text. I have sure that everything is amazing!"
/>
tools:text=
"This is a multiline chat message from Bertie that will take more than just one line of text. I have sure that everything is amazing!"
/>
<include
layout=
"@layout/layout_reactions"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
app:layout_constraintEnd_toEndOf=
"@+id/text_content"
app:layout_constraintStart_toStartOf=
"@+id/text_content"
app:layout_constraintTop_toBottomOf=
"@+id/text_content"
/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/layout/item_reaction.xml
0 → 100644
View file @
009cade1
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"2dp"
android:layout_marginRight=
"2dp"
android:layout_marginTop=
"2dp"
android:layout_marginBottom=
"2dp"
android:descendantFocusability=
"beforeDescendants"
android:background=
"@drawable/rounded_background"
android:orientation=
"horizontal"
>
<TextView
android:id=
"@+id/text_emoji"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:ellipsize=
"end"
android:maxLines=
"1"
android:paddingLeft=
"4dp"
android:paddingStart=
"4dp"
android:textColor=
"#868585"
android:textSize=
"16sp"
tools:text=
":)"
/>
<TextView
android:id=
"@+id/text_count"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:gravity=
"center"
android:paddingBottom=
"4dp"
android:paddingEnd=
"4dp"
android:paddingLeft=
"4dp"
android:paddingRight=
"4dp"
android:paddingStart=
"4dp"
android:paddingTop=
"4dp"
android:textColor=
"#868585"
android:textSize=
"16sp"
android:textStyle=
"bold"
tools:text=
"12"
/>
</LinearLayout>
app/src/main/res/layout/layout_reactions.xml
0 → 100644
View file @
009cade1
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:id=
"@+id/recycler_view_reactions"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
/>
\ No newline at end of file
app/src/main/res/layout/message_attachment.xml
View file @
009cade1
...
@@ -6,9 +6,9 @@
...
@@ -6,9 +6,9 @@
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:background=
"?android:attr/selectableItemBackground"
android:background=
"?android:attr/selectableItemBackground"
android:
paddingStart=
"72dp
"
android:
orientation=
"vertical
"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_margins"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_margins"
android:
orientation=
"vertical
"
>
android:
paddingStart=
"72dp
"
>
<com.facebook.drawee.view.SimpleDraweeView
<com.facebook.drawee.view.SimpleDraweeView
android:id=
"@+id/image_attachment"
android:id=
"@+id/image_attachment"
...
@@ -39,4 +39,9 @@
...
@@ -39,4 +39,9 @@
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
tools:text=
"Filename.png"
/>
tools:text=
"Filename.png"
/>
<include
layout=
"@layout/layout_reactions"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
app/src/main/res/layout/message_composer.xml
View file @
009cade1
...
@@ -27,6 +27,18 @@
...
@@ -27,6 +27,18 @@
android:visibility=
"gone"
android:visibility=
"gone"
app:layout_constraintTop_toBottomOf=
"@+id/divider"
/>
app:layout_constraintTop_toBottomOf=
"@+id/divider"
/>
<Button
android:id=
"@+id/button_join_chat"
android:layout_width=
"match_parent"
android:layout_height=
"45dp"
android:background=
"@color/white"
android:text=
"@string/action_join_chat"
android:textColor=
"@color/colorAccent"
android:visibility=
"gone"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/divider"
/>
<LinearLayout
<LinearLayout
android:id=
"@+id/input_container"
android:id=
"@+id/input_container"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
...
...
app/src/main/res/layout/message_url_preview.xml
View file @
009cade1
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:id=
"@+id/url_preview_layout"
android:id=
"@+id/url_preview_layout"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:background=
"?android:attr/selectableItemBackground"
android:background=
"?android:attr/selectableItemBackground"
android:padding
Start=
"72
dp"
android:padding
End=
"24
dp"
android:padding
End=
"24
dp"
>
android:padding
Start=
"72
dp"
>
<com.facebook.drawee.view.SimpleDraweeView
<com.facebook.drawee.view.SimpleDraweeView
android:id=
"@+id/image_preview"
android:id=
"@+id/image_preview"
android:layout_width=
"70dp"
android:layout_width=
"70dp"
android:layout_height=
"50dp"
android:layout_height=
"50dp"
app:actualImageScaleType=
"centerCrop"
/>
app:actualImageScaleType=
"centerCrop"
/>
<TextView
<TextView
android:id=
"@+id/text_host"
android:id=
"@+id/text_host"
...
@@ -22,26 +21,33 @@
...
@@ -22,26 +21,33 @@
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:layout_marginStart=
"8dp"
android:textColor=
"@color/colorSecondaryText"
android:textColor=
"@color/colorSecondaryText"
tools:text=
"www.uol.com.br"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toEndOf=
"@+id/image_preview"
/>
app:layout_constraintStart_toEndOf=
"@+id/image_preview"
tools:text=
"www.uol.com.br"
/>
<TextView
<TextView
android:id=
"@+id/text_title"
android:id=
"@+id/text_title"
android:layout_width=
"0dp"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:textColor=
"@color/colorAccent"
android:textColor=
"@color/colorAccent"
tools:text=
"Web page title"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"@+id/text_host"
app:layout_constraintStart_toStartOf=
"@+id/text_host"
app:layout_constraintTop_toBottomOf=
"@id/text_host"
/>
app:layout_constraintTop_toBottomOf=
"@id/text_host"
tools:text=
"Web page title"
/>
<TextView
<TextView
android:id=
"@+id/text_description"
android:id=
"@+id/text_description"
android:layout_width=
"0dp"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
tools:text=
"description"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"@+id/text_host"
app:layout_constraintStart_toStartOf=
"@+id/text_host"
app:layout_constraintTop_toBottomOf=
"@id/text_title"
/>
app:layout_constraintTop_toBottomOf=
"@id/text_title"
tools:text=
"description"
/>
<include
layout=
"@layout/layout_reactions"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
app:layout_constraintStart_toStartOf=
"@+id/image_preview"
app:layout_constraintTop_toBottomOf=
"@+id/text_description"
/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/layout/suggestion_member_item.xml
0 → 100644
View file @
009cade1
<?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_marginBottom=
"2dp"
android:layout_marginEnd=
"2dp"
android:layout_marginLeft=
"4dp"
android:layout_marginRight=
"2dp"
android:layout_marginStart=
"4dp"
android:layout_marginTop=
"2dp"
android:background=
"@color/suggestion_background_color"
>
<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/suggestion_background_color"
>
<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 @
009cade1
<?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/suggestion_background_color"
>
<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/suggestion_background_color"
>
<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/menu/message_actions.xml
View file @
009cade1
...
@@ -22,6 +22,11 @@
...
@@ -22,6 +22,11 @@
android:icon=
"@drawable/ic_content_copy_black_24px"
android:icon=
"@drawable/ic_content_copy_black_24px"
android:title=
"@string/action_msg_copy"
/>
android:title=
"@string/action_msg_copy"
/>
<item
android:id=
"@+id/action_menu_msg_react"
android:icon=
"@drawable/ic_add_reaction"
android:title=
"@string/action_msg_add_reaction"
/>
<!--<item-->
<!--<item-->
<!--android:id="@+id/action_menu_msg_share"-->
<!--android:id="@+id/action_menu_msg_share"-->
<!--andrtextIconicon="@drawable/ic_share_black_24px"-->
<!--andrtextIconicon="@drawable/ic_share_black_24px"-->
...
...
app/src/main/res/values-pt-rBR/strings.xml
View file @
009cade1
...
@@ -24,6 +24,8 @@
...
@@ -24,6 +24,8 @@
<string
name=
"action_logout"
>
Sair
</string>
<string
name=
"action_logout"
>
Sair
</string>
<string
name=
"action_files"
>
Arquivos
</string>
<string
name=
"action_files"
>
Arquivos
</string>
<string
name=
"action_confirm_password"
>
Confirme a nova senha
</string>
<string
name=
"action_confirm_password"
>
Confirme a nova senha
</string>
<string
name=
"action_join_chat"
>
Entrar no Chat
</string>
<!-- Settings List -->
<!-- Settings List -->
<string-array
name=
"settings_actions"
>
<string-array
name=
"settings_actions"
>
...
@@ -85,10 +87,11 @@
...
@@ -85,10 +87,11 @@
<string
name=
"action_msg_quote"
>
Citar
</string>
<string
name=
"action_msg_quote"
>
Citar
</string>
<string
name=
"action_msg_delete"
>
Remover
</string>
<string
name=
"action_msg_delete"
>
Remover
</string>
<string
name=
"action_msg_pin"
>
Fixar Mensagem
</string>
<string
name=
"action_msg_pin"
>
Fixar Mensagem
</string>
<string
name=
"action_msg_unpin"
>
Desafixar Me
s
sagem
</string>
<string
name=
"action_msg_unpin"
>
Desafixar Me
n
sagem
</string>
<string
name=
"action_msg_star"
>
Favoritar Mensagem
</string>
<string
name=
"action_msg_star"
>
Favoritar Mensagem
</string>
<string
name=
"action_msg_share"
>
Compartilhar
</string>
<string
name=
"action_msg_share"
>
Compartilhar
</string>
<string
name=
"action_title_editing"
>
Editando Mensagem
</string>
<string
name=
"action_title_editing"
>
Editando Mensagem
</string>
<string
name=
"action_msg_add_reaction"
>
Adicionar reação
</string>
<!-- Permission messages -->
<!-- Permission messages -->
<string
name=
"permission_editing_not_allowed"
>
Edição não permitida
</string>
<string
name=
"permission_editing_not_allowed"
>
Edição não permitida
</string>
...
...
app/src/main/res/values/colors.xml
View file @
009cade1
...
@@ -15,7 +15,7 @@
...
@@ -15,7 +15,7 @@
<color
name=
"colorUserStatusOnline"
>
#2FE1A8
</color>
<color
name=
"colorUserStatusOnline"
>
#2FE1A8
</color>
<color
name=
"colorUserStatusBusy"
>
#F33E5B
</color>
<color
name=
"colorUserStatusBusy"
>
#F33E5B
</color>
<color
name=
"colorUserStatusAway"
>
#FDD236
</color>
<color
name=
"colorUserStatusAway"
>
#FDD236
</color>
<color
name=
"colorUserStatusOffline"
>
#
1F2228
</color>
<color
name=
"colorUserStatusOffline"
>
#
d9d9d9
</color>
<color
name=
"colorDrawableTintGrey"
>
#9FA2A8
</color>
<color
name=
"colorDrawableTintGrey"
>
#9FA2A8
</color>
...
@@ -36,4 +36,7 @@
...
@@ -36,4 +36,7 @@
<color
name=
"colorEmojiIcon"
>
#FF767676
</color>
<color
name=
"colorEmojiIcon"
>
#FF767676
</color>
<!-- Suggestions -->
<color
name=
"suggestion_background_color"
>
@android:color/white
</color>
</resources>
</resources>
app/src/main/res/values/dimens.xml
View file @
009cade1
...
@@ -24,10 +24,15 @@
...
@@ -24,10 +24,15 @@
<!-- Emoji -->
<!-- Emoji -->
<dimen
name=
"picker_padding_bottom"
>
16dp
</dimen>
<dimen
name=
"picker_padding_bottom"
>
16dp
</dimen>
<dimen
name=
"supposed_keyboard_height"
>
252dp
</dimen>
<dimen
name=
"supposed_keyboard_height"
>
252dp
</dimen>
<dimen
name=
"picker_popup_height"
>
250dp
</dimen>
<dimen
name=
"picker_popup_width"
>
300dp
</dimen>
<!-- Message -->
<!-- Message -->
<dimen
name=
"padding_quote"
>
8dp
</dimen>
<dimen
name=
"padding_quote"
>
8dp
</dimen>
<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
app/src/main/res/values/strings.xml
View file @
009cade1
...
@@ -25,6 +25,7 @@
...
@@ -25,6 +25,7 @@
<string
name=
"action_logout"
>
Logout
</string>
<string
name=
"action_logout"
>
Logout
</string>
<string
name=
"action_files"
>
Files
</string>
<string
name=
"action_files"
>
Files
</string>
<string
name=
"action_confirm_password"
>
Confirm Password Change
</string>
<string
name=
"action_confirm_password"
>
Confirm Password Change
</string>
<string
name=
"action_join_chat"
>
Join Chat
</string>
<!-- Settings List -->
<!-- Settings List -->
<string-array
name=
"settings_actions"
>
<string-array
name=
"settings_actions"
>
...
@@ -91,6 +92,7 @@
...
@@ -91,6 +92,7 @@
<string
name=
"action_msg_star"
>
Star Message
</string>
<string
name=
"action_msg_star"
>
Star Message
</string>
<string
name=
"action_msg_share"
>
Share
</string>
<string
name=
"action_msg_share"
>
Share
</string>
<string
name=
"action_title_editing"
>
Editing Message
</string>
<string
name=
"action_title_editing"
>
Editing Message
</string>
<string
name=
"action_msg_add_reaction"
>
Add reaction
</string>
<!-- Permission messages -->
<!-- Permission messages -->
<string
name=
"permission_editing_not_allowed"
>
Editing is not allowed
</string>
<string
name=
"permission_editing_not_allowed"
>
Editing is not allowed
</string>
...
...
build.gradle
View file @
009cade1
...
@@ -14,7 +14,7 @@ buildscript {
...
@@ -14,7 +14,7 @@ buildscript {
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath
"org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath
"org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath
"org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath
'com.google.gms:google-services:3.2.0'
classpath
'com.google.gms:google-services:3.2.0'
classpath
'io.fabric.tools:gradle:1.
+
'
classpath
'io.fabric.tools:gradle:1.
25.1
'
// NOTE: Do not place your application dependencies here; they belong
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
// in the individual module build.gradle files
...
...
dependencies.gradle
View file @
009cade1
...
@@ -4,7 +4,7 @@ ext {
...
@@ -4,7 +4,7 @@ ext {
compileSdk
:
27
,
compileSdk
:
27
,
targetSdk
:
27
,
targetSdk
:
27
,
buildTools
:
'27.0.3'
,
buildTools
:
'27.0.3'
,
kotlin
:
'1.2.
21
'
,
kotlin
:
'1.2.
30
'
,
coroutine
:
'0.22'
,
coroutine
:
'0.22'
,
dokka
:
'0.9.15'
,
dokka
:
'0.9.15'
,
...
@@ -30,6 +30,7 @@ ext {
...
@@ -30,6 +30,7 @@ ext {
markwon
:
'1.0.3'
,
markwon
:
'1.0.3'
,
sheetMenu
:
'1.3.3'
,
sheetMenu
:
'1.3.3'
,
aVLoadingIndicatorView
:
'2.1.3'
,
aVLoadingIndicatorView
:
'2.1.3'
,
flexbox
:
'0.3.2'
,
// For testing
// For testing
junit
:
'4.12'
,
junit
:
'4.12'
,
...
@@ -49,6 +50,7 @@ ext {
...
@@ -49,6 +50,7 @@ ext {
design
:
"com.android.support:design:${versions.support}"
,
design
:
"com.android.support:design:${versions.support}"
,
constraintLayout
:
"com.android.support.constraint:constraint-layout:${versions.constraintLayout}"
,
constraintLayout
:
"com.android.support.constraint:constraint-layout:${versions.constraintLayout}"
,
cardView
:
"com.android.support:cardview-v7:${versions.support}"
,
cardView
:
"com.android.support:cardview-v7:${versions.support}"
,
flexbox
:
"com.google.android:flexbox:${versions.flexbox}"
,
androidKtx
:
"androidx.core:core-ktx:${versions.androidKtx}"
,
androidKtx
:
"androidx.core:core-ktx:${versions.androidKtx}"
,
...
...
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