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
b7606345
Unverified
Commit
b7606345
authored
May 22, 2018
by
Filipe de Lima Brito
Committed by
GitHub
May 22, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' into wear-module
parents
2fa3abb1
ca99f416
Changes
34
Show whitespace changes
Inline
Side-by-side
Showing
34 changed files
with
681 additions
and
276 deletions
+681
-276
build.gradle
app/build.gradle
+1
-1
ChatRoomAdapter.kt
...a/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
+26
-3
MessageReplyViewHolder.kt
...rocket/android/chatroom/adapter/MessageReplyViewHolder.kt
+30
-0
MessageViewHolder.kt
...chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
+1
-1
MessageReply.kt
.../java/chat/rocket/android/chatroom/domain/MessageReply.kt
+6
-0
ChatRoomNavigator.kt
...rocket/android/chatroom/presentation/ChatRoomNavigator.kt
+14
-0
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+118
-21
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+13
-3
MessageService.kt
...va/chat/rocket/android/chatroom/service/MessageService.kt
+14
-5
ChatRoomActivity.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
+51
-13
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+80
-40
BaseViewModel.kt
...a/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
+2
-1
MessageReplyViewModel.kt
...ocket/android/chatroom/viewmodel/MessageReplyViewModel.kt
+20
-0
RoomViewModel.kt
...a/chat/rocket/android/chatroom/viewmodel/RoomViewModel.kt
+9
-0
ViewModelMapper.kt
...chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
+59
-8
ChatRoomsPresenter.kt
...cket/android/chatrooms/presentation/ChatRoomsPresenter.kt
+28
-13
ChatRoomsFragment.kt
...ava/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
+0
-2
FavoriteMessagesPresenter.kt
...avoritemessages/presentation/FavoriteMessagesPresenter.kt
+2
-2
FavoriteMessagesFragment.kt
...t/android/favoritemessages/ui/FavoriteMessagesFragment.kt
+1
-1
MessageHelper.kt
...src/main/java/chat/rocket/android/helper/MessageHelper.kt
+71
-0
UserHelper.kt
app/src/main/java/chat/rocket/android/helper/UserHelper.kt
+1
-1
MainNavigator.kt
...va/chat/rocket/android/main/presentation/MainNavigator.kt
+2
-3
PinnedMessagesPresenter.kt
...id/pinnedmessages/presentation/PinnedMessagesPresenter.kt
+2
-2
PinnedMessagesFragment.kt
...ocket/android/pinnedmessages/ui/PinnedMessagesFragment.kt
+1
-1
ChatRoomsInteractor.kt
.../chat/rocket/android/server/domain/ChatRoomsInteractor.kt
+3
-4
ic_room_channel.xml
app/src/main/res/drawable/ic_room_channel.xml
+9
-0
ic_room_dm.xml
app/src/main/res/drawable/ic_room_dm.xml
+9
-0
ic_room_lock.xml
app/src/main/res/drawable/ic_room_lock.xml
+9
-0
message_reply_button_bg.xml
app/src/main/res/drawable/message_reply_button_bg.xml
+10
-0
activity_chat_room.xml
app/src/main/res/layout/activity_chat_room.xml
+1
-1
app_bar_chat_room.xml
app/src/main/res/layout/app_bar_chat_room.xml
+50
-0
item_message_reply.xml
app/src/main/res/layout/item_message_reply.xml
+37
-0
MemoryMessagesRepositoryTest.kt
.../java/chat/rocket/android/MemoryMessagesRepositoryTest.kt
+0
-150
gradle-wrapper.properties
gradle/wrapper/gradle-wrapper.properties
+1
-0
No files found.
app/build.gradle
View file @
b7606345
...
...
@@ -13,7 +13,7 @@ android {
applicationId
"chat.rocket.android"
minSdkVersion
21
targetSdkVersion
versions
.
targetSdk
versionCode
202
0
versionCode
202
1
versionName
"2.2.0"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled
true
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
View file @
b7606345
...
...
@@ -5,7 +5,21 @@ import android.view.MenuItem
import
android.view.ViewGroup
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.viewmodel.*
import
chat.rocket.android.chatroom.ui.chatRoomIntent
import
chat.rocket.android.chatroom.viewmodel.AudioAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.AuthorAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.BaseFileAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.chatroom.viewmodel.ColorAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.GenericFileAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.ImageAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.MessageAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.MessageReplyViewModel
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.chatroom.viewmodel.UrlPreviewViewModel
import
chat.rocket.android.chatroom.viewmodel.VideoAttachmentViewModel
import
chat.rocket.android.chatroom.viewmodel.toViewType
import
chat.rocket.android.main.presentation.MainNavigator
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
chat.rocket.core.model.Message
...
...
@@ -15,6 +29,7 @@ import java.security.InvalidParameterException
class
ChatRoomAdapter
(
private
val
roomType
:
String
,
private
val
roomName
:
String
,
private
val
presenter
:
ChatRoomPresenter
?,
private
val
enableActions
:
Boolean
=
true
,
private
val
reactionListener
:
EmojiReactionListener
?
=
null
...
...
@@ -64,6 +79,12 @@ class ChatRoomAdapter(
val
view
=
parent
.
inflate
(
R
.
layout
.
item_file_attachment
)
GenericFileAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
BaseViewModel
.
ViewType
.
MESSAGE_REPLY
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
item_message_reply
)
MessageReplyViewHolder
(
view
,
actionsListener
,
reactionListener
)
{
roomName
,
permalink
->
presenter
?.
openDirectMessage
(
roomName
,
permalink
)
}
}
else
->
{
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
}
...
...
@@ -115,6 +136,8 @@ class ChatRoomAdapter(
holder
.
bind
(
dataSet
[
position
]
as
ColorAttachmentViewModel
)
is
GenericFileAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
GenericFileAttachmentViewModel
)
is
MessageReplyViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageReplyViewModel
)
}
}
...
...
@@ -196,10 +219,10 @@ class ChatRoomAdapter(
message
.
apply
{
when
(
item
.
itemId
)
{
R
.
id
.
action_message_reply
->
{
presenter
?.
citeMessage
(
roomType
,
id
,
true
)
presenter
?.
citeMessage
(
room
Name
,
room
Type
,
id
,
true
)
}
R
.
id
.
action_message_quote
->
{
presenter
?.
citeMessage
(
roomType
,
id
,
false
)
presenter
?.
citeMessage
(
room
Name
,
room
Type
,
id
,
false
)
}
R
.
id
.
action_message_copy
->
{
presenter
?.
copyMessage
(
id
)
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageReplyViewHolder.kt
0 → 100644
View file @
b7606345
package
chat.rocket.android.chatroom.adapter
import
android.view.View
import
chat.rocket.android.chatroom.viewmodel.MessageReplyViewModel
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
kotlinx.android.synthetic.main.item_message_reply.view.*
class
MessageReplyViewHolder
(
itemView
:
View
,
listener
:
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
,
private
val
replyCallback
:
(
roomName
:
String
,
permalink
:
String
)
->
Unit
)
:
BaseViewHolder
<
MessageReplyViewModel
>(
itemView
,
listener
,
reactionListener
)
{
init
{
with
(
itemView
)
{
setupActionMenu
(
itemView
)
}
}
override
fun
bindViews
(
data
:
MessageReplyViewModel
)
{
with
(
itemView
)
{
button_message_reply
.
setOnClickListener
{
with
(
data
.
rawData
)
{
replyCallback
.
invoke
(
roomName
,
permalink
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
View file @
b7606345
...
...
@@ -37,7 +37,7 @@ class MessageViewHolder(
if
(
data
.
isTemporary
)
Color
.
GRAY
else
Color
.
BLACK
)
data
.
message
.
let
{
text_edit_indicator
.
isVisible
=
it
.
isSystemMessage
()
&&
it
.
editedBy
!=
null
text_edit_indicator
.
isVisible
=
!
it
.
isSystemMessage
()
&&
it
.
editedBy
!=
null
image_star_indicator
.
isVisible
=
it
.
starred
?.
isNotEmpty
()
?:
false
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/domain/MessageReply.kt
0 → 100644
View file @
b7606345
package
chat.rocket.android.chatroom.domain
data class
MessageReply
(
val
roomName
:
String
,
val
permalink
:
String
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomNavigator.kt
View file @
b7606345
...
...
@@ -2,6 +2,7 @@ package chat.rocket.android.chatroom.presentation
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.ui.ChatRoomActivity
import
chat.rocket.android.chatroom.ui.chatRoomIntent
import
chat.rocket.android.members.ui.newInstance
import
chat.rocket.android.server.ui.changeServerIntent
import
chat.rocket.android.util.extensions.addFragmentBackStack
...
...
@@ -30,4 +31,17 @@ class ChatRoomNavigator(internal val activity: ChatRoomActivity) {
activity
.
startActivity
(
activity
.
changeServerIntent
())
activity
.
finish
()
}
fun
toDirectMessage
(
chatRoomId
:
String
,
chatRoomName
:
String
,
chatRoomType
:
String
,
isChatRoomReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
,
isChatRoomSubscribed
:
Boolean
,
isChatRoomCreator
:
Boolean
,
chatRoomMessage
:
String
)
{
activity
.
startActivity
(
activity
.
chatRoomIntent
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
isChatRoomReadOnly
,
chatRoomLastSeen
,
isChatRoomSubscribed
,
isChatRoomCreator
,
chatRoomMessage
))
activity
.
overridePendingTransition
(
R
.
anim
.
open_enter
,
R
.
anim
.
open_exit
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
b7606345
...
...
@@ -6,16 +6,28 @@ 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.viewmodel.RoomViewModel
import
chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import
chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import
chat.rocket.android.core.behaviours.showMessage
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.MessageHelper
import
chat.rocket.android.helper.UserHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.username
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.ChatRoomsInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.GetSettingsInteractor
import
chat.rocket.android.server.domain.JobSchedulerInteractor
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.android.server.domain.PermissionsInteractor
import
chat.rocket.android.server.domain.PublicSettings
import
chat.rocket.android.server.domain.RoomRepository
import
chat.rocket.android.server.domain.UsersRepository
import
chat.rocket.android.server.domain.uploadMaxFileSize
import
chat.rocket.android.server.domain.uploadMimeTypeFilter
import
chat.rocket.android.server.domain.useRealName
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.state
import
chat.rocket.android.util.extensions.avatarUrl
...
...
@@ -31,7 +43,26 @@ import chat.rocket.core.internal.realtime.setTypingStatus
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.internal.realtime.subscribeTypingStatus
import
chat.rocket.core.internal.realtime.unsubscribe
import
chat.rocket.core.internal.rest.*
import
chat.rocket.core.internal.rest.chatRoomRoles
import
chat.rocket.core.internal.rest.commands
import
chat.rocket.core.internal.rest.deleteMessage
import
chat.rocket.core.internal.rest.getMembers
import
chat.rocket.core.internal.rest.history
import
chat.rocket.core.internal.rest.joinChat
import
chat.rocket.core.internal.rest.markAsRead
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.messages
import
chat.rocket.core.internal.rest.pinMessage
import
chat.rocket.core.internal.rest.runCommand
import
chat.rocket.core.internal.rest.sendMessage
import
chat.rocket.core.internal.rest.spotlight
import
chat.rocket.core.internal.rest.starMessage
import
chat.rocket.core.internal.rest.toggleReaction
import
chat.rocket.core.internal.rest.unpinMessage
import
chat.rocket.core.internal.rest.unstarMessage
import
chat.rocket.core.internal.rest.updateMessage
import
chat.rocket.core.internal.rest.uploadFile
import
chat.rocket.core.model.ChatRoomRole
import
chat.rocket.core.model.Command
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Myself
...
...
@@ -49,7 +80,7 @@ class ChatRoomPresenter @Inject constructor(
private
val
view
:
ChatRoomView
,
private
val
navigator
:
ChatRoomNavigator
,
private
val
strategy
:
CancelStrategy
,
private
val
getChatRoomsInteractor
:
Get
ChatRoomsInteractor
,
private
val
chatRoomsInteractor
:
ChatRoomsInteractor
,
private
val
permissions
:
PermissionsInteractor
,
private
val
uriInteractor
:
UriInteractor
,
private
val
messagesRepository
:
MessagesRepository
,
...
...
@@ -59,6 +90,7 @@ class ChatRoomPresenter @Inject constructor(
private
val
userHelper
:
UserHelper
,
private
val
mapper
:
ViewModelMapper
,
private
val
jobSchedulerInteractor
:
JobSchedulerInteractor
,
private
val
messageHelper
:
MessageHelper
,
getSettingsInteractor
:
GetSettingsInteractor
,
serverInteractor
:
GetCurrentServerInteractor
,
factory
:
ConnectionManagerFactory
...
...
@@ -67,23 +99,50 @@ class ChatRoomPresenter @Inject constructor(
private
val
manager
=
factory
.
create
(
currentServer
)
private
val
client
=
manager
.
client
private
var
settings
:
PublicSettings
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
private
val
currentLoggedUsername
=
localRepository
.
username
()
private
val
currentLoggedUsername
=
userHelper
.
username
()
private
val
messagesChannel
=
Channel
<
Message
>()
private
var
chatRoomId
:
String
?
=
null
private
var
chatRoomType
:
String
?
=
null
private
var
chatIsBroadcast
:
Boolean
=
false
private
var
chatRoles
=
emptyList
<
ChatRoomRole
>()
private
val
stateChannel
=
Channel
<
State
>()
private
var
typingStatusSubscriptionId
:
String
?
=
null
private
var
lastState
=
manager
.
state
private
var
typingStatusList
=
arrayListOf
<
String
>()
fun
setupChatRoom
()
{
fun
setupChatRoom
(
roomId
:
String
,
roomName
:
String
,
roomType
:
String
,
chatRoomMessage
:
String
?
=
null
)
{
launchUI
(
strategy
)
{
val
canPost
=
permissions
.
canPostToReadOnlyChannels
()
view
.
onRoomChanged
(
canPost
)
try
{
chatRoles
=
if
(
roomTypeOf
(
roomType
)
!
is
RoomType
.
DirectMessage
)
{
client
.
chatRoomRoles
(
roomType
=
roomTypeOf
(
roomType
),
roomName
=
roomName
)
}
else
emptyList
()
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
chatRoles
=
emptyList
()
}
finally
{
// User has at least an 'owner' or 'moderator' role.
val
userCanMod
=
isOwnerOrMod
()
// Can post anyway if has the 'post-readonly' permission on server.
val
userCanPost
=
userCanMod
||
permissions
.
canPostToReadOnlyChannels
()
chatIsBroadcast
=
chatRoomsInteractor
.
getById
(
currentServer
,
roomId
)
?.
run
{
broadcast
}
?:
false
view
.
onRoomUpdated
(
userCanPost
,
chatIsBroadcast
,
userCanMod
)
loadMessages
(
roomId
,
roomType
)
chatRoomMessage
?.
let
{
messageHelper
.
messageIdFromPermalink
(
it
)
}
?.
let
{
messageId
->
val
name
=
messageHelper
.
roomNameFromPermalink
(
chatRoomMessage
)
citeMessage
(
name
!!
,
messageHelper
.
roomTypeFromPermalink
(
chatRoomMessage
)
!!
,
messageId
,
true
)
}
}
}
}
private
fun
isOwnerOrMod
():
Boolean
{
return
chatRoles
.
firstOrNull
{
it
.
user
.
username
==
currentLoggedUsername
}
?.
roles
?.
any
{
it
==
"owner"
||
it
==
"moderator"
}
?:
false
}
fun
loadMessages
(
chatRoomId
:
String
,
chatRoomType
:
String
,
offset
:
Long
=
0
)
{
this
.
chatRoomId
=
chatRoomId
...
...
@@ -93,7 +152,8 @@ class ChatRoomPresenter @Inject constructor(
try
{
if
(
offset
==
0L
)
{
val
localMessages
=
messagesRepository
.
getByRoomId
(
chatRoomId
)
val
oldMessages
=
mapper
.
map
(
localMessages
)
val
oldMessages
=
mapper
.
map
(
localMessages
,
RoomViewModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
,
isRoom
=
true
))
if
(
oldMessages
.
isNotEmpty
())
{
view
.
showMessages
(
oldMessages
)
loadMissingMessages
()
...
...
@@ -133,8 +193,8 @@ class ChatRoomPresenter @Inject constructor(
client
.
messages
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
30
).
result
}
messagesRepository
.
saveAll
(
messages
)
v
al
allMessages
=
mapper
.
map
(
messages
)
view
.
showMessages
(
allMessages
)
v
iew
.
showMessages
(
mapper
.
map
(
messages
,
RoomViewModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
,
isRoom
=
true
))
)
}
fun
sendMessage
(
chatRoomId
:
String
,
text
:
String
,
messageId
:
String
?)
{
...
...
@@ -168,9 +228,10 @@ class ChatRoomPresenter @Inject constructor(
isTemporary
=
true
)
try
{
val
message
=
client
.
sendMessage
(
id
,
chatRoomId
,
text
)
messagesRepository
.
save
(
newMessage
)
view
.
showNewMessage
(
mapper
.
map
(
newMessage
))
val
message
=
client
.
sendMessage
(
id
,
chatRoomId
,
text
)
view
.
showNewMessage
(
mapper
.
map
(
newMessage
,
RoomViewModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
)))
message
}
catch
(
ex
:
Exception
)
{
// Ok, not very beautiful, but the backend sends us a not valid response
...
...
@@ -311,7 +372,8 @@ class ChatRoomPresenter @Inject constructor(
Timber
.
d
(
"History: $messages"
)
if
(
messages
.
result
.
isNotEmpty
())
{
val
models
=
mapper
.
map
(
messages
.
result
)
val
models
=
mapper
.
map
(
messages
.
result
,
RoomViewModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
,
isRoom
=
true
))
messagesRepository
.
saveAll
(
messages
.
result
)
launchUI
(
strategy
)
{
...
...
@@ -368,7 +430,7 @@ class ChatRoomPresenter @Inject constructor(
* @param messageId The id of the message to make citation for.
* @param mentionAuthor true means the citation is a reply otherwise it's a quote.
*/
fun
citeMessage
(
roomType
:
String
,
messageId
:
String
,
mentionAuthor
:
Boolean
)
{
fun
citeMessage
(
room
Name
:
String
,
room
Type
:
String
,
messageId
:
String
,
mentionAuthor
:
Boolean
)
{
launchUI
(
strategy
)
{
val
message
=
messagesRepository
.
getById
(
messageId
)
val
me
:
Myself
?
=
try
{
...
...
@@ -381,11 +443,19 @@ class ChatRoomPresenter @Inject constructor(
val
id
=
msg
.
id
val
username
=
msg
.
sender
?.
username
?:
""
val
mention
=
if
(
mentionAuthor
&&
me
?.
username
!=
username
)
"@$username"
else
""
val
room
=
if
(
roomTypeOf
(
roomType
)
is
RoomType
.
DirectMessage
)
username
else
roomType
val
room
=
if
(
roomTypeOf
(
roomType
)
is
RoomType
.
DirectMessage
)
username
else
roomName
val
chatRoomType
=
when
(
roomTypeOf
(
roomType
))
{
is
RoomType
.
DirectMessage
->
"direct"
is
RoomType
.
PrivateGroup
->
"group"
is
RoomType
.
Channel
->
"channel"
is
RoomType
.
Livechat
->
"livechat"
else
->
"custom"
}
view
.
showReplyingAction
(
username
=
getDisplayName
(
msg
.
sender
),
replyMarkdown
=
"[ ]($currentServer/$roomType/$room?msg=$id) $mention "
,
quotedMessage
=
mapper
.
map
(
message
).
last
().
preview
?.
message
?:
""
replyMarkdown
=
"[ ]($currentServer/$chatRoomType/$room?msg=$id) $mention "
,
quotedMessage
=
mapper
.
map
(
message
,
RoomViewModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
)).
last
().
preview
?.
message
?:
""
)
}
}
...
...
@@ -580,7 +650,7 @@ class ChatRoomPresenter @Inject constructor(
fun
loadChatRooms
()
{
launchUI
(
strategy
)
{
try
{
val
chatRooms
=
getC
hatRoomsInteractor
.
getAll
(
currentServer
)
val
chatRooms
=
c
hatRoomsInteractor
.
getAll
(
currentServer
)
.
filterNot
{
it
.
type
is
RoomType
.
DirectMessage
||
it
.
type
is
RoomType
.
Livechat
}
...
...
@@ -613,6 +683,32 @@ class ChatRoomPresenter @Inject constructor(
}
}
fun
openDirectMessage
(
roomName
:
String
,
message
:
String
)
{
launchUI
(
strategy
)
{
try
{
chatRoomsInteractor
.
getByName
(
currentServer
,
roomName
)
?.
let
{
if
(
it
.
type
is
RoomType
.
DirectMessage
)
{
navigator
.
toDirectMessage
(
chatRoomId
=
it
.
id
,
chatRoomType
=
it
.
type
.
toString
(),
chatRoomLastSeen
=
it
.
lastSeen
?:
-
1
,
chatRoomName
=
roomName
,
isChatRoomCreator
=
false
,
isChatRoomReadOnly
=
false
,
isChatRoomSubscribed
=
it
.
open
,
chatRoomMessage
=
message
)
}
else
{
throw
IllegalStateException
(
"Not a direct-message"
)
}
}
}
catch
(
ex
:
Exception
)
{
Timber
.
e
(
ex
)
view
.
showMessage
(
ex
.
message
!!
)
}
}
}
/**
* Send an emoji reaction to a message.
*/
...
...
@@ -736,7 +832,8 @@ class ChatRoomPresenter @Inject constructor(
private
fun
updateMessage
(
streamedMessage
:
Message
)
{
launchUI
(
strategy
)
{
val
viewModelStreamedMessage
=
mapper
.
map
(
streamedMessage
)
val
viewModelStreamedMessage
=
mapper
.
map
(
streamedMessage
,
RoomViewModel
(
roles
=
chatRoles
,
isBroadcast
=
chatIsBroadcast
))
val
roomMessages
=
messagesRepository
.
getByRoomId
(
streamedMessage
.
roomId
)
val
index
=
roomMessages
.
indexOfFirst
{
msg
->
msg
.
id
==
streamedMessage
.
id
}
if
(
index
>
-
1
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
b7606345
...
...
@@ -8,6 +8,7 @@ import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewMod
import
chat.rocket.android.core.behaviours.LoadingView
import
chat.rocket.android.core.behaviours.MessageView
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.model.ChatRoom
interface
ChatRoomView
:
LoadingView
,
MessageView
{
...
...
@@ -122,9 +123,9 @@ interface ChatRoomView : LoadingView, MessageView {
/**
* This user has joined the chat callback.
*
* @param
c
anPost Whether the user can post a message or not.
* @param
userC
anPost Whether the user can post a message or not.
*/
fun
onJoined
(
c
anPost
:
Boolean
)
fun
onJoined
(
userC
anPost
:
Boolean
)
fun
showReactionsPopup
(
messageId
:
String
)
...
...
@@ -135,5 +136,14 @@ interface ChatRoomView : LoadingView, MessageView {
*/
fun
populateCommandSuggestions
(
commands
:
List
<
CommandSuggestionViewModel
>)
fun
onRoomChanged
(
canPost
:
Boolean
)
/**
* Communicate whether it's a broadcast channel and if current user can post to it.
*/
fun
onRoomUpdated
(
userCanPost
:
Boolean
,
channelIsBroadcast
:
Boolean
,
userCanMod
:
Boolean
)
/**
* Open a DM with the user in the given [chatRoom] and pass the [permalink] for the message
* to reply.
*/
fun
openDirectMessage
(
chatRoom
:
ChatRoom
,
permalink
:
String
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/service/MessageService.kt
View file @
b7606345
...
...
@@ -60,8 +60,16 @@ class MessageService : JobService() {
)
messageRepository
.
save
(
message
.
copy
(
isTemporary
=
false
))
Timber
.
d
(
"Sent scheduled message given by id: ${message.id}"
)
}
catch
(
ex
:
RocketChat
Exception
)
{
}
catch
(
ex
:
Exception
)
{
Timber
.
e
(
ex
)
// TODO - remove the generic message when we implement :userId:/message subscription
if
(
ex
is
IllegalStateException
)
{
Timber
.
d
(
ex
,
"Probably a read-only problem..."
)
// TODO: For now we are only going to reschedule when api is fixed.
messageRepository
.
removeById
(
message
.
id
)
jobFinished
(
params
,
false
)
}
else
{
// some other error
if
(
ex
.
message
?.
contains
(
"E11000"
,
true
)
==
true
)
{
// XXX: Temporary solution. We need proper error codes from the api.
messageRepository
.
save
(
message
.
copy
(
isTemporary
=
false
))
...
...
@@ -71,6 +79,7 @@ class MessageService : JobService() {
}
}
}
}
companion
object
{
const
val
RETRY_SEND_MESSAGE_ID
=
1
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
View file @
b7606345
...
...
@@ -10,11 +10,14 @@ import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.util.extensions.addFragment
import
chat.rocket.android.util.extensions.textContent
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.roomTypeOf
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjector
import
dagger.android.DispatchingAndroidInjector
import
dagger.android.support.HasSupportFragmentInjector
import
kotlinx.android.synthetic.main.app_bar.*
import
kotlinx.android.synthetic.main.app_bar
_chat_room
.*
import
javax.inject.Inject
fun
Context
.
chatRoomIntent
(
...
...
@@ -24,7 +27,8 @@ fun Context.chatRoomIntent(
isChatRoomReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
,
isChatRoomSubscribed
:
Boolean
=
true
,
isChatRoomOwner
:
Boolean
=
false
isChatRoomCreator
:
Boolean
=
false
,
chatRoomMessage
:
String
?
=
null
):
Intent
{
return
Intent
(
this
,
ChatRoomActivity
::
class
.
java
).
apply
{
putExtra
(
INTENT_CHAT_ROOM_ID
,
chatRoomId
)
...
...
@@ -33,7 +37,8 @@ fun Context.chatRoomIntent(
putExtra
(
INTENT_CHAT_ROOM_IS_READ_ONLY
,
isChatRoomReadOnly
)
putExtra
(
INTENT_CHAT_ROOM_LAST_SEEN
,
chatRoomLastSeen
)
putExtra
(
INTENT_CHAT_IS_SUBSCRIBED
,
isChatRoomSubscribed
)
putExtra
(
INTENT_CHAT_ROOM_IS_OWNER
,
isChatRoomOwner
)
putExtra
(
INTENT_CHAT_ROOM_IS_CREATOR
,
isChatRoomCreator
)
putExtra
(
INTENT_CHAT_ROOM_MESSAGE
,
chatRoomMessage
)
}
}
...
...
@@ -41,9 +46,10 @@ private const val INTENT_CHAT_ROOM_ID = "chat_room_id"
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_IS_READ_ONLY
=
"chat_room_is_read_only"
private
const
val
INTENT_CHAT_ROOM_IS_
OWNER
=
"chat_room_is_owne
r"
private
const
val
INTENT_CHAT_ROOM_IS_
CREATOR
=
"chat_room_is_creato
r"
private
const
val
INTENT_CHAT_ROOM_LAST_SEEN
=
"chat_room_last_seen"
private
const
val
INTENT_CHAT_IS_SUBSCRIBED
=
"is_chat_room_subscribed"
private
const
val
INTENT_CHAT_ROOM_MESSAGE
=
"chat_room_message"
class
ChatRoomActivity
:
AppCompatActivity
(),
HasSupportFragmentInjector
{
@Inject
...
...
@@ -62,7 +68,7 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
private
lateinit
var
chatRoomType
:
String
private
var
isChatRoomReadOnly
:
Boolean
=
false
private
var
isChatRoomSubscribed
:
Boolean
=
true
private
var
isChatRoom
Owne
r
:
Boolean
=
false
private
var
isChatRoom
Creato
r
:
Boolean
=
false
private
var
chatRoomLastSeen
:
Long
=
-
1L
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
...
...
@@ -91,8 +97,10 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
isChatRoomReadOnly
=
intent
.
getBooleanExtra
(
INTENT_CHAT_ROOM_IS_READ_ONLY
,
true
)
requireNotNull
(
isChatRoomReadOnly
)
{
"no chat_room_is_read_only provided in Intent extras"
}
isChatRoomOwner
=
intent
.
getBooleanExtra
(
INTENT_CHAT_ROOM_IS_OWNER
,
false
)
requireNotNull
(
isChatRoomOwner
)
{
"no chat_room_is_owner provided in Intent extras"
}
isChatRoomCreator
=
intent
.
getBooleanExtra
(
INTENT_CHAT_ROOM_IS_CREATOR
,
false
)
requireNotNull
(
isChatRoomCreator
)
{
"no chat_room_is_creator provided in Intent extras"
}
val
chatRoomMessage
=
intent
.
getStringExtra
(
INTENT_CHAT_ROOM_MESSAGE
)
setupToolbar
()
...
...
@@ -102,10 +110,8 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
if
(
supportFragmentManager
.
findFragmentByTag
(
TAG_CHAT_ROOM_FRAGMENT
)
==
null
)
{
addFragment
(
TAG_CHAT_ROOM_FRAGMENT
,
R
.
id
.
fragment_container
)
{
newInstance
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
isChatRoomReadOnly
,
chatRoomLastSeen
,
isChatRoomSubscribed
,
isChatRoomOwner
)
newInstance
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
isChatRoomReadOnly
,
chatRoomLastSeen
,
isChatRoomSubscribed
,
isChatRoomCreator
,
chatRoomMessage
)
}
}
}
...
...
@@ -120,13 +126,45 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
private
fun
setupToolbar
()
{
setSupportActionBar
(
toolbar
)
supportActionBar
?.
setDisplayShowTitleEnabled
(
false
)
toolbar
.
setNavigationIcon
(
R
.
drawable
.
ic_arrow_back_white_24dp
)
toolbar
.
title
=
chatRoomName
text_room_name
.
textContent
=
chatRoomName
showRoomTypeIcon
(
true
)
toolbar
.
setNavigationOnClickListener
{
finishActivity
()
}
}
fun
showRoomTypeIcon
(
showRoomTypeIcon
:
Boolean
)
{
if
(
showRoomTypeIcon
)
{
val
roomType
=
roomTypeOf
(
chatRoomType
)
val
drawable
=
when
(
roomType
)
{
is
RoomType
.
Channel
->
{
DrawableHelper
.
getDrawableFromId
(
R
.
drawable
.
ic_room_channel
,
this
)
}
is
RoomType
.
PrivateGroup
->
{
DrawableHelper
.
getDrawableFromId
(
R
.
drawable
.
ic_room_lock
,
this
)
}
is
RoomType
.
DirectMessage
->
{
DrawableHelper
.
getDrawableFromId
(
R
.
drawable
.
ic_room_dm
,
this
)
}
else
->
null
}
drawable
?.
let
{
val
wrappedDrawable
=
DrawableHelper
.
wrapDrawable
(
it
)
val
mutableDrawable
=
wrappedDrawable
.
mutate
()
DrawableHelper
.
tintDrawable
(
mutableDrawable
,
this
,
R
.
color
.
white
)
DrawableHelper
.
compoundDrawable
(
text_room_name
,
mutableDrawable
)
}
}
else
{
text_room_name
.
setCompoundDrawablesWithIntrinsicBounds
(
0
,
0
,
0
,
0
)
}
}
fun
setupToolbarTitle
(
toolbarTitle
:
String
)
{
supportActionBar
?.
title
=
toolbarTitle
text_room_name
.
textContent
=
toolbarTitle
}
private
fun
finishActivity
()
{
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
b7606345
...
...
@@ -13,12 +13,22 @@ import android.support.v4.app.Fragment
import
android.support.v7.widget.DefaultItemAnimator
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.RecyclerView
import
android.view.KeyEvent
import
android.view.LayoutInflater
import
android.view.Menu
import
android.view.MenuInflater
import
android.view.MenuItem
import
android.view.View
import
android.view.ViewGroup
import
android.text.SpannableStringBuilder
import
android.view.*
import
androidx.core.text.bold
import
androidx.core.view.isVisible
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.*
import
chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import
chat.rocket.android.chatroom.adapter.CommandSuggestionsAdapter
import
chat.rocket.android.chatroom.adapter.PEOPLE
import
chat.rocket.android.chatroom.adapter.PeopleSuggestionsAdapter
import
chat.rocket.android.chatroom.adapter.RoomSuggestionsAdapter
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.presentation.ChatRoomView
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
...
...
@@ -29,9 +39,28 @@ import chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewMod
import
chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.widget.emoji.*
import
chat.rocket.android.util.extensions.asObservable
import
chat.rocket.android.util.extensions.circularRevealOrUnreveal
import
chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeOut
import
chat.rocket.android.util.extensions.hideKeyboard
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.isAtBottom
import
chat.rocket.android.util.extensions.rotateBy
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.showToast
import
chat.rocket.android.util.extensions.textContent
import
chat.rocket.android.util.extensions.ui
import
chat.rocket.android.widget.emoji.ComposerEditText
import
chat.rocket.android.widget.emoji.Emoji
import
chat.rocket.android.widget.emoji.EmojiKeyboardListener
import
chat.rocket.android.widget.emoji.EmojiKeyboardPopup
import
chat.rocket.android.widget.emoji.EmojiListenerAdapter
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.android.widget.emoji.EmojiPickerPopup
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
chat.rocket.core.internal.realtime.socket.model.State
import
chat.rocket.core.model.ChatRoom
import
dagger.android.support.AndroidSupportInjection
import
io.reactivex.Observable
import
io.reactivex.disposables.CompositeDisposable
...
...
@@ -51,7 +80,8 @@ fun newInstance(
isChatRoomReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
,
isSubscribed
:
Boolean
=
true
,
isChatRoomOwner
:
Boolean
=
false
isChatRoomCreator
:
Boolean
=
false
,
chatRoomMessage
:
String
?
=
null
):
Fragment
{
return
ChatRoomFragment
().
apply
{
arguments
=
Bundle
(
1
).
apply
{
...
...
@@ -61,7 +91,8 @@ fun newInstance(
putBoolean
(
BUNDLE_IS_CHAT_ROOM_READ_ONLY
,
isChatRoomReadOnly
)
putLong
(
BUNDLE_CHAT_ROOM_LAST_SEEN
,
chatRoomLastSeen
)
putBoolean
(
BUNDLE_CHAT_ROOM_IS_SUBSCRIBED
,
isSubscribed
)
putBoolean
(
BUNDLE_CHAT_ROOM_IS_OWNER
,
isChatRoomOwner
)
putBoolean
(
BUNDLE_CHAT_ROOM_IS_CREATOR
,
isChatRoomCreator
)
putString
(
BUNDLE_CHAT_ROOM_MESSAGE
,
chatRoomMessage
)
}
}
}
...
...
@@ -73,9 +104,11 @@ private const val BUNDLE_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only"
private
const
val
REQUEST_CODE_FOR_PERFORM_SAF
=
42
private
const
val
BUNDLE_CHAT_ROOM_LAST_SEEN
=
"chat_room_last_seen"
private
const
val
BUNDLE_CHAT_ROOM_IS_SUBSCRIBED
=
"chat_room_is_subscribed"
private
const
val
BUNDLE_CHAT_ROOM_IS_OWNER
=
"chat_room_is_owner"
private
const
val
BUNDLE_CHAT_ROOM_IS_CREATOR
=
"chat_room_is_creator"
private
const
val
BUNDLE_CHAT_ROOM_MESSAGE
=
"chat_room_message"
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiKeyboardListener
,
EmojiReactionListener
{
@Inject
lateinit
var
presenter
:
ChatRoomPresenter
@Inject
...
...
@@ -84,9 +117,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private
lateinit
var
chatRoomId
:
String
private
lateinit
var
chatRoomName
:
String
private
lateinit
var
chatRoomType
:
String
private
var
chatRoomMessage
:
String
?
=
null
private
var
isSubscribed
:
Boolean
=
true
private
var
isChatRoomReadOnly
:
Boolean
=
false
private
var
isChatRoomOwner
:
Boolean
=
false
private
var
isChatRoomCreator
:
Boolean
=
false
private
var
isBroadcastChannel
:
Boolean
=
false
private
lateinit
var
emojiKeyboardPopup
:
EmojiKeyboardPopup
private
var
chatRoomLastSeen
:
Long
=
-
1
private
lateinit
var
actionSnackbar
:
ActionSnackbar
...
...
@@ -127,8 +162,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
isChatRoomReadOnly
=
bundle
.
getBoolean
(
BUNDLE_IS_CHAT_ROOM_READ_ONLY
)
isSubscribed
=
bundle
.
getBoolean
(
BUNDLE_CHAT_ROOM_IS_SUBSCRIBED
)
chatRoomLastSeen
=
bundle
.
getLong
(
BUNDLE_CHAT_ROOM_LAST_SEEN
)
isChatRoom
Owner
=
bundle
.
getBoolean
(
BUNDLE_CHAT_ROOM_IS_OWNE
R
)
isChatRoom
Creator
=
bundle
.
getBoolean
(
BUNDLE_CHAT_ROOM_IS_CREATO
R
)
chatRoomMessage
=
bundle
.
getString
(
BUNDLE_CHAT_ROOM_MESSAGE
)
}
else
{
requireNotNull
(
bundle
)
{
"no arguments supplied when the fragment was instantiated"
}
}
...
...
@@ -146,13 +181,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
super
.
onViewCreated
(
view
,
savedInstanceState
)
setupToolbar
(
chatRoomName
)
presenter
.
setupChatRoom
()
presenter
.
loadMessages
(
chatRoomId
,
chatRoomType
)
presenter
.
setupChatRoom
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
chatRoomMessage
)
presenter
.
loadChatRooms
()
setupRecyclerView
()
setupFab
()
setupSuggestionsView
()
setupActionSnackbar
()
activity
?.
apply
{
(
this
as
?
ChatRoomActivity
)
?.
showRoomTypeIcon
(
true
)
}
}
override
fun
onActivityCreated
(
savedInstanceState
:
Bundle
?)
{
...
...
@@ -187,6 +224,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
onCreateOptionsMenu
(
menu
:
Menu
,
inflater
:
MenuInflater
)
{
super
.
onCreateOptionsMenu
(
menu
,
inflater
)
inflater
.
inflate
(
R
.
menu
.
chatroom_actions
,
menu
)
menu
.
findItem
(
R
.
id
.
action_members_list
)
?.
isVisible
=
!
isBroadcastChannel
}
override
fun
onOptionsItemSelected
(
item
:
MenuItem
):
Boolean
{
...
...
@@ -229,7 +267,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
if
(
recycler_view
.
adapter
==
null
)
{
adapter
=
ChatRoomAdapter
(
chatRoomType
,
presenter
,
chatRoomType
,
chatRoomName
,
presenter
,
reactionListener
=
this
@ChatRoomFragment
)
recycler_view
.
adapter
=
adapter
...
...
@@ -251,8 +289,16 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
override
fun
onRoomChanged
(
canPost
:
Boolean
)
{
setupMessageComposer
(
isChatRoomOwner
||
canPost
)
override
fun
onRoomUpdated
(
userCanPost
:
Boolean
,
channelIsBroadcast
:
Boolean
,
userCanMod
:
Boolean
)
{
// TODO: We should rely solely on the user being able to post, but we cannot guarantee
// that the "(channels|groups).roles" endpoint is supported by the server in use.
setupMessageComposer
(
userCanPost
)
isBroadcastChannel
=
channelIsBroadcast
if
(
isBroadcastChannel
&&
!
userCanMod
)
activity
?.
invalidateOptionsMenu
()
}
override
fun
openDirectMessage
(
chatRoom
:
ChatRoom
,
permalink
:
String
)
{
}
private
fun
toggleNoChatView
(
size
:
Int
)
{
...
...
@@ -316,7 +362,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
if
(!
recyclerView
.
canScrollVertically
(
1
))
{
button_fab
.
hide
()
}
else
{
if
(
dy
<
0
&&
!
button_fab
.
isVisible
()
)
{
if
(
dy
<
0
&&
!
button_fab
.
isVisible
)
{
button_fab
.
show
()
}
}
...
...
@@ -434,12 +480,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
actionSnackbar
.
text
=
quotedMessage
actionSnackbar
.
show
()
KeyboardHelper
.
showSoftKeyboard
(
text_message
)
if
(!
recycler_view
.
isAtBottom
())
{
if
(
adapter
.
itemCount
>
0
)
{
recycler_view
.
scrollToPosition
(
0
)
verticalScrollOffset
.
set
(
0
)
}
}
}
}
...
...
@@ -586,12 +626,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
override
fun
onJoined
(
c
anPost
:
Boolean
)
{
override
fun
onJoined
(
userC
anPost
:
Boolean
)
{
ui
{
input_container
.
setVisible
(
true
)
button_join_chat
.
setVisible
(
false
)
isSubscribed
=
true
setupMessageComposer
(
isChatRoomOwner
)
setupMessageComposer
(
userCanPost
)
}
}
...
...
@@ -623,7 +663,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
private
fun
setupMessageComposer
(
canPost
:
Boolean
)
{
if
(
!
canPost
&&
isChatRoomReadOnly
)
{
if
(
isChatRoomReadOnly
&&
!
canPost
)
{
text_room_is_read_only
.
setVisible
(
true
)
input_container
.
setVisible
(
false
)
}
else
if
(!
isSubscribed
)
{
...
...
@@ -728,7 +768,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
setReactionButtonIcon
(
R
.
drawable
.
ic_keyboard_black_24dp
)
}
else
{
// If popup is showing, simply dismiss it to show the undelying text keyboard
// If popup is showing, simply dismiss it to show the unde
r
lying text keyboard
emojiKeyboardPopup
.
dismiss
()
setReactionButtonIcon
(
R
.
drawable
.
ic_reaction_24dp
)
}
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
View file @
b7606345
...
...
@@ -24,7 +24,8 @@ interface BaseViewModel<out T> {
MESSAGE_ATTACHMENT
(
6
),
AUTHOR_ATTACHMENT
(
7
),
COLOR_ATTACHMENT
(
8
),
GENERIC_FILE_ATTACHMENT
(
9
)
GENERIC_FILE_ATTACHMENT
(
9
),
MESSAGE_REPLY
(
10
)
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/MessageReplyViewModel.kt
0 → 100644
View file @
b7606345
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.domain.MessageReply
import
chat.rocket.core.model.Message
data class
MessageReplyViewModel
(
override
val
rawData
:
MessageReply
,
override
val
messageId
:
String
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?,
override
var
preview
:
Message
?,
override
var
isTemporary
:
Boolean
=
false
,
override
val
message
:
Message
)
:
BaseViewModel
<
MessageReply
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
MESSAGE_REPLY
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
item_message_reply
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/RoomViewModel.kt
0 → 100644
View file @
b7606345
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.core.model.ChatRoomRole
data class
RoomViewModel
(
val
roles
:
List
<
ChatRoomRole
>,
val
isBroadcast
:
Boolean
=
false
,
val
isRoom
:
Boolean
=
false
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
View file @
b7606345
...
...
@@ -13,16 +13,32 @@ import androidx.core.text.buildSpannedString
import
androidx.core.text.color
import
androidx.core.text.scale
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.domain.MessageReply
import
chat.rocket.android.helper.MessageHelper
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.ChatRoomsInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.GetSettingsInteractor
import
chat.rocket.android.server.domain.TokenRepository
import
chat.rocket.android.server.domain.baseUrl
import
chat.rocket.android.server.domain.useRealName
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.isNotNullNorEmpty
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.core.model.ChatRoom
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.MessageType
import
chat.rocket.core.model.Value
import
chat.rocket.core.model.attachment.*
import
chat.rocket.core.model.attachment.Attachment
import
chat.rocket.core.model.attachment.AudioAttachment
import
chat.rocket.core.model.attachment.AuthorAttachment
import
chat.rocket.core.model.attachment.ColorAttachment
import
chat.rocket.core.model.attachment.FileAttachment
import
chat.rocket.core.model.attachment.GenericFileAttachment
import
chat.rocket.core.model.attachment.ImageAttachment
import
chat.rocket.core.model.attachment.MessageAttachment
import
chat.rocket.core.model.attachment.VideoAttachment
import
chat.rocket.core.model.isSystemMessage
import
chat.rocket.core.model.url.Url
import
kotlinx.coroutines.experimental.CommonPool
...
...
@@ -34,6 +50,8 @@ import javax.inject.Inject
class
ViewModelMapper
@Inject
constructor
(
private
val
context
:
Context
,
private
val
parser
:
MessageParser
,
private
val
roomsInteractor
:
ChatRoomsInteractor
,
private
val
messageHelper
:
MessageHelper
,
tokenRepository
:
TokenRepository
,
serverInteractor
:
GetCurrentServerInteractor
,
getSettingsInteractor
:
GetSettingsInteractor
,
...
...
@@ -47,21 +65,24 @@ class ViewModelMapper @Inject constructor(
private
val
currentUsername
:
String
?
=
localRepository
.
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
private
val
secondaryTextColor
=
ContextCompat
.
getColor
(
context
,
R
.
color
.
colorSecondaryText
)
suspend
fun
map
(
message
:
Message
):
List
<
BaseViewModel
<*
>>
{
return
translate
(
message
)
suspend
fun
map
(
message
:
Message
,
roomViewModel
:
RoomViewModel
=
RoomViewModel
(
roles
=
emptyList
(),
isBroadcast
=
true
)):
List
<
BaseViewModel
<*
>>
{
return
translate
(
message
,
roomViewModel
)
}
suspend
fun
map
(
messages
:
List
<
Message
>):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
suspend
fun
map
(
messages
:
List
<
Message
>,
roomViewModel
:
RoomViewModel
=
RoomViewModel
(
roles
=
emptyList
(),
isBroadcast
=
true
)):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
val
list
=
ArrayList
<
BaseViewModel
<*>>(
messages
.
size
)
messages
.
forEach
{
list
.
addAll
(
translate
(
it
))
list
.
addAll
(
translate
(
it
,
roomViewModel
))
}
return
@withContext
list
}
private
suspend
fun
translate
(
message
:
Message
):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
private
suspend
fun
translate
(
message
:
Message
,
roomViewModel
:
RoomViewModel
)
:
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
val
list
=
ArrayList
<
BaseViewModel
<*>>()
message
.
urls
?.
forEach
{
...
...
@@ -86,9 +107,40 @@ class ViewModelMapper @Inject constructor(
list
[
i
].
nextDownStreamMessage
=
next
}
if
(
isBroadcastReplyAvailable
(
roomViewModel
,
message
))
{
roomsInteractor
.
getById
(
currentServer
,
message
.
roomId
)
?.
let
{
chatRoom
->
val
replyViewModel
=
mapMessageReply
(
message
,
chatRoom
)
list
.
first
().
nextDownStreamMessage
=
replyViewModel
list
.
add
(
0
,
replyViewModel
)
}
}
return
@withContext
list
}
private
fun
isBroadcastReplyAvailable
(
roomViewModel
:
RoomViewModel
,
message
:
Message
):
Boolean
{
val
senderUsername
=
message
.
sender
?.
username
return
roomViewModel
.
isRoom
&&
roomViewModel
.
isBroadcast
&&
!
message
.
isSystemMessage
()
&&
senderUsername
!=
currentUsername
}
private
fun
mapMessageReply
(
message
:
Message
,
chatRoom
:
ChatRoom
):
MessageReplyViewModel
{
val
name
=
message
.
sender
?.
name
val
roomName
=
if
(
settings
.
useRealName
()
&&
name
!=
null
)
name
else
message
.
sender
?.
username
?:
""
val
permalink
=
messageHelper
.
createPermalink
(
message
,
chatRoom
)
return
MessageReplyViewModel
(
messageId
=
message
.
id
,
isTemporary
=
false
,
reactions
=
emptyList
(),
message
=
message
,
preview
=
mapMessagePreview
(
message
),
rawData
=
MessageReply
(
roomName
=
roomName
,
permalink
=
permalink
),
nextDownStreamMessage
=
null
)
}
private
fun
mapUrl
(
message
:
Message
,
url
:
Url
):
BaseViewModel
<
*
>?
{
if
(
url
.
ignoreParse
||
url
.
meta
==
null
)
return
null
...
...
@@ -313,7 +365,6 @@ class ViewModelMapper @Inject constructor(
}
private
fun
getSystemMessage
(
message
:
Message
):
CharSequence
{
println
(
message
)
val
content
=
when
(
message
.
type
)
{
//TODO: Add implementation for Welcome type.
is
MessageType
.
MessageRemoved
->
context
.
getString
(
R
.
string
.
message_removed
)
...
...
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
View file @
b7606345
...
...
@@ -9,7 +9,18 @@ import chat.rocket.android.helper.SharedPreferenceHelper
import
chat.rocket.android.helper.UserHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.main.presentation.MainNavigator
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.ChatRoomsInteractor
import
chat.rocket.android.server.domain.GetActiveUsersInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.JobSchedulerInteractor
import
chat.rocket.android.server.domain.PermissionsInteractor
import
chat.rocket.android.server.domain.RefreshSettingsInteractor
import
chat.rocket.android.server.domain.SaveActiveUsersInteractor
import
chat.rocket.android.server.domain.SaveChatRoomsInteractor
import
chat.rocket.android.server.domain.SettingsRepository
import
chat.rocket.android.server.domain.hasShowLastMessage
import
chat.rocket.android.server.domain.showLastMessage
import
chat.rocket.android.server.domain.useRealName
import
chat.rocket.android.server.infraestructure.ConnectionManager
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.chatRooms
...
...
@@ -31,9 +42,13 @@ import chat.rocket.core.internal.rest.permissions
import
chat.rocket.core.internal.rest.spotlight
import
chat.rocket.core.model.ChatRoom
import
chat.rocket.core.model.Room
import
kotlinx.coroutines.experimental.*
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.Deferred
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.async
import
kotlinx.coroutines.experimental.channels.Channel
import
kotlinx.coroutines.experimental.delay
import
kotlinx.coroutines.experimental.launch
import
timber.log.Timber
import
javax.inject.Inject
import
kotlin.reflect.KProperty1
...
...
@@ -43,7 +58,7 @@ class ChatRoomsPresenter @Inject constructor(
private
val
strategy
:
CancelStrategy
,
private
val
navigator
:
MainNavigator
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
getChatRoomsInteractor
:
Get
ChatRoomsInteractor
,
private
val
chatRoomsInteractor
:
ChatRoomsInteractor
,
private
val
saveChatRoomsInteractor
:
SaveChatRoomsInteractor
,
private
val
saveActiveUsersInteractor
:
SaveActiveUsersInteractor
,
private
val
getActiveUsersInteractor
:
GetActiveUsersInteractor
,
...
...
@@ -148,7 +163,7 @@ class ChatRoomsPresenter @Inject constructor(
val
currentServer
=
serverInteractor
.
get
()
!!
launchUI
(
strategy
)
{
try
{
val
roomList
=
getC
hatRoomsInteractor
.
getAllByName
(
currentServer
,
name
)
val
roomList
=
c
hatRoomsInteractor
.
getAllByName
(
currentServer
,
name
)
if
(
roomList
.
isEmpty
())
{
val
(
users
,
rooms
)
=
retryIO
(
"spotlight($name)"
)
{
client
.
spotlight
(
name
)
...
...
@@ -253,7 +268,7 @@ class ChatRoomsPresenter @Inject constructor(
fun
updateSortedChatRooms
()
{
launchUI
(
strategy
)
{
val
roomList
=
getC
hatRoomsInteractor
.
getAll
(
currentServer
)
val
roomList
=
c
hatRoomsInteractor
.
getAll
(
currentServer
)
view
.
updateChatRooms
(
sortRooms
(
roomList
))
}
}
...
...
@@ -453,7 +468,7 @@ class ChatRoomsPresenter @Inject constructor(
// Update a ChatRoom with a Room information
private
fun
updateRoom
(
room
:
Room
)
{
Timber
.
d
(
"Updating Room: ${room.id} - ${room.name}"
)
val
chatRooms
=
getC
hatRoomsInteractor
.
getAll
(
currentServer
).
toMutableList
()
val
chatRooms
=
c
hatRoomsInteractor
.
getAll
(
currentServer
).
toMutableList
()
val
chatRoom
=
chatRooms
.
find
{
chatRoom
->
chatRoom
.
id
==
room
.
id
}
chatRoom
?.
apply
{
val
newRoom
=
ChatRoom
(
...
...
@@ -493,7 +508,7 @@ class ChatRoomsPresenter @Inject constructor(
// Update a ChatRoom with a Subscription information
private
fun
updateSubscription
(
subscription
:
Subscription
)
{
Timber
.
d
(
"Updating subscription: ${subscription.id} - ${subscription.name}"
)
val
chatRooms
=
getC
hatRoomsInteractor
.
getAll
(
currentServer
).
toMutableList
()
val
chatRooms
=
c
hatRoomsInteractor
.
getAll
(
currentServer
).
toMutableList
()
val
chatRoom
=
chatRooms
.
find
{
chatRoom
->
chatRoom
.
id
==
subscription
.
roomId
}
chatRoom
?.
apply
{
val
newRoom
=
ChatRoom
(
...
...
@@ -532,7 +547,7 @@ class ChatRoomsPresenter @Inject constructor(
private
fun
removeRoom
(
id
:
String
,
chatRooms
:
MutableList
<
ChatRoom
>
=
getC
hatRoomsInteractor
.
getAll
(
currentServer
).
toMutableList
()
chatRooms
:
MutableList
<
ChatRoom
>
=
c
hatRoomsInteractor
.
getAll
(
currentServer
).
toMutableList
()
)
{
Timber
.
d
(
"Removing ROOM: $id"
)
synchronized
(
this
)
{
...
...
@@ -573,7 +588,7 @@ class ChatRoomsPresenter @Inject constructor(
val
username
=
user_
.
username
val
status
=
user_
.
status
if
(
username
!=
null
&&
status
!=
null
)
{
getC
hatRoomsInteractor
.
getByName
(
currentServer
,
username
)
?.
let
{
c
hatRoomsInteractor
.
getByName
(
currentServer
,
username
)
?.
let
{
val
newRoom
=
ChatRoom
(
id
=
it
.
id
,
type
=
it
.
type
,
...
...
@@ -600,10 +615,10 @@ class ChatRoomsPresenter @Inject constructor(
broadcast
=
it
.
broadcast
)
getC
hatRoomsInteractor
.
remove
(
currentServer
,
it
)
getC
hatRoomsInteractor
.
add
(
currentServer
,
newRoom
)
c
hatRoomsInteractor
.
remove
(
currentServer
,
it
)
c
hatRoomsInteractor
.
add
(
currentServer
,
newRoom
)
launchUI
(
strategy
)
{
view
.
updateChatRooms
(
sortRooms
(
getC
hatRoomsInteractor
.
getAll
(
currentServer
)))
view
.
updateChatRooms
(
sortRooms
(
c
hatRoomsInteractor
.
getAll
(
currentServer
)))
}
}
}
...
...
@@ -613,7 +628,7 @@ class ChatRoomsPresenter @Inject constructor(
Timber
.
i
(
"Updating ChatRooms"
)
launch
(
strategy
.
jobs
)
{
val
chatRoomsWithPreview
=
getChatRoomsWithPreviews
(
getC
hatRoomsInteractor
.
getAll
(
currentServer
)
c
hatRoomsInteractor
.
getAll
(
currentServer
)
)
val
chatRoomsWithStatus
=
getChatRoomWithStatus
(
chatRoomsWithPreview
)
view
.
updateChatRooms
(
chatRoomsWithStatus
)
...
...
app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
View file @
b7606345
...
...
@@ -45,7 +45,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
lateinit
var
settingsRepository
:
SettingsRepository
@Inject
lateinit
var
localRepository
:
LocalRepository
private
lateinit
var
preferences
:
SharedPreferences
private
var
searchView
:
SearchView
?
=
null
private
val
handler
=
Handler
()
...
...
@@ -60,7 +59,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
setHasOptionsMenu
(
true
)
preferences
=
context
?.
getSharedPreferences
(
"temp"
,
Context
.
MODE_PRIVATE
)
!!
}
override
fun
onDestroy
()
{
...
...
app/src/main/java/chat/rocket/android/favoritemessages/presentation/FavoriteMessagesPresenter.kt
View file @
b7606345
...
...
@@ -2,7 +2,7 @@ package chat.rocket.android.favoritemessages.presentation
import
chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.
Get
ChatRoomsInteractor
import
chat.rocket.android.server.domain.ChatRoomsInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.launchUI
...
...
@@ -16,7 +16,7 @@ class FavoriteMessagesPresenter @Inject constructor(
private
val
view
:
FavoriteMessagesView
,
private
val
strategy
:
CancelStrategy
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
roomsInteractor
:
Get
ChatRoomsInteractor
,
private
val
roomsInteractor
:
ChatRoomsInteractor
,
private
val
mapper
:
ViewModelMapper
,
factory
:
RocketChatClientFactory
)
{
...
...
app/src/main/java/chat/rocket/android/favoritemessages/ui/FavoriteMessagesFragment.kt
View file @
b7606345
...
...
@@ -70,7 +70,7 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
override
fun
showFavoriteMessages
(
favoriteMessages
:
List
<
BaseViewModel
<*
>>)
{
ui
{
if
(
recycler_view
.
adapter
==
null
)
{
adapter
=
ChatRoomAdapter
(
chatRoomType
,
null
,
false
)
adapter
=
ChatRoomAdapter
(
chatRoomType
,
""
,
null
,
false
)
recycler_view
.
adapter
=
adapter
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
...
...
app/src/main/java/chat/rocket/android/helper/MessageHelper.kt
0 → 100644
View file @
b7606345
package
chat.rocket.android.helper
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.GetSettingsInteractor
import
chat.rocket.android.server.domain.PublicSettings
import
chat.rocket.android.server.domain.useRealName
import
chat.rocket.common.model.RoomType
import
chat.rocket.core.model.ChatRoom
import
chat.rocket.core.model.Message
import
javax.inject.Inject
class
MessageHelper
@Inject
constructor
(
getSettingsInteractor
:
GetSettingsInteractor
,
serverInteractor
:
GetCurrentServerInteractor
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
settings
:
PublicSettings
=
getSettingsInteractor
.
get
(
currentServer
)
fun
createPermalink
(
message
:
Message
,
chatRoom
:
ChatRoom
):
String
{
val
type
=
when
(
chatRoom
.
type
)
{
is
RoomType
.
PrivateGroup
->
"group"
is
RoomType
.
Channel
->
"channel"
is
RoomType
.
DirectMessage
->
"direct"
is
RoomType
.
Livechat
->
"livechat"
else
->
"custom"
}
val
name
=
if
(
settings
.
useRealName
())
chatRoom
.
fullName
?:
chatRoom
.
name
else
chatRoom
.
name
return
"[ ]($currentServer/$type/$name?msg=${message.id}) "
}
fun
messageIdFromPermalink
(
permalink
:
String
):
String
?
{
PERMALINK_REGEX
.
find
(
permalink
.
trim
())
?.
let
{
if
(
it
.
groupValues
.
size
==
5
)
{
return
it
.
groupValues
[
MESSAGE_ID
]
}
}
return
null
}
fun
roomNameFromPermalink
(
permalink
:
String
):
String
?
{
PERMALINK_REGEX
.
find
(
permalink
.
trim
())
?.
let
{
if
(
it
.
groupValues
.
size
==
5
)
{
return
it
.
groupValues
[
ROOM_NAME
]
}
}
return
null
}
fun
roomTypeFromPermalink
(
permalink
:
String
):
String
?
{
PERMALINK_REGEX
.
find
(
permalink
.
trim
())
?.
let
{
if
(
it
.
groupValues
.
size
==
5
)
{
val
type
=
it
.
groupValues
[
ROOM_TYPE
]
return
when
(
type
)
{
"group"
->
"p"
"channel"
->
"c"
"direct"
->
"d"
"livechat"
->
"l"
else
->
type
}
}
}
return
null
}
companion
object
{
private
const
val
ROOM_TYPE
=
2
private
const
val
ROOM_NAME
=
3
private
const
val
MESSAGE_ID
=
4
val
PERMALINK_REGEX
=
"(?:__|[*#])|\\[(.+?)\\]\\(.+?//.+?/(.+)/(.+)\\?.*=(.*)\\)"
.
toRegex
()
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/helper/UserHelper.kt
View file @
b7606345
...
...
@@ -48,7 +48,7 @@ class UserHelper @Inject constructor(
/**
* Return the username for the current logged [User].
*/
fun
username
():
String
?
=
user
()
?.
username
fun
username
():
String
?
=
localRepository
.
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
,
null
)
/**
* Whether current [User] is admin on the current server.
...
...
app/src/main/java/chat/rocket/android/main/presentation/MainNavigator.kt
View file @
b7606345
package
chat.rocket.android.main.presentation
import
android.content.Context
import
chat.rocket.android.R
import
chat.rocket.android.authentication.ui.newServerIntent
import
chat.rocket.android.chatroom.ui.chatRoomIntent
...
...
@@ -37,9 +36,9 @@ class MainNavigator(internal val activity: MainActivity) {
isChatRoomReadOnly
:
Boolean
,
chatRoomLastSeen
:
Long
,
isChatRoomSubscribed
:
Boolean
,
isChatRoom
Owne
r
:
Boolean
)
{
isChatRoom
Creato
r
:
Boolean
)
{
activity
.
startActivity
(
activity
.
chatRoomIntent
(
chatRoomId
,
chatRoomName
,
chatRoomType
,
isChatRoomReadOnly
,
chatRoomLastSeen
,
isChatRoomSubscribed
,
isChatRoom
Owne
r
))
isChatRoomReadOnly
,
chatRoomLastSeen
,
isChatRoomSubscribed
,
isChatRoom
Creato
r
))
activity
.
overridePendingTransition
(
R
.
anim
.
open_enter
,
R
.
anim
.
open_exit
)
}
...
...
app/src/main/java/chat/rocket/android/pinnedmessages/presentation/PinnedMessagesPresenter.kt
View file @
b7606345
...
...
@@ -2,7 +2,7 @@ package chat.rocket.android.pinnedmessages.presentation
import
chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.
Get
ChatRoomsInteractor
import
chat.rocket.android.server.domain.ChatRoomsInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.launchUI
...
...
@@ -17,7 +17,7 @@ class PinnedMessagesPresenter @Inject constructor(
private
val
view
:
PinnedMessagesView
,
private
val
strategy
:
CancelStrategy
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
roomsInteractor
:
Get
ChatRoomsInteractor
,
private
val
roomsInteractor
:
ChatRoomsInteractor
,
private
val
mapper
:
ViewModelMapper
,
factory
:
RocketChatClientFactory
)
{
...
...
app/src/main/java/chat/rocket/android/pinnedmessages/ui/PinnedMessagesFragment.kt
View file @
b7606345
...
...
@@ -73,7 +73,7 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
override
fun
showPinnedMessages
(
pinnedMessages
:
List
<
BaseViewModel
<*
>>)
{
ui
{
if
(
recycler_view_pinned
.
adapter
==
null
)
{
adapter
=
ChatRoomAdapter
(
chatRoomType
,
null
,
false
)
adapter
=
ChatRoomAdapter
(
chatRoomType
,
""
,
null
,
false
)
recycler_view_pinned
.
adapter
=
adapter
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
...
...
app/src/main/java/chat/rocket/android/server/domain/
Get
ChatRoomsInteractor.kt
→
app/src/main/java/chat/rocket/android/server/domain/ChatRoomsInteractor.kt
View file @
b7606345
...
...
@@ -5,7 +5,7 @@ import kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.withContext
import
javax.inject.Inject
class
Get
ChatRoomsInteractor
@Inject
constructor
(
private
val
repository
:
ChatRoomsRepository
)
{
class
ChatRoomsInteractor
@Inject
constructor
(
private
val
repository
:
ChatRoomsRepository
)
{
/**
* Get all [ChatRoom].
...
...
@@ -41,8 +41,7 @@ class GetChatRoomsInteractor @Inject constructor(private val repository: ChatRoo
* @return The [ChatRoom] object or null if we couldn't find any.
*/
suspend
fun
getById
(
serverUrl
:
String
,
roomId
:
String
):
ChatRoom
?
=
withContext
(
CommonPool
)
{
val
allChatRooms
=
repository
.
get
(
serverUrl
)
return
@withContext
allChatRooms
.
first
{
return
@withContext
repository
.
get
(
serverUrl
).
find
{
it
.
id
==
roomId
}
}
...
...
@@ -55,7 +54,7 @@ class GetChatRoomsInteractor @Inject constructor(private val repository: ChatRoo
* @return The [ChatRoom] object or null if we couldn't find any.
*/
fun
getByName
(
serverUrl
:
String
,
name
:
String
):
ChatRoom
?
{
return
getAll
(
serverUrl
).
toMutableList
().
find
{
chatRoom
->
chatRoom
.
n
ame
==
name
}
return
getAll
(
serverUrl
).
firstOrNull
{
it
.
name
==
name
||
it
.
fullN
ame
==
name
}
}
/**
...
...
app/src/main/res/drawable/ic_room_channel.xml
0 → 100644
View file @
b7606345
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"16dp"
android:height=
"16dp"
android:viewportHeight=
"24.0"
android:viewportWidth=
"24.0"
>
<path
android:fillColor=
"#FF000000"
android:pathData=
"M22.548,9l0.452,-2h-5.364l1.364,-6h-2l-1.364,6h-5l1.364,-6h-2l-1.364,6h-6.184l-0.452,2h6.182l-1.364,6h-5.36l-0.458,2h5.364l-1.364,6h2l1.364,-6h5l-1.364,6h2l1.364,-6h6.185l0.451,-2h-6.182l1.364,-6h5.366zM13.818,15h-5l1.364,-6h5l-1.364,6z"
/>
</vector>
\ No newline at end of file
app/src/main/res/drawable/ic_room_dm.xml
0 → 100644
View file @
b7606345
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"16dp"
android:height=
"16dp"
android:viewportHeight=
"20.0"
android:viewportWidth=
"20.0"
>
<path
android:fillColor=
"#FF000000"
android:pathData=
"M13.6,13.47c-0.91,0.953 -2.191,1.545 -3.61,1.545 -2.756,0 -4.99,-2.234 -4.99,-4.99 0,-0.009 0,-0.018 0,-0.026v0.001c0,-2.761 2.239,-5 5,-5 1.131,0 2.175,0.376 3.013,1.009l-0.013,-0.009v-1h2v6.5c0,0.828 0.672,1.5 1.5,1.5s1.5,-0.672 1.5,-1.5v0,-1.5c-0.003,-4.416 -3.584,-7.994 -8,-7.994 -4.418,0 -8,3.582 -8,8s3.582,8 8,8c1.305,0 2.537,-0.312 3.625,-0.867l-0.045,0.021 0.9,1.79c-1.305,0.668 -2.847,1.06 -4.48,1.06 -5.523,0 -10,-4.477 -10,-10s4.477,-10 10,-10c5.519,0 9.994,4.472 10,9.99v0.001h-0.01v1.5c0,0.003 0,0.007 0,0.01 0,1.933 -1.567,3.5 -3.5,3.5 -1.202,0 -2.262,-0.606 -2.892,-1.528l-0.008,-0.012zM10,13c1.657,0 3,-1.343 3,-3s-1.343,-3 -3,-3v0c-1.657,0 -3,1.343 -3,3s1.343,3 3,3v0z"
/>
</vector>
\ No newline at end of file
app/src/main/res/drawable/ic_room_lock.xml
0 → 100644
View file @
b7606345
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"16dp"
android:height=
"16dp"
android:viewportHeight=
"24.0"
android:viewportWidth=
"24.0"
>
<path
android:fillColor=
"#FF000000"
android:pathData=
"M18,10v-4c0,-3.313 -2.687,-6 -6,-6s-6,2.687 -6,6v4h-3v14h18v-14h-3zM8,6c0,-2.206 1.794,-4 4,-4s4,1.794 4,4v4h-8v-4zM19,22h-14v-10h14v10z"
/>
</vector>
\ No newline at end of file
app/src/main/res/drawable/message_reply_button_bg.xml
0 → 100644
View file @
b7606345
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:shape=
"rectangle"
>
<solid
android:color=
"@android:color/white"
/>
<corners
android:radius=
"4dp"
/>
<stroke
android:color=
"#1D74F5"
android:width=
"2dp"
/>
</shape>
\ No newline at end of file
app/src/main/res/layout/activity_chat_room.xml
View file @
b7606345
...
...
@@ -8,7 +8,7 @@
<include
android:id=
"@+id/layout_app_bar"
layout=
"@layout/app_bar"
/>
layout=
"@layout/app_bar
_chat_room
"
/>
<FrameLayout
android:id=
"@+id/fragment_container"
...
...
app/src/main/res/layout/app_bar_chat_room.xml
0 → 100644
View file @
b7606345
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
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:background=
"@color/colorPrimary"
android:theme=
"@style/Theme.AppCompat.Light.NoActionBar"
>
<android.support.v7.widget.Toolbar
android:id=
"@+id/toolbar"
android:layout_width=
"match_parent"
android:layout_height=
"?attr/actionBarSize"
app:layout_scrollFlags=
"scroll|enterAlways"
app:navigationIcon=
"?android:attr/homeAsUpIndicator"
app:popupTheme=
"@style/ThemeOverlay.AppCompat.Light"
app:theme=
"@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<android.support.constraint.ConstraintLayout
android:id=
"@+id/toolbar_content_container"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:orientation=
"horizontal"
>
<!-- TODO implement -->
<com.facebook.drawee.view.SimpleDraweeView
android:id=
"@+id/image_room_avatar"
android:layout_width=
"30dp"
android:layout_height=
"30dp"
android:visibility=
"gone"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
app:roundAsCircle=
"true"
/>
<TextView
android:id=
"@+id/text_room_name"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"10dp"
android:drawablePadding=
"@dimen/text_view_drawable_padding"
android:ellipsize=
"end"
android:maxLines=
"1"
android:textColor=
"@color/white"
android:textSize=
"18sp"
android:textStyle=
"bold"
tools:text=
"Developers"
/>
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
\ No newline at end of file
app/src/main/res/layout/item_message_reply.xml
0 → 100644
View file @
b7606345
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
android:id=
"@+id/message_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"?android:attr/selectableItemBackground"
android:clickable=
"true"
android:focusable=
"true"
android:paddingBottom=
"@dimen/message_item_top_and_bottom_padding"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_padding"
android:paddingStart=
"@dimen/screen_edge_left_and_right_padding"
android:paddingTop=
"@dimen/message_item_top_and_bottom_padding"
>
<Button
android:id=
"@+id/button_message_reply"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"2dp"
android:layout_marginTop=
"5dp"
android:layout_marginStart=
"56dp"
android:background=
"@drawable/message_reply_button_bg"
android:text=
"@string/action_msg_reply"
android:textAllCaps=
"false"
android:textColor=
"#1D74F5"
android:textSize=
"14sp"
app:layout_constraintLeft_toLeftOf=
"parent"
/>
<include
layout=
"@layout/layout_reactions"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
app:layout_constraintEnd_toEndOf=
"@+id/button_message_reply"
app:layout_constraintStart_toStartOf=
"@+id/button_message_reply"
app:layout_constraintTop_toBottomOf=
"@+id/button_message_reply"
/>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/test/java/chat/rocket/android/MemoryMessagesRepositoryTest.kt
deleted
100644 → 0
View file @
2fa3abb1
package
chat.rocket.android
import
chat.rocket.android.server.infraestructure.MemoryMessagesRepository
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.MessageType
import
kotlinx.coroutines.experimental.runBlocking
import
org.hamcrest.CoreMatchers.notNullValue
import
org.hamcrest.MatcherAssert.assertThat
import
org.junit.Before
import
org.junit.Test
import
org.hamcrest.CoreMatchers.`is`
as
isEqualTo
class
MemoryMessagesRepositoryTest
{
val
repository
=
MemoryMessagesRepository
()
val
msg
=
Message
(
id
=
"messageId"
,
roomId
=
"GENERAL"
,
message
=
"Beam me up, Scotty."
,
timestamp
=
1511443964815
,
attachments
=
null
,
sender
=
null
,
avatar
=
null
,
channels
=
null
,
editedAt
=
null
,
editedBy
=
null
,
groupable
=
true
,
mentions
=
null
,
parseUrls
=
false
,
senderAlias
=
null
,
type
=
MessageType
.
MessageRemoved
(),
updatedAt
=
1511443964815
,
urls
=
null
,
pinned
=
false
,
reactions
=
null
)
val
msg2
=
Message
(
id
=
"messageId2"
,
roomId
=
"sandbox"
,
message
=
"Highly Illogical"
,
timestamp
=
1511443964818
,
attachments
=
null
,
sender
=
null
,
avatar
=
null
,
channels
=
null
,
editedAt
=
null
,
editedBy
=
null
,
groupable
=
true
,
mentions
=
null
,
parseUrls
=
false
,
senderAlias
=
null
,
type
=
MessageType
.
MessageRemoved
(),
updatedAt
=
1511443964818
,
urls
=
null
,
pinned
=
false
,
reactions
=
null
)
@Before
fun
setup
()
{
runBlocking
{
repository
.
clear
()
}
}
@Test
fun
`
save
()
should
save
a
single
message
`
()
{
runBlocking
{
assertThat
(
repository
.
getAll
().
size
,
isEqualTo
(
0
))
repository
.
save
(
msg
)
val
allMessages
=
repository
.
getAll
()
assertThat
(
allMessages
.
size
,
isEqualTo
(
1
))
allMessages
[
0
].
apply
{
assertThat
(
id
,
isEqualTo
(
"messageId"
))
assertThat
(
message
,
isEqualTo
(
"Beam me up, Scotty."
))
assertThat
(
roomId
,
isEqualTo
(
"GENERAL"
))
}
}
}
@Test
fun
`
saveAll
()
should
all
saved
messages
`
()
{
runBlocking
{
assertThat
(
repository
.
getAll
().
size
,
isEqualTo
(
0
))
repository
.
saveAll
(
listOf
(
msg
,
msg2
))
val
allMessages
=
repository
.
getAll
()
assertThat
(
allMessages
.
size
,
isEqualTo
(
2
))
allMessages
[
0
].
apply
{
assertThat
(
id
,
isEqualTo
(
"messageId"
))
assertThat
(
message
,
isEqualTo
(
"Beam me up, Scotty."
))
assertThat
(
roomId
,
isEqualTo
(
"GENERAL"
))
}
allMessages
[
1
].
apply
{
assertThat
(
id
,
isEqualTo
(
"messageId2"
))
assertThat
(
message
,
isEqualTo
(
"Highly Illogical"
))
assertThat
(
roomId
,
isEqualTo
(
"sandbox"
))
}
}
}
@Test
fun
`
getById
()
should
return
a
single
message
`
()
{
runBlocking
{
repository
.
saveAll
(
listOf
(
msg
,
msg2
))
var
singleMsg
=
repository
.
getById
(
"messageId"
)
assertThat
(
singleMsg
,
notNullValue
())
singleMsg
!!
.
apply
{
assertThat
(
id
,
isEqualTo
(
"messageId"
))
assertThat
(
message
,
isEqualTo
(
"Beam me up, Scotty."
))
assertThat
(
roomId
,
isEqualTo
(
"GENERAL"
))
}
singleMsg
=
repository
.
getById
(
"messageId2"
)
assertThat
(
singleMsg
,
notNullValue
())
singleMsg
!!
.
apply
{
assertThat
(
id
,
isEqualTo
(
"messageId2"
))
assertThat
(
message
,
isEqualTo
(
"Highly Illogical"
))
assertThat
(
roomId
,
isEqualTo
(
"sandbox"
))
}
}
}
@Test
fun
`
getByRoomId
()
should
return
all
messages
for
room
id
or
an
empty
list
`
()
{
runBlocking
{
repository
.
saveAll
(
listOf
(
msg
,
msg2
))
var
roomMessages
=
repository
.
getByRoomId
(
"faAad32fkasods2"
)
assertThat
(
roomMessages
.
isEmpty
(),
isEqualTo
(
true
))
roomMessages
=
repository
.
getByRoomId
(
"sandbox"
)
assertThat
(
roomMessages
.
size
,
isEqualTo
(
1
))
roomMessages
[
0
].
apply
{
assertThat
(
id
,
isEqualTo
(
"messageId2"
))
assertThat
(
message
,
isEqualTo
(
"Highly Illogical"
))
assertThat
(
roomId
,
isEqualTo
(
"sandbox"
))
}
roomMessages
=
repository
.
getByRoomId
(
"GENERAL"
)
assertThat
(
roomMessages
.
size
,
isEqualTo
(
1
))
roomMessages
[
0
].
apply
{
assertThat
(
id
,
isEqualTo
(
"messageId"
))
assertThat
(
message
,
isEqualTo
(
"Beam me up, Scotty."
))
assertThat
(
roomId
,
isEqualTo
(
"GENERAL"
))
}
}
}
}
\ No newline at end of file
gradle/wrapper/gradle-wrapper.properties
View file @
b7606345
...
...
@@ -4,3 +4,4 @@ distributionPath=wrapper/dists
zipStoreBase
=
GRADLE_USER_HOME
zipStorePath
=
wrapper/dists
distributionUrl
=
https
\:
//services.gradle.org/distributions/gradle-4.6-all.zip
distributionSha256Sum
=
9af7345c199f1731c187c96d3fe3d31f5405192a42046bafa71d846c3d9adacb
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