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
a9085e1c
Commit
a9085e1c
authored
Feb 26, 2018
by
Leonardo Aramaki
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'release/2.0.0-beta7' into emoji-keyboard
parents
d87e13a3
5c44395b
Changes
35
Hide whitespace changes
Inline
Side-by-side
Showing
35 changed files
with
830 additions
and
462 deletions
+830
-462
build.gradle
app/build.gradle
+2
-2
AudioAttachmentViewHolder.kt
...ket/android/chatroom/adapter/AudioAttachmentViewHolder.kt
+27
-0
BaseViewHolder.kt
...va/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt
+15
-0
ChatRoomAdapter.kt
...a/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
+111
-0
ImageAttachmentViewHolder.kt
...ket/android/chatroom/adapter/ImageAttachmentViewHolder.kt
+22
-0
MessageViewHolder.kt
...chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
+78
-0
UrlPreviewViewHolder.kt
...t/rocket/android/chatroom/adapter/UrlPreviewViewHolder.kt
+30
-0
VideoAttachmentViewHolder.kt
...ket/android/chatroom/adapter/VideoAttachmentViewHolder.kt
+27
-0
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+19
-4
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+4
-4
PinnedMessagesPresenter.kt
.../android/chatroom/presentation/PinnedMessagesPresenter.kt
+5
-4
PinnedMessagesView.kt
...ocket/android/chatroom/presentation/PinnedMessagesView.kt
+2
-2
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+10
-8
PinnedMessagesAdapter.kt
.../chat/rocket/android/chatroom/ui/PinnedMessagesAdapter.kt
+0
-133
PinnedMessagesFragment.kt
...chat/rocket/android/chatroom/ui/PinnedMessagesFragment.kt
+7
-5
AudioAttachmentViewModel.kt
...et/android/chatroom/viewmodel/AudioAttachmentViewModel.kt
+17
-0
BaseFileAttachmentViewModel.kt
...android/chatroom/viewmodel/BaseFileAttachmentViewModel.kt
+7
-0
BaseMessageViewModel.kt
...rocket/android/chatroom/viewmodel/BaseMessageViewModel.kt
+9
-0
BaseViewModel.kt
...a/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
+25
-0
ImageAttachmentViewModel.kt
...et/android/chatroom/viewmodel/ImageAttachmentViewModel.kt
+17
-0
MessageViewModel.kt
...hat/rocket/android/chatroom/viewmodel/MessageViewModel.kt
+16
-230
MessageViewModelMapper.kt
...cket/android/chatroom/viewmodel/MessageViewModelMapper.kt
+0
-39
UrlPreviewViewModel.kt
.../rocket/android/chatroom/viewmodel/UrlPreviewViewModel.kt
+18
-0
VideoAttachmentViewModel.kt
...et/android/chatroom/viewmodel/VideoAttachmentViewModel.kt
+17
-0
ViewModelMapper.kt
...chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
+255
-0
ChatRoomsAdapter.kt
...java/chat/rocket/android/chatrooms/ui/ChatRoomsAdapter.kt
+27
-11
AppModule.kt
.../main/java/chat/rocket/android/dagger/module/AppModule.kt
+4
-0
MessageParser.kt
...src/main/java/chat/rocket/android/helper/MessageParser.kt
+1
-1
SettingsRepository.kt
...a/chat/rocket/android/server/domain/SettingsRepository.kt
+3
-1
Text.kt
...src/main/java/chat/rocket/android/util/extensions/Text.kt
+1
-1
item_chat.xml
app/src/main/res/layout/item_chat.xml
+0
-1
item_message.xml
app/src/main/res/layout/item_message.xml
+1
-11
message_attachment.xml
app/src/main/res/layout/message_attachment.xml
+6
-5
message_url_preview.xml
app/src/main/res/layout/message_url_preview.xml
+46
-0
colors.xml
app/src/main/res/values/colors.xml
+1
-0
No files found.
app/build.gradle
View file @
a9085e1c
...
...
@@ -12,8 +12,8 @@ android {
applicationId
"chat.rocket.android"
minSdkVersion
21
targetSdkVersion
versions
.
targetSdk
versionCode
100
8
versionName
"2.0.0-dev
6
"
versionCode
100
9
versionName
"2.0.0-dev
7
"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled
true
}
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/AudioAttachmentViewHolder.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.adapter
import
android.view.View
import
chat.rocket.android.chatroom.viewmodel.AudioAttachmentViewModel
import
chat.rocket.android.player.PlayerActivity
import
chat.rocket.android.util.extensions.setVisible
import
kotlinx.android.synthetic.main.message_attachment.view.*
class
AudioAttachmentViewHolder
(
itemView
:
View
)
:
BaseViewHolder
<
AudioAttachmentViewModel
>(
itemView
)
{
init
{
with
(
itemView
)
{
image_attachment
.
setVisible
(
false
)
audio_video_attachment
.
setVisible
(
true
)
}
}
override
fun
bindViews
(
data
:
AudioAttachmentViewModel
)
{
with
(
itemView
)
{
file_name
.
text
=
data
.
attachmentTitle
audio_video_attachment
.
setOnClickListener
{
view
->
data
.
attachmentUrl
.
let
{
url
->
PlayerActivity
.
play
(
view
.
context
,
url
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/BaseViewHolder.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.adapter
import
android.support.v7.widget.RecyclerView
import
android.view.View
abstract
class
BaseViewHolder
<
T
>(
itemView
:
View
)
:
RecyclerView
.
ViewHolder
(
itemView
)
{
var
data
:
T
?
=
null
fun
bind
(
data
:
T
)
{
this
.
data
=
data
bindViews
(
data
)
}
abstract
fun
bindViews
(
data
:
T
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.adapter
import
android.support.v7.widget.RecyclerView
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.util.extensions.inflate
import
timber.log.Timber
import
java.security.InvalidParameterException
class
ChatRoomAdapter
(
private
val
roomType
:
String
,
private
val
roomName
:
String
,
private
val
presenter
:
ChatRoomPresenter
?,
private
val
enableActions
:
Boolean
=
true
)
:
RecyclerView
.
Adapter
<
BaseViewHolder
<*>>()
{
private
val
dataSet
=
ArrayList
<
BaseViewModel
<*>>()
init
{
setHasStableIds
(
true
)
}
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
BaseViewHolder
<
*
>
{
return
when
(
viewType
.
toViewType
())
{
BaseViewModel
.
ViewType
.
MESSAGE
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
item_message
)
MessageViewHolder
(
view
,
roomName
,
roomType
,
presenter
,
enableActions
)
}
BaseViewModel
.
ViewType
.
IMAGE_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
ImageAttachmentViewHolder
(
view
)
}
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
AudioAttachmentViewHolder
(
view
)
}
BaseViewModel
.
ViewType
.
VIDEO_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
message_attachment
)
VideoAttachmentViewHolder
(
view
)
}
BaseViewModel
.
ViewType
.
URL_PREVIEW
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
message_url_preview
)
UrlPreviewViewHolder
(
view
)
}
else
->
{
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
}
}
}
override
fun
getItemViewType
(
position
:
Int
):
Int
{
return
dataSet
[
position
].
viewType
}
override
fun
getItemCount
():
Int
{
return
dataSet
.
size
}
override
fun
onBindViewHolder
(
holder
:
BaseViewHolder
<
*
>,
position
:
Int
)
{
when
(
holder
)
{
is
MessageViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageViewModel
)
is
ImageAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
ImageAttachmentViewModel
)
is
AudioAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
AudioAttachmentViewModel
)
is
VideoAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
VideoAttachmentViewModel
)
is
UrlPreviewViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
UrlPreviewViewModel
)
}
}
override
fun
getItemId
(
position
:
Int
):
Long
{
val
model
=
dataSet
[
position
]
return
when
(
model
)
{
is
MessageViewModel
->
model
.
messageId
.
hashCode
().
toLong
()
is
BaseFileAttachmentViewModel
->
model
.
id
else
->
return
position
.
toLong
()
}
}
fun
appendData
(
dataSet
:
List
<
BaseViewModel
<*
>>)
{
val
previousDataSetSize
=
this
.
dataSet
.
size
this
.
dataSet
.
addAll
(
dataSet
)
notifyItemChanged
(
previousDataSetSize
,
dataSet
.
size
)
}
fun
prependData
(
dataSet
:
List
<
BaseViewModel
<*
>>)
{
this
.
dataSet
.
addAll
(
0
,
dataSet
)
notifyItemRangeInserted
(
0
,
dataSet
.
size
)
}
fun
updateItem
(
message
:
BaseViewModel
<
*
>)
{
val
index
=
dataSet
.
indexOfLast
{
it
.
messageId
==
message
.
messageId
}
Timber
.
d
(
"index: $index"
)
if
(
index
>
-
1
)
{
dataSet
[
index
]
=
message
notifyItemChanged
(
index
)
}
}
fun
removeItem
(
messageId
:
String
)
{
val
index
=
dataSet
.
indexOfFirst
{
it
.
messageId
==
messageId
}
if
(
index
>
-
1
)
{
val
oldSize
=
dataSet
.
size
val
newSet
=
dataSet
.
filterNot
{
it
.
messageId
==
messageId
}
dataSet
.
clear
()
dataSet
.
addAll
(
newSet
)
val
newSize
=
dataSet
.
size
notifyItemRangeRemoved
(
index
,
oldSize
-
newSize
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/ImageAttachmentViewHolder.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.adapter
import
android.view.View
import
chat.rocket.android.chatroom.viewmodel.ImageAttachmentViewModel
import
com.stfalcon.frescoimageviewer.ImageViewer
import
kotlinx.android.synthetic.main.message_attachment.view.*
class
ImageAttachmentViewHolder
(
itemView
:
View
)
:
BaseViewHolder
<
ImageAttachmentViewModel
>(
itemView
)
{
override
fun
bindViews
(
data
:
ImageAttachmentViewModel
)
{
with
(
itemView
)
{
image_attachment
.
setImageURI
(
data
.
attachmentUrl
)
file_name
.
text
=
data
.
attachmentTitle
image_attachment
.
setOnClickListener
{
view
->
// TODO - implement a proper image viewer with a proper Transition
ImageViewer
.
Builder
(
view
.
context
,
listOf
(
data
.
attachmentUrl
))
.
setStartPosition
(
0
)
.
show
()
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.adapter
import
android.text.method.LinkMovementMethod
import
android.view.MenuItem
import
android.view.View
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.ui.bottomsheet.BottomSheetMenu
import
chat.rocket.android.chatroom.ui.bottomsheet.adapter.ActionListAdapter
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
kotlinx.android.synthetic.main.avatar.view.*
import
kotlinx.android.synthetic.main.item_message.view.*
import
ru.whalemare.sheetmenu.extension.inflate
import
ru.whalemare.sheetmenu.extension.toList
class
MessageViewHolder
(
itemView
:
View
,
private
val
roomType
:
String
,
private
val
roomName
:
String
,
private
val
presenter
:
ChatRoomPresenter
?,
enableActions
:
Boolean
)
:
BaseViewHolder
<
MessageViewModel
>(
itemView
),
MenuItem
.
OnMenuItemClickListener
{
init
{
itemView
.
text_content
.
movementMethod
=
LinkMovementMethod
()
if
(
enableActions
)
{
itemView
.
setOnLongClickListener
{
if
(
data
?.
isSystemMessage
==
false
)
{
val
menuItems
=
it
.
context
.
inflate
(
R
.
menu
.
message_actions
).
toList
()
menuItems
.
find
{
it
.
itemId
==
R
.
id
.
action_menu_msg_pin_unpin
}
?.
apply
{
val
isPinned
=
data
?.
isPinned
?:
false
setTitle
(
if
(
isPinned
)
R
.
string
.
action_msg_unpin
else
R
.
string
.
action_msg_pin
)
isChecked
=
isPinned
}
val
adapter
=
ActionListAdapter
(
menuItems
,
this
@MessageViewHolder
)
BottomSheetMenu
(
adapter
).
apply
{
}.
show
(
it
.
context
)
}
true
}
}
}
override
fun
bindViews
(
data
:
MessageViewModel
)
{
with
(
itemView
)
{
text_message_time
.
text
=
data
.
time
text_sender
.
text
=
data
.
senderName
text_content
.
text
=
data
.
content
image_avatar
.
setImageURI
(
data
.
avatar
)
}
}
override
fun
onMenuItemClick
(
item
:
MenuItem
):
Boolean
{
data
?.
rawData
?.
apply
{
when
(
item
.
itemId
)
{
R
.
id
.
action_menu_msg_delete
->
presenter
?.
deleteMessage
(
roomId
,
id
)
R
.
id
.
action_menu_msg_quote
->
presenter
?.
citeMessage
(
roomType
,
roomName
,
id
,
false
)
R
.
id
.
action_menu_msg_reply
->
presenter
?.
citeMessage
(
roomType
,
roomName
,
id
,
true
)
R
.
id
.
action_menu_msg_copy
->
presenter
?.
copyMessage
(
id
)
R
.
id
.
action_menu_msg_edit
->
presenter
?.
editMessage
(
roomId
,
id
,
message
)
R
.
id
.
action_menu_msg_pin_unpin
->
{
with
(
item
)
{
if
(!
isChecked
)
{
presenter
?.
pinMessage
(
id
)
}
else
{
presenter
?.
unpinMessage
(
id
)
}
}
}
else
->
TODO
(
"Not implemented"
)
}
}
return
true
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/UrlPreviewViewHolder.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.adapter
import
android.content.Intent
import
android.net.Uri
import
android.view.View
import
chat.rocket.android.chatroom.viewmodel.UrlPreviewViewModel
import
chat.rocket.android.util.extensions.content
import
chat.rocket.android.util.extensions.setVisible
import
kotlinx.android.synthetic.main.message_url_preview.view.*
class
UrlPreviewViewHolder
(
itemView
:
View
)
:
BaseViewHolder
<
UrlPreviewViewModel
>(
itemView
)
{
override
fun
bindViews
(
data
:
UrlPreviewViewModel
)
{
with
(
itemView
)
{
if
(
data
.
thumbUrl
.
isNullOrEmpty
())
{
image_preview
.
setVisible
(
false
)
}
else
{
image_preview
.
setImageURI
(
data
.
thumbUrl
)
image_preview
.
setVisible
(
true
)
}
text_host
.
content
=
data
.
hostname
text_title
.
content
=
data
.
title
text_description
.
content
=
data
.
description
?:
""
url_preview_layout
.
setOnClickListener
{
view
->
view
.
context
.
startActivity
(
Intent
(
Intent
.
ACTION_VIEW
,
Uri
.
parse
(
data
.
rawData
.
url
)))
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/VideoAttachmentViewHolder.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.adapter
import
android.view.View
import
chat.rocket.android.chatroom.viewmodel.VideoAttachmentViewModel
import
chat.rocket.android.player.PlayerActivity
import
chat.rocket.android.util.extensions.setVisible
import
kotlinx.android.synthetic.main.message_attachment.view.*
class
VideoAttachmentViewHolder
(
itemView
:
View
)
:
BaseViewHolder
<
VideoAttachmentViewModel
>(
itemView
)
{
init
{
with
(
itemView
)
{
image_attachment
.
setVisible
(
false
)
audio_video_attachment
.
setVisible
(
true
)
}
}
override
fun
bindViews
(
data
:
VideoAttachmentViewModel
)
{
with
(
itemView
)
{
file_name
.
text
=
data
.
attachmentTitle
audio_video_attachment
.
setOnClickListener
{
view
->
data
.
attachmentUrl
.
let
{
url
->
PlayerActivity
.
play
(
view
.
context
,
url
)
}
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
a9085e1c
...
...
@@ -3,7 +3,7 @@ package chat.rocket.android.chatroom.presentation
import
android.net.Uri
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.domain.UriInteractor
import
chat.rocket.android.chatroom.viewmodel.
Message
ViewModelMapper
import
chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
...
...
@@ -34,7 +34,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private
val
uriInteractor
:
UriInteractor
,
private
val
messagesRepository
:
MessagesRepository
,
factory
:
RocketChatClientFactory
,
private
val
mapper
:
Message
ViewModelMapper
)
{
private
val
mapper
:
ViewModelMapper
)
{
private
val
client
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
private
var
subId
:
String
?
=
null
private
var
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
!!
...
...
@@ -48,7 +48,11 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
client
.
messages
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
30
).
result
messagesRepository
.
saveAll
(
messages
)
val
messagesViewModels
=
mapper
.
mapToViewModelList
(
messages
,
settings
)
// TODO: For now we are marking the room as read if we can get the messages (I mean, no exception occurs)
// but should mark only when the user see the first unread message.
markRoomAsRead
(
chatRoomId
)
val
messagesViewModels
=
mapper
.
map
(
messages
)
view
.
showMessages
(
messagesViewModels
)
// Subscribe after getting the first page of messages from REST
...
...
@@ -127,6 +131,17 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
}
fun
markRoomAsRead
(
roomId
:
String
)
{
launchUI
(
strategy
)
{
try
{
client
.
markAsRead
(
roomId
)
}
catch
(
ex
:
RocketChatException
)
{
view
.
showMessage
(
ex
.
message
!!
)
// TODO Remove.
Timber
.
e
(
ex
)
// FIXME: Right now we are only catching the exception with Timber.
}
}
}
private
fun
subscribeMessages
(
roomId
:
String
)
{
client
.
addStateChannel
(
stateChannel
)
launch
(
CommonPool
+
strategy
.
jobs
)
{
...
...
@@ -315,7 +330,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private
fun
updateMessage
(
streamedMessage
:
Message
)
{
launchUI
(
strategy
)
{
val
viewModelStreamedMessage
=
mapper
.
map
ToViewModel
(
streamedMessage
,
settings
)
val
viewModelStreamedMessage
=
mapper
.
map
(
streamedMessage
)
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 @
a9085e1c
package
chat.rocket.android.chatroom.presentation
import
android.net.Uri
import
chat.rocket.android.chatroom.viewmodel.
Messag
eViewModel
import
chat.rocket.android.chatroom.viewmodel.
Bas
eViewModel
import
chat.rocket.android.core.behaviours.LoadingView
import
chat.rocket.android.core.behaviours.MessageView
...
...
@@ -12,7 +12,7 @@ interface ChatRoomView : LoadingView, MessageView {
*
* @param dataSet The data set to show.
*/
fun
showMessages
(
dataSet
:
List
<
MessageViewModel
>)
fun
showMessages
(
dataSet
:
List
<
BaseViewModel
<*
>
>)
/**
* Send a message to a chat room.
...
...
@@ -43,7 +43,7 @@ interface ChatRoomView : LoadingView, MessageView {
*
* @param message The (recent) message sent to a chat room.
*/
fun
showNewMessage
(
message
:
MessageViewModel
)
fun
showNewMessage
(
message
:
List
<
BaseViewModel
<*
>>
)
/**
* Dispatch to the recycler views adapter that we should remove a message.
...
...
@@ -57,7 +57,7 @@ interface ChatRoomView : LoadingView, MessageView {
*
* @param index The index of the changed message
*/
fun
dispatchUpdateMessage
(
index
:
Int
,
message
:
MessageViewModel
)
fun
dispatchUpdateMessage
(
index
:
Int
,
message
:
List
<
BaseViewModel
<*
>>
)
/**
* Show reply status above the message composer.
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/PinnedMessagesPresenter.kt
View file @
a9085e1c
package
chat.rocket.android.chatroom.presentation
import
chat.rocket.android.chatroom.viewmodel.MessageViewModelMapper
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.chatroom.viewmodel.ViewModelMapper
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.GetChatRoomsInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
...
...
@@ -18,7 +19,7 @@ class PinnedMessagesPresenter @Inject constructor(private val view: PinnedMessag
private
val
strategy
:
CancelStrategy
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
roomsInteractor
:
GetChatRoomsInteractor
,
private
val
mapper
:
Message
ViewModelMapper
,
private
val
mapper
:
ViewModelMapper
,
factory
:
RocketChatClientFactory
,
getSettingsInteractor
:
GetSettingsInteractor
)
{
...
...
@@ -41,8 +42,8 @@ class PinnedMessagesPresenter @Inject constructor(private val view: PinnedMessag
val
pinnedMessages
=
client
.
getRoomPinnedMessages
(
roomId
,
room
.
type
,
pinnedMessagesListOffset
)
pinnedMessagesListOffset
=
pinnedMessages
.
offset
.
toInt
()
val
messageList
=
mapper
.
map
ToViewModelList
(
pinnedMessages
.
result
,
settings
)
.
filterNot
{
it
.
isSystemMessage
}
val
messageList
=
mapper
.
map
(
pinnedMessages
.
result
)
.
filter
{
it
is
MessageViewModel
}.
filterNot
{
(
it
as
MessageViewModel
)
.
isSystemMessage
}
view
.
showPinnedMessages
(
messageList
)
view
.
hideLoading
()
}.
ifNull
{
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/PinnedMessagesView.kt
View file @
a9085e1c
package
chat.rocket.android.chatroom.presentation
import
chat.rocket.android.chatroom.viewmodel.
Messag
eViewModel
import
chat.rocket.android.chatroom.viewmodel.
Bas
eViewModel
import
chat.rocket.android.core.behaviours.LoadingView
import
chat.rocket.android.core.behaviours.MessageView
...
...
@@ -11,5 +11,5 @@ interface PinnedMessagesView : MessageView, LoadingView {
*
* @param pinnedMessages The list of pinned messages.
*/
fun
showPinnedMessages
(
pinnedMessages
:
List
<
MessageViewModel
>)
fun
showPinnedMessages
(
pinnedMessages
:
List
<
BaseViewModel
<*
>
>)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
a9085e1c
...
...
@@ -15,9 +15,10 @@ import android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.RecyclerView
import
android.view.*
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.presentation.ChatRoomView
import
chat.rocket.android.chatroom.viewmodel.
Messag
eViewModel
import
chat.rocket.android.chatroom.viewmodel.
Bas
eViewModel
import
chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.MessageParser
...
...
@@ -144,7 +145,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
return
true
}
override
fun
showMessages
(
dataSet
:
List
<
MessageViewModel
>)
{
override
fun
showMessages
(
dataSet
:
List
<
BaseViewModel
<*
>
>)
{
activity
?.
apply
{
if
(
recycler_view
.
adapter
==
null
)
{
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
presenter
)
...
...
@@ -161,9 +162,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
})
}
}
val
oldMessagesCount
=
adapter
.
itemCount
adapter
.
a
ddDataSet
(
dataSet
)
if
(
oldMessagesCount
==
0
&&
dataSet
.
size
>
0
)
{
adapter
.
a
ppendData
(
dataSet
)
if
(
oldMessagesCount
==
0
&&
dataSet
.
isNotEmpty
()
)
{
recycler_view
.
scrollToPosition
(
0
)
}
}
...
...
@@ -182,8 +184,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
override
fun
showInvalidFileMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_invalid_file
))
override
fun
showNewMessage
(
message
:
MessageViewModel
)
{
adapter
.
addItem
(
message
)
override
fun
showNewMessage
(
message
:
List
<
BaseViewModel
<*
>>
)
{
adapter
.
prependData
(
message
)
recycler_view
.
scrollToPosition
(
0
)
}
...
...
@@ -204,8 +206,8 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
actionSnackbar
.
dismiss
()
}
override
fun
dispatchUpdateMessage
(
index
:
Int
,
message
:
MessageViewModel
)
{
adapter
.
updateItem
(
message
)
override
fun
dispatchUpdateMessage
(
index
:
Int
,
message
:
List
<
BaseViewModel
<*
>>
)
{
adapter
.
updateItem
(
message
.
last
()
)
}
override
fun
dispatchDeleteMessage
(
msgId
:
String
)
{
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/PinnedMessagesAdapter.kt
deleted
100644 → 0
View file @
d87e13a3
package
chat.rocket.android.chatroom.ui
import
android.support.v7.widget.RecyclerView
import
android.text.method.LinkMovementMethod
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.AttachmentType
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.player.PlayerActivity
import
chat.rocket.android.util.extensions.content
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.setVisible
import
com.facebook.drawee.view.SimpleDraweeView
import
com.stfalcon.frescoimageviewer.ImageViewer
import
kotlinx.android.synthetic.main.avatar.view.*
import
kotlinx.android.synthetic.main.item_message.view.*
import
kotlinx.android.synthetic.main.message_attachment.view.*
class
PinnedMessagesAdapter
:
RecyclerView
.
Adapter
<
PinnedMessagesAdapter
.
ViewHolder
>()
{
init
{
setHasStableIds
(
true
)
}
val
dataSet
=
ArrayList
<
MessageViewModel
>()
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
ViewHolder
=
ViewHolder
(
parent
.
inflate
(
R
.
layout
.
item_message
))
override
fun
onBindViewHolder
(
holder
:
ViewHolder
,
position
:
Int
)
=
holder
.
bind
(
dataSet
[
position
])
override
fun
onBindViewHolder
(
holder
:
ViewHolder
,
position
:
Int
,
payloads
:
MutableList
<
Any
>?)
{
onBindViewHolder
(
holder
,
position
)
}
override
fun
getItemCount
():
Int
=
dataSet
.
size
override
fun
getItemViewType
(
position
:
Int
):
Int
=
position
fun
addDataSet
(
dataSet
:
List
<
MessageViewModel
>)
{
val
previousDataSetSize
=
this
.
dataSet
.
size
this
.
dataSet
.
addAll
(
previousDataSetSize
,
dataSet
)
notifyItemRangeInserted
(
previousDataSetSize
,
dataSet
.
size
)
}
fun
addItem
(
message
:
MessageViewModel
)
{
dataSet
.
add
(
0
,
message
)
notifyItemInserted
(
0
)
}
fun
updateItem
(
message
:
MessageViewModel
)
{
val
index
=
dataSet
.
indexOfFirst
{
it
.
id
==
message
.
id
}
if
(
index
>
-
1
)
{
dataSet
[
index
]
=
message
notifyItemChanged
(
index
)
}
}
fun
removeItem
(
messageId
:
String
)
{
val
index
=
dataSet
.
indexOfFirst
{
it
.
id
==
messageId
}
if
(
index
>
-
1
)
{
dataSet
.
removeAt
(
index
)
notifyItemRemoved
(
index
)
}
}
override
fun
getItemId
(
position
:
Int
):
Long
{
return
dataSet
[
position
].
id
.
hashCode
().
toLong
()
}
class
ViewHolder
(
itemView
:
View
)
:
RecyclerView
.
ViewHolder
(
itemView
)
{
private
lateinit
var
messageViewModel
:
MessageViewModel
fun
bind
(
message
:
MessageViewModel
)
=
with
(
itemView
)
{
messageViewModel
=
message
image_avatar
.
setImageURI
(
message
.
avatarUri
)
text_sender
.
content
=
message
.
senderName
text_message_time
.
content
=
message
.
time
text_content
.
content
=
message
.
content
text_content
.
movementMethod
=
LinkMovementMethod
()
bindAttachment
(
message
,
message_attachment
,
image_attachment
,
audio_video_attachment
,
file_name
)
}
private
fun
bindAttachment
(
message
:
MessageViewModel
,
attachment_container
:
View
,
image_attachment
:
SimpleDraweeView
,
audio_video_attachment
:
View
,
file_name
:
TextView
)
{
with
(
message
)
{
if
(
attachmentUrl
==
null
||
attachmentType
==
null
)
{
attachment_container
.
setVisible
(
false
)
return
}
var
imageVisible
=
false
var
videoVisible
=
false
attachment_container
.
setVisible
(
true
)
when
(
message
.
attachmentType
)
{
is
AttachmentType
.
Image
->
{
imageVisible
=
true
image_attachment
.
setImageURI
(
message
.
attachmentUrl
)
image_attachment
.
setOnClickListener
{
view
->
// TODO - implement a proper image viewer with a proper Transition
ImageViewer
.
Builder
(
view
.
context
,
listOf
(
message
.
attachmentUrl
))
.
setStartPosition
(
0
)
.
show
()
}
}
is
AttachmentType
.
Video
,
is
AttachmentType
.
Audio
->
{
videoVisible
=
true
audio_video_attachment
.
setOnClickListener
{
view
->
message
.
attachmentUrl
?.
let
{
url
->
PlayerActivity
.
play
(
view
.
context
,
url
)
}
}
}
}
image_attachment
.
setVisible
(
imageVisible
)
audio_video_attachment
.
setVisible
(
videoVisible
)
file_name
.
text
=
message
.
attachmentTitle
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/ui/PinnedMessagesFragment.kt
View file @
a9085e1c
...
...
@@ -9,9 +9,10 @@ import android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.ChatRoomAdapter
import
chat.rocket.android.chatroom.presentation.PinnedMessagesPresenter
import
chat.rocket.android.chatroom.presentation.PinnedMessagesView
import
chat.rocket.android.chatroom.viewmodel.
Messag
eViewModel
import
chat.rocket.android.chatroom.viewmodel.
Bas
eViewModel
import
chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.showToast
...
...
@@ -39,7 +40,7 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
private
lateinit
var
chatRoomId
:
String
private
lateinit
var
chatRoomName
:
String
private
lateinit
var
chatRoomType
:
String
private
lateinit
var
adapter
:
PinnedMessages
Adapter
private
lateinit
var
adapter
:
ChatRoom
Adapter
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
...
...
@@ -71,10 +72,11 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
showPinnedMessages
(
pinnedMessages
:
List
<
MessageViewModel
>)
{
override
fun
showPinnedMessages
(
pinnedMessages
:
List
<
BaseViewModel
<*
>
>)
{
activity
?.
apply
{
if
(
recycler_view_pinned
.
adapter
==
null
)
{
adapter
=
PinnedMessagesAdapter
()
// TODO - add a better constructor for this case...
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
null
,
false
)
recycler_view_pinned
.
adapter
=
adapter
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
false
)
recycler_view_pinned
.
layoutManager
=
linearLayoutManager
...
...
@@ -88,7 +90,7 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
}
}
adapter
.
a
ddDataSet
(
pinnedMessages
)
adapter
.
a
ppendData
(
pinnedMessages
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/AudioAttachmentViewModel.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.R
import
chat.rocket.core.model.attachment.AudioAttachment
data class
AudioAttachmentViewModel
(
override
val
rawData
:
AudioAttachment
,
override
val
messageId
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentTitle
:
CharSequence
,
override
val
id
:
Long
)
:
BaseFileAttachmentViewModel
<
AudioAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
message_attachment
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/BaseFileAttachmentViewModel.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
interface
BaseFileAttachmentViewModel
<
out
T
>
:
BaseViewModel
<
T
>
{
val
attachmentUrl
:
String
val
attachmentTitle
:
CharSequence
val
id
:
Long
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/BaseMessageViewModel.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
interface
BaseMessageViewModel
<
out
T
>
:
BaseViewModel
<
T
>
{
val
avatar
:
String
val
time
:
CharSequence
val
senderName
:
CharSequence
val
content
:
CharSequence
val
isPinned
:
Boolean
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
import
java.security.InvalidParameterException
interface
BaseViewModel
<
out
T
>
{
val
rawData
:
T
val
messageId
:
String
val
viewType
:
Int
val
layoutId
:
Int
enum
class
ViewType
(
val
viewType
:
Int
)
{
MESSAGE
(
0
),
SYSTEM_MESSAGE
(
1
),
URL_PREVIEW
(
2
),
IMAGE_ATTACHMENT
(
3
),
VIDEO_ATTACHMENT
(
4
),
AUDIO_ATTACHMENT
(
5
),
MESSAGE_ATTACHMENT
(
6
)
}
}
internal
fun
Int
.
toViewType
():
BaseViewModel
.
ViewType
{
return
BaseViewModel
.
ViewType
.
values
().
firstOrNull
{
it
.
viewType
==
this
}
?:
throw
InvalidParameterException
(
"Invalid viewType: $this for BaseViewModel.ViewType"
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ImageAttachmentViewModel.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.R
import
chat.rocket.core.model.attachment.ImageAttachment
data class
ImageAttachmentViewModel
(
override
val
rawData
:
ImageAttachment
,
override
val
messageId
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentTitle
:
CharSequence
,
override
val
id
:
Long
)
:
BaseFileAttachmentViewModel
<
ImageAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
IMAGE_ATTACHMENT
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
message_attachment
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/MessageViewModel.kt
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
import
DateTimeHelper
import
android.content.Context
import
android.graphics.Color
import
android.graphics.Typeface
import
android.text.SpannableString
import
android.text.SpannableStringBuilder
import
android.text.style.AbsoluteSizeSpan
import
android.text.style.ForegroundColorSpan
import
android.text.style.StyleSpan
import
chat.rocket.android.R
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.common.model.Token
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.url.Url
import
okhttp3.HttpUrl
data class
MessageViewModel
(
val
context
:
Context
,
private
val
token
:
Token
?,
private
val
message
:
Message
,
private
val
settings
:
Map
<
String
,
Value
<
Any
>>,
private
val
parser
:
MessageParser
,
private
val
messagesRepository
:
MessagesRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
currentServerRepository
:
CurrentServerRepository
)
{
val
id
:
String
=
message
.
id
val
avatarUri
:
String
?
val
roomId
:
String
=
message
.
roomId
val
time
:
CharSequence
val
senderName
:
CharSequence
val
content
:
CharSequence
var
quote
:
Message
?
=
null
var
urlsWithMeta
=
arrayListOf
<
Url
>()
var
attachmentUrl
:
String
?
=
null
var
attachmentTitle
:
CharSequence
?
=
null
var
attachmentType
:
AttachmentType
?
=
null
var
attachmentMessageText
:
String
?
=
null
var
attachmentMessageAuthor
:
String
?
=
null
var
attachmentMessageIcon
:
String
?
=
null
var
attachmentTimestamp
:
Long
?
=
null
var
isSystemMessage
:
Boolean
=
false
var
isPinned
:
Boolean
=
false
var
currentUsername
:
String
?
=
null
private
val
baseUrl
=
settings
.
get
(
SITE_URL
)
init
{
currentUsername
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
avatarUri
=
getUserAvatar
()
time
=
getTime
(
message
.
timestamp
)
senderName
=
getSender
()
isPinned
=
message
.
pinned
val
baseUrl
=
settings
.
get
(
SITE_URL
)
message
.
urls
?.
let
{
if
(
it
.
isEmpty
())
return
@let
for
(
url
in
it
)
{
if
(
url
.
meta
!=
null
)
{
urlsWithMeta
.
add
(
url
)
}
baseUrl
?.
let
{
val
quoteUrl
=
HttpUrl
.
parse
(
url
.
url
)
val
serverUrl
=
HttpUrl
.
parse
(
baseUrl
.
value
.
toString
())
if
(
quoteUrl
!=
null
&&
serverUrl
!=
null
)
{
makeQuote
(
quoteUrl
,
serverUrl
)
}
}
}
}
message
.
attachments
?.
let
{
attachments
->
val
attachment
=
attachments
.
firstOrNull
()
if
(
attachments
.
isEmpty
()
||
attachment
==
null
)
return
@let
when
(
attachment
)
{
is
FileAttachment
->
{
baseUrl
?.
let
{
attachmentUrl
=
attachmentUrl
(
"${baseUrl.value}${attachment.url}"
)
attachmentTitle
=
attachment
.
title
attachmentType
=
when
(
attachment
)
{
is
ImageAttachment
->
AttachmentType
.
Image
is
VideoAttachment
->
AttachmentType
.
Video
is
AudioAttachment
->
AttachmentType
.
Audio
else
->
null
}
}
}
is
MessageAttachment
->
{
attachmentType
=
AttachmentType
.
Message
attachmentMessageText
=
attachment
.
text
?:
""
attachmentMessageAuthor
=
attachment
.
author
?:
""
attachmentMessageIcon
=
attachment
.
icon
attachmentTimestamp
=
attachment
.
timestamp
}
}
}
content
=
getContent
(
context
)
}
private
fun
getUserAvatar
():
String
?
{
val
username
=
message
.
sender
?.
username
?:
"?"
return
baseUrl
?.
let
{
UrlHelper
.
getAvatarUrl
(
baseUrl
.
value
.
toString
(),
username
)
}
}
private
fun
getTime
(
timestamp
:
Long
)
=
DateTimeHelper
.
getTime
(
DateTimeHelper
.
getLocalDateTime
(
timestamp
))
private
fun
getSender
():
CharSequence
{
val
useRealName
=
settings
?.
get
(
USE_REALNAME
)
?.
value
as
Boolean
val
username
=
message
.
sender
?.
username
val
realName
=
message
.
sender
?.
name
val
senderName
=
if
(
useRealName
)
realName
else
username
return
senderName
?:
context
.
getString
(
R
.
string
.
msg_unknown
)
}
private
fun
makeQuote
(
quoteUrl
:
HttpUrl
,
serverUrl
:
HttpUrl
)
{
if
(
quoteUrl
.
host
()
==
serverUrl
.
host
())
{
val
msgIdToQuote
=
quoteUrl
.
queryParameter
(
"msg"
)
if
(
msgIdToQuote
!=
null
)
{
quote
=
messagesRepository
.
getById
(
msgIdToQuote
)
}
}
}
/**
* Get the original message as a String.
*/
fun
getOriginalMessage
()
=
message
.
message
private
fun
getContent
(
context
:
Context
):
CharSequence
{
val
contentMessage
:
CharSequence
when
(
message
.
type
)
{
//TODO: Add implementation for Welcome type.
is
MessageRemoved
->
contentMessage
=
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_removed
))
is
UserJoined
->
contentMessage
=
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_user_joined_channel
))
is
UserLeft
->
contentMessage
=
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_user_left
))
is
UserAdded
->
contentMessage
=
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_user_added_by
,
message
.
message
,
message
.
sender
?.
username
))
is
RoomNameChanged
->
contentMessage
=
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_room_name_changed
,
message
.
message
,
message
.
sender
?.
username
))
is
UserRemoved
->
contentMessage
=
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_user_removed_by
,
message
.
message
,
message
.
sender
?.
username
))
is
MessagePinned
->
contentMessage
=
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_pinned
))
else
->
contentMessage
=
getNormalMessage
()
}
return
contentMessage
}
private
fun
getNormalMessage
():
CharSequence
{
var
quoteViewModel
:
MessageViewModel
?
=
null
if
(
quote
!=
null
)
{
val
quoteMessage
:
Message
=
quote
!!
quoteViewModel
=
MessageViewModel
(
context
,
token
,
quoteMessage
,
settings
,
parser
,
messagesRepository
,
localRepository
,
currentServerRepository
)
}
return
parser
.
renderMarkdown
(
message
.
message
,
quoteViewModel
,
currentUsername
)
}
private
fun
getSystemMessage
(
content
:
String
):
CharSequence
{
isSystemMessage
=
true
val
spannableMsg
=
SpannableStringBuilder
(
content
)
spannableMsg
.
setSpan
(
StyleSpan
(
Typeface
.
ITALIC
),
0
,
spannableMsg
.
length
,
0
)
spannableMsg
.
setSpan
(
ForegroundColorSpan
(
Color
.
GRAY
),
0
,
spannableMsg
.
length
,
0
)
if
(
attachmentType
==
null
)
{
val
username
=
message
.
sender
?.
username
val
message
=
message
.
message
val
usernameTextStartIndex
=
if
(
username
!=
null
)
content
.
indexOf
(
username
)
else
-
1
val
usernameTextEndIndex
=
if
(
username
!=
null
)
usernameTextStartIndex
+
username
.
length
else
-
1
val
messageTextStartIndex
=
if
(
message
.
isNotEmpty
())
content
.
indexOf
(
message
)
else
-
1
val
messageTextEndIndex
=
messageTextStartIndex
+
message
.
length
if
(
usernameTextStartIndex
>
-
1
)
{
spannableMsg
.
setSpan
(
StyleSpan
(
Typeface
.
BOLD_ITALIC
),
usernameTextStartIndex
,
usernameTextEndIndex
,
0
)
}
if
(
messageTextStartIndex
>
-
1
)
{
spannableMsg
.
setSpan
(
StyleSpan
(
Typeface
.
BOLD_ITALIC
),
messageTextStartIndex
,
messageTextEndIndex
,
0
)
}
}
else
if
(
attachmentType
==
AttachmentType
.
Message
)
{
spannableMsg
.
append
(
quoteMessage
(
attachmentMessageAuthor
!!
,
attachmentMessageText
!!
,
attachmentTimestamp
!!
))
}
return
spannableMsg
}
private
fun
quoteMessage
(
author
:
String
,
text
:
String
,
timestamp
:
Long
):
CharSequence
{
return
SpannableStringBuilder
().
apply
{
val
header
=
"\n$author ${getTime(timestamp)}\n"
append
(
SpannableString
(
header
).
apply
{
setSpan
(
StyleSpan
(
Typeface
.
BOLD
),
1
,
author
.
length
+
1
,
0
)
setSpan
(
MessageParser
.
QuoteMarginSpan
(
context
.
getDrawable
(
R
.
drawable
.
quote
),
10
),
1
,
length
,
0
)
setSpan
(
AbsoluteSizeSpan
(
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
message_time_text_size
)),
author
.
length
+
1
,
length
,
0
)
})
append
(
SpannableString
(
parser
.
renderMarkdown
(
text
)).
apply
{
setSpan
(
MessageParser
.
QuoteMarginSpan
(
context
.
getDrawable
(
R
.
drawable
.
quote
),
10
),
0
,
length
,
0
)
})
}
}
private
fun
attachmentUrl
(
url
:
String
):
String
{
var
response
=
url
val
httpUrl
=
HttpUrl
.
parse
(
url
)
httpUrl
?.
let
{
response
=
it
.
newBuilder
().
apply
{
addQueryParameter
(
"rc_uid"
,
token
?.
userId
)
addQueryParameter
(
"rc_token"
,
token
?.
authToken
)
}.
build
().
toString
()
}
return
response
}
}
sealed
class
AttachmentType
{
object
Image
:
AttachmentType
()
object
Video
:
AttachmentType
()
object
Audio
:
AttachmentType
()
object
Message
:
AttachmentType
()
}
data class
MessageViewModel
(
override
val
rawData
:
Message
,
override
val
messageId
:
String
,
override
val
avatar
:
String
,
override
val
time
:
CharSequence
,
override
val
senderName
:
CharSequence
,
override
val
content
:
CharSequence
,
override
val
isPinned
:
Boolean
,
val
isSystemMessage
:
Boolean
)
:
BaseMessageViewModel
<
Message
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
MESSAGE
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
item_message
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/MessageViewModelMapper.kt
deleted
100644 → 0
View file @
d87e13a3
package
chat.rocket.android.chatroom.viewmodel
import
android.content.Context
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.CurrentServerRepository
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.core.TokenRepository
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Value
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.withContext
import
javax.inject.Inject
class
MessageViewModelMapper
@Inject
constructor
(
private
val
context
:
Context
,
private
val
tokenRepository
:
TokenRepository
,
private
val
messageParser
:
MessageParser
,
private
val
messagesRepository
:
MessagesRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
currentServerRepository
:
CurrentServerRepository
)
{
suspend
fun
mapToViewModel
(
message
:
Message
,
settings
:
Map
<
String
,
Value
<
Any
>>):
MessageViewModel
=
withContext
(
CommonPool
)
{
MessageViewModel
(
this
@MessageViewModelMapper
.
context
,
tokenRepository
.
get
(),
message
,
settings
,
messageParser
,
messagesRepository
,
localRepository
,
currentServerRepository
)
}
suspend
fun
mapToViewModelList
(
messageList
:
List
<
Message
>,
settings
:
Map
<
String
,
Value
<
Any
>>):
List
<
MessageViewModel
>
{
return
messageList
.
map
{
MessageViewModel
(
context
,
tokenRepository
.
get
(),
it
,
settings
,
messageParser
,
messagesRepository
,
localRepository
,
currentServerRepository
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/UrlPreviewViewModel.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.R
import
chat.rocket.core.model.url.Url
data class
UrlPreviewViewModel
(
override
val
rawData
:
Url
,
override
val
messageId
:
String
,
val
title
:
CharSequence
?,
val
hostname
:
String
,
val
description
:
CharSequence
?,
val
thumbUrl
:
String
?
)
:
BaseViewModel
<
Url
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
URL_PREVIEW
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
message_url_preview
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/VideoAttachmentViewModel.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.R
import
chat.rocket.core.model.attachment.VideoAttachment
data class
VideoAttachmentViewModel
(
override
val
rawData
:
VideoAttachment
,
override
val
messageId
:
String
,
override
val
attachmentUrl
:
String
,
override
val
attachmentTitle
:
CharSequence
,
override
val
id
:
Long
)
:
BaseFileAttachmentViewModel
<
VideoAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
VIDEO_ATTACHMENT
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
message_attachment
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
0 → 100644
View file @
a9085e1c
package
chat.rocket.android.chatroom.viewmodel
import
DateTimeHelper
import
android.content.Context
import
android.graphics.Color
import
android.graphics.Typeface
import
android.text.SpannableString
import
android.text.SpannableStringBuilder
import
android.text.style.AbsoluteSizeSpan
import
android.text.style.ForegroundColorSpan
import
android.text.style.StyleSpan
import
chat.rocket.android.R
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.core.TokenRepository
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.url.Url
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.withContext
import
okhttp3.HttpUrl
import
timber.log.Timber
import
javax.inject.Inject
class
ViewModelMapper
@Inject
constructor
(
private
val
context
:
Context
,
private
val
parser
:
MessageParser
,
private
val
messagesRepository
:
MessagesRepository
,
tokenRepository
:
TokenRepository
,
localRepository
:
LocalRepository
,
serverInteractor
:
GetCurrentServerInteractor
,
getSettingsInteractor
:
GetSettingsInteractor
)
{
private
var
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
!!
private
val
baseUrl
=
settings
.
baseUrl
()
private
val
currentUsername
:
String
?
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
private
val
token
=
tokenRepository
.
get
()
suspend
fun
map
(
message
:
Message
):
List
<
BaseViewModel
<*
>>
{
return
translate
(
message
)
}
suspend
fun
map
(
messages
:
List
<
Message
>):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
val
list
=
ArrayList
<
BaseViewModel
<*>>(
messages
.
size
)
messages
.
forEach
{
list
.
addAll
(
translate
(
it
))
}
return
@withContext
list
}
private
suspend
fun
translate
(
message
:
Message
):
List
<
BaseViewModel
<*
>>
=
withContext
(
CommonPool
)
{
val
list
=
ArrayList
<
BaseViewModel
<*>>()
message
.
urls
?.
forEach
{
val
url
=
mapUrl
(
message
,
it
)
url
?.
let
{
list
.
add
(
url
)
}
}
message
.
attachments
?.
forEach
{
val
attachment
=
mapAttachment
(
message
,
it
)
attachment
?.
let
{
list
.
add
(
attachment
)
}
}
mapMessage
(
message
).
let
{
list
.
add
(
it
)
}
return
@withContext
list
}
private
fun
mapUrl
(
message
:
Message
,
url
:
Url
):
BaseViewModel
<
*
>?
{
if
(
url
.
ignoreParse
||
url
.
meta
==
null
)
return
null
val
hostname
=
url
.
parsedUrl
?.
hostname
?:
""
val
thumb
=
url
.
meta
?.
imageUrl
val
title
=
url
.
meta
?.
title
val
description
=
url
.
meta
?.
description
return
UrlPreviewViewModel
(
url
,
message
.
id
,
title
,
hostname
,
description
,
thumb
)
}
private
fun
mapAttachment
(
message
:
Message
,
attachment
:
Attachment
):
BaseViewModel
<
*
>?
{
return
when
(
attachment
)
{
is
FileAttachment
->
mapFileAttachment
(
message
,
attachment
)
else
->
null
}
}
private
fun
mapFileAttachment
(
message
:
Message
,
attachment
:
FileAttachment
):
BaseViewModel
<
*
>?
{
val
attachmentUrl
=
attachmentUrl
(
"$baseUrl${attachment.url}"
)
val
attachmentTitle
=
attachment
.
title
val
id
=
"${message.id}_${attachment.titleLink}"
.
hashCode
().
toLong
()
return
when
(
attachment
)
{
is
ImageAttachment
->
ImageAttachmentViewModel
(
attachment
,
message
.
id
,
attachmentUrl
,
attachmentTitle
?:
""
,
id
)
is
VideoAttachment
->
VideoAttachmentViewModel
(
attachment
,
message
.
id
,
attachmentUrl
,
attachmentTitle
?:
""
,
id
)
is
AudioAttachment
->
AudioAttachmentViewModel
(
attachment
,
message
.
id
,
attachmentUrl
,
attachmentTitle
?:
""
,
id
)
else
->
null
}
}
private
fun
attachmentUrl
(
url
:
String
):
String
{
var
response
=
url
val
httpUrl
=
HttpUrl
.
parse
(
url
)
httpUrl
?.
let
{
response
=
it
.
newBuilder
().
apply
{
addQueryParameter
(
"rc_uid"
,
token
?.
userId
)
addQueryParameter
(
"rc_token"
,
token
?.
authToken
)
}.
build
().
toString
()
}
return
response
}
private
suspend
fun
mapMessage
(
message
:
Message
):
MessageViewModel
=
withContext
(
CommonPool
)
{
val
sender
=
getSenderName
(
message
)
val
time
=
getTime
(
message
.
timestamp
)
val
avatar
=
getUserAvatar
(
message
)
val
baseUrl
=
settings
.
baseUrl
()
var
quote
:
Message
?
=
null
val
urls
=
ArrayList
<
Url
>()
message
.
urls
?.
let
{
if
(
it
.
isEmpty
())
return
@let
for
(
url
in
it
)
{
urls
.
add
(
url
)
baseUrl
?.
let
{
val
quoteUrl
=
HttpUrl
.
parse
(
url
.
url
)
val
serverUrl
=
HttpUrl
.
parse
(
baseUrl
)
if
(
quoteUrl
!=
null
&&
serverUrl
!=
null
)
{
quote
=
makeQuote
(
quoteUrl
,
serverUrl
)
}
}
}
}
val
content
=
getContent
(
context
,
message
,
quote
)
MessageViewModel
(
rawData
=
message
,
messageId
=
message
.
id
,
avatar
=
avatar
!!
,
time
=
time
,
senderName
=
sender
,
content
=
content
.
first
,
isPinned
=
message
.
pinned
,
isSystemMessage
=
content
.
second
)
}
private
fun
getSenderName
(
message
:
Message
):
CharSequence
{
val
username
=
message
.
sender
?.
username
val
realName
=
message
.
sender
?.
name
val
senderName
=
if
(
settings
.
useRealName
())
realName
else
username
return
senderName
?:
username
.
toString
()
}
private
fun
getUserAvatar
(
message
:
Message
):
String
?
{
val
username
=
message
.
sender
?.
username
?:
"?"
return
baseUrl
?.
let
{
UrlHelper
.
getAvatarUrl
(
baseUrl
,
username
)
}
}
private
fun
getTime
(
timestamp
:
Long
)
=
DateTimeHelper
.
getTime
(
DateTimeHelper
.
getLocalDateTime
(
timestamp
))
private
fun
makeQuote
(
quoteUrl
:
HttpUrl
,
serverUrl
:
HttpUrl
):
Message
?
{
if
(
quoteUrl
.
host
()
==
serverUrl
.
host
())
{
val
msgIdToQuote
=
quoteUrl
.
queryParameter
(
"msg"
)
Timber
.
d
(
"Will quote message Id: $msgIdToQuote"
)
return
if
(
msgIdToQuote
!=
null
)
messagesRepository
.
getById
(
msgIdToQuote
)
else
null
}
return
null
}
private
suspend
fun
getContent
(
context
:
Context
,
message
:
Message
,
quote
:
Message
?):
Pair
<
CharSequence
,
Boolean
>
{
var
systemMessage
=
true
val
content
=
when
(
message
.
type
)
{
//TODO: Add implementation for Welcome type.
is
MessageType
.
MessageRemoved
->
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_removed
))
is
MessageType
.
UserJoined
->
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_user_joined_channel
))
is
MessageType
.
UserLeft
->
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_user_left
))
is
MessageType
.
UserAdded
->
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_user_added_by
,
message
.
message
,
message
.
sender
?.
username
))
is
MessageType
.
RoomNameChanged
->
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_room_name_changed
,
message
.
message
,
message
.
sender
?.
username
))
is
MessageType
.
UserRemoved
->
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_user_removed_by
,
message
.
message
,
message
.
sender
?.
username
))
is
MessageType
.
MessagePinned
->
getSystemMessage
(
context
.
getString
(
R
.
string
.
message_pinned
))
else
->
{
systemMessage
=
false
getNormalMessage
(
message
,
quote
)
}
}
return
Pair
(
content
,
systemMessage
)
}
private
suspend
fun
getNormalMessage
(
message
:
Message
,
quote
:
Message
?):
CharSequence
{
var
quoteViewModel
:
MessageViewModel
?
=
null
if
(
quote
!=
null
)
{
val
quoteMessage
:
Message
=
quote
quoteViewModel
=
map
(
quoteMessage
).
first
{
it
is
MessageViewModel
}
as
MessageViewModel
}
return
parser
.
renderMarkdown
(
message
.
message
,
quoteViewModel
,
currentUsername
)
}
private
fun
getSystemMessage
(
content
:
String
):
CharSequence
{
//isSystemMessage = true
val
spannableMsg
=
SpannableStringBuilder
(
content
)
spannableMsg
.
setSpan
(
StyleSpan
(
Typeface
.
ITALIC
),
0
,
spannableMsg
.
length
,
0
)
spannableMsg
.
setSpan
(
ForegroundColorSpan
(
Color
.
GRAY
),
0
,
spannableMsg
.
length
,
0
)
/*if (attachmentType == null) {
val username = message.sender?.username
val message = message.message
val usernameTextStartIndex = if (username != null) content.indexOf(username) else -1
val usernameTextEndIndex = if (username != null) usernameTextStartIndex + username.length else -1
val messageTextStartIndex = if (message.isNotEmpty()) content.indexOf(message) else -1
val messageTextEndIndex = messageTextStartIndex + message.length
if (usernameTextStartIndex > -1) {
spannableMsg.setSpan(StyleSpan(Typeface.BOLD_ITALIC), usernameTextStartIndex, usernameTextEndIndex,
0)
}
if (messageTextStartIndex > -1) {
spannableMsg.setSpan(StyleSpan(Typeface.BOLD_ITALIC), messageTextStartIndex, messageTextEndIndex,
0)
}
} else if (attachmentType == AttachmentType.Message) {
spannableMsg.append(quoteMessage(attachmentMessageAuthor!!, attachmentMessageText!!, attachmentTimestamp!!))
}*/
return
spannableMsg
}
private
fun
quoteMessage
(
author
:
String
,
text
:
String
,
timestamp
:
Long
):
CharSequence
{
return
SpannableStringBuilder
().
apply
{
val
header
=
"\n$author ${getTime(timestamp)}\n"
append
(
SpannableString
(
header
).
apply
{
setSpan
(
StyleSpan
(
Typeface
.
BOLD
),
1
,
author
.
length
+
1
,
0
)
setSpan
(
MessageParser
.
QuoteMarginSpan
(
context
.
getDrawable
(
R
.
drawable
.
quote
),
10
),
1
,
length
,
0
)
setSpan
(
AbsoluteSizeSpan
(
context
.
resources
.
getDimensionPixelSize
(
R
.
dimen
.
message_time_text_size
)),
author
.
length
+
1
,
length
,
0
)
})
append
(
SpannableString
(
parser
.
renderMarkdown
(
text
)).
apply
{
setSpan
(
MessageParser
.
QuoteMarginSpan
(
context
.
getDrawable
(
R
.
drawable
.
quote
),
10
),
0
,
length
,
0
)
})
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsAdapter.kt
View file @
a9085e1c
...
...
@@ -2,16 +2,18 @@ package chat.rocket.android.chatrooms.ui
import
DateTimeHelper
import
android.content.Context
import
android.support.v4.content.
res.Resources
Compat
import
android.support.v4.content.
Context
Compat
import
android.support.v7.widget.RecyclerView
import
android.view.View
import
android.view.ViewGroup
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.util.extensions.content
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.textContent
import
chat.rocket.common.model.RoomType
import
chat.rocket.core.model.ChatRoom
import
com.facebook.drawee.view.SimpleDraweeView
import
kotlinx.android.synthetic.main.avatar.view.*
...
...
@@ -28,8 +30,6 @@ class ChatRoomsAdapter(private val context: Context,
override
fun
getItemCount
():
Int
=
dataSet
.
size
override
fun
getItemViewType
(
position
:
Int
):
Int
=
position
fun
updateRooms
(
newRooms
:
List
<
ChatRoom
>)
{
dataSet
.
clear
()
dataSet
.
addAll
(
newRooms
)
...
...
@@ -45,27 +45,40 @@ class ChatRoomsAdapter(private val context: Context,
bindUnreadMessages
(
chatRoom
,
text_total_unread_messages
)
if
(
chatRoom
.
alert
||
chatRoom
.
unread
>
0
)
{
text_chat_name
.
alpha
=
1F
text_last_message_date_time
.
setTextColor
(
ResourcesCompat
.
getColor
(
resources
,
R
.
color
.
colorAccent
,
null
))
text_last_message
.
setTextColor
(
ResourcesCompat
.
getColor
(
resources
,
android
.
R
.
color
.
primary_text_light
,
null
))
text_chat_name
.
setTextColor
(
ContextCompat
.
getColor
(
context
,
R
.
color
.
colorPrimaryText
))
text_last_message_date_time
.
setTextColor
(
ContextCompat
.
getColor
(
context
,
R
.
color
.
colorAccent
))
text_last_message
.
setTextColor
(
ContextCompat
.
getColor
(
context
,
android
.
R
.
color
.
primary_text_light
))
}
else
{
text_chat_name
.
setTextColor
(
ContextCompat
.
getColor
(
context
,
R
.
color
.
colorSecondaryText
))
text_last_message_date_time
.
setTextColor
(
ContextCompat
.
getColor
(
context
,
R
.
color
.
colorSecondaryText
))
text_last_message
.
setTextColor
(
ContextCompat
.
getColor
(
context
,
R
.
color
.
colorSecondaryText
))
}
setOnClickListener
{
listener
(
chatRoom
)
}
}
private
fun
bindAvatar
(
chatRoom
:
ChatRoom
,
drawee
:
SimpleDraweeView
)
{
drawee
.
setImageURI
(
UrlHelper
.
getAvatarUrl
(
chatRoom
.
client
.
url
,
chatRoom
.
name
))
val
avatarId
=
if
(
chatRoom
.
type
is
RoomType
.
DirectMessage
)
chatRoom
.
name
else
"@${chatRoom.name}"
drawee
.
setImageURI
(
UrlHelper
.
getAvatarUrl
(
chatRoom
.
client
.
url
,
avatarId
))
}
private
fun
bindName
(
chatRoom
:
ChatRoom
,
textView
:
TextView
)
{
textView
.
textC
ontent
=
chatRoom
.
name
textView
.
c
ontent
=
chatRoom
.
name
}
private
fun
bindLastMessageDateTime
(
chatRoom
:
ChatRoom
,
textView
:
TextView
)
{
val
lastMessage
=
chatRoom
.
lastMessage
if
(
lastMessage
!=
null
)
{
val
localDateTime
=
DateTimeHelper
.
getLocalDateTime
(
lastMessage
.
timestamp
)
textView
.
textContent
=
DateTimeHelper
.
getDate
(
localDateTime
,
context
)
textView
.
content
=
DateTimeHelper
.
getDate
(
localDateTime
,
context
)
}
else
{
textView
.
content
=
""
}
}
...
...
@@ -77,16 +90,18 @@ class ChatRoomsAdapter(private val context: Context,
val
senderUsername
=
lastMessageSender
.
username
when
(
senderUsername
)
{
chatRoom
.
name
->
{
textView
.
textC
ontent
=
message
textView
.
c
ontent
=
message
}
// TODO Change to MySelf
// chatRoom.user?.username -> {
// holder.lastMessage.textContent = context.getString(R.string.msg_you) + ": $message"
// }
else
->
{
textView
.
textC
ontent
=
"@$senderUsername: $message"
textView
.
c
ontent
=
"@$senderUsername: $message"
}
}
}
else
{
textView
.
content
=
""
}
}
...
...
@@ -101,6 +116,7 @@ class ChatRoomsAdapter(private val context: Context,
textView
.
textContent
=
context
.
getString
(
R
.
string
.
msg_more_than_ninety_nine_unread_messages
)
textView
.
setVisible
(
true
)
}
else
->
textView
.
setVisible
(
false
)
}
}
}
...
...
app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt
View file @
a9085e1c
...
...
@@ -39,6 +39,7 @@ import ru.noties.markwon.il.AsyncDrawableLoader
import
ru.noties.markwon.spans.SpannableTheme
import
timber.log.Timber
import
java.util.concurrent.Executors
import
java.util.concurrent.TimeUnit
import
javax.inject.Singleton
@Module
...
...
@@ -101,6 +102,9 @@ class AppModule {
fun
provideOkHttpClient
(
logger
:
HttpLoggingInterceptor
):
OkHttpClient
{
return
OkHttpClient
.
Builder
().
apply
{
addInterceptor
(
logger
)
connectTimeout
(
15
,
TimeUnit
.
SECONDS
)
readTimeout
(
20
,
TimeUnit
.
SECONDS
)
writeTimeout
(
15
,
TimeUnit
.
SECONDS
)
}.
build
()
}
...
...
app/src/main/java/chat/rocket/android/helper/MessageParser.kt
View file @
a9085e1c
...
...
@@ -56,7 +56,7 @@ class MessageParser @Inject constructor(val context: Application, private val co
var
quoteNode
=
parser
.
parse
(
"> $senderName $time"
)
parentNode
.
appendChild
(
quoteNode
)
quoteNode
.
accept
(
QuoteMessageSenderVisitor
(
context
,
configuration
,
builder
,
senderName
.
length
))
quoteNode
=
parser
.
parse
(
"> ${toLenientMarkdown(quote.
getOriginalMessage()
)}"
)
quoteNode
=
parser
.
parse
(
"> ${toLenientMarkdown(quote.
rawData.message
)}"
)
quoteNode
.
accept
(
QuoteMessageBodyVisitor
(
context
,
configuration
,
builder
))
}
parentNode
.
accept
(
LinkVisitor
(
builder
))
...
...
app/src/main/java/chat/rocket/android/server/domain/SettingsRepository.kt
View file @
a9085e1c
...
...
@@ -82,4 +82,6 @@ fun Map<String, Value<Any>>.uploadMimeTypeFilter(): Array<String> {
fun
Map
<
String
,
Value
<
Any
>>.
uploadMaxFileSize
():
Int
{
return
this
[
UPLOAD_MAX_FILE_SIZE
]
?.
value
?.
let
{
it
as
Int
}
?:
Int
.
MAX_VALUE
}
\ No newline at end of file
}
fun
Map
<
String
,
Value
<
Any
>>.
baseUrl
()
:
String
?
=
this
[
SITE_URL
]
?.
value
as
String
\ No newline at end of file
app/src/main/java/chat/rocket/android/util/extensions/Text.kt
View file @
a9085e1c
...
...
@@ -43,7 +43,7 @@ var TextView.hintContent: String
hint
=
value
}
var
TextView
.
content
:
CharSequence
var
TextView
.
content
:
CharSequence
?
get
()
=
text
set
(
value
)
{
Markwon
.
unscheduleDrawables
(
this
)
...
...
app/src/main/res/layout/item_chat.xml
View file @
a9085e1c
...
...
@@ -31,7 +31,6 @@
style=
"@style/ChatRoom.Name.TextView"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:alpha=
"0.6"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toLeftOf=
"@+id/text_last_message_date_time"
app:layout_constraintTop_toTopOf=
"parent"
...
...
app/src/main/res/layout/item_message.xml
View file @
a9085e1c
...
...
@@ -48,20 +48,10 @@
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"5dp"
android:layout_marginBottom=
"2dp"
app:layout_constraintLeft_toLeftOf=
"@id/top_container"
app:layout_constraintRight_toRightOf=
"parent"
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!"
/>
<!-- TODO - Use separate adapter items for messages and attachments. -->
<include
android:id=
"@+id/message_attachment"
layout=
"@layout/message_attachment"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"4dp"
app:layout_constraintLeft_toLeftOf=
"@id/top_container"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/text_content"
/>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/layout/message_attachment.xml
View file @
a9085e1c
...
...
@@ -5,16 +5,17 @@
android:id=
"@+id/attachment_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"72dp"
android:layout_marginEnd=
"@dimen/screen_edge_left_and_right_margins"
android:orientation=
"vertical"
>
<com.facebook.drawee.view.SimpleDraweeView
android:id=
"@+id/image_attachment"
android:layout_width=
"match_parent"
android:layout_height=
"150dp"
android:visibility=
"gone"
fresco:actualImageScaleType=
"fitStart"
fresco:placeholderImage=
"@drawable/image_dummy"
tools:visibility=
"visible"
/>
android:visibility=
"visible"
fresco:actualImageScaleType=
"centerCrop"
fresco:placeholderImage=
"@drawable/image_dummy"
/>
<FrameLayout
android:id=
"@+id/audio_video_attachment"
...
...
@@ -22,7 +23,7 @@
android:layout_height=
"150dp"
android:background=
"@color/black"
android:visibility=
"gone"
tools:visibility=
"
gon
e"
>
tools:visibility=
"
visibl
e"
>
<ImageView
android:layout_width=
"wrap_content"
...
...
app/src/main/res/layout/message_url_preview.xml
0 → 100644
View file @
a9085e1c
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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"
android:id=
"@+id/url_preview_layout"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"72dp"
android:layout_marginEnd=
"24dp"
>
<com.facebook.drawee.view.SimpleDraweeView
android:id=
"@+id/image_preview"
android:layout_width=
"70dp"
android:layout_height=
"50dp"
app:actualImageScaleType=
"centerCrop"
/>
<TextView
android:id=
"@+id/text_host"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:textColor=
"@color/colorSecondaryText"
tools:text=
"www.uol.com.br"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toEndOf=
"@+id/image_preview"
/>
<TextView
android:id=
"@+id/text_title"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:textColor=
"@color/colorAccent"
tools:text=
"Web page title"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"@+id/text_host"
app:layout_constraintTop_toBottomOf=
"@id/text_host"
/>
<TextView
android:id=
"@+id/text_description"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
tools:text=
"description"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"@+id/text_host"
app:layout_constraintTop_toBottomOf=
"@id/text_title"
/>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/values/colors.xml
View file @
a9085e1c
...
...
@@ -9,6 +9,7 @@
<!-- Text colors -->
<color
name=
"colorPrimaryText"
>
#DE000000
</color>
<color
name=
"colorSecondaryText"
>
#787878
</color>
<!-- User status colors -->
<color
name=
"colorUserStatusOnline"
>
#2FE1A8
</color>
...
...
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