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
3e8ef19b
Commit
3e8ef19b
authored
Apr 17, 2018
by
Filipe de Lima Brito
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat.Android into new/active-users
parents
81a4bae4
7b7997d5
Changes
49
Show whitespace changes
Inline
Side-by-side
Showing
49 changed files
with
1203 additions
and
399 deletions
+1203
-399
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+22
-3
LoginDeepLinkInfo.kt
.../android/authentication/domain/model/LoginDeepLinkInfo.kt
+40
-0
LoginPresenter.kt
...droid/authentication/login/presentation/LoginPresenter.kt
+48
-6
LoginFragment.kt
...t/rocket/android/authentication/login/ui/LoginFragment.kt
+30
-11
AuthenticationNavigator.kt
...id/authentication/presentation/AuthenticationNavigator.kt
+7
-0
ServerPresenter.kt
...oid/authentication/server/presentation/ServerPresenter.kt
+17
-6
ServerFragment.kt
...rocket/android/authentication/server/ui/ServerFragment.kt
+15
-1
TwoFAFragment.kt
...cket/android/authentication/twofactor/ui/TwoFAFragment.kt
+1
-1
AuthenticationActivity.kt
...ocket/android/authentication/ui/AuthenticationActivity.kt
+8
-5
ChatRoomAdapter.kt
...a/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
+17
-2
ColorAttachmentViewHolder.kt
...ket/android/chatroom/adapter/ColorAttachmentViewHolder.kt
+38
-0
MessageViewHolder.kt
...chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
+4
-0
MessageServiceProvider.kt
...chat/rocket/android/chatroom/di/MessageServiceProvider.kt
+11
-0
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+108
-69
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+1
-3
MessageService.kt
...va/chat/rocket/android/chatroom/service/MessageService.kt
+78
-0
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+32
-31
AudioAttachmentViewModel.kt
...et/android/chatroom/viewmodel/AudioAttachmentViewModel.kt
+2
-1
AuthorAttachmentViewModel.kt
...t/android/chatroom/viewmodel/AuthorAttachmentViewModel.kt
+12
-11
BaseViewModel.kt
...a/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
+3
-1
ColorAttachmentViewModel.kt
...et/android/chatroom/viewmodel/ColorAttachmentViewModel.kt
+24
-0
ImageAttachmentViewModel.kt
...et/android/chatroom/viewmodel/ImageAttachmentViewModel.kt
+2
-1
MessageAttachmentViewModel.kt
.../android/chatroom/viewmodel/MessageAttachmentViewModel.kt
+2
-1
MessageViewModel.kt
...hat/rocket/android/chatroom/viewmodel/MessageViewModel.kt
+2
-1
UrlPreviewViewModel.kt
.../rocket/android/chatroom/viewmodel/UrlPreviewViewModel.kt
+2
-1
VideoAttachmentViewModel.kt
...et/android/chatroom/viewmodel/VideoAttachmentViewModel.kt
+2
-1
ViewModelMapper.kt
...chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
+16
-1
ChatRoomsPresenter.kt
...cket/android/chatrooms/presentation/ChatRoomsPresenter.kt
+99
-91
MessageView.kt
...n/java/chat/rocket/android/core/behaviours/MessageView.kt
+9
-0
AppComponent.kt
app/src/main/java/chat/rocket/android/dagger/AppComponent.kt
+3
-0
AppModule.kt
.../main/java/chat/rocket/android/dagger/module/AppModule.kt
+87
-14
ServiceBuilder.kt
.../java/chat/rocket/android/dagger/module/ServiceBuilder.kt
+5
-0
ForMessages.kt
.../java/chat/rocket/android/dagger/qualifier/ForMessages.kt
+11
-0
LocalRepository.kt
...ava/chat/rocket/android/infrastructure/LocalRepository.kt
+2
-1
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+16
-18
ProfilePresenter.kt
...t/rocket/android/profile/presentation/ProfilePresenter.kt
+2
-5
ProfileFragment.kt
...in/java/chat/rocket/android/profile/ui/ProfileFragment.kt
+41
-22
FirebaseTokenService.kt
...ain/java/chat/rocket/android/push/FirebaseTokenService.kt
+18
-13
JobSchedulerInteractor.kt
...at/rocket/android/server/domain/JobSchedulerInteractor.kt
+8
-0
MessagesRepository.kt
...a/chat/rocket/android/server/domain/MessagesRepository.kt
+13
-9
RefreshSettingsInteractor.kt
...rocket/android/server/domain/RefreshSettingsInteractor.kt
+4
-1
RemoveAccountInteractor.kt
...t/rocket/android/server/domain/RemoveAccountInteractor.kt
+1
-1
JobSchedulerInteractorImpl.kt
...roid/server/infraestructure/JobSchedulerInteractorImpl.kt
+21
-0
MemoryMessagesRepository.kt
...ndroid/server/infraestructure/MemoryMessagesRepository.kt
+35
-13
SharedPreferencesMessagesRepository.kt
...er/infraestructure/SharedPreferencesMessagesRepository.kt
+137
-0
CheckServerPresenter.kt
...ocket/android/server/presentation/CheckServerPresenter.kt
+47
-14
fragment_profile.xml
app/src/main/res/layout/fragment_profile.xml
+48
-40
item_color_attachment.xml
app/src/main/res/layout/item_color_attachment.xml
+44
-0
backup_config.xml
app/src/main/res/xml/backup_config.xml
+8
-0
No files found.
app/src/main/AndroidManifest.xml
View file @
3e8ef19b
...
...
@@ -17,10 +17,11 @@
<application
android:name=
".app.RocketChatApplication"
android:allowBackup=
"true"
android:fullBackupContent=
"@xml/backup_config"
android:icon=
"@mipmap/ic_launcher"
android:label=
"@string/app_name"
android:roundIcon=
"@mipmap/ic_launcher_round"
android:networkSecurityConfig=
"@xml/network_security_config"
>
android:networkSecurityConfig=
"@xml/network_security_config"
android:supportsRtl=
"true"
>
<activity
...
...
@@ -34,6 +35,19 @@
<category
android:name=
"android.intent.category.DEFAULT"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
<intent-filter>
<action
android:name=
"android.intent.action.VIEW"
/>
<category
android:name=
"android.intent.category.BROWSABLE"
/>
<category
android:name=
"android.intent.category.DEFAULT"
/>
<data
android:host=
"auth"
android:scheme=
"rocketchat"
/>
<data
android:host=
"go.rocket.chat"
android:path=
"/auth"
android:scheme=
"https"
/>
</intent-filter>
</activity>
<activity
...
...
@@ -102,13 +116,18 @@
<action
android:name=
"com.google.android.c2dm.intent.RECEIVE"
/>
</intent-filter>
</service>
<service
android:name=
".chatroom.service.MessageService"
android:exported=
"true"
android:permission=
"android.permission.BIND_JOB_SERVICE"
/>
<meta-data
android:name=
"io.fabric.ApiKey"
android:value=
"12ac6e94f850aaffcdff52001af77ca415d06a43"
/>
<activity
android:name=
".settings.about.ui.AboutActivity"
android:theme=
"@style/AppTheme"
/>
<activity
android:name=
".settings.about.ui.AboutActivity"
android:theme=
"@style/AppTheme"
/>
</application>
</manifest>
app/src/main/java/chat/rocket/android/authentication/domain/model/LoginDeepLinkInfo.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.authentication.domain.model
import
android.annotation.SuppressLint
import
android.content.Intent
import
android.net.Uri
import
android.os.Parcelable
import
kotlinx.android.parcel.Parcelize
import
timber.log.Timber
@SuppressLint
(
"ParcelCreator"
)
@Parcelize
data class
LoginDeepLinkInfo
(
val
url
:
String
,
val
userId
:
String
,
val
token
:
String
)
:
Parcelable
fun
Intent
.
getLoginDeepLinkInfo
():
LoginDeepLinkInfo
?
{
val
uri
=
data
return
if
(
action
==
Intent
.
ACTION_VIEW
&&
uri
!=
null
&&
uri
.
isAuthenticationDeepLink
())
{
val
host
=
uri
.
getQueryParameter
(
"host"
)
val
url
=
if
(
host
.
startsWith
(
"http"
))
host
else
"https://$host"
val
userId
=
uri
.
getQueryParameter
(
"userId"
)
val
token
=
uri
.
getQueryParameter
(
"token"
)
try
{
LoginDeepLinkInfo
(
url
,
userId
,
token
)
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error parsing login deeplink"
)
null
}
}
else
null
}
private
inline
fun
Uri
.
isAuthenticationDeepLink
():
Boolean
{
if
(
host
==
"auth"
)
return
true
else
if
(
host
==
"go.rocket.chat"
&&
path
==
"/auth"
)
return
true
return
false
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
View file @
3e8ef19b
package
chat.rocket.android.authentication.login.presentation
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.OauthHelper
...
...
@@ -10,6 +11,7 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.presentation.CheckServerPresenter
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatAuthException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatTwoFactorException
import
chat.rocket.common.model.Token
...
...
@@ -24,6 +26,7 @@ import javax.inject.Inject
private
const
val
TYPE_LOGIN_USER_EMAIL
=
0
private
const
val
TYPE_LOGIN_CAS
=
1
private
const
val
TYPE_LOGIN_OAUTH
=
2
private
const
val
TYPE_LOGIN_DEEP_LINK
=
3
private
const
val
SERVICE_NAME_GITHUB
=
"github"
private
const
val
SERVICE_NAME_GOOGLE
=
"google"
private
const
val
SERVICE_NAME_LINKEDIN
=
"linkedin"
...
...
@@ -35,26 +38,31 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
private
val
tokenRepository
:
TokenRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
settingsInteractor
:
GetSettingsInteractor
,
private
val
settingsInteractor
:
GetSettingsInteractor
,
serverInteractor
:
GetCurrentServerInteractor
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
factory
:
RocketChatClientFactory
)
:
CheckServerPresenter
(
strategy
,
factory
.
create
(
serverInteractor
.
get
()
!!
)
,
view
)
{
:
CheckServerPresenter
(
strategy
,
factory
,
view
)
{
// 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
)
private
val
settings
:
PublicSettings
=
settingsInteractor
.
get
(
currentServer
)
private
lateinit
var
client
:
RocketChatClient
private
lateinit
var
settings
:
PublicSettings
//private val client: RocketChatClient = factory.create(currentServer)
//private val settings: PublicSettings = settingsInteractor.get(currentServer)
private
lateinit
var
usernameOrEmail
:
String
private
lateinit
var
password
:
String
private
lateinit
var
credentialToken
:
String
private
lateinit
var
credentialSecret
:
String
private
lateinit
var
deepLinkUserId
:
String
private
lateinit
var
deepLinkToken
:
String
fun
setupView
()
{
setupConnectionInfo
(
currentServer
)
setupLoginView
()
setupUserRegistrationView
()
setupCasView
()
setupOauthServicesView
()
checkServerInfo
()
checkServerInfo
(
currentServer
)
}
fun
authenticateWithUserAndPassword
(
usernameOrEmail
:
String
,
password
:
String
)
{
...
...
@@ -84,6 +92,32 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
doAuthentication
(
TYPE_LOGIN_OAUTH
)
}
fun
authenticadeWithDeepLink
(
deepLinkInfo
:
LoginDeepLinkInfo
)
{
val
serverUrl
=
deepLinkInfo
.
url
setupConnectionInfo
(
serverUrl
)
deepLinkUserId
=
deepLinkInfo
.
userId
deepLinkToken
=
deepLinkInfo
.
token
tokenRepository
.
save
(
serverUrl
,
Token
(
deepLinkUserId
,
deepLinkToken
))
launchUI
(
strategy
)
{
try
{
val
version
=
checkServerVersion
(
serverUrl
).
await
()
when
(
version
)
{
is
Version
.
OutOfDateError
->
{
view
.
blockAndAlertNotRequiredVersion
()
}
else
->
doAuthentication
(
TYPE_LOGIN_DEEP_LINK
)
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error performing deep link login"
)
}
}
}
private
fun
setupConnectionInfo
(
serverUrl
:
String
)
{
client
=
factory
.
create
(
serverUrl
)
settings
=
settingsInteractor
.
get
(
serverUrl
)
}
fun
signup
()
=
navigator
.
toSignUp
()
private
fun
setupLoginView
()
{
...
...
@@ -212,8 +246,16 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
TYPE_LOGIN_OAUTH
->
{
client
.
loginWithOauth
(
credentialToken
,
credentialSecret
)
}
TYPE_LOGIN_DEEP_LINK
->
{
val
myself
=
client
.
me
()
// Just checking if the credentials worked.
if
(
myself
.
id
==
deepLinkUserId
)
{
Token
(
deepLinkUserId
,
deepLinkToken
)
}
else
{
throw
RocketChatAuthException
(
"Invalid Authentication Deep Link Credentials..."
)
}
}
else
->
{
throw
IllegalStateException
(
"Expected TYPE_LOGIN_USER_EMAIL, TYPE_LOGIN_CAS
or TYPE_LOGIN_OAUTH
"
)
throw
IllegalStateException
(
"Expected TYPE_LOGIN_USER_EMAIL, TYPE_LOGIN_CAS
, TYPE_LOGIN_OAUTH or TYPE_LOGIN_DEEP_LINK
"
)
}
}
}
...
...
app/src/main/java/chat/rocket/android/authentication/login/ui/LoginFragment.kt
View file @
3e8ef19b
...
...
@@ -14,8 +14,10 @@ import android.view.ViewGroup
import
android.view.ViewTreeObserver
import
android.widget.ImageButton
import
android.widget.ScrollView
import
androidx.core.view.postDelayed
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.login.presentation.LoginPresenter
import
chat.rocket.android.authentication.login.presentation.LoginView
import
chat.rocket.android.helper.KeyboardHelper
...
...
@@ -26,6 +28,7 @@ import chat.rocket.android.webview.cas.ui.casWebViewIntent
import
chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_SECRET
import
chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_TOKEN
import
chat.rocket.android.webview.oauth.ui.oauthWebViewIntent
import
chat.rocket.common.util.ifNull
import
dagger.android.support.AndroidSupportInjection
import
kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import
javax.inject.Inject
...
...
@@ -40,14 +43,22 @@ class LoginFragment : Fragment(), LoginView {
areLoginOptionsNeeded
()
}
private
var
isGlobalLayoutListenerSetUp
=
false
private
var
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
companion
object
{
fun
newInstance
()
=
LoginFragment
()
private
const
val
DEEP_LINK_INFO
=
"DeepLinkInfo"
fun
newInstance
(
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
)
=
LoginFragment
().
apply
{
arguments
=
Bundle
().
apply
{
putParcelable
(
DEEP_LINK_INFO
,
deepLinkInfo
)
}
}
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
deepLinkInfo
=
arguments
?.
getParcelable
(
DEEP_LINK_INFO
)
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
...
...
@@ -60,8 +71,12 @@ class LoginFragment : Fragment(), LoginView {
tintEditTextDrawableStart
()
}
deepLinkInfo
?.
let
{
presenter
.
authenticadeWithDeepLink
(
it
)
}.
ifNull
{
presenter
.
setupView
()
}
}
override
fun
onDestroyView
()
{
super
.
onDestroyView
()
...
...
@@ -377,19 +392,23 @@ class LoginFragment : Fragment(), LoginView {
}
private
fun
showRemainingSocialAccountsView
()
{
social_accounts_container
.
postDelayed
({
social_accounts_container
.
postDelayed
(
300
)
{
ui
{
(
0
..
social_accounts_container
.
childCount
)
.
mapNotNull
{
social_accounts_container
.
getChildAt
(
it
)
as
?
ImageButton
}
.
filter
{
it
.
isClickable
}
.
forEach
{
ui
{
it
.
setVisible
(
true
)
}}
},
1000
)
.
forEach
{
it
.
setVisible
(
true
)
}
}
}
}
// Scrolling to the bottom of the screen.
private
fun
scrollToBottom
()
{
scroll_view
.
postDelayed
({
ui
{
scroll_view
.
fullScroll
(
ScrollView
.
FOCUS_DOWN
)
}
},
1250
)
scroll_view
.
postDelayed
(
1250
)
{
ui
{
scroll_view
.
fullScroll
(
ScrollView
.
FOCUS_DOWN
)
}
}
}
...
...
app/src/main/java/chat/rocket/android/authentication/presentation/AuthenticationNavigator.kt
View file @
3e8ef19b
...
...
@@ -2,6 +2,7 @@ package chat.rocket.android.authentication.presentation
import
android.content.Intent
import
chat.rocket.android.R
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.login.ui.LoginFragment
import
chat.rocket.android.authentication.registerusername.ui.RegisterUsernameFragment
import
chat.rocket.android.authentication.signup.ui.SignupFragment
...
...
@@ -21,6 +22,12 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) {
}
}
fun
toLogin
(
deepLinkInfo
:
LoginDeepLinkInfo
)
{
activity
.
addFragmentBackStack
(
"LoginFragment"
,
R
.
id
.
fragment_container
)
{
LoginFragment
.
newInstance
(
deepLinkInfo
)
}
}
fun
toTwoFA
(
username
:
String
,
password
:
String
)
{
activity
.
addFragmentBackStack
(
"TwoFAFragment"
,
R
.
id
.
fragment_container
)
{
TwoFAFragment
.
newInstance
(
username
,
password
)
...
...
app/src/main/java/chat/rocket/android/authentication/server/presentation/ServerPresenter.kt
View file @
3e8ef19b
package
chat.rocket.android.authentication.server.presentation
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.behaviours.showMessage
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.GetAccountsInteractor
import
chat.rocket.android.server.domain.RefreshSettingsInteractor
...
...
@@ -16,7 +18,14 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
private
val
serverInteractor
:
SaveCurrentServerInteractor
,
private
val
refreshSettingsInteractor
:
RefreshSettingsInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
)
{
fun
connect
(
server
:
String
)
{
connectToServer
(
server
)
{
navigator
.
toLogin
()
}
}
fun
connectToServer
(
server
:
String
,
block
:
()
->
Unit
)
{
if
(!
server
.
isValidUrl
())
{
view
.
showInvalidServerUrlMessage
()
}
else
{
...
...
@@ -32,17 +41,19 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
try
{
refreshSettingsInteractor
.
refresh
(
server
)
serverInteractor
.
save
(
server
)
navigator
.
toLogin
()
block
()
}
catch
(
ex
:
Exception
)
{
ex
.
message
?.
let
{
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
view
.
showMessage
(
ex
)
}
finally
{
view
.
hideLoading
()
}
}
}
}
fun
deepLink
(
deepLinkInfo
:
LoginDeepLinkInfo
)
{
connectToServer
(
deepLinkInfo
.
url
)
{
navigator
.
toLogin
(
deepLinkInfo
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/authentication/server/ui/ServerFragment.kt
View file @
3e8ef19b
...
...
@@ -7,6 +7,7 @@ import android.view.View
import
android.view.ViewGroup
import
android.view.ViewTreeObserver
import
chat.rocket.android.R
import
chat.rocket.android.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.server.presentation.ServerPresenter
import
chat.rocket.android.authentication.server.presentation.ServerView
import
chat.rocket.android.helper.KeyboardHelper
...
...
@@ -17,17 +18,26 @@ import javax.inject.Inject
class
ServerFragment
:
Fragment
(),
ServerView
{
@Inject
lateinit
var
presenter
:
ServerPresenter
private
var
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
private
val
layoutListener
=
ViewTreeObserver
.
OnGlobalLayoutListener
{
text_server_url
.
isCursorVisible
=
KeyboardHelper
.
isSoftKeyboardShown
(
relative_layout
.
rootView
)
}
companion
object
{
fun
newInstance
()
=
ServerFragment
()
private
const
val
DEEP_LINK_INFO
=
"DeepLinkInfo"
fun
newInstance
(
deepLinkInfo
:
LoginDeepLinkInfo
?)
=
ServerFragment
().
apply
{
arguments
=
Bundle
().
apply
{
putParcelable
(
DEEP_LINK_INFO
,
deepLinkInfo
)
}
}
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
deepLinkInfo
=
arguments
?.
getParcelable
(
DEEP_LINK_INFO
)
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
...
...
@@ -37,6 +47,10 @@ class ServerFragment : Fragment(), ServerView {
super
.
onViewCreated
(
view
,
savedInstanceState
)
relative_layout
.
viewTreeObserver
.
addOnGlobalLayoutListener
(
layoutListener
)
setupOnClickListener
()
deepLinkInfo
?.
let
{
presenter
.
deepLink
(
it
)
}
}
override
fun
onDestroyView
()
{
...
...
app/src/main/java/chat/rocket/android/authentication/twofactor/ui/TwoFAFragment.kt
View file @
3e8ef19b
...
...
@@ -28,7 +28,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
private
const
val
PASSWORD
=
"password"
fun
newInstance
(
username
:
String
,
password
:
String
)
=
TwoFAFragment
().
apply
{
arguments
=
Bundle
(
1
).
apply
{
arguments
=
Bundle
(
2
).
apply
{
putString
(
USERNAME
,
username
)
putString
(
PASSWORD
,
password
)
}
...
...
app/src/main/java/chat/rocket/android/authentication/ui/AuthenticationActivity.kt
View file @
3e8ef19b
...
...
@@ -6,10 +6,11 @@ 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.authentication.domain.model.LoginDeepLinkInfo
import
chat.rocket.android.authentication.domain.model.getLoginDeepLinkInfo
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
...
...
@@ -30,11 +31,13 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
setTheme
(
R
.
style
.
AuthenticationTheme
)
super
.
onCreate
(
savedInstanceState
)
val
deepLinkInfo
=
intent
.
getLoginDeepLinkInfo
()
launch
(
UI
+
job
)
{
val
newServer
=
intent
.
getBooleanExtra
(
INTENT_ADD_NEW_SERVER
,
false
)
presenter
.
loadCredentials
(
newServer
)
{
authenticated
->
// if we got authenticadeWithDeepLink information, pass true to newServer also
presenter
.
loadCredentials
(
newServer
||
deepLinkInfo
!=
null
)
{
authenticated
->
if
(!
authenticated
)
{
showServerInput
(
savedInstanceState
)
showServerInput
(
savedInstanceState
,
deepLinkInfo
)
}
}
}
...
...
@@ -49,9 +52,9 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
return
fragmentDispatchingAndroidInjector
}
fun
showServerInput
(
savedInstanceState
:
Bundle
?)
{
fun
showServerInput
(
savedInstanceState
:
Bundle
?
,
deepLinkInfo
:
LoginDeepLinkInfo
?
)
{
addFragment
(
"ServerFragment"
,
R
.
id
.
fragment_container
)
{
ServerFragment
.
newInstance
()
ServerFragment
.
newInstance
(
deepLinkInfo
)
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ChatRoomAdapter.kt
View file @
3e8ef19b
...
...
@@ -57,6 +57,10 @@ class ChatRoomAdapter(
val
view
=
parent
.
inflate
(
R
.
layout
.
item_author_attachment
)
AuthorAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
BaseViewModel
.
ViewType
.
COLOR_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
item_color_attachment
)
ColorAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
else
->
{
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
}
...
...
@@ -97,6 +101,7 @@ class ChatRoomAdapter(
is
UrlPreviewViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
UrlPreviewViewModel
)
is
MessageAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageAttachmentViewModel
)
is
AuthorAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
AuthorAttachmentViewModel
)
is
ColorAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
ColorAttachmentViewModel
)
}
}
...
...
@@ -117,12 +122,22 @@ class ChatRoomAdapter(
}
fun
prependData
(
dataSet
:
List
<
BaseViewModel
<*
>>)
{
val
item
=
dataSet
.
firstOrNull
{
newItem
->
val
item
=
dataSet
.
indexOfFirst
{
newItem
->
this
.
dataSet
.
indexOfFirst
{
it
.
messageId
==
newItem
.
messageId
&&
it
.
viewType
==
newItem
.
viewType
}
>
-
1
}
if
(
item
==
null
)
{
if
(
item
==
-
1
)
{
this
.
dataSet
.
addAll
(
0
,
dataSet
)
notifyItemRangeInserted
(
0
,
dataSet
.
size
)
}
else
{
dataSet
.
forEach
{
item
->
val
index
=
this
.
dataSet
.
indexOfFirst
{
item
.
messageId
==
it
.
messageId
&&
item
.
viewType
==
it
.
viewType
}
if
(
index
>
-
1
)
{
this
.
dataSet
[
index
]
=
item
notifyItemChanged
(
index
)
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/adapter/ColorAttachmentViewHolder.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.chatroom.adapter
import
android.graphics.drawable.Drawable
import
android.support.v4.content.ContextCompat
import
android.text.method.LinkMovementMethod
import
android.view.View
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.viewmodel.ColorAttachmentViewModel
import
chat.rocket.android.widget.emoji.EmojiReactionListener
import
kotlinx.android.synthetic.main.item_color_attachment.view.*
class
ColorAttachmentViewHolder
(
itemView
:
View
,
listener
:
BaseViewHolder
.
ActionsListener
,
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
ColorAttachmentViewModel
>(
itemView
,
listener
,
reactionListener
)
{
val
drawable
:
Drawable
?
=
ContextCompat
.
getDrawable
(
itemView
.
context
,
R
.
drawable
.
quote_vertical_bar
)
init
{
with
(
itemView
)
{
setupActionMenu
(
attachment_text
)
setupActionMenu
(
color_attachment_container
)
attachment_text
.
movementMethod
=
LinkMovementMethod
()
}
}
override
fun
bindViews
(
data
:
ColorAttachmentViewModel
)
{
with
(
itemView
)
{
drawable
?.
let
{
quote_bar
.
background
=
drawable
.
mutate
().
apply
{
setTint
(
data
.
color
)
}
attachment_text
.
text
=
data
.
text
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/adapter/MessageViewHolder.kt
View file @
3e8ef19b
package
chat.rocket.android.chatroom.adapter
import
android.graphics.Color
import
android.text.method.LinkMovementMethod
import
android.view.View
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
...
...
@@ -29,6 +30,9 @@ class MessageViewHolder(
text_sender
.
text
=
data
.
senderName
text_content
.
text
=
data
.
content
image_avatar
.
setImageURI
(
data
.
avatar
)
text_content
.
setTextColor
(
if
(
data
.
isTemporary
)
Color
.
GRAY
else
Color
.
BLACK
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/di/MessageServiceProvider.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.chatroom.di
import
chat.rocket.android.chatroom.service.MessageService
import
chat.rocket.android.dagger.module.AppModule
import
dagger.Module
import
dagger.android.ContributesAndroidInjector
@Module
abstract
class
MessageServiceProvider
{
@ContributesAndroidInjector
(
modules
=
[
AppModule
::
class
])
abstract
fun
provideMessageService
():
MessageService
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
3e8ef19b
...
...
@@ -12,6 +12,7 @@ import chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewMo
import
chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.username
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.state
...
...
@@ -20,6 +21,7 @@ import chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.SimpleUser
import
chat.rocket.common.model.UserStatus
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.common.util.ifNull
...
...
@@ -52,7 +54,8 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private
val
roomsRepository
:
RoomRepository
,
private
val
localRepository
:
LocalRepository
,
factory
:
ConnectionManagerFactory
,
private
val
mapper
:
ViewModelMapper
)
{
private
val
mapper
:
ViewModelMapper
,
private
val
jobSchedulerInteractor
:
JobSchedulerInteractor
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
manager
=
factory
.
create
(
currentServer
)
private
val
client
=
manager
.
client
...
...
@@ -70,14 +73,18 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
launchUI
(
strategy
)
{
view
.
showLoading
()
try
{
val
messages
=
retryIO
(
description
=
"messages chatRoom: $chatRoomId, type: $chatRoomType, offset: $offset"
)
{
client
.
messages
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
30
).
result
if
(
offset
==
0L
)
{
val
localMessages
=
messagesRepository
.
getByRoomId
(
chatRoomId
)
val
oldMessages
=
mapper
.
map
(
localMessages
)
if
(
oldMessages
.
isNotEmpty
())
{
view
.
showMessages
(
oldMessages
)
loadMissingMessages
()
}
else
{
loadAndShowMessages
(
chatRoomId
,
chatRoomType
,
offset
)
}
}
else
{
loadAndShowMessages
(
chatRoomId
,
chatRoomType
,
offset
)
}
messagesRepository
.
saveAll
(
messages
)
val
messagesViewModels
=
mapper
.
map
(
messages
)
view
.
showMessages
(
messagesViewModels
)
// TODO: For now we are marking the room as read if we can get the messages (I mean, no exception occurs)
// but should mark only when the user see the first unread message.
...
...
@@ -85,7 +92,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
subscribeMessages
(
chatRoomId
)
}
catch
(
ex
:
Exception
)
{
ex
.
printStackTrace
(
)
Timber
.
e
(
ex
)
ex
.
message
?.
let
{
view
.
showMessage
(
it
)
}.
ifNull
{
...
...
@@ -101,28 +108,58 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
}
private
suspend
fun
loadAndShowMessages
(
chatRoomId
:
String
,
chatRoomType
:
String
,
offset
:
Long
=
0
)
{
val
messages
=
retryIO
(
description
=
"messages chatRoom: $chatRoomId, type: $chatRoomType, offset: $offset"
)
{
client
.
messages
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
30
).
result
}
messagesRepository
.
saveAll
(
messages
)
val
allMessages
=
mapper
.
map
(
messages
)
view
.
showMessages
(
allMessages
)
}
fun
sendMessage
(
chatRoomId
:
String
,
text
:
String
,
messageId
:
String
?)
{
launchUI
(
strategy
)
{
view
.
disableSendMessageButton
()
try
{
// ignore message for now, will receive it on the stream
val
message
=
retryIO
{
if
(
messageId
==
null
)
{
val
id
=
UUID
.
randomUUID
().
toString
()
val
message
=
if
(
messageId
==
null
)
{
val
username
=
localRepository
.
username
()
val
newMessage
=
Message
(
id
=
id
,
roomId
=
chatRoomId
,
message
=
text
,
timestamp
=
Instant
.
now
().
toEpochMilli
(),
sender
=
SimpleUser
(
null
,
username
,
username
),
attachments
=
null
,
avatar
=
currentServer
.
avatarUrl
(
username
!!
),
channels
=
null
,
editedAt
=
null
,
editedBy
=
null
,
groupable
=
false
,
parseUrls
=
false
,
pinned
=
false
,
mentions
=
emptyList
(),
reactions
=
null
,
senderAlias
=
null
,
type
=
null
,
updatedAt
=
null
,
urls
=
null
,
isTemporary
=
true
)
messagesRepository
.
save
(
newMessage
)
view
.
showNewMessage
(
mapper
.
map
(
newMessage
))
client
.
sendMessage
(
id
,
chatRoomId
,
text
)
}
else
{
client
.
updateMessage
(
chatRoomId
,
messageId
,
text
)
}
}
view
.
enableSendMessageButton
(
false
)
view
.
enableSendMessageButton
()
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error sending message..."
)
ex
.
message
?.
let
{
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
view
.
enableSendMessageButton
(
true
)
jobSchedulerInteractor
.
scheduleSendingMessages
()
}
finally
{
view
.
enableSendMessageButton
()
}
}
}
...
...
@@ -189,6 +226,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
if
(
state
is
State
.
Connected
)
{
jobSchedulerInteractor
.
scheduleSendingMessages
()
loadMissingMessages
()
}
}
...
...
@@ -563,12 +601,13 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
// failed, command is not valid so post it
sendMessage
(
roomId
,
text
,
null
)
}
view
.
enableSendMessageButton
(
false
)
}
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
// command is not valid, post it
sendMessage
(
roomId
,
text
,
null
)
}
finally
{
view
.
enableSendMessageButton
()
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
3e8ef19b
...
...
@@ -92,10 +92,8 @@ interface ChatRoomView : LoadingView, MessageView {
/**
* Enables the send message button.
*
* @param sendFailed Whether the sent message has failed.
*/
fun
enableSendMessageButton
(
sendFailed
:
Boolean
)
fun
enableSendMessageButton
()
/**
* Clears the message composition.
...
...
app/src/main/java/chat/rocket/android/chatroom/service/MessageService.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.chatroom.service
import
android.app.job.JobParameters
import
android.app.job.JobService
import
chat.rocket.android.server.domain.CurrentServerRepository
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.internal.rest.sendMessage
import
chat.rocket.core.model.Message
import
dagger.android.AndroidInjection
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.launch
import
timber.log.Timber
import
javax.inject.Inject
class
MessageService
:
JobService
()
{
@Inject
lateinit
var
factory
:
ConnectionManagerFactory
@Inject
lateinit
var
currentServerRepository
:
CurrentServerRepository
@Inject
lateinit
var
messageRepository
:
MessagesRepository
override
fun
onCreate
()
{
super
.
onCreate
()
AndroidInjection
.
inject
(
this
)
}
override
fun
onStopJob
(
params
:
JobParameters
?):
Boolean
{
return
false
}
override
fun
onStartJob
(
params
:
JobParameters
?):
Boolean
{
launch
(
CommonPool
)
{
val
currentServer
=
currentServerRepository
.
get
()
if
(
currentServer
!=
null
)
{
retrySendingMessages
(
params
,
currentServer
)
jobFinished
(
params
,
false
)
}
}
return
true
}
private
suspend
fun
retrySendingMessages
(
params
:
JobParameters
?,
currentServer
:
String
)
{
val
temporaryMessages
=
messageRepository
.
getAllUnsent
()
.
sortedWith
(
compareBy
(
Message
::
timestamp
))
if
(
temporaryMessages
.
isNotEmpty
())
{
val
connectionManager
=
factory
.
create
(
currentServer
)
val
client
=
connectionManager
.
client
temporaryMessages
.
forEach
{
message
->
try
{
client
.
sendMessage
(
message
=
message
.
message
,
messageId
=
message
.
id
,
roomId
=
message
.
roomId
,
avatar
=
message
.
avatar
,
attachments
=
message
.
attachments
,
alias
=
message
.
senderAlias
)
messageRepository
.
save
(
message
.
copy
(
isTemporary
=
false
))
Timber
.
d
(
"Sent scheduled message given by id: ${message.id}"
)
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
if
(
ex
.
message
?.
contains
(
"E11000"
,
true
)
==
true
)
{
// XXX: Temporary solution. We need proper error codes from the api.
messageRepository
.
save
(
message
.
copy
(
isTemporary
=
false
))
}
jobFinished
(
params
,
true
)
}
}
}
}
companion
object
{
const
val
RETRY_SEND_MESSAGE_ID
=
1
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
3e8ef19b
...
...
@@ -18,7 +18,6 @@ import android.support.v7.widget.DefaultItemAnimator
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.RecyclerView
import
android.view.*
import
androidx.core.content.systemService
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.*
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
...
...
@@ -70,8 +69,10 @@ private const val BUNDLE_CHAT_ROOM_LAST_SEEN = "chat_room_last_seen"
private
const
val
BUNDLE_CHAT_ROOM_IS_SUBSCRIBED
=
"chat_room_is_subscribed"
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiKeyboardListener
,
EmojiReactionListener
{
@Inject
lateinit
var
presenter
:
ChatRoomPresenter
@Inject
lateinit
var
parser
:
MessageParser
@Inject
lateinit
var
presenter
:
ChatRoomPresenter
@Inject
lateinit
var
parser
:
MessageParser
private
lateinit
var
adapter
:
ChatRoomAdapter
private
lateinit
var
chatRoomId
:
String
private
lateinit
var
chatRoomName
:
String
...
...
@@ -232,9 +233,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
// if y is positive the keyboard is up else it's down
recycler_view
.
post
{
if
(
y
>
0
||
Math
.
abs
(
verticalScrollOffset
.
get
())
>=
Math
.
abs
(
y
))
{
recycler_view
.
scrollBy
(
0
,
y
)
ui
{
recycler_view
.
scrollBy
(
0
,
y
)
}
}
else
{
recycler_view
.
scrollBy
(
0
,
verticalScrollOffset
.
get
())
ui
{
recycler_view
.
scrollBy
(
0
,
verticalScrollOffset
.
get
())
}
}
}
}
...
...
@@ -316,15 +317,14 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
override
fun
enableSendMessageButton
(
sendFailed
:
Boolean
)
{
override
fun
enableSendMessageButton
()
{
ui
{
button_send
.
isEnabled
=
true
text_message
.
isEnabled
=
true
if
(!
sendFailed
)
{
clearMessageComposition
()
}
}
}
override
fun
clearMessageComposition
()
{
ui
{
...
...
@@ -408,7 +408,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
copyToClipboard
(
message
:
String
)
{
ui
{
val
clipboard
:
ClipboardManager
=
it
.
systemService
()
val
clipboard
=
it
.
getSystemService
(
Context
.
CLIPBOARD_SERVICE
)
as
ClipboardManager
clipboard
.
primaryClip
=
ClipData
.
newPlainText
(
""
,
message
)
}
}
...
...
@@ -589,6 +589,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
var
textMessage
=
citation
?:
""
textMessage
+=
text_message
.
textContent
sendMessage
(
textMessage
)
clearMessageComposition
()
}
button_show_attachment_options
.
setOnClickListener
{
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/AudioAttachmentViewModel.kt
View file @
3e8ef19b
...
...
@@ -13,7 +13,8 @@ data class AudioAttachmentViewModel(
override
val
id
:
Long
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseFileAttachmentViewModel
<
AudioAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/AuthorAttachmentViewModel.kt
View file @
3e8ef19b
...
...
@@ -15,7 +15,8 @@ data class AuthorAttachmentViewModel(
override
val
messageId
:
String
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseAttachmentViewModel
<
AuthorAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
AUTHOR_ATTACHMENT
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/BaseViewModel.kt
View file @
3e8ef19b
...
...
@@ -12,6 +12,7 @@ interface BaseViewModel<out T> {
var
reactions
:
List
<
ReactionViewModel
>
var
nextDownStreamMessage
:
BaseViewModel
<*>?
var
preview
:
Message
?
var
isTemporary
:
Boolean
enum
class
ViewType
(
val
viewType
:
Int
)
{
MESSAGE
(
0
),
...
...
@@ -21,7 +22,8 @@ interface BaseViewModel<out T> {
VIDEO_ATTACHMENT
(
4
),
AUDIO_ATTACHMENT
(
5
),
MESSAGE_ATTACHMENT
(
6
),
AUTHOR_ATTACHMENT
(
7
)
AUTHOR_ATTACHMENT
(
7
),
COLOR_ATTACHMENT
(
8
)
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ColorAttachmentViewModel.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.chatroom.viewmodel
import
chat.rocket.android.R
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.attachment.ColorAttachment
data class
ColorAttachmentViewModel
(
override
val
attachmentUrl
:
String
,
val
id
:
Long
,
val
color
:
Int
,
val
text
:
CharSequence
,
override
val
message
:
Message
,
override
val
rawData
:
ColorAttachment
,
override
val
messageId
:
String
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseAttachmentViewModel
<
ColorAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
COLOR_ATTACHMENT
.
viewType
override
val
layoutId
:
Int
get
()
=
R
.
layout
.
item_color_attachment
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ImageAttachmentViewModel.kt
View file @
3e8ef19b
...
...
@@ -13,7 +13,8 @@ data class ImageAttachmentViewModel(
override
val
id
:
Long
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseFileAttachmentViewModel
<
ImageAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
IMAGE_ATTACHMENT
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/MessageAttachmentViewModel.kt
View file @
3e8ef19b
...
...
@@ -14,7 +14,8 @@ data class MessageAttachmentViewModel(
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
var
messageLink
:
String
?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseViewModel
<
Message
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
MESSAGE_ATTACHMENT
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/MessageViewModel.kt
View file @
3e8ef19b
...
...
@@ -15,7 +15,8 @@ data class MessageViewModel(
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
,
var
isFirstUnread
:
Boolean
var
isFirstUnread
:
Boolean
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseMessageViewModel
<
Message
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
MESSAGE
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/UrlPreviewViewModel.kt
View file @
3e8ef19b
...
...
@@ -14,7 +14,8 @@ data class UrlPreviewViewModel(
val
thumbUrl
:
String
?,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseViewModel
<
Url
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
URL_PREVIEW
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/VideoAttachmentViewModel.kt
View file @
3e8ef19b
...
...
@@ -13,7 +13,8 @@ data class VideoAttachmentViewModel(
override
val
id
:
Long
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseFileAttachmentViewModel
<
VideoAttachment
>
{
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
VIDEO_ATTACHMENT
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
View file @
3e8ef19b
...
...
@@ -5,6 +5,7 @@ import android.content.Context
import
android.graphics.Color
import
android.graphics.Typeface
import
android.support.v4.content.ContextCompat
import
android.text.Html
import
android.text.SpannableStringBuilder
import
android.text.style.ForegroundColorSpan
import
android.text.style.StyleSpan
...
...
@@ -106,10 +107,23 @@ class ViewModelMapper @Inject constructor(private val context: Context,
is
FileAttachment
->
mapFileAttachment
(
message
,
attachment
)
is
MessageAttachment
->
mapMessageAttachment
(
message
,
attachment
)
is
AuthorAttachment
->
mapAuthorAttachment
(
message
,
attachment
)
is
ColorAttachment
->
mapColorAttachment
(
message
,
attachment
)
else
->
null
}
}
private
suspend
fun
mapColorAttachment
(
message
:
Message
,
attachment
:
ColorAttachment
):
BaseViewModel
<
*
>?
{
return
with
(
attachment
)
{
val
content
=
stripMessageQuotes
(
message
)
val
id
=
attachmentId
(
message
,
attachment
)
ColorAttachmentViewModel
(
attachmentUrl
=
url
,
id
=
id
,
color
=
color
.
color
,
text
=
text
,
message
=
message
,
rawData
=
attachment
,
messageId
=
message
.
id
,
reactions
=
getReactions
(
message
),
preview
=
message
.
copy
(
message
=
content
.
message
))
}
}
private
suspend
fun
mapAuthorAttachment
(
message
:
Message
,
attachment
:
AuthorAttachment
):
AuthorAttachmentViewModel
{
return
with
(
attachment
)
{
val
content
=
stripMessageQuotes
(
message
)
...
...
@@ -212,12 +226,13 @@ class ViewModelMapper @Inject constructor(private val context: Context,
val
time
=
getTime
(
message
.
timestamp
)
val
avatar
=
getUserAvatar
(
message
)
val
preview
=
mapMessagePreview
(
message
)
val
isTemp
=
message
.
isTemporary
?:
false
val
content
=
getContent
(
stripMessageQuotes
(
message
))
MessageViewModel
(
message
=
stripMessageQuotes
(
message
),
rawData
=
message
,
messageId
=
message
.
id
,
avatar
=
avatar
!!
,
time
=
time
,
senderName
=
sender
,
content
=
content
,
isPinned
=
message
.
pinned
,
reactions
=
getReactions
(
message
),
isFirstUnread
=
false
,
preview
=
preview
)
isFirstUnread
=
false
,
preview
=
preview
,
isTemporary
=
isTemp
)
}
private
suspend
fun
mapMessagePreview
(
message
:
Message
):
Message
{
...
...
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
View file @
3e8ef19b
...
...
@@ -42,6 +42,7 @@ class ChatRoomsPresenter @Inject constructor(
private
val
saveChatRoomsInteractor
:
SaveChatRoomsInteractor
,
private
val
refreshSettingsInteractor
:
RefreshSettingsInteractor
,
private
val
viewModelMapper
:
ViewModelMapper
,
private
val
jobSchedulerInteractor
:
JobSchedulerInteractor
,
settingsRepository
:
SettingsRepository
,
factory
:
ConnectionManagerFactory
)
{
...
...
@@ -121,7 +122,8 @@ class ChatRoomsPresenter @Inject constructor(
private
fun
usersToChatRooms
(
users
:
List
<
User
>):
List
<
ChatRoom
>
{
return
users
.
map
{
ChatRoom
(
id
=
it
.
id
,
ChatRoom
(
id
=
it
.
id
,
type
=
RoomType
.
DIRECT_MESSAGE
,
user
=
SimpleUser
(
username
=
it
.
username
,
name
=
it
.
name
,
id
=
null
),
status
=
getActiveUserByUsername
(
it
.
name
!!
)
?.
status
,
...
...
@@ -148,7 +150,8 @@ class ChatRoomsPresenter @Inject constructor(
private
fun
roomsToChatRooms
(
rooms
:
List
<
Room
>):
List
<
ChatRoom
>
{
return
rooms
.
map
{
ChatRoom
(
id
=
it
.
id
,
ChatRoom
(
id
=
it
.
id
,
type
=
it
.
type
,
user
=
it
.
user
,
status
=
getActiveUserByUsername
(
it
.
name
!!
)
?.
status
,
...
...
@@ -254,6 +257,7 @@ class ChatRoomsPresenter @Inject constructor(
view
.
showConnectionState
(
state
)
}
if
(
state
is
State
.
Connected
)
{
jobSchedulerInteractor
.
scheduleSendingMessages
()
reloadRooms
()
updateChatRooms
()
}
...
...
@@ -339,7 +343,8 @@ class ChatRoomsPresenter @Inject constructor(
val
chatRooms
=
getChatRoomsInteractor
.
getAll
(
currentServer
).
toMutableList
()
val
chatRoom
=
chatRooms
.
find
{
chatRoom
->
chatRoom
.
id
==
room
.
id
}
chatRoom
?.
apply
{
val
newRoom
=
ChatRoom
(
id
=
room
.
id
,
val
newRoom
=
ChatRoom
(
id
=
room
.
id
,
type
=
room
.
type
,
user
=
room
.
user
?:
user
,
status
=
getActiveUserByUsername
(
room
.
name
!!
)
?.
status
,
...
...
@@ -360,7 +365,8 @@ class ChatRoomsPresenter @Inject constructor(
userMenstions
=
userMenstions
,
groupMentions
=
groupMentions
,
lastMessage
=
room
.
lastMessage
,
client
=
client
)
client
=
client
)
removeRoom
(
room
.
id
,
chatRooms
)
chatRooms
.
add
(
newRoom
)
saveChatRoomsInteractor
.
save
(
currentServer
,
sortRooms
(
chatRooms
))
...
...
@@ -373,7 +379,8 @@ class ChatRoomsPresenter @Inject constructor(
val
chatRooms
=
getChatRoomsInteractor
.
getAll
(
currentServer
).
toMutableList
()
val
chatRoom
=
chatRooms
.
find
{
chatRoom
->
chatRoom
.
id
==
subscription
.
roomId
}
chatRoom
?.
apply
{
val
newRoom
=
ChatRoom
(
id
=
subscription
.
roomId
,
val
newRoom
=
ChatRoom
(
id
=
subscription
.
roomId
,
type
=
subscription
.
type
,
user
=
subscription
.
user
?:
user
,
status
=
getActiveUserByUsername
(
subscription
.
name
)
?.
status
,
...
...
@@ -394,7 +401,8 @@ class ChatRoomsPresenter @Inject constructor(
userMenstions
=
subscription
.
userMentions
,
groupMentions
=
subscription
.
groupMentions
,
lastMessage
=
lastMessage
,
client
=
client
)
client
=
client
)
removeRoom
(
subscription
.
roomId
,
chatRooms
)
chatRooms
.
add
(
newRoom
)
saveChatRoomsInteractor
.
save
(
currentServer
,
sortRooms
(
chatRooms
))
...
...
app/src/main/java/chat/rocket/android/core/behaviours/MessageView.kt
View file @
3e8ef19b
package
chat.rocket.android.core.behaviours
import
android.support.annotation.StringRes
import
chat.rocket.common.util.ifNull
interface
MessageView
{
...
...
@@ -15,3 +16,11 @@ interface MessageView {
fun
showGenericErrorMessage
()
}
fun
MessageView
.
showMessage
(
ex
:
Exception
)
{
ex
.
message
?.
let
{
showMessage
(
it
)
}.
ifNull
{
showGenericErrorMessage
()
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/dagger/AppComponent.kt
View file @
3e8ef19b
...
...
@@ -2,6 +2,7 @@ package chat.rocket.android.dagger
import
android.app.Application
import
chat.rocket.android.app.RocketChatApplication
import
chat.rocket.android.chatroom.service.MessageService
import
chat.rocket.android.dagger.module.ActivityBuilder
import
chat.rocket.android.dagger.module.AppModule
import
chat.rocket.android.dagger.module.ReceiverBuilder
...
...
@@ -29,6 +30,8 @@ interface AppComponent {
fun
inject
(
service
:
FirebaseTokenService
)
fun
inject
(
service
:
MessageService
)
/*@Component.Builder
abstract class Builder : AndroidInjector.Builder<RocketChatApplication>()*/
}
app/src/main/java/chat/rocket/android/dagger/module/AppModule.kt
View file @
3e8ef19b
...
...
@@ -2,16 +2,20 @@ package chat.rocket.android.dagger.module
import
android.app.Application
import
android.app.NotificationManager
import
android.app.job.JobInfo
import
android.app.job.JobScheduler
import
android.arch.persistence.room.Room
import
android.content.ComponentName
import
android.content.Context
import
android.content.SharedPreferences
import
androidx.core.content.systemService
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.app.RocketChatDatabase
import
chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository
import
chat.rocket.android.authentication.infraestructure.SharedPreferencesTokenRepository
import
chat.rocket.android.chatroom.service.MessageService
import
chat.rocket.android.dagger.qualifier.ForFresco
import
chat.rocket.android.dagger.qualifier.ForMessages
import
chat.rocket.android.helper.FrescoAuthInterceptor
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.infrastructure.LocalRepository
...
...
@@ -20,11 +24,39 @@ import chat.rocket.android.push.GroupedPush
import
chat.rocket.android.push.PushManager
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.*
import
chat.rocket.android.server.domain.AccountsRepository
import
chat.rocket.android.server.domain.ChatRoomsRepository
import
chat.rocket.android.server.domain.CurrentServerRepository
import
chat.rocket.android.server.domain.GetAccountInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.GetPermissionsInteractor
import
chat.rocket.android.server.domain.GetSettingsInteractor
import
chat.rocket.android.server.domain.JobSchedulerInteractor
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.android.server.domain.MultiServerTokenRepository
import
chat.rocket.android.server.domain.RoomRepository
import
chat.rocket.android.server.domain.SettingsRepository
import
chat.rocket.android.server.domain.TokenRepository
import
chat.rocket.android.server.domain.UsersRepository
import
chat.rocket.android.server.infraestructure.JobSchedulerInteractorImpl
import
chat.rocket.android.server.infraestructure.MemoryChatRoomsRepository
import
chat.rocket.android.server.infraestructure.MemoryRoomRepository
import
chat.rocket.android.server.infraestructure.MemoryUsersRepository
import
chat.rocket.android.server.infraestructure.ServerDao
import
chat.rocket.android.server.infraestructure.SharedPreferencesAccountsRepository
import
chat.rocket.android.server.infraestructure.SharedPreferencesMessagesRepository
import
chat.rocket.android.server.infraestructure.SharedPreferencesSettingsRepository
import
chat.rocket.android.server.infraestructure.SharedPrefsCurrentServerRepository
import
chat.rocket.android.util.AppJsonAdapterFactory
import
chat.rocket.android.util.TimberLogger
import
chat.rocket.common.internal.FallbackSealedClassJsonAdapter
import
chat.rocket.common.internal.ISO8601Date
import
chat.rocket.common.model.TimestampAdapter
import
chat.rocket.common.util.CalendarISO8601Converter
import
chat.rocket.common.util.Logger
import
chat.rocket.common.util.PlatformLogger
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.AttachmentAdapterFactory
import
com.facebook.drawee.backends.pipeline.DraweeConfig
import
com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory
import
com.facebook.imagepipeline.core.ImagePipelineConfig
...
...
@@ -64,7 +96,7 @@ class AppModule {
@Provides
@Singleton
fun
provideRocketChatDatabase
(
context
:
Application
):
RocketChatDatabase
{
return
Room
.
databaseBuilder
(
context
,
RocketChatDatabase
::
class
.
java
,
"rocketchat-db"
).
build
()
return
Room
.
databaseBuilder
(
context
.
applicationContext
,
RocketChatDatabase
::
class
.
java
,
"rocketchat-db"
).
build
()
}
@Provides
...
...
@@ -114,7 +146,7 @@ class AppModule {
@Provides
@ForFresco
@Singleton
fun
provideFrescoAuthIntercept
e
r
(
tokenRepository
:
TokenRepository
,
currentServerInteractor
:
GetCurrentServerInteractor
):
Interceptor
{
fun
provideFrescoAuthIntercept
o
r
(
tokenRepository
:
TokenRepository
,
currentServerInteractor
:
GetCurrentServerInteractor
):
Interceptor
{
return
FrescoAuthInterceptor
(
tokenRepository
,
currentServerInteractor
)
}
...
...
@@ -159,9 +191,14 @@ class AppModule {
}
@Provides
fun
provideSharedPreferences
(
context
:
Application
):
SharedPreferences
{
return
context
.
getSharedPreferences
(
"rocket.chat"
,
Context
.
MODE_PRIVATE
)
}
fun
provideSharedPreferences
(
context
:
Application
)
=
context
.
getSharedPreferences
(
"rocket.chat"
,
Context
.
MODE_PRIVATE
)
@Provides
@ForMessages
fun
provideMessagesSharedPreferences
(
context
:
Application
)
=
context
.
getSharedPreferences
(
"messages"
,
Context
.
MODE_PRIVATE
)
@Provides
@Singleton
...
...
@@ -201,10 +238,25 @@ class AppModule {
@Provides
@Singleton
fun
provideMoshi
():
Moshi
{
fun
provideMoshi
(
logger
:
PlatformLogger
,
currentServerInteractor
:
GetCurrentServerInteractor
):
Moshi
{
val
url
=
currentServerInteractor
.
get
()
?:
""
return
Moshi
.
Builder
()
.
add
(
FallbackSealedClassJsonAdapter
.
ADAPTER_FACTORY
)
.
add
(
AppJsonAdapterFactory
.
INSTANCE
)
.
add
(
AttachmentAdapterFactory
(
Logger
(
logger
,
url
)))
.
add
(
java
.
lang
.
Long
::
class
.
java
,
ISO8601Date
::
class
.
java
,
TimestampAdapter
(
CalendarISO8601Converter
())
)
.
add
(
Long
::
class
.
java
,
ISO8601Date
::
class
.
java
,
TimestampAdapter
(
CalendarISO8601Converter
())
)
.
build
()
}
...
...
@@ -216,8 +268,10 @@ class AppModule {
@Provides
@Singleton
fun
provideMessageRepository
():
MessagesRepository
{
return
MemoryMessagesRepository
()
fun
provideMessageRepository
(
@ForMessages
preferences
:
SharedPreferences
,
moshi
:
Moshi
,
currentServerInteractor
:
GetCurrentServerInteractor
):
MessagesRepository
{
return
SharedPreferencesMessagesRepository
(
preferences
,
moshi
,
currentServerInteractor
)
}
@Provides
...
...
@@ -260,7 +314,8 @@ class AppModule {
SharedPreferencesAccountsRepository
(
preferences
,
moshi
)
@Provides
fun
provideNotificationManager
(
context
:
Context
):
NotificationManager
=
context
.
systemService
()
fun
provideNotificationManager
(
context
:
Application
)
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
@Provides
@Singleton
...
...
@@ -269,7 +324,7 @@ class AppModule {
@Provides
@Singleton
fun
providePushManager
(
context
:
Context
,
context
:
Application
,
groupedPushes
:
GroupedPush
,
manager
:
NotificationManager
,
moshi
:
Moshi
,
...
...
@@ -277,4 +332,22 @@ class AppModule {
getSettingsInteractor
:
GetSettingsInteractor
):
PushManager
{
return
PushManager
(
groupedPushes
,
manager
,
moshi
,
getAccountInteractor
,
getSettingsInteractor
,
context
)
}
@Provides
fun
provideJobScheduler
(
context
:
Application
):
JobScheduler
{
return
context
.
getSystemService
(
Context
.
JOB_SCHEDULER_SERVICE
)
as
JobScheduler
}
@Provides
fun
provideSendMessageJob
(
context
:
Application
):
JobInfo
{
return
JobInfo
.
Builder
(
MessageService
.
RETRY_SEND_MESSAGE_ID
,
ComponentName
(
context
,
MessageService
::
class
.
java
))
.
setRequiredNetworkType
(
JobInfo
.
NETWORK_TYPE_ANY
)
.
build
()
}
@Provides
fun
provideJobSchedulerInteractor
(
jobScheduler
:
JobScheduler
,
jobInfo
:
JobInfo
):
JobSchedulerInteractor
{
return
JobSchedulerInteractorImpl
(
jobScheduler
,
jobInfo
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/dagger/module/ServiceBuilder.kt
View file @
3e8ef19b
package
chat.rocket.android.dagger.module
import
chat.rocket.android.chatroom.di.MessageServiceProvider
import
chat.rocket.android.chatroom.service.MessageService
import
chat.rocket.android.push.FirebaseTokenService
import
chat.rocket.android.push.GcmListenerService
import
chat.rocket.android.push.di.FirebaseTokenServiceProvider
...
...
@@ -14,4 +16,7 @@ import dagger.android.ContributesAndroidInjector
@ContributesAndroidInjector
(
modules
=
[
GcmListenerServiceProvider
::
class
])
abstract
fun
bindGcmListenerService
():
GcmListenerService
@ContributesAndroidInjector
(
modules
=
[
MessageServiceProvider
::
class
])
abstract
fun
bindMessageService
():
MessageService
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/dagger/qualifier/ForMessages.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.dagger.qualifier
import
javax.inject.Qualifier
/**
* Created by luciofm on 4/14/18.
*/
@Qualifier
@Retention
(
AnnotationRetention
.
RUNTIME
)
annotation
class
ForMessages
\ No newline at end of file
app/src/main/java/chat/rocket/android/infrastructure/LocalRepository.kt
View file @
3e8ef19b
...
...
@@ -24,4 +24,5 @@ interface LocalRepository {
}
}
fun
LocalRepository
.
checkIfMyself
(
username
:
String
)
=
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
==
username
\ No newline at end of file
fun
LocalRepository
.
checkIfMyself
(
username
:
String
)
=
username
()
==
username
fun
LocalRepository
.
username
()
=
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
3e8ef19b
...
...
@@ -23,9 +23,7 @@ import chat.rocket.core.internal.rest.logout
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.unregisterPushToken
import
chat.rocket.core.model.Myself
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.channels.Channel
import
kotlinx.coroutines.experimental.launch
import
timber.log.Timber
import
javax.inject.Inject
...
...
@@ -39,11 +37,11 @@ class MainPresenter @Inject constructor(
private
val
navHeaderMapper
:
NavHeaderViewModelMapper
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
private
val
removeAccountInterector
:
RemoveAccountIntere
ctor
,
private
val
removeAccountInteractor
:
RemoveAccountIntera
ctor
,
private
val
factory
:
RocketChatClientFactory
,
getSettingsInteractor
:
GetSettingsInteractor
,
managerFactory
:
ConnectionManagerFactory
)
:
CheckServerPresenter
(
strategy
,
client
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
,
view
=
view
)
{
)
:
CheckServerPresenter
(
strategy
,
factory
,
view
=
view
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
manager
=
managerFactory
.
create
(
currentServer
)
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
...
...
@@ -58,7 +56,7 @@ class MainPresenter @Inject constructor(
fun
toSettings
()
=
navigator
.
toSettings
()
fun
loadCurrentInfo
()
{
checkServerInfo
()
checkServerInfo
(
currentServer
)
launchUI
(
strategy
)
{
try
{
val
me
=
retryIO
(
"me"
)
{
...
...
@@ -105,7 +103,7 @@ class MainPresenter @Inject constructor(
try
{
disconnect
()
removeAccountInter
e
ctor
.
remove
(
currentServer
)
removeAccountInter
a
ctor
.
remove
(
currentServer
)
tokenRepository
.
remove
(
currentServer
)
navigator
.
toNewServer
()
}
catch
(
ex
:
Exception
)
{
...
...
app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt
View file @
3e8ef19b
package
chat.rocket.android.profile.presentation
import
chat.rocket.android.core.behaviours.showMessage
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
...
...
@@ -36,11 +37,7 @@ class ProfilePresenter @Inject constructor(private val view: ProfileView,
myself
.
emails
?.
get
(
0
)
?.
address
!!
)
}
catch
(
exception
:
RocketChatException
)
{
exception
.
message
?.
let
{
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
view
.
showMessage
(
exception
)
}
finally
{
view
.
hideLoading
()
}
...
...
app/src/main/java/chat/rocket/android/profile/ui/ProfileFragment.kt
View file @
3e8ef19b
...
...
@@ -12,6 +12,7 @@ import chat.rocket.android.profile.presentation.ProfilePresenter
import
chat.rocket.android.profile.presentation.ProfileView
import
chat.rocket.android.util.extensions.*
import
dagger.android.support.AndroidSupportInjection
import
io.reactivex.disposables.CompositeDisposable
import
io.reactivex.rxkotlin.Observables
import
kotlinx.android.synthetic.main.app_bar.*
import
kotlinx.android.synthetic.main.avatar_profile.*
...
...
@@ -25,6 +26,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
private
lateinit
var
currentEmail
:
String
private
lateinit
var
currentAvatar
:
String
private
var
actionMode
:
ActionMode
?
=
null
private
val
disposables
=
CompositeDisposable
()
companion
object
{
fun
newInstance
()
=
ProfileFragment
()
...
...
@@ -48,7 +50,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
presenter
.
loadUserProfile
()
}
override
fun
onDestroyView
()
{
disposables
.
clear
()
super
.
onDestroyView
()
}
override
fun
showProfile
(
avatarUrl
:
String
,
name
:
String
,
username
:
String
,
email
:
String
)
{
ui
{
image_avatar
.
setImageURI
(
avatarUrl
)
text_name
.
textContent
=
name
...
...
@@ -65,6 +73,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
listenToChanges
()
}
}
override
fun
showProfileUpdateSuccessfullyMessage
()
{
showMessage
(
getString
(
R
.
string
.
msg_profile_update_successfully
))
...
...
@@ -72,23 +81,31 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override
fun
showLoading
()
{
enableUserInput
(
false
)
ui
{
view_loading
.
setVisible
(
true
)
}
}
override
fun
hideLoading
()
{
ui
{
if
(
view_loading
!=
null
)
{
view_loading
.
setVisible
(
false
)
}
}
enableUserInput
(
true
)
}
override
fun
showMessage
(
resId
:
Int
)
{
ui
{
showToast
(
resId
)
}
}
override
fun
showMessage
(
message
:
String
)
{
ui
{
showToast
(
message
)
}
}
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
...
...
@@ -136,7 +153,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
private
fun
listenToChanges
()
{
Observables
.
combineLatest
(
text_name
.
asObservable
(),
disposables
.
add
(
Observables
.
combineLatest
(
text_name
.
asObservable
(),
text_username
.
asObservable
(),
text_email
.
asObservable
(),
text_avatar_url
.
asObservable
())
{
text_name
,
text_username
,
text_email
,
text_avatar_url
->
...
...
@@ -144,7 +161,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
text_username
.
toString
()
!=
currentUsername
||
text_email
.
toString
()
!=
currentEmail
||
(
text_avatar_url
.
toString
()
!=
""
&&
text_avatar_url
.
toString
()
!=
currentAvatar
))
}.
subscribe
(
{
isValid
->
}.
subscribe
{
isValid
->
if
(
isValid
)
{
startActionMode
()
}
else
{
...
...
@@ -162,9 +179,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
private
fun
finishActionMode
()
=
actionMode
?.
finish
()
private
fun
enableUserInput
(
value
:
Boolean
)
{
ui
{
text_username
.
isEnabled
=
value
text_username
.
isEnabled
=
value
text_email
.
isEnabled
=
value
text_avatar_url
.
isEnabled
=
value
}
}
}
app/src/main/java/chat/rocket/android/push/FirebaseTokenService.kt
View file @
3e8ef19b
...
...
@@ -4,6 +4,7 @@ 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.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.internal.rest.registerPushToken
import
com.google.android.gms.gcm.GoogleCloudMessaging
...
...
@@ -32,6 +33,7 @@ class FirebaseTokenService : FirebaseInstanceIdService() {
override
fun
onTokenRefresh
()
{
//TODO: We need to use the Cordova Project gcm_sender_id since it's the one configured on RC
// default push gateway. We should register this project's own project sender id into it.
try
{
val
gcmToken
=
InstanceID
.
getInstance
(
this
)
.
getToken
(
getString
(
R
.
string
.
gcm_sender_id
),
GoogleCloudMessaging
.
INSTANCE_ID_SCOPE
,
null
)
val
currentServer
=
getCurrentServerInteractor
.
get
()
...
...
@@ -43,12 +45,15 @@ class FirebaseTokenService : FirebaseInstanceIdService() {
launch
{
try
{
Timber
.
d
(
"Registering push token: $gcmToken for ${client.url}"
)
client
.
registerPushToken
(
gcmToken
)
retryIO
(
"register push token"
)
{
client
.
registerPushToken
(
gcmToken
)
}
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
Timber
.
e
(
ex
,
"Error registering push token"
)
}
}
}
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error refreshing Firebase TOKEN"
)
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/domain/JobSchedulerInteractor.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.server.domain
interface
JobSchedulerInteractor
{
/**
* Schedule job to retry previously failed sending messages.
*/
fun
scheduleSendingMessages
()
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/domain/MessagesRepository.kt
View file @
3e8ef19b
...
...
@@ -11,7 +11,7 @@ interface MessagesRepository {
*
* @return The Message object given by the id or null if message wasn't found.
*/
fun
getById
(
id
:
String
):
Message
?
suspend
fun
getById
(
id
:
String
):
Message
?
/**
* Get all messages from the current room id.
...
...
@@ -19,7 +19,7 @@ interface MessagesRepository {
* @param rid The room id.
* @return A list of Message objects for the room with given room id or an empty list.
*/
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
suspend
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
/**
* Get most recent messages up to count different users.
...
...
@@ -29,43 +29,47 @@ interface MessagesRepository {
*
* @return List of last count messages.
*/
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
suspend
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
/**
* Get all messages. Use carefully!
*
* @return All messages or an empty list.
*/
fun
getAll
():
List
<
Message
>
suspend
fun
getAll
():
List
<
Message
>
/**
* Save a single message object.
*
* @param The message object to saveAll.
*/
fun
save
(
message
:
Message
)
suspend
fun
save
(
message
:
Message
)
/**
* Save a list of messages.
*/
fun
saveAll
(
newMessages
:
List
<
Message
>)
suspend
fun
saveAll
(
newMessages
:
List
<
Message
>)
/**
* Removes all messages.
*/
fun
clear
()
suspend
fun
clear
()
/**
* Remove message by id.
*
* @param id The id of the message to remove.
*/
fun
removeById
(
id
:
String
)
suspend
fun
removeById
(
id
:
String
)
/**
* Remove all messages from a given room.
*
* @param rid The room id where messages are to be removed.
*/
fun
removeByRoomId
(
rid
:
String
)
suspend
fun
removeByRoomId
(
rid
:
String
)
suspend
fun
getAllUnsent
():
List
<
Message
>
suspend
fun
getUnsentByRoomId
(
roomId
:
String
):
List
<
Message
>
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/domain/RefreshSettingsInteractor.kt
View file @
3e8ef19b
package
chat.rocket.android.server.domain
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.retryIO
import
chat.rocket.core.internal.rest.settings
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.async
...
...
@@ -27,7 +28,9 @@ class RefreshSettingsInteractor @Inject constructor(private val factory: RocketC
suspend
fun
refresh
(
server
:
String
)
{
withContext
(
CommonPool
)
{
factory
.
create
(
server
).
let
{
client
->
val
settings
=
client
.
settings
(*
settingsFilter
)
val
settings
=
retryIO
(
description
=
"settings"
,
times
=
5
)
{
client
.
settings
(*
settingsFilter
)
}
repository
.
save
(
server
,
settings
)
}
}
...
...
app/src/main/java/chat/rocket/android/server/domain/RemoveAccountInter
e
ctor.kt
→
app/src/main/java/chat/rocket/android/server/domain/RemoveAccountInter
a
ctor.kt
View file @
3e8ef19b
...
...
@@ -2,7 +2,7 @@ package chat.rocket.android.server.domain
import
javax.inject.Inject
class
RemoveAccountInter
e
ctor
@Inject
constructor
(
val
repository
:
AccountsRepository
)
{
class
RemoveAccountInter
a
ctor
@Inject
constructor
(
val
repository
:
AccountsRepository
)
{
suspend
fun
remove
(
serverUrl
:
String
)
{
repository
.
remove
(
serverUrl
)
}
...
...
app/src/main/java/chat/rocket/android/server/infraestructure/JobSchedulerInteractorImpl.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.server.infraestructure
import
android.app.job.JobInfo
import
android.app.job.JobScheduler
import
chat.rocket.android.server.domain.JobSchedulerInteractor
import
timber.log.Timber
import
javax.inject.Inject
/**
* Uses the Android framework [JobScheduler].
*/
class
JobSchedulerInteractorImpl
@Inject
constructor
(
private
val
jobScheduler
:
JobScheduler
,
private
val
jobInfo
:
JobInfo
)
:
JobSchedulerInteractor
{
override
fun
scheduleSendingMessages
()
{
Timber
.
d
(
"Scheduling unsent messages to send..."
)
jobScheduler
.
schedule
(
jobInfo
)
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/infraestructure/MemoryMessagesRepository.kt
View file @
3e8ef19b
...
...
@@ -2,45 +2,67 @@ package chat.rocket.android.server.infraestructure
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.core.model.Message
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.withContext
class
MemoryMessagesRepository
:
MessagesRepository
{
private
val
messages
:
HashMap
<
String
,
Message
>
=
HashMap
()
override
fun
getById
(
id
:
String
):
Message
?
{
return
messages
[
id
]
override
suspend
fun
getById
(
id
:
String
):
Message
?
=
withContext
(
CommonPool
)
{
return
@withContext
messages
[
id
]
}
override
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
{
return
messages
.
filter
{
it
.
value
.
roomId
==
rid
}.
values
.
toList
()
override
suspend
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
return
@withContext
messages
.
filter
{
it
.
value
.
roomId
==
rid
}.
values
.
toList
()
}
override
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
{
return
getByRoomId
(
rid
).
sortedByDescending
{
it
.
timestamp
}
override
suspend
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
return
@withContext
getByRoomId
(
rid
).
sortedByDescending
{
it
.
timestamp
}
.
distinctBy
{
it
.
sender
}.
take
(
count
.
toInt
())
}
override
fun
getAll
():
List
<
Message
>
=
messages
.
values
.
toList
()
override
suspend
fun
getAll
():
List
<
Message
>
=
withContext
(
CommonPool
)
{
return
@withContext
messages
.
values
.
toList
()
}
override
suspend
fun
getUnsentByRoomId
(
roomId
:
String
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
val
allByRoomId
=
getByRoomId
(
roomId
)
if
(
allByRoomId
.
isEmpty
())
{
return
@withContext
emptyList
<
Message
>()
}
return
@withContext
allByRoomId
.
filter
{
it
.
isTemporary
?:
false
&&
it
.
roomId
==
roomId
}
}
override
fun
save
(
message
:
Message
)
{
override
suspend
fun
getAllUnsent
():
List
<
Message
>
=
withContext
(
CommonPool
)
{
val
all
=
getAll
()
if
(
all
.
isEmpty
())
{
return
@withContext
emptyList
<
Message
>()
}
return
@withContext
all
.
filter
{
it
.
isTemporary
?:
false
}
}
override
suspend
fun
save
(
message
:
Message
)
=
withContext
(
CommonPool
)
{
messages
[
message
.
id
]
=
message
}
override
fun
saveAll
(
newMessages
:
List
<
Message
>
)
{
override
suspend
fun
saveAll
(
newMessages
:
List
<
Message
>)
=
withContext
(
CommonPool
)
{
for
(
msg
in
newMessages
)
{
messages
[
msg
.
id
]
=
msg
}
}
override
fun
clear
(
)
{
override
suspend
fun
clear
()
=
withContext
(
CommonPool
)
{
messages
.
clear
()
}
override
fun
removeById
(
id
:
String
)
{
override
suspend
fun
removeById
(
id
:
String
)
{
withContext
(
CommonPool
)
{
messages
.
remove
(
id
)
}
}
override
fun
removeByRoomId
(
rid
:
String
)
{
override
suspend
fun
removeByRoomId
(
rid
:
String
)
=
withContext
(
CommonPool
)
{
val
roomMessages
=
messages
.
filter
{
it
.
value
.
roomId
==
rid
}.
values
roomMessages
.
forEach
{
messages
.
remove
(
it
.
roomId
)
...
...
app/src/main/java/chat/rocket/android/server/infraestructure/SharedPreferencesMessagesRepository.kt
0 → 100644
View file @
3e8ef19b
package
chat.rocket.android.server.infraestructure
import
android.content.SharedPreferences
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.core.model.Message
import
com.squareup.moshi.Moshi
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.withContext
class
SharedPreferencesMessagesRepository
(
private
val
prefs
:
SharedPreferences
,
private
val
moshi
:
Moshi
,
private
val
currentServerInteractor
:
GetCurrentServerInteractor
)
:
MessagesRepository
{
override
suspend
fun
getById
(
id
:
String
):
Message
?
=
withContext
(
CommonPool
)
{
currentServerInteractor
.
get
()
?.
also
{
server
->
if
(
prefs
.
all
.
values
.
isEmpty
())
{
return
@withContext
null
}
val
adapter
=
moshi
.
adapter
<
Message
>(
Message
::
class
.
java
)
val
values
=
prefs
.
all
.
entries
.
filter
{
it
.
key
.
startsWith
(
server
)
}
.
map
{
it
.
value
}
as
Collection
<
String
>
return
@withContext
values
.
map
{
adapter
.
fromJson
(
it
)
}.
firstOrNull
{
it
?.
id
==
id
}
}
return
@withContext
null
}
override
suspend
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
currentServerInteractor
.
get
()
?.
also
{
server
->
val
adapter
=
moshi
.
adapter
<
Message
>(
Message
::
class
.
java
)
if
(
prefs
.
all
.
values
.
isEmpty
())
{
return
@withContext
emptyList
<
Message
>()
}
val
values
=
prefs
.
all
.
entries
.
filter
{
it
.
key
.
startsWith
(
server
)
}
.
map
{
it
.
value
}
as
Collection
<
String
>
return
@withContext
values
.
mapNotNull
{
adapter
.
fromJson
(
it
)
}.
filter
{
it
.
roomId
==
rid
}.
toList
().
sortedWith
(
compareBy
(
Message
::
timestamp
)).
reversed
()
}
return
@withContext
emptyList
<
Message
>()
}
override
suspend
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
return
@withContext
getByRoomId
(
rid
).
sortedByDescending
{
it
.
timestamp
}
.
distinctBy
{
it
.
sender
}.
take
(
count
.
toInt
())
}
override
suspend
fun
getAll
():
List
<
Message
>
=
withContext
(
CommonPool
)
{
val
adapter
=
moshi
.
adapter
<
Message
>(
Message
::
class
.
java
)
if
(
prefs
.
all
.
values
.
isEmpty
())
{
return
@withContext
emptyList
<
Message
>()
}
currentServerInteractor
.
get
()
?.
also
{
server
->
val
values
=
prefs
.
all
.
entries
.
filter
{
it
.
key
.
startsWith
(
server
)
}
.
map
{
it
.
value
}
as
Collection
<
String
>
return
@withContext
values
.
mapNotNull
{
adapter
.
fromJson
(
it
)
}
}
return
@withContext
emptyList
<
Message
>()
}
override
suspend
fun
getAllUnsent
():
List
<
Message
>
=
withContext
(
CommonPool
)
{
if
(
prefs
.
all
.
values
.
isEmpty
())
{
return
@withContext
emptyList
<
Message
>()
}
currentServerInteractor
.
get
()
?.
also
{
server
->
val
values
=
prefs
.
all
.
entries
.
filter
{
it
.
key
.
startsWith
(
server
)
}
.
map
{
it
.
value
}
as
Collection
<
String
>
val
adapter
=
moshi
.
adapter
<
Message
>(
Message
::
class
.
java
)
return
@withContext
values
.
mapNotNull
{
adapter
.
fromJson
(
it
)
}
.
filter
{
it
.
isTemporary
?:
false
}
}
return
@withContext
emptyList
<
Message
>()
}
override
suspend
fun
getUnsentByRoomId
(
roomId
:
String
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
val
allByRoomId
=
getByRoomId
(
roomId
)
if
(
allByRoomId
.
isEmpty
())
{
return
@withContext
emptyList
<
Message
>()
}
return
@withContext
allByRoomId
.
filter
{
it
.
isTemporary
?:
false
}
}
override
suspend
fun
save
(
message
:
Message
)
{
withContext
(
CommonPool
)
{
currentServerInteractor
.
get
()
?.
also
{
val
adapter
=
moshi
.
adapter
<
Message
>(
Message
::
class
.
java
)
prefs
.
edit
().
putString
(
"${it}_${message.id}"
,
adapter
.
toJson
(
message
)).
apply
()
}
}
}
override
suspend
fun
saveAll
(
newMessages
:
List
<
Message
>)
{
withContext
(
CommonPool
)
{
currentServerInteractor
.
get
()
?.
also
{
val
adapter
=
moshi
.
adapter
<
Message
>(
Message
::
class
.
java
)
val
editor
=
prefs
.
edit
()
for
(
msg
in
newMessages
)
{
editor
.
putString
(
"${it}_${msg.id}"
,
adapter
.
toJson
(
msg
))
}
editor
.
apply
()
}
}
}
override
suspend
fun
clear
()
=
withContext
(
CommonPool
)
{
prefs
.
edit
().
clear
().
apply
()
}
override
suspend
fun
removeById
(
id
:
String
)
{
withContext
(
CommonPool
)
{
currentServerInteractor
.
get
()
?.
also
{
prefs
.
edit
().
putString
(
"${it}_$id"
,
null
).
apply
()
}
}
}
override
suspend
fun
removeByRoomId
(
rid
:
String
)
{
withContext
(
CommonPool
)
{
currentServerInteractor
.
get
()
?.
also
{
server
->
val
adapter
=
moshi
.
adapter
<
Message
>(
Message
::
class
.
java
)
val
editor
=
prefs
.
edit
()
prefs
.
all
.
entries
.
forEach
{
val
value
=
it
.
value
if
(
value
is
String
)
{
val
message
=
adapter
.
fromJson
(
value
)
if
(
message
?.
roomId
==
rid
)
{
editor
.
putString
(
"${server}_${message.id}"
,
null
)
}
}
}
editor
.
apply
()
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt
View file @
3e8ef19b
...
...
@@ -3,19 +3,51 @@ package chat.rocket.android.server.presentation
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.authentication.server.presentation.VersionCheckView
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.VersionInfo
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.serverInfo
import
kotlinx.coroutines.experimental.Deferred
import
kotlinx.coroutines.experimental.Job
import
kotlinx.coroutines.experimental.async
import
timber.log.Timber
abstract
class
CheckServerPresenter
constructor
(
private
val
strategy
:
CancelStrategy
,
private
val
client
:
RocketChatClient
,
private
val
factory
:
RocketChatClientFactory
,
private
val
view
:
VersionCheckView
)
{
internal
fun
checkServerInfo
()
{
launchUI
(
strategy
)
{
private
lateinit
var
currentServer
:
String
private
val
client
:
RocketChatClient
by
lazy
{
factory
.
create
(
currentServer
)
}
internal
fun
checkServerInfo
(
serverUrl
:
String
):
Job
{
return
launchUI
(
strategy
)
{
try
{
val
version
=
checkServerVersion
(
serverUrl
).
await
()
when
(
version
)
{
is
Version
.
VersionOk
->
{
Timber
.
i
(
"Your version is nice! (Requires: 0.62.0, Yours: ${version.version})"
)
}
is
Version
.
RecommendedVersionWarning
->
{
Timber
.
i
(
"Your server ${version.version} is bellow recommended version ${BuildConfig.RECOMMENDED_SERVER_VERSION}"
)
view
.
alertNotRecommendedVersion
()
}
is
Version
.
OutOfDateError
->
{
Timber
.
i
(
"Oops. Looks like your server ${version.version} is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!"
)
view
.
blockAndAlertNotRequiredVersion
()
}
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error getting server info"
)
}
}
}
internal
fun
checkServerVersion
(
serverUrl
:
String
):
Deferred
<
Version
>
{
currentServer
=
serverUrl
return
async
{
val
serverInfo
=
retryIO
(
description
=
"serverInfo"
,
times
=
5
)
{
client
.
serverInfo
()
}
val
thisServerVersion
=
serverInfo
.
version
val
isRequiredVersion
=
isRequiredServerVersion
(
thisServerVersion
)
...
...
@@ -23,17 +55,12 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
if
(
isRequiredVersion
)
{
if
(
isRecommendedVersion
)
{
Timber
.
i
(
"Your version is nice! (Requires: 0.62.0, Yours: $thisServerVersion)"
)
return
@async
Version
.
VersionOk
(
thisServerVersion
)
}
else
{
view
.
alertNotRecommendedVersion
(
)
return
@async
Version
.
RecommendedVersionWarning
(
thisServerVersion
)
}
}
else
{
if
(!
isRecommendedVersion
)
{
view
.
blockAndAlertNotRequiredVersion
()
Timber
.
i
(
"Oops. Looks like your server is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!"
)
}
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error getting server info"
)
return
@async
Version
.
OutOfDateError
(
thisServerVersion
)
}
}
}
...
...
@@ -92,4 +119,10 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
0
}
}
sealed
class
Version
(
val
version
:
String
)
{
data class
VersionOk
(
private
val
currentVersion
:
String
)
:
Version
(
currentVersion
)
data class
RecommendedVersionWarning
(
private
val
currentVersion
:
String
)
:
Version
(
currentVersion
)
data class
OutOfDateError
(
private
val
currentVersion
:
String
)
:
Version
(
currentVersion
)
}
}
\ No newline at end of file
app/src/main/res/layout/fragment_profile.xml
View file @
3e8ef19b
...
...
@@ -8,13 +8,18 @@
android:focusableInTouchMode=
"true"
tools:context=
".profile.ui.ProfileFragment"
>
<ScrollView
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
>
<LinearLayout
android:id=
"@+id/profile_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:gravity=
"center"
android:orientation=
"vertical"
android:visibility=
"gone"
>
android:visibility=
"gone"
tools:visibility=
"visible"
>
<include
android:id=
"@+id/layout_avatar_profile"
...
...
@@ -53,9 +58,12 @@
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_link_black_24dp"
android:hint=
"@string/msg_avatar_url"
android:inputType=
"text"
/>
android:inputType=
"text"
android:layout_marginBottom=
"16dp"
/>
</LinearLayout>
</ScrollView>
<com.wang.avi.AVLoadingIndicatorView
android:id=
"@+id/view_loading"
android:layout_width=
"wrap_content"
...
...
app/src/main/res/layout/item_color_attachment.xml
0 → 100644
View file @
3e8ef19b
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:id=
"@+id/color_attachment_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"?android:attr/selectableItemBackground"
android:clickable=
"true"
android:focusable=
"true"
android:paddingBottom=
"@dimen/message_item_top_and_bottom_padding"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_padding"
android:paddingStart=
"@dimen/screen_edge_left_and_right_padding"
android:paddingTop=
"@dimen/message_item_top_and_bottom_padding"
>
<View
android:id=
"@+id/quote_bar"
android:layout_width=
"4dp"
android:layout_height=
"0dp"
android:layout_marginStart=
"56dp"
android:background=
"@drawable/quote_vertical_bar"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
app:layout_constraintBottom_toTopOf=
"@id/recycler_view_reactions"
/>
<TextView
android:id=
"@+id/attachment_text"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body1"
android:autoLink=
"web"
app:layout_constraintStart_toEndOf=
"@id/quote_bar"
app:layout_constraintEnd_toEndOf=
"parent"
tools:text=
"#5571 - User profile from SSO must not have password change option"
/>
<include
layout=
"@layout/layout_reactions"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
app:layout_constraintStart_toStartOf=
"@id/quote_bar"
app:layout_constraintTop_toBottomOf=
"@id/attachment_text"
/>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/xml/backup_config.xml
0 → 100644
View file @
3e8ef19b
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content
xmlns:tools=
"http://schemas.android.com/tools"
>
<include
domain=
"sharedpref"
path=
"."
/>
<exclude
domain=
"sharedpref"
path=
"messages.xml"
tools:ignore=
"FullBackupContent"
/>
<exclude
domain=
"file"
path=
"instant-run"
tools:ignore=
"FullBackupContent"
/>
</full-backup-content>
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