Unverified Commit 628a9200 authored by Noor Binte Amir's avatar Noor Binte Amir Committed by GitHub

Merge pull request #1 from RocketChat/develop

Pulling original
parents 26d85e2e 3da3ec81
...@@ -18,7 +18,7 @@ android { ...@@ -18,7 +18,7 @@ android {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion versions.minSdk minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk targetSdkVersion versions.targetSdk
versionCode 2061 versionCode 2062
versionName "3.4.0" versionName "3.4.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 11, "version": 11,
"identityHash": "fb9f1c815809b0217d326452aeb34e92", "identityHash": "f0e15bc95a0bb09b052c484704dd3abd",
"entities": [ "entities": [
{ {
"tableName": "users", "tableName": "users",
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
}, },
{ {
"tableName": "chatrooms", "tableName": "chatrooms",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `subscriptionId` TEXT NOT NULL, `parentId` TEXT, `type` TEXT NOT NULL, `name` TEXT NOT NULL, `fullname` TEXT, `userId` TEXT, `ownerId` TEXT, `readonly` INTEGER, `isDefault` INTEGER, `favorite` INTEGER, `topic` TEXT, `announcement` TEXT, `description` TEXT, `open` INTEGER NOT NULL, `alert` INTEGER NOT NULL, `unread` INTEGER NOT NULL, `userMentions` INTEGER, `groupMentions` INTEGER, `updatedAt` INTEGER, `timestamp` INTEGER, `lastSeen` INTEGER, `lastMessageText` TEXT, `lastMessageUserId` TEXT, `lastMessageTimestamp` INTEGER, `broadcast` INTEGER, `muted` TEXT, PRIMARY KEY(`id`), FOREIGN KEY(`ownerId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`userId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION , FOREIGN KEY(`lastMessageUserId`) REFERENCES `users`(`id`) ON UPDATE NO ACTION ON DELETE NO ACTION )",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
...@@ -73,6 +73,12 @@ ...@@ -73,6 +73,12 @@
"affinity": "TEXT", "affinity": "TEXT",
"notNull": true "notNull": true
}, },
{
"fieldPath": "parentId",
"columnName": "parentId",
"affinity": "TEXT",
"notNull": false
},
{ {
"fieldPath": "type", "fieldPath": "type",
"columnName": "type", "columnName": "type",
...@@ -1099,7 +1105,7 @@ ...@@ -1099,7 +1105,7 @@
], ],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"fb9f1c815809b0217d326452aeb34e92\")" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"f0e15bc95a0bb09b052c484704dd3abd\")"
] ]
} }
} }
\ No newline at end of file
This diff is collapsed.
...@@ -4,7 +4,7 @@ import androidx.lifecycle.Lifecycle ...@@ -4,7 +4,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.OnLifecycleEvent
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
......
...@@ -24,7 +24,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor ...@@ -24,7 +24,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.SITE_URL import chat.rocket.android.server.domain.SITE_URL
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.android.util.setupFabric import chat.rocket.android.util.setupFabric
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
......
package chat.rocket.android.authentication.infraestructure package chat.rocket.android.authentication.infrastructure
import chat.rocket.android.authentication.domain.model.TokenModel import chat.rocket.android.authentication.domain.model.TokenModel
import chat.rocket.android.dagger.scope.PerActivity import chat.rocket.android.dagger.scope.PerActivity
......
package chat.rocket.android.authentication.infraestructure package chat.rocket.android.authentication.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
......
...@@ -15,8 +15,9 @@ import chat.rocket.android.server.domain.favicon ...@@ -15,8 +15,9 @@ import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.isLdapAuthenticationEnabled import chat.rocket.android.server.domain.isLdapAuthenticationEnabled
import chat.rocket.android.server.domain.isPasswordResetEnabled import chat.rocket.android.server.domain.isPasswordResetEnabled
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isEmail import chat.rocket.android.util.extensions.isEmail
...@@ -50,6 +51,7 @@ class LoginPresenter @Inject constructor( ...@@ -50,6 +51,7 @@ class LoginPresenter @Inject constructor(
) { ) {
// TODO - we should validate the current server when opening the app, and have a nonnull get() // TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!! private var currentServer = serverInteractor.get()!!
private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings private lateinit var settings: PublicSettings
...@@ -140,8 +142,15 @@ class LoginPresenter @Inject constructor( ...@@ -140,8 +142,15 @@ class LoginPresenter @Inject constructor(
val logo = settings.wideTile()?.let { val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val thumb = currentServer.avatarUrl(username) val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(currentServer, icon, logo, username, thumb) val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account) saveAccountInteractor.save(account)
} }
......
...@@ -14,8 +14,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor ...@@ -14,8 +14,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.serverLogoUrl import chat.rocket.android.util.extensions.serverLogoUrl
...@@ -54,6 +55,7 @@ class LoginOptionsPresenter @Inject constructor( ...@@ -54,6 +55,7 @@ class LoginOptionsPresenter @Inject constructor(
) { ) {
// TODO - we should validate the current server when opening the app, and have a nonnull get() // TODO - we should validate the current server when opening the app, and have a nonnull get()
private var currentServer = serverInteractor.get()!! private var currentServer = serverInteractor.get()!!
private val token = tokenRepository.get(currentServer)
private lateinit var client: RocketChatClient private lateinit var client: RocketChatClient
private lateinit var settings: PublicSettings private lateinit var settings: PublicSettings
private lateinit var credentialToken: String private lateinit var credentialToken: String
...@@ -180,8 +182,15 @@ class LoginOptionsPresenter @Inject constructor( ...@@ -180,8 +182,15 @@ class LoginOptionsPresenter @Inject constructor(
val logo = settings.wideTile()?.let { val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val thumb = currentServer.avatarUrl(username) val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(currentServer, icon, logo, username, thumb) val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account) saveAccountInteractor.save(account)
} }
......
package chat.rocket.android.authentication.loginoptions.ui package chat.rocket.android.authentication.loginoptions.ui
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.graphics.PorterDuff import android.graphics.PorterDuff
...@@ -7,10 +10,13 @@ import android.os.Bundle ...@@ -7,10 +10,13 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.animation.AlphaAnimation
import android.view.animation.Animation
import android.widget.Button import android.widget.Button
import android.widget.LinearLayout import android.widget.LinearLayout
import androidx.appcompat.view.ContextThemeWrapper import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.core.view.marginTop
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager import chat.rocket.android.analytics.AnalyticsManager
...@@ -28,6 +34,7 @@ import chat.rocket.android.webview.sso.ui.ssoWebViewIntent ...@@ -28,6 +34,7 @@ import chat.rocket.android.webview.sso.ui.ssoWebViewIntent
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.app_bar.* import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.fragment_authentication_login_options.* import kotlinx.android.synthetic.main.fragment_authentication_login_options.*
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
private const val SERVER_NAME = "server_name" private const val SERVER_NAME = "server_name"
...@@ -61,6 +68,8 @@ internal const val REQUEST_CODE_FOR_OAUTH = 1 ...@@ -61,6 +68,8 @@ internal const val REQUEST_CODE_FOR_OAUTH = 1
internal const val REQUEST_CODE_FOR_CAS = 2 internal const val REQUEST_CODE_FOR_CAS = 2
internal const val REQUEST_CODE_FOR_SAML = 3 internal const val REQUEST_CODE_FOR_SAML = 3
private const val DEFAULT_ANIMATION_DURATION = 400L
fun newInstance( fun newInstance(
serverName: String, serverName: String,
state: String? = null, state: String? = null,
...@@ -238,7 +247,6 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -238,7 +247,6 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
enableLoginByLinkedin() enableLoginByLinkedin()
} }
if (gitlabOauthUrl != null && state != null) { if (gitlabOauthUrl != null && state != null) {
setupGitlabButtonListener(gitlabOauthUrl.toString(), state.toString()) setupGitlabButtonListener(gitlabOauthUrl.toString(), state.toString())
enableLoginByGitlab() enableLoginByGitlab()
...@@ -390,11 +398,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -390,11 +398,11 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
var isAccountsCollapsed = true var isAccountsCollapsed = true
button_expand_collapse_accounts.setOnClickListener { button_expand_collapse_accounts.setOnClickListener {
isAccountsCollapsed = if (isAccountsCollapsed) { isAccountsCollapsed = if (isAccountsCollapsed) {
button_expand_collapse_accounts.rotateBy(180F, 400) button_expand_collapse_accounts.rotateBy(180F, DEFAULT_ANIMATION_DURATION)
expandAccountsView() expandAccountsView()
false false
} else { } else {
button_expand_collapse_accounts.rotateBy(180F, 400) button_expand_collapse_accounts.rotateBy(180F, DEFAULT_ANIMATION_DURATION)
collapseAccountsView() collapseAccountsView()
true true
} }
...@@ -532,17 +540,73 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView { ...@@ -532,17 +540,73 @@ class LoginOptionsFragment : Fragment(), LoginOptionsView {
} }
private fun expandAccountsView() { private fun expandAccountsView() {
(0..accounts_container.childCount) val buttons = (0..accounts_container.childCount)
.mapNotNull { accounts_container.getChildAt(it) as? Button } .mapNotNull { accounts_container.getChildAt(it) as? Button }
.filter { it.isClickable && !it.isVisible } .filter { it.isClickable && !it.isVisible }
.forEach { it.isVisible = true } val optionHeight = accounts_container.getChildAt(1).height +
accounts_container.getChildAt(1).marginTop
val collapsedHeight = accounts_container.height
val expandedHeight = collapsedHeight + optionHeight * buttons.size
with(ValueAnimator.ofInt(collapsedHeight, expandedHeight)) {
addUpdateListener {
val params = accounts_container.layoutParams
params.height = animatedValue as Int
accounts_container.layoutParams = params
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animator: Animator) {
buttons.forEach {
it.isVisible = true
val anim = AlphaAnimation(0.0f, 1.0f)
anim.duration = DEFAULT_ANIMATION_DURATION
it.startAnimation(anim)
}
}
})
setDuration(DEFAULT_ANIMATION_DURATION).start()
}
} }
private fun collapseAccountsView() { private fun collapseAccountsView() {
(0..accounts_container.childCount) val buttons = (0..accounts_container.childCount)
.mapNotNull { accounts_container.getChildAt(it) as? Button } .mapNotNull { accounts_container.getChildAt(it) as? Button }
.filter { it.isClickable && it.isVisible } .filter { it.isClickable && it.isVisible }
.drop(3) .drop(3)
.forEach { it.isVisible = false } val optionHeight = accounts_container.getChildAt(1).height +
accounts_container.getChildAt(1).marginTop
val expandedHeight = accounts_container.height
val collapsedHeight = expandedHeight - optionHeight * buttons.size
with(ValueAnimator.ofInt(expandedHeight, collapsedHeight)) {
addUpdateListener {
val params = accounts_container.layoutParams
params.height = animatedValue as Int
accounts_container.layoutParams = params
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationStart(animator: Animator) {
buttons.forEach {
val anim = AlphaAnimation(1.0f, 0.0f)
anim.duration = DEFAULT_ANIMATION_DURATION
anim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {
Timber.d("Animation starts: $animation")
}
override fun onAnimationEnd(animation: Animation) {
it.isVisible = false
}
override fun onAnimationRepeat(animation: Animation) {
Timber.d("Animation repeats: $animation")
}
})
it.startAnimation(anim)
}
}
})
setDuration(DEFAULT_ANIMATION_DURATION).start()
}
} }
} }
...@@ -7,7 +7,7 @@ import chat.rocket.android.server.domain.GetAccountsInteractor ...@@ -7,7 +7,7 @@ import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveConnectingServerInteractor import chat.rocket.android.server.domain.SaveConnectingServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
......
...@@ -12,8 +12,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor ...@@ -12,8 +12,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.serverLogoUrl import chat.rocket.android.util.extensions.serverLogoUrl
...@@ -39,7 +40,8 @@ class RegisterUsernamePresenter @Inject constructor( ...@@ -39,7 +40,8 @@ class RegisterUsernamePresenter @Inject constructor(
) { ) {
private val currentServer = serverInteractor.get()!! private val currentServer = serverInteractor.get()!!
private val client: RocketChatClient = factory.get(currentServer) private val client: RocketChatClient = factory.get(currentServer)
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!) private var settings: PublicSettings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
fun registerUsername(username: String, userId: String, authToken: String) { fun registerUsername(username: String, userId: String, authToken: String) {
launchUI(strategy) { launchUI(strategy) {
...@@ -72,15 +74,22 @@ class RegisterUsernamePresenter @Inject constructor( ...@@ -72,15 +74,22 @@ class RegisterUsernamePresenter @Inject constructor(
} }
} }
private suspend fun saveAccount(username: String) { private fun saveAccount(username: String) {
val icon = settings.favicon()?.let { val icon = settings.favicon()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val logo = settings.wideTile()?.let { val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val thumb = currentServer.avatarUrl(username) val thumb = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val account = Account(currentServer, icon, logo, username, thumb) val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
username,
thumb
)
saveAccountInteractor.save(account) saveAccountInteractor.save(account)
} }
} }
\ No newline at end of file
...@@ -3,7 +3,7 @@ package chat.rocket.android.authentication.resetpassword.presentation ...@@ -3,7 +3,7 @@ package chat.rocket.android.authentication.resetpassword.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetConnectingServerInteractor import chat.rocket.android.server.domain.GetConnectingServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
......
...@@ -8,7 +8,7 @@ import chat.rocket.android.server.domain.GetAccountsInteractor ...@@ -8,7 +8,7 @@ import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.domain.SaveConnectingServerInteractor import chat.rocket.android.server.domain.SaveConnectingServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.isValidUrl import chat.rocket.android.util.extensions.isValidUrl
......
...@@ -10,10 +10,12 @@ import chat.rocket.android.server.domain.GetSettingsInteractor ...@@ -10,10 +10,12 @@ import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SaveAccountInteractor import chat.rocket.android.server.domain.SaveAccountInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.privacyPolicyUrl import chat.rocket.android.util.extensions.privacyPolicyUrl
...@@ -38,10 +40,12 @@ class SignupPresenter @Inject constructor( ...@@ -38,10 +40,12 @@ class SignupPresenter @Inject constructor(
private val analyticsManager: AnalyticsManager, private val analyticsManager: AnalyticsManager,
private val factory: RocketChatClientFactory, private val factory: RocketChatClientFactory,
private val saveAccountInteractor: SaveAccountInteractor, private val saveAccountInteractor: SaveAccountInteractor,
tokenRepository: TokenRepository,
settingsInteractor: GetSettingsInteractor settingsInteractor: GetSettingsInteractor
) { ) {
private val currentServer = serverInteractor.get()!! private val currentServer = serverInteractor.get()!!
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!) private var settings: PublicSettings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
fun signup(name: String, username: String, password: String, email: String) { fun signup(name: String, username: String, password: String, email: String) {
val client = factory.get(currentServer) val client = factory.get(currentServer)
...@@ -98,8 +102,15 @@ class SignupPresenter @Inject constructor( ...@@ -98,8 +102,15 @@ class SignupPresenter @Inject constructor(
val logo = settings.wideTile()?.let { val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val thumb = currentServer.avatarUrl(me.username!!) val thumb = currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken)
val account = Account(currentServer, icon, logo, me.username!!, thumb) val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
me.username!!,
thumb
)
saveAccountInteractor.save(account) saveAccountInteractor.save(account)
} }
} }
\ No newline at end of file
...@@ -13,8 +13,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor ...@@ -13,8 +13,9 @@ import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.favicon import chat.rocket.android.server.domain.favicon
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.wideTile import chat.rocket.android.server.domain.wideTile
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.isEmail import chat.rocket.android.util.extensions.isEmail
...@@ -43,7 +44,8 @@ class TwoFAPresenter @Inject constructor( ...@@ -43,7 +44,8 @@ class TwoFAPresenter @Inject constructor(
val settingsInteractor: GetSettingsInteractor val settingsInteractor: GetSettingsInteractor
) { ) {
private val currentServer = serverInteractor.get()!! private val currentServer = serverInteractor.get()!!
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!) private var settings: PublicSettings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
fun authenticate( fun authenticate(
usernameOrEmail: String, usernameOrEmail: String,
...@@ -101,8 +103,15 @@ class TwoFAPresenter @Inject constructor( ...@@ -101,8 +103,15 @@ class TwoFAPresenter @Inject constructor(
val logo = settings.wideTile()?.let { val logo = settings.wideTile()?.let {
currentServer.serverLogoUrl(it) currentServer.serverLogoUrl(it)
} }
val thumb = currentServer.avatarUrl(me.username!!) val thumb = currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken)
val account = Account(currentServer, icon, logo, me.username!!, thumb) val account = Account(
settings.siteName() ?: currentServer,
currentServer,
icon,
logo,
me.username!!,
thumb
)
saveAccountInteractor.save(account) saveAccountInteractor.save(account)
} }
} }
\ No newline at end of file
...@@ -4,7 +4,7 @@ import chat.rocket.android.chatdetails.domain.ChatDetails ...@@ -4,7 +4,7 @@ import chat.rocket.android.chatdetails.domain.ChatDetails
import chat.rocket.android.chatroom.presentation.ChatRoomNavigator import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
......
...@@ -3,7 +3,7 @@ package chat.rocket.android.chatinformation.presentation ...@@ -3,7 +3,7 @@ package chat.rocket.android.chatinformation.presentation
import chat.rocket.android.chatroom.uimodel.UiModelMapper import chat.rocket.android.chatroom.uimodel.UiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
......
...@@ -56,6 +56,7 @@ class ChatRoomFragmentModule { ...@@ -56,6 +56,7 @@ class ChatRoomFragmentModule {
context: Application, context: Application,
repository: SettingsRepository, repository: SettingsRepository,
userInteractor: GetCurrentUserInteractor, userInteractor: GetCurrentUserInteractor,
tokenRepository: TokenRepository,
@Named("currentServer") serverUrl: String, @Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper { ): RoomUiModelMapper {
...@@ -63,6 +64,7 @@ class ChatRoomFragmentModule { ...@@ -63,6 +64,7 @@ class ChatRoomFragmentModule {
context, context,
repository.get(serverUrl), repository.get(serverUrl),
userInteractor, userInteractor,
tokenRepository,
serverUrl, serverUrl,
permissionsInteractor permissionsInteractor
) )
......
...@@ -29,12 +29,13 @@ import chat.rocket.android.server.domain.JobSchedulerInteractor ...@@ -29,12 +29,13 @@ import chat.rocket.android.server.domain.JobSchedulerInteractor
import chat.rocket.android.server.domain.MessagesRepository import chat.rocket.android.server.domain.MessagesRepository
import chat.rocket.android.server.domain.PermissionsInteractor import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.UsersRepository import chat.rocket.android.server.domain.UsersRepository
import chat.rocket.android.server.domain.uploadMaxFileSize import chat.rocket.android.server.domain.uploadMaxFileSize
import chat.rocket.android.server.domain.uploadMimeTypeFilter import chat.rocket.android.server.domain.uploadMimeTypeFilter
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.state import chat.rocket.android.server.infrastructure.state
import chat.rocket.android.util.extension.getByteArray import chat.rocket.android.util.extension.getByteArray
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
...@@ -101,6 +102,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -101,6 +102,7 @@ class ChatRoomPresenter @Inject constructor(
private val jobSchedulerInteractor: JobSchedulerInteractor, private val jobSchedulerInteractor: JobSchedulerInteractor,
private val messageHelper: MessageHelper, private val messageHelper: MessageHelper,
private val dbManager: DatabaseManager, private val dbManager: DatabaseManager,
tokenRepository: TokenRepository,
getSettingsInteractor: GetSettingsInteractor, getSettingsInteractor: GetSettingsInteractor,
serverInteractor: GetCurrentServerInteractor, serverInteractor: GetCurrentServerInteractor,
factory: ConnectionManagerFactory factory: ConnectionManagerFactory
...@@ -109,6 +111,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -109,6 +111,7 @@ class ChatRoomPresenter @Inject constructor(
private val manager = factory.create(currentServer) private val manager = factory.create(currentServer)
private val client = manager.client private val client = manager.client
private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!) private var settings: PublicSettings = getSettingsInteractor.get(serverInteractor.get()!!)
private val token = tokenRepository.get(currentServer)
private val currentLoggedUsername = userHelper.username() private val currentLoggedUsername = userHelper.username()
private val messagesChannel = Channel<Message>() private val messagesChannel = Channel<Message>()
...@@ -327,7 +330,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -327,7 +330,7 @@ class ChatRoomPresenter @Inject constructor(
timestamp = Instant.now().toEpochMilli(), timestamp = Instant.now().toEpochMilli(),
sender = SimpleUser(user?.id, user?.username ?: username, user?.name), sender = SimpleUser(user?.id, user?.username ?: username, user?.name),
attachments = null, attachments = null,
avatar = currentServer.avatarUrl(username ?: ""), avatar = currentServer.avatarUrl(username!!, token?.userId, token?.authToken),
channels = null, channels = null,
editedAt = null, editedAt = null,
editedBy = null, editedBy = null,
...@@ -812,7 +815,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -812,7 +815,7 @@ class ChatRoomPresenter @Inject constructor(
val sender = it.sender val sender = it.sender
val username = sender?.username ?: "" val username = sender?.username ?: ""
val name = sender?.name ?: "" val name = sender?.name ?: ""
val avatarUrl = currentServer.avatarUrl(username) val avatarUrl = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val found = members.firstOrNull { member -> member.username == username } val found = members.firstOrNull { member -> member.username == username }
val status = if (found != null) found.status else UserStatus.Offline() val status = if (found != null) found.status else UserStatus.Offline()
val searchList = mutableListOf(username, name) val searchList = mutableListOf(username, name)
...@@ -833,7 +836,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -833,7 +836,7 @@ class ChatRoomPresenter @Inject constructor(
activeUsers.addAll(others.map { activeUsers.addAll(others.map {
val username = it.username ?: "" val username = it.username ?: ""
val name = it.name ?: "" val name = it.name ?: ""
val avatarUrl = currentServer.avatarUrl(username) val avatarUrl = currentServer.avatarUrl(username, token?.userId, token?.authToken)
val searchList = mutableListOf(username, name) val searchList = mutableListOf(username, name)
PeopleSuggestionUiModel( PeopleSuggestionUiModel(
avatarUrl, avatarUrl,
...@@ -869,7 +872,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -869,7 +872,7 @@ class ChatRoomPresenter @Inject constructor(
val searchList = mutableListOf(username, name) val searchList = mutableListOf(username, name)
it.emails?.forEach { email -> searchList.add(email.address) } it.emails?.forEach { email -> searchList.add(email.address) }
PeopleSuggestionUiModel( PeopleSuggestionUiModel(
currentServer.avatarUrl(username), currentServer.avatarUrl(username, token?.userId, token?.authToken),
username, username, name, it.status, false, searchList username, username, name, it.status, false, searchList
) )
}.filterNot { filterSelfOut && self != null && self == it.text }) }.filterNot { filterSelfOut && self != null && self == it.text })
...@@ -931,6 +934,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -931,6 +934,7 @@ class ChatRoomPresenter @Inject constructor(
ChatRoom( ChatRoom(
id = id, id = id,
subscriptionId = subscriptionId, subscriptionId = subscriptionId,
parentId = parentId,
type = roomTypeOf(type), type = roomTypeOf(type),
unread = unread, unread = unread,
broadcast = broadcast ?: false, broadcast = broadcast ?: false,
...@@ -974,6 +978,7 @@ class ChatRoomPresenter @Inject constructor( ...@@ -974,6 +978,7 @@ class ChatRoomPresenter @Inject constructor(
ChatRoom( ChatRoom(
id = id, id = id,
subscriptionId = subscriptionId, subscriptionId = subscriptionId,
parentId = parentId,
type = roomTypeOf(type), type = roomTypeOf(type),
unread = unread, unread = unread,
broadcast = broadcast ?: false, broadcast = broadcast ?: false,
......
...@@ -4,9 +4,9 @@ import android.app.job.JobParameters ...@@ -4,9 +4,9 @@ import android.app.job.JobParameters
import android.app.job.JobService import android.app.job.JobService
import chat.rocket.android.db.DatabaseManagerFactory import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.server.domain.GetAccountsInteractor import chat.rocket.android.server.domain.GetAccountsInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.DatabaseMessageMapper import chat.rocket.android.server.infrastructure.DatabaseMessageMapper
import chat.rocket.android.server.infraestructure.DatabaseMessagesRepository import chat.rocket.android.server.infrastructure.DatabaseMessagesRepository
import chat.rocket.core.internal.rest.sendMessage import chat.rocket.core.internal.rest.sendMessage
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import dagger.android.AndroidInjection import dagger.android.AndroidInjection
......
...@@ -10,7 +10,7 @@ import androidx.fragment.app.Fragment ...@@ -10,7 +10,7 @@ import androidx.fragment.app.Fragment
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.presentation.ChatRoomNavigator import chat.rocket.android.chatroom.presentation.ChatRoomNavigator
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extensions.addFragment import chat.rocket.android.util.extensions.addFragment
import chat.rocket.android.util.extensions.textContent import chat.rocket.android.util.extensions.textContent
import dagger.android.AndroidInjection import dagger.android.AndroidInjection
......
...@@ -71,6 +71,7 @@ import chat.rocket.android.helper.AndroidPermissionsHelper.hasCameraPermission ...@@ -71,6 +71,7 @@ import chat.rocket.android.helper.AndroidPermissionsHelper.hasCameraPermission
import chat.rocket.android.helper.AndroidPermissionsHelper.hasWriteExternalStoragePermission import chat.rocket.android.helper.AndroidPermissionsHelper.hasWriteExternalStoragePermission
import chat.rocket.android.util.extension.asObservable import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extension.createImageFile import chat.rocket.android.util.extension.createImageFile
import chat.rocket.android.util.extension.orFalse
import chat.rocket.android.util.extensions.circularRevealOrUnreveal import chat.rocket.android.util.extensions.circularRevealOrUnreveal
import chat.rocket.android.util.extensions.clearLightStatusBar import chat.rocket.android.util.extensions.clearLightStatusBar
import chat.rocket.android.util.extensions.fadeIn import chat.rocket.android.util.extensions.fadeIn
...@@ -463,6 +464,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -463,6 +464,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
setupToolbar(roomUiModel.name.toString()) setupToolbar(roomUiModel.name.toString())
setupMessageComposer(roomUiModel) setupMessageComposer(roomUiModel)
isBroadcastChannel = roomUiModel.broadcast isBroadcastChannel = roomUiModel.broadcast
isFavorite = roomUiModel.favorite.orFalse()
if (isBroadcastChannel && !roomUiModel.canModerate) { if (isBroadcastChannel && !roomUiModel.canModerate) {
disableMenu = true disableMenu = true
activity?.invalidateOptionsMenu() activity?.invalidateOptionsMenu()
......
...@@ -30,7 +30,7 @@ import chat.rocket.android.server.domain.baseUrl ...@@ -30,7 +30,7 @@ import chat.rocket.android.server.domain.baseUrl
import chat.rocket.android.server.domain.messageReadReceiptEnabled import chat.rocket.android.server.domain.messageReadReceiptEnabled
import chat.rocket.android.server.domain.messageReadReceiptStoreUsers import chat.rocket.android.server.domain.messageReadReceiptStoreUsers
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.isImage import chat.rocket.android.util.extension.isImage
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.ifNotNullNorEmpty import chat.rocket.android.util.extensions.ifNotNullNorEmpty
...@@ -108,7 +108,7 @@ class UiModelMapper @Inject constructor( ...@@ -108,7 +108,7 @@ class UiModelMapper @Inject constructor(
readReceipts.forEach { readReceipts.forEach {
list.add( list.add(
ReadReceiptViewModel( ReadReceiptViewModel(
avatar = baseUrl.avatarUrl(it.user.username ?: ""), avatar = baseUrl.avatarUrl(it.user.username!!, token?.userId, token?.authToken),
name = userHelper.displayName(it.user), name = userHelper.displayName(it.user),
time = DateTimeHelper.getTime(DateTimeHelper.getLocalDateTime(it.timestamp)) time = DateTimeHelper.getTime(DateTimeHelper.getLocalDateTime(it.timestamp))
) )
...@@ -173,6 +173,7 @@ class UiModelMapper @Inject constructor( ...@@ -173,6 +173,7 @@ class UiModelMapper @Inject constructor(
ChatRoom( ChatRoom(
id = id, id = id,
subscriptionId = subscriptionId, subscriptionId = subscriptionId,
parentId = parentId,
type = roomTypeOf(type), type = roomTypeOf(type),
unread = unread, unread = unread,
broadcast = broadcast ?: false, broadcast = broadcast ?: false,
...@@ -525,7 +526,7 @@ class UiModelMapper @Inject constructor( ...@@ -525,7 +526,7 @@ class UiModelMapper @Inject constructor(
val username = message.sender?.username ?: "?" val username = message.sender?.username ?: "?"
return baseUrl.let { return baseUrl.let {
baseUrl.avatarUrl(username) baseUrl.avatarUrl(username, token?.userId, token?.authToken)
} }
} }
......
...@@ -8,11 +8,13 @@ import chat.rocket.android.db.model.ChatRoom ...@@ -8,11 +8,13 @@ import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.server.domain.GetCurrentUserInteractor import chat.rocket.android.server.domain.GetCurrentUserInteractor
import chat.rocket.android.server.domain.PermissionsInteractor import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.showLastMessage import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.date import chat.rocket.android.util.extensions.date
import chat.rocket.android.util.extensions.isNotNullNorEmpty
import chat.rocket.android.util.extensions.localDateTime import chat.rocket.android.util.extensions.localDateTime
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.User import chat.rocket.common.model.User
...@@ -26,10 +28,12 @@ class RoomUiModelMapper( ...@@ -26,10 +28,12 @@ class RoomUiModelMapper(
private val context: Application, private val context: Application,
private val settings: PublicSettings, private val settings: PublicSettings,
private val userInteractor: GetCurrentUserInteractor, private val userInteractor: GetCurrentUserInteractor,
private val tokenRepository: TokenRepository,
private val serverUrl: String, private val serverUrl: String,
private val permissions: PermissionsInteractor private val permissions: PermissionsInteractor
) { ) {
private val currentUser by lazy { userInteractor.get() } private val currentUser by lazy { userInteractor.get() }
private val token by lazy { tokenRepository.get(serverUrl) }
fun map( fun map(
rooms: List<ChatRoom>, rooms: List<ChatRoom>,
...@@ -80,7 +84,7 @@ class RoomUiModelMapper( ...@@ -80,7 +84,7 @@ class RoomUiModelMapper(
private fun mapUser(user: User): RoomUiModel = with(user) { private fun mapUser(user: User): RoomUiModel = with(user) {
val name = mapName(user.username!!, user.name) val name = mapName(user.username!!, user.name)
val status = user.status val status = user.status
val avatar = serverUrl.avatarUrl(user.username!!) val avatar = serverUrl.avatarUrl(user.username!!, token?.userId, token?.authToken)
val username = user.username!! val username = user.username!!
RoomUiModel( RoomUiModel(
...@@ -98,7 +102,7 @@ class RoomUiModelMapper( ...@@ -98,7 +102,7 @@ class RoomUiModelMapper(
id = id, id = id,
name = name!!, name = name!!,
type = type, type = type,
avatar = serverUrl.avatarUrl(name!!, isGroupOrChannel = true), avatar = serverUrl.avatarUrl(name!!, token?.userId, token?.authToken, isGroupOrChannel = true),
lastMessage = if (showLastMessage) { lastMessage = if (showLastMessage) {
mapLastMessage( mapLastMessage(
lastMessage?.sender?.id, lastMessage?.sender?.username, lastMessage?.sender?.id, lastMessage?.sender?.username,
...@@ -113,36 +117,40 @@ class RoomUiModelMapper( ...@@ -113,36 +117,40 @@ class RoomUiModelMapper(
) )
} }
fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel = with(chatRoom.chatRoom) { fun map(chatRoom: ChatRoom, showLastMessage: Boolean = true): RoomUiModel =
val isUnread = alert || unread > 0 with(chatRoom.chatRoom) {
val type = roomTypeOf(type) val isUnread = alert || unread > 0
val status = chatRoom.status?.let { userStatusOf(it) } val type = roomTypeOf(type)
val roomName = mapName(name, fullname) val status = chatRoom.status?.let { userStatusOf(it) }
val favorite = favorite val roomName = mapName(name, fullname)
val timestamp = mapDate(lastMessageTimestamp ?: updatedAt) val favorite = favorite
val avatar = if (type is RoomType.DirectMessage) { val timestamp = mapDate(lastMessageTimestamp ?: updatedAt)
serverUrl.avatarUrl(name) val avatar =
} else { if (type is RoomType.DirectMessage) {
serverUrl.avatarUrl(name, isGroupOrChannel = true) serverUrl.avatarUrl(name, token?.userId, token?.authToken)
} } else {
val unread = mapUnread(unread) serverUrl.avatarUrl(name, token?.userId, token?.authToken, isGroupOrChannel = true)
val lastMessage = if (showLastMessage) { }
mapLastMessage( val unread = mapUnread(unread)
val lastMessage = if (showLastMessage) {
mapLastMessage(
lastMessageUserId, lastMessageUserId,
chatRoom.lastMessageUserName, chatRoom.lastMessageUserName,
chatRoom.lastMessageUserFullName, chatRoom.lastMessageUserFullName,
lastMessageText, lastMessageText,
type is RoomType.DirectMessage type is RoomType.DirectMessage
) )
} else { } else {
null null
} }
val hasMentions = mapMentions(userMentions, groupMentions) val hasMentions = mapMentions(userMentions, groupMentions)
val open = open val open = open
val lastMessageMarkdown = lastMessage?.let { Markwon.markdown(context, it.toString()).toString() } val lastMessageMarkdown =
lastMessage?.let { Markwon.markdown(context, it.toString()).toString() }
RoomUiModel( RoomUiModel(
id = id, id = id,
isDiscussion = parentId.isNotNullNorEmpty(),
name = roomName, name = roomName,
type = type, type = type,
avatar = avatar, avatar = avatar,
...@@ -157,8 +165,8 @@ class RoomUiModelMapper( ...@@ -157,8 +165,8 @@ class RoomUiModelMapper(
username = if (type is RoomType.DirectMessage) name else null, username = if (type is RoomType.DirectMessage) name else null,
muted = muted.orEmpty(), muted = muted.orEmpty(),
writable = isChannelWritable(muted) writable = isChannelWritable(muted)
) )
} }
private fun isChannelWritable(muted: List<String>?): Boolean { private fun isChannelWritable(muted: List<String>?): Boolean {
val canWriteToReadOnlyChannels = permissions.canPostToReadOnlyChannels() val canWriteToReadOnlyChannels = permissions.canPostToReadOnlyChannels()
......
...@@ -11,6 +11,9 @@ import chat.rocket.android.chatrooms.adapter.model.RoomUiModel ...@@ -11,6 +11,9 @@ import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.util.extension.setTextViewAppearance import chat.rocket.android.util.extension.setTextViewAppearance
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import kotlinx.android.synthetic.main.item_chat.view.* import kotlinx.android.synthetic.main.item_chat.view.*
import kotlinx.android.synthetic.main.unread_messages_badge.view.* import kotlinx.android.synthetic.main.unread_messages_badge.view.*
...@@ -19,6 +22,7 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit ...@@ -19,6 +22,7 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
private val resources: Resources = itemView.resources private val resources: Resources = itemView.resources
private val channelIcon: Drawable = resources.getDrawable(R.drawable.ic_hashtag_12dp, null) private val channelIcon: Drawable = resources.getDrawable(R.drawable.ic_hashtag_12dp, null)
private val groupIcon: Drawable = resources.getDrawable(R.drawable.ic_lock_12_dp, null) private val groupIcon: Drawable = resources.getDrawable(R.drawable.ic_lock_12_dp, null)
private val discussionIcon: Drawable = resources.getDrawable(R.drawable.ic_discussion_20dp, null)
private val onlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_online_12dp, null) private val onlineIcon: Drawable = resources.getDrawable(R.drawable.ic_status_online_12dp, null)
private val awayIcon: Drawable = resources.getDrawable(R.drawable.ic_status_away_12dp, null) private val awayIcon: Drawable = resources.getDrawable(R.drawable.ic_status_away_12dp, null)
private val busyIcon: Drawable = resources.getDrawable(R.drawable.ic_status_busy_12dp, null) private val busyIcon: Drawable = resources.getDrawable(R.drawable.ic_status_busy_12dp, null)
...@@ -27,10 +31,18 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit ...@@ -27,10 +31,18 @@ class RoomViewHolder(itemView: View, private val listener: (RoomUiModel) -> Unit
override fun bindViews(data: RoomItemHolder) { override fun bindViews(data: RoomItemHolder) {
val room = data.data val room = data.data
with(itemView) { with(itemView) {
image_avatar.setImageURI(room.avatar) val avatar = room.avatar
Glide.with(image_avatar.context)
.load(room.avatar)
.apply(RequestOptions.bitmapTransform(RoundedCorners(10)))
.into(image_avatar)
text_chat_name.text = room.name text_chat_name.text = room.name
if (room.status != null && room.type is RoomType.DirectMessage) { if (room.isDiscussion) {
image_chat_icon.setImageDrawable(discussionIcon)
} else if (room.status != null && room.type is RoomType.DirectMessage) {
image_chat_icon.setImageDrawable(getStatusDrawable(room.status)) image_chat_icon.setImageDrawable(getStatusDrawable(room.status))
} else { } else {
image_chat_icon.setImageDrawable(getRoomDrawable(room.type)) image_chat_icon.setImageDrawable(getRoomDrawable(room.type))
......
...@@ -5,6 +5,7 @@ import chat.rocket.common.model.UserStatus ...@@ -5,6 +5,7 @@ import chat.rocket.common.model.UserStatus
data class RoomUiModel( data class RoomUiModel(
val id: String, val id: String,
val isDiscussion: Boolean = false,
val type: RoomType, val type: RoomType,
val name: CharSequence, val name: CharSequence,
val avatar: String, val avatar: String,
......
...@@ -15,9 +15,9 @@ import chat.rocket.android.server.domain.PermissionsInteractor ...@@ -15,9 +15,9 @@ import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.PublicSettings import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infrastructure.ConnectionManager
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
...@@ -86,12 +86,20 @@ class ChatRoomsFragmentModule { ...@@ -86,12 +86,20 @@ class ChatRoomsFragmentModule {
@PerFragment @PerFragment
fun provideRoomMapper( fun provideRoomMapper(
context: Application, context: Application,
repository: SettingsRepository, settingsRepository: SettingsRepository,
userInteractor: GetCurrentUserInteractor, userInteractor: GetCurrentUserInteractor,
tokenRepository: TokenRepository,
@Named("currentServer") serverUrl: String, @Named("currentServer") serverUrl: String,
permissionsInteractor: PermissionsInteractor permissionsInteractor: PermissionsInteractor
): RoomUiModelMapper { ): RoomUiModelMapper {
return RoomUiModelMapper(context, repository.get(serverUrl), userInteractor, serverUrl, permissionsInteractor) return RoomUiModelMapper(
context,
settingsRepository.get(serverUrl),
userInteractor,
tokenRepository,
serverUrl,
permissionsInteractor
)
} }
@Provides @Provides
......
...@@ -15,6 +15,10 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao) { ...@@ -15,6 +15,10 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao) {
Order.GROUPED_ACTIVITY -> dao.getAllGrouped() Order.GROUPED_ACTIVITY -> dao.getAllGrouped()
Order.NAME -> dao.getAllAlphabetically() Order.NAME -> dao.getAllAlphabetically()
Order.GROUPED_NAME -> dao.getAllAlphabeticallyGrouped() Order.GROUPED_NAME -> dao.getAllAlphabeticallyGrouped()
Order.UNREAD_ON_TOP_ACTIVITY -> dao.getAllUnread();
Order.UNREAD_ON_TOP_NAME -> dao.getAllAlphabeticallyUnread();
Order.UNREAD_ON_TOP_GROUPED_ACTIVITY -> dao.getAllGroupedUnread();
Order.UNREAD_ON_TOP_GROUPED_NAME -> dao.getAllAlphabeticallyGroupedUnread();
} }
} }
...@@ -28,8 +32,16 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao) { ...@@ -28,8 +32,16 @@ class ChatRoomsRepository @Inject constructor(private val dao: ChatRoomDao) {
GROUPED_ACTIVITY, GROUPED_ACTIVITY,
NAME, NAME,
GROUPED_NAME, GROUPED_NAME,
UNREAD_ON_TOP_ACTIVITY,
UNREAD_ON_TOP_NAME,
UNREAD_ON_TOP_GROUPED_ACTIVITY,
UNREAD_ON_TOP_GROUPED_NAME
} }
} }
fun ChatRoomsRepository.Order.isGrouped(): Boolean = this == ChatRoomsRepository.Order.GROUPED_ACTIVITY fun ChatRoomsRepository.Order.isGrouped(): Boolean = this == ChatRoomsRepository.Order.GROUPED_ACTIVITY
|| this == ChatRoomsRepository.Order.GROUPED_NAME || this == ChatRoomsRepository.Order.GROUPED_NAME
\ No newline at end of file
fun ChatRoomsRepository.Order.isUnreadOnTop(): Boolean = this == ChatRoomsRepository.Order.UNREAD_ON_TOP_ACTIVITY
|| this == ChatRoomsRepository.Order.UNREAD_ON_TOP_NAME
...@@ -11,9 +11,10 @@ import chat.rocket.android.infrastructure.LocalRepository ...@@ -11,9 +11,10 @@ import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.SortingAndGroupingInteractor import chat.rocket.android.server.domain.SortingAndGroupingInteractor
import chat.rocket.android.server.domain.siteName
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infrastructure.ConnectionManager
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryDB import chat.rocket.android.util.retryDB
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
...@@ -52,7 +53,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -52,7 +53,7 @@ class ChatRoomsPresenter @Inject constructor(
fun toDirectory() = navigator.toDirectory() fun toDirectory() = navigator.toDirectory()
fun getCurrentServerName() = view.setupToolbar(currentServer) fun getCurrentServerName() = view.setupToolbar(settings.siteName() ?: currentServer)
fun getSortingAndGroupingPreferences() { fun getSortingAndGroupingPreferences() {
with(sortingAndGroupingInteractor) { with(sortingAndGroupingInteractor) {
...@@ -93,6 +94,7 @@ class ChatRoomsPresenter @Inject constructor( ...@@ -93,6 +94,7 @@ class ChatRoomsPresenter @Inject constructor(
val entity = ChatRoomEntity( val entity = ChatRoomEntity(
id = id, id = id,
subscriptionId = "", subscriptionId = "",
parentId = null,
type = type.toString(), type = type.toString(),
name = username ?: name.toString(), name = username ?: name.toString(),
fullname = name.toString(), fullname = name.toString(),
......
...@@ -301,10 +301,10 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -301,10 +301,10 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
this.isGroupByFavorites = isGroupByFavorites this.isGroupByFavorites = isGroupByFavorites
if (isSortByName) { if (isSortByName) {
viewModel.setQuery(Query.ByName(isGroupByType)) viewModel.setQuery(Query.ByName(isGroupByType, isUnreadOnTop))
changeSortByTitle(getString(R.string.msg_sort_by_name)) changeSortByTitle(getString(R.string.msg_sort_by_name))
} else { } else {
viewModel.setQuery(Query.ByActivity(isGroupByType)) viewModel.setQuery(Query.ByActivity(isGroupByType, isUnreadOnTop))
changeSortByTitle(getString(R.string.msg_sort_by_activity)) changeSortByTitle(getString(R.string.msg_sort_by_activity))
} }
} }
...@@ -324,9 +324,9 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -324,9 +324,9 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
private fun showAllChats() { private fun showAllChats() {
if (isSortByName) { if (isSortByName) {
viewModel.setQuery(Query.ByName(isGroupByType)) viewModel.setQuery(Query.ByName(isGroupByType, isUnreadOnTop))
} else { } else {
viewModel.setQuery(Query.ByActivity(isGroupByType)) viewModel.setQuery(Query.ByActivity(isGroupByType, isUnreadOnTop))
} }
} }
......
...@@ -9,7 +9,7 @@ import chat.rocket.android.chatrooms.adapter.LoadingItemHolder ...@@ -9,7 +9,7 @@ import chat.rocket.android.chatrooms.adapter.LoadingItemHolder
import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper
import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor
import chat.rocket.android.chatrooms.infrastructure.ChatRoomsRepository import chat.rocket.android.chatrooms.infrastructure.ChatRoomsRepository
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infrastructure.ConnectionManager
import chat.rocket.android.util.livedata.transform import chat.rocket.android.util.livedata.transform
import chat.rocket.android.util.livedata.wrap import chat.rocket.android.util.livedata.wrap
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
...@@ -140,8 +140,10 @@ sealed class LoadingState { ...@@ -140,8 +140,10 @@ sealed class LoadingState {
} }
sealed class Query { sealed class Query {
data class ByActivity(val grouped: Boolean = false) : Query()
data class ByName(val grouped: Boolean = false) : Query() data class ByActivity(val grouped: Boolean = false, val unreadOnTop: Boolean = false) : Query()
data class ByName(val grouped: Boolean = false, val unreadOnTop: Boolean = false ) : Query()
data class Search(val query: String) : Query() data class Search(val query: String) : Query()
} }
...@@ -155,22 +157,44 @@ fun Query.isGrouped(): Boolean { ...@@ -155,22 +157,44 @@ fun Query.isGrouped(): Boolean {
} }
} }
fun Query.isUnreadOnTop(): Boolean {
return when(this) {
is Query.Search -> false
is Query.ByName -> unreadOnTop
is Query.ByActivity -> unreadOnTop
}
}
fun Query.asSortingOrder(): ChatRoomsRepository.Order { fun Query.asSortingOrder(): ChatRoomsRepository.Order {
return when(this) { return when(this) {
is Query.ByName -> { is Query.ByName -> {
if (grouped) { if (grouped && !unreadOnTop) {
ChatRoomsRepository.Order.GROUPED_NAME ChatRoomsRepository.Order.GROUPED_NAME
} else { }
else if(unreadOnTop && !grouped){
ChatRoomsRepository.Order.UNREAD_ON_TOP_NAME
}
else if(unreadOnTop && grouped){
ChatRoomsRepository.Order.UNREAD_ON_TOP_GROUPED_NAME
}
else {
ChatRoomsRepository.Order.NAME ChatRoomsRepository.Order.NAME
} }
} }
is Query.ByActivity -> { is Query.ByActivity -> {
if (grouped) { if (grouped && !unreadOnTop) {
ChatRoomsRepository.Order.GROUPED_ACTIVITY ChatRoomsRepository.Order.GROUPED_ACTIVITY
} else { }
else if(unreadOnTop && !grouped){
ChatRoomsRepository.Order.UNREAD_ON_TOP_ACTIVITY
}
else if(unreadOnTop && grouped){
ChatRoomsRepository.Order.UNREAD_ON_TOP_GROUPED_ACTIVITY
}
else {
ChatRoomsRepository.Order.ACTIVITY ChatRoomsRepository.Order.ACTIVITY
} }
} }
else -> throw IllegalArgumentException("Should be ByName or ByActivity") else -> throw IllegalArgumentException("Should be ByName or ByActivity")
} }
} }
\ No newline at end of file
...@@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModelProvider ...@@ -5,7 +5,7 @@ import androidx.lifecycle.ViewModelProvider
import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper import chat.rocket.android.chatrooms.adapter.RoomUiModelMapper
import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor import chat.rocket.android.chatrooms.domain.FetchChatRoomsInteractor
import chat.rocket.android.chatrooms.infrastructure.ChatRoomsRepository import chat.rocket.android.chatrooms.infrastructure.ChatRoomsRepository
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infrastructure.ConnectionManager
import javax.inject.Inject import javax.inject.Inject
class ChatRoomsViewModelFactory @Inject constructor( class ChatRoomsViewModelFactory @Inject constructor(
......
package chat.rocket.android.core.behaviours
interface AppLanguageView {
/**
* Updates the app language
*
* @param language The app language to be updated.
* @param country Opcional. The country code to be updated.
*/
fun updateLanguage(language: String, country: String? = null)
}
\ No newline at end of file
...@@ -4,7 +4,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy ...@@ -4,7 +4,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.members.uimodel.MemberUiModelMapper import chat.rocket.android.members.uimodel.MemberUiModelMapper
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
......
...@@ -14,9 +14,15 @@ import dagger.android.support.AndroidSupportInjectionModule ...@@ -14,9 +14,15 @@ import dagger.android.support.AndroidSupportInjectionModule
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
@Component(modules = [AndroidSupportInjectionModule::class, @Component(
AppModule::class, ActivityBuilder::class, ServiceBuilder::class, ReceiverBuilder::class, modules = [
AndroidWorkerInjectionModule::class]) AndroidSupportInjectionModule::class,
AppModule::class,
ActivityBuilder::class,
ServiceBuilder::class,
ReceiverBuilder::class,
AndroidWorkerInjectionModule::class]
)
interface AppComponent { interface AppComponent {
@Component.Builder @Component.Builder
......
...@@ -12,8 +12,8 @@ import chat.rocket.android.R ...@@ -12,8 +12,8 @@ import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.AnswersAnalytics import chat.rocket.android.analytics.AnswersAnalytics
import chat.rocket.android.analytics.GoogleAnalyticsForFirebase import chat.rocket.android.analytics.GoogleAnalyticsForFirebase
import chat.rocket.android.authentication.infraestructure.SharedPreferencesMultiServerTokenRepository import chat.rocket.android.authentication.infrastructure.SharedPreferencesMultiServerTokenRepository
import chat.rocket.android.authentication.infraestructure.SharedPreferencesTokenRepository import chat.rocket.android.authentication.infrastructure.SharedPreferencesTokenRepository
import chat.rocket.android.chatroom.service.MessageService import chat.rocket.android.chatroom.service.MessageService
import chat.rocket.android.dagger.qualifier.ForAuthentication import chat.rocket.android.dagger.qualifier.ForAuthentication
import chat.rocket.android.dagger.qualifier.ForMessages import chat.rocket.android.dagger.qualifier.ForMessages
...@@ -44,19 +44,21 @@ import chat.rocket.android.server.domain.SettingsRepository ...@@ -44,19 +44,21 @@ import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.SortingAndGroupingRepository import chat.rocket.android.server.domain.SortingAndGroupingRepository
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.UsersRepository import chat.rocket.android.server.domain.UsersRepository
import chat.rocket.android.server.infraestructure.DatabaseMessageMapper import chat.rocket.android.server.infrastructure.CurrentLanguageRepository
import chat.rocket.android.server.infraestructure.DatabaseMessagesRepository import chat.rocket.android.server.infrastructure.SharedPrefsCurrentLanguageRepository
import chat.rocket.android.server.infraestructure.JobSchedulerInteractorImpl import chat.rocket.android.server.infrastructure.DatabaseMessageMapper
import chat.rocket.android.server.infraestructure.MemoryChatRoomsRepository import chat.rocket.android.server.infrastructure.DatabaseMessagesRepository
import chat.rocket.android.server.infraestructure.MemoryUsersRepository import chat.rocket.android.server.infrastructure.JobSchedulerInteractorImpl
import chat.rocket.android.server.infraestructure.SharedPreferencesAccountsRepository import chat.rocket.android.server.infrastructure.MemoryChatRoomsRepository
import chat.rocket.android.server.infraestructure.SharedPreferencesPermissionsRepository import chat.rocket.android.server.infrastructure.MemoryUsersRepository
import chat.rocket.android.server.infraestructure.SharedPreferencesSettingsRepository import chat.rocket.android.server.infrastructure.SharedPreferencesAccountsRepository
import chat.rocket.android.server.infraestructure.SharedPrefsAnalyticsTrackingRepository import chat.rocket.android.server.infrastructure.SharedPreferencesPermissionsRepository
import chat.rocket.android.server.infraestructure.SharedPrefsBasicAuthRepository import chat.rocket.android.server.infrastructure.SharedPreferencesSettingsRepository
import chat.rocket.android.server.infraestructure.SharedPrefsConnectingServerRepository import chat.rocket.android.server.infrastructure.SharedPrefsAnalyticsTrackingRepository
import chat.rocket.android.server.infraestructure.SharedPrefsCurrentServerRepository import chat.rocket.android.server.infrastructure.SharedPrefsBasicAuthRepository
import chat.rocket.android.server.infraestructure.SharedPrefsSortingAndGroupingRepository import chat.rocket.android.server.infrastructure.SharedPrefsConnectingServerRepository
import chat.rocket.android.server.infrastructure.SharedPrefsCurrentServerRepository
import chat.rocket.android.server.infrastructure.SharedPrefsSortingAndGroupingRepository
import chat.rocket.android.util.AppJsonAdapterFactory import chat.rocket.android.util.AppJsonAdapterFactory
import chat.rocket.android.util.BasicAuthenticatorInterceptor import chat.rocket.android.util.BasicAuthenticatorInterceptor
import chat.rocket.android.util.HttpLoggingInterceptor import chat.rocket.android.util.HttpLoggingInterceptor
...@@ -175,7 +177,6 @@ class AppModule { ...@@ -175,7 +177,6 @@ class AppModule {
fun provideSharedPreferences(context: Application) = fun provideSharedPreferences(context: Application) =
context.getSharedPreferences("rocket.chat", Context.MODE_PRIVATE) context.getSharedPreferences("rocket.chat", Context.MODE_PRIVATE)
@Provides @Provides
@ForMessages @ForMessages
fun provideMessagesSharedPreferences(context: Application) = fun provideMessagesSharedPreferences(context: Application) =
...@@ -211,6 +212,12 @@ class AppModule { ...@@ -211,6 +212,12 @@ class AppModule {
return SharedPrefsConnectingServerRepository(prefs) return SharedPrefsConnectingServerRepository(prefs)
} }
@Provides
@Singleton
fun provideCurrentLanguageRepository(prefs: SharedPreferences): CurrentLanguageRepository {
return SharedPrefsCurrentLanguageRepository(prefs)
}
@Provides @Provides
@Singleton @Singleton
fun provideSettingsRepository(localRepository: LocalRepository): SettingsRepository { fun provideSettingsRepository(localRepository: LocalRepository): SettingsRepository {
......
...@@ -6,7 +6,7 @@ import chat.rocket.android.infrastructure.LocalRepository ...@@ -6,7 +6,7 @@ import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.SharedPreferencesLocalRepository import chat.rocket.android.infrastructure.SharedPreferencesLocalRepository
import chat.rocket.android.server.domain.CurrentServerRepository import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.SharedPrefsCurrentServerRepository import chat.rocket.android.server.infrastructure.SharedPrefsCurrentServerRepository
import chat.rocket.android.util.AppJsonAdapterFactory import chat.rocket.android.util.AppJsonAdapterFactory
import chat.rocket.android.util.TimberLogger import chat.rocket.android.util.TimberLogger
import chat.rocket.common.internal.FallbackSealedClassJsonAdapter import chat.rocket.common.internal.FallbackSealedClassJsonAdapter
......
...@@ -65,11 +65,59 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> { ...@@ -65,11 +65,59 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> {
""") """)
abstract fun getAllGrouped(): LiveData<List<ChatRoom>> abstract fun getAllGrouped(): LiveData<List<ChatRoom>>
@Transaction
@Query("""
$BASE_QUERY
$FILTER_NOT_OPENED
ORDER BY
$UNREAD,
CASE
WHEN lastMessageTimeStamp IS NOT NULL THEN lastMessageTimeStamp
ELSE updatedAt
END DESC
""")
abstract fun getAllUnread(): LiveData<List<ChatRoom>>
@Transaction
@Query("""
$BASE_QUERY
$FILTER_NOT_OPENED
ORDER BY
$UNREAD,
name COLLATE NOCASE
""")
abstract fun getAllAlphabeticallyUnread(): LiveData<List<ChatRoom>>
@Transaction @Transaction
@Query(""" @Query("""
$BASE_QUERY $BASE_QUERY
$FILTER_NOT_OPENED $FILTER_NOT_OPENED
ORDER BY name ORDER BY
$TYPE_ORDER,
$UNREAD,
name COLLATE NOCASE
""")
abstract fun getAllAlphabeticallyGroupedUnread(): LiveData<List<ChatRoom>>
@Transaction
@Query("""
$BASE_QUERY
$FILTER_NOT_OPENED
ORDER BY
$TYPE_ORDER,
$UNREAD,
CASE
WHEN lastMessageTimeStamp IS NOT NULL THEN lastMessageTimeStamp
ELSE updatedAt
END DESC
""")
abstract fun getAllGroupedUnread(): LiveData<List<ChatRoom>>
@Transaction
@Query("""
$BASE_QUERY
$FILTER_NOT_OPENED
ORDER BY name COLLATE NOCASE
""") """)
abstract fun getAllAlphabetically(): LiveData<List<ChatRoom>> abstract fun getAllAlphabetically(): LiveData<List<ChatRoom>>
...@@ -79,7 +127,7 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> { ...@@ -79,7 +127,7 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> {
$FILTER_NOT_OPENED $FILTER_NOT_OPENED
ORDER BY ORDER BY
$TYPE_ORDER, $TYPE_ORDER,
name name COLLATE NOCASE
""") """)
abstract fun getAllAlphabeticallyGrouped(): LiveData<List<ChatRoom>> abstract fun getAllAlphabeticallyGrouped(): LiveData<List<ChatRoom>>
...@@ -139,5 +187,11 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> { ...@@ -139,5 +187,11 @@ abstract class ChatRoomDao : BaseDao<ChatRoomEntity> {
ELSE 5 ELSE 5
END END
""" """
const val UNREAD = """
CASE
WHEN alert OR unread > 0 THEN 1
ELSE 2
END
"""
} }
} }
\ No newline at end of file
...@@ -475,6 +475,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -475,6 +475,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
return ChatRoomEntity( return ChatRoomEntity(
id = room.id, id = room.id,
subscriptionId = subscription.id, subscriptionId = subscription.id,
parentId = subscription.parentId,
type = room.type.toString(), type = room.type.toString(),
name = room.name ?: subscription.name name = room.name ?: subscription.name
?: throw NullPointerException(), // this should be filtered on the SDK ?: throw NullPointerException(), // this should be filtered on the SDK
...@@ -516,6 +517,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) { ...@@ -516,6 +517,7 @@ class DatabaseManager(val context: Application, val serverUrl: String) {
return ChatRoomEntity( return ChatRoomEntity(
id = id, id = id,
subscriptionId = subscriptionId, subscriptionId = subscriptionId,
parentId = parentId,
type = type.toString(), type = type.toString(),
name = name, name = name,
fullname = fullName, fullname = fullName,
......
...@@ -25,7 +25,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter ...@@ -25,7 +25,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter
AttachmentFieldEntity::class, AttachmentActionEntity::class, UrlEntity::class, AttachmentFieldEntity::class, AttachmentActionEntity::class, UrlEntity::class,
ReactionEntity::class, MessagesSync::class ReactionEntity::class, MessagesSync::class
], ],
version = 11, version = 12,
exportSchema = true exportSchema = true
) )
@TypeConverters(StringListConverter::class) @TypeConverters(StringListConverter::class)
......
...@@ -26,6 +26,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter ...@@ -26,6 +26,7 @@ import chat.rocket.android.emoji.internal.db.StringListConverter
data class ChatRoomEntity( data class ChatRoomEntity(
@PrimaryKey var id: String, @PrimaryKey var id: String,
var subscriptionId: String, var subscriptionId: String,
var parentId: String?,
var type: String, var type: String,
var name: String, var name: String,
var fullname: String? = null, var fullname: String? = null,
......
...@@ -7,7 +7,7 @@ import chat.rocket.android.db.model.ChatRoomEntity ...@@ -7,7 +7,7 @@ import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.directory.uimodel.DirectoryUiModelMapper import chat.rocket.android.directory.uimodel.DirectoryUiModelMapper
import chat.rocket.android.helper.UserHelper import chat.rocket.android.helper.UserHelper
import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
...@@ -146,6 +146,7 @@ class DirectoryPresenter @Inject constructor( ...@@ -146,6 +146,7 @@ class DirectoryPresenter @Inject constructor(
val chatRoomEntity = ChatRoomEntity( val chatRoomEntity = ChatRoomEntity(
id = directMessage.id, id = directMessage.id,
parentId = null,
name = username, name = username,
description = null, description = null,
type = RoomType.DIRECT_MESSAGE, type = RoomType.DIRECT_MESSAGE,
......
package chat.rocket.android.directory.uimodel package chat.rocket.android.directory.uimodel
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.common.model.Token
import chat.rocket.core.model.DirectoryResult import chat.rocket.core.model.DirectoryResult
class DirectoryUiModel( class DirectoryUiModel(
private val directoryResult: DirectoryResult, private val directoryResult: DirectoryResult,
private val baseUrl: String? private val baseUrl: String?,
private val token: Token?
) { ) {
val id: String = directoryResult.id val id: String = directoryResult.id
val channelAvatarUri: String? val channelAvatarUri: String?
...@@ -22,12 +24,12 @@ class DirectoryUiModel( ...@@ -22,12 +24,12 @@ class DirectoryUiModel(
} }
private fun getChannelAvatar(): String? { private fun getChannelAvatar(): String? {
return baseUrl?.avatarUrl(name, isGroupOrChannel = true) return baseUrl?.avatarUrl(name, token?.userId, token?.authToken, isGroupOrChannel = true)
} }
private fun getUserAvatar(): String? { private fun getUserAvatar(): String? {
return directoryResult.username?.let { return directoryResult.username?.let {
baseUrl?.avatarUrl(it) baseUrl?.avatarUrl(it, token?.userId, token?.authToken)
} }
} }
} }
package chat.rocket.android.directory.uimodel package chat.rocket.android.directory.uimodel
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.baseUrl import chat.rocket.android.server.domain.baseUrl
import chat.rocket.core.model.DirectoryResult import chat.rocket.core.model.DirectoryResult
import chat.rocket.core.model.Value import chat.rocket.core.model.Value
...@@ -9,13 +10,14 @@ import javax.inject.Named ...@@ -9,13 +10,14 @@ import javax.inject.Named
class DirectoryUiModelMapper @Inject constructor( class DirectoryUiModelMapper @Inject constructor(
getSettingsInteractor: GetSettingsInteractor, getSettingsInteractor: GetSettingsInteractor,
@Named("currentServer") private val currentServer: String @Named("currentServer") private val currentServer: String,
tokenRepository: TokenRepository
) { ) {
private var settings: Map<String, Value<Any>> = getSettingsInteractor.get(currentServer) private var settings: Map<String, Value<Any>> = getSettingsInteractor.get(currentServer)
private val baseUrl = settings.baseUrl() private val baseUrl = settings.baseUrl()
private val token = tokenRepository.get(currentServer)
fun mapToUiModelList(directoryList: List<DirectoryResult>): List<DirectoryUiModel> { fun mapToUiModelList(directoryList: List<DirectoryResult>): List<DirectoryUiModel> {
return directoryList.map { DirectoryUiModel(it, baseUrl) } return directoryList.map { DirectoryUiModel(it, baseUrl, token) }
} }
} }
\ No newline at end of file
...@@ -3,7 +3,7 @@ package chat.rocket.android.favoritemessages.presentation ...@@ -3,7 +3,7 @@ package chat.rocket.android.favoritemessages.presentation
import chat.rocket.android.chatroom.uimodel.UiModelMapper import chat.rocket.android.chatroom.uimodel.UiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
......
...@@ -5,7 +5,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy ...@@ -5,7 +5,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.files.uimodel.FileUiModel import chat.rocket.android.files.uimodel.FileUiModel
import chat.rocket.android.files.uimodel.FileUiModelMapper import chat.rocket.android.files.uimodel.FileUiModelMapper
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
......
...@@ -26,7 +26,7 @@ object AndroidPermissionsHelper { ...@@ -26,7 +26,7 @@ object AndroidPermissionsHelper {
} }
fun hasCameraPermission(context: Context): Boolean { fun hasCameraPermission(context: Context): Boolean {
return AndroidPermissionsHelper.checkPermission(context, Manifest.permission.CAMERA) return checkPermission(context, Manifest.permission.CAMERA)
} }
fun getCameraPermission(fragment: Fragment) { fun getCameraPermission(fragment: Fragment) {
...@@ -50,10 +50,10 @@ object AndroidPermissionsHelper { ...@@ -50,10 +50,10 @@ object AndroidPermissionsHelper {
fun checkWritingPermission(context: Context) { fun checkWritingPermission(context: Context) {
if (context is ContextThemeWrapper) { if (context is ContextThemeWrapper) {
val activity = if (context.baseContext is Activity) context.baseContext as Activity else context as Activity val activity = if (context.baseContext is Activity) context.baseContext as Activity else context as Activity
AndroidPermissionsHelper.requestPermission( requestPermission(
activity, activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
AndroidPermissionsHelper.WRITE_EXTERNAL_STORAGE_CODE WRITE_EXTERNAL_STORAGE_CODE
) )
} }
} }
......
...@@ -3,7 +3,7 @@ package chat.rocket.android.helper ...@@ -3,7 +3,7 @@ package chat.rocket.android.helper
object JitsiHelper { object JitsiHelper {
/** /**
* Returns the for the Jitsi video conferencing URL. * Returns the Jitsi video conferencing URL.
* *
* @param isSecureProtocol True if using SSL, false otherwise - from the public settings. * @param isSecureProtocol True if using SSL, false otherwise - from the public settings.
* @param domain The Jitsi domain - from public settings. * @param domain The Jitsi domain - from public settings.
......
...@@ -94,10 +94,16 @@ class MessageParser @Inject constructor( ...@@ -94,10 +94,16 @@ class MessageParser @Inject constructor(
} }
private fun getMention(user: SimpleUser): String { private fun getMention(user: SimpleUser): String {
user.id?.let {
if (SYSTEM_MENTIONS.contains(it)) {
return "@$it"
}
}
return if (settings.useRealName()) { return if (settings.useRealName()) {
user.name ?: "@${user.username}" user.name ?: user.username.orEmpty()
} else { } else {
"@${user.username}" user.username.orEmpty()
} }
} }
...@@ -527,5 +533,7 @@ class MessageParser @Inject constructor( ...@@ -527,5 +533,7 @@ class MessageParser @Inject constructor(
*/ */
private val WEB_URL = Pattern.compile( private val WEB_URL = Pattern.compile(
"($WEB_URL_WITH_PROTOCOL|$WEB_URL_WITHOUT_PROTOCOL)") "($WEB_URL_WITH_PROTOCOL|$WEB_URL_WITHOUT_PROTOCOL)")
private val SYSTEM_MENTIONS = arrayOf("all", "here")
} }
} }
package chat.rocket.android.main.di package chat.rocket.android.main.di
import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.LifecycleOwner
import chat.rocket.android.core.behaviours.AppLanguageView
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerActivity import chat.rocket.android.dagger.scope.PerActivity
import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.main.presentation.MainNavigator
...@@ -16,6 +17,12 @@ class MainModule { ...@@ -16,6 +17,12 @@ class MainModule {
@PerActivity @PerActivity
fun provideMainNavigator(activity: MainActivity) = MainNavigator(activity) fun provideMainNavigator(activity: MainActivity) = MainNavigator(activity)
@Provides
@PerActivity
fun appLanguageView(activity: MainActivity): AppLanguageView {
return activity
}
@Provides @Provides
@PerActivity @PerActivity
fun provideJob() = Job() fun provideJob() = Job()
......
package chat.rocket.android.main.presentation package chat.rocket.android.main.presentation
import chat.rocket.android.core.behaviours.AppLanguageView
import chat.rocket.android.push.GroupedPush import chat.rocket.android.push.GroupedPush
import chat.rocket.android.server.domain.GetCurrentLanguageInteractor
import chat.rocket.android.server.domain.RefreshPermissionsInteractor import chat.rocket.android.server.domain.RefreshPermissionsInteractor
import chat.rocket.android.server.domain.RefreshSettingsInteractor import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named import javax.inject.Named
class MainPresenter @Inject constructor( class MainPresenter @Inject constructor(
@Named("currentServer") private val currentServerUrl: String, @Named("currentServer") private val currentServerUrl: String,
private val mainNavigator: MainNavigator, private val mainNavigator: MainNavigator,
private val appLanguageView: AppLanguageView,
private val refreshSettingsInteractor: RefreshSettingsInteractor, private val refreshSettingsInteractor: RefreshSettingsInteractor,
private val refreshPermissionsInteractor: RefreshPermissionsInteractor, private val refreshPermissionsInteractor: RefreshPermissionsInteractor,
private val connectionManagerFactory: ConnectionManagerFactory, private val connectionManagerFactory: ConnectionManagerFactory,
private var getLanguageInteractor: GetCurrentLanguageInteractor,
private val groupedPush: GroupedPush private val groupedPush: GroupedPush
) { ) {
...@@ -31,4 +35,13 @@ class MainPresenter @Inject constructor( ...@@ -31,4 +35,13 @@ class MainPresenter @Inject constructor(
} }
fun showChatList(chatRoomId: String? = null) = mainNavigator.toChatList(chatRoomId) fun showChatList(chatRoomId: String? = null) = mainNavigator.toChatList(chatRoomId)
fun getAppLanguage() {
with(getLanguageInteractor) {
getLanguage()?.let { language ->
appLanguageView.updateLanguage(language, getCountry())
}
}
}
} }
\ No newline at end of file
...@@ -3,10 +3,14 @@ package chat.rocket.android.main.ui ...@@ -3,10 +3,14 @@ package chat.rocket.android.main.ui
import android.app.Activity import android.app.Activity
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.content.res.Configuration
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.LocaleList
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.core.behaviours.AppLanguageView
import chat.rocket.android.main.presentation.MainPresenter import chat.rocket.android.main.presentation.MainPresenter
import chat.rocket.android.push.refreshPushToken import chat.rocket.android.push.refreshPushToken
import chat.rocket.android.server.ui.INTENT_CHAT_ROOM_ID import chat.rocket.android.server.ui.INTENT_CHAT_ROOM_ID
...@@ -15,10 +19,11 @@ import dagger.android.AndroidInjector ...@@ -15,10 +19,11 @@ import dagger.android.AndroidInjector
import dagger.android.DispatchingAndroidInjector import dagger.android.DispatchingAndroidInjector
import dagger.android.HasActivityInjector import dagger.android.HasActivityInjector
import dagger.android.support.HasSupportFragmentInjector import dagger.android.support.HasSupportFragmentInjector
import java.util.*
import javax.inject.Inject import javax.inject.Inject
class MainActivity : AppCompatActivity(), HasActivityInjector, class MainActivity : AppCompatActivity(), HasActivityInjector,
HasSupportFragmentInjector { HasSupportFragmentInjector, AppLanguageView {
@Inject @Inject
lateinit var activityDispatchingAndroidInjector: DispatchingAndroidInjector<Activity> lateinit var activityDispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
@Inject @Inject
...@@ -30,11 +35,11 @@ class MainActivity : AppCompatActivity(), HasActivityInjector, ...@@ -30,11 +35,11 @@ class MainActivity : AppCompatActivity(), HasActivityInjector,
AndroidInjection.inject(this) AndroidInjection.inject(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
refreshPushToken() refreshPushToken()
with(presenter) { with(presenter) {
connect() connect()
getAppLanguage()
intent.getStringExtra(INTENT_CHAT_ROOM_ID).let { intent.getStringExtra(INTENT_CHAT_ROOM_ID).let {
clearNotificationsForChatRoom(it) clearNotificationsForChatRoom(it)
showChatList(it) showChatList(it)
...@@ -53,6 +58,28 @@ class MainActivity : AppCompatActivity(), HasActivityInjector, ...@@ -53,6 +58,28 @@ class MainActivity : AppCompatActivity(), HasActivityInjector,
override fun supportFragmentInjector(): AndroidInjector<Fragment> = override fun supportFragmentInjector(): AndroidInjector<Fragment> =
fagmentDispatchingAndroidInjector fagmentDispatchingAndroidInjector
override fun updateLanguage(language: String, country: String?) {
val locale: Locale = if (country != null) {
Locale(language, country)
} else {
Locale(language)
}
Locale.setDefault(locale)
val config = Configuration()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
config.locales = LocaleList(locale)
} else {
config.locale = locale
}
// TODO We need to check out a better way to use createConfigurationContext
// instead of updateConfiguration here since it is deprecated.
resources.updateConfiguration(config, resources.displayMetrics)
}
private fun clearAppNotifications() = private fun clearAppNotifications() =
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancelAll() (getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).cancelAll()
} }
...@@ -6,7 +6,7 @@ import chat.rocket.android.db.DatabaseManager ...@@ -6,7 +6,7 @@ import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.helper.UserHelper import chat.rocket.android.helper.UserHelper
import chat.rocket.android.members.uimodel.MemberUiModel import chat.rocket.android.members.uimodel.MemberUiModel
import chat.rocket.android.members.uimodel.MemberUiModelMapper import chat.rocket.android.members.uimodel.MemberUiModelMapper
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
......
...@@ -2,6 +2,7 @@ package chat.rocket.android.members.uimodel ...@@ -2,6 +2,7 @@ package chat.rocket.android.members.uimodel
import chat.rocket.android.server.domain.useRealName import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.common.model.Token
import chat.rocket.common.model.User import chat.rocket.common.model.User
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import chat.rocket.core.model.Value import chat.rocket.core.model.Value
...@@ -9,7 +10,8 @@ import chat.rocket.core.model.Value ...@@ -9,7 +10,8 @@ import chat.rocket.core.model.Value
class MemberUiModel( class MemberUiModel(
private val member: User, private val member: User,
private val settings: Map<String, Value<Any>>, private val settings: Map<String, Value<Any>>,
private val baseUrl: String? private val baseUrl: String?,
private val token: Token?
) { ) {
val userId: String = member.id val userId: String = member.id
val avatarUri: String? val avatarUri: String?
...@@ -33,7 +35,7 @@ class MemberUiModel( ...@@ -33,7 +35,7 @@ class MemberUiModel(
private fun getUserAvatar(): String? { private fun getUserAvatar(): String? {
val username = member.username ?: "?" val username = member.username ?: "?"
return baseUrl?.let { return baseUrl?.let {
baseUrl.avatarUrl(username, format = "png") baseUrl.avatarUrl(username, token?.userId, token?.authToken, format = "png")
} }
} }
......
...@@ -2,19 +2,24 @@ package chat.rocket.android.members.uimodel ...@@ -2,19 +2,24 @@ package chat.rocket.android.members.uimodel
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.baseUrl import chat.rocket.android.server.domain.baseUrl
import chat.rocket.common.model.User import chat.rocket.common.model.User
import chat.rocket.core.model.Value import chat.rocket.core.model.Value
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Named
class MemberUiModelMapper @Inject constructor( class MemberUiModelMapper @Inject constructor(
serverInteractor: GetCurrentServerInteractor, serverInteractor: GetCurrentServerInteractor,
getSettingsInteractor: GetSettingsInteractor getSettingsInteractor: GetSettingsInteractor,
@Named("currentServer") private val currentServer: String,
tokenRepository: TokenRepository
) { ) {
private var settings: Map<String, Value<Any>> = getSettingsInteractor.get(serverInteractor.get()!!) private var settings: Map<String, Value<Any>> = getSettingsInteractor.get(serverInteractor.get()!!)
private val baseUrl = settings.baseUrl() private val baseUrl = settings.baseUrl()
private val token = tokenRepository.get(currentServer)
fun mapToUiModelList(memberList: List<User>): List<MemberUiModel> { fun mapToUiModelList(memberList: List<User>): List<MemberUiModel> {
return memberList.map { MemberUiModel(it, settings, baseUrl) } return memberList.map { MemberUiModel(it, settings, baseUrl, token) }
} }
} }
...@@ -2,7 +2,7 @@ package chat.rocket.android.mentions.presentention ...@@ -2,7 +2,7 @@ package chat.rocket.android.mentions.presentention
import chat.rocket.android.chatroom.uimodel.UiModelMapper import chat.rocket.android.chatroom.uimodel.UiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
......
...@@ -3,7 +3,7 @@ package chat.rocket.android.pinnedmessages.presentation ...@@ -3,7 +3,7 @@ package chat.rocket.android.pinnedmessages.presentation
import chat.rocket.android.chatroom.uimodel.UiModelMapper import chat.rocket.android.chatroom.uimodel.UiModelMapper
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
......
...@@ -11,8 +11,8 @@ import chat.rocket.android.main.presentation.MainNavigator ...@@ -11,8 +11,8 @@ import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.compressImageAndGetByteArray import chat.rocket.android.util.extension.compressImageAndGetByteArray
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
...@@ -57,6 +57,7 @@ class ProfilePresenter @Inject constructor( ...@@ -57,6 +57,7 @@ class ProfilePresenter @Inject constructor(
private val serverUrl = serverInteractor.get()!! private val serverUrl = serverInteractor.get()!!
private val client: RocketChatClient = factory.get(serverUrl) private val client: RocketChatClient = factory.get(serverUrl)
private val user = userHelper.user() private val user = userHelper.user()
private val token = tokenRepository.get(serverUrl)
fun loadUserProfile() { fun loadUserProfile() {
launchUI(strategy) { launchUI(strategy) {
...@@ -68,7 +69,7 @@ class ProfilePresenter @Inject constructor( ...@@ -68,7 +69,7 @@ class ProfilePresenter @Inject constructor(
view.showProfile( view.showProfile(
me.status.toString(), me.status.toString(),
serverUrl.avatarUrl(me.username ?: ""), serverUrl.avatarUrl(me.username!!, token?.userId, token?.authToken),
me.name ?: "", me.name ?: "",
me.username ?: "", me.username ?: "",
me.emails?.getOrNull(0)?.address ?: "" me.emails?.getOrNull(0)?.address ?: ""
...@@ -97,7 +98,7 @@ class ProfilePresenter @Inject constructor( ...@@ -97,7 +98,7 @@ class ProfilePresenter @Inject constructor(
view.showProfileUpdateSuccessfullyMessage() view.showProfileUpdateSuccessfullyMessage()
view.showProfile( view.showProfile(
user.status.toString(), user.status.toString(),
serverUrl.avatarUrl(user.username ?: ""), serverUrl.avatarUrl(user.username!!, token?.userId, token?.authToken),
name, name,
username, username,
email email
...@@ -127,7 +128,15 @@ class ProfilePresenter @Inject constructor( ...@@ -127,7 +128,15 @@ class ProfilePresenter @Inject constructor(
uriInteractor.getInputStream(uri) uriInteractor.getInputStream(uri)
} }
} }
user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) } user?.username?.let {
view.reloadUserAvatar(
serverUrl.avatarUrl(
it,
token?.userId,
token?.authToken
)
)
}
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
exception.message?.let { exception.message?.let {
view.showMessage(it) view.showMessage(it)
...@@ -155,7 +164,15 @@ class ProfilePresenter @Inject constructor( ...@@ -155,7 +164,15 @@ class ProfilePresenter @Inject constructor(
} }
} }
user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) } user?.username?.let {
view.reloadUserAvatar(
serverUrl.avatarUrl(
it,
token?.userId,
token?.authToken
)
)
}
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
exception.message?.let { exception.message?.let {
view.showMessage(it) view.showMessage(it)
...@@ -175,7 +192,15 @@ class ProfilePresenter @Inject constructor( ...@@ -175,7 +192,15 @@ class ProfilePresenter @Inject constructor(
user?.id?.let { id -> user?.id?.let { id ->
retryIO { client.resetAvatar(id) } retryIO { client.resetAvatar(id) }
} }
user?.username?.let { view.reloadUserAvatar(serverUrl.avatarUrl(it)) } user?.username?.let {
view.reloadUserAvatar(
serverUrl.avatarUrl(
it,
token?.userId,
token?.authToken
)
)
}
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
exception.message?.let { exception.message?.let {
view.showMessage(it) view.showMessage(it)
......
...@@ -3,6 +3,7 @@ package chat.rocket.android.profile.ui ...@@ -3,6 +3,7 @@ package chat.rocket.android.profile.ui
import DrawableHelper import DrawableHelper
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
...@@ -21,6 +22,9 @@ import androidx.fragment.app.Fragment ...@@ -21,6 +22,9 @@ import androidx.fragment.app.Fragment
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.helper.AndroidPermissionsHelper
import chat.rocket.android.helper.AndroidPermissionsHelper.getCameraPermission
import chat.rocket.android.helper.AndroidPermissionsHelper.hasCameraPermission
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.profile.presentation.ProfilePresenter import chat.rocket.android.profile.presentation.ProfilePresenter
import chat.rocket.android.profile.presentation.ProfileView import chat.rocket.android.profile.presentation.ProfileView
...@@ -35,12 +39,15 @@ import chat.rocket.android.util.invalidateFirebaseToken ...@@ -35,12 +39,15 @@ import chat.rocket.android.util.invalidateFirebaseToken
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
import chat.rocket.common.model.userStatusOf import chat.rocket.common.model.userStatusOf
import com.facebook.drawee.backends.pipeline.Fresco import com.facebook.drawee.backends.pipeline.Fresco
import com.google.android.material.snackbar.Snackbar
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import io.reactivex.rxkotlin.Observables import io.reactivex.rxkotlin.Observables
import kotlinx.android.synthetic.main.app_bar.* import kotlinx.android.synthetic.main.app_bar.*
import kotlinx.android.synthetic.main.avatar_profile.* import kotlinx.android.synthetic.main.avatar_profile.*
import kotlinx.android.synthetic.main.fragment_profile.* import kotlinx.android.synthetic.main.fragment_profile.*
import kotlinx.android.synthetic.main.fragment_profile.view_dim
import kotlinx.android.synthetic.main.fragment_profile.view_loading
import kotlinx.android.synthetic.main.update_avatar_options.* import kotlinx.android.synthetic.main.update_avatar_options.*
import javax.inject.Inject import javax.inject.Inject
...@@ -52,8 +59,10 @@ private const val REQUEST_CODE_FOR_PERFORM_CAMERA = 2 ...@@ -52,8 +59,10 @@ private const val REQUEST_CODE_FOR_PERFORM_CAMERA = 2
fun newInstance() = ProfileFragment() fun newInstance() = ProfileFragment()
class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
@Inject lateinit var presenter: ProfilePresenter @Inject
@Inject lateinit var analyticsManager: AnalyticsManager lateinit var presenter: ProfilePresenter
@Inject
lateinit var analyticsManager: AnalyticsManager
private var currentStatus = "" private var currentStatus = ""
private var currentName = "" private var currentName = ""
private var currentUsername = "" private var currentUsername = ""
...@@ -223,7 +232,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -223,7 +232,13 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
} }
button_take_a_photo.setOnClickListener { button_take_a_photo.setOnClickListener {
dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA) context?.let {
if (hasCameraPermission(it)) {
dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
} else {
getCameraPermission(this)
}
}
hideUpdateAvatarOptions() hideUpdateAvatarOptions()
} }
...@@ -331,4 +346,28 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback { ...@@ -331,4 +346,28 @@ class ProfileFragment : Fragment(), ProfileView, ActionMode.Callback {
}.show() }.show()
} }
} }
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
AndroidPermissionsHelper.CAMERA_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted
dispatchTakePicture(REQUEST_CODE_FOR_PERFORM_CAMERA)
} else {
// permission denied
Snackbar.make(
relative_layout,
R.string.msg_camera_permission_denied,
Snackbar.LENGTH_SHORT
).show()
}
return
}
}
}
} }
...@@ -7,7 +7,7 @@ import android.content.Intent ...@@ -7,7 +7,7 @@ import android.content.Intent
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
import android.widget.Toast import android.widget.Toast
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.core.internal.rest.sendMessage import chat.rocket.core.internal.rest.sendMessage
import dagger.android.AndroidInjection import dagger.android.AndroidInjection
......
package chat.rocket.android.server.domain
import chat.rocket.android.server.infrastructure.CurrentLanguageRepository
import javax.inject.Inject
class GetCurrentLanguageInteractor @Inject constructor(
private val repository: CurrentLanguageRepository
) {
fun getLanguage(): String? = repository.getLanguage()
fun getCountry(): String? = repository.getCountry()
}
\ No newline at end of file
package chat.rocket.android.server.domain package chat.rocket.android.server.domain
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.core.internal.rest.permissions import chat.rocket.core.internal.rest.permissions
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
......
package chat.rocket.android.server.domain package chat.rocket.android.server.domain
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.core.internal.rest.settings import chat.rocket.core.internal.rest.settings
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
......
package chat.rocket.android.server.domain
import chat.rocket.android.server.infrastructure.CurrentLanguageRepository
import javax.inject.Inject
class SaveCurrentLanguageInteractor @Inject constructor(
private val repository: CurrentLanguageRepository
) {
fun save(language: String, country: String?) = repository.save(language, country)
}
\ No newline at end of file
...@@ -4,6 +4,7 @@ import se.ansman.kotshi.JsonSerializable ...@@ -4,6 +4,7 @@ import se.ansman.kotshi.JsonSerializable
@JsonSerializable @JsonSerializable
data class Account( data class Account(
val serverName: String?,
val serverUrl: String, val serverUrl: String,
val serverLogo: String?, val serverLogo: String?,
val serverBg: String?, val serverBg: String?,
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import chat.rocket.android.db.DatabaseManagerFactory import chat.rocket.android.db.DatabaseManagerFactory
import timber.log.Timber import timber.log.Timber
......
package chat.rocket.android.server.infrastructure
interface CurrentLanguageRepository {
fun save(language: String, country: String? = null)
fun getLanguage(): String?
fun getCountry(): String?
}
\ No newline at end of file
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.model.* import chat.rocket.android.db.model.*
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.db.Operation import chat.rocket.android.db.Operation
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import android.app.job.JobInfo import android.app.job.JobInfo
import android.app.job.JobScheduler import android.app.job.JobScheduler
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import chat.rocket.android.server.domain.ChatRoomsRepository import chat.rocket.android.server.domain.ChatRoomsRepository
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import chat.rocket.android.server.domain.UsersRepository import chat.rocket.android.server.domain.UsersRepository
import chat.rocket.android.server.domain.UsersRepository.Query import chat.rocket.android.server.domain.UsersRepository.Query
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import android.os.Build import android.os.Build
import chat.rocket.android.BuildConfig import chat.rocket.android.BuildConfig
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.PermissionsRepository import chat.rocket.android.server.domain.PermissionsRepository
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.LocalRepository.Companion.SETTINGS_KEY import chat.rocket.android.infrastructure.LocalRepository.Companion.SETTINGS_KEY
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import chat.rocket.android.server.domain.AnalyticsTrackingRepository import chat.rocket.android.server.domain.AnalyticsTrackingRepository
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import chat.rocket.android.server.domain.CurrentServerRepository import chat.rocket.android.server.domain.CurrentServerRepository
......
package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences
private const val CURRENT_LANGUAGE = "current_language"
private const val CURRENT_LANGUAGE_COUNTRY = "current_language_country"
class SharedPrefsCurrentLanguageRepository(private val preferences: SharedPreferences) :
CurrentLanguageRepository {
override fun save(language: String, country: String?) {
with(preferences) {
edit().putString(CURRENT_LANGUAGE, language).apply()
edit().putString(CURRENT_LANGUAGE_COUNTRY, country).apply()
}
}
override fun getLanguage(): String? {
return preferences.getString(CURRENT_LANGUAGE, "")
}
override fun getCountry(): String? {
return preferences.getString(CURRENT_LANGUAGE_COUNTRY, "")
}
}
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import chat.rocket.android.server.domain.CurrentServerRepository import chat.rocket.android.server.domain.CurrentServerRepository
......
package chat.rocket.android.server.infraestructure package chat.rocket.android.server.infrastructure
import android.content.SharedPreferences import android.content.SharedPreferences
import chat.rocket.android.server.domain.SortingAndGroupingRepository import chat.rocket.android.server.domain.SortingAndGroupingRepository
......
...@@ -9,7 +9,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor ...@@ -9,7 +9,7 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.SaveCurrentServerInteractor import chat.rocket.android.server.domain.SaveCurrentServerInteractor
import chat.rocket.android.server.domain.SettingsRepository import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import javax.inject.Inject import javax.inject.Inject
......
...@@ -26,9 +26,9 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor ...@@ -26,9 +26,9 @@ import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.RefreshSettingsInteractor import chat.rocket.android.server.domain.RefreshSettingsInteractor
import chat.rocket.android.server.infraestructure.ConnectionManager import chat.rocket.android.server.infrastructure.ConnectionManager
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.VersionInfo import chat.rocket.android.util.VersionInfo
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.casUrl import chat.rocket.android.util.extensions.casUrl
......
...@@ -13,7 +13,7 @@ class ServerViewHolder(itemView: View, private val currentServerUrl: String) : ...@@ -13,7 +13,7 @@ class ServerViewHolder(itemView: View, private val currentServerUrl: String) :
fun bind(account: Account) { fun bind(account: Account) {
with(itemView) { with(itemView) {
Glide.with(context).load(account.serverLogo).into(image_server) Glide.with(context).load(account.serverLogo).into(image_server)
text_server_name.text = account.serverUrl text_server_name.text = account.serverName ?: account.serverUrl
text_server_url.text = account.serverUrl text_server_url.text = account.serverUrl
image_check.isInvisible = currentServerUrl != account.serverUrl image_check.isInvisible = currentServerUrl != account.serverUrl
} }
......
...@@ -4,7 +4,7 @@ import chat.rocket.android.analytics.AnalyticsManager ...@@ -4,7 +4,7 @@ import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.UserHelper import chat.rocket.android.helper.UserHelper
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
......
...@@ -5,12 +5,14 @@ import chat.rocket.android.db.DatabaseManagerFactory ...@@ -5,12 +5,14 @@ import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.helper.UserHelper import chat.rocket.android.helper.UserHelper
import chat.rocket.android.main.presentation.MainNavigator import chat.rocket.android.main.presentation.MainNavigator
import chat.rocket.android.server.domain.AnalyticsTrackingInteractor import chat.rocket.android.server.domain.AnalyticsTrackingInteractor
import chat.rocket.android.server.domain.GetCurrentLanguageInteractor
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.PermissionsInteractor import chat.rocket.android.server.domain.PermissionsInteractor
import chat.rocket.android.server.domain.RemoveAccountInteractor import chat.rocket.android.server.domain.RemoveAccountInteractor
import chat.rocket.android.server.domain.SaveCurrentLanguageInteractor
import chat.rocket.android.server.domain.TokenRepository import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.server.presentation.CheckServerPresenter import chat.rocket.android.server.presentation.CheckServerPresenter
import chat.rocket.android.util.extension.gethash import chat.rocket.android.util.extension.gethash
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
...@@ -41,7 +43,8 @@ class SettingsPresenter @Inject constructor( ...@@ -41,7 +43,8 @@ class SettingsPresenter @Inject constructor(
getCurrentServerInteractor: GetCurrentServerInteractor, getCurrentServerInteractor: GetCurrentServerInteractor,
removeAccountInteractor: RemoveAccountInteractor, removeAccountInteractor: RemoveAccountInteractor,
databaseManagerFactory: DatabaseManagerFactory, databaseManagerFactory: DatabaseManagerFactory,
connectionManagerFactory: ConnectionManagerFactory connectionManagerFactory: ConnectionManagerFactory,
private val saveLanguageInteractor: SaveCurrentLanguageInteractor
) : CheckServerPresenter( ) : CheckServerPresenter(
strategy = strategy, strategy = strategy,
factory = rocketChatClientFactory, factory = rocketChatClientFactory,
...@@ -53,6 +56,7 @@ class SettingsPresenter @Inject constructor( ...@@ -53,6 +56,7 @@ class SettingsPresenter @Inject constructor(
tokenView = view, tokenView = view,
navigator = navigator navigator = navigator
) { ) {
private val token = tokenRepository.get(currentServer)
fun setupView() { fun setupView() {
launchUI(strategy) { launchUI(strategy) {
...@@ -67,7 +71,7 @@ class SettingsPresenter @Inject constructor( ...@@ -67,7 +71,7 @@ class SettingsPresenter @Inject constructor(
userHelper.user()?.let { user -> userHelper.user()?.let { user ->
view.setupSettingsView( view.setupSettingsView(
currentServer.avatarUrl(me.username ?: ""), currentServer.avatarUrl(me.username!!, token?.userId, token?.authToken),
userHelper.displayName(user) ?: me.username ?: "", userHelper.displayName(user) ?: me.username ?: "",
me.status.toString(), me.status.toString(),
permissions.isAdministrationEnabled(), permissions.isAdministrationEnabled(),
...@@ -123,6 +127,10 @@ class SettingsPresenter @Inject constructor( ...@@ -123,6 +127,10 @@ class SettingsPresenter @Inject constructor(
} }
} }
fun saveLocale(language: String, country: String? = null) {
saveLanguageInteractor.save(language, country)
}
fun toProfile() = navigator.toProfile() fun toProfile() = navigator.toProfile()
fun toAdmin() = tokenRepository.get(currentServer)?.let { fun toAdmin() = tokenRepository.get(currentServer)?.let {
......
...@@ -17,6 +17,7 @@ import chat.rocket.android.BuildConfig ...@@ -17,6 +17,7 @@ import chat.rocket.android.BuildConfig
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.analytics.AnalyticsManager import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.ScreenViewEvent import chat.rocket.android.analytics.event.ScreenViewEvent
import chat.rocket.android.core.behaviours.AppLanguageView
import chat.rocket.android.helper.TextHelper.getDeviceAndAppInformation import chat.rocket.android.helper.TextHelper.getDeviceAndAppInformation
import chat.rocket.android.settings.presentation.SettingsPresenter import chat.rocket.android.settings.presentation.SettingsPresenter
import chat.rocket.android.settings.presentation.SettingsView import chat.rocket.android.settings.presentation.SettingsView
...@@ -33,7 +34,7 @@ internal const val TAG_SETTINGS_FRAGMENT = "SettingsFragment" ...@@ -33,7 +34,7 @@ internal const val TAG_SETTINGS_FRAGMENT = "SettingsFragment"
fun newInstance(): Fragment = SettingsFragment() fun newInstance(): Fragment = SettingsFragment()
class SettingsFragment : Fragment(), SettingsView { class SettingsFragment : Fragment(), SettingsView, AppLanguageView {
@Inject lateinit var analyticsManager: AnalyticsManager @Inject lateinit var analyticsManager: AnalyticsManager
@Inject lateinit var presenter: SettingsPresenter @Inject lateinit var presenter: SettingsPresenter
...@@ -74,7 +75,7 @@ class SettingsFragment : Fragment(), SettingsView { ...@@ -74,7 +75,7 @@ class SettingsFragment : Fragment(), SettingsView {
text_contact_us.setOnClickListener { contactSupport() } text_contact_us.setOnClickListener { contactSupport() }
text_language.setOnClickListener {} text_language.setOnClickListener { changeLanguage() }
text_review_this_app.setOnClickListener { showAppOnStore() } text_review_this_app.setOnClickListener { showAppOnStore() }
...@@ -109,6 +110,11 @@ class SettingsFragment : Fragment(), SettingsView { ...@@ -109,6 +110,11 @@ class SettingsFragment : Fragment(), SettingsView {
} }
} }
override fun updateLanguage(language: String, country: String?) {
presenter.saveLocale(language, country)
activity?.recreate()
}
override fun invalidateToken(token: String) = invalidateFirebaseToken(token) override fun invalidateToken(token: String) = invalidateFirebaseToken(token)
override fun showLoading() { override fun showLoading() {
...@@ -155,6 +161,38 @@ class SettingsFragment : Fragment(), SettingsView { ...@@ -155,6 +161,38 @@ class SettingsFragment : Fragment(), SettingsView {
} }
} }
private fun changeLanguage() {
context?.let {
AlertDialog.Builder(it)
.setTitle(R.string.title_choose_language)
.setSingleChoiceItems(
resources.getStringArray(R.array.languages), -1
) { dialog, option ->
when (option) {
0 -> updateLanguage("en")
1 -> updateLanguage("ar")
2 -> updateLanguage("de")
3 -> updateLanguage("es")
4 -> updateLanguage("fa")
5 -> updateLanguage("fr")
6 -> updateLanguage("hi", "IN")
7 -> updateLanguage("it")
8 -> updateLanguage("ja")
9 -> updateLanguage("pt", "BR")
10 -> updateLanguage("pt", "PT")
11 -> updateLanguage("ru", "RU")
12 -> updateLanguage("tr")
13 -> updateLanguage("uk")
14 -> updateLanguage("zh", "CN")
15 -> updateLanguage("zh", "TW")
}
dialog.dismiss()
}
.create()
.show()
}
}
private fun showAppOnStore() { private fun showAppOnStore() {
try { try {
startActivity(Intent(Intent.ACTION_VIEW, getString(R.string.market_link).toUri())) startActivity(Intent(Intent.ACTION_VIEW, getString(R.string.market_link).toUri()))
......
...@@ -8,12 +8,14 @@ import chat.rocket.android.db.model.ChatRoomEntity ...@@ -8,12 +8,14 @@ import chat.rocket.android.db.model.ChatRoomEntity
import chat.rocket.android.db.model.UserEntity import chat.rocket.android.db.model.UserEntity
import chat.rocket.android.server.domain.CurrentServerRepository import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.GetSettingsInteractor import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.TokenRepository
import chat.rocket.android.server.domain.isJitsiEnabled import chat.rocket.android.server.domain.isJitsiEnabled
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.android.util.extensions.avatarUrl import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.Token
import chat.rocket.common.util.ifNull import chat.rocket.common.util.ifNull
import chat.rocket.core.internal.rest.createDirectMessage import chat.rocket.core.internal.rest.createDirectMessage
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
...@@ -26,6 +28,7 @@ class UserDetailsPresenter @Inject constructor( ...@@ -26,6 +28,7 @@ class UserDetailsPresenter @Inject constructor(
private val dbManager: DatabaseManager, private val dbManager: DatabaseManager,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val navigator: ChatRoomNavigator, private val navigator: ChatRoomNavigator,
tokenRepository: TokenRepository,
settingsInteractor: GetSettingsInteractor, settingsInteractor: GetSettingsInteractor,
serverInteractor: CurrentServerRepository, serverInteractor: CurrentServerRepository,
factory: ConnectionManagerFactory factory: ConnectionManagerFactory
...@@ -35,6 +38,7 @@ class UserDetailsPresenter @Inject constructor( ...@@ -35,6 +38,7 @@ class UserDetailsPresenter @Inject constructor(
private val client = manager.client private val client = manager.client
private val interactor = FetchChatRoomsInteractor(client, dbManager) private val interactor = FetchChatRoomsInteractor(client, dbManager)
private val settings = settingsInteractor.get(currentServer) private val settings = settingsInteractor.get(currentServer)
private val token = tokenRepository.get(currentServer)
private lateinit var userEntity: UserEntity private lateinit var userEntity: UserEntity
fun loadUserDetails(userId: String) { fun loadUserDetails(userId: String) {
...@@ -44,7 +48,13 @@ class UserDetailsPresenter @Inject constructor( ...@@ -44,7 +48,13 @@ class UserDetailsPresenter @Inject constructor(
dbManager.getUser(userId)?.let { dbManager.getUser(userId)?.let {
userEntity = it userEntity = it
val avatarUrl = val avatarUrl =
userEntity.username?.let { username -> currentServer.avatarUrl(avatar = username) } userEntity.username?.let { username ->
currentServer.avatarUrl(
username,
token?.userId,
token?.authToken
)
}
val username = userEntity.username val username = userEntity.username
val name = userEntity.name val name = userEntity.name
val utcOffset = val utcOffset =
...@@ -89,6 +99,7 @@ class UserDetailsPresenter @Inject constructor( ...@@ -89,6 +99,7 @@ class UserDetailsPresenter @Inject constructor(
val chatRoomEntity = ChatRoomEntity( val chatRoomEntity = ChatRoomEntity(
id = directMessage.id, id = directMessage.id,
name = userEntity.username ?: userEntity.name.orEmpty(), name = userEntity.username ?: userEntity.name.orEmpty(),
parentId = null,
description = null, description = null,
type = RoomType.DIRECT_MESSAGE, type = RoomType.DIRECT_MESSAGE,
fullname = userEntity.name, fullname = userEntity.name,
......
...@@ -2,7 +2,7 @@ package chat.rocket.android.util.extensions ...@@ -2,7 +2,7 @@ package chat.rocket.android.util.extensions
import chat.rocket.android.db.model.MessageEntity import chat.rocket.android.db.model.MessageEntity
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infrastructure.RocketChatClientFactory
import chat.rocket.android.util.retryIO import chat.rocket.android.util.retryIO
import chat.rocket.core.internal.rest.registerPushToken import chat.rocket.core.internal.rest.registerPushToken
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
......
...@@ -21,13 +21,15 @@ fun String.sanitize(): String { ...@@ -21,13 +21,15 @@ fun String.sanitize(): String {
fun String.avatarUrl( fun String.avatarUrl(
avatar: String, avatar: String,
userId: String?,
token: String?,
isGroupOrChannel: Boolean = false, isGroupOrChannel: Boolean = false,
format: String = "jpeg" format: String = "jpeg"
): String { ): String {
return if (isGroupOrChannel) { return if (isGroupOrChannel) {
"${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format" "${removeTrailingSlash()}/avatar/%23${avatar.removeTrailingSlash()}?format=$format&rc_uid=$userId&rc_token=$token"
} else { } else {
"${removeTrailingSlash()}/avatar/${avatar.removeTrailingSlash()}?format=$format" "${removeTrailingSlash()}/avatar/${avatar.removeTrailingSlash()}?format=$format&rc_uid=$userId&rc_token=$token"
} }
} }
......
...@@ -6,7 +6,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy ...@@ -6,7 +6,7 @@ import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.JitsiHelper import chat.rocket.android.helper.JitsiHelper
import chat.rocket.android.helper.UserHelper import chat.rocket.android.helper.UserHelper
import chat.rocket.android.server.domain.* import chat.rocket.android.server.domain.*
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infrastructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="#9EA2A8"
android:fillType="nonZero"
android:pathData="M17.0178,9.0088C17.4002,8.2308 17.479,7.9789 17.479,7.6459C17.479,4.8323 15.0667,2.5397 12.1027,2.5397C9.1391,2.5397 6.7273,4.832 6.7273,7.6459C6.7273,10.6045 9.2399,12.7514 12.8986,12.7514L13.0419,12.7522L13.2199,12.7522C15.7971,12.7522 17.3253,12.49 17.9955,12.099C17.4393,11.8181 17.312,11.7402 17.0644,11.4817C16.7269,11.1295 16.5447,10.6642 16.5903,10.1635C16.6148,9.8935 16.6686,9.7447 16.7751,9.5219C16.8362,9.3843 16.8928,9.2651 17.0178,9.0088ZM18.3011,10.1607C18.1916,10.3871 18.2091,10.4113 18.8615,10.7397C19.8228,11.2213 20.24,11.6696 19.8612,12.4352C19.1566,13.8599 16.8659,14.3395 13.2199,14.3395L13.0419,14.3395L12.8892,14.3387C8.3595,14.3387 5.0607,11.5237 5.0607,7.6459C5.0607,3.9545 8.2195,0.9524 12.1027,0.9524C15.9862,0.9524 19.1457,3.9547 19.1457,7.6459C19.1457,8.2881 18.979,8.7628 18.5273,9.6817C18.4105,9.9212 18.3589,10.0296 18.3011,10.1607ZM13.5847,16.3438C13.4018,16.575 13.2033,16.7931 12.9903,16.9977C12.7079,16.9977 12.4278,16.9894 12.1501,16.973L12.251,15.4273C12.2578,15.4187 12.2646,15.4102 12.2714,15.4016L13.5847,16.3438ZM12.2535,15.3888L12.2714,15.4016C12.2744,15.3979 12.2774,15.3941 12.2804,15.3903C12.5148,15.4037 12.7523,15.4104 12.9928,15.4104L13.1738,15.4114L13.3848,15.4114C13.6721,15.4114 13.9523,15.4089 14.2253,15.4036C13.9139,15.9928 13.5075,16.528 13.0195,16.9979L12.9928,16.9977C12.9919,16.9977 12.9911,16.9977 12.9903,16.9977C11.5566,18.3752 9.469,19.1391 7.111,19.1391L6.9581,19.1399L6.7801,19.1399C4.1004,19.1399 2.2612,18.8789 1.204,18.2903L0.9763,18.1635C0.5978,17.9163 0.3174,17.6159 0.1388,17.2549C-0.1741,16.6227 0.056,16.2068 0.6871,15.8098L1.263,15.5183C1.6568,15.319 1.6328,15.3349 1.7194,15.2446C1.7599,15.2023 1.7736,15.1649 1.7694,15.1185C1.7642,15.0606 1.772,15.0866 1.7081,14.9517C1.6576,14.8377 1.6095,14.736 1.491,14.4933C1.0219,13.5389 0.8746,13.0988 0.8746,12.4656C0.8746,11.0845 1.3214,9.7648 2.1303,8.6606C2.129,8.6512 2.1278,8.6417 2.1265,8.6322C2.5652,8.0375 3.1029,7.5134 3.7168,7.0817C3.713,7.1803 3.7112,7.2792 3.7112,7.3786C3.7112,7.962 3.7726,8.5253 3.8907,9.0644C3.8873,9.068 3.8839,9.0717 3.8805,9.0753L3.896,9.0884L3.8618,9.0953C3.0102,10.0132 2.521,11.2015 2.521,12.4656C2.521,12.7985 2.5998,13.0505 2.9842,13.8326C3.1146,14.0999 3.1702,14.2175 3.2126,14.3161C3.3274,14.5534 3.3842,14.703 3.4097,14.9832C3.4553,15.4839 3.2731,15.9492 2.9356,16.3014C2.6884,16.5596 2.561,16.6376 2.0044,16.9188C2.6743,17.3097 4.2025,17.5719 6.7801,17.5719L6.9487,17.5719L7.1108,17.5711C9.3389,17.5711 11.1786,16.7606 12.251,15.4273L12.2535,15.3888ZM1.9145,16.9641C1.6344,17.1044 1.5191,17.1878 1.5466,17.1462C1.6888,16.9311 1.6902,16.6667 1.6467,16.5786C1.7065,16.6996 1.8245,16.8138 2.0044,16.9188C1.9756,16.9333 1.9457,16.9484 1.9145,16.9641ZM2.2655,9.4174C2.2101,9.1681 2.165,8.9157 2.1303,8.6606C2.2904,8.4422 2.4646,8.2321 2.6523,8.0317L3.8805,9.0753C3.8743,9.0819 3.868,9.0886 3.8618,9.0953L2.2655,9.4174ZM2.8863,15.5497L2.0452,16.92L2.8273,18.3216C3.5014,17.9804 3.7692,17.8068 4.1368,17.4308C4.8511,17.5089 5.7278,17.5526 6.7801,17.5526L6.9581,17.5526L7.1013,17.5518C9.3708,17.5518 11.1972,16.724 12.2535,15.3888C12.4966,15.4031 12.7431,15.4104 12.9928,15.4104L13.1738,15.4114L13.3848,15.4114C13.6721,15.4114 13.9523,15.4089 14.2253,15.4036C13.0193,17.6858 10.387,19.1584 7.1108,19.1584L6.9581,19.1592L6.7801,19.1592C3.1341,19.1592 0.8434,18.6796 0.1388,17.2549C-0.24,16.4893 0.1772,16.041 1.1385,15.5594C1.7909,15.231 1.8084,15.2068 1.6989,14.9803C1.6411,14.8493 1.5895,14.7409 1.4727,14.5014C1.021,13.5824 0.8543,13.1078 0.8543,12.4656C0.8543,10.2609 1.9815,8.302 3.7168,7.0817C3.713,7.1803 3.7112,7.2792 3.7112,7.3786C3.7112,7.9706 3.7745,8.542 3.896,9.0884C3.0537,9.9876 2.5412,11.1713 2.5412,12.4656C2.5412,12.7951 2.6193,13.0447 3.0005,13.8203C3.1256,14.0767 3.1822,14.1961 3.2434,14.3338C3.3508,14.5585 3.405,14.7087 3.4299,14.9815C3.4528,15.2336 3.4186,15.4768 3.3365,15.7014C3.1322,15.6538 2.9811,15.6024 2.8863,15.5497Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file
...@@ -13,14 +13,15 @@ ...@@ -13,14 +13,15 @@
<ScrollView <ScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="0dp"
android:layout_below="@+id/layout_app_bar" android:layout_below="@+id/layout_app_bar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/layout_app_bar"> app:layout_constraintTop_toBottomOf="@+id/layout_app_bar">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="20dp"> android:paddingTop="20dp">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/profile_container" android:id="@+id/profile_container"
......
...@@ -95,7 +95,7 @@ ...@@ -95,7 +95,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins" android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:text="@string/status" android:text="@string/user_detail_status"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_message" /> app:layout_constraintTop_toBottomOf="@+id/text_message" />
......
...@@ -8,21 +8,22 @@ ...@@ -8,21 +8,22 @@
android:paddingStart="@dimen/screen_edge_left_and_right_padding" android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/chat_item_top_and_bottom_padding" android:paddingTop="@dimen/chat_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding" android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingBottom="@dimen/chat_item_top_and_bottom_padding"> android:paddingBottom="@dimen/chat_item_top_and_bottom_padding"
tools:context=".chatrooms.adapter.RoomsAdapter">
<com.facebook.drawee.view.SimpleDraweeView <ImageView
android:id="@+id/image_avatar" android:id="@+id/image_avatar"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginTop="5dp" android:layout_marginTop="2dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:roundedCornerRadius="4dp" /> tools:src="@tools:sample/avatars" />
<ImageView <ImageView
android:id="@+id/image_chat_icon" android:id="@+id/image_chat_icon"
android:layout_width="12dp" android:layout_width="12dp"
android:layout_height="0dp" android:layout_height="12dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
app:layout_constraintBottom_toBottomOf="@+id/text_chat_name" app:layout_constraintBottom_toBottomOf="@+id/text_chat_name"
app:layout_constraintStart_toEndOf="@+id/image_avatar" app:layout_constraintStart_toEndOf="@+id/image_avatar"
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="@dimen/text_view_drawable_padding" android:layout_marginStart="@dimen/text_view_drawable_padding"
android:layout_marginEnd="@dimen/text_view_drawable_padding"
android:textDirection="locale" android:textDirection="locale"
app:layout_constraintEnd_toStartOf="@+id/text_timestamp" app:layout_constraintEnd_toStartOf="@+id/text_timestamp"
app:layout_constraintStart_toEndOf="@+id/image_chat_icon" app:layout_constraintStart_toEndOf="@+id/image_chat_icon"
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
<string name="title_password">تغيير كلمة السر</string> <string name="title_password">تغيير كلمة السر</string>
<string name="title_update_profile">تحديث الملف الشخصي</string> <string name="title_update_profile">تحديث الملف الشخصي</string>
<string name="title_create_channel">إنشاء قناة</string> <string name="title_create_channel">إنشاء قناة</string>
<string name="title_choose_language">Choose Language</string> <!-- TODO Add translation -->
<string name="title_license">الترخيص</string> <string name="title_license">الترخيص</string>
<string name="title_are_you_sure">هل أنت متأكد؟</string> <string name="title_are_you_sure">هل أنت متأكد؟</string>
<string name="title_channel_details">تفاصيل القناة</string> <string name="title_channel_details">تفاصيل القناة</string>
...@@ -74,6 +75,25 @@ ...@@ -74,6 +75,25 @@
<string name="msg_delete_account">Delete account</string> <!-- TODO Translate --> <string name="msg_delete_account">Delete account</string> <!-- TODO Translate -->
<string name="msg_change_status">Change status</string> <!-- TODO Translate --> <string name="msg_change_status">Change status</string> <!-- TODO Translate -->
<string-array name="languages"> <!-- TODO Add translations -->
<item>English</item>
<item>Arabic</item>
<item>German</item>
<item>Spanish</item>
<item>Persian</item>
<item>French</item>
<item>Hindi (IN)</item>
<item>Italian</item>
<item>Japanese</item>
<item>Portuguese (BR)</item>
<item>Portuguese (PT)</item>
<item>Russian (RU)</item>
<item>Turkish</item>
<item>Ukrainian</item>
<item>Chinese (CN)</item>
<item>Chinese (TW)</item>
</string-array>
<!-- Regular information messages --> <!-- Regular information messages -->
<string name="msg_generic_error">نأسف حدث خطأ ما حاول مرة أخرى</string> <string name="msg_generic_error">نأسف حدث خطأ ما حاول مرة أخرى</string>
<string name="msg_no_data_to_display">لا يوجد بيانات للعرض</string> <string name="msg_no_data_to_display">لا يوجد بيانات للعرض</string>
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
<string name="title_authentication">Login Daten prüfen</string> <string name="title_authentication">Login Daten prüfen</string>
<string name="title_legal_terms">Legal Terms</string> <string name="title_legal_terms">Legal Terms</string>
<string name="title_chats">Chats</string> <string name="title_chats">Chats</string>
<string name="title_choose_language">Choose Language</string> <!-- TODO Add translation -->
<string name="title_profile">Profil</string> <string name="title_profile">Profil</string>
<string name="title_members">Benutzer</string> <string name="title_members">Benutzer</string>
<string name="title_counted_members">Benutzer (%d)</string> <string name="title_counted_members">Benutzer (%d)</string>
...@@ -32,7 +33,7 @@ ...@@ -32,7 +33,7 @@
<string name="action_use_this_username">Benutze den Benutzernamen</string> <string name="action_use_this_username">Benutze den Benutzernamen</string>
<string name="action_terms_of_service">Nutzungsbedingungen</string> <string name="action_terms_of_service">Nutzungsbedingungen</string>
<string name="action_privacy_policy">Datenschutz</string> <string name="action_privacy_policy">Datenschutz</string>
<string name="action_new_channel">New channel</string> <!-- TODO Translate --> <string name="action_new_channel">Neuer Kanal</string>
<string name="action_search">Suche</string> <string name="action_search">Suche</string>
<string name="action_update">Updaten</string> <string name="action_update">Updaten</string>
<string name="action_settings">Einstellungen</string> <string name="action_settings">Einstellungen</string>
...@@ -60,18 +61,37 @@ ...@@ -60,18 +61,37 @@
<string name="action_remove_favorite">Favoriten entfernen</string> <string name="action_remove_favorite">Favoriten entfernen</string>
<!-- Settings messages --> <!-- Settings messages -->
<string name="msg_contact_us">Contact us</string> <!-- TODO Translate --> <string name="msg_contact_us">Kontaktiere uns</string>
<string name="msg_language">Language</string> <!-- TODO Translate --> <string name="msg_language">Sprache</string>
<string name="msg_review_this_app">Review this app</string> <!-- TODO Translate --> <string name="msg_review_this_app">Bewerte diese App</string>
<string name="msg_share_this_app">Share this app</string> <!-- TODO Translate --> <string name="msg_share_this_app">Teile diese App</string>
<string name="msg_administration">Administration</string> <!-- TODO Translate --> <string name="msg_administration">Administration</string>
<string name="msg_license">License</string> <!-- TODO Translate --> <string name="msg_license">Lizenz</string>
<string name="msg_app_version">Version: %1$s (%2$d)</string> <!-- TODO Translate --> <string name="msg_app_version">Version: %1$s (%2$d)</string>
<string name="msg_server_version">Server version: %1$s</string> <!-- TODO Translate --> <string name="msg_server_version">Serverversion: %1$s</string>
<string name="msg_send_analytics">Send analytics</string> <!-- TODO Translate --> <string name="msg_send_analytics">Analysesaten senden</string>
<string name="msg_logout_from_rocket_chat">Logout from Rocket.Chat</string> <!-- TODO Translate --> <string name="msg_logout_from_rocket_chat">Logout von Rocket.Chat</string>
<string name="msg_delete_account">Delete account</string> <!-- TODO Translate --> <string name="msg_delete_account">Konto löschen</string>
<string name="msg_change_status">Change status</string> <!-- TODO Translate --> <string name="msg_change_status">Status ändern</string>
<string-array name="languages"> <!-- TODO Add translations -->
<item>English</item>
<item>Arabic</item>
<item>German</item>
<item>Spanish</item>
<item>Persian</item>
<item>French</item>
<item>Hindi (IN)</item>
<item>Italian</item>
<item>Japanese</item>
<item>Portuguese (BR)</item>
<item>Portuguese (PT)</item>
<item>Russian (RU)</item>
<item>Turkish</item>
<item>Ukrainian</item>
<item>Chinese (CN)</item>
<item>Chinese (TW)</item>
</string-array>
<!-- Regular information messages --> <!-- Regular information messages -->
<string name="msg_generic_error">Entschuldigung, ein Fehler ist aufgetreten, bitte versuchen Sie es noch einmal.</string> <string name="msg_generic_error">Entschuldigung, ein Fehler ist aufgetreten, bitte versuchen Sie es noch einmal.</string>
...@@ -172,11 +192,11 @@ ...@@ -172,11 +192,11 @@
<item quantity="other">%1$s reagierte mit %2$s</item> <item quantity="other">%1$s reagierte mit %2$s</item>
</plurals> </plurals>
<string name="msg_credentials_saved_successfully">Login-Daten erfolgreich gespeichert</string> <string name="msg_credentials_saved_successfully">Login-Daten erfolgreich gespeichert</string>
<string name="msg_camera_permission_denied">Camera permission is needed to open camera.</string> <!-- TODO Add translation --> <string name="msg_camera_permission_denied">Zum Öffnen der Kamera ist eine Kamera-Berechtigung erforderlich.</string>
<string name="msg_storage_permission_denied">Storage permission is needed to open Drawing.</string> <!-- TODO Add translation --> <string name="msg_storage_permission_denied">Zum Öffnen der Zeichnung ist eine Speicher-Berechtigung erforderlich.</string>
<string name="msg_server">Server</string> <!-- TODO Translate --> <string name="msg_server">Server</string>
<string name="msg_add_new_server">Add New Server</string> <!-- TODO Translate --> <string name="msg_add_new_server">Neuen Server hinzufügen</string>
<string name="msg_directory">Directory</string> <!-- TODO Translate --> <string name="msg_directory">Verzeichnis</string>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Privat</string> <string name="msg_private_channel">Privat</string>
...@@ -314,20 +334,20 @@ ...@@ -314,20 +334,20 @@
<string name="alert_title_default_skin_tone">Standard Hautton</string> <string name="alert_title_default_skin_tone">Standard Hautton</string>
<!-- Sort and group --> <!-- Sort and group -->
<string name="msg_sort_by_placeholder">Sort by %1$s</string> <!-- TODO Translate --> <string name="msg_sort_by_placeholder">Sortiere nach %1$s</string>
<string name="msg_sort_by">Sort by</string> <!-- TODO Translate --> <string name="msg_sort_by">Sortiert nach</string>
<string name="msg_sort_by_activity">Activity</string> <!-- TODO Translate --> <string name="msg_sort_by_activity">Aktivität</string>
<string name="msg_sort_by_name">Name</string> <!-- TODO Translate --> <string name="msg_sort_by_name">Name</string>
<string name="msg_group_by_unread_on_top">Unread on top</string> <!-- TODO Translate --> <string name="msg_group_by_unread_on_top">Ungelesen oben</string>
<string name="msg_group_by_type">Group by type</string> <!-- TODO Translate --> <string name="msg_group_by_type">Gruppieren nach Typ</string>
<string name="msg_group_by_favorites">Group by favorites</string> <!-- TODO Translate --> <string name="msg_group_by_favorites">Gruppieren nach Favoriten</string>
<!--ChatRooms Headers--> <!--ChatRooms Headers-->
<string name="header_favorite">Favoriten</string> <string name="header_favorite">Favoriten</string>
<string name="msg_channels">Räume</string> <string name="msg_channels">Räume</string>
<string name="msg_users">Users</string> <!-- TODO Translate --> <string name="msg_users">Benutzer</string>
<string name="msg_search_for_global_users">Search for global users</string> <!-- TODO Translate --> <string name="msg_search_for_global_users">Suche nach globalen Benutzern</string>
<string name="msg_search_for_global_users_description">If you turn on, you can search for any user from others companies or servers.</string> <!-- TODO Translate --> <string name="msg_search_for_global_users_description">Wenn Sie dies einschalten, können Sie nach Benutzern von anderen Unternehmen oder Servern suchen.</string>
<string name="header_private_groups">Private Räume</string> <string name="header_private_groups">Private Räume</string>
<string name="header_direct_messages">Direkt Nachrichten</string> <string name="header_direct_messages">Direkt Nachrichten</string>
<string name="header_live_chats">Live Chats</string> <string name="header_live_chats">Live Chats</string>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment