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
Expand all
Hide 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 @@
...
@@ -17,10 +17,11 @@
<application
<application
android:name=
".app.RocketChatApplication"
android:name=
".app.RocketChatApplication"
android:allowBackup=
"true"
android:allowBackup=
"true"
android:fullBackupContent=
"@xml/backup_config"
android:icon=
"@mipmap/ic_launcher"
android:icon=
"@mipmap/ic_launcher"
android:label=
"@string/app_name"
android:label=
"@string/app_name"
android:roundIcon=
"@mipmap/ic_launcher_round"
android:roundIcon=
"@mipmap/ic_launcher_round"
android:networkSecurityConfig=
"@xml/network_security_config"
>
android:networkSecurityConfig=
"@xml/network_security_config"
android:supportsRtl=
"true"
>
android:supportsRtl=
"true"
>
<activity
<activity
...
@@ -34,6 +35,19 @@
...
@@ -34,6 +35,19 @@
<category
android:name=
"android.intent.category.DEFAULT"
/>
<category
android:name=
"android.intent.category.DEFAULT"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
<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>
</intent-filter>
</activity>
</activity>
<activity
<activity
...
@@ -102,13 +116,18 @@
...
@@ -102,13 +116,18 @@
<action
android:name=
"com.google.android.c2dm.intent.RECEIVE"
/>
<action
android:name=
"com.google.android.c2dm.intent.RECEIVE"
/>
</intent-filter>
</intent-filter>
</service>
</service>
<service
android:name=
".chatroom.service.MessageService"
android:exported=
"true"
android:permission=
"android.permission.BIND_JOB_SERVICE"
/>
<meta-data
<meta-data
android:name=
"io.fabric.ApiKey"
android:name=
"io.fabric.ApiKey"
android:value=
"12ac6e94f850aaffcdff52001af77ca415d06a43"
/>
android:value=
"12ac6e94f850aaffcdff52001af77ca415d06a43"
/>
<activity
android:name=
".settings.about.ui.AboutActivity"
<activity
android:theme=
"@style/AppTheme"
/>
android:name=
".settings.about.ui.AboutActivity"
android:theme=
"@style/AppTheme"
/>
</application>
</application>
</manifest>
</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
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.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.OauthHelper
import
chat.rocket.android.helper.OauthHelper
...
@@ -10,6 +11,7 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
...
@@ -10,6 +11,7 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.presentation.CheckServerPresenter
import
chat.rocket.android.server.presentation.CheckServerPresenter
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.util.retryIO
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatAuthException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatTwoFactorException
import
chat.rocket.common.RocketChatTwoFactorException
import
chat.rocket.common.model.Token
import
chat.rocket.common.model.Token
...
@@ -24,6 +26,7 @@ import javax.inject.Inject
...
@@ -24,6 +26,7 @@ import javax.inject.Inject
private
const
val
TYPE_LOGIN_USER_EMAIL
=
0
private
const
val
TYPE_LOGIN_USER_EMAIL
=
0
private
const
val
TYPE_LOGIN_CAS
=
1
private
const
val
TYPE_LOGIN_CAS
=
1
private
const
val
TYPE_LOGIN_OAUTH
=
2
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_GITHUB
=
"github"
private
const
val
SERVICE_NAME_GOOGLE
=
"google"
private
const
val
SERVICE_NAME_GOOGLE
=
"google"
private
const
val
SERVICE_NAME_LINKEDIN
=
"linkedin"
private
const
val
SERVICE_NAME_LINKEDIN
=
"linkedin"
...
@@ -35,26 +38,31 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
...
@@ -35,26 +38,31 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
private
val
tokenRepository
:
TokenRepository
,
private
val
tokenRepository
:
TokenRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
settingsInteractor
:
GetSettingsInteractor
,
private
val
settingsInteractor
:
GetSettingsInteractor
,
serverInteractor
:
GetCurrentServerInteractor
,
serverInteractor
:
GetCurrentServerInteractor
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
factory
:
RocketChatClientFactory
)
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()
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
private
lateinit
var
client
:
RocketChatClient
private
val
settings
:
PublicSettings
=
settingsInteractor
.
get
(
currentServer
)
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
usernameOrEmail
:
String
private
lateinit
var
password
:
String
private
lateinit
var
password
:
String
private
lateinit
var
credentialToken
:
String
private
lateinit
var
credentialToken
:
String
private
lateinit
var
credentialSecret
:
String
private
lateinit
var
credentialSecret
:
String
private
lateinit
var
deepLinkUserId
:
String
private
lateinit
var
deepLinkToken
:
String
fun
setupView
()
{
fun
setupView
()
{
setupConnectionInfo
(
currentServer
)
setupLoginView
()
setupLoginView
()
setupUserRegistrationView
()
setupUserRegistrationView
()
setupCasView
()
setupCasView
()
setupOauthServicesView
()
setupOauthServicesView
()
checkServerInfo
()
checkServerInfo
(
currentServer
)
}
}
fun
authenticateWithUserAndPassword
(
usernameOrEmail
:
String
,
password
:
String
)
{
fun
authenticateWithUserAndPassword
(
usernameOrEmail
:
String
,
password
:
String
)
{
...
@@ -84,6 +92,32 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
...
@@ -84,6 +92,32 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
doAuthentication
(
TYPE_LOGIN_OAUTH
)
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
()
fun
signup
()
=
navigator
.
toSignUp
()
private
fun
setupLoginView
()
{
private
fun
setupLoginView
()
{
...
@@ -212,8 +246,16 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
...
@@ -212,8 +246,16 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
TYPE_LOGIN_OAUTH
->
{
TYPE_LOGIN_OAUTH
->
{
client
.
loginWithOauth
(
credentialToken
,
credentialSecret
)
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
->
{
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
...
@@ -14,8 +14,10 @@ import android.view.ViewGroup
import
android.view.ViewTreeObserver
import
android.view.ViewTreeObserver
import
android.widget.ImageButton
import
android.widget.ImageButton
import
android.widget.ScrollView
import
android.widget.ScrollView
import
androidx.core.view.postDelayed
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
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.LoginPresenter
import
chat.rocket.android.authentication.login.presentation.LoginView
import
chat.rocket.android.authentication.login.presentation.LoginView
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.KeyboardHelper
...
@@ -26,6 +28,7 @@ import chat.rocket.android.webview.cas.ui.casWebViewIntent
...
@@ -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_SECRET
import
chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_TOKEN
import
chat.rocket.android.webview.oauth.ui.INTENT_OAUTH_CREDENTIAL_TOKEN
import
chat.rocket.android.webview.oauth.ui.oauthWebViewIntent
import
chat.rocket.android.webview.oauth.ui.oauthWebViewIntent
import
chat.rocket.common.util.ifNull
import
dagger.android.support.AndroidSupportInjection
import
dagger.android.support.AndroidSupportInjection
import
kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import
kotlinx.android.synthetic.main.fragment_authentication_log_in.*
import
javax.inject.Inject
import
javax.inject.Inject
...
@@ -40,14 +43,22 @@ class LoginFragment : Fragment(), LoginView {
...
@@ -40,14 +43,22 @@ class LoginFragment : Fragment(), LoginView {
areLoginOptionsNeeded
()
areLoginOptionsNeeded
()
}
}
private
var
isGlobalLayoutListenerSetUp
=
false
private
var
isGlobalLayoutListenerSetUp
=
false
private
var
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
companion
object
{
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
?)
{
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
AndroidSupportInjection
.
inject
(
this
)
deepLinkInfo
=
arguments
?.
getParcelable
(
DEEP_LINK_INFO
)
}
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
...
@@ -60,7 +71,11 @@ class LoginFragment : Fragment(), LoginView {
...
@@ -60,7 +71,11 @@ class LoginFragment : Fragment(), LoginView {
tintEditTextDrawableStart
()
tintEditTextDrawableStart
()
}
}
presenter
.
setupView
()
deepLinkInfo
?.
let
{
presenter
.
authenticadeWithDeepLink
(
it
)
}.
ifNull
{
presenter
.
setupView
()
}
}
}
override
fun
onDestroyView
()
{
override
fun
onDestroyView
()
{
...
@@ -377,19 +392,23 @@ class LoginFragment : Fragment(), LoginView {
...
@@ -377,19 +392,23 @@ class LoginFragment : Fragment(), LoginView {
}
}
private
fun
showRemainingSocialAccountsView
()
{
private
fun
showRemainingSocialAccountsView
()
{
social_accounts_container
.
postDelayed
({
social_accounts_container
.
postDelayed
(
300
)
{
(
0
..
social_accounts_container
.
childCount
)
ui
{
.
mapNotNull
{
social_accounts_container
.
getChildAt
(
it
)
as
?
ImageButton
}
(
0
..
social_accounts_container
.
childCount
)
.
filter
{
it
.
isClickable
}
.
mapNotNull
{
social_accounts_container
.
getChildAt
(
it
)
as
?
ImageButton
}
.
forEach
{
ui
{
it
.
setVisible
(
true
)
}}
.
filter
{
it
.
isClickable
}
},
1000
)
.
forEach
{
it
.
setVisible
(
true
)
}
}
}
}
}
// Scrolling to the bottom of the screen.
// Scrolling to the bottom of the screen.
private
fun
scrollToBottom
()
{
private
fun
scrollToBottom
()
{
scroll_view
.
postDelayed
({
scroll_view
.
postDelayed
(
1250
)
{
ui
{
scroll_view
.
fullScroll
(
ScrollView
.
FOCUS_DOWN
)
}
ui
{
},
1250
)
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
...
@@ -2,6 +2,7 @@ package chat.rocket.android.authentication.presentation
import
android.content.Intent
import
android.content.Intent
import
chat.rocket.android.R
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.login.ui.LoginFragment
import
chat.rocket.android.authentication.registerusername.ui.RegisterUsernameFragment
import
chat.rocket.android.authentication.registerusername.ui.RegisterUsernameFragment
import
chat.rocket.android.authentication.signup.ui.SignupFragment
import
chat.rocket.android.authentication.signup.ui.SignupFragment
...
@@ -21,6 +22,12 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) {
...
@@ -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
)
{
fun
toTwoFA
(
username
:
String
,
password
:
String
)
{
activity
.
addFragmentBackStack
(
"TwoFAFragment"
,
R
.
id
.
fragment_container
)
{
activity
.
addFragmentBackStack
(
"TwoFAFragment"
,
R
.
id
.
fragment_container
)
{
TwoFAFragment
.
newInstance
(
username
,
password
)
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
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.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.behaviours.showMessage
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.GetAccountsInteractor
import
chat.rocket.android.server.domain.GetAccountsInteractor
import
chat.rocket.android.server.domain.RefreshSettingsInteractor
import
chat.rocket.android.server.domain.RefreshSettingsInteractor
...
@@ -16,7 +18,14 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
...
@@ -16,7 +18,14 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
private
val
serverInteractor
:
SaveCurrentServerInteractor
,
private
val
serverInteractor
:
SaveCurrentServerInteractor
,
private
val
refreshSettingsInteractor
:
RefreshSettingsInteractor
,
private
val
refreshSettingsInteractor
:
RefreshSettingsInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
)
{
private
val
getAccountsInteractor
:
GetAccountsInteractor
)
{
fun
connect
(
server
:
String
)
{
fun
connect
(
server
:
String
)
{
connectToServer
(
server
)
{
navigator
.
toLogin
()
}
}
fun
connectToServer
(
server
:
String
,
block
:
()
->
Unit
)
{
if
(!
server
.
isValidUrl
())
{
if
(!
server
.
isValidUrl
())
{
view
.
showInvalidServerUrlMessage
()
view
.
showInvalidServerUrlMessage
()
}
else
{
}
else
{
...
@@ -32,17 +41,19 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
...
@@ -32,17 +41,19 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
try
{
try
{
refreshSettingsInteractor
.
refresh
(
server
)
refreshSettingsInteractor
.
refresh
(
server
)
serverInteractor
.
save
(
server
)
serverInteractor
.
save
(
server
)
navigator
.
toLogin
()
block
()
}
catch
(
ex
:
Exception
)
{
}
catch
(
ex
:
Exception
)
{
ex
.
message
?.
let
{
view
.
showMessage
(
ex
)
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
}
finally
{
}
finally
{
view
.
hideLoading
()
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
...
@@ -7,6 +7,7 @@ import android.view.View
import
android.view.ViewGroup
import
android.view.ViewGroup
import
android.view.ViewTreeObserver
import
android.view.ViewTreeObserver
import
chat.rocket.android.R
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.ServerPresenter
import
chat.rocket.android.authentication.server.presentation.ServerView
import
chat.rocket.android.authentication.server.presentation.ServerView
import
chat.rocket.android.helper.KeyboardHelper
import
chat.rocket.android.helper.KeyboardHelper
...
@@ -17,17 +18,26 @@ import javax.inject.Inject
...
@@ -17,17 +18,26 @@ import javax.inject.Inject
class
ServerFragment
:
Fragment
(),
ServerView
{
class
ServerFragment
:
Fragment
(),
ServerView
{
@Inject
lateinit
var
presenter
:
ServerPresenter
@Inject
lateinit
var
presenter
:
ServerPresenter
private
var
deepLinkInfo
:
LoginDeepLinkInfo
?
=
null
private
val
layoutListener
=
ViewTreeObserver
.
OnGlobalLayoutListener
{
private
val
layoutListener
=
ViewTreeObserver
.
OnGlobalLayoutListener
{
text_server_url
.
isCursorVisible
=
KeyboardHelper
.
isSoftKeyboardShown
(
relative_layout
.
rootView
)
text_server_url
.
isCursorVisible
=
KeyboardHelper
.
isSoftKeyboardShown
(
relative_layout
.
rootView
)
}
}
companion
object
{
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
?)
{
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
super
.
onCreate
(
savedInstanceState
)
AndroidSupportInjection
.
inject
(
this
)
AndroidSupportInjection
.
inject
(
this
)
deepLinkInfo
=
arguments
?.
getParcelable
(
DEEP_LINK_INFO
)
}
}
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
override
fun
onCreateView
(
inflater
:
LayoutInflater
,
container
:
ViewGroup
?,
savedInstanceState
:
Bundle
?):
View
?
=
...
@@ -37,6 +47,10 @@ class ServerFragment : Fragment(), ServerView {
...
@@ -37,6 +47,10 @@ class ServerFragment : Fragment(), ServerView {
super
.
onViewCreated
(
view
,
savedInstanceState
)
super
.
onViewCreated
(
view
,
savedInstanceState
)
relative_layout
.
viewTreeObserver
.
addOnGlobalLayoutListener
(
layoutListener
)
relative_layout
.
viewTreeObserver
.
addOnGlobalLayoutListener
(
layoutListener
)
setupOnClickListener
()
setupOnClickListener
()
deepLinkInfo
?.
let
{
presenter
.
deepLink
(
it
)
}
}
}
override
fun
onDestroyView
()
{
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 {
...
@@ -28,7 +28,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
private
const
val
PASSWORD
=
"password"
private
const
val
PASSWORD
=
"password"
fun
newInstance
(
username
:
String
,
password
:
String
)
=
TwoFAFragment
().
apply
{
fun
newInstance
(
username
:
String
,
password
:
String
)
=
TwoFAFragment
().
apply
{
arguments
=
Bundle
(
1
).
apply
{
arguments
=
Bundle
(
2
).
apply
{
putString
(
USERNAME
,
username
)
putString
(
USERNAME
,
username
)
putString
(
PASSWORD
,
password
)
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
...
@@ -6,10 +6,11 @@ import android.os.Bundle
import
android.support.v4.app.Fragment
import
android.support.v4.app.Fragment
import
android.support.v7.app.AppCompatActivity
import
android.support.v7.app.AppCompatActivity
import
chat.rocket.android.R
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.presentation.AuthenticationPresenter
import
chat.rocket.android.authentication.server.ui.ServerFragment
import
chat.rocket.android.authentication.server.ui.ServerFragment
import
chat.rocket.android.util.extensions.addFragment
import
chat.rocket.android.util.extensions.addFragment
import
chat.rocket.android.util.extensions.launchUI
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjection
import
dagger.android.AndroidInjector
import
dagger.android.AndroidInjector
import
dagger.android.DispatchingAndroidInjector
import
dagger.android.DispatchingAndroidInjector
...
@@ -30,11 +31,13 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
...
@@ -30,11 +31,13 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
setTheme
(
R
.
style
.
AuthenticationTheme
)
setTheme
(
R
.
style
.
AuthenticationTheme
)
super
.
onCreate
(
savedInstanceState
)
super
.
onCreate
(
savedInstanceState
)
val
deepLinkInfo
=
intent
.
getLoginDeepLinkInfo
()
launch
(
UI
+
job
)
{
launch
(
UI
+
job
)
{
val
newServer
=
intent
.
getBooleanExtra
(
INTENT_ADD_NEW_SERVER
,
false
)
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
)
{
if
(!
authenticated
)
{
showServerInput
(
savedInstanceState
)
showServerInput
(
savedInstanceState
,
deepLinkInfo
)
}
}
}
}
}
}
...
@@ -49,9 +52,9 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
...
@@ -49,9 +52,9 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
return
fragmentDispatchingAndroidInjector
return
fragmentDispatchingAndroidInjector
}
}
fun
showServerInput
(
savedInstanceState
:
Bundle
?)
{
fun
showServerInput
(
savedInstanceState
:
Bundle
?
,
deepLinkInfo
:
LoginDeepLinkInfo
?
)
{
addFragment
(
"ServerFragment"
,
R
.
id
.
fragment_container
)
{
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(
...
@@ -57,6 +57,10 @@ class ChatRoomAdapter(
val
view
=
parent
.
inflate
(
R
.
layout
.
item_author_attachment
)
val
view
=
parent
.
inflate
(
R
.
layout
.
item_author_attachment
)
AuthorAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
AuthorAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
}
BaseViewModel
.
ViewType
.
COLOR_ATTACHMENT
->
{
val
view
=
parent
.
inflate
(
R
.
layout
.
item_color_attachment
)
ColorAttachmentViewHolder
(
view
,
actionsListener
,
reactionListener
)
}
else
->
{
else
->
{
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
throw
InvalidParameterException
(
"TODO - implement for ${viewType.toViewType()}"
)
}
}
...
@@ -97,6 +101,7 @@ class ChatRoomAdapter(
...
@@ -97,6 +101,7 @@ class ChatRoomAdapter(
is
UrlPreviewViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
UrlPreviewViewModel
)
is
UrlPreviewViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
UrlPreviewViewModel
)
is
MessageAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageAttachmentViewModel
)
is
MessageAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
MessageAttachmentViewModel
)
is
AuthorAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
AuthorAttachmentViewModel
)
is
AuthorAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
AuthorAttachmentViewModel
)
is
ColorAttachmentViewHolder
->
holder
.
bind
(
dataSet
[
position
]
as
ColorAttachmentViewModel
)
}
}
}
}
...
@@ -117,12 +122,22 @@ class ChatRoomAdapter(
...
@@ -117,12 +122,22 @@ class ChatRoomAdapter(
}
}
fun
prependData
(
dataSet
:
List
<
BaseViewModel
<*
>>)
{
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
this
.
dataSet
.
indexOfFirst
{
it
.
messageId
==
newItem
.
messageId
&&
it
.
viewType
==
newItem
.
viewType
}
>
-
1
}
}
if
(
item
==
null
)
{
if
(
item
==
-
1
)
{
this
.
dataSet
.
addAll
(
0
,
dataSet
)
this
.
dataSet
.
addAll
(
0
,
dataSet
)
notifyItemRangeInserted
(
0
,
dataSet
.
size
)
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
package
chat.rocket.android.chatroom.adapter
import
android.graphics.Color
import
android.text.method.LinkMovementMethod
import
android.text.method.LinkMovementMethod
import
android.view.View
import
android.view.View
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
import
chat.rocket.android.chatroom.viewmodel.MessageViewModel
...
@@ -29,6 +30,9 @@ class MessageViewHolder(
...
@@ -29,6 +30,9 @@ class MessageViewHolder(
text_sender
.
text
=
data
.
senderName
text_sender
.
text
=
data
.
senderName
text_content
.
text
=
data
.
content
text_content
.
text
=
data
.
content
image_avatar
.
setImageURI
(
data
.
avatar
)
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
This diff is collapsed.
Click to expand it.
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
3e8ef19b
...
@@ -92,10 +92,8 @@ interface ChatRoomView : LoadingView, MessageView {
...
@@ -92,10 +92,8 @@ interface ChatRoomView : LoadingView, MessageView {
/**
/**
* Enables the send message button.
* Enables the send message button.
*
* @param sendFailed Whether the sent message has failed.
*/
*/
fun
enableSendMessageButton
(
sendFailed
:
Boolean
)
fun
enableSendMessageButton
()
/**
/**
* Clears the message composition.
* 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
...
@@ -18,7 +18,6 @@ import android.support.v7.widget.DefaultItemAnimator
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.LinearLayoutManager
import
android.support.v7.widget.RecyclerView
import
android.support.v7.widget.RecyclerView
import
android.view.*
import
android.view.*
import
androidx.core.content.systemService
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.adapter.*
import
chat.rocket.android.chatroom.adapter.*
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
import
chat.rocket.android.chatroom.presentation.ChatRoomPresenter
...
@@ -70,8 +69,10 @@ private const val BUNDLE_CHAT_ROOM_LAST_SEEN = "chat_room_last_seen"
...
@@ -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"
private
const
val
BUNDLE_CHAT_ROOM_IS_SUBSCRIBED
=
"chat_room_is_subscribed"
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiKeyboardListener
,
EmojiReactionListener
{
class
ChatRoomFragment
:
Fragment
(),
ChatRoomView
,
EmojiKeyboardListener
,
EmojiReactionListener
{
@Inject
lateinit
var
presenter
:
ChatRoomPresenter
@Inject
@Inject
lateinit
var
parser
:
MessageParser
lateinit
var
presenter
:
ChatRoomPresenter
@Inject
lateinit
var
parser
:
MessageParser
private
lateinit
var
adapter
:
ChatRoomAdapter
private
lateinit
var
adapter
:
ChatRoomAdapter
private
lateinit
var
chatRoomId
:
String
private
lateinit
var
chatRoomId
:
String
private
lateinit
var
chatRoomName
:
String
private
lateinit
var
chatRoomName
:
String
...
@@ -207,7 +208,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -207,7 +208,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
if
(
recycler_view
.
adapter
==
null
)
{
if
(
recycler_view
.
adapter
==
null
)
{
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
presenter
,
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
presenter
,
reactionListener
=
this
@ChatRoomFragment
)
reactionListener
=
this
@ChatRoomFragment
)
recycler_view
.
adapter
=
adapter
recycler_view
.
adapter
=
adapter
if
(
dataSet
.
size
>=
30
)
{
if
(
dataSet
.
size
>=
30
)
{
recycler_view
.
addOnScrollListener
(
endlessRecyclerViewScrollListener
)
recycler_view
.
addOnScrollListener
(
endlessRecyclerViewScrollListener
)
...
@@ -232,9 +233,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -232,9 +233,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
// if y is positive the keyboard is up else it's down
// if y is positive the keyboard is up else it's down
recycler_view
.
post
{
recycler_view
.
post
{
if
(
y
>
0
||
Math
.
abs
(
verticalScrollOffset
.
get
())
>=
Math
.
abs
(
y
))
{
if
(
y
>
0
||
Math
.
abs
(
verticalScrollOffset
.
get
())
>=
Math
.
abs
(
y
))
{
recycler_view
.
scrollBy
(
0
,
y
)
ui
{
recycler_view
.
scrollBy
(
0
,
y
)
}
}
else
{
}
else
{
recycler_view
.
scrollBy
(
0
,
verticalScrollOffset
.
get
())
ui
{
recycler_view
.
scrollBy
(
0
,
verticalScrollOffset
.
get
())
}
}
}
}
}
}
}
...
@@ -316,16 +317,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -316,16 +317,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
}
}
override
fun
enableSendMessageButton
(
sendFailed
:
Boolean
)
{
override
fun
enableSendMessageButton
()
{
ui
{
ui
{
button_send
.
isEnabled
=
true
button_send
.
isEnabled
=
true
text_message
.
isEnabled
=
true
text_message
.
isEnabled
=
true
if
(!
sendFailed
)
{
clearMessageComposition
()
clearMessageComposition
()
}
}
}
}
}
override
fun
clearMessageComposition
()
{
override
fun
clearMessageComposition
()
{
ui
{
ui
{
citation
=
null
citation
=
null
...
@@ -408,7 +408,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -408,7 +408,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
copyToClipboard
(
message
:
String
)
{
override
fun
copyToClipboard
(
message
:
String
)
{
ui
{
ui
{
val
clipboard
:
ClipboardManager
=
it
.
systemService
()
val
clipboard
=
it
.
getSystemService
(
Context
.
CLIPBOARD_SERVICE
)
as
ClipboardManager
clipboard
.
primaryClip
=
ClipData
.
newPlainText
(
""
,
message
)
clipboard
.
primaryClip
=
ClipData
.
newPlainText
(
""
,
message
)
}
}
}
}
...
@@ -469,10 +469,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -469,10 +469,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override
fun
showFileSelection
(
filter
:
Array
<
String
>)
{
override
fun
showFileSelection
(
filter
:
Array
<
String
>)
{
ui
{
ui
{
if
(
ContextCompat
.
checkSelfPermission
(
it
,
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
)
if
(
ContextCompat
.
checkSelfPermission
(
it
,
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
)
!=
PackageManager
.
PERMISSION_GRANTED
)
{
!=
PackageManager
.
PERMISSION_GRANTED
)
{
ActivityCompat
.
requestPermissions
(
it
,
ActivityCompat
.
requestPermissions
(
it
,
arrayOf
(
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
),
arrayOf
(
Manifest
.
permission
.
READ_EXTERNAL_STORAGE
),
1
)
1
)
}
else
{
}
else
{
val
intent
=
Intent
(
Intent
.
ACTION_GET_CONTENT
)
val
intent
=
Intent
(
Intent
.
ACTION_GET_CONTENT
)
intent
.
type
=
"*/*"
intent
.
type
=
"*/*"
...
@@ -536,7 +536,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -536,7 +536,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
recycler_view
.
layoutManager
=
linearLayoutManager
recycler_view
.
layoutManager
=
linearLayoutManager
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
endlessRecyclerViewScrollListener
=
object
:
endlessRecyclerViewScrollListener
=
object
:
EndlessRecyclerViewScrollListener
(
recycler_view
.
layoutManager
as
LinearLayoutManager
)
{
EndlessRecyclerViewScrollListener
(
recycler_view
.
layoutManager
as
LinearLayoutManager
)
{
override
fun
onLoadMore
(
page
:
Int
,
totalItemsCount
:
Int
,
recyclerView
:
RecyclerView
?)
{
override
fun
onLoadMore
(
page
:
Int
,
totalItemsCount
:
Int
,
recyclerView
:
RecyclerView
?)
{
presenter
.
loadMessages
(
chatRoomId
,
chatRoomType
,
page
*
30L
)
presenter
.
loadMessages
(
chatRoomId
,
chatRoomType
,
page
*
30L
)
}
}
...
@@ -589,6 +589,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -589,6 +589,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
var
textMessage
=
citation
?:
""
var
textMessage
=
citation
?:
""
textMessage
+=
text_message
.
textContent
textMessage
+=
text_message
.
textContent
sendMessage
(
textMessage
)
sendMessage
(
textMessage
)
clearMessageComposition
()
}
}
button_show_attachment_options
.
setOnClickListener
{
button_show_attachment_options
.
setOnClickListener
{
...
@@ -621,23 +622,23 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -621,23 +622,23 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private
fun
setupSuggestionsView
()
{
private
fun
setupSuggestionsView
()
{
suggestions_view
.
anchorTo
(
text_message
)
suggestions_view
.
anchorTo
(
text_message
)
.
setMaximumHeight
(
resources
.
getDimensionPixelSize
(
R
.
dimen
.
suggestions_box_max_height
))
.
setMaximumHeight
(
resources
.
getDimensionPixelSize
(
R
.
dimen
.
suggestions_box_max_height
))
.
addTokenAdapter
(
PeopleSuggestionsAdapter
(
context
!!
))
.
addTokenAdapter
(
PeopleSuggestionsAdapter
(
context
!!
))
.
addTokenAdapter
(
CommandSuggestionsAdapter
())
.
addTokenAdapter
(
CommandSuggestionsAdapter
())
.
addTokenAdapter
(
RoomSuggestionsAdapter
())
.
addTokenAdapter
(
RoomSuggestionsAdapter
())
.
addSuggestionProviderAction
(
"@"
)
{
query
->
.
addSuggestionProviderAction
(
"@"
)
{
query
->
if
(
query
.
isNotEmpty
())
{
if
(
query
.
isNotEmpty
())
{
presenter
.
spotlight
(
query
,
PEOPLE
,
true
)
presenter
.
spotlight
(
query
,
PEOPLE
,
true
)
}
}
}
.
addSuggestionProviderAction
(
"#"
)
{
query
->
}
if
(
query
.
isNotEmpty
())
{
.
addSuggestionProviderAction
(
"#"
)
{
query
->
presenter
.
loadChatRooms
()
if
(
query
.
isNotEmpty
())
{
}
presenter
.
loadChatRooms
()
}
.
addSuggestionProviderAction
(
"/"
)
{
_
->
presenter
.
loadCommands
()
}
}
}
.
addSuggestionProviderAction
(
"/"
)
{
_
->
presenter
.
loadCommands
()
}
presenter
.
loadCommands
()
presenter
.
loadCommands
()
}
}
...
@@ -672,7 +673,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
...
@@ -672,7 +673,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private
fun
subscribeTextMessage
()
{
private
fun
subscribeTextMessage
()
{
val
disposable
=
text_message
.
asObservable
(
0
)
val
disposable
=
text_message
.
asObservable
(
0
)
.
subscribe
({
t
->
setupComposeMessageButtons
(
t
)
})
.
subscribe
({
t
->
setupComposeMessageButtons
(
t
)
})
compositeDisposable
.
add
(
disposable
)
compositeDisposable
.
add
(
disposable
)
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/AudioAttachmentViewModel.kt
View file @
3e8ef19b
...
@@ -13,7 +13,8 @@ data class AudioAttachmentViewModel(
...
@@ -13,7 +13,8 @@ data class AudioAttachmentViewModel(
override
val
id
:
Long
,
override
val
id
:
Long
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseFileAttachmentViewModel
<
AudioAttachment
>
{
)
:
BaseFileAttachmentViewModel
<
AudioAttachment
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
.
viewType
get
()
=
BaseViewModel
.
ViewType
.
AUDIO_ATTACHMENT
.
viewType
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/AuthorAttachmentViewModel.kt
View file @
3e8ef19b
...
@@ -5,17 +5,18 @@ import chat.rocket.core.model.Message
...
@@ -5,17 +5,18 @@ import chat.rocket.core.model.Message
import
chat.rocket.core.model.attachment.AuthorAttachment
import
chat.rocket.core.model.attachment.AuthorAttachment
data class
AuthorAttachmentViewModel
(
data class
AuthorAttachmentViewModel
(
override
val
attachmentUrl
:
String
,
override
val
attachmentUrl
:
String
,
val
id
:
Long
,
val
id
:
Long
,
val
name
:
CharSequence
?,
val
name
:
CharSequence
?,
val
icon
:
String
?,
val
icon
:
String
?,
val
fields
:
CharSequence
?,
val
fields
:
CharSequence
?,
override
val
message
:
Message
,
override
val
message
:
Message
,
override
val
rawData
:
AuthorAttachment
,
override
val
rawData
:
AuthorAttachment
,
override
val
messageId
:
String
,
override
val
messageId
:
String
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseAttachmentViewModel
<
AuthorAttachment
>
{
)
:
BaseAttachmentViewModel
<
AuthorAttachment
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
AUTHOR_ATTACHMENT
.
viewType
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> {
...
@@ -12,6 +12,7 @@ interface BaseViewModel<out T> {
var
reactions
:
List
<
ReactionViewModel
>
var
reactions
:
List
<
ReactionViewModel
>
var
nextDownStreamMessage
:
BaseViewModel
<*>?
var
nextDownStreamMessage
:
BaseViewModel
<*>?
var
preview
:
Message
?
var
preview
:
Message
?
var
isTemporary
:
Boolean
enum
class
ViewType
(
val
viewType
:
Int
)
{
enum
class
ViewType
(
val
viewType
:
Int
)
{
MESSAGE
(
0
),
MESSAGE
(
0
),
...
@@ -21,7 +22,8 @@ interface BaseViewModel<out T> {
...
@@ -21,7 +22,8 @@ interface BaseViewModel<out T> {
VIDEO_ATTACHMENT
(
4
),
VIDEO_ATTACHMENT
(
4
),
AUDIO_ATTACHMENT
(
5
),
AUDIO_ATTACHMENT
(
5
),
MESSAGE_ATTACHMENT
(
6
),
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(
...
@@ -13,7 +13,8 @@ data class ImageAttachmentViewModel(
override
val
id
:
Long
,
override
val
id
:
Long
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseFileAttachmentViewModel
<
ImageAttachment
>
{
)
:
BaseFileAttachmentViewModel
<
ImageAttachment
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
IMAGE_ATTACHMENT
.
viewType
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(
...
@@ -14,7 +14,8 @@ data class MessageAttachmentViewModel(
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
var
messageLink
:
String
?
=
null
,
var
messageLink
:
String
?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseViewModel
<
Message
>
{
)
:
BaseViewModel
<
Message
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
MESSAGE_ATTACHMENT
.
viewType
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(
...
@@ -15,7 +15,8 @@ data class MessageViewModel(
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
,
override
var
preview
:
Message
?
=
null
,
var
isFirstUnread
:
Boolean
var
isFirstUnread
:
Boolean
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseMessageViewModel
<
Message
>
{
)
:
BaseMessageViewModel
<
Message
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
MESSAGE
.
viewType
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(
...
@@ -14,7 +14,8 @@ data class UrlPreviewViewModel(
val
thumbUrl
:
String
?,
val
thumbUrl
:
String
?,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseViewModel
<
Url
>
{
)
:
BaseViewModel
<
Url
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
URL_PREVIEW
.
viewType
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(
...
@@ -13,7 +13,8 @@ data class VideoAttachmentViewModel(
override
val
id
:
Long
,
override
val
id
:
Long
,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
reactions
:
List
<
ReactionViewModel
>,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
nextDownStreamMessage
:
BaseViewModel
<*>?
=
null
,
override
var
preview
:
Message
?
=
null
override
var
preview
:
Message
?
=
null
,
override
var
isTemporary
:
Boolean
=
false
)
:
BaseFileAttachmentViewModel
<
VideoAttachment
>
{
)
:
BaseFileAttachmentViewModel
<
VideoAttachment
>
{
override
val
viewType
:
Int
override
val
viewType
:
Int
get
()
=
BaseViewModel
.
ViewType
.
VIDEO_ATTACHMENT
.
viewType
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
...
@@ -5,6 +5,7 @@ import android.content.Context
import
android.graphics.Color
import
android.graphics.Color
import
android.graphics.Typeface
import
android.graphics.Typeface
import
android.support.v4.content.ContextCompat
import
android.support.v4.content.ContextCompat
import
android.text.Html
import
android.text.SpannableStringBuilder
import
android.text.SpannableStringBuilder
import
android.text.style.ForegroundColorSpan
import
android.text.style.ForegroundColorSpan
import
android.text.style.StyleSpan
import
android.text.style.StyleSpan
...
@@ -106,10 +107,23 @@ class ViewModelMapper @Inject constructor(private val context: Context,
...
@@ -106,10 +107,23 @@ class ViewModelMapper @Inject constructor(private val context: Context,
is
FileAttachment
->
mapFileAttachment
(
message
,
attachment
)
is
FileAttachment
->
mapFileAttachment
(
message
,
attachment
)
is
MessageAttachment
->
mapMessageAttachment
(
message
,
attachment
)
is
MessageAttachment
->
mapMessageAttachment
(
message
,
attachment
)
is
AuthorAttachment
->
mapAuthorAttachment
(
message
,
attachment
)
is
AuthorAttachment
->
mapAuthorAttachment
(
message
,
attachment
)
is
ColorAttachment
->
mapColorAttachment
(
message
,
attachment
)
else
->
null
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
{
private
suspend
fun
mapAuthorAttachment
(
message
:
Message
,
attachment
:
AuthorAttachment
):
AuthorAttachmentViewModel
{
return
with
(
attachment
)
{
return
with
(
attachment
)
{
val
content
=
stripMessageQuotes
(
message
)
val
content
=
stripMessageQuotes
(
message
)
...
@@ -212,12 +226,13 @@ class ViewModelMapper @Inject constructor(private val context: Context,
...
@@ -212,12 +226,13 @@ class ViewModelMapper @Inject constructor(private val context: Context,
val
time
=
getTime
(
message
.
timestamp
)
val
time
=
getTime
(
message
.
timestamp
)
val
avatar
=
getUserAvatar
(
message
)
val
avatar
=
getUserAvatar
(
message
)
val
preview
=
mapMessagePreview
(
message
)
val
preview
=
mapMessagePreview
(
message
)
val
isTemp
=
message
.
isTemporary
?:
false
val
content
=
getContent
(
stripMessageQuotes
(
message
))
val
content
=
getContent
(
stripMessageQuotes
(
message
))
MessageViewModel
(
message
=
stripMessageQuotes
(
message
),
rawData
=
message
,
MessageViewModel
(
message
=
stripMessageQuotes
(
message
),
rawData
=
message
,
messageId
=
message
.
id
,
avatar
=
avatar
!!
,
time
=
time
,
senderName
=
sender
,
messageId
=
message
.
id
,
avatar
=
avatar
!!
,
time
=
time
,
senderName
=
sender
,
content
=
content
,
isPinned
=
message
.
pinned
,
reactions
=
getReactions
(
message
),
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
{
private
suspend
fun
mapMessagePreview
(
message
:
Message
):
Message
{
...
...
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
View file @
3e8ef19b
This diff is collapsed.
Click to expand it.
app/src/main/java/chat/rocket/android/core/behaviours/MessageView.kt
View file @
3e8ef19b
package
chat.rocket.android.core.behaviours
package
chat.rocket.android.core.behaviours
import
android.support.annotation.StringRes
import
android.support.annotation.StringRes
import
chat.rocket.common.util.ifNull
interface
MessageView
{
interface
MessageView
{
...
@@ -14,4 +15,12 @@ interface MessageView {
...
@@ -14,4 +15,12 @@ interface MessageView {
fun
showMessage
(
message
:
String
)
fun
showMessage
(
message
:
String
)
fun
showGenericErrorMessage
()
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
...
@@ -2,6 +2,7 @@ package chat.rocket.android.dagger
import
android.app.Application
import
android.app.Application
import
chat.rocket.android.app.RocketChatApplication
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.ActivityBuilder
import
chat.rocket.android.dagger.module.AppModule
import
chat.rocket.android.dagger.module.AppModule
import
chat.rocket.android.dagger.module.ReceiverBuilder
import
chat.rocket.android.dagger.module.ReceiverBuilder
...
@@ -29,6 +30,8 @@ interface AppComponent {
...
@@ -29,6 +30,8 @@ interface AppComponent {
fun
inject
(
service
:
FirebaseTokenService
)
fun
inject
(
service
:
FirebaseTokenService
)
fun
inject
(
service
:
MessageService
)
/*@Component.Builder
/*@Component.Builder
abstract class Builder : AndroidInjector.Builder<RocketChatApplication>()*/
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
...
@@ -2,16 +2,20 @@ package chat.rocket.android.dagger.module
import
android.app.Application
import
android.app.Application
import
android.app.NotificationManager
import
android.app.NotificationManager
import
android.app.job.JobInfo
import
android.app.job.JobScheduler
import
android.arch.persistence.room.Room
import
android.arch.persistence.room.Room
import
android.content.ComponentName
import
android.content.Context
import
android.content.Context
import
android.content.SharedPreferences
import
android.content.SharedPreferences
import
androidx.core.content.systemService
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.app.RocketChatDatabase
import
chat.rocket.android.app.RocketChatDatabase
import
chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository
import
chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository
import
chat.rocket.android.authentication.infraestructure.SharedPreferencesTokenRepository
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.ForFresco
import
chat.rocket.android.dagger.qualifier.ForMessages
import
chat.rocket.android.helper.FrescoAuthInterceptor
import
chat.rocket.android.helper.FrescoAuthInterceptor
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.LocalRepository
...
@@ -20,11 +24,39 @@ import chat.rocket.android.push.GroupedPush
...
@@ -20,11 +24,39 @@ import chat.rocket.android.push.GroupedPush
import
chat.rocket.android.push.PushManager
import
chat.rocket.android.push.PushManager
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.*
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.AppJsonAdapterFactory
import
chat.rocket.android.util.TimberLogger
import
chat.rocket.android.util.TimberLogger
import
chat.rocket.common.internal.FallbackSealedClassJsonAdapter
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.common.util.PlatformLogger
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.AttachmentAdapterFactory
import
com.facebook.drawee.backends.pipeline.DraweeConfig
import
com.facebook.drawee.backends.pipeline.DraweeConfig
import
com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory
import
com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory
import
com.facebook.imagepipeline.core.ImagePipelineConfig
import
com.facebook.imagepipeline.core.ImagePipelineConfig
...
@@ -64,7 +96,7 @@ class AppModule {
...
@@ -64,7 +96,7 @@ class AppModule {
@Provides
@Provides
@Singleton
@Singleton
fun
provideRocketChatDatabase
(
context
:
Application
):
RocketChatDatabase
{
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
@Provides
...
@@ -114,7 +146,7 @@ class AppModule {
...
@@ -114,7 +146,7 @@ class AppModule {
@Provides
@Provides
@ForFresco
@ForFresco
@Singleton
@Singleton
fun
provideFrescoAuthIntercept
e
r
(
tokenRepository
:
TokenRepository
,
currentServerInteractor
:
GetCurrentServerInteractor
):
Interceptor
{
fun
provideFrescoAuthIntercept
o
r
(
tokenRepository
:
TokenRepository
,
currentServerInteractor
:
GetCurrentServerInteractor
):
Interceptor
{
return
FrescoAuthInterceptor
(
tokenRepository
,
currentServerInteractor
)
return
FrescoAuthInterceptor
(
tokenRepository
,
currentServerInteractor
)
}
}
...
@@ -159,9 +191,14 @@ class AppModule {
...
@@ -159,9 +191,14 @@ class AppModule {
}
}
@Provides
@Provides
fun
provideSharedPreferences
(
context
:
Application
):
SharedPreferences
{
fun
provideSharedPreferences
(
context
:
Application
)
=
return
context
.
getSharedPreferences
(
"rocket.chat"
,
Context
.
MODE_PRIVATE
)
context
.
getSharedPreferences
(
"rocket.chat"
,
Context
.
MODE_PRIVATE
)
}
@Provides
@ForMessages
fun
provideMessagesSharedPreferences
(
context
:
Application
)
=
context
.
getSharedPreferences
(
"messages"
,
Context
.
MODE_PRIVATE
)
@Provides
@Provides
@Singleton
@Singleton
...
@@ -201,11 +238,26 @@ class AppModule {
...
@@ -201,11 +238,26 @@ class AppModule {
@Provides
@Provides
@Singleton
@Singleton
fun
provideMoshi
():
Moshi
{
fun
provideMoshi
(
logger
:
PlatformLogger
,
currentServerInteractor
:
GetCurrentServerInteractor
):
Moshi
{
val
url
=
currentServerInteractor
.
get
()
?:
""
return
Moshi
.
Builder
()
return
Moshi
.
Builder
()
.
add
(
FallbackSealedClassJsonAdapter
.
ADAPTER_FACTORY
)
.
add
(
FallbackSealedClassJsonAdapter
.
ADAPTER_FACTORY
)
.
add
(
AppJsonAdapterFactory
.
INSTANCE
)
.
add
(
AppJsonAdapterFactory
.
INSTANCE
)
.
build
()
.
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
()
}
}
@Provides
@Provides
...
@@ -216,8 +268,10 @@ class AppModule {
...
@@ -216,8 +268,10 @@ class AppModule {
@Provides
@Provides
@Singleton
@Singleton
fun
provideMessageRepository
():
MessagesRepository
{
fun
provideMessageRepository
(
@ForMessages
preferences
:
SharedPreferences
,
return
MemoryMessagesRepository
()
moshi
:
Moshi
,
currentServerInteractor
:
GetCurrentServerInteractor
):
MessagesRepository
{
return
SharedPreferencesMessagesRepository
(
preferences
,
moshi
,
currentServerInteractor
)
}
}
@Provides
@Provides
...
@@ -260,7 +314,8 @@ class AppModule {
...
@@ -260,7 +314,8 @@ class AppModule {
SharedPreferencesAccountsRepository
(
preferences
,
moshi
)
SharedPreferencesAccountsRepository
(
preferences
,
moshi
)
@Provides
@Provides
fun
provideNotificationManager
(
context
:
Context
):
NotificationManager
=
context
.
systemService
()
fun
provideNotificationManager
(
context
:
Application
)
=
context
.
getSystemService
(
Context
.
NOTIFICATION_SERVICE
)
as
NotificationManager
@Provides
@Provides
@Singleton
@Singleton
...
@@ -269,7 +324,7 @@ class AppModule {
...
@@ -269,7 +324,7 @@ class AppModule {
@Provides
@Provides
@Singleton
@Singleton
fun
providePushManager
(
fun
providePushManager
(
context
:
Context
,
context
:
Application
,
groupedPushes
:
GroupedPush
,
groupedPushes
:
GroupedPush
,
manager
:
NotificationManager
,
manager
:
NotificationManager
,
moshi
:
Moshi
,
moshi
:
Moshi
,
...
@@ -277,4 +332,22 @@ class AppModule {
...
@@ -277,4 +332,22 @@ class AppModule {
getSettingsInteractor
:
GetSettingsInteractor
):
PushManager
{
getSettingsInteractor
:
GetSettingsInteractor
):
PushManager
{
return
PushManager
(
groupedPushes
,
manager
,
moshi
,
getAccountInteractor
,
getSettingsInteractor
,
context
)
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
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.FirebaseTokenService
import
chat.rocket.android.push.GcmListenerService
import
chat.rocket.android.push.GcmListenerService
import
chat.rocket.android.push.di.FirebaseTokenServiceProvider
import
chat.rocket.android.push.di.FirebaseTokenServiceProvider
...
@@ -14,4 +16,7 @@ import dagger.android.ContributesAndroidInjector
...
@@ -14,4 +16,7 @@ import dagger.android.ContributesAndroidInjector
@ContributesAndroidInjector
(
modules
=
[
GcmListenerServiceProvider
::
class
])
@ContributesAndroidInjector
(
modules
=
[
GcmListenerServiceProvider
::
class
])
abstract
fun
bindGcmListenerService
():
GcmListenerService
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 {
...
@@ -24,4 +24,5 @@ interface LocalRepository {
}
}
}
}
fun
LocalRepository
.
checkIfMyself
(
username
:
String
)
=
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
==
username
fun
LocalRepository
.
checkIfMyself
(
username
:
String
)
=
username
()
==
username
\ No newline at end of file
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,27 +23,25 @@ import chat.rocket.core.internal.rest.logout
...
@@ -23,27 +23,25 @@ import chat.rocket.core.internal.rest.logout
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.unregisterPushToken
import
chat.rocket.core.internal.rest.unregisterPushToken
import
chat.rocket.core.model.Myself
import
chat.rocket.core.model.Myself
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.channels.Channel
import
kotlinx.coroutines.experimental.channels.Channel
import
kotlinx.coroutines.experimental.launch
import
timber.log.Timber
import
timber.log.Timber
import
javax.inject.Inject
import
javax.inject.Inject
class
MainPresenter
@Inject
constructor
(
class
MainPresenter
@Inject
constructor
(
private
val
view
:
MainView
,
private
val
view
:
MainView
,
private
val
strategy
:
CancelStrategy
,
private
val
strategy
:
CancelStrategy
,
private
val
navigator
:
MainNavigator
,
private
val
navigator
:
MainNavigator
,
private
val
tokenRepository
:
TokenRepository
,
private
val
tokenRepository
:
TokenRepository
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
private
val
localRepository
:
LocalRepository
,
private
val
localRepository
:
LocalRepository
,
private
val
navHeaderMapper
:
NavHeaderViewModelMapper
,
private
val
navHeaderMapper
:
NavHeaderViewModelMapper
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
saveAccountInteractor
:
SaveAccountInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
,
private
val
removeAccountInterector
:
RemoveAccountIntere
ctor
,
private
val
removeAccountInteractor
:
RemoveAccountIntera
ctor
,
private
val
factory
:
RocketChatClientFactory
,
private
val
factory
:
RocketChatClientFactory
,
getSettingsInteractor
:
GetSettingsInteractor
,
getSettingsInteractor
:
GetSettingsInteractor
,
managerFactory
:
ConnectionManagerFactory
managerFactory
:
ConnectionManagerFactory
)
:
CheckServerPresenter
(
strategy
,
client
=
factory
.
create
(
serverInteractor
.
get
()
!!
)
,
view
=
view
)
{
)
:
CheckServerPresenter
(
strategy
,
factory
,
view
=
view
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
val
manager
=
managerFactory
.
create
(
currentServer
)
private
val
manager
=
managerFactory
.
create
(
currentServer
)
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
private
val
client
:
RocketChatClient
=
factory
.
create
(
currentServer
)
...
@@ -58,7 +56,7 @@ class MainPresenter @Inject constructor(
...
@@ -58,7 +56,7 @@ class MainPresenter @Inject constructor(
fun
toSettings
()
=
navigator
.
toSettings
()
fun
toSettings
()
=
navigator
.
toSettings
()
fun
loadCurrentInfo
()
{
fun
loadCurrentInfo
()
{
checkServerInfo
()
checkServerInfo
(
currentServer
)
launchUI
(
strategy
)
{
launchUI
(
strategy
)
{
try
{
try
{
val
me
=
retryIO
(
"me"
)
{
val
me
=
retryIO
(
"me"
)
{
...
@@ -105,7 +103,7 @@ class MainPresenter @Inject constructor(
...
@@ -105,7 +103,7 @@ class MainPresenter @Inject constructor(
try
{
try
{
disconnect
()
disconnect
()
removeAccountInter
e
ctor
.
remove
(
currentServer
)
removeAccountInter
a
ctor
.
remove
(
currentServer
)
tokenRepository
.
remove
(
currentServer
)
tokenRepository
.
remove
(
currentServer
)
navigator
.
toNewServer
()
navigator
.
toNewServer
()
}
catch
(
ex
:
Exception
)
{
}
catch
(
ex
:
Exception
)
{
...
...
app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt
View file @
3e8ef19b
package
chat.rocket.android.profile.presentation
package
chat.rocket.android.profile.presentation
import
chat.rocket.android.core.behaviours.showMessage
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
...
@@ -36,11 +37,7 @@ class ProfilePresenter @Inject constructor(private val view: ProfileView,
...
@@ -36,11 +37,7 @@ class ProfilePresenter @Inject constructor(private val view: ProfileView,
myself
.
emails
?.
get
(
0
)
?.
address
!!
myself
.
emails
?.
get
(
0
)
?.
address
!!
)
)
}
catch
(
exception
:
RocketChatException
)
{
}
catch
(
exception
:
RocketChatException
)
{
exception
.
message
?.
let
{
view
.
showMessage
(
exception
)
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
}
finally
{
}
finally
{
view
.
hideLoading
()
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
...
@@ -12,6 +12,7 @@ import chat.rocket.android.profile.presentation.ProfilePresenter
import
chat.rocket.android.profile.presentation.ProfileView
import
chat.rocket.android.profile.presentation.ProfileView
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.util.extensions.*
import
dagger.android.support.AndroidSupportInjection
import
dagger.android.support.AndroidSupportInjection
import
io.reactivex.disposables.CompositeDisposable
import
io.reactivex.rxkotlin.Observables
import
io.reactivex.rxkotlin.Observables
import
kotlinx.android.synthetic.main.app_bar.*
import
kotlinx.android.synthetic.main.app_bar.*
import
kotlinx.android.synthetic.main.avatar_profile.*
import
kotlinx.android.synthetic.main.avatar_profile.*
...
@@ -25,6 +26,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -25,6 +26,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
private
lateinit
var
currentEmail
:
String
private
lateinit
var
currentEmail
:
String
private
lateinit
var
currentAvatar
:
String
private
lateinit
var
currentAvatar
:
String
private
var
actionMode
:
ActionMode
?
=
null
private
var
actionMode
:
ActionMode
?
=
null
private
val
disposables
=
CompositeDisposable
()
companion
object
{
companion
object
{
fun
newInstance
()
=
ProfileFragment
()
fun
newInstance
()
=
ProfileFragment
()
...
@@ -48,22 +50,29 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -48,22 +50,29 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
presenter
.
loadUserProfile
()
presenter
.
loadUserProfile
()
}
}
override
fun
onDestroyView
()
{
disposables
.
clear
()
super
.
onDestroyView
()
}
override
fun
showProfile
(
avatarUrl
:
String
,
name
:
String
,
username
:
String
,
email
:
String
)
{
override
fun
showProfile
(
avatarUrl
:
String
,
name
:
String
,
username
:
String
,
email
:
String
)
{
image_avatar
.
setImageURI
(
avatarUrl
)
ui
{
image_avatar
.
setImageURI
(
avatarUrl
)
text_name
.
textContent
=
name
text_name
.
textContent
=
name
text_username
.
textContent
=
username
text_username
.
textContent
=
username
text_email
.
textContent
=
email
text_email
.
textContent
=
email
text_avatar_url
.
textContent
=
""
text_avatar_url
.
textContent
=
""
currentName
=
name
currentName
=
name
currentUsername
=
username
currentUsername
=
username
currentEmail
=
email
currentEmail
=
email
currentAvatar
=
avatarUrl
currentAvatar
=
avatarUrl
profile_container
.
setVisible
(
true
)
profile_container
.
setVisible
(
true
)
listenToChanges
()
listenToChanges
()
}
}
}
override
fun
showProfileUpdateSuccessfullyMessage
()
{
override
fun
showProfileUpdateSuccessfullyMessage
()
{
...
@@ -72,22 +81,30 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -72,22 +81,30 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
override
fun
showLoading
()
{
override
fun
showLoading
()
{
enableUserInput
(
false
)
enableUserInput
(
false
)
view_loading
.
setVisible
(
true
)
ui
{
view_loading
.
setVisible
(
true
)
}
}
}
override
fun
hideLoading
()
{
override
fun
hideLoading
()
{
if
(
view_loading
!=
null
)
{
ui
{
view_loading
.
setVisible
(
false
)
if
(
view_loading
!=
null
)
{
view_loading
.
setVisible
(
false
)
}
}
}
enableUserInput
(
true
)
enableUserInput
(
true
)
}
}
override
fun
showMessage
(
resId
:
Int
)
{
override
fun
showMessage
(
resId
:
Int
)
{
showToast
(
resId
)
ui
{
showToast
(
resId
)
}
}
}
override
fun
showMessage
(
message
:
String
)
{
override
fun
showMessage
(
message
:
String
)
{
showToast
(
message
)
ui
{
showToast
(
message
)
}
}
}
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
override
fun
showGenericErrorMessage
()
=
showMessage
(
getString
(
R
.
string
.
msg_generic_error
))
...
@@ -136,7 +153,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -136,7 +153,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}
}
private
fun
listenToChanges
()
{
private
fun
listenToChanges
()
{
Observables
.
combineLatest
(
text_name
.
asObservable
(),
disposables
.
add
(
Observables
.
combineLatest
(
text_name
.
asObservable
(),
text_username
.
asObservable
(),
text_username
.
asObservable
(),
text_email
.
asObservable
(),
text_email
.
asObservable
(),
text_avatar_url
.
asObservable
())
{
text_name
,
text_username
,
text_email
,
text_avatar_url
->
text_avatar_url
.
asObservable
())
{
text_name
,
text_username
,
text_email
,
text_avatar_url
->
...
@@ -144,7 +161,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -144,7 +161,7 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
text_username
.
toString
()
!=
currentUsername
||
text_username
.
toString
()
!=
currentUsername
||
text_email
.
toString
()
!=
currentEmail
||
text_email
.
toString
()
!=
currentEmail
||
(
text_avatar_url
.
toString
()
!=
""
&&
text_avatar_url
.
toString
()
!=
currentAvatar
))
(
text_avatar_url
.
toString
()
!=
""
&&
text_avatar_url
.
toString
()
!=
currentAvatar
))
}.
subscribe
(
{
isValid
->
}.
subscribe
{
isValid
->
if
(
isValid
)
{
if
(
isValid
)
{
startActionMode
()
startActionMode
()
}
else
{
}
else
{
...
@@ -162,9 +179,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
...
@@ -162,9 +179,11 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
private
fun
finishActionMode
()
=
actionMode
?.
finish
()
private
fun
finishActionMode
()
=
actionMode
?.
finish
()
private
fun
enableUserInput
(
value
:
Boolean
)
{
private
fun
enableUserInput
(
value
:
Boolean
)
{
text_username
.
isEnabled
=
value
ui
{
text_username
.
isEnabled
=
value
text_username
.
isEnabled
=
value
text_email
.
isEnabled
=
value
text_username
.
isEnabled
=
value
text_avatar_url
.
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
...
@@ -4,6 +4,7 @@ import chat.rocket.android.R
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.internal.rest.registerPushToken
import
chat.rocket.core.internal.rest.registerPushToken
import
com.google.android.gms.gcm.GoogleCloudMessaging
import
com.google.android.gms.gcm.GoogleCloudMessaging
...
@@ -32,23 +33,27 @@ class FirebaseTokenService : FirebaseInstanceIdService() {
...
@@ -32,23 +33,27 @@ class FirebaseTokenService : FirebaseInstanceIdService() {
override
fun
onTokenRefresh
()
{
override
fun
onTokenRefresh
()
{
//TODO: We need to use the Cordova Project gcm_sender_id since it's the one configured on RC
//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.
// default push gateway. We should register this project's own project sender id into it.
val
gcmToken
=
InstanceID
.
getInstance
(
this
)
try
{
.
getToken
(
getString
(
R
.
string
.
gcm_sender_id
),
GoogleCloudMessaging
.
INSTANCE_ID_SCOPE
,
null
)
val
gcmToken
=
InstanceID
.
getInstance
(
this
)
val
currentServer
=
getCurrentServerInteractor
.
get
()
.
getToken
(
getString
(
R
.
string
.
gcm_sender_id
),
GoogleCloudMessaging
.
INSTANCE_ID_SCOPE
,
null
)
val
client
=
currentServer
?.
let
{
factory
.
create
(
currentServer
)
}
val
currentServer
=
getCurrentServerInteractor
.
get
()
val
client
=
currentServer
?.
let
{
factory
.
create
(
currentServer
)
}
gcmToken
?.
let
{
gcmToken
?.
let
{
localRepository
.
save
(
LocalRepository
.
KEY_PUSH_TOKEN
,
gcmToken
)
localRepository
.
save
(
LocalRepository
.
KEY_PUSH_TOKEN
,
gcmToken
)
client
?.
let
{
client
?.
let
{
launch
{
launch
{
try
{
try
{
Timber
.
d
(
"Registering push token: $gcmToken for ${client.url}"
)
Timber
.
d
(
"Registering push token: $gcmToken for ${client.url}"
)
client
.
registerPushToken
(
gcmToken
)
retryIO
(
"register push token"
)
{
client
.
registerPushToken
(
gcmToken
)
}
}
catch
(
ex
:
RocketChatException
)
{
}
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 {
...
@@ -11,7 +11,7 @@ interface MessagesRepository {
*
*
* @return The Message object given by the id or null if message wasn't found.
* @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.
* Get all messages from the current room id.
...
@@ -19,7 +19,7 @@ interface MessagesRepository {
...
@@ -19,7 +19,7 @@ interface MessagesRepository {
* @param rid The room id.
* @param rid The room id.
* @return A list of Message objects for the room with given room id or an empty list.
* @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.
* Get most recent messages up to count different users.
...
@@ -29,43 +29,47 @@ interface MessagesRepository {
...
@@ -29,43 +29,47 @@ interface MessagesRepository {
*
*
* @return List of last count messages.
* @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!
* Get all messages. Use carefully!
*
*
* @return All messages or an empty list.
* @return All messages or an empty list.
*/
*/
fun
getAll
():
List
<
Message
>
suspend
fun
getAll
():
List
<
Message
>
/**
/**
* Save a single message object.
* Save a single message object.
*
*
* @param The message object to saveAll.
* @param The message object to saveAll.
*/
*/
fun
save
(
message
:
Message
)
suspend
fun
save
(
message
:
Message
)
/**
/**
* Save a list of messages.
* Save a list of messages.
*/
*/
fun
saveAll
(
newMessages
:
List
<
Message
>)
suspend
fun
saveAll
(
newMessages
:
List
<
Message
>)
/**
/**
* Removes all messages.
* Removes all messages.
*/
*/
fun
clear
()
suspend
fun
clear
()
/**
/**
* Remove message by id.
* Remove message by id.
*
*
* @param id The id of the message to remove.
* @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.
* Remove all messages from a given room.
*
*
* @param rid The room id where messages are to be removed.
* @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
package
chat.rocket.android.server.domain
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.retryIO
import
chat.rocket.core.internal.rest.settings
import
chat.rocket.core.internal.rest.settings
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.async
import
kotlinx.coroutines.experimental.async
...
@@ -27,7 +28,9 @@ class RefreshSettingsInteractor @Inject constructor(private val factory: RocketC
...
@@ -27,7 +28,9 @@ class RefreshSettingsInteractor @Inject constructor(private val factory: RocketC
suspend
fun
refresh
(
server
:
String
)
{
suspend
fun
refresh
(
server
:
String
)
{
withContext
(
CommonPool
)
{
withContext
(
CommonPool
)
{
factory
.
create
(
server
).
let
{
client
->
factory
.
create
(
server
).
let
{
client
->
val
settings
=
client
.
settings
(*
settingsFilter
)
val
settings
=
retryIO
(
description
=
"settings"
,
times
=
5
)
{
client
.
settings
(*
settingsFilter
)
}
repository
.
save
(
server
,
settings
)
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
...
@@ -2,7 +2,7 @@ package chat.rocket.android.server.domain
import
javax.inject.Inject
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
)
{
suspend
fun
remove
(
serverUrl
:
String
)
{
repository
.
remove
(
serverUrl
)
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
...
@@ -2,45 +2,67 @@ package chat.rocket.android.server.infraestructure
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.android.server.domain.MessagesRepository
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Message
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.withContext
class
MemoryMessagesRepository
:
MessagesRepository
{
class
MemoryMessagesRepository
:
MessagesRepository
{
private
val
messages
:
HashMap
<
String
,
Message
>
=
HashMap
()
private
val
messages
:
HashMap
<
String
,
Message
>
=
HashMap
()
override
fun
getById
(
id
:
String
):
Message
?
{
override
suspend
fun
getById
(
id
:
String
):
Message
?
=
withContext
(
CommonPool
)
{
return
messages
[
id
]
return
@withContext
messages
[
id
]
}
}
override
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
{
override
suspend
fun
getByRoomId
(
rid
:
String
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
return
messages
.
filter
{
it
.
value
.
roomId
==
rid
}.
values
.
toList
()
return
@withContext
messages
.
filter
{
it
.
value
.
roomId
==
rid
}.
values
.
toList
()
}
}
override
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
{
override
suspend
fun
getRecentMessages
(
rid
:
String
,
count
:
Long
):
List
<
Message
>
=
withContext
(
CommonPool
)
{
return
getByRoomId
(
rid
).
sortedByDescending
{
it
.
timestamp
}
return
@withContext
getByRoomId
(
rid
).
sortedByDescending
{
it
.
timestamp
}
.
distinctBy
{
it
.
sender
}.
take
(
count
.
toInt
())
.
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
messages
[
message
.
id
]
=
message
}
}
override
fun
saveAll
(
newMessages
:
List
<
Message
>
)
{
override
suspend
fun
saveAll
(
newMessages
:
List
<
Message
>)
=
withContext
(
CommonPool
)
{
for
(
msg
in
newMessages
)
{
for
(
msg
in
newMessages
)
{
messages
[
msg
.
id
]
=
msg
messages
[
msg
.
id
]
=
msg
}
}
}
}
override
fun
clear
(
)
{
override
suspend
fun
clear
()
=
withContext
(
CommonPool
)
{
messages
.
clear
()
messages
.
clear
()
}
}
override
fun
removeById
(
id
:
String
)
{
override
suspend
fun
removeById
(
id
:
String
)
{
messages
.
remove
(
id
)
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
val
roomMessages
=
messages
.
filter
{
it
.
value
.
roomId
==
rid
}.
values
roomMessages
.
forEach
{
roomMessages
.
forEach
{
messages
.
remove
(
it
.
roomId
)
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,33 +3,40 @@ package chat.rocket.android.server.presentation
...
@@ -3,33 +3,40 @@ package chat.rocket.android.server.presentation
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.authentication.server.presentation.VersionCheckView
import
chat.rocket.android.authentication.server.presentation.VersionCheckView
import
chat.rocket.android.core.lifecycle.CancelStrategy
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.VersionInfo
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.android.util.retryIO
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.serverInfo
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
import
timber.log.Timber
abstract
class
CheckServerPresenter
constructor
(
private
val
strategy
:
CancelStrategy
,
abstract
class
CheckServerPresenter
constructor
(
private
val
strategy
:
CancelStrategy
,
private
val
client
:
RocketChatClient
,
private
val
factory
:
RocketChatClientFactory
,
private
val
view
:
VersionCheckView
)
{
private
val
view
:
VersionCheckView
)
{
internal
fun
checkServerInfo
()
{
private
lateinit
var
currentServer
:
String
launchUI
(
strategy
)
{
private
val
client
:
RocketChatClient
by
lazy
{
factory
.
create
(
currentServer
)
}
internal
fun
checkServerInfo
(
serverUrl
:
String
):
Job
{
return
launchUI
(
strategy
)
{
try
{
try
{
val
serverInfo
=
retryIO
(
description
=
"serverInfo"
,
times
=
5
)
{
client
.
serverInfo
()
}
val
version
=
checkServerVersion
(
serverUrl
).
await
()
val
thisServerVersion
=
serverInfo
.
version
when
(
version
)
{
val
isRequiredVersion
=
isRequiredServerVersion
(
thisServerVersion
)
is
Version
.
VersionOk
->
{
val
isRecommendedVersion
=
isRecommendedServerVersion
(
thisServerVersion
)
Timber
.
i
(
"Your version is nice! (Requires: 0.62.0, Yours: ${version.version})"
)
if
(
isRequiredVersion
)
{
}
if
(
isRecommendedVersion
)
{
is
Version
.
RecommendedVersionWarning
->
{
Timber
.
i
(
"Your version is nice! (Requires: 0.62.0, Yours: $thisServerVersion)"
)
Timber
.
i
(
"Your server ${version.version} is bellow recommended version ${BuildConfig.RECOMMENDED_SERVER_VERSION}"
)
}
else
{
view
.
alertNotRecommendedVersion
()
view
.
alertNotRecommendedVersion
()
}
}
}
else
{
is
Version
.
OutOfDateError
->
{
if
(!
isRecommendedVersion
)
{
Timber
.
i
(
"Oops. Looks like your server ${version.version} is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!"
)
view
.
blockAndAlertNotRequiredVersion
()
view
.
blockAndAlertNotRequiredVersion
()
Timber
.
i
(
"Oops. Looks like your server is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!"
)
}
}
}
}
}
catch
(
ex
:
Exception
)
{
}
catch
(
ex
:
Exception
)
{
...
@@ -38,6 +45,26 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
...
@@ -38,6 +45,26 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
}
}
}
}
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
)
val
isRecommendedVersion
=
isRecommendedServerVersion
(
thisServerVersion
)
if
(
isRequiredVersion
)
{
if
(
isRecommendedVersion
)
{
Timber
.
i
(
"Your version is nice! (Requires: 0.62.0, Yours: $thisServerVersion)"
)
return
@async
Version
.
VersionOk
(
thisServerVersion
)
}
else
{
return
@async
Version
.
RecommendedVersionWarning
(
thisServerVersion
)
}
}
else
{
return
@async
Version
.
OutOfDateError
(
thisServerVersion
)
}
}
}
private
fun
isRequiredServerVersion
(
version
:
String
):
Boolean
{
private
fun
isRequiredServerVersion
(
version
:
String
):
Boolean
{
return
isMinimumVersion
(
version
,
getVersionDistilled
(
BuildConfig
.
REQUIRED_SERVER_VERSION
))
return
isMinimumVersion
(
version
,
getVersionDistilled
(
BuildConfig
.
REQUIRED_SERVER_VERSION
))
}
}
...
@@ -92,4 +119,10 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
...
@@ -92,4 +119,10 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
0
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,53 +8,61 @@
...
@@ -8,53 +8,61 @@
android:focusableInTouchMode=
"true"
android:focusableInTouchMode=
"true"
tools:context=
".profile.ui.ProfileFragment"
>
tools:context=
".profile.ui.ProfileFragment"
>
<LinearLayout
<ScrollView
android:id=
"@+id/profile_container"
android:layout_width=
"match_parent"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
>
android:gravity=
"center"
android:orientation=
"vertical"
android:visibility=
"gone"
>
<include
<LinearLayout
android:id=
"@+id/layout_avatar_profile"
android:id=
"@+id/profile_container"
layout=
"@layout/avatar_profile"
android:layout_width=
"match_parent"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"32dp"
/>
android:gravity=
"center"
android:orientation=
"vertical"
android:visibility=
"gone"
tools:visibility=
"visible"
>
<include
android:id=
"@+id/layout_avatar_profile"
layout=
"@layout/avatar_profile"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"32dp"
/>
<EditText
android:id=
"@+id/text_name"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"32dp"
android:drawableStart=
"@drawable/ic_person_black_24dp"
android:hint=
"@string/msg_name"
android:inputType=
"textCapWords"
/>
<EditText
<EditText
android:id=
"@+id/text_
name"
android:id=
"@+id/text_user
name"
style=
"@style/Profile.EditText"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"32
dp"
android:layout_marginTop=
"16
dp"
android:drawableStart=
"@drawable/ic_person
_black_24dp"
android:drawableStart=
"@drawable/ic_at
_black_24dp"
android:hint=
"@string/msg_
name"
android:hint=
"@string/msg_user
name"
android:inputType=
"textCapWords
"
/>
android:inputType=
"text
"
/>
<EditText
<EditText
android:id=
"@+id/text_username
"
android:id=
"@+id/text_email
"
style=
"@style/Profile.EditText"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16dp"
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_at
_black_24dp"
android:drawableStart=
"@drawable/ic_email
_black_24dp"
android:hint=
"@string/msg_username
"
android:hint=
"@string/msg_email
"
android:inputType=
"text
"
/>
android:inputType=
"textEmailAddress
"
/>
<EditText
<EditText
android:id=
"@+id/text_email"
android:id=
"@+id/text_avatar_url"
style=
"@style/Profile.EditText"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16dp"
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_email_black_24dp"
android:drawableStart=
"@drawable/ic_link_black_24dp"
android:hint=
"@string/msg_email"
android:hint=
"@string/msg_avatar_url"
android:inputType=
"textEmailAddress"
/>
android:inputType=
"text"
android:layout_marginBottom=
"16dp"
/>
</LinearLayout>
<EditText
</ScrollView>
android:id=
"@+id/text_avatar_url"
style=
"@style/Profile.EditText"
android:layout_marginTop=
"16dp"
android:drawableStart=
"@drawable/ic_link_black_24dp"
android:hint=
"@string/msg_avatar_url"
android:inputType=
"text"
/>
</LinearLayout>
<com.wang.avi.AVLoadingIndicatorView
<com.wang.avi.AVLoadingIndicatorView
android:id=
"@+id/view_loading"
android:id=
"@+id/view_loading"
...
...
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