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
4505780c
Commit
4505780c
authored
Mar 27, 2018
by
Lucio Maciel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Better multi server support, support push notifications
parent
d2cc3161
Changes
39
Show whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
637 additions
and
591 deletions
+637
-591
RocketChatApplication.kt
...ain/java/chat/rocket/android/app/RocketChatApplication.kt
+47
-19
TokenModel.kt
.../rocket/android/authentication/domain/model/TokenModel.kt
+4
-1
MemoryTokenRepository.kt
...d/authentication/infraestructure/MemoryTokenRepository.kt
+0
-16
SharedPreferencesTokenRepository.kt
...ation/infraestructure/SharedPreferencesTokenRepository.kt
+82
-0
LoginPresenter.kt
...droid/authentication/login/presentation/LoginPresenter.kt
+10
-7
AuthenticationPresenter.kt
...id/authentication/presentation/AuthenticationPresenter.kt
+18
-14
SignupPresenter.kt
...oid/authentication/signup/presentation/SignupPresenter.kt
+1
-1
TwoFAPresenter.kt
...d/authentication/twofactor/presentation/TwoFAPresenter.kt
+7
-9
AuthenticationActivity.kt
...ocket/android/authentication/ui/AuthenticationActivity.kt
+18
-8
MessageReactionsAdapter.kt
...ocket/android/chatroom/adapter/MessageReactionsAdapter.kt
+1
-1
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+2
-2
ViewModelMapper.kt
...chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
+9
-6
AppComponent.kt
app/src/main/java/chat/rocket/android/dagger/AppComponent.kt
+3
-1
AppModule.kt
.../main/java/chat/rocket/android/dagger/module/AppModule.kt
+20
-7
ReceiverBuilder.kt
...java/chat/rocket/android/dagger/module/ReceiverBuilder.kt
+13
-0
ServiceBuilder.kt
.../java/chat/rocket/android/dagger/module/ServiceBuilder.kt
+5
-0
FrescoAuthInterceptor.kt
.../java/chat/rocket/android/helper/FrescoAuthInterceptor.kt
+18
-12
LocalRepository.kt
...ava/chat/rocket/android/infrastructure/LocalRepository.kt
+1
-1
SharedPrefsLocalRepository.kt
...cket/android/infrastructure/SharedPrefsLocalRepository.kt
+1
-1
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+24
-14
MainActivity.kt
...src/main/java/chat/rocket/android/main/ui/MainActivity.kt
+10
-2
DeleteReceiver.kt
app/src/main/java/chat/rocket/android/push/DeleteReceiver.kt
+40
-0
FirebaseTokenService.kt
...ain/java/chat/rocket/android/push/FirebaseTokenService.kt
+9
-2
GcmListenerService.kt
.../main/java/chat/rocket/android/push/GcmListenerService.kt
+11
-1
GroupedPush.kt
app/src/main/java/chat/rocket/android/push/GroupedPush.kt
+15
-0
PushManager.kt
app/src/main/java/chat/rocket/android/push/PushManager.kt
+176
-394
DeleteReceiverProvider.kt
...ava/chat/rocket/android/push/di/DeleteReceiverProvider.kt
+12
-0
GcmListenerServiceProvider.kt
...chat/rocket/android/push/di/GcmListenerServiceProvider.kt
+11
-0
GetAccountInteractor.kt
...chat/rocket/android/server/domain/GetAccountInteractor.kt
+9
-0
GetServersInteractor.java
...at/rocket/android/server/domain/GetServersInteractor.java
+0
-17
ServersRepository.kt
...va/chat/rocket/android/server/domain/ServersRepository.kt
+0
-14
SettingsRepository.kt
...a/chat/rocket/android/server/domain/SettingsRepository.kt
+2
-1
TokenRepository.kt
...java/chat/rocket/android/server/domain/TokenRepository.kt
+6
-0
RocketChatClientFactory.kt
...android/server/infraestructure/RocketChatClientFactory.kt
+4
-4
RoomServersRepository.kt
...t/android/server/infraestructure/RoomServersRepository.kt
+0
-20
ChangeServerPresenter.kt
...cket/android/server/presentation/ChangeServerPresenter.kt
+20
-14
ChangeServerActivity.kt
...ava/chat/rocket/android/server/ui/ChangeServerActivity.kt
+1
-1
RocketChatClient.kt
...a/chat/rocket/android/util/extensions/RocketChatClient.kt
+26
-0
dependencies.gradle
dependencies.gradle
+1
-1
No files found.
app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt
View file @
4505780c
...
...
@@ -3,30 +3,31 @@ package chat.rocket.android.app
import
android.app.Activity
import
android.app.Application
import
android.app.Service
import
android.content.SharedPreferences
import
androidx.content.edit
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.authentication.domain.model.toToken
import
chat.rocket.android.dagger.DaggerAppComponent
import
chat.rocket.android.helper.CrashlyticsTree
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.MultiServerTokenRepository
import
chat.rocket.android.server.domain.SettingsRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.widget.emoji.EmojiRepository
import
chat.rocket.common.model.Token
import
chat.rocket.core.TokenRepository
import
com.crashlytics.android.Crashlytics
import
com.crashlytics.android.core.CrashlyticsCore
import
com.facebook.drawee.backends.pipeline.DraweeConfig
import
com.facebook.drawee.backends.pipeline.Fresco
import
com.facebook.imagepipeline.core.ImagePipelineConfig
import
com.jakewharton.threetenabp.AndroidThreeTen
import
dagger.android.AndroidInjector
import
dagger.android.DispatchingAndroidInjector
import
dagger.android.HasActivityInjector
import
dagger.android.HasServiceInjector
import
io.fabric.sdk.android.Fabric
import
kotlinx.coroutines.experimental.runBlocking
import
timber.log.Timber
import
javax.inject.Inject
import
android.content.BroadcastReceiver
import
dagger.android.*
class
RocketChatApplication
:
Application
(),
HasActivityInjector
,
HasServiceInjector
{
class
RocketChatApplication
:
Application
(),
HasActivityInjector
,
HasServiceInjector
,
HasBroadcastReceiverInjector
{
@Inject
lateinit
var
activityDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Activity
>
...
...
@@ -34,6 +35,9 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
@Inject
lateinit
var
serviceDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Service
>
@Inject
lateinit
var
broadcastReceiverInjector
:
DispatchingAndroidInjector
<
BroadcastReceiver
>
@Inject
lateinit
var
imagePipelineConfig
:
ImagePipelineConfig
@Inject
...
...
@@ -48,14 +52,19 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
lateinit
var
settingsRepository
:
SettingsRepository
@Inject
lateinit
var
tokenRepository
:
TokenRepository
@Inject
lateinit
var
prefs
:
SharedPreferences
@Inject
lateinit
var
getAccountsInteractor
:
GetAccountsInteractor
override
fun
onCreate
()
{
super
.
onCreate
()
DaggerAppComponent
.
builder
().
application
(
this
).
build
().
inject
(
this
)
// TODO - remove this when we have a proper service handling connection...
initCurrentServer
()
// TODO - remove this on the future, temporary migration stuff for pre-release versions.
prefs
.
edit
{
putBoolean
(
INTERNAL_TOKEN_MIGRATION_NEEDED
,
true
)
}
migrateInternalTokens
()
AndroidThreeTen
.
init
(
this
)
EmojiRepository
.
load
(
this
)
...
...
@@ -65,14 +74,27 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
setupTimber
()
}
// TODO - remove this when we have a proper service handling connection...
private
fun
initCurrentServer
()
{
val
currentServer
=
getCurrentServerInteractor
.
get
()
val
serverToken
=
currentServer
?.
let
{
multiServerRepository
.
get
(
currentServer
)
}
val
settings
=
currentServer
?.
let
{
settingsRepository
.
get
(
currentServer
)
}
if
(
currentServer
!=
null
&&
serverToken
!=
null
&&
settings
!=
null
)
{
tokenRepository
.
save
(
Token
(
serverToken
.
userId
,
serverToken
.
authToken
))
private
fun
migrateInternalTokens
()
{
if
(!
prefs
.
getBoolean
(
INTERNAL_TOKEN_MIGRATION_NEEDED
,
true
))
{
Timber
.
d
(
"Tokens already migrated"
)
return
}
getCurrentServerInteractor
.
get
()
?.
let
{
serverUrl
->
multiServerRepository
.
get
(
serverUrl
)
?.
let
{
token
->
tokenRepository
.
save
(
serverUrl
,
Token
(
token
.
userId
,
token
.
authToken
))
}
}
runBlocking
{
getAccountsInteractor
.
get
().
forEach
{
account
->
multiServerRepository
.
get
(
account
.
serverUrl
)
?.
let
{
token
->
tokenRepository
.
save
(
account
.
serverUrl
,
token
.
toToken
())
}
}
}
prefs
.
edit
{
putBoolean
(
INTERNAL_TOKEN_MIGRATION_NEEDED
,
false
)
}
}
private
fun
setupCrashlytics
()
{
...
...
@@ -99,4 +121,10 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
override
fun
serviceInjector
():
AndroidInjector
<
Service
>
{
return
serviceDispatchingAndroidInjector
}
override
fun
broadcastReceiverInjector
():
AndroidInjector
<
BroadcastReceiver
>
{
return
broadcastReceiverInjector
}
}
private
const
val
INTERNAL_TOKEN_MIGRATION_NEEDED
=
"INTERNAL_TOKEN_MIGRATION_NEEDED"
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/domain/model/TokenModel.kt
View file @
4505780c
package
chat.rocket.android.authentication.domain.model
import
chat.rocket.common.model.Token
import
se.ansman.kotshi.JsonSerializable
@JsonSerializable
data class
TokenModel
(
val
userId
:
String
,
val
authToken
:
String
)
fun
TokenModel
.
toToken
()
=
Token
(
userId
,
authToken
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/infraestructure/MemoryTokenRepository.kt
deleted
100644 → 0
View file @
d2cc3161
package
chat.rocket.android.authentication.infraestructure
import
chat.rocket.common.model.Token
import
chat.rocket.core.TokenRepository
class
MemoryTokenRepository
:
TokenRepository
{
var
savedToken
:
Token
?
=
null
override
fun
get
():
Token
?
{
return
savedToken
}
override
fun
save
(
token
:
Token
)
{
savedToken
=
token
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/infraestructure/SharedPreferencesTokenRepository.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.authentication.infraestructure
import
android.content.SharedPreferences
import
androidx.content.edit
import
chat.rocket.android.authentication.domain.model.TokenModel
import
chat.rocket.android.server.domain.TokenRepository
import
chat.rocket.common.model.Token
import
com.squareup.moshi.Moshi
import
timber.log.Timber
class
SharedPreferencesTokenRepository
(
private
val
prefs
:
SharedPreferences
,
moshi
:
Moshi
)
:
TokenRepository
{
private
var
servers
=
prefs
.
getStringSet
(
KEY_SERVERS
,
emptySet
()).
toMutableSet
()
private
var
currentUrl
:
String
?
=
null
private
var
currentToken
:
Token
?
=
null
private
val
adapter
=
moshi
.
adapter
<
TokenModel
>(
TokenModel
::
class
.
java
)
override
fun
get
(
url
:
String
):
Token
?
{
if
(
currentToken
!=
null
&&
url
==
currentUrl
)
{
return
currentToken
}
try
{
prefs
.
getString
(
tokenKey
(
url
),
null
)
?.
let
{
tokenStr
->
val
model
=
adapter
.
fromJson
(
tokenStr
)
model
?.
let
{
val
token
=
Token
(
model
.
userId
,
model
.
authToken
)
currentToken
=
token
currentUrl
=
url
}
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error parsing token for ${tokenKey(url)}"
)
ex
.
printStackTrace
()
}
return
currentToken
}
override
fun
save
(
url
:
String
,
token
:
Token
)
{
try
{
val
model
=
TokenModel
(
token
.
userId
,
token
.
authToken
)
val
str
=
adapter
.
toJson
(
model
)
servers
.
add
(
url
)
prefs
.
edit
{
putString
(
tokenKey
(
url
),
str
)
putStringSet
(
KEY_SERVERS
,
servers
)
}
currentToken
=
token
currentUrl
=
url
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error saving token for ${tokenKey(url)}"
)
ex
.
printStackTrace
()
}
}
override
fun
remove
(
url
:
String
)
{
servers
.
remove
(
url
)
prefs
.
edit
{
remove
(
url
)
putStringSet
(
KEY_SERVERS
,
servers
)
}
}
override
fun
clear
()
{
servers
.
forEach
{
server
->
prefs
.
edit
{
remove
(
server
)
}
}
servers
.
clear
()
prefs
.
edit
{
remove
(
KEY_SERVERS
)
}
}
private
fun
tokenKey
(
url
:
String
)
=
"$KEY_TOKEN$url"
}
private
const
val
KEY_TOKEN
=
"KEY_TOKEN_"
private
const
val
KEY_SERVERS
=
"KEY_SERVERS"
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
View file @
4505780c
package
chat.rocket.android.authentication.login.presentation
import
chat.rocket.android.authentication.domain.model.TokenModel
import
chat.rocket.android.authentication.domain.model.toToken
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.NetworkHelper
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.main.viewmodel.NavHeaderViewModel
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.generateRandomString
import
chat.rocket.android.util.extensions.isEmailValid
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.registerPushToken
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatTwoFactorException
import
chat.rocket.common.util.ifNull
...
...
@@ -26,12 +27,13 @@ import javax.inject.Inject
class
LoginPresenter
@Inject
constructor
(
private
val
view
:
LoginView
,
private
val
strategy
:
CancelStrategy
,
private
val
navigator
:
AuthenticationNavigator
,
private
val
multiServerRepository
:
MultiServer
TokenRepository
,
private
val
tokenRepository
:
TokenRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
private
val
settingsInteractor
:
GetSettingsInteractor
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
factory
:
RocketChatClientFactory
)
{
private
val
factory
:
RocketChatClientFactory
)
{
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
...
...
@@ -198,16 +200,17 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
fun
signup
()
=
navigator
.
toSignUp
()
private
suspend
fun
saveToken
(
server
:
String
,
tokenModel
:
TokenModel
,
username
:
String
?)
{
multiServerRepository
.
save
(
server
,
tokenModel
)
localRepository
.
save
(
LocalRepository
.
USERNAME_KEY
,
username
)
localRepository
.
save
(
LocalRepository
.
CURRENT_USERNAME_KEY
,
username
)
tokenRepository
.
save
(
server
,
tokenModel
.
toToken
()
)
registerPushToken
()
}
private
suspend
fun
registerPushToken
()
{
localRepository
.
get
(
LocalRepository
.
KEY_PUSH_TOKEN
)
?.
let
{
client
.
registerPushToken
(
it
)
client
.
registerPushToken
(
it
,
getAccountsInteractor
.
get
(),
factory
)
}
// TODO: Schedule push token registering when it comes up null
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
private
suspend
fun
saveAccount
(
me
:
Myself
)
{
...
...
app/src/main/java/chat/rocket/android/authentication/presentation/AuthenticationPresenter.kt
View file @
4505780c
package
chat.rocket.android.authentication.presentation
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.GetAccountInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.MultiServerTokenRepository
import
chat.rocket.android.server.domain.SettingsRepository
import
chat.rocket.android.server.infraestructure.ConnectionManager
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.common.model.Token
import
chat.rocket.core.TokenRepository
import
chat.rocket.android.server.domain.TokenRepository
import
javax.inject.Inject
class
AuthenticationPresenter
@Inject
constructor
(
private
val
navigator
:
AuthenticationNavigator
,
class
AuthenticationPresenter
@Inject
constructor
(
private
val
navigator
:
AuthenticationNavigator
,
private
val
getCurrentServerInteractor
:
GetCurrentServerInteractor
,
private
val
multiServerRepository
:
MultiServerTokenRepository
,
private
val
getAccountInteractor
:
GetAccountInteractor
,
private
val
settingsRepository
:
SettingsRepository
,
private
val
tokenRepository
:
TokenRepository
)
{
fun
loadCredentials
(
newServer
:
Boolean
,
callback
:
(
authenticated
:
Boolean
)
->
Unit
)
{
private
val
localRepository
:
LocalRepository
,
private
val
tokenRepository
:
TokenRepository
)
{
suspend
fun
loadCredentials
(
newServer
:
Boolean
,
callback
:
(
authenticated
:
Boolean
)
->
Unit
)
{
val
currentServer
=
getCurrentServerInteractor
.
get
()
val
serverToken
=
currentServer
?.
let
{
multiServer
Repository
.
get
(
currentServer
)
}
val
serverToken
=
currentServer
?.
let
{
token
Repository
.
get
(
currentServer
)
}
val
settings
=
currentServer
?.
let
{
settingsRepository
.
get
(
currentServer
)
}
val
account
=
currentServer
?.
let
{
getAccountInteractor
.
get
(
currentServer
)
}
account
?.
let
{
localRepository
.
save
(
LocalRepository
.
CURRENT_USERNAME_KEY
,
account
.
userName
)
}
if
(
newServer
||
currentServer
==
null
||
serverToken
==
null
||
settings
==
null
)
{
callback
(
false
)
}
else
{
tokenRepository
.
save
(
Token
(
serverToken
.
userId
,
serverToken
.
authToken
))
callback
(
true
)
navigator
.
toChatList
()
}
...
...
app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt
View file @
4505780c
...
...
@@ -62,7 +62,7 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
// TODO This function returns a user token so should we save it?
client
.
login
(
username
,
password
)
val
me
=
client
.
me
()
localRepository
.
save
(
LocalRepository
.
USERNAME_KEY
,
me
.
username
)
localRepository
.
save
(
LocalRepository
.
CURRENT_
USERNAME_KEY
,
me
.
username
)
saveAccount
(
me
)
registerPushToken
()
navigator
.
toChatList
()
...
...
app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt
View file @
4505780c
package
chat.rocket.android.authentication.twofactor.presentation
import
chat.rocket.android.authentication.domain.model.TokenModel
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.NetworkHelper
...
...
@@ -10,24 +9,25 @@ import chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.registerPushToken
import
chat.rocket.common.RocketChatAuthException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.login
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.registerPushToken
import
chat.rocket.core.model.Myself
import
javax.inject.Inject
class
TwoFAPresenter
@Inject
constructor
(
private
val
view
:
TwoFAView
,
private
val
strategy
:
CancelStrategy
,
private
val
navigator
:
AuthenticationNavigator
,
private
val
multiServerRepository
:
MultiServer
TokenRepository
,
private
val
tokenRepository
:
TokenRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
factory
:
RocketChatClientFactory
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
settingsInteractor
:
GetSettingsInteractor
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
...
...
@@ -54,10 +54,7 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
client
.
login
(
usernameOrEmail
,
password
,
twoFactorAuthenticationCode
)
val
me
=
client
.
me
()
saveAccount
(
me
)
multiServerRepository
.
save
(
server
,
TokenModel
(
token
.
userId
,
token
.
authToken
)
)
tokenRepository
.
save
(
server
,
token
)
registerPushToken
()
navigator
.
toChatList
()
}
catch
(
exception
:
RocketChatException
)
{
...
...
@@ -85,9 +82,10 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
private
suspend
fun
registerPushToken
()
{
localRepository
.
get
(
LocalRepository
.
KEY_PUSH_TOKEN
)
?.
let
{
client
.
registerPushToken
(
it
)
client
.
registerPushToken
(
it
,
getAccountsInteractor
.
get
(),
factory
)
}
// TODO: Schedule push token registering when it comes up null
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
private
suspend
fun
saveAccount
(
me
:
Myself
)
{
...
...
app/src/main/java/chat/rocket/android/authentication/ui/AuthenticationActivity.kt
View file @
4505780c
...
...
@@ -9,29 +9,39 @@ import chat.rocket.android.R
import
chat.rocket.android.authentication.presentation.AuthenticationPresenter
import
chat.rocket.android.authentication.server.ui.ServerFragment
import
chat.rocket.android.util.extensions.addFragment
import
chat.rocket.android.util.extensions.launchUI
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjector
import
dagger.android.DispatchingAndroidInjector
import
dagger.android.support.HasSupportFragmentInjector
import
kotlinx.coroutines.experimental.Job
import
kotlinx.coroutines.experimental.android.UI
import
kotlinx.coroutines.experimental.launch
import
javax.inject.Inject
class
AuthenticationActivity
:
AppCompatActivity
(),
HasSupportFragmentInjector
{
@Inject
lateinit
var
fragmentDispatchingAndroidInjector
:
DispatchingAndroidInjector
<
Fragment
>
@Inject
lateinit
var
presenter
:
AuthenticationPresenter
val
job
=
Job
()
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
AndroidInjection
.
inject
(
this
)
val
newServer
=
intent
.
getBooleanExtra
(
INTENT_ADD_NEW_SERVER
,
fals
e
)
super
.
onCreate
(
savedInstanceStat
e
)
launch
(
UI
+
job
)
{
val
newServer
=
intent
.
getBooleanExtra
(
INTENT_ADD_NEW_SERVER
,
false
)
presenter
.
loadCredentials
(
newServer
)
{
authenticated
->
if
(
authenticated
)
{
// just call onCreate, and the presenter will call the navigator...
super
.
onCreate
(
savedInstanceState
)
}
else
{
if
(!
authenticated
)
{
showServerInput
(
savedInstanceState
)
}
}
}
}
override
fun
onDestroy
()
{
job
.
cancel
()
super
.
onDestroy
()
}
override
fun
supportFragmentInjector
():
AndroidInjector
<
Fragment
>
{
return
fragmentDispatchingAndroidInjector
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageReactionsAdapter.kt
View file @
4505780c
...
...
@@ -97,7 +97,7 @@ class MessageReactionsAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>()
val
countTextView
=
findViewById
<
TextView
>(
R
.
id
.
text_count
)
emojiTextView
.
text
=
reaction
.
unicode
countTextView
.
text
=
reaction
.
count
.
toString
()
val
myself
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
val
myself
=
localRepository
.
get
(
LocalRepository
.
CURRENT_
USERNAME_KEY
)
if
(
reaction
.
usernames
.
contains
(
myself
))
{
val
context
=
itemView
.
context
val
resources
=
context
.
resources
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
4505780c
...
...
@@ -361,7 +361,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
try
{
val
members
=
client
.
getMembers
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
50
).
result
usersRepository
.
saveAll
(
members
)
val
self
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
val
self
=
localRepository
.
get
(
LocalRepository
.
CURRENT_
USERNAME_KEY
)
// Take at most the 100 most recent messages distinguished by user. Can return less.
val
recentMessages
=
messagesRepository
.
getRecentMessages
(
chatRoomId
,
100
)
.
filterNot
{
filterSelfOut
&&
it
.
sender
?.
username
==
self
}
...
...
@@ -408,7 +408,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
if
(
users
.
isNotEmpty
())
{
usersRepository
.
saveAll
(
users
)
}
val
self
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
val
self
=
localRepository
.
get
(
LocalRepository
.
CURRENT_
USERNAME_KEY
)
view
.
populatePeopleSuggestions
(
users
.
map
{
val
username
=
it
.
username
?:
""
val
name
=
it
.
name
?:
""
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
View file @
4505780c
...
...
@@ -15,7 +15,6 @@ import chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.core.TokenRepository
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.MessageType
import
chat.rocket.core.model.Value
...
...
@@ -23,6 +22,7 @@ import chat.rocket.core.model.attachment.*
import
chat.rocket.core.model.isSystemMessage
import
chat.rocket.core.model.url.Url
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.launch
import
kotlinx.coroutines.experimental.withContext
import
okhttp3.HttpUrl
import
timber.log.Timber
...
...
@@ -32,15 +32,17 @@ import javax.inject.Inject
class
ViewModelMapper
@Inject
constructor
(
private
val
context
:
Context
,
private
val
parser
:
MessageParser
,
private
val
messagesRepository
:
MessagesRepository
,
private
val
getAccountInteractor
:
GetAccountInteractor
,
tokenRepository
:
TokenRepository
,
localRepository
:
LocalRepository
,
serverInteractor
:
GetCurrentServerInteractor
,
getSettingsInteractor
:
GetSettingsInteractor
)
{
getSettingsInteractor
:
GetSettingsInteractor
,
localRepository
:
LocalRepository
)
{
private
var
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
serverInteractor
.
get
()
!!
)
!!
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
settings
:
Map
<
String
,
Value
<
Any
>>
=
getSettingsInteractor
.
get
(
currentServer
)
private
val
baseUrl
=
settings
.
baseUrl
()
private
val
currentUsername
:
String
?
=
localRepository
.
get
(
LocalRepository
.
USERNAME_KEY
)
private
val
token
=
tokenRepository
.
get
(
)
private
val
token
=
tokenRepository
.
get
(
currentServer
)
private
val
currentUsername
:
String
?
=
localRepository
.
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
suspend
fun
map
(
message
:
Message
):
List
<
BaseViewModel
<*
>>
{
return
translate
(
message
)
...
...
@@ -249,6 +251,7 @@ class ViewModelMapper @Inject constructor(private val context: Context,
val
quoteMessage
:
Message
=
quote
quoteViewModel
=
mapMessage
(
quoteMessage
)
}
return
parser
.
renderMarkdown
(
message
.
message
,
quoteViewModel
,
currentUsername
)
}
...
...
app/src/main/java/chat/rocket/android/dagger/AppComponent.kt
View file @
4505780c
...
...
@@ -4,6 +4,7 @@ import android.app.Application
import
chat.rocket.android.app.RocketChatApplication
import
chat.rocket.android.dagger.module.ActivityBuilder
import
chat.rocket.android.dagger.module.AppModule
import
chat.rocket.android.dagger.module.ReceiverBuilder
import
chat.rocket.android.dagger.module.ServiceBuilder
import
chat.rocket.android.push.FirebaseTokenService
import
dagger.BindsInstance
...
...
@@ -12,7 +13,8 @@ import dagger.android.support.AndroidSupportInjectionModule
import
javax.inject.Singleton
@Singleton
@Component
(
modules
=
[
AndroidSupportInjectionModule
::
class
,
AppModule
::
class
,
ActivityBuilder
::
class
,
ServiceBuilder
::
class
])
@Component
(
modules
=
[
AndroidSupportInjectionModule
::
class
,
AppModule
::
class
,
ActivityBuilder
::
class
,
ServiceBuilder
::
class
,
ReceiverBuilder
::
class
])
interface
AppComponent
{
@Component
.
Builder
...
...
app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt
View file @
4505780c
package
chat.rocket.android.dagger.module
import
android.app.Application
import
android.app.NotificationManager
import
android.arch.persistence.room.Room
import
android.content.Context
import
android.content.SharedPreferences
import
androidx.content.systemService
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.app.RocketChatDatabase
import
chat.rocket.android.authentication.infraestructure.
Memory
TokenRepository
import
chat.rocket.android.authentication.infraestructure.
SharedPreferences
TokenRepository
import
chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository
import
chat.rocket.android.dagger.qualifier.ForFresco
import
chat.rocket.android.helper.FrescoAuthInterceptor
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.SharedPrefsLocalRepository
import
chat.rocket.android.push.GroupedPush
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.*
import
chat.rocket.android.util.AppJsonAdapterFactory
import
chat.rocket.android.util.TimberLogger
import
chat.rocket.common.internal.FallbackSealedClassJsonAdapter
import
chat.rocket.common.util.PlatformLogger
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.TokenRepository
import
com.facebook.drawee.backends.pipeline.DraweeConfig
import
com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory
import
com.facebook.imagepipeline.core.ImagePipelineConfig
...
...
@@ -110,8 +113,8 @@ class AppModule {
@Provides
@ForFresco
@Singleton
fun
provideFrescoAuthIntercepter
(
tokenRepository
:
TokenRepository
):
Interceptor
{
return
FrescoAuthInterceptor
(
tokenRepository
)
fun
provideFrescoAuthIntercepter
(
tokenRepository
:
TokenRepository
,
currentServerInteractor
:
GetCurrentServerInteractor
):
Interceptor
{
return
FrescoAuthInterceptor
(
tokenRepository
,
currentServerInteractor
)
}
@Provides
...
...
@@ -144,8 +147,8 @@ class AppModule {
@Provides
@Singleton
fun
provideTokenRepository
():
TokenRepository
{
return
MemoryTokenRepository
(
)
fun
provideTokenRepository
(
prefs
:
SharedPreferences
,
moshi
:
Moshi
):
TokenRepository
{
return
SharedPreferencesTokenRepository
(
prefs
,
moshi
)
}
@Provides
...
...
@@ -192,7 +195,10 @@ class AppModule {
@Provides
@Singleton
fun
provideMoshi
():
Moshi
{
return
Moshi
.
Builder
().
add
(
AppJsonAdapterFactory
.
INSTANCE
).
build
()
return
Moshi
.
Builder
()
.
add
(
FallbackSealedClassJsonAdapter
.
ADAPTER_FACTORY
)
.
add
(
AppJsonAdapterFactory
.
INSTANCE
)
.
build
()
}
@Provides
...
...
@@ -245,4 +251,11 @@ class AppModule {
@Singleton
fun
provideAccountsRepository
(
preferences
:
SharedPreferences
,
moshi
:
Moshi
):
AccountsRepository
=
SharedPreferencesAccountsRepository
(
preferences
,
moshi
)
@Provides
fun
provideNotificationManager
(
context
:
Context
):
NotificationManager
=
context
.
systemService
()
@Provides
@Singleton
fun
provideGroupedPush
()
=
GroupedPush
()
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/dagger/module/ReceiverBuilder.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.dagger.module
import
chat.rocket.android.push.DeleteReceiver
import
chat.rocket.android.push.di.DeleteReceiverProvider
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
@Module
abstract
class
ReceiverBuilder
{
@ContributesAndroidInjector
(
modules
=
[
DeleteReceiverProvider
::
class
])
abstract
fun
bindDeleteReceiver
():
DeleteReceiver
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/dagger/module/ServiceBuilder.kt
View file @
4505780c
package
chat.rocket.android.dagger.module
import
chat.rocket.android.push.FirebaseTokenService
import
chat.rocket.android.push.GcmListenerService
import
chat.rocket.android.push.di.FirebaseTokenServiceProvider
import
chat.rocket.android.push.di.GcmListenerServiceProvider
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
...
...
@@ -9,4 +11,7 @@ import dagger.android.ContributesAndroidInjector
@ContributesAndroidInjector
(
modules
=
[
FirebaseTokenServiceProvider
::
class
])
abstract
fun
bindFirebaseTokenService
():
FirebaseTokenService
@ContributesAndroidInjector
(
modules
=
[
GcmListenerServiceProvider
::
class
])
abstract
fun
bindGcmListenerService
():
GcmListenerService
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/helper/FrescoAuthInterceptor.kt
View file @
4505780c
package
chat.rocket.android.helper
import
chat.rocket.core.TokenRepository
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.TokenRepository
import
okhttp3.Interceptor
import
okhttp3.Response
class
FrescoAuthInterceptor
(
private
val
tokenRepository
:
TokenRepository
)
:
Interceptor
{
class
FrescoAuthInterceptor
(
private
val
tokenRepository
:
TokenRepository
,
private
val
currentServerInteractor
:
GetCurrentServerInteractor
)
:
Interceptor
{
override
fun
intercept
(
chain
:
Interceptor
.
Chain
):
Response
{
val
token
=
tokenRepository
.
get
()
var
request
=
chain
.
request
()
currentServerInteractor
.
get
()
?.
let
{
serverUrl
->
val
token
=
tokenRepository
.
get
(
serverUrl
)
token
?.
let
{
return
@let
token
?.
let
{
val
url
=
request
.
url
().
newBuilder
().
apply
{
addQueryParameter
(
"rc_uid"
,
token
.
userId
)
addQueryParameter
(
"rc_token"
,
token
.
authToken
)
...
...
@@ -18,7 +24,7 @@ class FrescoAuthInterceptor(private val tokenRepository: TokenRepository) : Inte
url
(
url
)
}.
build
()
}
}
return
chain
.
proceed
(
request
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/infrastructure/LocalRepository.kt
View file @
4505780c
...
...
@@ -6,7 +6,7 @@ interface LocalRepository {
const
val
KEY_PUSH_TOKEN
=
"KEY_PUSH_TOKEN"
const
val
TOKEN_KEY
=
"token_"
const
val
SETTINGS_KEY
=
"settings_"
const
val
USERNAME_KEY
=
"my_username
"
const
val
CURRENT_USERNAME_KEY
=
"username_
"
}
fun
save
(
key
:
String
,
value
:
String
?)
...
...
app/src/main/java/chat/rocket/android/infrastructure/SharedPrefsLocalRepository.kt
View file @
4505780c
...
...
@@ -20,6 +20,6 @@ class SharedPrefsLocalRepository(private val preferences: SharedPreferences) : L
clear
(
LocalRepository
.
KEY_PUSH_TOKEN
)
clear
(
LocalRepository
.
TOKEN_KEY
+
server
)
clear
(
LocalRepository
.
SETTINGS_KEY
+
server
)
clear
(
LocalRepository
.
USERNAME_KEY
+
server
)
clear
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
4505780c
...
...
@@ -10,28 +10,32 @@ import chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.registerPushToken
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.logout
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.registerPushToken
import
chat.rocket.core.internal.rest.unregisterPushToken
import
timber.log.Timber
import
javax.inject.Inject
class
MainPresenter
@Inject
constructor
(
private
val
view
:
MainView
,
class
MainPresenter
@Inject
constructor
(
private
val
view
:
MainView
,
private
val
strategy
:
CancelStrategy
,
private
val
navigator
:
MainNavigator
,
private
val
multiServerRepository
:
MultiServer
TokenRepository
,
private
val
tokenRepository
:
TokenRepository
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
localRepository
:
LocalRepository
,
private
val
navHeaderMapper
:
NavHeaderViewModelMapper
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
private
val
removeAccountInterector
:
RemoveAccountInterector
,
private
val
factory
:
RocketChatClientFactory
,
getSettingsInteractor
:
GetSettingsInteractor
,
managerFactory
:
ConnectionManagerFactory
,
factory
:
RocketChatClientFactory
)
{
managerFactory
:
ConnectionManagerFactory
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
manager
=
managerFactory
.
create
(
currentServer
)
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
...
...
@@ -79,7 +83,7 @@ class MainPresenter @Inject constructor(private val view: MainView,
client
.
logout
()
disconnect
()
removeAccountInterector
.
remove
(
currentServer
)
multiServerRepository
.
clear
(
currentServer
)
tokenRepository
.
remove
(
currentServer
)
navigator
.
toNewServer
()
}
catch
(
exception
:
RocketChatException
)
{
exception
.
message
?.
let
{
...
...
@@ -120,4 +124,10 @@ class MainPresenter @Inject constructor(private val view: MainView,
fun
addNewServer
()
{
navigator
.
toServerScreen
()
}
suspend
fun
refreshToken
(
token
:
String
?)
{
token
?.
let
{
client
.
registerPushToken
(
it
,
getAccountsInteractor
.
get
(),
factory
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
View file @
4505780c
package
chat.rocket.android.main.ui
import
android.app.Activity
import
android.content.Intent
import
android.os.Bundle
import
android.support.v4.app.Fragment
import
android.support.v7.app.AppCompatActivity
...
...
@@ -10,7 +9,6 @@ import android.view.Gravity
import
android.view.MenuItem
import
android.view.View
import
chat.rocket.android.R
import
chat.rocket.android.authentication.ui.AuthenticationActivity
import
chat.rocket.android.main.adapter.AccountSelector
import
chat.rocket.android.main.adapter.AccountsAdapter
import
chat.rocket.android.main.presentation.MainPresenter
...
...
@@ -21,6 +19,8 @@ import chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeOut
import
chat.rocket.android.util.extensions.rotateBy
import
chat.rocket.android.util.extensions.showToast
import
com.google.android.gms.gcm.GoogleCloudMessaging
import
com.google.android.gms.iid.InstanceID
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjector
import
dagger.android.DispatchingAndroidInjector
...
...
@@ -29,6 +29,8 @@ import dagger.android.support.HasSupportFragmentInjector
import
kotlinx.android.synthetic.main.activity_main.*
import
kotlinx.android.synthetic.main.app_bar.*
import
kotlinx.android.synthetic.main.nav_header.view.*
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.launch
import
timber.log.Timber
import
javax.inject.Inject
...
...
@@ -43,6 +45,12 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_main
)
launch
(
CommonPool
)
{
val
token
=
InstanceID
.
getInstance
(
this
@MainActivity
).
getToken
(
getString
(
R
.
string
.
gcm_sender_id
),
GoogleCloudMessaging
.
INSTANCE_ID_SCOPE
,
null
)
Timber
.
d
(
"GCM token: $token"
)
presenter
.
refreshToken
(
token
)
}
presenter
.
connect
()
presenter
.
loadCurrentInfo
()
setupToolbar
()
...
...
app/src/main/java/chat/rocket/android/push/DeleteReceiver.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.push
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
dagger.android.AndroidInjection
import
javax.inject.Inject
/**
* BroadcastReceiver for dismissed notifications.
*/
class
DeleteReceiver
:
BroadcastReceiver
()
{
@Inject
lateinit
var
groupedPushes
:
GroupedPush
override
fun
onReceive
(
context
:
Context
,
intent
:
Intent
)
{
AndroidInjection
.
inject
(
this
,
context
)
val
notId
=
intent
.
extras
?.
getInt
(
EXTRA_NOT_ID
)
val
host
=
intent
.
extras
?.
getString
(
EXTRA_HOSTNAME
)
if
(
host
!=
null
&&
notId
!=
null
)
{
clearNotificationsByHostAndNotificationId
(
host
,
notId
)
}
}
/**
* Clear notifications by the host they belong to and its unique id.
*/
fun
clearNotificationsByHostAndNotificationId
(
host
:
String
,
notificationId
:
Int
)
{
if
(
groupedPushes
.
hostToPushMessageList
.
isNotEmpty
())
{
val
notifications
=
groupedPushes
.
hostToPushMessageList
[
host
]
notifications
?.
let
{
notifications
.
removeAll
{
it
.
notificationId
.
toInt
()
==
notificationId
}
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/FirebaseTokenService.kt
View file @
4505780c
...
...
@@ -2,6 +2,8 @@ package chat.rocket.android.push
import
chat.rocket.android.R
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.registerPushToken
...
...
@@ -16,14 +18,16 @@ import javax.inject.Inject
class
FirebaseTokenService
:
FirebaseInstanceIdService
()
{
@Inject
lateinit
var
client
:
RocketChatClient
lateinit
var
factory
:
RocketChatClientFactory
@Inject
lateinit
var
getCurrentServerInteractor
:
GetCurrentServerInteractor
@Inject
lateinit
var
localRepository
:
LocalRepository
override
fun
onCreate
()
{
super
.
onCreate
()
AndroidInjection
.
inject
(
this
)
;
AndroidInjection
.
inject
(
this
)
}
override
fun
onTokenRefresh
()
{
...
...
@@ -31,11 +35,14 @@ class FirebaseTokenService : FirebaseInstanceIdService() {
// default push gateway. We should register this project's own project sender id into it.
val
gcmToken
=
InstanceID
.
getInstance
(
this
)
.
getToken
(
getString
(
R
.
string
.
gcm_sender_id
),
GoogleCloudMessaging
.
INSTANCE_ID_SCOPE
,
null
)
val
currentServer
=
getCurrentServerInteractor
.
get
()
!!
val
client
=
factory
.
create
(
currentServer
)
gcmToken
?.
let
{
localRepository
.
save
(
LocalRepository
.
KEY_PUSH_TOKEN
,
gcmToken
)
launch
{
try
{
Timber
.
d
(
"Registering push token: $gcmToken for ${client.url}"
)
client
.
registerPushToken
(
gcmToken
)
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
...
...
app/src/main/java/chat/rocket/android/push/GcmListenerService.kt
View file @
4505780c
...
...
@@ -2,12 +2,22 @@ package chat.rocket.android.push
import
android.os.Bundle
import
com.google.android.gms.gcm.GcmListenerService
import
dagger.android.AndroidInjection
import
javax.inject.Inject
class
GcmListenerService
:
GcmListenerService
()
{
@Inject
lateinit
var
pushManager
:
PushManager
override
fun
onCreate
()
{
super
.
onCreate
()
AndroidInjection
.
inject
(
this
)
}
override
fun
onMessageReceived
(
from
:
String
?,
data
:
Bundle
?)
{
data
?.
let
{
PushManager
.
handle
(
this
,
data
)
pushManager
.
handle
(
data
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/GroupedPush.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.push
import
java.util.concurrent.atomic.AtomicInteger
import
javax.inject.Singleton
typealias
TupleGroupIdMessageCount
=
Pair
<
Int
,
AtomicInteger
>
class
GroupedPush
{
// Notifications received from the same server are grouped in a single bundled notification.
// This map associates a host to a group id.
val
groupMap
=
HashMap
<
String
,
TupleGroupIdMessageCount
>()
// Map a hostname to a list of push messages that pertain to it.
val
hostToPushMessageList
=
HashMap
<
String
,
MutableList
<
PushMessage
>>()
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/PushManager.kt
View file @
4505780c
...
...
@@ -5,7 +5,6 @@ import android.app.Notification
import
android.app.NotificationChannel
import
android.app.NotificationManager
import
android.app.PendingIntent
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
android.media.RingtoneManager
...
...
@@ -17,36 +16,34 @@ import android.support.v4.app.NotificationManagerCompat
import
android.support.v4.app.RemoteInput
import
android.text.Html
import
android.text.Spanned
import
android.util.Log
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.main.ui.MainActivity
import
org.json.JSONObject
import
java.io.Serializable
import
chat.rocket.android.server.domain.GetAccountInteractor
import
chat.rocket.android.server.domain.GetSettingsInteractor
import
chat.rocket.android.server.domain.siteName
import
chat.rocket.android.server.ui.changeServerIntent
import
chat.rocket.common.model.RoomType
import
com.squareup.moshi.Json
import
com.squareup.moshi.Moshi
import
kotlinx.coroutines.experimental.runBlocking
import
se.ansman.kotshi.JsonSerializable
import
timber.log.Timber
import
java.util.*
import
java.util.concurrent.atomic.AtomicInteger
import
kotlin.collections.HashMap
typealias
TupleGroupIdMessageCount
=
Pair
<
Int
,
AtomicInteger
>
import
javax.inject.Inject
/**
* Refer to: https://github.com/RocketChat/Rocket.Chat.Android/blob/9e846b7fde8fe0c74b9e0117c37ce49293308db5/app/src/main/java/chat/rocket/android/push/PushManager.kt
* for old source code.
*/
object
PushManager
{
const
val
EXTRA_NOT_ID
=
"chat.rocket.android.EXTRA_NOT_ID"
const
val
EXTRA_HOSTNAME
=
"chat.rocket.android.EXTRA_HOSTNAME"
const
val
EXTRA_PUSH_MESSAGE
=
"chat.rocket.android.EXTRA_PUSH_MESSAGE"
const
val
EXTRA_ROOM_ID
=
"chat.rocket.android.EXTRA_ROOM_ID"
private
const
val
REPLY_LABEL
=
"REPLY"
private
const
val
REMOTE_INPUT_REPLY
=
"REMOTE_INPUT_REPLY"
// Notifications received from the same server are grouped in a single bundled notification.
// This map associates a host to a group id.
private
val
groupMap
=
HashMap
<
String
,
TupleGroupIdMessageCount
>()
// Map a hostname to a list of push messages that pertain to it.
private
val
hostToPushMessageList
=
HashMap
<
String
,
MutableList
<
PushMessage
>>()
class
PushManager
@Inject
constructor
(
private
val
groupedPushes
:
GroupedPush
,
private
val
manager
:
NotificationManager
,
private
val
moshi
:
Moshi
,
private
val
getAccountInteractor
:
GetAccountInteractor
,
private
val
getSettingsInteractor
:
GetSettingsInteractor
,
private
val
context
:
Context
)
{
private
val
randomizer
=
Random
()
/**
...
...
@@ -54,187 +51,108 @@ object PushManager {
* on the *data* param bundle received.
*/
@Synchronized
fun
handle
(
context
:
Context
,
data
:
Bundle
)
{
val
appContext
=
context
.
applicationContext
fun
handle
(
data
:
Bundle
)
=
runBlocking
{
val
message
=
data
[
"message"
]
as
String
?
val
image
=
data
[
"image"
]
as
String
?
val
ejson
=
data
[
"ejson"
]
as
String
?
val
title
=
data
[
"title"
]
as
String
?
val
notId
=
data
[
"notId"
]
as
String
?
?:
randomizer
.
nextInt
().
toString
()
val
image
=
data
[
"image"
]
as
String
?
val
style
=
data
[
"style"
]
as
String
?
val
summaryText
=
data
[
"summaryText"
]
as
String
?
val
count
=
data
[
"count"
]
as
String
?
val
title
=
data
[
"title"
]
as
String
?
if
(
ejson
==
null
||
message
==
null
||
title
==
null
)
{
return
}
try
{
val
adapter
=
moshi
.
adapter
<
PushInfo
>(
PushInfo
::
class
.
java
)
val
info
=
adapter
.
fromJson
(
ejson
)
val
lastPushMessage
=
PushMessage
(
title
,
message
,
image
,
ejson
,
count
,
notId
,
summaryText
,
style
)
val
pushMessage
=
PushMessage
(
title
!!
,
message
!!
,
info
!!
,
image
,
count
,
notId
,
summaryText
,
style
)
// We should use Timber here
if
(
BuildConfig
.
DEBUG
)
{
Log
.
d
(
PushMessage
::
class
.
java
.
simpleName
,
lastPushMessage
.
toString
())
}
showNotification
(
appContext
,
lastPushMessage
)
}
/**
* Clear all messages received to a given host the user is signed-in.
*/
fun
clearNotificationsByHost
(
host
:
String
)
{
hostToPushMessageList
.
remove
(
host
)
}
/**
* Remove a notification solely by it's unique id.
*/
fun
clearNotificationsByNotificationId
(
notificationId
:
Int
)
{
if
(
hostToPushMessageList
.
isNotEmpty
())
{
for
(
entry
in
hostToPushMessageList
.
entries
)
{
entry
.
value
.
removeAll
{
it
.
notificationId
.
toInt
()
==
notificationId
}
}
}
}
/**
* Clear notifications by the host they belong to and its unique id.
*/
fun
clearNotificationsByHostAndNotificationId
(
host
:
String
?,
notificationId
:
Int
?)
{
if
(
host
==
null
||
notificationId
==
null
)
{
return
}
if
(
hostToPushMessageList
.
isNotEmpty
())
{
val
notifications
=
hostToPushMessageList
[
host
]
notifications
?.
let
{
notifications
.
removeAll
{
it
.
notificationId
.
toInt
()
==
notificationId
}
}
}
}
Timber
.
d
(
"Received push message: $pushMessage"
)
private
fun
getGroupForHost
(
host
:
String
):
TupleGroupIdMessageCount
{
val
size
=
groupMap
.
size
var
group
=
groupMap
.
get
(
host
)
if
(
group
==
null
)
{
group
=
TupleGroupIdMessageCount
(
size
+
1
,
AtomicInteger
(
0
))
groupMap
.
put
(
host
,
group
)
showNotification
(
pushMessage
)
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error parsing PUSH message: $data"
)
ex
.
printStackTrace
()
}
return
group
}
@SuppressLint
(
"NewApi"
)
internal
fun
showNotification
(
context
:
Context
,
lastPushMessage
:
PushMessage
)
{
if
(
lastPushMessage
.
host
==
null
||
lastPushMessage
.
message
==
null
||
lastPushMessage
.
title
==
null
)
{
private
suspend
fun
showNotification
(
pushMessage
:
PushMessage
)
{
if
(!
hasAccount
(
pushMessage
.
info
.
host
))
{
Timber
.
d
(
"ignoring push message: $pushMessage"
)
return
}
val
manager
:
NotificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
val
notId
=
lastP
ushMessage
.
notificationId
.
toInt
()
val
host
=
lastPushMessage
.
host
val
notId
=
p
ushMessage
.
notificationId
.
toInt
()
val
host
=
pushMessage
.
info
.
host
val
groupTuple
=
getGroupForHost
(
host
)
groupTuple
.
second
.
incrementAndGet
()
val
notIdListForHostname
:
MutableList
<
PushMessage
>?
=
hostToPushMessageList
.
get
(
host
)
val
notIdListForHostname
:
MutableList
<
PushMessage
>?
=
groupedPushes
.
hostToPushMessageList
.
get
(
host
)
if
(
notIdListForHostname
==
null
)
{
hostToPushMessageList
.
put
(
host
,
arrayListOf
(
lastPushMessage
)
)
groupedPushes
.
hostToPushMessageList
[
host
]
=
arrayListOf
(
pushMessage
)
}
else
{
notIdListForHostname
.
add
(
0
,
lastPushMessage
)
}
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
N
)
{
val
notification
=
createSingleNotificationForNougatAndAbove
(
context
,
lastPushMessage
)
val
groupNotification
=
createGroupNotificationForNougatAndAbove
(
context
,
lastPushMessage
)
notification
?.
let
{
manager
.
notify
(
notId
,
notification
)
notIdListForHostname
.
add
(
0
,
pushMessage
)
}
groupNotification
?.
let
{
manager
.
notify
(
groupTuple
.
first
,
groupNotification
)
}
}
else
{
val
notification
=
createSingleNotification
(
context
,
lastPushMessage
)
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
val
notification
=
createSingleNotification
(
pushMessage
)
val
pushMessageList
=
groupedPushes
.
hostToPushMessageList
[
host
]
notification
?.
let
{
NotificationManagerCompat
.
from
(
context
)
.
notify
(
notId
,
notification
)
manager
.
notify
(
notId
,
notification
)
}
pushMessageList
?.
let
{
if
(
pushMessageList
.
size
>
1
)
{
val
groupNotification
=
createGroupNotification
(
context
,
lastP
ushMessage
)
val
groupNotification
=
createGroupNotification
(
p
ushMessage
)
groupNotification
?.
let
{
NotificationManagerCompat
.
from
(
context
).
notify
(
groupTuple
.
first
,
groupNotification
)
}
}
}
}
}
internal
fun
createGroupNotification
(
context
:
Context
,
lastPushMessage
:
PushMessage
):
Notification
?
{
with
(
lastPushMessage
)
{
if
(
host
==
null
||
message
==
null
||
title
==
null
)
{
return
null
private
fun
getGroupForHost
(
host
:
String
):
TupleGroupIdMessageCount
{
val
size
=
groupedPushes
.
groupMap
.
size
var
group
=
groupedPushes
.
groupMap
[
host
]
if
(
group
==
null
)
{
group
=
TupleGroupIdMessageCount
(
size
+
1
,
AtomicInteger
(
0
))
groupedPushes
.
groupMap
[
host
]
=
group
}
return
group
}
val
id
=
lastPushMessage
.
notificationId
.
toInt
()
val
contentIntent
=
getContentIntent
(
context
,
id
,
lastPushMessage
)
val
deleteIntent
=
getDismissIntent
(
context
,
lastPushMessage
)
val
builder
=
NotificationCompat
.
Builder
(
context
)
.
setWhen
(
createdAt
)
.
setContentTitle
(
title
.
fromHtml
())
.
setContentText
(
message
.
fromHtml
())
.
setGroup
(
host
)
.
setGroupSummary
(
true
)
.
setContentIntent
(
contentIntent
)
.
setDeleteIntent
(
deleteIntent
)
.
setMessageNotification
()
//TODO: Get Site_Name PublicSetting from cache
val
subText
=
"Rocket.Chat"
if
(
subText
.
isNotEmpty
())
{
builder
.
setSubText
(
subText
)
private
suspend
fun
hasAccount
(
host
:
String
):
Boolean
{
return
getAccountInteractor
.
get
(
host
)
!=
null
}
@SuppressLint
(
"NewApi"
)
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
private
fun
createGroupNotification
(
pushMessage
:
PushMessage
):
Notification
?
{
with
(
pushMessage
)
{
val
host
=
info
.
host
val
builder
=
createBaseNotificationBuilder
(
pushMessage
,
grouped
=
true
)
.
setGroupSummary
(
true
)
if
(
style
==
null
||
style
==
"inbox"
)
{
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
val
pushMessageList
=
groupedPushes
.
hostToPushMessageList
[
host
]
pushMessageList
?.
let
{
val
messageCount
=
pushMessageList
.
size
val
summary
=
summaryText
?.
replace
(
"%n%"
,
messageCount
.
toString
())
?.
fromHtml
()
?:
"$messageCount new messages"
builder
.
setNumber
(
messageCount
)
if
(
messageCount
>
1
)
{
val
firstPush
=
pushMessageList
[
0
]
val
singleConversation
=
pushMessageList
.
filter
{
firstPush
.
sender
?.
username
!=
it
.
sender
?.
username
}.
isEmpty
()
val
count
=
pushMessageList
.
filter
{
it
.
title
==
title
}.
size
builder
.
setContentTitle
(
getTitle
(
count
,
title
))
val
inbox
=
NotificationCompat
.
InboxStyle
()
.
setBigContentTitle
(
if
(
singleConversation
)
title
else
summary
)
.
setBigContentTitle
(
getTitle
(
count
,
title
)
)
for
(
push
in
pushMessageList
)
{
if
(
singleConversation
)
{
inbox
.
addLine
(
push
.
message
)
}
else
{
inbox
.
addLine
(
"<font color='black'>${push.title}</font> <font color='gray'>${push.message}</font>"
.
fromHtml
())
}
}
builder
.
setStyle
(
inbox
)
}
else
{
val
firstMsg
=
pushMessageList
[
0
]
if
(
firstMsg
.
host
==
null
||
firstMsg
.
message
==
null
||
firstMsg
.
title
==
null
)
{
return
null
}
val
bigText
=
NotificationCompat
.
BigTextStyle
()
.
bigText
(
firstMsg
.
message
.
fromHtml
())
.
setBigContentTitle
(
firstMsg
.
title
.
fromHtml
())
builder
.
setStyle
(
bigText
)
}
}
}
else
{
val
bigText
=
NotificationCompat
.
BigTextStyle
()
...
...
@@ -250,147 +168,69 @@ object PushManager {
@SuppressLint
(
"NewApi"
)
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
internal
fun
createGroupNotificationForNougatAndAbove
(
context
:
Context
,
lastPushMessage
:
PushMessage
):
Notification
?
{
with
(
lastPushMessage
)
{
if
(
host
==
null
||
message
==
null
||
title
==
null
)
{
return
null
}
val
manager
:
NotificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
val
id
=
notificationId
.
toInt
()
val
contentIntent
=
getContentIntent
(
context
,
id
,
lastPushMessage
,
grouped
=
true
)
val
deleteIntent
=
getDismissIntent
(
context
,
lastPushMessage
)
private
fun
createSingleNotification
(
pushMessage
:
PushMessage
):
Notification
?
{
with
(
pushMessage
)
{
val
host
=
info
.
host
val
builder
=
Notification
.
Builder
(
context
)
.
setWhen
(
createdAt
)
.
setContentTitle
(
title
.
fromHtml
())
.
setContentText
(
message
.
fromHtml
())
.
setGroup
(
host
)
.
setGroupSummary
(
true
)
.
setContentIntent
(
contentIntent
)
.
setDeleteIntent
(
deleteIntent
)
.
setMessageNotification
(
context
)
val
builder
=
createBaseNotificationBuilder
(
pushMessage
)
.
setGroupSummary
(
false
)
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
builder
.
setChannelId
(
host
)
val
groupChannel
=
NotificationChannel
(
host
,
host
,
NotificationManager
.
IMPORTANCE_HIGH
)
groupChannel
.
lockscreenVisibility
=
Notification
.
VISIBILITY_PUBLIC
groupChannel
.
enableLights
(
false
)
groupChannel
.
enableVibration
(
true
)
groupChannel
.
setShowBadge
(
true
)
manager
.
createNotificationChannel
(
groupChannel
)
}
if
(
style
==
null
||
"inbox"
==
style
)
{
val
pushMessageList
=
groupedPushes
.
hostToPushMessageList
.
get
(
host
)
//TODO: Get Site_Name PublicSetting from cache
val
subText
=
"Rocket.Chat"
if
(
subText
.
isNotEmpty
())
{
builder
.
setSubText
(
subText
)
pushMessageList
?.
let
{
val
userMessages
=
pushMessageList
.
filter
{
it
.
notificationId
==
pushMessage
.
notificationId
}
if
(
style
==
null
||
style
==
"inbox"
)
{
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
pushMessageList
?.
let
{
val
count
=
pushMessageList
.
filter
{
it
.
title
==
title
}.
size
builder
.
setContentTitle
(
getTitle
(
count
,
title
))
val
inbox
=
Notification
.
InboxStyle
()
.
setBigContentTitle
(
getTitle
(
count
,
title
)
)
for
(
push
in
pushMessageList
)
{
if
(
count
>
1
)
{
val
inbox
=
NotificationCompat
.
InboxStyle
(
)
inbox
.
setBigContentTitle
(
getTitle
(
count
,
title
))
for
(
push
in
userMessages
)
{
inbox
.
addLine
(
push
.
message
)
}
builder
.
setStyle
(
inbox
)
}
}
else
{
val
bigText
=
Notification
.
BigTextStyle
()
val
bigTextStyle
=
NotificationCompat
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
.
setBigContentTitle
(
title
.
fromHtml
())
builder
.
setStyle
(
bigText
)
}
return
builder
.
build
()
}
}
internal
fun
createSingleNotification
(
context
:
Context
,
lastPushMessage
:
PushMessage
):
Notification
?
{
with
(
lastPushMessage
)
{
if
(
host
==
null
||
message
==
null
||
title
==
null
)
{
return
null
}
val
id
=
notificationId
.
toInt
()
val
contentIntent
=
getContentIntent
(
context
,
id
,
lastPushMessage
)
val
deleteIntent
=
getDismissIntent
(
context
,
lastPushMessage
)
val
builder
=
NotificationCompat
.
Builder
(
context
)
.
setWhen
(
createdAt
)
.
setContentTitle
(
title
.
fromHtml
())
.
setContentText
(
message
.
fromHtml
())
.
setGroupSummary
(
false
)
.
setGroup
(
host
)
.
setDeleteIntent
(
deleteIntent
)
.
setContentIntent
(
contentIntent
)
.
setMessageNotification
()
//TODO: Get Site_Name PublicSetting from cache
val
subText
=
"Rocket.Chat"
if
(
subText
.
isNotEmpty
())
{
builder
.
setSubText
(
subText
)
builder
.
setStyle
(
bigTextStyle
)
}
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
pushMessageList
?.
let
{
val
lastPushMsg
=
pushMessageList
.
last
()
if
(
lastPushMsg
.
host
==
null
||
lastPushMsg
.
message
==
null
||
lastPushMsg
.
title
==
null
)
{
return
null
}
if
(
pushMessageList
.
isNotEmpty
())
{
val
messageCount
=
pushMessageList
.
size
val
bigText
=
NotificationCompat
.
BigTextStyle
()
.
bigText
(
lastPushMsg
.
message
.
fromHtml
())
.
setBigContentTitle
(
lastPushMsg
.
title
.
fromHtml
())
builder
.
setStyle
(
bigText
).
setNumber
(
messageCount
)
}
}
else
{
val
bigTextStyle
=
NotificationCompat
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
builder
.
setStyle
(
bigTextStyle
)
}
return
builder
.
build
()
}
}
@SuppressLint
(
"NewApi"
)
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
internal
fun
createSingleNotificationForNougatAndAbove
(
context
:
Context
,
lastPushMessage
:
PushMessage
):
Notification
?
{
val
manager
:
NotificationManager
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
with
(
lastPushMessage
)
{
if
(
host
==
null
||
message
==
null
||
title
==
null
)
{
return
null
}
@RequiresApi
(
Build
.
VERSION_CODES
.
O
)
private
fun
createBaseNotificationBuilder
(
pushMessage
:
PushMessage
,
grouped
:
Boolean
=
false
):
NotificationCompat
.
Builder
{
return
with
(
pushMessage
)
{
val
id
=
notificationId
.
toInt
()
val
contentIntent
=
getContentIntent
(
context
,
id
,
lastPushMessage
)
val
deleteIntent
=
getDismissIntent
(
context
,
lastPushMessage
)
val
host
=
info
.
host
val
contentIntent
=
getContentIntent
(
context
,
id
,
pushMessage
,
grouped
)
val
deleteIntent
=
getDismissIntent
(
context
,
pushMessage
)
val
builder
=
Notification
.
Builder
(
contex
t
)
.
setWhen
(
createdAt
)
val
builder
=
Notification
Compat
.
Builder
(
context
,
hos
t
)
.
setWhen
(
info
.
createdAt
)
.
setContentTitle
(
title
.
fromHtml
())
.
setContentText
(
message
.
fromHtml
())
.
setGroup
(
host
)
.
setGroupSummary
(
false
)
.
setDeleteIntent
(
deleteIntent
)
.
setContentIntent
(
contentIntent
)
.
setMessageNotification
(
context
)
.
addReplyAction
(
context
,
lastPushMessage
)
.
setMessageNotification
()
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
O
)
{
builder
.
setChannelId
(
host
)
val
channel
=
NotificationChannel
(
host
,
host
,
NotificationManager
.
IMPORTANCE_HIGH
)
channel
.
lockscreenVisibility
=
Notification
.
VISIBILITY_PUBLIC
channel
.
enableLights
(
false
)
...
...
@@ -400,47 +240,18 @@ object PushManager {
}
//TODO: Get Site_Name PublicSetting from cache
val
subText
=
"Rocket.Chat"
val
subText
=
getSiteName
(
host
)
if
(
subText
.
isNotEmpty
())
{
builder
.
setSubText
(
subText
)
}
if
(
style
==
null
||
"inbox"
==
style
)
{
val
pushMessageList
=
hostToPushMessageList
.
get
(
host
)
pushMessageList
?.
let
{
val
userMessages
=
pushMessageList
.
filter
{
it
.
notificationId
==
lastPushMessage
.
notificationId
}
val
count
=
pushMessageList
.
filter
{
it
.
title
==
title
}.
size
builder
.
setContentTitle
(
getTitle
(
count
,
title
))
if
(
count
>
1
)
{
val
inbox
=
Notification
.
InboxStyle
()
inbox
.
setBigContentTitle
(
getTitle
(
count
,
title
))
for
(
push
in
userMessages
)
{
inbox
.
addLine
(
push
.
message
)
}
builder
.
setStyle
(
inbox
)
}
else
{
val
bigTextStyle
=
Notification
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
builder
.
setStyle
(
bigTextStyle
)
}
return
@with
builder
}
}
else
{
val
bigTextStyle
=
Notification
.
BigTextStyle
()
.
bigText
(
message
.
fromHtml
())
builder
.
setStyle
(
bigTextStyle
)
}
return
builder
.
build
()
}
private
fun
getSiteName
(
host
:
String
):
String
{
val
settings
=
getSettingsInteractor
.
get
(
host
)
return
settings
.
siteName
()
?:
"Rocket.Chat"
}
private
fun
getTitle
(
messageCount
:
Int
,
title
:
String
):
CharSequence
{
...
...
@@ -450,18 +261,16 @@ object PushManager {
private
fun
getDismissIntent
(
context
:
Context
,
pushMessage
:
PushMessage
):
PendingIntent
{
val
deleteIntent
=
Intent
(
context
,
DeleteReceiver
::
class
.
java
)
.
putExtra
(
EXTRA_NOT_ID
,
pushMessage
.
notificationId
.
toInt
())
.
putExtra
(
EXTRA_HOSTNAME
,
pushMessage
.
host
)
.
putExtra
(
EXTRA_HOSTNAME
,
pushMessage
.
info
.
host
)
return
PendingIntent
.
getBroadcast
(
context
,
pushMessage
.
notificationId
.
toInt
(),
deleteIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
}
private
fun
getContentIntent
(
context
:
Context
,
notificationId
:
Int
,
pushMessage
:
PushMessage
,
grouped
:
Boolean
=
false
):
PendingIntent
{
val
notificationIntent
=
Intent
(
context
,
MainActivity
::
class
.
java
)
.
addFlags
(
Intent
.
FLAG_ACTIVITY_SINGLE_TOP
or
Intent
.
FLAG_ACTIVITY_CLEAR_TOP
)
.
putExtra
(
EXTRA_NOT_ID
,
notificationId
)
.
putExtra
(
EXTRA_HOSTNAME
,
pushMessage
.
host
)
if
(!
grouped
)
{
notificationIntent
.
putExtra
(
EXTRA_ROOM_ID
,
pushMessage
.
rid
)
}
val
notificationIntent
=
context
.
changeServerIntent
(
pushMessage
.
info
.
host
)
// TODO - add support to go directly to the chatroom
/*if (!grouped) {
notificationIntent.putExtra(EXTRA_ROOM_ID, pushMessage.info.roomId)
}*/
return
PendingIntent
.
getActivity
(
context
,
randomizer
.
nextInt
(),
notificationIntent
,
PendingIntent
.
FLAG_UPDATE_CURRENT
)
}
...
...
@@ -472,18 +281,18 @@ object PushManager {
//Notification.Builder extensions
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
private
fun
Notification
.
Builder
.
addReplyAction
(
ctx
:
Context
,
pushMessage
:
PushMessage
):
Notification
.
Builder
{
private
fun
Notification
.
Builder
.
addReplyAction
(
pushMessage
:
PushMessage
):
Notification
.
Builder
{
val
replyRemoteInput
=
android
.
app
.
RemoteInput
.
Builder
(
REMOTE_INPUT_REPLY
)
.
setLabel
(
REPLY_LABEL
)
.
build
()
//TODO: Implement this when we have sendMessage call
// val replyIntent = Intent(c
tx
, ReplyReceiver::class.java)
// val replyIntent = Intent(c
ontext
, ReplyReceiver::class.java)
// replyIntent.putExtra(EXTRA_PUSH_MESSAGE, pushMessage as Serializable)
// val pendingIntent = PendingIntent.getBroadcast(
// c
tx
, randomizer.nextInt(), replyIntent, 0)
// c
ontext
, randomizer.nextInt(), replyIntent, 0)
// val replyAction =
// Notification.Action.Builder(
// Icon.createWithResource(c
tx
, R.drawable.ic_reply), REPLY_LABEL, pendingIntent)
// Icon.createWithResource(c
ontext
, R.drawable.ic_reply), REPLY_LABEL, pendingIntent)
// .addRemoteInput(replyRemoteInput)
// .setAllowGeneratedReplies(true)
// .build()
...
...
@@ -491,25 +300,8 @@ object PushManager {
return
this
}
@RequiresApi
(
Build
.
VERSION_CODES
.
N
)
private
fun
Notification
.
Builder
.
setMessageNotification
(
ctx
:
Context
):
Notification
.
Builder
{
val
alarmSound
=
RingtoneManager
.
getDefaultUri
(
RingtoneManager
.
TYPE_NOTIFICATION
)
val
res
=
ctx
.
resources
val
smallIcon
=
res
.
getIdentifier
(
"rocket_chat_notification"
,
"drawable"
,
ctx
.
packageName
)
with
(
this
,
{
setAutoCancel
(
true
)
setShowWhen
(
true
)
setColor
(
res
.
getColor
(
R
.
color
.
colorPrimary
,
ctx
.
theme
))
setSmallIcon
(
smallIcon
)
setSound
(
alarmSound
)
})
return
this
}
// NotificationCompat.Builder extensions
private
fun
NotificationCompat
.
Builder
.
addReplyAction
(
pushMessage
:
PushMessage
):
NotificationCompat
.
Builder
{
val
context
=
this
.
mContext
val
replyRemoteInput
=
RemoteInput
.
Builder
(
REMOTE_INPUT_REPLY
)
.
setLabel
(
REPLY_LABEL
)
.
build
()
...
...
@@ -529,76 +321,66 @@ object PushManager {
private
fun
NotificationCompat
.
Builder
.
setMessageNotification
():
NotificationCompat
.
Builder
{
val
alarmSound
=
RingtoneManager
.
getDefaultUri
(
RingtoneManager
.
TYPE_NOTIFICATION
)
val
ctx
=
this
.
mContext
val
res
=
ctx
.
resources
val
res
=
context
.
resources
val
smallIcon
=
res
.
getIdentifier
(
"rocket_chat_notification"
,
"drawable"
,
c
tx
.
packageName
)
"rocket_chat_notification"
,
"drawable"
,
c
ontext
.
packageName
)
with
(
this
,
{
setAutoCancel
(
true
)
setShowWhen
(
true
)
color
=
c
tx
.
resources
.
getColor
(
R
.
color
.
colorPrimary
)
color
=
c
ontext
.
resources
.
getColor
(
R
.
color
.
colorPrimary
)
setDefaults
(
Notification
.
DEFAULT_ALL
)
setSmallIcon
(
smallIcon
)
setSound
(
alarmSound
)
})
return
this
}
}
internal
data class
PushMessage
(
val
title
:
String
?
=
null
,
val
message
:
String
?
=
null
,
data class
PushMessage
(
val
title
:
String
,
val
message
:
String
,
val
info
:
PushInfo
,
val
image
:
String
?
=
null
,
val
ejson
:
String
?
=
null
,
val
count
:
String
?
=
null
,
val
notificationId
:
String
,
val
summaryText
:
String
?
=
null
,
val
style
:
String
?
=
null
)
:
Serializable
{
val
host
:
String
?
val
rid
:
String
?
val
type
:
String
?
val
channelName
:
String
?
val
sender
:
Sender
?
val
style
:
String
?
=
null
)
@JsonSerializable
data class
PushInfo
(
@Json
(
name
=
"host"
)
val
hostname
:
String
,
@Json
(
name
=
"rid"
)
val
roomId
:
String
,
val
type
:
RoomType
,
val
name
:
String
?,
val
sender
:
PushSender
?
)
{
val
createdAt
:
Long
init
{
val
json
=
if
(
ejson
==
null
)
JSONObject
()
else
JSONObject
(
ejson
)
host
=
json
.
optString
(
"host"
,
null
)
rid
=
json
.
optString
(
"rid"
,
null
)
type
=
json
.
optString
(
"type"
,
null
)
channelName
=
json
.
optString
(
"name"
,
null
)
val
senderJson
=
json
.
optString
(
"sender"
,
null
)
if
(
senderJson
!=
null
&&
senderJson
!=
"null"
)
{
sender
=
Sender
(
senderJson
)
}
else
{
sender
=
null
}
createdAt
=
System
.
currentTimeMillis
()
get
()
=
System
.
currentTimeMillis
()
val
host
by
lazy
{
sanitizeUrl
(
hostname
)
}
data class
Sender
(
val
sender
:
String
)
:
Serializable
{
val
_id
:
String
?
val
username
:
String
?
val
name
:
String
?
init
{
val
json
=
JSONObject
(
sender
)
_id
=
json
.
optString
(
"_id"
,
null
)
username
=
json
.
optString
(
"username"
,
null
)
name
=
json
.
optString
(
"name"
,
null
)
}
}
private
fun
sanitizeUrl
(
baseUrl
:
String
):
String
{
var
url
=
baseUrl
.
trim
()
while
(
url
.
endsWith
(
'/'
))
{
url
=
url
.
dropLast
(
1
)
}
/**
* BroadcastReceiver for dismissed notifications.
*/
class
DeleteReceiver
:
BroadcastReceiver
()
{
override
fun
onReceive
(
context
:
Context
?,
intent
:
Intent
?)
{
val
notId
=
intent
?.
extras
?.
getInt
(
EXTRA_NOT_ID
)
val
host
=
intent
?.
extras
?.
getString
(
EXTRA_HOSTNAME
)
if
(
host
!=
null
&&
notId
!=
null
)
{
clearNotificationsByHostAndNotificationId
(
host
,
notId
)
}
}
return
url
}
}
@JsonSerializable
data class
PushSender
(
@Json
(
name
=
"_id"
)
val
id
:
String
,
val
username
:
String
?,
val
name
:
String
?
)
const
val
EXTRA_NOT_ID
=
"chat.rocket.android.EXTRA_NOT_ID"
const
val
EXTRA_HOSTNAME
=
"chat.rocket.android.EXTRA_HOSTNAME"
const
val
EXTRA_PUSH_MESSAGE
=
"chat.rocket.android.EXTRA_PUSH_MESSAGE"
const
val
EXTRA_ROOM_ID
=
"chat.rocket.android.EXTRA_ROOM_ID"
private
const
val
REPLY_LABEL
=
"REPLY"
private
const
val
REMOTE_INPUT_REPLY
=
"REMOTE_INPUT_REPLY"
app/src/main/java/chat/rocket/android/push/di/DeleteReceiverProvider.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.push.di
import
chat.rocket.android.dagger.module.AppModule
import
chat.rocket.android.push.DeleteReceiver
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
@Module
abstract
class
DeleteReceiverProvider
{
@ContributesAndroidInjector
(
modules
=
[
AppModule
::
class
])
abstract
fun
provideDeleteReceiver
():
DeleteReceiver
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/push/di/GcmListenerServiceProvider.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.push.di
import
chat.rocket.android.dagger.module.AppModule
import
chat.rocket.android.push.GcmListenerService
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
@Module
abstract
class
GcmListenerServiceProvider
{
@ContributesAndroidInjector
(
modules
=
[
AppModule
::
class
])
abstract
fun
provideGcmListenerService
():
GcmListenerService
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/domain/GetAccountInteractor.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.server.domain
import
javax.inject.Inject
class
GetAccountInteractor
@Inject
constructor
(
val
repository
:
AccountsRepository
)
{
suspend
fun
get
(
url
:
String
)
=
repository
.
load
().
firstOrNull
{
account
->
url
==
account
.
serverUrl
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/domain/GetServersInteractor.java
deleted
100644 → 0
View file @
d2cc3161
package
chat
.
rocket
.
android
.
server
.
domain
;
import
java.util.List
;
import
io.reactivex.Scheduler
;
import
io.reactivex.Single
;
public
class
GetServersInteractor
{
private
final
ServersRepository
repository
;
private
final
Scheduler
executionScheduler
;
public
GetServersInteractor
(
ServersRepository
repository
,
Scheduler
executionScheduler
)
{
this
.
repository
=
repository
;
this
.
executionScheduler
=
executionScheduler
;
}
}
app/src/main/java/chat/rocket/android/server/domain/ServersRepository.kt
deleted
100644 → 0
View file @
d2cc3161
package
chat.rocket.android.server.domain
import
chat.rocket.android.server.domain.model.Server
import
chat.rocket.android.server.infraestructure.ServerEntity
import
io.reactivex.Completable
import
io.reactivex.Single
interface
ServersRepository
{
val
servers
:
Single
<
List
<
Server
>>
fun
saveServer
(
server
:
Server
):
Completable
fun
updateServer
(
server
:
Server
):
Completable
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/domain/SettingsRepository.kt
View file @
4505780c
...
...
@@ -96,3 +96,4 @@ fun PublicSettings.uploadMaxFileSize(): Int {
}
fun
PublicSettings
.
baseUrl
():
String
?
=
this
[
SITE_URL
]
?.
value
as
String
fun
PublicSettings
.
siteName
():
String
?
=
this
[
SITE_NAME
]
?.
value
as
String
?
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/domain/TokenRepository.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.server.domain
interface
TokenRepository
:
chat
.
rocket
.
core
.
TokenRepository
{
fun
remove
(
url
:
String
)
fun
clear
()
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/infraestructure/RocketChatClientFactory.kt
View file @
4505780c
...
...
@@ -2,16 +2,16 @@ package chat.rocket.android.server.infraestructure
import
chat.rocket.common.util.PlatformLogger
import
chat.rocket.core.RocketChatClient
import
chat.rocket.
core
.TokenRepository
import
chat.rocket.
android.server.domain
.TokenRepository
import
okhttp3.OkHttpClient
import
timber.log.Timber
import
javax.inject.Inject
import
javax.inject.Singleton
@Singleton
class
RocketChatClientFactory
@Inject
constructor
(
val
okHttpClient
:
OkHttpClient
,
val
repository
:
TokenRepository
,
val
logger
:
PlatformLogger
)
{
class
RocketChatClientFactory
@Inject
constructor
(
private
val
okHttpClient
:
OkHttpClient
,
private
val
repository
:
TokenRepository
,
private
val
logger
:
PlatformLogger
)
{
private
val
cache
=
HashMap
<
String
,
RocketChatClient
>()
fun
create
(
url
:
String
):
RocketChatClient
{
...
...
app/src/main/java/chat/rocket/android/server/infraestructure/RoomServersRepository.kt
deleted
100644 → 0
View file @
d2cc3161
package
chat.rocket.android.server.infraestructure
import
chat.rocket.android.server.domain.ServersRepository
import
chat.rocket.android.server.domain.model.Server
import
io.reactivex.Completable
import
io.reactivex.Single
class
RoomServersRepository
:
ServersRepository
{
override
val
servers
:
Single
<
List
<
Server
>>
get
()
=
TODO
(
"not implemented"
)
override
fun
saveServer
(
server
:
Server
):
Completable
{
TODO
(
"not implemented"
)
}
override
fun
updateServer
(
server
:
Server
):
Completable
{
TODO
(
"not implemented"
)
}
}
app/src/main/java/chat/rocket/android/server/presentation/ChangeServerPresenter.kt
View file @
4505780c
package
chat.rocket.android.server.presentation
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.common.model.Token
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.TokenRepository
import
javax.inject.Inject
class
ChangeServerPresenter
@Inject
constructor
(
private
val
view
:
ChangeServerView
,
class
ChangeServerPresenter
@Inject
constructor
(
private
val
view
:
ChangeServerView
,
private
val
navigator
:
ChangeServerNavigator
,
private
val
strategy
:
CancelStrategy
,
private
val
saveCurrentServerInteractor
:
SaveCurrentServerInteractor
,
private
val
getCurrentServerInteractor
:
GetCurrentServerInteractor
,
private
val
getAccountInteractor
:
GetAccountInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
private
val
multiServerRepository
:
MultiServerTokenRepository
,
private
val
settingsRepository
:
SettingsRepository
,
private
val
tokenRepository
:
TokenRepository
,
private
val
connectionManager
:
ConnectionManagerFactory
)
{
private
val
localRepository
:
LocalRepository
,
private
val
connectionManager
:
ConnectionManagerFactory
)
{
fun
loadServer
(
newUrl
:
String
?)
{
launchUI
(
strategy
)
{
view
.
showProgress
()
...
...
@@ -29,7 +31,7 @@ class ChangeServerPresenter @Inject constructor(private val view: ChangeServerVi
}
url
?.
let
{
serverUrl
->
val
token
=
multiServer
Repository
.
get
(
serverUrl
)
val
token
=
token
Repository
.
get
(
serverUrl
)
if
(
token
==
null
)
{
view
.
showInvalidCredentials
()
view
.
hideProgress
()
...
...
@@ -47,7 +49,11 @@ class ChangeServerPresenter @Inject constructor(private val view: ChangeServerVi
connectionManager
.
get
(
url
)
?.
disconnect
()
}
tokenRepository
.
save
(
Token
(
token
.
userId
,
token
.
authToken
))
// Save the current username.
getAccountInteractor
.
get
(
serverUrl
)
?.
let
{
account
->
localRepository
.
save
(
LocalRepository
.
CURRENT_USERNAME_KEY
,
account
.
userName
)
}
saveCurrentServerInteractor
.
save
(
serverUrl
)
view
.
hideProgress
()
navigator
.
toChatRooms
()
...
...
app/src/main/java/chat/rocket/android/server/ui/ChangeServerActivity.kt
View file @
4505780c
...
...
@@ -39,7 +39,7 @@ class ChangeServerActivity : AppCompatActivity(), ChangeServerView {
private
const
val
INTENT_SERVER_URL
=
"INTENT_SERVER_URL"
private
const
val
INTENT_CHAT_ROOM_NAME
=
"INTENT_CHAT_ROOM_NAME"
private
const
val
INTENT_CHAT_ROOM_TYPE
=
"INTENT_CHAT_ROOM_
NAM
E"
private
const
val
INTENT_CHAT_ROOM_TYPE
=
"INTENT_CHAT_ROOM_
TYP
E"
fun
Context
.
changeServerIntent
(
serverUrl
:
String
?):
Intent
{
return
Intent
(
this
,
ChangeServerActivity
::
class
.
java
).
apply
{
...
...
app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt
0 → 100644
View file @
4505780c
package
chat.rocket.android.util.extensions
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.registerPushToken
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.launch
import
timber.log.Timber
suspend
fun
RocketChatClient
.
registerPushToken
(
token
:
String
,
accounts
:
List
<
Account
>,
factory
:
RocketChatClientFactory
)
{
launch
(
CommonPool
)
{
accounts
.
forEach
{
account
->
try
{
factory
.
create
(
account
.
serverUrl
).
registerPushToken
(
token
)
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error registering Push token for ${account.serverUrl}"
)
ex
.
printStackTrace
()
}
}
}
}
\ No newline at end of file
dependencies.gradle
View file @
4505780c
...
...
@@ -24,7 +24,7 @@ ext {
threeTenABP
:
'1.0.5'
,
rxBinding
:
'2.0.0'
,
fresco
:
'1.8.1'
,
kotshi
:
'
0.3.0
'
,
kotshi
:
'
1.0.2
'
,
frescoImageViewer
:
'0.5.1'
,
markwon
:
'1.0.3'
,
sheetMenu
:
'1.3.3'
,
...
...
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