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
1cb3f896
Unverified
Commit
1cb3f896
authored
Feb 28, 2018
by
Lucio Maciel
Committed by
GitHub
Feb 28, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #822 from RocketChat/improve-socket
[NEW] Improve socket connection
parents
3b576568
31b9a410
Changes
19
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
531 additions
and
175 deletions
+531
-175
build.gradle
app/build.gradle
+2
-0
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+70
-59
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+3
-0
ChatRoomActivity.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
+10
-0
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+24
-1
ChatRoomsPresenter.kt
...cket/android/chatrooms/presentation/ChatRoomsPresenter.kt
+86
-79
ChatRoomsView.kt
...at/rocket/android/chatrooms/presentation/ChatRoomsView.kt
+3
-0
ChatRoomsFragment.kt
...ava/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
+40
-9
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+12
-1
MainActivity.kt
...src/main/java/chat/rocket/android/main/ui/MainActivity.kt
+8
-0
ConnectionManager.kt
...ocket/android/server/infraestructure/ConnectionManager.kt
+155
-0
ConnectionManagerFactory.kt
...ndroid/server/infraestructure/ConnectionManagerFactory.kt
+22
-0
RocketChatClientFactory.kt
...android/server/infraestructure/RocketChatClientFactory.kt
+1
-1
Animation.kt
...ain/java/chat/rocket/android/util/extensions/Animation.kt
+47
-25
fragment_chat_room.xml
app/src/main/res/layout/fragment_chat_room.xml
+15
-0
fragment_chat_rooms.xml
app/src/main/res/layout/fragment_chat_rooms.xml
+15
-0
strings.xml
app/src/main/res/values-pt-rBR/strings.xml
+7
-0
strings.xml
app/src/main/res/values/strings.xml
+8
-0
dependencies.gradle
dependencies.gradle
+3
-0
No files found.
app/build.gradle
View file @
1cb3f896
...
...
@@ -60,6 +60,8 @@ dependencies {
implementation
libraries
.
constraintLayout
implementation
libraries
.
cardView
implementation
libraries
.
androidKtx
implementation
libraries
.
dagger
implementation
libraries
.
daggerSupport
kapt
libraries
.
daggerProcessor
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
1cb3f896
...
...
@@ -6,23 +6,23 @@ import chat.rocket.android.chatroom.domain.UriInteractor
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
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.state
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.internal.realtime.State
import
chat.rocket.core.internal.realtime.connect
import
chat.rocket.core.internal.realtime.subscribeRoomMessages
import
chat.rocket.core.internal.realtime.unsubscribe
import
chat.rocket.core.internal.rest.*
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Value
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.async
import
kotlinx.coroutines.experimental.channels.Channel
import
kotlinx.coroutines.experimental.launch
import
org.threeten.bp.Instant
import
timber.log.Timber
import
javax.inject.Inject
...
...
@@ -33,14 +33,22 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private
val
permissions
:
GetPermissionsInteractor
,
private
val
uriInteractor
:
UriInteractor
,
private
val
messagesRepository
:
MessagesRepository
,
factory
:
RocketChatClient
Factory
,
factory
:
ConnectionManager
Factory
,
private
val
mapper
:
ViewModelMapper
)
{
private
val
client
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
private
var
subId
:
String
?
=
null
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
manager
=
factory
.
create
(
currentServer
)
private
val
client
=
manager
.
client
private
var
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
!!
private
val
messagesChannel
=
Channel
<
Message
>()
private
var
chatRoomId
:
String
?
=
null
private
var
chatRoomType
:
String
?
=
null
private
val
stateChannel
=
Channel
<
State
>()
private
var
lastState
=
manager
.
state
fun
loadMessages
(
chatRoomId
:
String
,
chatRoomType
:
String
,
offset
:
Long
=
0
)
{
this
.
chatRoomId
=
chatRoomId
this
.
chatRoomType
=
chatRoomType
launchUI
(
strategy
)
{
view
.
showLoading
()
try
{
...
...
@@ -55,10 +63,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
val
messagesViewModels
=
mapper
.
map
(
messages
)
view
.
showMessages
(
messagesViewModels
)
// Subscribe after getting the first page of messages from REST
if
(
offset
==
0L
)
{
subscribeMessages
(
chatRoomId
)
}
subscribeMessages
(
chatRoomId
)
}
catch
(
ex
:
Exception
)
{
ex
.
printStackTrace
()
ex
.
message
?.
let
{
...
...
@@ -69,6 +74,10 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
finally
{
view
.
hideLoading
()
}
if
(
offset
==
0L
)
{
subscribeState
()
}
}
}
...
...
@@ -131,7 +140,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
}
fun
markRoomAsRead
(
roomId
:
String
)
{
private
fun
markRoomAsRead
(
roomId
:
String
)
{
launchUI
(
strategy
)
{
try
{
client
.
markAsRead
(
roomId
)
...
...
@@ -142,57 +151,70 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
}
private
fun
subscribeMessages
(
roomId
:
String
)
{
client
.
addStateChannel
(
stateChannel
)
private
fun
subscribeState
()
{
Timber
.
d
(
"Subscribing to Status changes"
)
lastState
=
manager
.
state
manager
.
addStatusChannel
(
stateChannel
)
launch
(
CommonPool
+
strategy
.
jobs
)
{
for
(
status
in
stateChannel
)
{
Timber
.
d
(
"Changing status to: $status"
)
when
(
status
)
{
State
.
Authenticating
->
Timber
.
d
(
"Authenticating"
)
State
.
Connected
->
{
Timber
.
d
(
"Connected"
)
subId
=
client
.
subscribeRoomMessages
(
roomId
)
{
Timber
.
d
(
"subscribe messages for $roomId: $it"
)
}
for
(
state
in
stateChannel
)
{
Timber
.
d
(
"Got new state: $state - last: $lastState"
)
if
(
state
!=
lastState
)
{
launch
(
UI
)
{
view
.
showConnectionState
(
state
)
}
}
}
Timber
.
d
(
"Done on statusChannel"
)
}
when
(
client
.
state
)
{
State
.
Connected
->
{
Timber
.
d
(
"Already connected"
)
subId
=
client
.
subscribeRoomMessages
(
roomId
)
{
Timber
.
d
(
"subscribe messages for $roomId: $it"
)
if
(
state
is
State
.
Connected
)
{
loadMissingMessages
()
}
}
lastState
=
state
}
else
->
client
.
connect
()
}
}
launchUI
(
strategy
)
{
listenMessages
(
roomId
)
}
private
fun
subscribeMessages
(
roomId
:
String
)
{
manager
.
subscribeRoomMessages
(
roomId
,
messagesChannel
)
// TODO - when we have a proper service, we won't need to take care of connection, just
// subscribe and listen...
/*launchUI(strategy) {
subId = client.subscribeRoomMessages(roomId) {
Timber.d("subscribe messages for $roomId: $it")
launch
(
CommonPool
+
strategy
.
jobs
)
{
for
(
message
in
messagesChannel
)
{
Timber
.
d
(
"New message for room ${message.roomId}"
)
updateMessage
(
message
)
}
listenMessages(roomId)
}*/
}
}
fun
unsubscribeMessages
()
{
launch
(
CommonPool
)
{
client
.
removeStateChannel
(
stateChannel
)
subId
?.
let
{
subscriptionId
->
client
.
unsubscribe
(
subscriptionId
)
private
fun
loadMissingMessages
()
{
launch
(
parent
=
strategy
.
jobs
)
{
if
(
chatRoomId
!=
null
&&
chatRoomType
!=
null
)
{
val
roomType
=
roomTypeOf
(
chatRoomType
!!
)
val
lastMessage
=
messagesRepository
.
getByRoomId
(
chatRoomId
!!
).
sortedByDescending
{
it
.
timestamp
}.
first
()
val
instant
=
Instant
.
ofEpochMilli
(
lastMessage
.
timestamp
)
val
messages
=
client
.
history
(
chatRoomId
!!
,
roomType
,
count
=
50
,
oldest
=
instant
.
toString
())
Timber
.
d
(
"History: $messages"
)
if
(
messages
.
result
.
isNotEmpty
())
{
val
models
=
mapper
.
map
(
messages
.
result
)
messagesRepository
.
saveAll
(
messages
.
result
)
launchUI
(
strategy
)
{
view
.
showNewMessage
(
models
)
}
if
(
messages
.
result
.
size
==
50
)
{
// we loade at least count messages, try one more to fetch more messages
loadMissingMessages
()
}
}
}
}
}
fun
unsubscribeMessages
(
chatRoomId
:
String
)
{
manager
.
removeStatusChannel
(
stateChannel
)
manager
.
unsubscribeRoomMessages
(
chatRoomId
)
}
/**
* Delete the message with the given id.
*
...
...
@@ -317,17 +339,6 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
}
private
suspend
fun
listenMessages
(
roomId
:
String
)
{
launch
(
CommonPool
+
strategy
.
jobs
)
{
for
(
message
in
client
.
messagesChannel
)
{
if
(
message
.
roomId
!=
roomId
)
{
Timber
.
d
(
"Ignoring message for room ${message.roomId}, expecting $roomId"
)
}
updateMessage
(
message
)
}
}
}
private
fun
updateMessage
(
streamedMessage
:
Message
)
{
launchUI
(
strategy
)
{
val
viewModelStreamedMessage
=
mapper
.
map
(
streamedMessage
)
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
1cb3f896
...
...
@@ -4,6 +4,7 @@ import android.net.Uri
import
chat.rocket.android.chatroom.viewmodel.BaseViewModel
import
chat.rocket.android.core.behaviours.LoadingView
import
chat.rocket.android.core.behaviours.MessageView
import
chat.rocket.core.internal.realtime.State
interface
ChatRoomView
:
LoadingView
,
MessageView
{
...
...
@@ -97,4 +98,6 @@ interface ChatRoomView : LoadingView, MessageView {
fun
clearMessageComposition
()
fun
showInvalidFileSize
(
fileSize
:
Int
,
maxFileSize
:
Int
)
fun
showConnectionState
(
state
:
State
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomActivity.kt
View file @
1cb3f896
...
...
@@ -6,6 +6,8 @@ import android.os.Bundle
import
android.support.v4.app.Fragment
import
android.support.v7.app.AppCompatActivity
import
chat.rocket.android.R
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
dagger.android.AndroidInjection
...
...
@@ -32,6 +34,11 @@ private const val INTENT_IS_CHAT_ROOM_READ_ONLY = "is_chat_room_read_only"
class
ChatRoomActivity
:
AppCompatActivity
(),
HasSupportFragmentInjector
{
@Inject
lateinit
var
fragmentDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Fragment
>
// TODO - workaround for now... We will move to a single activity
@Inject
lateinit
var
serverInteractor
:
GetCurrentServerInteractor
@Inject
lateinit
var
managerFactory
:
ConnectionManagerFactory
private
lateinit
var
chatRoomId
:
String
private
lateinit
var
chatRoomName
:
String
private
lateinit
var
chatRoomType
:
String
...
...
@@ -42,6 +49,9 @@ class ChatRoomActivity : AppCompatActivity(), HasSupportFragmentInjector {
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_chat_room
)
// Workaround for when we are coming to the app via the recents app and the app was killed.
managerFactory
.
create
(
serverInteractor
.
get
()
!!
).
connect
()
chatRoomId
=
intent
.
getStringExtra
(
INTENT_CHAT_ROOM_ID
)
requireNotNull
(
chatRoomId
)
{
"no chat_room_id provided in Intent extras"
}
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
1cb3f896
...
...
@@ -27,6 +27,7 @@ import chat.rocket.android.widget.emoji.ComposerEditText
import
chat.rocket.android.widget.emoji.Emoji
import
chat.rocket.android.widget.emoji.EmojiKeyboardPopup
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.core.internal.realtime.State
import
dagger.android.support.AndroidSupportInjection
import
io.reactivex.disposables.CompositeDisposable
import
kotlinx.android.synthetic.main.fragment_chat_room.*
...
...
@@ -112,7 +113,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
}
override
fun
onDestroyView
()
{
presenter
.
unsubscribeMessages
()
presenter
.
unsubscribeMessages
(
chatRoomId
)
handler
.
removeCallbacksAndMessages
(
null
)
unsubscribeTextMessage
()
super
.
onDestroyView
()
...
...
@@ -290,6 +291,28 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardPopup.Listener {
showMessage
(
getString
(
R
.
string
.
max_file_size_exceeded
,
fileSize
,
maxFileSize
))
}
override
fun
showConnectionState
(
state
:
State
)
{
activity
?.
apply
{
connection_status_text
.
fadeIn
()
handler
.
removeCallbacks
(
dismissStatus
)
when
(
state
)
{
is
State
.
Connected
->
{
connection_status_text
.
text
=
getString
(
R
.
string
.
status_connected
)
handler
.
postDelayed
(
dismissStatus
,
2000
)
}
is
State
.
Disconnected
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_disconnected
)
is
State
.
Connecting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_connecting
)
is
State
.
Authenticating
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_authenticating
)
is
State
.
Disconnecting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_disconnecting
)
is
State
.
Waiting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_waiting
,
state
.
seconds
)
}
}
}
private
val
dismissStatus
=
{
connection_status_text
.
fadeOut
()
}
private
fun
setupRecyclerView
()
{
recycler_view
.
addOnScrollListener
(
object
:
RecyclerView
.
OnScrollListener
()
{
override
fun
onScrolled
(
recyclerView
:
RecyclerView
,
dx
:
Int
,
dy
:
Int
)
{
...
...
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
View file @
1cb3f896
This diff is collapsed.
Click to expand it.
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsView.kt
View file @
1cb3f896
...
...
@@ -2,6 +2,7 @@ package chat.rocket.android.chatrooms.presentation
import
chat.rocket.android.core.behaviours.LoadingView
import
chat.rocket.android.core.behaviours.MessageView
import
chat.rocket.core.internal.realtime.State
import
chat.rocket.core.model.ChatRoom
interface
ChatRoomsView
:
LoadingView
,
MessageView
{
...
...
@@ -17,4 +18,6 @@ interface ChatRoomsView : LoadingView, MessageView {
* Shows no chat rooms to display.
*/
fun
showNoChatRoomsToDisplay
()
fun
showConnectionState
(
state
:
State
)
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
View file @
1cb3f896
package
chat.rocket.android.chatrooms.ui
import
android.os.Bundle
import
android.os.Handler
import
android.support.v4.app.Fragment
import
android.support.v7.app.AppCompatActivity
import
android.support.v7.util.DiffUtil
...
...
@@ -13,14 +14,16 @@ import chat.rocket.android.chatrooms.presentation.ChatRoomsPresenter
import
chat.rocket.android.chatrooms.presentation.ChatRoomsView
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.SettingsRepository
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.setVisible
import
chat.rocket.android.util.extensions.showToast
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.widget.DividerItemDecoration
import
chat.rocket.core.internal.realtime.State
import
chat.rocket.core.model.ChatRoom
import
dagger.android.support.AndroidSupportInjection
import
kotlinx.android.synthetic.main.fragment_chat_rooms.*
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.Job
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.async
import
kotlinx.coroutines.experimental.launch
import
javax.inject.Inject
...
...
@@ -29,6 +32,9 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
@Inject
lateinit
var
serverInteractor
:
GetCurrentServerInteractor
@Inject
lateinit
var
settingsRepository
:
SettingsRepository
private
var
searchView
:
SearchView
?
=
null
private
val
handler
=
Handler
()
private
var
listJob
:
Job
?
=
null
companion
object
{
fun
newInstance
()
=
ChatRoomsFragment
()
...
...
@@ -41,6 +47,7 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
}
override
fun
onDestroy
()
{
handler
.
removeCallbacks
(
dismissStatus
)
presenter
.
disconnect
()
super
.
onDestroy
()
}
...
...
@@ -74,17 +81,19 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
override
suspend
fun
updateChatRooms
(
newDataSet
:
List
<
ChatRoom
>)
{
activity
.
apply
{
launch
(
UI
)
{
listJob
?.
cancel
()
listJob
=
launch
(
UI
)
{
val
adapter
=
recycler_view
.
adapter
as
ChatRoomsAdapter
// FIXME https://fabric.io/rocketchat3/android/apps/chat.rocket.android.dev/issues/5a90d4718cb3c2fa63b3f557?time=last-seven-days
// TODO - fix this bug to reenable DiffUtil
/*
val diff = async(CommonPool) {
val
diff
=
async
(
CommonPool
)
{
DiffUtil
.
calculateDiff
(
RoomsDiffCallback
(
adapter
.
dataSet
,
newDataSet
))
}.await()
*/
}.
await
()
adapter
.
updateRooms
(
newDataSet
)
adapter
.
notifyDataSetChanged
()
//diff.dispatchUpdatesTo(adapter)
if
(
isActive
)
{
adapter
.
updateRooms
(
newDataSet
)
diff
.
dispatchUpdatesTo
(
adapter
)
}
}
}
}
...
...
@@ -101,6 +110,28 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
showConnectionState
(
state
:
State
)
{
activity
?.
apply
{
connection_status_text
.
fadeIn
()
handler
.
removeCallbacks
(
dismissStatus
)
when
(
state
)
{
is
State
.
Connected
->
{
connection_status_text
.
text
=
getString
(
R
.
string
.
status_connected
)
handler
.
postDelayed
(
dismissStatus
,
2000
)
}
is
State
.
Disconnected
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_disconnected
)
is
State
.
Connecting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_connecting
)
is
State
.
Authenticating
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_authenticating
)
is
State
.
Disconnecting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_disconnecting
)
is
State
.
Waiting
->
connection_status_text
.
text
=
getString
(
R
.
string
.
status_waiting
,
state
.
seconds
)
}
}
}
private
val
dismissStatus
=
{
connection_status_text
.
fadeOut
()
}
private
fun
setupToolbar
()
{
(
activity
as
AppCompatActivity
).
supportActionBar
?.
title
=
getString
(
R
.
string
.
title_chats
)
}
...
...
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
1cb3f896
...
...
@@ -2,6 +2,7 @@ package chat.rocket.android.main.presentation
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.RocketChatClient
...
...
@@ -13,9 +14,11 @@ import javax.inject.Inject
class
MainPresenter
@Inject
constructor
(
private
val
navigator
:
MainNavigator
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
localRepository
:
LocalRepository
,
managerFactory
:
ConnectionManagerFactory
,
factory
:
RocketChatClientFactory
)
{
private
val
client
:
RocketChatClient
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
manager
=
managerFactory
.
create
(
currentServer
)
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
fun
toChatList
()
=
navigator
.
toChatList
()
...
...
@@ -49,4 +52,12 @@ class MainPresenter @Inject constructor(private val navigator: MainNavigator,
}
localRepository
.
clearAllFromServer
(
currentServer
)
}
fun
connect
()
{
manager
.
connect
()
}
fun
disconnect
()
{
manager
.
disconnect
()
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
View file @
1cb3f896
...
...
@@ -29,6 +29,7 @@ class MainActivity : AppCompatActivity(), MainView, HasSupportFragmentInjector {
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_main
)
presenter
.
connect
()
setupToolbar
()
setupNavigationView
()
}
...
...
@@ -41,6 +42,13 @@ class MainActivity : AppCompatActivity(), MainView, HasSupportFragmentInjector {
}
}
override
fun
onDestroy
()
{
super
.
onDestroy
()
if
(
isFinishing
)
{
presenter
.
disconnect
()
}
}
override
fun
onLogout
()
{
finish
()
val
intent
=
Intent
(
this
,
AuthenticationActivity
::
class
.
java
)
...
...
app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManager.kt
0 → 100644
View file @
1cb3f896
package
chat.rocket.android.server.infraestructure
import
chat.rocket.common.model.BaseRoom
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.realtime.*
import
chat.rocket.core.internal.rest.chatRooms
import
chat.rocket.core.model.Message
import
kotlinx.coroutines.experimental.Job
import
kotlinx.coroutines.experimental.channels.Channel
import
kotlinx.coroutines.experimental.launch
import
timber.log.Timber
class
ConnectionManager
(
internal
val
client
:
RocketChatClient
)
{
private
val
statusChannelList
=
ArrayList
<
Channel
<
State
>>()
private
val
statusChannel
=
Channel
<
State
>()
private
var
connectJob
:
Job
?
=
null
private
val
roomAndSubscriptionChannels
=
ArrayList
<
Channel
<
StreamMessage
<
BaseRoom
>>>()
private
val
roomMessagesChannels
=
LinkedHashMap
<
String
,
Channel
<
Message
>>()
private
val
subscriptionIdMap
=
HashMap
<
String
,
String
>()
private
var
subscriptionId
:
String
?
=
null
private
var
roomsId
:
String
?
=
null
fun
connect
()
{
if
(
connectJob
?.
isActive
==
true
&&
(
state
!
is
State
.
Disconnected
))
{
Timber
.
d
(
"Already connected, just returning..."
)
return
}
// cleanup first
client
.
removeStateChannel
(
statusChannel
)
client
.
disconnect
()
connectJob
?.
cancel
()
// Connect and setup
client
.
addStateChannel
(
statusChannel
)
connectJob
=
launch
{
for
(
status
in
statusChannel
)
{
Timber
.
d
(
"Changing status to: $status"
)
when
(
status
)
{
is
State
.
Connected
->
{
client
.
subscribeSubscriptions
{
_
,
id
->
Timber
.
d
(
"Subscribed to subscriptions: $id"
)
subscriptionId
=
id
}
client
.
subscribeRooms
{
_
,
id
->
Timber
.
d
(
"Subscribed to rooms: $id"
)
roomsId
=
id
}
resubscribeRooms
()
}
is
State
.
Waiting
->
{
Timber
.
d
(
"Connection in: ${status.seconds}"
)
}
}
for
(
channel
in
statusChannelList
)
{
channel
.
send
(
status
)
}
}
}
launch
(
parent
=
connectJob
)
{
for
(
room
in
client
.
roomsChannel
)
{
Timber
.
d
(
"GOT Room streamed"
)
for
(
channel
in
roomAndSubscriptionChannels
)
{
channel
.
send
(
room
)
}
}
}
launch
(
parent
=
connectJob
)
{
for
(
subscription
in
client
.
subscriptionsChannel
)
{
Timber
.
d
(
"GOT Subscription streamed"
)
for
(
channel
in
roomAndSubscriptionChannels
)
{
channel
.
send
(
subscription
)
}
}
}
launch
(
parent
=
connectJob
)
{
for
(
message
in
client
.
messagesChannel
)
{
Timber
.
d
(
"Received new Message for room ${message.roomId}"
)
val
channel
=
roomMessagesChannels
[
message
.
roomId
]
channel
?.
send
(
message
)
}
}
client
.
connect
()
// Broadcast initial state...
val
state
=
client
.
state
for
(
channel
in
statusChannelList
)
{
channel
.
offer
(
state
)
}
}
private
fun
resubscribeRooms
()
{
roomMessagesChannels
.
toList
().
map
{
(
roomId
,
channel
)
->
client
.
subscribeRoomMessages
(
roomId
)
{
_
,
id
->
Timber
.
d
(
"Subscribed to $roomId: $id"
)
subscriptionIdMap
[
roomId
]
=
id
}
}
}
fun
disconnect
()
{
Timber
.
d
(
"ConnectionManager DISCONNECT"
)
client
.
removeStateChannel
(
statusChannel
)
client
.
disconnect
()
connectJob
?.
cancel
()
}
fun
addStatusChannel
(
channel
:
Channel
<
State
>)
=
statusChannelList
.
add
(
channel
)
fun
removeStatusChannel
(
channel
:
Channel
<
State
>)
=
statusChannelList
.
remove
(
channel
)
fun
addRoomsAndSubscriptionsChannel
(
channel
:
Channel
<
StreamMessage
<
BaseRoom
>>)
=
roomAndSubscriptionChannels
.
add
(
channel
)
fun
removeRoomsAndSubscriptionsChannel
(
channel
:
Channel
<
StreamMessage
<
BaseRoom
>>)
=
roomAndSubscriptionChannels
.
remove
(
channel
)
fun
subscribeRoomMessages
(
roomId
:
String
,
channel
:
Channel
<
Message
>)
{
val
oldSub
=
roomMessagesChannels
.
put
(
roomId
,
channel
)
if
(
oldSub
!=
null
)
{
Timber
.
d
(
"Room $roomId already subscribed..."
)
return
}
if
(
client
.
state
is
State
.
Connected
)
{
client
.
subscribeRoomMessages
(
roomId
)
{
_
,
id
->
Timber
.
d
(
"Subscribed to $roomId: $id"
)
subscriptionIdMap
[
roomId
]
=
id
}
}
}
fun
unsubscribeRoomMessages
(
roomId
:
String
)
{
val
sub
=
roomMessagesChannels
.
remove
(
roomId
)
if
(
sub
!=
null
)
{
val
id
=
subscriptionIdMap
.
remove
(
roomId
)
id
?.
let
{
client
.
unsubscribe
(
it
)
}
}
}
}
suspend
fun
ConnectionManager
.
chatRooms
(
timestamp
:
Long
=
0
,
filterCustom
:
Boolean
=
true
)
=
client
.
chatRooms
(
timestamp
,
filterCustom
)
val
ConnectionManager
.
state
:
State
get
()
=
client
.
state
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/infraestructure/ConnectionManagerFactory.kt
0 → 100644
View file @
1cb3f896
package
chat.rocket.android.server.infraestructure
import
timber.log.Timber
import
javax.inject.Inject
import
javax.inject.Singleton
@Singleton
class
ConnectionManagerFactory
@Inject
constructor
(
private
val
factory
:
RocketChatClientFactory
)
{
private
val
cache
=
HashMap
<
String
,
ConnectionManager
>()
fun
create
(
url
:
String
):
ConnectionManager
{
cache
[
url
]
?.
let
{
Timber
.
d
(
"Returning CACHED Manager for: $url"
)
return
it
}
Timber
.
d
(
"Returning FRESH Manager for: $url"
)
val
manager
=
ConnectionManager
(
factory
.
create
(
url
))
cache
[
url
]
=
manager
return
manager
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/infraestructure/RocketChatClientFactory.kt
View file @
1cb3f896
...
...
@@ -28,7 +28,7 @@ class RocketChatClientFactory @Inject constructor(val okHttpClient: OkHttpClient
}
Timber
.
d
(
"Returning NEW client for: $url"
)
cache
.
put
(
url
,
client
)
cache
[
url
]
=
client
return
client
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/util/extensions/Animation.kt
View file @
1cb3f896
...
...
@@ -2,7 +2,6 @@ package chat.rocket.android.util.extensions
import
android.view.View
import
android.view.ViewAnimationUtils
import
android.view.animation.AccelerateInterpolator
import
android.view.animation.DecelerateInterpolator
fun
View
.
rotateBy
(
value
:
Float
,
duration
:
Long
=
100
)
{
...
...
@@ -12,36 +11,59 @@ fun View.rotateBy(value: Float, duration: Long = 100) {
.
start
()
}
fun
View
.
fadeIn
(
startValue
:
Float
,
finishValue
:
Float
,
duration
:
Long
=
200
)
{
animate
()
.
alpha
(
startValue
)
.
setDuration
(
duration
)
.
setInterpolator
(
DecelerateInterpolator
())
.
withEndAction
({
animate
()
.
alpha
(
finishValue
)
.
setDuration
(
duration
)
.
setInterpolator
(
AccelerateInterpolator
()).
start
()
}).
start
()
fun
View
.
fadeIn
(
start
:
Float
=
0f
,
end
:
Float
=
1f
,
duration
:
Long
=
200
)
{
// already at end alpha, just set visible and return
if
(
alpha
==
end
)
{
setVisible
(
true
)
return
}
val
animation
=
animate
()
.
alpha
(
end
)
.
setDuration
(
duration
)
.
setInterpolator
(
DecelerateInterpolator
())
if
(
start
!=
alpha
)
{
animate
()
.
alpha
(
start
)
.
setDuration
(
duration
/
2
)
// half the time, so the entire animation runs on duration
.
setInterpolator
(
DecelerateInterpolator
())
.
withEndAction
{
animation
.
setDuration
(
duration
/
2
).
start
()
}.
start
()
}
else
{
animation
.
start
()
}
setVisible
(
true
)
}
fun
View
.
fadeOut
(
startValue
:
Float
,
finishValue
:
Float
,
duration
:
Long
=
200
)
{
animate
()
.
alpha
(
startValue
)
.
setDuration
(
duration
)
.
setInterpolator
(
DecelerateInterpolator
())
.
withEndAction
({
animate
()
.
alpha
(
finishValue
)
.
setDuration
(
duration
)
.
setInterpolator
(
AccelerateInterpolator
()).
start
()
}).
start
()
setVisible
(
false
)
fun
View
.
fadeOut
(
start
:
Float
=
1f
,
end
:
Float
=
0f
,
duration
:
Long
=
200
)
{
if
(
alpha
==
end
)
{
setVisible
(
false
)
return
}
val
animation
=
animate
()
.
alpha
(
end
)
.
setDuration
(
duration
)
.
setInterpolator
(
DecelerateInterpolator
())
.
withEndAction
{
setVisible
(
false
)
}
if
(
start
!=
alpha
)
{
animate
()
.
alpha
(
start
)
.
setDuration
(
duration
/
2
)
// half the time, so the entire animation runs on duration
.
setInterpolator
(
DecelerateInterpolator
())
.
withEndAction
{
animation
.
setDuration
(
duration
/
2
).
start
()
}.
start
()
}
else
{
animation
.
start
()
}
}
fun
View
.
circularRevealOrUnreveal
(
centerX
:
Int
,
centerY
:
Int
,
startRadius
:
Float
,
endRadius
:
Float
,
duration
:
Long
=
200
)
{
val
anim
=
ViewAnimationUtils
.
createCircularReveal
(
this
,
centerX
,
centerY
,
startRadius
,
endRadius
)
anim
.
duration
=
duration
...
...
app/src/main/res/layout/fragment_chat_room.xml
View file @
1cb3f896
...
...
@@ -53,4 +53,19 @@
android:layout_margin=
"5dp"
android:visibility=
"gone"
/>
<TextView
android:id=
"@+id/connection_status_text"
android:layout_width=
"match_parent"
android:layout_height=
"32dp"
android:background=
"@color/colorPrimary"
android:elevation=
"4dp"
android:textColor=
"@color/white"
android:gravity=
"center"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body2"
android:visibility=
"gone"
android:alpha=
"0"
tools:alpha=
"1"
tools:visibility=
"visible"
tools:text=
"connected"
/>
</RelativeLayout>
app/src/main/res/layout/fragment_chat_rooms.xml
View file @
1cb3f896
...
...
@@ -29,4 +29,19 @@
android:visibility=
"gone"
tools:visibility=
"visible"
/>
<TextView
android:id=
"@+id/connection_status_text"
android:layout_width=
"match_parent"
android:layout_height=
"32dp"
android:background=
"@color/colorPrimary"
android:elevation=
"4dp"
android:textColor=
"@color/white"
android:gravity=
"center"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body2"
android:visibility=
"gone"
android:alpha=
"0"
tools:alpha=
"1"
tools:visibility=
"visible"
tools:text=
"connected"
/>
</RelativeLayout>
\ No newline at end of file
app/src/main/res/values-pt-rBR/strings.xml
View file @
1cb3f896
...
...
@@ -84,4 +84,11 @@
<!-- Upload Messages -->
<string
name=
"max_file_size_exceeded"
>
Tamanho de arquivo (%1$d bytes) excedeu tamanho máximo de upload (%2$d bytes)
</string>
<!-- Socket status -->
<string
name=
"status_connected"
>
conectado
</string>
<string
name=
"status_disconnected"
>
desconetado
</string>
<string
name=
"status_connecting"
>
conectando
</string>
<string
name=
"status_authenticating"
>
autenticando
</string>
<string
name=
"status_disconnecting"
>
desconectando
</string>
<string
name=
"status_waiting"
>
conectando em %d segundos
</string>
</resources>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
1cb3f896
...
...
@@ -86,4 +86,12 @@
<!-- Upload Messages -->
<string
name=
"max_file_size_exceeded"
>
File size %1$d bytes exceeded max upload size of %2$d bytes
</string>
<!-- Socket status -->
<string
name=
"status_connected"
>
connected
</string>
<string
name=
"status_disconnected"
>
disconnected
</string>
<string
name=
"status_connecting"
>
connecting
</string>
<string
name=
"status_authenticating"
>
authenticating
</string>
<string
name=
"status_disconnecting"
>
disconnecting
</string>
<string
name=
"status_waiting"
>
connecting in %d seconds
</string>
</resources>
\ No newline at end of file
dependencies.gradle
View file @
1cb3f896
...
...
@@ -11,6 +11,7 @@ ext {
// Main dependencies
support
:
'27.0.2'
,
constraintLayout
:
'1.0.2'
,
androidKtx
:
'0.1'
,
dagger
:
'2.14.1'
,
exoPlayer
:
'2.6.0'
,
playServices
:
'11.8.0'
,
...
...
@@ -49,6 +50,8 @@ ext {
constraintLayout
:
"com.android.support.constraint:constraint-layout:${versions.constraintLayout}"
,
cardView
:
"com.android.support:cardview-v7:${versions.support}"
,
androidKtx
:
"androidx.core:core-ktx:${versions.androidKtx}"
,
dagger
:
"com.google.dagger:dagger:${versions.dagger}"
,
daggerSupport
:
"com.google.dagger:dagger-android-support:${versions.dagger}"
,
daggerProcessor
:
"com.google.dagger:dagger-compiler:${versions.dagger}"
,
...
...
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