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
3e7984fd
Unverified
Commit
3e7984fd
authored
Apr 06, 2018
by
Rafael Kellermann Streit
Committed by
GitHub
Apr 06, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'develop-2.x' into new/direct-reply
parents
08174a78
18e1cf9e
Changes
42
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
42 changed files
with
630 additions
and
390 deletions
+630
-390
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
+12
-10
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
+74
-41
ChatRoomFragment.kt
.../java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
+74
-60
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
MainPresenter.kt
...va/chat/rocket/android/main/presentation/MainPresenter.kt
+18
-8
MainView.kt
...in/java/chat/rocket/android/main/presentation/MainView.kt
+2
-2
MainActivity.kt
...src/main/java/chat/rocket/android/main/ui/MainActivity.kt
+12
-6
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
ic_app_name.xml
app/src/main/res/drawable/ic_app_name.xml
+57
-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
item_chat.xml
app/src/main/res/layout/item_chat.xml
+35
-54
nav_header.xml
app/src/main/res/layout/nav_header.xml
+0
-1
strings.xml
app/src/main/res/values-hi-rIN/strings.xml
+4
-0
strings.xml
app/src/main/res/values-pt-rBR/strings.xml
+4
-0
strings.xml
app/src/main/res/values/strings.xml
+4
-0
No files found.
app/build.gradle
View file @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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"
/>
...
...
@@ -101,7 +92,6 @@
<action
android:name=
"com.google.firebase.INSTANCE_ID_EVENT"
/>
</intent-filter>
</service>
<service
android:name=
".push.GcmListenerService"
android:exported=
"false"
>
...
...
@@ -113,6 +103,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 @
3e7984fd
...
...
@@ -106,19 +106,21 @@ 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
)
}
return
userStatusDrawable
}
// TODO Why we need to UserStatus?
// TODO Why we need t
w
o UserStatus?
/**
* Returns the user status drawable.
...
...
app/src/main/java/chat/rocket/android/app/RocketChatApplication.kt
View file @
3e7984fd
...
...
@@ -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 @
3e7984fd
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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
This diff is collapsed.
Click to expand it.
app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
View file @
3e7984fd
...
...
@@ -37,6 +37,7 @@ import kotlinx.android.synthetic.main.message_composer.*
import
kotlinx.android.synthetic.main.message_list.*
import
java.util.concurrent.atomic.AtomicInteger
import
javax.inject.Inject
import
kotlin.math.absoluteValue
fun
newInstance
(
chatRoomId
:
String
,
chatRoomName
:
String
,
...
...
@@ -132,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
()
...
...
@@ -200,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
(
Math
.
abs
(
y
)
>
0
)
{
// if y is positive the keyboard is up else it's down
recycler_view
.
post
{
if
(
y
>
0
||
Math
.
abs
(
verticalScrollOffset
.
get
())
>=
Math
.
abs
(
y
))
{
recycler_view
.
scrollBy
(
0
,
y
)
}
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
...
...
@@ -264,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
(
"/"
))
{
...
...
@@ -462,17 +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
)
{
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
()
{
...
...
app/src/main/java/chat/rocket/android/chatroom/viewmodel/ViewModelMapper.kt
View file @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
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 @
08174a78
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/presentation/MainPresenter.kt
View file @
3e7984fd
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,6 +11,8 @@ 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
...
...
@@ -54,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
)
{
...
...
@@ -77,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
)
}
...
...
@@ -92,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
{
...
...
@@ -119,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
)
}
...
...
app/src/main/java/chat/rocket/android/main/presentation/MainView.kt
View file @
3e7984fd
...
...
@@ -18,10 +18,10 @@ interface MainView : MessageView, VersionCheckView {
/**
* Setups the navigation header.
*
* @param
m
odel The [NavHeaderViewModel].
* @param
viewM
odel The [NavHeaderViewModel].
* @param accounts The list of accounts.
*/
fun
setupNavHeader
(
m
odel
:
NavHeaderViewModel
,
accounts
:
List
<
Account
>)
fun
setupNavHeader
(
viewM
odel
:
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 @
3e7984fd
...
...
@@ -92,13 +92,19 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
}
}
override
fun
setupNavHeader
(
m
odel
:
NavHeaderViewModel
,
accounts
:
List
<
Account
>)
{
Timber
.
d
(
"Setting up nav header: $
m
odel"
)
override
fun
setupNavHeader
(
viewM
odel
:
NavHeaderViewModel
,
accounts
:
List
<
Account
>)
{
Timber
.
d
(
"Setting up nav header: $
viewM
odel"
)
with
(
headerLayout
)
{
text_user_name
.
text
=
model
.
username
text_server_url
.
text
=
model
.
server
image_avatar
.
setImageURI
(
model
.
avatar
)
server_logo
.
setImageURI
(
model
.
serverLogo
)
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
)
}
}
...
...
app/src/main/java/chat/rocket/android/main/viewmodel/NavHeaderViewModel.kt
View file @
3e7984fd
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 @
3e7984fd
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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
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 @
3e7984fd
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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
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 @
3e7984fd
...
...
@@ -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 @
3e7984fd
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 @
3e7984fd
...
...
@@ -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/ic_app_name.xml
0 → 100644
View file @
3e7984fd
<?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/layout/about_view.xml
0 → 100644
View file @
3e7984fd
<?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 @
3e7984fd
<?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/item_chat.xml
View file @
3e7984fd
...
...
@@ -16,70 +16,51 @@
android:layout_width=
"40dp"
android:layout_height=
"40dp"
android:layout_marginTop=
"6dp"
app:layout_constraint
Left_toLef
tOf=
"parent"
app:layout_constraint
Start_toStar
tOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
/>
<android.support.constraint.ConstraintLayout
android:id=
"@+id/top_container"
<TextView
android:id=
"@+id/text_chat_name"
style=
"@style/ChatRoom.Name.TextView"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"16dp"
app:layout_constraintLeft_toRightOf=
"@+id/layout_avatar"
app:layout_constraintRight_toRightOf=
"parent"
>
app:layout_constraintStart_toEndOf=
"@id/layout_avatar"
android:textDirection=
"locale"
tools:text=
"General"
/>
<TextView
android:id=
"@+id/text_chat_name"
style=
"@style/ChatRoom.Name.TextView"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:drawablePadding=
"@dimen/text_view_drawable_padding"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toLeftOf=
"@+id/text_last_message_date_time"
app:layout_constraintTop_toTopOf=
"parent"
tools:text=
"General"
/>
<TextView
android:id=
"@+id/text_last_message_date_time"
style=
"@style/Timestamp.TextView"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"5dp"
app:layout_constraintBaseline_toBaselineOf=
"@+id/text_chat_name"
app:layout_constraintLeft_toRightOf=
"@+id/text_chat_name"
app:layout_constraintRight_toRightOf=
"parent"
tools:text=
"11:45 AM"
/>
</android.support.constraint.ConstraintLayout>
<TextView
android:id=
"@+id/text_last_message_date_time"
style=
"@style/Timestamp.TextView"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"5dp"
android:layout_marginEnd=
"5dp"
app:layout_constraintBaseline_toBaselineOf=
"@+id/text_chat_name"
app:layout_constraintEnd_toEndOf=
"parent"
tools:text=
"11:45 AM"
/>
<
android.support.constraint.ConstraintLayout
android:id=
"@+id/
bottom_container
"
<
TextView
android:id=
"@+id/
text_last_message
"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_marginStart=
"16dp"
android:ellipsize=
"end"
android:maxLines=
"2"
android:layout_marginTop=
"2dp"
app:layout_constraintLeft_toRightOf=
"@+id/layout_avatar"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@+id/top_container"
>
app:layout_constraintStart_toStartOf=
"@id/text_chat_name"
app:layout_constraintTop_toBottomOf=
"@id/text_chat_name"
app:layout_constraintEnd_toStartOf=
"@id/layout_unread_messages_badge"
android:textDirection=
"locale"
tools:text=
"You: Type something"
/>
<TextView
android:id=
"@+id/text_last_message"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:ellipsize=
"end"
android:maxLines=
"2"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toLeftOf=
"@+id/layout_unread_messages_badge"
app:layout_constraintTop_toTopOf=
"parent"
tools:text=
"You: Type something"
/>
<include
android:id=
"@+id/layout_unread_messages_badge"
layout=
"@layout/unread_messages_badge"
android:layout_width=
"18dp"
android:layout_height=
"18dp"
android:layout_marginStart=
"5dp"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintLeft_toRightOf=
"@+id/text_last_message"
app:layout_constraintRight_toRightOf=
"parent"
/>
</android.support.constraint.ConstraintLayout>
<include
android:id=
"@+id/layout_unread_messages_badge"
layout=
"@layout/unread_messages_badge"
android:layout_width=
"18dp"
android:layout_height=
"18dp"
android:layout_marginStart=
"5dp"
android:layout_marginEnd=
"5dp"
app:layout_constraintTop_toTopOf=
"@id/text_last_message"
app:layout_constraintEnd_toEndOf=
"parent"
/>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
app/src/main/res/layout/nav_header.xml
View file @
3e7984fd
...
...
@@ -45,7 +45,6 @@
android:id=
"@+id/image_user_status"
android:layout_width=
"14dp"
android:layout_height=
"14dp"
android:src=
"@drawable/ic_status_online_24dp"
app:layout_constraintStart_toStartOf=
"parent"
/>
<TextView
...
...
app/src/main/res/values-hi-rIN/strings.xml
View file @
3e7984fd
...
...
@@ -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>
...
...
@@ -36,6 +37,7 @@
<!-- Settings List -->
<string-array
name=
"settings_actions"
>
<item
name=
"item_password"
>
पासवर्ड बदलें
</item>
<item
name=
"item_password"
>
परिचय
</item>
</string-array>
<!-- Regular information messages -->
...
...
@@ -86,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 @
3e7984fd
...
...
@@ -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>
...
...
@@ -36,6 +37,7 @@
<!-- 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 -->
...
...
@@ -79,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/strings.xml
View file @
3e7984fd
...
...
@@ -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>
...
...
@@ -37,6 +38,7 @@
<!-- 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 -->
...
...
@@ -81,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