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
35fe51af
Unverified
Commit
35fe51af
authored
Apr 06, 2018
by
divyanshu bhargava
Committed by
GitHub
Apr 06, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop-2.x' into RTL-layout
parents
ed1635be
c9fe5d91
Changes
55
Hide whitespace changes
Inline
Side-by-side
Showing
55 changed files
with
941 additions
and
423 deletions
+941
-423
build.gradle
app/build.gradle
+2
-2
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+15
-22
DrawableHelper.kt
app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
+39
-9
RocketChatApplication.kt
...ain/java/chat/rocket/android/app/RocketChatApplication.kt
+5
-4
LoginPresenter.kt
...droid/authentication/login/presentation/LoginPresenter.kt
+29
-28
RegisterUsernamePresenter.kt
...egisterusername/presentation/RegisterUsernamePresenter.kt
+9
-5
ServerPresenter.kt
...oid/authentication/server/presentation/ServerPresenter.kt
+2
-2
SignupPresenter.kt
...oid/authentication/signup/presentation/SignupPresenter.kt
+13
-11
TwoFAPresenter.kt
...d/authentication/twofactor/presentation/TwoFAPresenter.kt
+9
-6
ChatRoomPresenter.kt
...rocket/android/chatroom/presentation/ChatRoomPresenter.kt
+80
-43
ChatRoomView.kt
...chat/rocket/android/chatroom/presentation/ChatRoomView.kt
+3
-1
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+77
-68
ViewModelMapper.kt
...chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
+2
-2
ChatRoomsPresenter.kt
...cket/android/chatrooms/presentation/ChatRoomsPresenter.kt
+5
-2
ChatRoomsAdapter.kt
...java/chat/rocket/android/chatrooms/ui/ChatRoomsAdapter.kt
+2
-2
ChatRoomsFragment.kt
...ava/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
+6
-5
OauthHelper.kt
app/src/main/java/chat/rocket/android/helper/OauthHelper.kt
+5
-3
UrlHelper.kt
app/src/main/java/chat/rocket/android/helper/UrlHelper.kt
+0
-74
AccountViewHolder.kt
...ava/chat/rocket/android/main/adapter/AccountViewHolder.kt
+1
-0
AccountsAdapter.kt
.../java/chat/rocket/android/main/adapter/AccountsAdapter.kt
+26
-12
StatusViewHolder.kt
...java/chat/rocket/android/main/adapter/StatusViewHolder.kt
+18
-0
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+35
-8
MainView.kt
...in/java/chat/rocket/android/main/presentation/MainView.kt
+17
-1
MainActivity.kt
...src/main/java/chat/rocket/android/main/ui/MainActivity.kt
+35
-12
NavHeaderViewModel.kt
.../chat/rocket/android/main/viewmodel/NavHeaderViewModel.kt
+7
-3
NavHeaderViewModelMapper.kt
...rocket/android/main/viewmodel/NavHeaderViewModelMapper.kt
+12
-8
MembersPresenter.kt
...t/rocket/android/members/presentation/MembersPresenter.kt
+4
-1
MemberViewModel.kt
.../chat/rocket/android/members/viewmodel/MemberViewModel.kt
+2
-2
ProfilePresenter.kt
...t/rocket/android/profile/presentation/ProfilePresenter.kt
+6
-5
FirebaseTokenService.kt
...ain/java/chat/rocket/android/push/FirebaseTokenService.kt
+0
-1
CheckServerPresenter.kt
...ocket/android/server/presentation/CheckServerPresenter.kt
+18
-13
AboutActivity.kt
...va/chat/rocket/android/settings/about/ui/AboutActivity.kt
+43
-0
PasswordPresenter.kt
...droid/settings/password/presentation/PasswordPresenter.kt
+5
-1
SettingsFragment.kt
.../java/chat/rocket/android/settings/ui/SettingsFragment.kt
+4
-1
IO.kt
app/src/main/java/chat/rocket/android/util/IO.kt
+29
-0
RocketChatClient.kt
...a/chat/rocket/android/util/extensions/RocketChatClient.kt
+4
-1
String.kt
...c/main/java/chat/rocket/android/util/extensions/String.kt
+25
-0
Uri.kt
app/src/main/java/chat/rocket/android/util/extensions/Uri.kt
+4
-4
black_gradient.xml
app/src/main/res/drawable/black_gradient.xml
+2
-3
ic_app_name.xml
app/src/main/res/drawable/ic_app_name.xml
+57
-0
ic_status_away_24dp.xml
app/src/main/res/drawable/ic_status_away_24dp.xml
+19
-0
ic_status_busy_24dp.xml
app/src/main/res/drawable/ic_status_busy_24dp.xml
+19
-0
ic_status_invisible_24dp.xml
app/src/main/res/drawable/ic_status_invisible_24dp.xml
+19
-0
ic_status_online_24dp.xml
app/src/main/res/drawable/ic_status_online_24dp.xml
+19
-0
about_view.xml
app/src/main/res/layout/about_view.xml
+53
-0
activity_about.xml
app/src/main/res/layout/activity_about.xml
+14
-0
activity_main.xml
app/src/main/res/layout/activity_main.xml
+7
-5
item_account.xml
app/src/main/res/layout/item_account.xml
+16
-15
item_add_account.xml
app/src/main/res/layout/item_add_account.xml
+4
-9
item_change_status.xml
app/src/main/res/layout/item_change_status.xml
+54
-0
nav_header.xml
app/src/main/res/layout/nav_header.xml
+31
-25
strings.xml
app/src/main/res/values-hi-rIN/strings.xml
+8
-0
strings.xml
app/src/main/res/values-pt-rBR/strings.xml
+10
-2
dimens.xml
app/src/main/res/values/dimens.xml
+2
-1
strings.xml
app/src/main/res/values/strings.xml
+9
-1
No files found.
app/build.gradle
View file @
35fe51af
...
...
@@ -13,8 +13,8 @@ android {
applicationId
"chat.rocket.android"
minSdkVersion
21
targetSdkVersion
versions
.
targetSdk
versionCode
200
3
versionName
"2.0.0-beta
3
"
versionCode
200
6
versionName
"2.0.0-beta
4
"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled
true
}
...
...
app/src/main/AndroidManifest.xml
View file @
35fe51af
...
...
@@ -20,7 +20,6 @@
android:label=
"@string/app_name"
android:roundIcon=
"@mipmap/ic_launcher_round"
android:supportsRtl=
"true"
>
<activity
android:name=
".authentication.ui.AuthenticationActivity"
android:configChanges=
"orientation"
...
...
@@ -34,41 +33,33 @@
<category
android:name=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
<activity
android:name=
".server.ui.ChangeServerActivity"
android:theme=
"@style/AuthenticationTheme"
/>
<activity
android:name=
".main.ui.MainActivity"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
android:theme=
"@style/AppTheme"
/>
android:theme=
"@style/AppTheme"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
/>
<activity
android:name=
".webview.ui.WebViewActivity"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
android:theme=
"@style/AppTheme"
/>
android:theme=
"@style/AppTheme"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
/>
<activity
android:name=
".webview.cas.ui.CasWebViewActivity"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
android:theme=
"@style/AppTheme"
/>
android:theme=
"@style/AppTheme"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
/>
<activity
android:name=
".webview.oauth.ui.OauthWebViewActivity"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
android:theme=
"@style/AppTheme"
/>
android:theme=
"@style/AppTheme"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
/>
<activity
android:name=
".chatroom.ui.ChatRoomActivity"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
android:theme=
"@style/AppTheme"
/>
android:theme=
"@style/AppTheme"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
/>
<activity
android:name=
".chatroom.ui.PinnedMessagesActivity"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
android:theme=
"@style/AppTheme"
/>
android:theme=
"@style/AppTheme"
android:windowSoftInputMode=
"adjustResize|stateAlwaysHidden"
/>
<activity
android:name=
".settings.password.ui.PasswordActivity"
android:theme=
"@style/AppTheme"
/>
...
...
@@ -92,7 +83,6 @@
<action
android:name=
"com.google.firebase.INSTANCE_ID_EVENT"
/>
</intent-filter>
</service>
<service
android:name=
".push.GcmListenerService"
android:exported=
"false"
>
...
...
@@ -104,6 +94,9 @@
<meta-data
android:name=
"io.fabric.ApiKey"
android:value=
"12ac6e94f850aaffcdff52001af77ca415d06a43"
/>
<activity
android:name=
".settings.about.ui.AboutActivity"
android:theme=
"@style/AppTheme"
/>
</application>
</manifest>
\ No newline at end of file
app/src/main/java/chat/rocket/android/app/DrawableHelper.kt
View file @
35fe51af
...
...
@@ -106,15 +106,45 @@ object DrawableHelper {
* @return The user status drawable.
*/
fun
getUserStatusDrawable
(
userStatus
:
UserStatus
,
context
:
Context
):
Drawable
{
val
userStatusDrawable
=
getDrawableFromId
(
R
.
drawable
.
ic_user_status_black
,
context
).
mutate
()
wrapDrawable
(
userStatusDrawable
)
when
(
userStatus
)
{
is
UserStatus
.
Online
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusOnline
)
is
UserStatus
.
Busy
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusBusy
)
is
UserStatus
.
Away
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusAway
)
is
UserStatus
.
Offline
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusOffline
)
else
->
tintDrawable
(
userStatusDrawable
,
context
,
R
.
color
.
colorUserStatusOffline
)
return
when
(
userStatus
)
{
is
UserStatus
.
Online
->
{
getDrawableFromId
(
R
.
drawable
.
ic_status_online_24dp
,
context
)
}
is
UserStatus
.
Away
->
{
getDrawableFromId
(
R
.
drawable
.
ic_status_away_24dp
,
context
)
}
is
UserStatus
.
Busy
->
{
getDrawableFromId
(
R
.
drawable
.
ic_status_busy_24dp
,
context
)
}
else
->
getDrawableFromId
(
R
.
drawable
.
ic_status_invisible_24dp
,
context
)
}
}
// TODO Why we need two UserStatus?
/**
* Returns the user status drawable.
*
* @param userStatus The user status.
* @param context The context.
* @sse [chat.rocket.core.internal.realtime.UserStatus]
* @return The user status drawable.
*/
fun
getUserStatusDrawable
(
userStatus
:
chat
.
rocket
.
core
.
internal
.
realtime
.
UserStatus
,
context
:
Context
):
Drawable
{
return
when
(
userStatus
)
{
is
chat
.
rocket
.
core
.
internal
.
realtime
.
UserStatus
.
Online
->
{
getDrawableFromId
(
R
.
drawable
.
ic_status_online_24dp
,
context
)
}
is
chat
.
rocket
.
core
.
internal
.
realtime
.
UserStatus
.
Away
->
{
getDrawableFromId
(
R
.
drawable
.
ic_status_away_24dp
,
context
)
}
is
chat
.
rocket
.
core
.
internal
.
realtime
.
UserStatus
.
Busy
->
{
getDrawableFromId
(
R
.
drawable
.
ic_status_busy_24dp
,
context
)
}
else
->
getDrawableFromId
(
R
.
drawable
.
ic_status_invisible_24dp
,
context
)
}
return
userStatusDrawable
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt
View file @
35fe51af
...
...
@@ -18,10 +18,11 @@ import chat.rocket.android.app.migration.model.RealmUser
import
chat.rocket.android.authentication.domain.model.toToken
import
chat.rocket.android.dagger.DaggerAppComponent
import
chat.rocket.android.helper.CrashlyticsTree
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.serverLogoUrl
import
chat.rocket.android.widget.emoji.EmojiRepository
import
chat.rocket.common.model.Token
import
chat.rocket.core.model.Value
...
...
@@ -148,12 +149,12 @@ class RocketChatApplication : Application(), HasActivityInjector, HasServiceInje
private
fun
migrateServerInfo
(
url
:
String
,
authToken
:
String
,
settings
:
PublicSettings
,
user
:
RealmUser
)
{
val
userId
=
user
.
_id
val
avatar
=
UrlHelper
.
getAvatarUrl
(
url
,
user
.
username
!!
)
val
avatar
=
url
.
avatarUrl
(
user
.
username
!!
)
val
icon
=
settings
.
favicon
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
url
,
it
)
url
.
serverLogoUrl
(
it
)
}
val
logo
=
settings
.
wideTile
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
url
,
it
)
url
.
serverLogoUrl
(
it
)
}
val
account
=
Account
(
url
,
icon
,
logo
,
user
.
username
!!
,
avatar
)
launch
(
CommonPool
)
{
...
...
app/src/main/java/chat/rocket/android/authentication/login/presentation/LoginPresenter.kt
View file @
35fe51af
package
chat.rocket.android.authentication.login.presentation
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.NetworkHelper
import
chat.rocket.android.helper.OauthHelper
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.presentation.CheckServerPresenter
import
chat.rocket.android.util.VersionInfo
import
chat.rocket.android.util.extensions.*
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.RocketChatTwoFactorException
import
chat.rocket.common.model.Token
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.*
import
chat.rocket.core.model.Myself
import
kotlinx.coroutines.experimental.delay
import
timber.log.Timber
import
java.util.concurrent.TimeUnit
...
...
@@ -103,7 +100,7 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
private
fun
setupCasView
()
{
if
(
settings
.
isCasAuthenticationEnabled
())
{
val
token
=
generateRandomString
(
17
)
view
.
setupCasButtonListener
(
UrlHelper
.
getCasUrl
(
settings
.
casLoginUrl
(),
currentServer
,
token
),
token
)
view
.
setupCasButtonListener
(
settings
.
casLoginUrl
().
casUrl
(
currentServer
,
token
),
token
)
view
.
showCasButton
()
}
}
...
...
@@ -118,7 +115,9 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
private
fun
setupOauthServicesView
()
{
launchUI
(
strategy
)
{
try
{
val
services
=
client
.
settingsOauth
().
services
val
services
=
retryIO
(
"settingsOauth()"
)
{
client
.
settingsOauth
().
services
}
if
(
services
.
isNotEmpty
())
{
val
state
=
"{\"loginStyle\":\"popup\",\"credentialToken\":\"${generateRandomString(40)}\",\"isCordova\":true}"
.
encodeToBase64
()
var
totalSocialAccountsEnabled
=
0
...
...
@@ -195,30 +194,32 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
view
.
disableUserInput
()
view
.
showLoading
()
try
{
val
token
=
when
(
loginType
)
{
TYPE_LOGIN_USER_EMAIL
->
{
if
(
usernameOrEmail
.
isEmail
())
{
client
.
loginWithEmail
(
usernameOrEmail
,
password
)
}
else
{
if
(
settings
.
isLdapAuthenticationEnabled
())
{
client
.
loginWithLdap
(
usernameOrEmail
,
password
)
val
token
=
retryIO
(
"login"
)
{
when
(
loginType
)
{
TYPE_LOGIN_USER_EMAIL
->
{
if
(
usernameOrEmail
.
isEmail
())
{
client
.
loginWithEmail
(
usernameOrEmail
,
password
)
}
else
{
client
.
login
(
usernameOrEmail
,
password
)
if
(
settings
.
isLdapAuthenticationEnabled
())
{
client
.
loginWithLdap
(
usernameOrEmail
,
password
)
}
else
{
client
.
login
(
usernameOrEmail
,
password
)
}
}
}
}
TYPE_LOGIN_CAS
->
{
delay
(
3
,
TimeUnit
.
SECONDS
)
client
.
loginWithCas
(
credentialToken
)
}
TYPE_LOGIN_OAUTH
->
{
client
.
loginWithOauth
(
credentialToken
,
credentialSecret
)
}
else
->
{
throw
IllegalStateException
(
"Expected TYPE_LOGIN_USER_EMAIL, TYPE_LOGIN_CAS or TYPE_LOGIN_OAUTH"
)
TYPE_LOGIN_CAS
->
{
delay
(
3
,
TimeUnit
.
SECONDS
)
client
.
loginWithCas
(
credentialToken
)
}
TYPE_LOGIN_OAUTH
->
{
client
.
loginWithOauth
(
credentialToken
,
credentialSecret
)
}
else
->
{
throw
IllegalStateException
(
"Expected TYPE_LOGIN_USER_EMAIL, TYPE_LOGIN_CAS or TYPE_LOGIN_OAUTH"
)
}
}
}
val
username
=
client
.
me
().
username
val
username
=
retryIO
(
"me()"
)
{
client
.
me
().
username
}
if
(
username
!=
null
)
{
localRepository
.
save
(
LocalRepository
.
CURRENT_USERNAME_KEY
,
username
)
saveAccount
(
username
)
...
...
@@ -258,12 +259,12 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
private
suspend
fun
saveAccount
(
username
:
String
)
{
val
icon
=
settings
.
favicon
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
logo
=
settings
.
wideTile
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
thumb
=
UrlHelper
.
getAvatarUrl
(
currentServer
,
username
)
val
thumb
=
currentServer
.
avatarUrl
(
username
)
val
account
=
Account
(
currentServer
,
icon
,
logo
,
username
,
thumb
)
saveAccountInteractor
.
save
(
account
)
}
...
...
app/src/main/java/chat/rocket/android/authentication/registerusername/presentation/RegisterUsernamePresenter.kt
View file @
35fe51af
...
...
@@ -3,13 +3,15 @@ package chat.rocket.android.authentication.registerusername.presentation
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.NetworkHelper
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.registerPushToken
import
chat.rocket.android.util.extensions.serverLogoUrl
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.model.Token
import
chat.rocket.common.util.ifNull
...
...
@@ -41,7 +43,9 @@ class RegisterUsernamePresenter @Inject constructor(
if
(
NetworkHelper
.
hasInternetAccess
())
{
view
.
showLoading
()
try
{
val
me
=
client
.
updateOwnBasicInformation
(
username
=
username
)
val
me
=
retryIO
(
"updateOwnBasicInformation(username = $username)"
)
{
client
.
updateOwnBasicInformation
(
username
=
username
)
}
val
registeredUsername
=
me
.
username
if
(
registeredUsername
!=
null
)
{
saveAccount
(
registeredUsername
)
...
...
@@ -75,12 +79,12 @@ class RegisterUsernamePresenter @Inject constructor(
private
suspend
fun
saveAccount
(
username
:
String
)
{
val
icon
=
settings
.
favicon
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
logo
=
settings
.
wideTile
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
thumb
=
UrlHelper
.
getAvatarUrl
(
currentServer
,
username
)
val
thumb
=
currentServer
.
avatarUrl
(
username
)
val
account
=
Account
(
currentServer
,
icon
,
logo
,
username
,
thumb
)
saveAccountInteractor
.
save
(
account
)
}
...
...
app/src/main/java/chat/rocket/android/authentication/server/presentation/ServerPresenter.kt
View file @
35fe51af
...
...
@@ -3,10 +3,10 @@ package chat.rocket.android.authentication.server.presentation
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.NetworkHelper
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.server.domain.GetAccountsInteractor
import
chat.rocket.android.server.domain.RefreshSettingsInteractor
import
chat.rocket.android.server.domain.SaveCurrentServerInteractor
import
chat.rocket.android.util.extensions.isValidUrl
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.common.util.ifNull
import
javax.inject.Inject
...
...
@@ -18,7 +18,7 @@ class ServerPresenter @Inject constructor(private val view: ServerView,
private
val
refreshSettingsInteractor
:
RefreshSettingsInteractor
,
private
val
getAccountsInteractor
:
GetAccountsInteractor
)
{
fun
connect
(
server
:
String
)
{
if
(!
UrlHelper
.
isValidUrl
(
server
))
{
if
(!
server
.
isValidUrl
(
))
{
view
.
showInvalidServerUrlMessage
()
}
else
{
launchUI
(
strategy
)
{
...
...
app/src/main/java/chat/rocket/android/authentication/signup/presentation/SignupPresenter.kt
View file @
35fe51af
...
...
@@ -3,20 +3,22 @@ package chat.rocket.android.authentication.signup.presentation
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.NetworkHelper
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.main.viewmodel.NavHeaderViewModel
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.privacyPolicyUrl
import
chat.rocket.android.util.extensions.registerPushToken
import
chat.rocket.android.util.extensions.serverLogoUrl
import
chat.rocket.android.util.extensions.termsOfServiceUrl
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.login
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.registerPushToken
import
chat.rocket.core.internal.rest.signup
import
chat.rocket.core.model.Myself
import
javax.inject.Inject
...
...
@@ -60,10 +62,10 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
try
{
// TODO This function returns a user so should we save it?
client
.
signup
(
email
,
name
,
username
,
password
)
retryIO
(
"signup"
)
{
client
.
signup
(
email
,
name
,
username
,
password
)
}
// TODO This function returns a user token so should we save it?
client
.
login
(
username
,
password
)
val
me
=
client
.
me
()
retryIO
(
"login"
)
{
client
.
login
(
username
,
password
)
}
val
me
=
retryIO
(
"me"
)
{
client
.
me
()
}
localRepository
.
save
(
LocalRepository
.
CURRENT_USERNAME_KEY
,
me
.
username
)
saveAccount
(
me
)
registerPushToken
()
...
...
@@ -88,13 +90,13 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
fun
termsOfService
()
{
serverInteractor
.
get
()
?.
let
{
navigator
.
toWebPage
(
UrlHelper
.
getTermsOfServiceUrl
(
it
))
navigator
.
toWebPage
(
it
.
termsOfServiceUrl
(
))
}
}
fun
privacyPolicy
()
{
serverInteractor
.
get
()
?.
let
{
navigator
.
toWebPage
(
UrlHelper
.
getPrivacyPolicyUrl
(
it
))
navigator
.
toWebPage
(
it
.
privacyPolicyUrl
(
))
}
}
...
...
@@ -108,12 +110,12 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
private
suspend
fun
saveAccount
(
me
:
Myself
)
{
val
icon
=
settings
.
favicon
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
logo
=
settings
.
wideTile
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
thumb
=
UrlHelper
.
getAvatarUrl
(
currentServer
,
me
.
username
!!
)
val
thumb
=
currentServer
.
avatarUrl
(
me
.
username
!!
)
val
account
=
Account
(
currentServer
,
icon
,
logo
,
me
.
username
!!
,
thumb
)
saveAccountInteractor
.
save
(
account
)
}
...
...
app/src/main/java/chat/rocket/android/authentication/twofactor/presentation/TwoFAPresenter.kt
View file @
35fe51af
...
...
@@ -3,13 +3,15 @@ package chat.rocket.android.authentication.twofactor.presentation
import
chat.rocket.android.authentication.presentation.AuthenticationNavigator
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.NetworkHelper
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.registerPushToken
import
chat.rocket.android.util.extensions.serverLogoUrl
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatAuthException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.util.ifNull
...
...
@@ -50,9 +52,10 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
view
.
showLoading
()
try
{
// The token is saved via the client TokenProvider
val
token
=
val
token
=
retryIO
(
"login"
)
{
client
.
login
(
usernameOrEmail
,
password
,
twoFactorAuthenticationCode
)
val
me
=
client
.
me
()
}
val
me
=
retryIO
(
"me"
)
{
client
.
me
()
}
saveAccount
(
me
)
tokenRepository
.
save
(
server
,
token
)
registerPushToken
()
...
...
@@ -90,12 +93,12 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
private
suspend
fun
saveAccount
(
me
:
Myself
)
{
val
icon
=
settings
.
favicon
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
logo
=
settings
.
wideTile
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
thumb
=
UrlHelper
.
getAvatarUrl
(
currentServer
,
me
.
username
!!
)
val
thumb
=
currentServer
.
avatarUrl
(
me
.
username
!!
)
val
account
=
Account
(
currentServer
,
icon
,
logo
,
me
.
username
!!
,
thumb
)
saveAccountInteractor
.
save
(
account
)
}
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomPresenter.kt
View file @
35fe51af
...
...
@@ -11,12 +11,13 @@ import chat.rocket.android.chatroom.viewmodel.suggestion.ChatRoomSuggestionViewM
import
chat.rocket.android.chatroom.viewmodel.suggestion.CommandSuggestionViewModel
import
chat.rocket.android.chatroom.viewmodel.suggestion.PeopleSuggestionViewModel
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.state
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.model.RoomType
import
chat.rocket.common.model.UserStatus
...
...
@@ -26,6 +27,7 @@ import chat.rocket.core.internal.realtime.State
import
chat.rocket.core.internal.rest.*
import
chat.rocket.core.model.Command
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.Myself
import
chat.rocket.core.model.Value
import
kotlinx.coroutines.experimental.CommonPool
import
kotlinx.coroutines.experimental.android.UI
...
...
@@ -34,13 +36,14 @@ import kotlinx.coroutines.experimental.channels.Channel
import
kotlinx.coroutines.experimental.launch
import
org.threeten.bp.Instant
import
timber.log.Timber
import
java.util.*
import
javax.inject.Inject
class
ChatRoomPresenter
@Inject
constructor
(
private
val
view
:
ChatRoomView
,
private
val
navigator
:
ChatRoomNavigator
,
private
val
strategy
:
CancelStrategy
,
getSettingsInteractor
:
GetSettingsInteractor
,
private
val
serverInteractor
:
GetCurrentServerInteractor
,
serverInteractor
:
GetCurrentServerInteractor
,
private
val
getChatRoomsInteractor
:
GetChatRoomsInteractor
,
private
val
permissions
:
GetPermissionsInteractor
,
private
val
uriInteractor
:
UriInteractor
,
...
...
@@ -68,7 +71,9 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
view
.
showLoading
()
try
{
val
messages
=
client
.
messages
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
30
).
result
retryIO
(
description
=
"messages chatRoom: $chatRoomId, type: $chatRoomType, offset: $offset"
)
{
client
.
messages
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
30
).
result
}
messagesRepository
.
saveAll
(
messages
)
val
messagesViewModels
=
mapper
.
map
(
messages
)
...
...
@@ -101,20 +106,23 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
view
.
disableSendMessageButton
()
try
{
// ignore message for now, will receive it on the stream
val
message
=
if
(
messageId
==
null
)
{
client
.
sendMessage
(
chatRoomId
,
text
)
}
else
{
client
.
updateMessage
(
chatRoomId
,
messageId
,
text
)
val
message
=
retryIO
{
if
(
messageId
==
null
)
{
val
id
=
UUID
.
randomUUID
().
toString
()
client
.
sendMessage
(
id
,
chatRoomId
,
text
)
}
else
{
client
.
updateMessage
(
chatRoomId
,
messageId
,
text
)
}
}
view
.
clearMessageComposition
(
)
view
.
enableSendMessageButton
(
false
)
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error sending message..."
)
ex
.
message
?.
let
{
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
}
finally
{
view
.
enableSendMessageButton
()
view
.
enableSendMessageButton
(
true
)
}
}
}
...
...
@@ -137,8 +145,10 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
fileSize
>
maxFileSize
->
view
.
showInvalidFileSize
(
fileSize
,
maxFileSize
)
else
->
{
Timber
.
d
(
"Uploading to $roomId: $fileName - $mimeType"
)
client
.
uploadFile
(
roomId
,
fileName
!!
,
mimeType
,
msg
,
description
=
fileName
)
{
uriInteractor
.
getInputStream
(
uri
)
retryIO
(
"uploadFile($roomId, $fileName, $mimeType"
)
{
client
.
uploadFile
(
roomId
,
fileName
!!
,
mimeType
,
msg
,
description
=
fileName
)
{
uriInteractor
.
getInputStream
(
uri
)
}
}
}
}
...
...
@@ -158,7 +168,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
private
fun
markRoomAsRead
(
roomId
:
String
)
{
launchUI
(
strategy
)
{
try
{
client
.
markAsRead
(
roomId
)
retryIO
(
description
=
"markAsRead($roomId)"
)
{
client
.
markAsRead
(
roomId
)
}
}
catch
(
ex
:
RocketChatException
)
{
view
.
showMessage
(
ex
.
message
!!
)
// TODO Remove.
Timber
.
e
(
ex
)
// FIXME: Right now we are only catching the exception with Timber.
...
...
@@ -204,23 +214,32 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
val
roomType
=
roomTypeOf
(
chatRoomType
!!
)
messagesRepository
.
getByRoomId
(
chatRoomId
!!
)
.
sortedByDescending
{
it
.
timestamp
}.
firstOrNull
()
?.
let
{
lastMessage
->
val
instant
=
Instant
.
ofEpochMilli
(
lastMessage
.
timestamp
)
val
messages
=
client
.
history
(
chatRoomId
!!
,
roomType
,
count
=
50
,
oldest
=
instant
.
toString
())
Timber
.
d
(
"History: $messages"
)
val
instant
=
Instant
.
ofEpochMilli
(
lastMessage
.
timestamp
).
toString
()
try
{
val
messages
=
retryIO
(
description
=
"history($chatRoomId, $roomType, $instant)"
)
{
client
.
history
(
chatRoomId
!!
,
roomType
,
count
=
50
,
oldest
=
instant
)
}
Timber
.
d
(
"History: $messages"
)
if
(
messages
.
result
.
isNotEmpty
())
{
val
models
=
mapper
.
map
(
messages
.
result
)
messagesRepository
.
saveAll
(
messages
.
result
)
if
(
messages
.
result
.
isNotEmpty
())
{
val
models
=
mapper
.
map
(
messages
.
result
)
messagesRepository
.
saveAll
(
messages
.
result
)
launchUI
(
strategy
)
{
view
.
showNewMessage
(
models
)
}
launchUI
(
strategy
)
{
view
.
showNewMessage
(
models
)
}
if
(
messages
.
result
.
size
==
50
)
{
// we loade at least count messages, try one more to fetch more messages
loadMissingMessages
()
if
(
messages
.
result
.
size
==
50
)
{
// we loaded at least count messages, try one more to fetch more messages
loadMissingMessages
()
}
}
}
catch
(
ex
:
Exception
)
{
// TODO - we need to better treat connection problems here, but no let gaps
// on the messages list
Timber
.
d
(
ex
,
"Error fetching channel history"
)
ex
.
printStackTrace
()
}
}
}
...
...
@@ -249,7 +268,9 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
//TODO: Default delete message always to true. Until we have the permissions system
//implemented, a user will only be able to delete his own messages.
try
{
client
.
deleteMessage
(
roomId
,
id
,
true
)
retryIO
(
description
=
"deleteMessage($roomId, $id)"
)
{
client
.
deleteMessage
(
roomId
,
id
,
true
)
}
// if Message_ShowDeletedStatus == true an update to that message will be dispatched.
// Otherwise we signalize that we just want the message removed.
if
(!
permissions
.
showDeletedStatus
())
{
...
...
@@ -272,14 +293,19 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
fun
citeMessage
(
roomType
:
String
,
roomName
:
String
,
messageId
:
String
,
mentionAuthor
:
Boolean
)
{
launchUI
(
strategy
)
{
val
message
=
messagesRepository
.
getById
(
messageId
)
val
me
=
client
.
me
()
//TODO: Cache this and use an interactor
val
serverUrl
=
serverInteractor
.
get
()
!!
val
me
:
Myself
?
=
try
{
retryIO
(
"me()"
)
{
client
.
me
()
}
//TODO: Cache this and use an interactor
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error getting myself info."
)
ex
.
printStackTrace
()
null
}
message
?.
let
{
m
->
val
id
=
m
.
id
val
username
=
m
.
sender
?.
username
val
user
=
"@"
+
if
(
settings
.
useRealName
())
m
.
sender
?.
name
?:
m
.
sender
?.
username
else
m
.
sender
?.
username
val
mention
=
if
(
mentionAuthor
&&
me
.
username
!=
username
)
user
else
""
val
mention
=
if
(
mentionAuthor
&&
me
?
.
username
!=
username
)
user
else
""
val
type
=
roomTypeOf
(
roomType
)
val
room
=
when
(
type
)
{
is
RoomType
.
Channel
->
"channel"
...
...
@@ -290,7 +316,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
view
.
showReplyingAction
(
username
=
user
,
replyMarkdown
=
"[ ]($
serverUrl
/$room/$roomName?msg=$id) $mention "
,
replyMarkdown
=
"[ ]($
currentServer
/$room/$roomName?msg=$id) $mention "
,
quotedMessage
=
mapper
.
map
(
message
).
last
().
preview
?.
message
?:
""
)
}
...
...
@@ -338,7 +364,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
return
@launchUI
}
try
{
client
.
pinMessage
(
messageId
)
retryIO
(
"pinMessage($messageId)"
)
{
client
.
pinMessage
(
messageId
)
}
}
catch
(
e
:
RocketChatException
)
{
Timber
.
e
(
e
)
}
...
...
@@ -352,7 +378,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
return
@launchUI
}
try
{
client
.
unpinMessage
(
messageId
)
retryIO
(
"unpinMessage($messageId)"
)
{
client
.
unpinMessage
(
messageId
)
}
}
catch
(
e
:
RocketChatException
)
{
Timber
.
e
(
e
)
}
...
...
@@ -362,7 +388,9 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
fun
loadActiveMembers
(
chatRoomId
:
String
,
chatRoomType
:
String
,
offset
:
Long
=
0
,
filterSelfOut
:
Boolean
=
false
)
{
launchUI
(
strategy
)
{
try
{
val
members
=
client
.
getMembers
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
50
).
result
val
members
=
retryIO
(
"getMembers($chatRoomId, $chatRoomType, $offset)"
)
{
client
.
getMembers
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
50
).
result
}
usersRepository
.
saveAll
(
members
)
val
self
=
localRepository
.
get
(
LocalRepository
.
CURRENT_USERNAME_KEY
)
// Take at most the 100 most recent messages distinguished by user. Can return less.
...
...
@@ -373,7 +401,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
val
sender
=
it
.
sender
!!
val
username
=
sender
.
username
?:
""
val
name
=
sender
.
name
?:
""
val
avatarUrl
=
UrlHelper
.
getAvatarUrl
(
currentServer
,
username
)
val
avatarUrl
=
currentServer
.
avatarUrl
(
username
)
val
found
=
members
.
firstOrNull
{
member
->
member
.
username
==
username
}
val
status
=
if
(
found
!=
null
)
found
.
status
else
UserStatus
.
Offline
()
val
searchList
=
mutableListOf
(
username
,
name
)
...
...
@@ -390,7 +418,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
activeUsers
.
addAll
(
others
.
map
{
val
username
=
it
.
username
?:
""
val
name
=
it
.
name
?:
""
val
avatarUrl
=
UrlHelper
.
getAvatarUrl
(
currentServer
,
username
)
val
avatarUrl
=
currentServer
.
avatarUrl
(
username
)
val
searchList
=
mutableListOf
(
username
,
name
)
PeopleSuggestionViewModel
(
avatarUrl
,
username
,
username
,
name
,
it
.
status
,
true
,
searchList
)
})
...
...
@@ -405,7 +433,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
fun
spotlight
(
query
:
String
,
@AutoCompleteType
type
:
Int
,
filterSelfOut
:
Boolean
=
false
)
{
launchUI
(
strategy
)
{
try
{
val
(
users
,
rooms
)
=
client
.
spotlight
(
query
)
val
(
users
,
rooms
)
=
retryIO
(
"spotlight($query)"
)
{
client
.
spotlight
(
query
)
}
when
(
type
)
{
PEOPLE
->
{
if
(
users
.
isNotEmpty
())
{
...
...
@@ -417,7 +445,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
val
name
=
it
.
name
?:
""
val
searchList
=
mutableListOf
(
username
,
name
)
it
.
emails
?.
forEach
{
email
->
searchList
.
add
(
email
.
address
)
}
PeopleSuggestionViewModel
(
UrlHelper
.
getAvatarUrl
(
currentServer
,
username
),
PeopleSuggestionViewModel
(
currentServer
.
avatarUrl
(
username
),
username
,
username
,
name
,
it
.
status
,
false
,
searchList
)
}.
filterNot
{
filterSelfOut
&&
self
!=
null
&&
self
==
it
.
text
})
}
...
...
@@ -468,7 +496,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
fun
joinChat
(
chatRoomId
:
String
)
{
launchUI
(
strategy
)
{
try
{
client
.
joinChat
(
chatRoomId
)
retryIO
(
"joinChat($chatRoomId)"
)
{
client
.
joinChat
(
chatRoomId
)
}
view
.
onJoined
()
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
...
...
@@ -482,7 +510,9 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
fun
react
(
messageId
:
String
,
emoji
:
String
)
{
launchUI
(
strategy
)
{
try
{
client
.
toggleReaction
(
messageId
,
emoji
.
removeSurrounding
(
":"
))
retryIO
(
"toogleEmoji($messageId, $emoji)"
)
{
client
.
toggleReaction
(
messageId
,
emoji
.
removeSurrounding
(
":"
))
}
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
}
...
...
@@ -497,7 +527,9 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
launchUI
(
strategy
)
{
try
{
//TODO: cache the commands
val
commands
=
client
.
commands
(
0
,
100
).
result
val
commands
=
retryIO
(
"commands(0, 100)"
)
{
client
.
commands
(
0
,
100
).
result
}
view
.
populateCommandSuggestions
(
commands
.
map
{
CommandSuggestionViewModel
(
it
.
command
,
it
.
description
?:
""
,
listOf
(
it
.
command
))
})
...
...
@@ -511,22 +543,27 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
launchUI
(
strategy
)
{
try
{
if
(
text
.
length
==
1
)
{
view
.
disableSendMessageButton
()
// we have just the slash, post it anyway
sendMessage
(
roomId
,
text
,
null
)
}
else
{
view
.
disableSendMessageButton
()
val
command
=
text
.
split
(
" "
)
val
name
=
command
[
0
].
substring
(
1
)
var
params
:
String
=
""
var
params
=
""
command
.
forEachIndexed
{
index
,
param
->
if
(
index
>
0
)
{
params
+=
"$param "
}
}
val
result
=
client
.
runCommand
(
Command
(
name
,
params
),
roomId
)
val
result
=
retryIO
(
"runCommand($name, $params, $roomId)"
)
{
client
.
runCommand
(
Command
(
name
,
params
),
roomId
)
}
if
(!
result
)
{
// failed, command is not valid so post it
sendMessage
(
roomId
,
text
,
null
)
}
view
.
enableSendMessageButton
(
false
)
}
}
catch
(
ex
:
RocketChatException
)
{
Timber
.
e
(
ex
)
...
...
app/src/main/java/chat/rocket/android/chatroom/presentation/ChatRoomView.kt
View file @
35fe51af
...
...
@@ -92,8 +92,10 @@ interface ChatRoomView : LoadingView, MessageView {
/**
* Enables the send message button.
*
* @param sendFailed Whether the sent message has failed.
*/
fun
enableSendMessageButton
()
fun
enableSendMessageButton
(
sendFailed
:
Boolean
)
/**
* Clears the message composition.
...
...
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
35fe51af
...
...
@@ -35,7 +35,6 @@ import kotlinx.android.synthetic.main.fragment_chat_room.*
import
kotlinx.android.synthetic.main.message_attachment_options.*
import
kotlinx.android.synthetic.main.message_composer.*
import
kotlinx.android.synthetic.main.message_list.*
import
timber.log.Timber
import
java.util.concurrent.atomic.AtomicInteger
import
javax.inject.Inject
import
kotlin.math.absoluteValue
...
...
@@ -126,7 +125,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
activity
?.
apply
{
(
this
as
?
ChatRoomActivity
)
?.
showRoomTypeIcon
(
true
)
}
}
override
fun
onActivityCreated
(
savedInstanceState
:
Bundle
?)
{
...
...
@@ -135,6 +133,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
override
fun
onDestroyView
()
{
recycler_view
.
removeOnScrollListener
(
endlessRecyclerViewScrollListener
)
recycler_view
.
removeOnScrollListener
(
onScrollListener
)
recycler_view
.
removeOnLayoutChangeListener
(
layoutChangeListener
)
presenter
.
unsubscribeMessages
(
chatRoomId
)
handler
.
removeCallbacksAndMessages
(
null
)
unsubscribeTextMessage
()
...
...
@@ -203,58 +205,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
adapter
=
ChatRoomAdapter
(
chatRoomType
,
chatRoomName
,
presenter
,
reactionListener
=
this
@ChatRoomFragment
)
recycler_view
.
adapter
=
adapter
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
true
)
linearLayoutManager
.
stackFromEnd
=
true
recycler_view
.
layoutManager
=
linearLayoutManager
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
if
(
dataSet
.
size
>=
30
)
{
recycler_view
.
addOnScrollListener
(
object
:
EndlessRecyclerViewScrollListener
(
linearLayoutManager
)
{
override
fun
onLoadMore
(
page
:
Int
,
totalItemsCount
:
Int
,
recyclerView
:
RecyclerView
?)
{
presenter
.
loadMessages
(
chatRoomId
,
chatRoomType
,
page
*
30L
)
}
})
}
recycler_view
.
addOnLayoutChangeListener
{
_
,
_
,
_
,
_
,
bottom
,
_
,
_
,
_
,
oldBottom
->
val
y
=
oldBottom
-
bottom
if
(
y
.
absoluteValue
>
0
)
{
// if y is positive the keyboard is up else it's down
recycler_view
.
post
{
if
(
y
>
0
||
verticalScrollOffset
.
get
().
absoluteValue
>=
y
.
absoluteValue
)
{
recycler_view
.
scrollBy
(
0
,
y
)
}
else
{
recycler_view
.
scrollBy
(
0
,
verticalScrollOffset
.
get
())
}
}
}
recycler_view
.
addOnScrollListener
(
endlessRecyclerViewScrollListener
)
}
recycler_view
.
addOnScrollListener
(
object
:
RecyclerView
.
OnScrollListener
()
{
var
state
=
AtomicInteger
(
RecyclerView
.
SCROLL_STATE_IDLE
)
override
fun
onScrollStateChanged
(
recyclerView
:
RecyclerView
,
newState
:
Int
)
{
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_IDLE
,
newState
)
when
(
newState
)
{
RecyclerView
.
SCROLL_STATE_IDLE
->
{
if
(!
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_SETTLING
,
newState
))
{
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_DRAGGING
,
newState
)
}
}
RecyclerView
.
SCROLL_STATE_DRAGGING
->
{
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_IDLE
,
newState
)
}
RecyclerView
.
SCROLL_STATE_SETTLING
->
{
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_DRAGGING
,
newState
)
}
}
}
override
fun
onScrolled
(
recyclerView
:
RecyclerView
,
dx
:
Int
,
dy
:
Int
)
{
if
(
state
.
get
()
!=
RecyclerView
.
SCROLL_STATE_IDLE
)
{
verticalScrollOffset
.
getAndAdd
(
dy
)
}
}
})
recycler_view
.
addOnLayoutChangeListener
(
layoutChangeListener
)
recycler_view
.
addOnScrollListener
(
onScrollListener
)
}
val
oldMessagesCount
=
adapter
.
itemCount
...
...
@@ -267,6 +222,61 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
}
private
val
layoutChangeListener
=
View
.
OnLayoutChangeListener
{
_
,
_
,
_
,
_
,
bottom
,
_
,
_
,
_
,
oldBottom
->
val
y
=
oldBottom
-
bottom
if
(
y
.
absoluteValue
>
0
&&
isAdded
)
{
// if y is positive the keyboard is up else it's down
recycler_view
.
post
{
if
(
y
>
0
||
verticalScrollOffset
.
get
().
absoluteValue
>=
y
.
absoluteValue
)
{
recycler_view
.
scrollBy
(
0
,
y
)
}
else
{
recycler_view
.
scrollBy
(
0
,
verticalScrollOffset
.
get
())
}
}
}
}
private
lateinit
var
endlessRecyclerViewScrollListener
:
EndlessRecyclerViewScrollListener
private
val
onScrollListener
=
object
:
RecyclerView
.
OnScrollListener
()
{
var
state
=
AtomicInteger
(
RecyclerView
.
SCROLL_STATE_IDLE
)
override
fun
onScrollStateChanged
(
recyclerView
:
RecyclerView
,
newState
:
Int
)
{
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_IDLE
,
newState
)
when
(
newState
)
{
RecyclerView
.
SCROLL_STATE_IDLE
->
{
if
(!
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_SETTLING
,
newState
))
{
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_DRAGGING
,
newState
)
}
}
RecyclerView
.
SCROLL_STATE_DRAGGING
->
{
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_IDLE
,
newState
)
}
RecyclerView
.
SCROLL_STATE_SETTLING
->
{
state
.
compareAndSet
(
RecyclerView
.
SCROLL_STATE_DRAGGING
,
newState
)
}
}
}
override
fun
onScrolled
(
recyclerView
:
RecyclerView
,
dx
:
Int
,
dy
:
Int
)
{
if
(
state
.
get
()
!=
RecyclerView
.
SCROLL_STATE_IDLE
)
{
verticalScrollOffset
.
getAndAdd
(
dy
)
}
}
}
private
val
fabScrollListener
=
object
:
RecyclerView
.
OnScrollListener
()
{
override
fun
onScrolled
(
recyclerView
:
RecyclerView
,
dx
:
Int
,
dy
:
Int
)
{
if
(!
recyclerView
.
canScrollVertically
(
1
))
{
button_fab
.
hide
()
}
else
{
if
(
dy
<
0
&&
!
button_fab
.
isVisible
())
{
button_fab
.
show
()
}
}
}
}
override
fun
sendMessage
(
text
:
String
)
{
if
(!
text
.
isBlank
())
{
if
(!
text
.
startsWith
(
"/"
))
{
...
...
@@ -296,10 +306,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_send
.
isEnabled
=
false
}
override
fun
enableSendMessageButton
()
{
override
fun
enableSendMessageButton
(
sendFailed
:
Boolean
)
{
button_send
.
isEnabled
=
true
text_message
.
isEnabled
=
true
text_message
.
erase
()
if
(!
sendFailed
)
{
clearMessageComposition
()
}
}
override
fun
clearMessageComposition
()
{
...
...
@@ -463,18 +475,18 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
}
private
fun
setupRecyclerView
()
{
recycler_view
.
addOnScrollListener
(
object
:
RecyclerView
.
OnScrollListener
()
{
override
fun
onScrolled
(
recyclerView
:
RecyclerView
,
dx
:
Int
,
dy
:
Int
)
{
Timber
.
i
(
"Scrolling vertically: $dy"
)
if
(!
recyclerView
.
canScrollVertically
(
1
))
{
button_fab
.
hide
()
}
else
{
if
(
dy
<
0
&&
!
button_fab
.
isVisible
())
{
button_fab
.
show
()
}
}
// Initialize the endlessRecyclerViewScrollListener so we don't NPE at onDestroyView
val
linearLayoutManager
=
LinearLayoutManager
(
context
,
LinearLayoutManager
.
VERTICAL
,
true
)
linearLayoutManager
.
stackFromEnd
=
true
recycler_view
.
layoutManager
=
linearLayoutManager
recycler_view
.
itemAnimator
=
DefaultItemAnimator
()
endlessRecyclerViewScrollListener
=
object
:
EndlessRecyclerViewScrollListener
(
recycler_view
.
layoutManager
as
LinearLayoutManager
)
{
override
fun
onLoadMore
(
page
:
Int
,
totalItemsCount
:
Int
,
recyclerView
:
RecyclerView
?)
{
presenter
.
loadMessages
(
chatRoomId
,
chatRoomType
,
page
*
30L
)
}
})
}
recycler_view
.
addOnScrollListener
(
fabScrollListener
)
}
private
fun
setupFab
()
{
...
...
@@ -522,8 +534,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
var
textMessage
=
citation
?:
""
textMessage
+=
text_message
.
textContent
sendMessage
(
textMessage
)
clearMessageComposition
()
}
button_show_attachment_options
.
setOnClickListener
{
...
...
@@ -588,7 +598,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
text_message
.
requestFocus
()
emojiKeyboardPopup
.
showAtBottomPending
()
KeyboardHelper
.
showSoftKeyboard
(
text_message
)
}
setReactionButtonIcon
(
R
.
drawable
.
ic_keyboard_black_24dp
)
}
else
{
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
View file @
35fe51af
...
...
@@ -9,9 +9,9 @@ import android.text.style.ForegroundColorSpan
import
android.text.style.StyleSpan
import
chat.rocket.android.R
import
chat.rocket.android.helper.MessageParser
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.widget.emoji.EmojiParser
import
chat.rocket.core.model.Message
import
chat.rocket.core.model.MessageType
...
...
@@ -235,7 +235,7 @@ class ViewModelMapper @Inject constructor(private val context: Context,
val
username
=
message
.
sender
?.
username
?:
"?"
return
baseUrl
?.
let
{
UrlHelper
.
getAvatarUrl
(
baseUrl
,
username
)
baseUrl
.
avatarUrl
(
username
)
}
}
...
...
app/src/main/java/chat/rocket/android/chatrooms/presentation/ChatRoomsPresenter.kt
View file @
35fe51af
...
...
@@ -12,6 +12,7 @@ import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import
chat.rocket.android.server.infraestructure.chatRooms
import
chat.rocket.android.server.infraestructure.state
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.model.BaseRoom
import
chat.rocket.common.model.RoomType
...
...
@@ -94,7 +95,9 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
try
{
val
roomList
=
getChatRoomsInteractor
.
getByName
(
currentServer
,
name
)
if
(
roomList
.
isEmpty
())
{
val
(
users
,
rooms
)
=
client
.
spotlight
(
name
)
val
(
users
,
rooms
)
=
retryIO
(
"spotlight($name)"
)
{
client
.
spotlight
(
name
)
}
val
chatRoomsCombined
=
mutableListOf
<
ChatRoom
>()
chatRoomsCombined
.
addAll
(
usersToChatRooms
(
users
))
chatRoomsCombined
.
addAll
(
roomsToChatRooms
(
rooms
))
...
...
@@ -161,7 +164,7 @@ class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
}
private
suspend
fun
loadRooms
():
List
<
ChatRoom
>
{
val
chatRooms
=
manager
.
chatRooms
().
update
val
chatRooms
=
retryIO
(
"chatRooms"
)
{
manager
.
chatRooms
().
update
}
val
sortedRooms
=
sortRooms
(
chatRooms
)
Timber
.
d
(
"Loaded rooms: ${sortedRooms.size}"
)
saveChatRoomsInteractor
.
save
(
currentServer
,
sortedRooms
)
...
...
app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsAdapter.kt
View file @
35fe51af
...
...
@@ -12,11 +12,11 @@ import android.view.View
import
android.view.ViewGroup
import
android.widget.TextView
import
chat.rocket.android.R
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.infrastructure.checkIfMyself
import
chat.rocket.android.server.domain.PublicSettings
import
chat.rocket.android.server.domain.useRealName
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.content
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.android.util.extensions.setVisible
...
...
@@ -75,7 +75,7 @@ class ChatRoomsAdapter(private val context: Context,
private
fun
bindAvatar
(
chatRoom
:
ChatRoom
,
drawee
:
SimpleDraweeView
)
{
val
avatarId
=
if
(
chatRoom
.
type
is
RoomType
.
DirectMessage
)
chatRoom
.
name
else
"@${chatRoom.name}"
drawee
.
setImageURI
(
UrlHelper
.
getAvatarUrl
(
chatRoom
.
client
.
url
,
avatarId
))
drawee
.
setImageURI
(
chatRoom
.
client
.
url
.
avatarUrl
(
avatarId
))
}
private
fun
bindName
(
chatRoom
:
ChatRoom
,
textView
:
TextView
)
{
...
...
app/src/main/java/chat/rocket/android/chatrooms/ui/ChatRoomsFragment.kt
View file @
35fe51af
...
...
@@ -158,15 +158,16 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
listJob
?.
cancel
()
listJob
=
launch
(
UI
)
{
val
adapter
=
recycler_view
.
adapter
as
SimpleSectionedRecyclerViewAdapter
// FIXME https://fabric.io/rocketchat3/android/apps/chat.rocket.android
.dev/issues/5a90d4718cb3c2fa63b3f557?time=last-seven-days
// TODO - fix this bug to reenable DiffUtil
val
diff
=
async
(
CommonPool
)
{
// FIXME https://fabric.io/rocketchat3/android/apps/chat.rocket.android
/issues/5ac2916c36c7b235275ccccf
// TODO - fix this bug to re
-
enable DiffUtil
/*
val diff = async(CommonPool) {
DiffUtil.calculateDiff(RoomsDiffCallback(adapter.baseAdapter.dataSet, newDataSet))
}.
await
()
}.await()
*/
if
(
isActive
)
{
adapter
.
baseAdapter
.
updateRooms
(
newDataSet
)
diff
.
dispatchUpdatesTo
(
adapter
)
// TODO - fix crash to re-enable diff.dispatchUpdatesTo(adapter)
adapter
.
notifyDataSetChanged
()
//Set sections always after data set is updated
setSections
()
...
...
app/src/main/java/chat/rocket/android/helper/OauthHelper.kt
View file @
35fe51af
package
chat.rocket.android.helper
import
chat.rocket.android.util.extensions.removeTrailingSlash
object
OauthHelper
{
/**
...
...
@@ -27,7 +29,7 @@ object OauthHelper {
fun
getGoogleOauthUrl
(
clientId
:
String
,
serverUrl
:
String
,
state
:
String
):
String
{
return
"https://accounts.google.com/o/oauth2/v2/auth"
+
"?client_id=$clientId"
+
"&redirect_uri=${
UrlHelper.removeTrailingSlash(serverUrl
)}/_oauth/google?close"
+
"&redirect_uri=${
serverUrl.removeTrailingSlash(
)}/_oauth/google?close"
+
"&state=$state"
+
"&response_type=code"
+
"&scope=email%20profile"
...
...
@@ -44,7 +46,7 @@ object OauthHelper {
fun
getLinkedinOauthUrl
(
clientId
:
String
,
serverUrl
:
String
,
state
:
String
):
String
{
return
"https://linkedin.com/oauth/v2/authorization"
+
"?client_id=$clientId"
+
"&redirect_uri=${
UrlHelper.removeTrailingSlash(serverUrl
)}/_oauth/linkedin?close"
+
"&redirect_uri=${
serverUrl.removeTrailingSlash(
)}/_oauth/linkedin?close"
+
"&state=$state"
+
"&response_type=code"
}
...
...
@@ -60,7 +62,7 @@ object OauthHelper {
fun
getGitlabOauthUrl
(
clientId
:
String
,
serverUrl
:
String
,
state
:
String
):
String
{
return
"https://gitlab.com/oauth/authorize"
+
"?client_id=$clientId"
+
"&redirect_uri=${
UrlHelper.removeTrailingSlash(serverUrl
)}/_oauth/gitlab?close"
+
"&redirect_uri=${
serverUrl.removeTrailingSlash(
)}/_oauth/gitlab?close"
+
"&state=$state"
+
"&response_type=code"
+
"&scope=read_user"
...
...
app/src/main/java/chat/rocket/android/helper/UrlHelper.kt
deleted
100644 → 0
View file @
ed1635be
package
chat.rocket.android.helper
import
android.util.Patterns
object
UrlHelper
{
/**
* Returns the avatar URL.
*
* @param serverUrl The server URL.
* @param avatarName The avatar name.
* @return The avatar URL.
*/
fun
getAvatarUrl
(
serverUrl
:
String
,
avatarName
:
String
,
format
:
String
=
"jpeg"
):
String
=
removeTrailingSlash
(
serverUrl
)
+
"/avatar/"
+
removeTrailingSlash
(
avatarName
)
+
"?format=$format"
/**
* Returns the server logo URL.
*
* @param serverUrl The server URL.
* @param favicon The faviconLarge from the server settings.
* @return The server logo URL.
*/
fun
getServerLogoUrl
(
serverUrl
:
String
,
favicon
:
String
):
String
=
removeTrailingSlash
(
serverUrl
)
+
"/$favicon"
/**
* Returns the CAS URL.
*
* @param casLoginUrl The CAS login URL from the server settings.
* @param serverUrl The server URL.
* @param token The token to be send to the CAS server.
* @return The avatar URL.
*/
fun
getCasUrl
(
casLoginUrl
:
String
,
serverUrl
:
String
,
token
:
String
):
String
=
removeTrailingSlash
(
casLoginUrl
)
+
"?service="
+
removeTrailingSlash
(
serverUrl
)
+
"/_cas/"
+
token
/**
* Returns the server's Terms of Service URL.
*
* @param serverUrl The server URL.
* @return The server's Terms of Service URL.
*/
fun
getTermsOfServiceUrl
(
serverUrl
:
String
)
=
removeTrailingSlash
(
serverUrl
)
+
"/terms-of-service"
/**
* Returns the server's Privacy Policy URL.
*
* @param serverUrl The server URL.
* @return The server's Privacy Policy URL.
*/
fun
getPrivacyPolicyUrl
(
serverUrl
:
String
)
=
removeTrailingSlash
(
serverUrl
)
+
"/privacy-policy"
/**
* Returns an URL without trailing slash.
*
* @param serverUrl The URL to remove the trailing slash (if exists).
* @return An URL without trailing slash.
*/
fun
removeTrailingSlash
(
serverUrl
:
String
):
String
{
return
if
(
serverUrl
[
serverUrl
.
length
-
1
]
==
'/'
)
{
serverUrl
.
replace
(
"/+$"
,
""
)
}
else
{
serverUrl
}
}
/**
* Checks if the given URL is valid or not.
* @param url The url to check its valid.
* @return True if url is valid, false otherwise.
*/
fun
isValidUrl
(
url
:
String
):
Boolean
=
Patterns
.
WEB_URL
.
matcher
(
url
).
matches
()
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/adapter/AccountViewHolder.kt
View file @
35fe51af
...
...
@@ -6,6 +6,7 @@ import chat.rocket.android.server.domain.model.Account
import
kotlinx.android.synthetic.main.item_account.view.*
class
AccountViewHolder
(
itemView
:
View
)
:
RecyclerView
.
ViewHolder
(
itemView
)
{
fun
bind
(
account
:
Account
)
{
with
(
itemView
)
{
server_logo
.
setImageURI
(
account
.
serverLogo
)
...
...
app/src/main/java/chat/rocket/android/main/adapter/AccountsAdapter.kt
View file @
35fe51af
...
...
@@ -5,50 +5,64 @@ import android.view.ViewGroup
import
chat.rocket.android.R
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.util.extensions.inflate
import
chat.rocket.core.internal.realtime.UserStatus
private
const
val
VIEW_TYPE_CHANGE_STATUS
=
0
private
const
val
VIEW_TYPE_ACCOUNT
=
1
private
const
val
VIEW_TYPE_ADD_ACCOUNT
=
2
class
AccountsAdapter
(
private
val
accounts
:
List
<
Account
>,
private
val
selector
:
Account
Selector
private
val
selector
:
Selector
)
:
RecyclerView
.
Adapter
<
RecyclerView
.
ViewHolder
>()
{
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
RecyclerView
.
ViewHolder
{
return
when
(
viewType
)
{
VIEW_TYPE_CHANGE_STATUS
->
StatusViewHolder
(
parent
.
inflate
(
R
.
layout
.
item_change_status
))
VIEW_TYPE_ACCOUNT
->
AccountViewHolder
(
parent
.
inflate
(
R
.
layout
.
item_account
))
else
->
AddAccountViewHolder
(
parent
.
inflate
(
R
.
layout
.
item_add_account
))
}
}
override
fun
getItemCount
()
=
accounts
.
size
+
1
override
fun
getItemCount
()
=
accounts
.
size
+
2
override
fun
getItemViewType
(
position
:
Int
)
=
if
(
position
==
accounts
.
size
)
VIEW_TYPE_ADD_ACCOUNT
else
VIEW_TYPE_ACCOUNT
override
fun
getItemViewType
(
position
:
Int
):
Int
{
return
when
{
position
==
0
->
VIEW_TYPE_CHANGE_STATUS
position
<=
accounts
.
size
->
VIEW_TYPE_ACCOUNT
else
->
VIEW_TYPE_ADD_ACCOUNT
}
}
override
fun
onBindViewHolder
(
holder
:
RecyclerView
.
ViewHolder
,
position
:
Int
)
{
when
(
holder
)
{
is
StatusViewHolder
->
bindStatusViewHolder
(
holder
)
is
AccountViewHolder
->
bindAccountViewHolder
(
holder
,
position
)
is
AddAccountViewHolder
->
bindAddAccountViewHolder
(
holder
,
position
)
is
AddAccountViewHolder
->
bindAddAccountViewHolder
(
holder
)
}
}
private
fun
bindStatusViewHolder
(
holder
:
StatusViewHolder
)
{
holder
.
bind
{
userStatus
->
selector
.
onStatusSelected
(
userStatus
)
}
}
private
fun
bindAccountViewHolder
(
holder
:
AccountViewHolder
,
position
:
Int
)
{
val
account
=
accounts
[
position
]
val
account
=
accounts
[
position
-
1
]
holder
.
bind
(
account
)
holder
.
itemView
.
setOnClickListener
{
selector
.
onAccountSelected
(
account
.
serverUrl
)
}
}
private
fun
bindAddAccountViewHolder
(
holder
:
AddAccountViewHolder
,
position
:
Int
)
{
private
fun
bindAddAccountViewHolder
(
holder
:
AddAccountViewHolder
)
{
holder
.
itemView
.
setOnClickListener
{
selector
.
onAddedAccountSelected
()
}
}
}
interface
AccountSelector
{
interface
Selector
{
fun
onStatusSelected
(
userStatus
:
UserStatus
)
fun
onAccountSelected
(
serverUrl
:
String
)
fun
onAddedAccountSelected
()
}
private
const
val
VIEW_TYPE_ACCOUNT
=
0
private
const
val
VIEW_TYPE_ADD_ACCOUNT
=
1
\ No newline at end of file
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/adapter/StatusViewHolder.kt
0 → 100644
View file @
35fe51af
package
chat.rocket.android.main.adapter
import
android.support.v7.widget.RecyclerView
import
android.view.View
import
chat.rocket.core.internal.realtime.UserStatus
import
kotlinx.android.synthetic.main.item_change_status.view.*
class
StatusViewHolder
(
itemView
:
View
)
:
RecyclerView
.
ViewHolder
(
itemView
)
{
fun
bind
(
listener
:
(
UserStatus
)
->
Unit
)
{
with
(
itemView
)
{
text_online
.
setOnClickListener
{
listener
(
UserStatus
.
Online
)
}
text_away
.
setOnClickListener
{
listener
(
UserStatus
.
Away
)
}
text_busy
.
setOnClickListener
{
listener
(
UserStatus
.
Busy
)
}
text_invisible
.
setOnClickListener
{
listener
(
UserStatus
.
Offline
)
}
}
}
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/presentation/MainPresenter.kt
View file @
35fe51af
package
chat.rocket.android.main.presentation
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.main.viewmodel.NavHeaderViewModel
import
chat.rocket.android.main.viewmodel.NavHeaderViewModelMapper
...
...
@@ -12,10 +11,14 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.server.presentation.CheckServerPresenter
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.extensions.registerPushToken
import
chat.rocket.android.util.extensions.serverLogoUrl
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatAuthException
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.realtime.UserStatus
import
chat.rocket.core.internal.realtime.setDefaultStatus
import
chat.rocket.core.internal.rest.logout
import
chat.rocket.core.internal.rest.me
import
chat.rocket.core.internal.rest.unregisterPushToken
...
...
@@ -52,9 +55,8 @@ class MainPresenter @Inject constructor(
checkServerInfo
()
launchUI
(
strategy
)
{
try
{
val
me
=
client
.
me
()
val
me
=
retryIO
(
"me"
)
{
client
.
me
()
}
val
model
=
navHeaderMapper
.
mapToViewModel
(
me
)
saveAccount
(
model
)
view
.
setupNavHeader
(
model
,
getAccountsInteractor
.
get
())
}
catch
(
ex
:
Exception
)
{
...
...
@@ -75,11 +77,17 @@ class MainPresenter @Inject constructor(
}
}
private
suspend
fun
saveAccount
(
me
:
NavHeaderViewModel
)
{
private
suspend
fun
saveAccount
(
viewModel
:
NavHeaderViewModel
)
{
val
icon
=
settings
.
favicon
()
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
currentServer
.
serverLogoUrl
(
it
)
}
val
account
=
Account
(
currentServer
,
icon
,
me
.
serverLogo
,
me
.
username
,
me
.
avatar
)
val
account
=
Account
(
currentServer
,
icon
,
viewModel
.
serverLogo
,
viewModel
.
userDisplayName
,
viewModel
.
userAvatar
)
saveAccountInteractor
.
save
(
account
)
}
...
...
@@ -90,7 +98,7 @@ class MainPresenter @Inject constructor(
launchUI
(
strategy
)
{
try
{
clearTokens
()
client
.
logout
()
retryIO
(
"logout"
)
{
client
.
logout
()
}
}
catch
(
exception
:
RocketChatException
)
{
Timber
.
d
(
exception
,
"Error calling logout"
)
exception
.
message
?.
let
{
...
...
@@ -117,7 +125,11 @@ class MainPresenter @Inject constructor(
serverInteractor
.
clear
()
val
pushToken
=
localRepository
.
get
(
LocalRepository
.
KEY_PUSH_TOKEN
)
if
(
pushToken
!=
null
)
{
client
.
unregisterPushToken
(
pushToken
)
try
{
retryIO
(
"unregisterPushToken"
)
{
client
.
unregisterPushToken
(
pushToken
)
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error unregistering push token"
)
}
}
localRepository
.
clearAllFromServer
(
currentServer
)
}
...
...
@@ -142,6 +154,21 @@ class MainPresenter @Inject constructor(
navigator
.
toServerScreen
()
}
fun
changeStatus
(
userStatus
:
UserStatus
)
{
launchUI
(
strategy
)
{
try
{
client
.
setDefaultStatus
(
userStatus
)
view
.
showUserStatus
(
userStatus
)
}
catch
(
ex
:
RocketChatException
)
{
ex
.
message
?.
let
{
view
.
showMessage
(
it
)
}.
ifNull
{
view
.
showGenericErrorMessage
()
}
}
}
}
suspend
fun
refreshToken
(
token
:
String
?)
{
token
?.
let
{
localRepository
.
save
(
LocalRepository
.
KEY_PUSH_TOKEN
,
token
)
...
...
app/src/main/java/chat/rocket/android/main/presentation/MainView.kt
View file @
35fe51af
...
...
@@ -4,8 +4,24 @@ import chat.rocket.android.authentication.server.presentation.VersionCheckView
import
chat.rocket.android.core.behaviours.MessageView
import
chat.rocket.android.main.viewmodel.NavHeaderViewModel
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.core.internal.realtime.UserStatus
interface
MainView
:
MessageView
,
VersionCheckView
{
fun
setupNavHeader
(
model
:
NavHeaderViewModel
,
accounts
:
List
<
Account
>)
/**
* Shows the current user status.
*
* @see [UserStatus]
*/
fun
showUserStatus
(
userStatus
:
UserStatus
)
/**
* Setups the navigation header.
*
* @param viewModel The [NavHeaderViewModel].
* @param accounts The list of accounts.
*/
fun
setupNavHeader
(
viewModel
:
NavHeaderViewModel
,
accounts
:
List
<
Account
>)
fun
closeServerSelection
()
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/ui/MainActivity.kt
View file @
35fe51af
...
...
@@ -11,7 +11,7 @@ import android.view.MenuItem
import
android.view.View
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.main.adapter.
Account
Selector
import
chat.rocket.android.main.adapter.Selector
import
chat.rocket.android.main.adapter.AccountsAdapter
import
chat.rocket.android.main.presentation.MainPresenter
import
chat.rocket.android.main.presentation.MainView
...
...
@@ -21,6 +21,7 @@ import chat.rocket.android.util.extensions.fadeIn
import
chat.rocket.android.util.extensions.fadeOut
import
chat.rocket.android.util.extensions.rotateBy
import
chat.rocket.android.util.extensions.showToast
import
chat.rocket.core.internal.realtime.UserStatus
import
com.google.android.gms.gcm.GoogleCloudMessaging
import
com.google.android.gms.iid.InstanceID
import
dagger.android.AndroidInjection
...
...
@@ -42,6 +43,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
@Inject
lateinit
var
presenter
:
MainPresenter
private
var
isFragmentAdded
:
Boolean
=
false
private
var
expanded
=
false
private
val
headerLayout
by
lazy
{
view_navigation
.
getHeaderView
(
0
)
}
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
AndroidInjection
.
inject
(
this
)
...
...
@@ -79,14 +81,32 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
}
}
override
fun
setupNavHeader
(
model
:
NavHeaderViewModel
,
accounts
:
List
<
Account
>)
{
Timber
.
d
(
"Setting up nav header: $model"
)
val
headerLayout
=
view_navigation
.
getHeaderView
(
0
)
headerLayout
.
text_name
.
text
=
model
.
username
headerLayout
.
text_server
.
text
=
model
.
server
headerLayout
.
image_avatar
.
setImageURI
(
model
.
avatar
)
headerLayout
.
server_logo
.
setImageURI
(
model
.
serverLogo
)
setupAccountsList
(
headerLayout
,
accounts
)
override
fun
showUserStatus
(
userStatus
:
UserStatus
)
{
headerLayout
.
apply
{
image_user_status
.
setImageDrawable
(
DrawableHelper
.
getUserStatusDrawable
(
userStatus
,
this
.
context
)
)
}
}
override
fun
setupNavHeader
(
viewModel
:
NavHeaderViewModel
,
accounts
:
List
<
Account
>)
{
Timber
.
d
(
"Setting up nav header: $viewModel"
)
with
(
headerLayout
)
{
image_user_status
.
setImageDrawable
(
DrawableHelper
.
getUserStatusDrawable
(
viewModel
.
userStatus
!!
,
this
.
context
)
)
text_user_name
.
text
=
viewModel
.
userDisplayName
text_server_url
.
text
=
viewModel
.
serverUrl
image_avatar
.
setImageURI
(
viewModel
.
userAvatar
)
server_logo
.
setImageURI
(
viewModel
.
serverLogo
)
setupAccountsList
(
headerLayout
,
accounts
)
}
}
override
fun
closeServerSelection
()
{
...
...
@@ -112,7 +132,11 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
private
fun
setupAccountsList
(
header
:
View
,
accounts
:
List
<
Account
>)
{
accounts_list
.
layoutManager
=
LinearLayoutManager
(
this
)
accounts_list
.
adapter
=
AccountsAdapter
(
accounts
,
object
:
AccountSelector
{
accounts_list
.
adapter
=
AccountsAdapter
(
accounts
,
object
:
Selector
{
override
fun
onStatusSelected
(
userStatus
:
UserStatus
)
{
presenter
.
changeStatus
(
userStatus
)
}
override
fun
onAccountSelected
(
serverUrl
:
String
)
{
presenter
.
changeServer
(
serverUrl
)
}
...
...
@@ -120,11 +144,10 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
override
fun
onAddedAccountSelected
()
{
presenter
.
addNewServer
()
}
})
header
.
account_container
.
setOnClickListener
{
header
.
account_expand
.
rotateBy
(
180f
)
header
.
image_
account_expand
.
rotateBy
(
180f
)
if
(
expanded
)
{
accounts_list
.
fadeOut
()
}
else
{
...
...
app/src/main/java/chat/rocket/android/main/viewmodel/NavHeaderViewModel.kt
View file @
35fe51af
package
chat.rocket.android.main.viewmodel
import
chat.rocket.common.model.UserStatus
data class
NavHeaderViewModel
(
val
username
:
String
,
val
server
:
String
,
val
avatar
:
String
?,
val
userDisplayName
:
String
,
val
userStatus
:
UserStatus
?,
val
userAvatar
:
String
?,
val
serverUrl
:
String
,
val
serverLogo
:
String
?
)
\ No newline at end of file
app/src/main/java/chat/rocket/android/main/viewmodel/NavHeaderViewModelMapper.kt
View file @
35fe51af
package
chat.rocket.android.main.viewmodel
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.server.domain.*
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.serverLogoUrl
import
chat.rocket.core.model.Myself
import
javax.inject.Inject
class
NavHeaderViewModelMapper
@Inject
constructor
(
serverInteractor
:
GetCurrentServerInteractor
,
getSettingsInteractor
:
GetSettingsInteractor
)
{
class
NavHeaderViewModelMapper
@Inject
constructor
(
serverInteractor
:
GetCurrentServerInteractor
,
getSettingsInteractor
:
GetSettingsInteractor
)
{
private
val
currentServer
=
serverInteractor
.
get
()
!!
private
var
settings
:
PublicSettings
=
getSettingsInteractor
.
get
(
currentServer
)
fun
mapToViewModel
(
me
:
Myself
):
NavHeaderViewModel
{
val
username
=
mapUsername
(
me
)
val
thumb
=
me
.
username
?.
let
{
UrlHelper
.
getAvatarUrl
(
currentServer
,
it
)
}
val
displayName
=
mapDisplayName
(
me
)
val
status
=
me
.
status
val
avatar
=
me
.
username
?.
let
{
currentServer
.
avatarUrl
(
it
)
}
val
image
=
settings
.
wideTile
()
?:
settings
.
faviconLarge
()
val
logo
=
image
?.
let
{
UrlHelper
.
getServerLogoUrl
(
currentServer
,
it
)
}
val
logo
=
image
?.
let
{
currentServer
.
serverLogoUrl
(
it
)
}
return
NavHeaderViewModel
(
username
,
currentServer
,
thumb
,
logo
)
return
NavHeaderViewModel
(
displayName
,
status
,
avatar
,
currentServer
,
logo
)
}
private
fun
map
Usern
ame
(
me
:
Myself
):
String
{
private
fun
map
DisplayN
ame
(
me
:
Myself
):
String
{
val
username
=
me
.
username
val
realName
=
me
.
name
val
senderName
=
if
(
settings
.
useRealName
())
realName
else
username
...
...
app/src/main/java/chat/rocket/android/members/presentation/MembersPresenter.kt
View file @
35fe51af
...
...
@@ -6,6 +6,7 @@ import chat.rocket.android.members.viewmodel.MemberViewModelMapper
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.model.roomTypeOf
import
chat.rocket.common.util.ifNull
...
...
@@ -26,7 +27,9 @@ class MembersPresenter @Inject constructor(private val view: MembersView,
try
{
view
.
showLoading
()
val
members
=
client
.
getMembers
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
60
)
val
members
=
retryIO
(
"getMembers($chatRoomId, $chatRoomType, $offset)"
)
{
client
.
getMembers
(
chatRoomId
,
roomTypeOf
(
chatRoomType
),
offset
,
60
)
}
val
memberViewModels
=
mapper
.
mapToViewModelList
(
members
.
result
)
view
.
showMembers
(
memberViewModels
,
members
.
total
)
}
catch
(
ex
:
RocketChatException
)
{
...
...
app/src/main/java/chat/rocket/android/members/viewmodel/MemberViewModel.kt
View file @
35fe51af
package
chat.rocket.android.members.viewmodel
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.server.domain.useRealName
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.common.model.User
import
chat.rocket.core.model.Value
...
...
@@ -25,7 +25,7 @@ class MemberViewModel(private val member: User, private val settings: Map<String
private
fun
getUserAvatar
():
String
?
{
val
username
=
member
.
username
?:
"?"
return
baseUrl
?.
let
{
UrlHelper
.
getAvatarUrl
(
baseUrl
,
username
,
"png"
)
baseUrl
.
avatarUrl
(
username
,
"png"
)
}
}
...
...
app/src/main/java/chat/rocket/android/profile/presentation/ProfilePresenter.kt
View file @
35fe51af
package
chat.rocket.android.profile.presentation
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.helper.UrlHelper
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.avatarUrl
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.common.util.ifNull
import
chat.rocket.core.RocketChatClient
...
...
@@ -25,9 +26,9 @@ class ProfilePresenter @Inject constructor(private val view: ProfileView,
launchUI
(
strategy
)
{
view
.
showLoading
()
try
{
val
myself
=
client
.
me
()
val
myself
=
retryIO
(
"me"
)
{
client
.
me
()
}
myselfId
=
myself
.
id
val
avatarUrl
=
UrlHelper
.
getAvatarUrl
(
serverUrl
,
myself
.
username
!!
)
val
avatarUrl
=
serverUrl
.
avatarUrl
(
myself
.
username
!!
)
view
.
showProfile
(
avatarUrl
,
myself
.
name
?:
""
,
...
...
@@ -51,9 +52,9 @@ class ProfilePresenter @Inject constructor(private val view: ProfileView,
view
.
showLoading
()
try
{
if
(
avatarUrl
!=
""
)
{
client
.
setAvatar
(
avatarUrl
)
retryIO
{
client
.
setAvatar
(
avatarUrl
)
}
}
val
user
=
client
.
updateProfile
(
myselfId
,
email
,
name
,
username
)
val
user
=
retryIO
{
client
.
updateProfile
(
myselfId
,
email
,
name
,
username
)
}
view
.
showProfileUpdateSuccessfullyMessage
()
loadUserProfile
()
}
catch
(
exception
:
RocketChatException
)
{
...
...
app/src/main/java/chat/rocket/android/push/FirebaseTokenService.kt
View file @
35fe51af
...
...
@@ -5,7 +5,6 @@ import chat.rocket.android.infrastructure.LocalRepository
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.registerPushToken
import
com.google.android.gms.gcm.GoogleCloudMessaging
import
com.google.android.gms.iid.InstanceID
...
...
app/src/main/java/chat/rocket/android/server/presentation/CheckServerPresenter.kt
View file @
35fe51af
...
...
@@ -5,6 +5,7 @@ import chat.rocket.android.authentication.server.presentation.VersionCheckView
import
chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.util.VersionInfo
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.serverInfo
import
timber.log.Timber
...
...
@@ -14,21 +15,25 @@ abstract class CheckServerPresenter constructor(private val strategy: CancelStra
private
val
view
:
VersionCheckView
)
{
internal
fun
checkServerInfo
()
{
launchUI
(
strategy
)
{
val
serverInfo
=
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)"
)
try
{
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)"
)
}
else
{
view
.
alertNotRecommendedVersion
()
}
}
else
{
view
.
alertNotRecommendedVersion
()
}
}
else
{
if
(!
isRecommendedVersion
)
{
view
.
blockAndAlertNotRequiredVersion
()
Timber
.
i
(
"Oops. Looks like your server is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!"
)
if
(!
isRecommendedVersion
)
{
view
.
blockAndAlertNotRequiredVersion
()
Timber
.
i
(
"Oops. Looks like your server is out-of-date! Minimum server version required ${BuildConfig.REQUIRED_SERVER_VERSION}!"
)
}
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error getting server info"
)
}
}
}
...
...
app/src/main/java/chat/rocket/android/settings/about/ui/AboutActivity.kt
0 → 100644
View file @
35fe51af
package
chat.rocket.android.settings.about.ui
import
android.support.v7.app.AppCompatActivity
import
android.os.Bundle
import
chat.rocket.android.BuildConfig
import
chat.rocket.android.R
import
chat.rocket.android.util.extensions.textContent
import
kotlinx.android.synthetic.main.about_view.*
import
kotlinx.android.synthetic.main.app_bar_password.*
class
AboutActivity
:
AppCompatActivity
()
{
override
fun
onCreate
(
savedInstanceState
:
Bundle
?)
{
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
activity_about
)
setupToolbar
()
setupViews
()
}
private
fun
setupViews
()
{
val
versionName
=
resources
.
getString
(
R
.
string
.
msg_version
)
+
" "
+
BuildConfig
.
VERSION_NAME
val
versionCode
=
resources
.
getString
(
R
.
string
.
msg_build
)+
" #"
+
BuildConfig
.
VERSION_CODE
text_version_name
.
text
=
versionName
text_build_number
.
text
=
versionCode
}
private
fun
setupToolbar
()
{
setSupportActionBar
(
toolbar
)
text_change_password
.
textContent
=
resources
.
getString
(
R
.
string
.
title_about
)
}
override
fun
onBackPressed
()
{
super
.
onBackPressed
()
finish
()
overridePendingTransition
(
R
.
anim
.
close_enter
,
R
.
anim
.
close_exit
)
}
override
fun
onSupportNavigateUp
():
Boolean
{
onBackPressed
()
return
super
.
onNavigateUp
()
}
}
app/src/main/java/chat/rocket/android/settings/password/presentation/PasswordPresenter.kt
View file @
35fe51af
...
...
@@ -4,6 +4,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import
chat.rocket.android.server.domain.GetCurrentServerInteractor
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.extensions.launchUI
import
chat.rocket.android.util.retryIO
import
chat.rocket.common.RocketChatException
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.me
...
...
@@ -22,7 +23,10 @@ class PasswordPresenter @Inject constructor (private val view: PasswordView,
try
{
view
.
showLoading
()
client
.
updateProfile
(
client
.
me
().
id
,
null
,
null
,
password
,
null
)
val
me
=
retryIO
(
"me"
)
{
client
.
me
()
}
retryIO
(
"updateProfile(${me.id})"
)
{
client
.
updateProfile
(
me
.
id
,
null
,
null
,
password
,
null
)
}
view
.
showPasswordSuccessfullyUpdatedMessage
()
view
.
hideLoading
()
...
...
app/src/main/java/chat/rocket/android/settings/ui/SettingsFragment.kt
View file @
35fe51af
...
...
@@ -10,6 +10,7 @@ import android.view.ViewGroup
import
android.widget.AdapterView
import
chat.rocket.android.R
import
chat.rocket.android.main.ui.MainActivity
import
chat.rocket.android.settings.about.ui.AboutActivity
import
chat.rocket.android.settings.password.ui.PasswordActivity
import
chat.rocket.android.settings.presentation.SettingsView
import
chat.rocket.android.util.extensions.inflate
...
...
@@ -33,8 +34,10 @@ class SettingsFragment: Fragment(), SettingsView, AdapterView.OnItemClickListene
override
fun
onItemClick
(
parent
:
AdapterView
<
*
>?,
view
:
View
?,
position
:
Int
,
id
:
Long
)
{
when
(
parent
?.
getItemAtPosition
(
position
).
toString
())
{
"Change Password"
->
{
resources
.
getString
(
R
.
string
.
title_password
)
->
{
startNewActivity
(
PasswordActivity
::
class
)
}
resources
.
getString
(
R
.
string
.
title_about
)
->
{
startNewActivity
(
AboutActivity
::
class
)
}
}
}
...
...
app/src/main/java/chat/rocket/android/util/IO.kt
0 → 100644
View file @
35fe51af
package
chat.rocket.android.util
import
chat.rocket.common.RocketChatNetworkErrorException
import
kotlinx.coroutines.experimental.delay
import
timber.log.Timber
const
val
DEFAULT_RETRY
=
3
suspend
fun
<
T
>
retryIO
(
description
:
String
=
"<missing description>"
,
times
:
Int
=
DEFAULT_RETRY
,
initialDelay
:
Long
=
100
,
// 0.1 second
maxDelay
:
Long
=
1000
,
// 1 second
factor
:
Double
=
2.0
,
block
:
suspend
()
->
T
):
T
{
var
currentDelay
=
initialDelay
repeat
(
times
-
1
)
{
currentTry
->
try
{
return
block
()
}
catch
(
e
:
RocketChatNetworkErrorException
)
{
Timber
.
d
(
e
,
"failed call($currentTry): $description"
)
e
.
printStackTrace
()
}
delay
(
currentDelay
)
currentDelay
=
(
currentDelay
*
factor
).
toLong
().
coerceAtMost
(
maxDelay
)
}
return
block
()
// last attempt
}
\ No newline at end of file
app/src/main/java/chat/rocket/android/util/extensions/RocketChatClient.kt
View file @
35fe51af
...
...
@@ -2,6 +2,7 @@ package chat.rocket.android.util.extensions
import
chat.rocket.android.server.domain.model.Account
import
chat.rocket.android.server.infraestructure.RocketChatClientFactory
import
chat.rocket.android.util.retryIO
import
chat.rocket.core.RocketChatClient
import
chat.rocket.core.internal.rest.registerPushToken
import
kotlinx.coroutines.experimental.CommonPool
...
...
@@ -16,7 +17,9 @@ suspend fun RocketChatClient.registerPushToken(
launch
(
CommonPool
)
{
accounts
.
forEach
{
account
->
try
{
factory
.
create
(
account
.
serverUrl
).
registerPushToken
(
token
)
retryIO
(
description
=
"register push token: ${account.serverUrl}"
)
{
factory
.
create
(
account
.
serverUrl
).
registerPushToken
(
token
)
}
}
catch
(
ex
:
Exception
)
{
Timber
.
d
(
ex
,
"Error registering Push token for ${account.serverUrl}"
)
ex
.
printStackTrace
()
...
...
app/src/main/java/chat/rocket/android/util/extensions/String.kt
0 → 100644
View file @
35fe51af
package
chat.rocket.android.util.extensions
import
android.util.Patterns
fun
String
.
removeTrailingSlash
():
String
{
return
if
(
isNotEmpty
()
&&
this
[
length
-
1
]
==
'/'
)
{
this
.
replace
(
"/+$"
,
""
)
}
else
{
this
}
}
fun
String
.
avatarUrl
(
avatar
:
String
,
format
:
String
=
"jpeg"
)
=
"${removeTrailingSlash()}/avatar/${avatar.removeTrailingSlash()}?format=$format"
fun
String
.
serverLogoUrl
(
favicon
:
String
)
=
"${removeTrailingSlash()}/$favicon"
fun
String
.
casUrl
(
serverUrl
:
String
,
token
:
String
)
=
"${removeTrailingSlash()}?service=${serverUrl.removeTrailingSlash()}/_cas/$token"
fun
String
.
termsOfServiceUrl
()
=
"${removeTrailingSlash()}/terms-of-service"
fun
String
.
privacyPolicyUrl
()
=
"${removeTrailingSlash()}/privacy-policy"
fun
String
.
isValidUrl
():
Boolean
=
Patterns
.
WEB_URL
.
matcher
(
this
).
matches
()
\ No newline at end of file
app/src/main/java/chat/rocket/android/util/extensions/Uri.kt
View file @
35fe51af
...
...
@@ -29,14 +29,14 @@ fun Uri.getFileName(context: Context): String? {
fun
Uri
.
getFileSize
(
context
:
Context
):
Int
{
val
cursor
=
context
.
contentResolver
.
query
(
this
,
null
,
null
,
null
,
null
,
null
)
var
fileSize
:
String
?
=
null
cursor
.
use
{
cursor
->
val
fileSize
=
cursor
?.
use
{
val
sizeIndex
=
cursor
.
getColumnIndex
(
OpenableColumns
.
SIZE
)
if
(
cursor
!=
null
&&
cursor
.
moveToFirst
())
{
if
(
cursor
.
moveToFirst
())
{
if
(!
cursor
.
isNull
(
sizeIndex
))
{
fileSize
=
cursor
.
getString
(
sizeIndex
)
return
@use
cursor
.
getString
(
sizeIndex
)
}
}
return
@use
null
}
return
fileSize
?.
toIntOrNull
()
?:
-
1
}
...
...
app/src/main/res/drawable/black_gradient.xml
View file @
35fe51af
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android=
"http://schemas.android.com/apk/res/android"
<shape
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:shape=
"rectangle"
>
<gradient
android:angle=
"90"
android:endColor=
"#00000000"
android:centerColor=
"#30000000"
android:endColor=
"#00000000"
android:startColor=
"#C0000000"
android:type=
"linear"
/>
</shape>
\ No newline at end of file
app/src/main/res/drawable/ic_app_name.xml
0 → 100644
View file @
35fe51af
<?xml version="1.0" encoding="utf-8"?>
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"832.000000dp"
android:height=
"220.000000dp"
android:viewportWidth=
"832.000000"
android:viewportHeight=
"220.000000"
>
<group
android:translateY=
"220.000000"
android:scaleX=
"0.100000"
android:scaleY=
"-0.100000"
>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M65 1778 c-3 -7 -4 -308 -3 -668 l3 -655 104 -3 c67 -2 108 1 117 9 11 9 14 54 14 220 l0 209 49 0 49 0 16 -52 c8 -29 28 -107 45 -173 17 -66 36 -140 43 -165 l14 -45 111 -3 c129 -3 129 -3 106 85 -8 32 -21 83 -28 113 -7 30 -21 82 -30 115 -41 151 -41 145 -6 172 17 14 42 44 54 66 21 41 22 51 22 342 l0 300 -25 45 c-18 32 -39 51 -79 72 l-53 28 -259 0 c-199 0 -261 -3 -264 -12z m435 -238 c5 -8 10 -97 10 -197 0 -152 -3 -184 -16 -197 -12 -12 -37 -16 -105 -16 l-89 0 0 216 0 216 95 -4 c71 -2 98 -7 105 -18z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M1006 1774 c-48 -17 -70 -36 -105 -89 l-26 -40 0 -521 0 -521 30 -49 c22 -36 44 -56 80 -74 48 -24 58 -25 225 -25 169 0 177 1 225 26 35 18 59 39 80 74 l30 48 3 501 c2 448 1 506 -14 546 -22 60 -67 106 -122 125 -62 21 -349 20 -406 -1z m299 -230 c14 -14 15 -61 13 -430 -3 -356 -5 -416 -18 -424 -26 -17 -156 -12 -174 6 -14 13 -16 66 -16 428 0 307 3 415 12 424 19 19 163 16 183 -4z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M1835 1774 c-45 -17 -77 -44 -108 -94 -22 -35 -22 -38 -22 -555 0 -476 1 -523 17 -552 55 -100 114 -123 318 -123 166 0 229 15 276 65 49 53 58 83 62 217 2 70 1 139 -2 153 l-7 26 -107 -3 -107 -3 -6 -90 c-8 -128 -5 -125 -105 -125 l-83 0 -11 38 c-8 25 -10 161 -8 420 3 443 -4 412 104 412 91 0 101 -15 107 -160 l2 -65 99 -3 c64 -2 103 1 112 9 18 14 20 212 3 290 -14 66 -63 122 -126 143 -63 22 -349 21 -408 0z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M2542 1778 c-17 -17 -17 -1299 0 -1316 8 -8 48 -12 114 -12 84 0 103 3 108 16 3 9 6 100 6 202 1 184 1 188 28 240 l28 53 13 -38 c12 -33 38 -95 71 -168 5 -11 28 -65 50 -120 23 -55 51 -119 62 -142 l21 -43 112 0 c140 0 145 4 109 86 -55 125 -67 151 -94 209 -40 86 -70 153 -70 159 0 3 -25 58 -56 123 -30 65 -56 125 -57 134 0 9 26 72 60 140 220 449 217 443 214 477 -1 9 -31 12 -114 12 -98 0 -116 -3 -130 -18 -10 -10 -17 -21 -17 -25 0 -3 -52 -111 -115 -239 l-114 -233 -1 242 c0 133 -3 248 -6 257 -5 13 -24 16 -108 16 -66 0 -106 -4 -114 -12z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M3395 1778 c-3 -7 -4 -308 -3 -668 l3 -655 325 -3 c297 -2 326 -1 338 15 19 26 16 187 -4 207 -13 14 -48 16 -225 16 l-209 0 0 160 0 160 168 2 167 3 0 110 0 110 -167 3 -168 2 0 160 0 160 219 0 c190 0 220 2 225 16 11 29 7 189 -6 202 -18 18 -657 17 -663 0z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M4184 1777 c-2 -7 -3 -58 -2 -113 l3 -99 107 -3 108 -3 2 -552 3 -552 115 0 115 0 3 552 2 552 108 3 107 3 3 90 c2 50 0 100 -3 113 l-5 22 -331 0 c-264 0 -331 -3 -335 -13z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M5345 1774 c-50 -18 -101 -67 -117 -113 -10 -27 -13 -157 -13 -531 0 -272 3 -511 7 -530 11 -51 67 -108 127 -131 42 -16 77 -19 200 -19 208 0 268 24 316 125 24 52 25 62 23 192 l-3 138 -104 3 c-66 2 -108 -1 -117 -9 -9 -7 -14 -41 -16 -107 l-3 -97 -88 -3 c-86 -3 -87 -2 -97 23 -6 16 -10 183 -10 416 0 454 -6 429 101 429 94 0 99 -5 99 -106 0 -123 1 -124 118 -124 63 0 102 4 110 12 19 19 16 252 -5 308 -22 60 -66 106 -121 125 -62 21 -349 20 -407 -1z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M6047 1784 c-9 -9 -9 -1296 -1 -1318 9 -24 219 -24 228 0 3 9 6 135 6 280 l0 264 100 0 100 0 0 -264 c0 -145 3 -271 6 -280 9 -24 219 -24 228 0 8 20 8 1288 0 1308 -9 24 -219 24 -228 0 -3 -9 -6 -132 -6 -275 l0 -259 -100 0 -100 0 -2 273 -3 272 -111 3 c-60 1 -113 -1 -117 -4z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M7099 1763 c-6 -16 -26 -102 -45 -193 -18 -91 -41 -196 -50 -235 -20 -91 -34 -152 -79 -365 -20 -96 -46 -215 -56 -265 -45 -208 -49 -231 -44 -242 3 -9 35 -13 114 -13 94 0 110 2 116 17 6 18 32 146 42 210 l5 32 144 3 c79 2 144 3 144 3 0 0 9 -50 19 -112 28 -161 20 -153 152 -153 l111 0 -5 47 c-3 27 -12 82 -22 123 -9 41 -23 107 -31 145 -23 114 -69 329 -104 480 -11 50 -27 124 -35 165 -8 41 -21 104 -29 140 -8 36 -23 103 -33 150 l-18 85 -143 3 -142 3 -11 -28z m176 -463 c35 -182 58 -307 62 -342 l5 -38 -97 0 -97 0 6 28 c6 27 71 390 84 467 l6 40 7 -35 c4 -19 14 -73 24 -120z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M7645 1768 c-3 -13 -5 -63 -3 -113 l3 -90 108 -3 107 -3 0 -539 c0 -296 3 -545 6 -554 9 -24 219 -24 228 0 3 9 6 258 6 554 l0 539 108 3 107 3 0 110 0 110 -332 3 -333 2 -5 -22z"
/>
<path
android:fillColor=
"#04436A"
android:strokeWidth=
"1"
android:pathData=
"M4842 674 c-20 -14 -22 -23 -22 -102 1 -119 3 -122 122 -122 60 0 98 4 106 12 8 8 12 47 12 110 0 86 -2 98 -19 108 -32 16 -173 13 -199 -6z"
/>
</group>
</vector>
\ No newline at end of file
app/src/main/res/drawable/ic_status_away_24dp.xml
0 → 100644
View file @
35fe51af
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportHeight=
"24"
android:viewportWidth=
"24"
>
<path
android:fillColor=
"#FFFFD100"
android:fillType=
"evenOdd"
android:pathData=
"M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeColor=
"#00000000"
android:strokeWidth=
"1"
/>
<path
android:fillColor=
"#00000000"
android:fillType=
"evenOdd"
android:pathData=
"M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:strokeColor=
"#FFFFFFFF"
android:strokeWidth=
"2"
/>
</vector>
app/src/main/res/drawable/ic_status_busy_24dp.xml
0 → 100644
View file @
35fe51af
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportHeight=
"24"
android:viewportWidth=
"24"
>
<path
android:fillColor=
"#FFFF2A57"
android:fillType=
"evenOdd"
android:pathData=
"M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeColor=
"#00000000"
android:strokeWidth=
"1"
/>
<path
android:fillColor=
"#00000000"
android:fillType=
"evenOdd"
android:pathData=
"M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:strokeColor=
"#FFFFFFFF"
android:strokeWidth=
"2"
/>
</vector>
app/src/main/res/drawable/ic_status_invisible_24dp.xml
0 → 100644
View file @
35fe51af
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportHeight=
"24"
android:viewportWidth=
"24"
>
<path
android:fillColor=
"#FFCBCED1"
android:fillType=
"evenOdd"
android:pathData=
"M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeColor=
"#00000000"
android:strokeWidth=
"1"
/>
<path
android:fillColor=
"#00000000"
android:fillType=
"evenOdd"
android:pathData=
"M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:strokeColor=
"#FFFFFFFF"
android:strokeWidth=
"2"
/>
</vector>
app/src/main/res/drawable/ic_status_online_24dp.xml
0 → 100644
View file @
35fe51af
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:width=
"24dp"
android:height=
"24dp"
android:viewportHeight=
"24"
android:viewportWidth=
"24"
>
<path
android:fillColor=
"#FF2DE0A5"
android:fillType=
"evenOdd"
android:pathData=
"M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeColor=
"#00000000"
android:strokeWidth=
"1"
/>
<path
android:fillColor=
"#00000000"
android:fillType=
"evenOdd"
android:pathData=
"M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:strokeColor=
"#FFFFFFFF"
android:strokeWidth=
"2"
/>
</vector>
app/src/main/res/layout/about_view.xml
0 → 100644
View file @
35fe51af
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
>
<ImageView
android:id=
"@+id/image_app_name"
android:layout_width=
"wrap_content"
android:layout_height=
"60dp"
android:src=
"@drawable/ic_app_name"
app:layout_constraintTop_toTopOf=
"parent"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
/>
<ImageView
android:layout_width=
"160dp"
android:layout_height=
"160dp"
android:src=
"@drawable/ic_launcher_foreground"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintBottom_toTopOf=
"@id/image_app_name"
android:adjustViewBounds=
"true"
android:scaleX=
"1.5"
android:scaleY=
"1.5"
/>
<TextView
android:id=
"@+id/text_version_name"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
tools:text=
"Version alpha2.0.1"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/image_app_name"
android:layout_marginTop=
"16dp"
android:textColor=
"@color/colorSecondaryText"
/>
<TextView
android:id=
"@+id/text_build_number"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
tools:text=
"Build # 2000"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/text_version_name"
android:layout_marginTop=
"8dp"
android:textColor=
"@color/colorSecondaryText"
/>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/layout/activity_about.xml
0 → 100644
View file @
35fe51af
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:orientation=
"vertical"
android:theme=
"@style/AppTheme"
tools:context=
"chat.rocket.android.settings.about.ui.AboutActivity"
>
<include
android:id=
"@+id/layout_app_bar"
layout=
"@layout/app_bar_password"
/>
<include
layout=
"@layout/about_view"
/>
</LinearLayout>
\ No newline at end of file
app/src/main/res/layout/activity_main.xml
View file @
35fe51af
...
...
@@ -28,21 +28,23 @@
android:layout_width=
"wrap_content"
android:layout_height=
"match_parent"
android:layout_gravity=
"start"
>
<android.support.design.widget.NavigationView
android:id=
"@+id/view_navigation"
android:layout_width=
"wrap_content"
android:layout_height=
"match_parent"
app:menu=
"@menu/navigation"
app:headerLayout=
"@layout/nav_header"
/>
app:headerLayout=
"@layout/nav_header"
app:menu=
"@menu/navigation"
/>
<android.support.v7.widget.RecyclerView
android:id=
"@+id/accounts_list"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:layout_marginTop=
"@dimen/nav_header_height"
android:elevation=
"20dp"
android:background=
"@color/white"
android:alpha=
"0"
android:visibility=
"gone"
/>
android:background=
"@color/white"
android:elevation=
"20dp"
android:visibility=
"gone"
/>
</FrameLayout>
</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
app/src/main/res/layout/item_account.xml
View file @
35fe51af
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
<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:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"?selectableItemBackground"
>
android:paddingEnd=
"16dp"
android:paddingStart=
"16dp"
android:paddingTop=
"16dp"
android:background=
"?selectableItemBackground"
>
<com.facebook.drawee.view.SimpleDraweeView
android:id=
"@+id/server_logo"
android:layout_width=
"40dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"8dp"
android:layout_marginStart=
"16dp"
android:layout_marginBottom=
"8dp"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
app:actualImageScaleType=
"centerInside"
app:layout_constraintBottom_toBottomOf=
"parent"
app:actualImageScaleType=
"centerInside"
/>
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
/>
<TextView
android:id=
"@+id/text_server_url"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:layout_marginEnd=
"16dp"
android:ellipsize=
"end"
android:maxLines=
"1"
android:textStyle=
"bold"
app:layout_constraintTop_toTopOf=
"@id/server_logo"
app:layout_constraintStart_toEndOf=
"@id/server_logo"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toEndOf=
"@id/server_logo"
app:layout_constraintTop_toTopOf=
"@id/server_logo"
tools:text=
"https://open.rocket.chat"
/>
<TextView
...
...
@@ -36,10 +36,11 @@
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:layout_marginEnd=
"16dp"
android:ellipsize=
"end"
android:maxLines=
"1"
app:layout_constraintBottom_toBottomOf=
"@id/server_logo"
app:layout_constraintStart_toEndOf=
"@id/server_logo"
app:layout_constraintEnd_toEndOf=
"parent"
tools:text=
"Lucio Maciel"
/>
app:layout_constraintStart_toEndOf=
"@id/server_logo"
tools:text=
"Lucio Maciel"
/>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/layout/item_add_account.xml
View file @
35fe51af
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
<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:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:background=
"?selectableItemBackground"
>
android:padding=
"16dp"
android:background=
"?selectableItemBackground"
>
<ImageView
android:id=
"@+id/server_logo"
android:layout_width=
"40dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"8dp"
android:layout_marginStart=
"16dp"
android:layout_marginBottom=
"8dp"
android:src=
"@drawable/ic_add_24dp"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
...
...
@@ -23,8 +19,7 @@
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"8dp"
android:layout_marginEnd=
"16dp"
android:textAppearance=
"@style/TextAppearance.AppCompat.Medium"
android:textAppearance=
"@style/TextAppearance.AppCompat.Body2"
android:text=
"@string/action_add_account"
app:layout_constraintTop_toTopOf=
"parent"
app:layout_constraintBottom_toBottomOf=
"parent"
...
...
app/src/main/res/layout/item_change_status.xml
0 → 100644
View file @
35fe51af
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:divider=
"?android:dividerHorizontal"
android:orientation=
"vertical"
android:showDividers=
"end"
>
<TextView
android:id=
"@+id/text_online"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"10dp"
android:layout_marginEnd=
"16dp"
android:layout_marginStart=
"16dp"
android:layout_marginTop=
"16dp"
android:drawablePadding=
"10dp"
android:drawableStart=
"@drawable/ic_status_online_24dp"
android:text=
"@string/action_online"
/>
<TextView
android:id=
"@+id/text_away"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"10dp"
android:layout_marginEnd=
"16dp"
android:layout_marginStart=
"16dp"
android:drawablePadding=
"10dp"
android:drawableStart=
"@drawable/ic_status_away_24dp"
android:text=
"@string/action_away"
/>
<TextView
android:id=
"@+id/text_busy"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"10dp"
android:layout_marginEnd=
"16dp"
android:layout_marginStart=
"16dp"
android:drawablePadding=
"10dp"
android:drawableStart=
"@drawable/ic_status_busy_24dp"
android:text=
"@string/action_busy"
/>
<TextView
android:id=
"@+id/text_invisible"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"16dp"
android:layout_marginEnd=
"16dp"
android:layout_marginStart=
"16dp"
android:drawablePadding=
"10dp"
android:drawableStart=
"@drawable/ic_status_invisible_24dp"
android:text=
"@string/action_invisible"
/>
</LinearLayout>
\ No newline at end of file
app/src/main/res/layout/nav_header.xml
View file @
35fe51af
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
<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:layout_width=
"match_parent"
...
...
@@ -11,11 +10,11 @@
android:layout_width=
"0dp"
android:layout_height=
"0dp"
android:foreground=
"@drawable/black_gradient"
app:actualImageScaleType=
"centerCrop"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
app:actualImageScaleType=
"centerCrop"
tools:src=
"@tools:sample/backgrounds/scenic"
/>
<com.facebook.drawee.view.SimpleDraweeView
...
...
@@ -33,50 +32,57 @@
android:id=
"@+id/account_container"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"8dp"
android:layout_marginStart=
"12dp"
android:layout_marginEnd=
"12dp"
android:layout_marginTop=
"16dp"
android:padding=
"4dp"
android:elevation=
"2dp"
android:background=
"?selectableItemBackground"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintStart_toStartOf=
"@+id/image_avatar"
android:elevation=
"2dp"
android:paddingBottom=
"4dp"
android:paddingEnd=
"12dp"
android:paddingStart=
"12dp"
android:paddingTop=
"4dp"
app:layout_constraintTop_toBottomOf=
"@+id/image_avatar"
>
<ImageView
android:id=
"@+id/image_user_status"
android:layout_width=
"14dp"
android:layout_height=
"14dp"
app:layout_constraintStart_toStartOf=
"parent"
/>
<TextView
android:id=
"@+id/text_name"
android:id=
"@+id/text_user_name"
style=
"@style/Sender.Name.TextView"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"
8
dp"
android:
textAppearance=
"@style/TextAppearance.AppCompat.Medium
"
android:layout_marginEnd=
"
10
dp"
android:
layout_marginStart=
"10dp
"
android:textColor=
"@color/white"
app:layout_constraintEnd_toStartOf=
"@+id/account_expand"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintBottom_toBottomOf=
"@+id/image_user_status"
app:layout_constraintEnd_toStartOf=
"@+id/image_account_expand"
app:layout_constraintStart_toEndOf=
"@+id/image_user_status"
app:layout_constraintTop_toTopOf=
"@+id/image_user_status"
tools:text=
"Lucio Maciel"
/>
<TextView
android:id=
"@+id/text_server"
android:id=
"@+id/text_server
_url
"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"8dp"
android:layout_marginEnd=
"10dp"
android:ellipsize=
"end"
android:maxLines=
"1"
android:textAppearance=
"@style/TextAppearance.AppCompat.Small"
android:textColor=
"@color/white"
app:layout_constraintEnd_toStartOf=
"@+id/account_expand"
app:layout_constraintEnd_toStartOf=
"@+id/
image_
account_expand"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/text_name"
app:layout_constraintTop_toBottomOf=
"@+id/text_
user_
name"
tools:text=
"https://open.rocket.chat"
/>
<ImageView
android:id=
"@+id/account_expand"
android:id=
"@+id/
image_
account_expand"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginEnd=
"8dp"
android:src=
"@drawable/ic_expand_more_24dp"
android:tint=
"@color/whitesmoke"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintEnd_toEndOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
/>
android:tint=
"@color/white"
app:layout_constraintBottom_toBottomOf=
"@+id/text_server_url"
app:layout_constraintEnd_toEndOf=
"parent"
/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/values-hi-rIN/strings.xml
View file @
35fe51af
...
...
@@ -13,6 +13,7 @@
<string
name=
"title_settings"
>
सेटिंग्स
</string>
<string
name=
"title_password"
>
पासवर्ड बदलें
</string>
<string
name=
"title_update_profile"
>
प्रोफ़ाइल अपडेट करें
</string>
<string
name=
"title_about"
>
परिचय
</string>
<!-- Actions -->
<string
name=
"action_connect"
>
जुडिये
</string>
...
...
@@ -28,10 +29,15 @@
<string
name=
"action_confirm_password"
>
पासवर्ड परिवर्तन की पुष्टि करें
</string>
<string
name=
"action_join_chat"
>
चैट में शामिल हों
</string>
<string
name=
"action_add_account"
>
खाता जोड़ो
</string>
<string
name=
"action_online"
>
ऑनलाइन
</string>
<string
name=
"action_away"
>
दूर
</string>
<string
name=
"action_busy"
>
व्यस्त
</string>
<string
name=
"action_invisible"
>
अदृश्य
</string>
<!-- Settings List -->
<string-array
name=
"settings_actions"
>
<item
name=
"item_password"
>
पासवर्ड बदलें
</item>
<item
name=
"item_password"
>
परिचय
</item>
</string-array>
<!-- Regular information messages -->
...
...
@@ -82,6 +88,8 @@
<string
name=
"msg_ver_not_minimum"
>
ऐसा लगता है कि आपका सर्वर संस्करण न्यूनतम आवश्यक संस्करण %1$s से कम है।\nकृपया लॉगिन करने के लिए अपने सर्वर को अपग्रेड करें!
</string>
<string
name=
"msg_version"
>
वर्शन
</string>
<string
name=
"msg_build"
>
बिल्ड
</string>
<!-- System messages -->
<string
name=
"message_room_name_changed"
>
%2$s ने रूम का नाम बदलकर %1$s किया
</string>
...
...
app/src/main/res/values-pt-rBR/strings.xml
View file @
35fe51af
...
...
@@ -13,6 +13,7 @@
<string
name=
"title_settings"
>
Configurações
</string>
<string
name=
"title_password"
>
Alterar senha
</string>
<string
name=
"title_update_profile"
>
Editar perfil
</string>
<string
name=
"title_about"
>
Sobre
</string>
<!-- Actions -->
<string
name=
"action_connect"
>
Conectar
</string>
...
...
@@ -27,11 +28,16 @@
<string
name=
"action_files"
>
Arquivos
</string>
<string
name=
"action_confirm_password"
>
Confirme a nova senha
</string>
<string
name=
"action_join_chat"
>
Entrar no Chat
</string>
<string
name=
"action_add_account"
>
Adicionar Conta
</string>
<string
name=
"action_add_account"
>
Adicionar conta
</string>
<string
name=
"action_online"
>
Online
</string>
<string
name=
"action_away"
>
Ausente
</string>
<string
name=
"action_busy"
>
Ocupado
</string>
<string
name=
"action_invisible"
>
Invisível
</string>
<!-- Settings List -->
<string-array
name=
"settings_actions"
>
<item
name=
"item_password"
>
Alterar senha
</item>
<item
name=
"item_password"
>
Sobre
</item>
</string-array>
<!-- Regular information messages -->
...
...
@@ -50,7 +56,7 @@
<string
name=
"msg_new_user_agreement"
>
Ao proceder você concorda com nossos %1$s e %2$s
</string>
<string
name=
"msg_2fa_code"
>
Código 2FA
</string>
<string
name=
"msg_yesterday"
>
ontem
</string>
<string
name=
"msg_message"
>
Me
s
sagem
</string>
<string
name=
"msg_message"
>
Me
n
sagem
</string>
<string
name=
"msg_this_room_is_read_only"
>
Este chat é apenas de leitura
</string>
<string
name=
"msg_invalid_2fa_code"
>
Código 2FA inválido
</string>
<string
name=
"msg_invalid_file"
>
Arquivo inválido
</string>
...
...
@@ -75,6 +81,8 @@
<string
name=
"msg_preview_audio"
>
Audio
</string>
<string
name=
"msg_preview_photo"
>
Foto
</string>
<string
name=
"msg_no_messages_yet"
>
Nenhuma mensagem ainda
</string>
<string
name=
"msg_version"
>
Versão
</string>
<string
name=
"msg_build"
>
Build
</string>
<string
name=
"msg_ok"
>
OK
</string>
<string
name=
"msg_ver_not_recommended"
>
Parece que a versão do seu servidor está abaixo da recomendada %1$s.\nVocê ainda assim pode logar e continuar mas podem ocorrer alguns problemas inesperados.
...
...
app/src/main/res/values/dimens.xml
View file @
35fe51af
...
...
@@ -21,6 +21,8 @@
<dimen
name=
"message_time_text_size"
>
12sp
</dimen>
<dimen
name=
"nav_header_height"
>
140dp
</dimen>
<!-- Emoji -->
<dimen
name=
"picker_padding_bottom"
>
16dp
</dimen>
<dimen
name=
"supposed_keyboard_height"
>
252dp
</dimen>
...
...
@@ -35,6 +37,5 @@
<!-- Autocomplete Popup -->
<dimen
name=
"popup_max_height"
>
150dp
</dimen>
<dimen
name=
"suggestions_box_max_height"
>
250dp
</dimen>
<dimen
name=
"nav_header_height"
>
160dp
</dimen>
</resources>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
35fe51af
...
...
@@ -14,6 +14,7 @@
<string
name=
"title_settings"
>
Settings
</string>
<string
name=
"title_password"
>
Change Password
</string>
<string
name=
"title_update_profile"
>
Update profile
</string>
<string
name=
"title_about"
>
About
</string>
<!-- Actions -->
<string
name=
"action_connect"
>
Connect
</string>
...
...
@@ -28,11 +29,16 @@
<string
name=
"action_files"
>
Files
</string>
<string
name=
"action_confirm_password"
>
Confirm Password Change
</string>
<string
name=
"action_join_chat"
>
Join Chat
</string>
<string
name=
"action_add_account"
>
Add Account
</string>
<string
name=
"action_add_account"
>
Add account
</string>
<string
name=
"action_online"
>
Online
</string>
<string
name=
"action_away"
>
Away
</string>
<string
name=
"action_busy"
>
Busy
</string>
<string
name=
"action_invisible"
>
Invisible
</string>
<!-- Settings List -->
<string-array
name=
"settings_actions"
>
<item
name=
"item_password"
>
Change Password
</item>
<item
name=
"item_password"
>
About
</item>
</string-array>
<!-- Regular information messages -->
...
...
@@ -77,6 +83,8 @@
<string
name=
"msg_preview_audio"
>
Audio
</string>
<string
name=
"msg_preview_photo"
>
Photo
</string>
<string
name=
"msg_no_messages_yet"
>
No messages yet
</string>
<string
name=
"msg_version"
>
Version
</string>
<string
name=
"msg_build"
>
Build
</string>
<string
name=
"msg_ok"
>
OK
</string>
<string
name=
"msg_ver_not_recommended"
>
Looks like your server version is below the recommended version %1$s.\nYou can still login but you may experience unexpected behaviors.
</string>
...
...
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