Commit c412154b authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Merge branch 'develop' of github.com:RocketChat/Rocket.Chat.Android into new/update-avatar-by-photo

parents 6cd577a3 2358e213
...@@ -12,8 +12,8 @@ android { ...@@ -12,8 +12,8 @@ android {
applicationId "chat.rocket.android" applicationId "chat.rocket.android"
minSdkVersion versions.minSdk minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk targetSdkVersion versions.targetSdk
versionCode 2032 versionCode 2036
versionName "2.5.0" versionName "2.5.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true multiDexEnabled true
...@@ -126,7 +126,7 @@ dependencies { ...@@ -126,7 +126,7 @@ dependencies {
implementation "com.github.luciofm:livedata-ktx:b1e8bbc25a" implementation "com.github.luciofm:livedata-ktx:b1e8bbc25a"
implementation('com.crashlytics.sdk.android:crashlytics:2.9.2@aar') { implementation('com.crashlytics.sdk.android:crashlytics:2.9.4@aar') {
transitive = true transitive = true
} }
......
#Thu Feb 15 15:50:42 BRST 2018 #Wed Aug 01 21:56:00 EDT 2018
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
...@@ -5,6 +5,7 @@ import androidx.lifecycle.LifecycleObserver ...@@ -5,6 +5,7 @@ import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.OnLifecycleEvent
import chat.rocket.android.server.domain.GetAccountInteractor import chat.rocket.android.server.domain.GetAccountInteractor
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.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.model.UserStatus import chat.rocket.common.model.UserStatus
...@@ -15,8 +16,7 @@ import javax.inject.Inject ...@@ -15,8 +16,7 @@ import javax.inject.Inject
class AppLifecycleObserver @Inject constructor( class AppLifecycleObserver @Inject constructor(
private val serverInteractor: GetCurrentServerInteractor, private val serverInteractor: GetCurrentServerInteractor,
private val factory: RocketChatClientFactory, private val factory: ConnectionManagerFactory
private val getAccountInteractor: GetAccountInteractor
) : LifecycleObserver { ) : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_START) @OnLifecycleEvent(Lifecycle.Event.ON_START)
...@@ -31,14 +31,8 @@ class AppLifecycleObserver @Inject constructor( ...@@ -31,14 +31,8 @@ class AppLifecycleObserver @Inject constructor(
private fun changeTemporaryStatus(userStatus: UserStatus) { private fun changeTemporaryStatus(userStatus: UserStatus) {
launch { launch {
val currentServer = serverInteractor.get() serverInteractor.get()?.let { currentServer ->
val account = currentServer?.let { getAccountInteractor.get(currentServer) } factory.create(currentServer).setTemporaryStatus(userStatus)
val client = account?.let { factory.create(currentServer) }
try {
client?.setTemporaryStatus(userStatus)
} catch (exception: RocketChatException) {
Timber.e(exception)
} }
} }
} }
......
...@@ -44,39 +44,48 @@ object DateTimeHelper { ...@@ -44,39 +44,48 @@ object DateTimeHelper {
} }
} }
/** fun getFormattedDateForMessages(localDateTime: LocalDateTime, context: Context): String {
val localDate = localDateTime.toLocalDate()
return when (localDate) {
today -> context.getString(R.string.msg_today)
yesterday -> context.getString(R.string.msg_yesterday)
else -> formatLocalDate(localDate)
}
}
/**
* Returns a time from a [LocalDateTime]. * Returns a time from a [LocalDateTime].
* *
* @param localDateTime The [LocalDateTime]. * @param localDateTime The [LocalDateTime].
* @return The time from a [LocalDateTime]. * @return The time from a [LocalDateTime].
*/ */
fun getTime(localDateTime: LocalDateTime): String { fun getTime(localDateTime: LocalDateTime): String {
val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
return localDateTime.toLocalTime().format(formatter).toString() return localDateTime.toLocalTime().format(formatter).toString()
} }
/** /**
* Returns a date time from a [LocalDateTime]. * Returns a date time from a [LocalDateTime].
* *
* @param localDateTime The [LocalDateTime]. * @param localDateTime The [LocalDateTime].
* @return The time from a [LocalDateTime]. * @return The time from a [LocalDateTime].
*/ */
fun getDateTime(localDateTime: LocalDateTime): String { fun getDateTime(localDateTime: LocalDateTime): String {
return formatLocalDateTime(localDateTime) return formatLocalDateTime(localDateTime)
} }
private fun formatLocalDateTime(localDateTime: LocalDateTime): String { private fun formatLocalDateTime(localDateTime: LocalDateTime): String {
val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
return localDateTime.format(formatter).toString() return localDateTime.format(formatter).toString()
} }
private fun formatLocalDate(localDate: LocalDate): String { private fun formatLocalDate(localDate: LocalDate): String {
val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
return localDate.format(formatter).toString() return localDate.format(formatter).toString()
} }
private fun formatLocalTime(localTime: LocalTime): String { private fun formatLocalTime(localTime: LocalTime): String {
val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) val formatter = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT)
return localTime.format(formatter).toString() return localTime.format(formatter).toString()
} }
} }
\ No newline at end of file
...@@ -11,8 +11,8 @@ import timber.log.Timber ...@@ -11,8 +11,8 @@ import timber.log.Timber
@Parcelize @Parcelize
data class LoginDeepLinkInfo( data class LoginDeepLinkInfo(
val url: String, val url: String,
val userId: String, val userId: String?,
val token: String val token: String?
) : Parcelable ) : Parcelable
fun Intent.getLoginDeepLinkInfo(): LoginDeepLinkInfo? { fun Intent.getLoginDeepLinkInfo(): LoginDeepLinkInfo? {
......
...@@ -23,10 +23,10 @@ import chat.rocket.android.server.domain.isGoogleAuthenticationEnabled ...@@ -23,10 +23,10 @@ import chat.rocket.android.server.domain.isGoogleAuthenticationEnabled
import chat.rocket.android.server.domain.isLdapAuthenticationEnabled import chat.rocket.android.server.domain.isLdapAuthenticationEnabled
import chat.rocket.android.server.domain.isLinkedinAuthenticationEnabled import chat.rocket.android.server.domain.isLinkedinAuthenticationEnabled
import chat.rocket.android.server.domain.isLoginFormEnabled import chat.rocket.android.server.domain.isLoginFormEnabled
import chat.rocket.android.server.domain.isMeteorAuthenticationEnabled import chat.rocket.android.server.domain.isWordpressAuthenticationEnabled
import chat.rocket.android.server.domain.isPasswordResetEnabled import chat.rocket.android.server.domain.isPasswordResetEnabled
import chat.rocket.android.server.domain.isRegistrationEnabledForNewUsers import chat.rocket.android.server.domain.isRegistrationEnabledForNewUsers
import chat.rocket.android.server.domain.isTwitterAuthenticationEnabled import chat.rocket.android.server.domain.wordpressUrl
import chat.rocket.android.server.domain.model.Account import chat.rocket.android.server.domain.model.Account
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.infraestructure.RocketChatClientFactory
...@@ -72,6 +72,7 @@ private const val SERVICE_NAME_GITHUB = "github" ...@@ -72,6 +72,7 @@ private const val SERVICE_NAME_GITHUB = "github"
private const val SERVICE_NAME_GOOGLE = "google" private const val SERVICE_NAME_GOOGLE = "google"
private const val SERVICE_NAME_LINKEDIN = "linkedin" private const val SERVICE_NAME_LINKEDIN = "linkedin"
private const val SERVICE_NAME_GILAB = "gitlab" private const val SERVICE_NAME_GILAB = "gitlab"
private const val SERVICE_NAME_WORDPRESS = "wordpress"
class LoginPresenter @Inject constructor( class LoginPresenter @Inject constructor(
private val view: LoginView, private val view: LoginView,
...@@ -141,10 +142,15 @@ class LoginPresenter @Inject constructor( ...@@ -141,10 +142,15 @@ class LoginPresenter @Inject constructor(
fun authenticateWithDeepLink(deepLinkInfo: LoginDeepLinkInfo) { fun authenticateWithDeepLink(deepLinkInfo: LoginDeepLinkInfo) {
val serverUrl = deepLinkInfo.url val serverUrl = deepLinkInfo.url
setupConnectionInfo(serverUrl) setupConnectionInfo(serverUrl)
if (deepLinkInfo.userId != null && deepLinkInfo.token != null) {
deepLinkUserId = deepLinkInfo.userId deepLinkUserId = deepLinkInfo.userId
deepLinkToken = deepLinkInfo.token deepLinkToken = deepLinkInfo.token
tokenRepository.save(serverUrl, Token(deepLinkUserId, deepLinkToken)) tokenRepository.save(serverUrl, Token(deepLinkUserId, deepLinkToken))
doAuthentication(TYPE_LOGIN_DEEP_LINK) doAuthentication(TYPE_LOGIN_DEEP_LINK)
} else {
// If we don't have the login credentials, just go through normal setup and user input.
setupView()
}
} }
private fun setupConnectionInfo(serverUrl: String) { private fun setupConnectionInfo(serverUrl: String) {
...@@ -204,8 +210,8 @@ class LoginPresenter @Inject constructor( ...@@ -204,8 +210,8 @@ class LoginPresenter @Inject constructor(
var totalSocialAccountsEnabled = 0 var totalSocialAccountsEnabled = 0
if (settings.isFacebookAuthenticationEnabled()) { if (settings.isFacebookAuthenticationEnabled()) {
val clientId = getOauthClientId(services, SERVICE_NAME_FACEBOOK) getServiceMap(services, SERVICE_NAME_FACEBOOK)?.let { serviceMap ->
if (clientId != null) { getOauthClientId(serviceMap)?.let { clientId ->
view.setupFacebookButtonListener( view.setupFacebookButtonListener(
OauthHelper.getFacebookOauthUrl( OauthHelper.getFacebookOauthUrl(
clientId, clientId,
...@@ -217,9 +223,11 @@ class LoginPresenter @Inject constructor( ...@@ -217,9 +223,11 @@ class LoginPresenter @Inject constructor(
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
} }
} }
}
if (settings.isGithubAuthenticationEnabled()) { if (settings.isGithubAuthenticationEnabled()) {
val clientId = getOauthClientId(services, SERVICE_NAME_GITHUB) getServiceMap(services, SERVICE_NAME_GITHUB)?.let { serviceMap ->
if (clientId != null) { getOauthClientId(serviceMap)?.let { clientId ->
view.setupGithubButtonListener( view.setupGithubButtonListener(
OauthHelper.getGithubOauthUrl( OauthHelper.getGithubOauthUrl(
clientId, clientId,
...@@ -230,9 +238,11 @@ class LoginPresenter @Inject constructor( ...@@ -230,9 +238,11 @@ class LoginPresenter @Inject constructor(
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
} }
} }
}
if (settings.isGoogleAuthenticationEnabled()) { if (settings.isGoogleAuthenticationEnabled()) {
val clientId = getOauthClientId(services, SERVICE_NAME_GOOGLE) getServiceMap(services, SERVICE_NAME_GOOGLE)?.let { serviceMap ->
if (clientId != null) { getOauthClientId(serviceMap)?.let { clientId ->
view.setupGoogleButtonListener( view.setupGoogleButtonListener(
OauthHelper.getGoogleOauthUrl( OauthHelper.getGoogleOauthUrl(
clientId, clientId,
...@@ -244,9 +254,11 @@ class LoginPresenter @Inject constructor( ...@@ -244,9 +254,11 @@ class LoginPresenter @Inject constructor(
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
} }
} }
}
if (settings.isLinkedinAuthenticationEnabled()) { if (settings.isLinkedinAuthenticationEnabled()) {
val clientId = getOauthClientId(services, SERVICE_NAME_LINKEDIN) getServiceMap(services, SERVICE_NAME_LINKEDIN)?.let { serviceMap ->
if (clientId != null) { getOauthClientId(serviceMap)?.let { clientId ->
view.setupLinkedinButtonListener( view.setupLinkedinButtonListener(
OauthHelper.getLinkedinOauthUrl( OauthHelper.getLinkedinOauthUrl(
clientId, clientId,
...@@ -256,21 +268,14 @@ class LoginPresenter @Inject constructor( ...@@ -256,21 +268,14 @@ class LoginPresenter @Inject constructor(
) )
view.enableLoginByLinkedin() view.enableLoginByLinkedin()
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
} }
} }
if (settings.isMeteorAuthenticationEnabled()) {
//TODO: Remove until we have this implemented
// view.enableLoginByMeteor()
// totalSocialAccountsEnabled++
}
if (settings.isTwitterAuthenticationEnabled()) {
//TODO: Remove until Twitter provides support to OAuth2
// view.enableLoginByTwitter()
// totalSocialAccountsEnabled++
} }
if (settings.isGitlabAuthenticationEnabled()) { if (settings.isGitlabAuthenticationEnabled()) {
val clientId = getOauthClientId(services, SERVICE_NAME_GILAB) getServiceMap(services, SERVICE_NAME_GILAB)?.let { serviceMap ->
if (clientId != null) { getOauthClientId(serviceMap)?.let { clientId ->
val gitlabOauthUrl = if (settings.gitlabUrl() != null) { val gitlabOauthUrl = if (settings.gitlabUrl() != null) {
OauthHelper.getGitlabOauthUrl( OauthHelper.getGitlabOauthUrl(
host = settings.gitlabUrl(), host = settings.gitlabUrl(),
...@@ -290,46 +295,105 @@ class LoginPresenter @Inject constructor( ...@@ -290,46 +295,105 @@ class LoginPresenter @Inject constructor(
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
} }
} }
}
getCustomOauthServices(services).let { if (settings.isWordpressAuthenticationEnabled()) {
for (service in it) { getServiceMap(services, SERVICE_NAME_WORDPRESS)?.let { serviceMap ->
val serviceName = getCustomOauthServiceName(service) getOauthClientId(serviceMap)?.let { clientId ->
val wordpressOauthUrl =
if (settings.wordpressUrl().isNullOrEmpty()) {
OauthHelper.getWordpressComOauthUrl(
clientId,
currentServer,
state
)
} else {
OauthHelper.getWordpressCustomOauthUrl(
getCustomOauthHost(serviceMap)
?: "https://public-api.wordpress.com",
getCustomOauthAuthorizePath(serviceMap)
?: "/oauth/authorize",
clientId,
currentServer,
SERVICE_NAME_WORDPRESS,
state,
getCustomOauthScope(serviceMap) ?: "openid"
)
}
wordpressOauthUrl?.let {
view.setupWordpressButtonListener(it, state)
view.enableLoginByWordpress()
totalSocialAccountsEnabled++
}
}
}
}
getCustomOauthServices(services).let {
for (serviceMap in it) {
val serviceName = getCustomOauthServiceName(serviceMap)
val host = getCustomOauthHost(serviceMap)
val authorizePath = getCustomOauthAuthorizePath(serviceMap)
val clientId = getOauthClientId(serviceMap)
val scope = getCustomOauthScope(serviceMap)
val textColor = getServiceNameColorForCustomOauthOrSaml(serviceMap)
val buttonColor = getServiceButtonColor(serviceMap)
if (serviceName != null &&
host != null &&
authorizePath != null &&
clientId != null &&
scope != null &&
textColor != null &&
buttonColor != null
) {
val customOauthUrl = OauthHelper.getCustomOauthUrl( val customOauthUrl = OauthHelper.getCustomOauthUrl(
getCustomOauthHost(service), host,
getCustomOauthAuthorizePath(service), authorizePath,
getCustomOauthClientId(service), clientId,
currentServer, currentServer,
serviceName, serviceName,
state, state,
getCustomOauthScope(service) scope
) )
view.addCustomOauthServiceButton( view.addCustomOauthServiceButton(
customOauthUrl, customOauthUrl,
state, state,
serviceName, serviceName,
getServiceNameColor(service), textColor,
getServiceButtonColor(service) buttonColor
) )
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
} }
} }
}
getSamlServices(services).let { getSamlServices(services).let {
val samlToken = generateRandomString(17) val samlToken = generateRandomString(17)
for (serviceMap in it) {
for (service in it) { val provider = getSamlProvider(serviceMap)
val serviceName = getSamlServiceName(serviceMap)
val textColor = getServiceNameColorForCustomOauthOrSaml(serviceMap)
val buttonColor = getServiceButtonColor(serviceMap)
if (provider != null &&
serviceName != null &&
textColor != null &&
buttonColor != null
) {
view.addSamlServiceButton( view.addSamlServiceButton(
currentServer.samlUrl(getSamlProvider(service), samlToken), currentServer.samlUrl(provider, samlToken),
samlToken, samlToken,
getSamlServiceName(service), serviceName,
getServiceNameColor(service), textColor,
getServiceButtonColor(service) buttonColor
) )
totalSocialAccountsEnabled++ totalSocialAccountsEnabled++
} }
} }
}
if (totalSocialAccountsEnabled > 0) { if (totalSocialAccountsEnabled > 0) {
view.enableOauthView() view.enableOauthView()
...@@ -433,55 +497,114 @@ class LoginPresenter @Inject constructor( ...@@ -433,55 +497,114 @@ class LoginPresenter @Inject constructor(
} }
} }
private fun getOauthClientId(listMap: List<Map<String, Any>>, serviceName: String): String? { /**
return listMap.find { map -> map.containsValue(serviceName) }?.let { * Returns an OAuth service map given a [serviceName].
it["clientId"] ?: it["appId"] *
}.toString() * @param listMap The list of [Map] to get the service from.
} * @param serviceName The service name to get in the [listMap]
* @return The OAuth service map or null otherwise.
private fun getSamlServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> { */
return listMap.filter { map -> map["service"] == "saml" } private fun getServiceMap(
} listMap: List<Map<String, Any>>,
serviceName: String
private fun getSamlServiceName(service: Map<String, Any>): String { ): Map<String, Any>? = listMap.find { map -> map.containsValue(serviceName) }
return service["buttonLabelText"].toString()
} /**
* Returns the OAuth client ID of a [serviceMap].
private fun getSamlProvider(service: Map<String, Any>): String { * REMARK: This function works for common OAuth providers (Google, Facebook, Github and so on)
return (service["clientConfig"] as Map<*, *>)["provider"].toString() * as well as custom OAuth.
} *
* @param serviceMap The service map to get the OAuth client ID.
private fun getCustomOauthServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> { * @return The OAuth client ID or null otherwise.
return listMap.filter { map -> map["custom"] == true } */
} private fun getOauthClientId(serviceMap: Map<String, Any>): String? =
serviceMap["clientId"] as? String ?: serviceMap["appId"] as? String
private fun getCustomOauthHost(service: Map<String, Any>): String {
return service["serverURL"].toString() /**
} * Returns a custom OAuth service list.
*
private fun getCustomOauthAuthorizePath(service: Map<String, Any>): String { * @return A custom OAuth service list, otherwise an empty list if there is no custom OAuth service.
return service["authorizePath"].toString() */
} private fun getCustomOauthServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> =
listMap.filter { map -> map["custom"] == true }
private fun getCustomOauthClientId(service: Map<String, Any>): String {
return service["clientId"].toString() /** Returns the custom OAuth service host.
} *
* @param serviceMap The service map to get the custom OAuth service host.
private fun getCustomOauthServiceName(service: Map<String, Any>): String { * @return The custom OAuth service host, otherwise null.
return service["service"].toString() */
} private fun getCustomOauthHost(serviceMap: Map<String, Any>): String? =
serviceMap["serverURL"] as? String
private fun getCustomOauthScope(service: Map<String, Any>): String {
return service["scope"].toString() /** Returns the custom OAuth service authorize path.
} *
* @param serviceMap The service map to get the custom OAuth service authorize path.
private fun getServiceButtonColor(service: Map<String, Any>): Int { * @return The custom OAuth service authorize path, otherwise null.
return service["buttonColor"].toString().parseColor() */
} private fun getCustomOauthAuthorizePath(serviceMap: Map<String, Any>): String? =
serviceMap["authorizePath"] as? String
private fun getServiceNameColor(service: Map<String, Any>): Int {
return service["buttonLabelColor"].toString().parseColor() /** Returns the custom OAuth service scope.
} *
* @param serviceMap The service map to get the custom OAuth service scope.
* @return The custom OAuth service scope, otherwise null.
*/
private fun getCustomOauthScope(serviceMap: Map<String, Any>): String? =
serviceMap["scope"] as? String
/** Returns the text of the custom OAuth service.
*
* @param serviceMap The service map to get the text of the custom OAuth service.
* @return The text of the custom OAuth service, otherwise null.
*/
private fun getCustomOauthServiceName(serviceMap: Map<String, Any>): String? =
serviceMap["service"] as? String
/**
* Returns a SAML OAuth service list.
*
* @return A SAML service list, otherwise an empty list if there is no SAML OAuth service.
*/
private fun getSamlServices(listMap: List<Map<String, Any>>): List<Map<String, Any>> =
listMap.filter { map -> map["service"] == "saml" }
/**
* Returns the SAML provider.
*
* @param serviceMap The service map to provider from.
* @return The SAML provider, otherwise null.
*/
private fun getSamlProvider(serviceMap: Map<String, Any>): String? =
(serviceMap["clientConfig"] as Map<*, *>)["provider"] as? String
/**
* Returns the text of the SAML service.
*
* @param serviceMap The service map to get the text of the SAML service.
* @return The text of the SAML service, otherwise null.
*/
private fun getSamlServiceName(serviceMap: Map<String, Any>): String? =
serviceMap["buttonLabelText"] as? String
/**
* Returns the text color of the service name.
* REMARK: This can be used for custom OAuth or SAML.
*
* @param serviceMap The service map to get the text color from.
* @return The text color of the service (custom OAuth or SAML), otherwise null.
*/
private fun getServiceNameColorForCustomOauthOrSaml(serviceMap: Map<String, Any>): Int? =
(serviceMap["buttonLabelColor"] as? String)?.parseColor()
/**
* Returns the button color of the service name.
* REMARK: This can be used for custom OAuth or SAML.
*
* @param serviceMap The service map to get the button color from.
* @return The button color of the service (custom OAuth or SAML), otherwise null.
*/
private fun getServiceButtonColor(serviceMap: Map<String, Any>): Int? =
(serviceMap["buttonColor"] as? String)?.parseColor()
private suspend fun saveAccount(username: String) { private suspend fun saveAccount(username: String) {
val icon = settings.favicon()?.let { val icon = settings.favicon()?.let {
......
...@@ -190,6 +190,21 @@ interface LoginView : LoadingView, MessageView { ...@@ -190,6 +190,21 @@ interface LoginView : LoadingView, MessageView {
*/ */
fun setupGitlabButtonListener(gitlabUrl: String, state: String) fun setupGitlabButtonListener(gitlabUrl: String, state: String)
/**
* Shows the "login by WordPress" view if it is enable by the server settings.
*
* REMARK: We must set up the Gitlab button listener before enabling it [setupWordpressButtonListener].
*/
fun enableLoginByWordpress()
/**
* Setups the WordPress button when tapped.
*
* @param wordpressUrl The WordPress OAuth URL to authenticate with.
* @param state A random string generated by the app, which you'll verify later (to protect against forgery attacks).
*/
fun setupWordpressButtonListener(wordpressUrl: String, state: String)
/** /**
* Adds a custom OAuth button in the oauth view. * Adds a custom OAuth button in the oauth view.
* *
......
...@@ -443,6 +443,24 @@ class LoginFragment : Fragment(), LoginView { ...@@ -443,6 +443,24 @@ class LoginFragment : Fragment(), LoginView {
} }
} }
override fun enableLoginByWordpress() {
ui {
button_wordpress.isClickable = true
}
}
override fun setupWordpressButtonListener(wordpressUrl: String, state: String) {
ui { activity ->
button_wordpress.setOnClickListener {
startActivityForResult(
activity.oauthWebViewIntent(wordpressUrl, state),
REQUEST_CODE_FOR_OAUTH
)
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
}
}
override fun addCustomOauthServiceButton( override fun addCustomOauthServiceButton(
customOauthUrl: String, customOauthUrl: String,
state: String, state: String,
...@@ -488,11 +506,11 @@ class LoginFragment : Fragment(), LoginView { ...@@ -488,11 +506,11 @@ class LoginFragment : Fragment(), LoginView {
override fun setupFabListener() { override fun setupFabListener() {
ui { ui {
button_fab.isVisible = true button_fab.isVisible = true
button_fab.setOnClickListener({ button_fab.setOnClickListener {
button_fab.hide() button_fab.hide()
showRemainingSocialAccountsView() showRemainingSocialAccountsView()
scrollToBottom() scrollToBottom()
}) }
} }
} }
......
...@@ -104,6 +104,8 @@ class ServerFragment : Fragment(), ServerView { ...@@ -104,6 +104,8 @@ class ServerFragment : Fragment(), ServerView {
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
// reset deep link info, so user can come back and log to another server...
deepLinkInfo = null
relative_layout.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener) relative_layout.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
} }
...@@ -144,9 +146,9 @@ class ServerFragment : Fragment(), ServerView { ...@@ -144,9 +146,9 @@ class ServerFragment : Fragment(), ServerView {
hideLoading() hideLoading()
AlertDialog.Builder(it) AlertDialog.Builder(it)
.setMessage(getString(R.string.msg_ver_not_recommended, BuildConfig.RECOMMENDED_SERVER_VERSION)) .setMessage(getString(R.string.msg_ver_not_recommended, BuildConfig.RECOMMENDED_SERVER_VERSION))
.setPositiveButton(R.string.msg_ok, { _, _ -> .setPositiveButton(R.string.msg_ok) { _, _ ->
performConnect() performConnect()
}) }
.create() .create()
.show() .show()
} }
......
...@@ -56,9 +56,7 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector { ...@@ -56,9 +56,7 @@ class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
val currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) val currentFragment = supportFragmentManager.findFragmentById(R.id.fragment_container)
if (currentFragment != null) { currentFragment?.onActivityResult(requestCode, resultCode, data)
currentFragment.onActivityResult(requestCode, resultCode, data)
}
} }
override fun supportFragmentInjector(): AndroidInjector<Fragment> { override fun supportFragmentInjector(): AndroidInjector<Fragment> {
......
...@@ -68,7 +68,7 @@ class MessageInfoFragment : Fragment(), MessageInfoView { ...@@ -68,7 +68,7 @@ class MessageInfoFragment : Fragment(), MessageInfoView {
private fun setupRecyclerView() { private fun setupRecyclerView() {
// Initialize the endlessRecyclerViewScrollListener so we don't NPE at onDestroyView // Initialize the endlessRecyclerViewScrollListener so we don't NPE at onDestroyView
val linearLayoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true) val linearLayoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, true)
adapter = ReadReceiptAdapter() adapter = ReadReceiptAdapter()
linearLayoutManager.stackFromEnd = true linearLayoutManager.stackFromEnd = true
receipt_list.layoutManager = linearLayoutManager receipt_list.layoutManager = linearLayoutManager
......
...@@ -6,6 +6,7 @@ import android.view.View ...@@ -6,6 +6,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.children import androidx.core.view.children
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.ui.bottomsheet.MessageActionsBottomSheet import chat.rocket.android.chatroom.ui.bottomsheet.MessageActionsBottomSheet
...@@ -94,6 +95,7 @@ abstract class BaseViewHolder<T : BaseUiModel<*>>( ...@@ -94,6 +95,7 @@ abstract class BaseViewHolder<T : BaseUiModel<*>>(
view.context?.let { view.context?.let {
if (it is ContextThemeWrapper && it.baseContext is AppCompatActivity) { if (it is ContextThemeWrapper && it.baseContext is AppCompatActivity) {
with(it.baseContext as AppCompatActivity) { with(it.baseContext as AppCompatActivity) {
if (this.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
val actionsBottomSheet = MessageActionsBottomSheet() val actionsBottomSheet = MessageActionsBottomSheet()
actionsBottomSheet.addItems(menuItems, this@BaseViewHolder) actionsBottomSheet.addItems(menuItems, this@BaseViewHolder)
actionsBottomSheet.show(supportFragmentManager, null) actionsBottomSheet.show(supportFragmentManager, null)
...@@ -104,6 +106,7 @@ abstract class BaseViewHolder<T : BaseUiModel<*>>( ...@@ -104,6 +106,7 @@ abstract class BaseViewHolder<T : BaseUiModel<*>>(
} }
} }
} }
}
internal fun setupActionMenu(view: View) { internal fun setupActionMenu(view: View) {
if (listener.isActionsEnabled()) { if (listener.isActionsEnabled()) {
......
...@@ -18,10 +18,9 @@ import java.security.InvalidParameterException ...@@ -18,10 +18,9 @@ import java.security.InvalidParameterException
class ChatRoomAdapter( class ChatRoomAdapter(
private val roomType: String? = null, private val roomType: String? = null,
private val roomName: String? = null, private val roomName: String? = null,
private val presenter: ChatRoomPresenter? = null, private val actionSelectListener: OnActionSelected? = null,
private val enableActions: Boolean = true, private val enableActions: Boolean = true,
private val reactionListener: EmojiReactionListener? = null, private val reactionListener: EmojiReactionListener? = null
private val context: Context? = null
) : RecyclerView.Adapter<BaseViewHolder<*>>() { ) : RecyclerView.Adapter<BaseViewHolder<*>>() {
private val dataSet = ArrayList<BaseUiModel<*>>() private val dataSet = ArrayList<BaseUiModel<*>>()
...@@ -70,7 +69,7 @@ class ChatRoomAdapter( ...@@ -70,7 +69,7 @@ class ChatRoomAdapter(
BaseUiModel.ViewType.MESSAGE_REPLY -> { BaseUiModel.ViewType.MESSAGE_REPLY -> {
val view = parent.inflate(R.layout.item_message_reply) val view = parent.inflate(R.layout.item_message_reply)
MessageReplyViewHolder(view, actionsListener, reactionListener) { roomName, permalink -> MessageReplyViewHolder(view, actionsListener, reactionListener) { roomName, permalink ->
presenter?.openDirectMessage(roomName, permalink) actionSelectListener?.openDirectMessage(roomName, permalink)
} }
} }
else -> { else -> {
...@@ -212,52 +211,53 @@ class ChatRoomAdapter( ...@@ -212,52 +211,53 @@ class ChatRoomAdapter(
message.apply { message.apply {
when (item.itemId) { when (item.itemId) {
R.id.action_message_info -> { R.id.action_message_info -> {
presenter?.messageInfo(id) actionSelectListener?.showMessageInfo(id)
} }
R.id.action_message_reply -> { R.id.action_message_reply -> {
if (roomName != null && roomType != null) { if (roomName != null && roomType != null) {
presenter?.citeMessage(roomName, roomType, id, true) actionSelectListener?.citeMessage(roomName, roomType, id, true)
} }
} }
R.id.action_message_quote -> { R.id.action_message_quote -> {
if (roomName != null && roomType != null) { if (roomName != null && roomType != null) {
presenter?.citeMessage(roomName, roomType, id, false) actionSelectListener?.citeMessage(roomName, roomType, id, false)
} }
} }
R.id.action_message_copy -> { R.id.action_message_copy -> {
presenter?.copyMessage(id) actionSelectListener?.copyMessage(id)
} }
R.id.action_message_edit -> { R.id.action_message_edit -> {
presenter?.editMessage(roomId, id, message.message) actionSelectListener?.editMessage(roomId, id, message.message)
} }
R.id.action_message_star -> { R.id.action_message_star -> {
if (!item.isChecked) { actionSelectListener?.toogleStar(id, !item.isChecked)
presenter?.starMessage(id)
} else {
presenter?.unstarMessage(id)
}
} }
R.id.action_message_unpin -> { R.id.action_message_unpin -> {
if (!item.isChecked) { actionSelectListener?.tooglePin(id, !item.isChecked)
presenter?.pinMessage(id)
} else {
presenter?.unpinMessage(id)
}
} }
R.id.action_message_delete -> { R.id.action_message_delete -> {
context?.let { actionSelectListener?.deleteMessage(roomId, id)
val builder = AlertDialog.Builder(it)
builder.setTitle(it.getString(R.string.msg_delete_message))
.setMessage(it.getString(R.string.msg_delete_description))
.setPositiveButton(it.getString(R.string.msg_ok)) { _, _ -> presenter?.deleteMessage(roomId, id) }
.setNegativeButton(it.getString(R.string.msg_cancel)) { _, _ -> }
.show()
} }
R.id.action_menu_msg_react -> {
actionSelectListener?.showReactions(id)
}
else -> {
TODO("Not implemented")
} }
R.id.action_menu_msg_react -> presenter?.showReactions(id)
else -> TODO("Not implemented")
} }
} }
} }
} }
interface OnActionSelected {
fun showMessageInfo(id: String)
fun citeMessage(roomName: String, roomType: String, messageId: String, mentionAuthor: Boolean)
fun copyMessage(id: String)
fun editMessage(roomId: String, messageId: String, text: String)
fun toogleStar(id: String, star: Boolean)
fun tooglePin(id: String, pin: Boolean)
fun deleteMessage(roomId: String, id: String)
fun showReactions(id: String)
fun openDirectMessage(roomName: String, message: String)
}
} }
\ No newline at end of file
...@@ -26,20 +26,30 @@ class MessageViewHolder( ...@@ -26,20 +26,30 @@ class MessageViewHolder(
override fun bindViews(data: MessageUiModel) { override fun bindViews(data: MessageUiModel) {
with(itemView) { with(itemView) {
if (data.isFirstUnread) new_messages_notif.visibility = View.VISIBLE day_marker_layout.visibility = if (data.showDayMarker) {
else new_messages_notif.visibility = View.GONE day.text = data.currentDayMarkerText
View.VISIBLE
} else {
View.GONE
}
if (data.isFirstUnread) {
new_messages_notif.visibility = View.VISIBLE
} else {
new_messages_notif.visibility = View.GONE
}
text_message_time.text = data.time text_message_time.text = data.time
text_sender.text = data.senderName text_sender.text = data.senderName
text_content.text = data.content text_content.text = data.content
image_avatar.setImageURI(data.avatar) image_avatar.setImageURI(data.avatar)
text_content.setTextColor( text_content.setTextColor(if (data.isTemporary) Color.GRAY else Color.BLACK)
if (data.isTemporary) Color.GRAY else Color.BLACK
)
data.message.let { data.message.let {
text_edit_indicator.isVisible = !it.isSystemMessage() && it.editedBy != null text_edit_indicator.isVisible = !it.isSystemMessage() && it.editedBy != null
image_star_indicator.isVisible = it.starred?.isNotEmpty() ?: false image_star_indicator.isVisible = it.starred?.isNotEmpty() ?: false
} }
if (data.unread == null) { if (data.unread == null) {
read_receipt_view.isVisible = false read_receipt_view.isVisible = false
} else { } else {
......
package chat.rocket.android.chatroom.adapter package chat.rocket.android.chatroom.adapter
import android.net.Uri
import android.view.View import android.view.View
import androidx.core.view.isVisible import androidx.core.view.isVisible
import chat.rocket.android.chatroom.uimodel.UrlPreviewUiModel import chat.rocket.android.chatroom.uimodel.UrlPreviewUiModel
import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.android.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.util.extensions.content import chat.rocket.android.util.extensions.content
import chat.rocket.android.util.extensions.openTabbedUrl
import kotlinx.android.synthetic.main.message_url_preview.view.* import kotlinx.android.synthetic.main.message_url_preview.view.*
class UrlPreviewViewHolder(itemView: View, class UrlPreviewViewHolder(itemView: View,
...@@ -42,7 +41,7 @@ class UrlPreviewViewHolder(itemView: View, ...@@ -42,7 +41,7 @@ class UrlPreviewViewHolder(itemView: View,
private val onClickListener = { view: View -> private val onClickListener = { view: View ->
if (data != null) { if (data != null) {
view.openTabbedUrl(Uri.parse(data!!.rawData.url)) view.openTabbedUrl(data!!.rawData.url)
} }
} }
} }
\ No newline at end of file
...@@ -15,11 +15,11 @@ import android.view.Menu ...@@ -15,11 +15,11 @@ import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.TextView
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.text.bold import androidx.core.text.bold
import androidx.core.view.isVisible import androidx.core.view.isVisible
...@@ -52,9 +52,9 @@ import chat.rocket.android.emoji.EmojiParser ...@@ -52,9 +52,9 @@ import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiPickerPopup import chat.rocket.android.emoji.EmojiPickerPopup
import chat.rocket.android.emoji.EmojiReactionListener import chat.rocket.android.emoji.EmojiReactionListener
import chat.rocket.android.helper.EndlessRecyclerViewScrollListener import chat.rocket.android.helper.EndlessRecyclerViewScrollListener
import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.helper.KeyboardHelper import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.MessageParser import chat.rocket.android.helper.MessageParser
import chat.rocket.android.helper.ImageHelper
import chat.rocket.android.util.extension.asObservable import chat.rocket.android.util.extension.asObservable
import chat.rocket.android.util.extensions.circularRevealOrUnreveal import chat.rocket.android.util.extensions.circularRevealOrUnreveal
import chat.rocket.android.util.extensions.fadeIn import chat.rocket.android.util.extensions.fadeIn
...@@ -126,7 +126,8 @@ internal const val MENU_ACTION_PINNED_MESSAGES = 4 ...@@ -126,7 +126,8 @@ internal const val MENU_ACTION_PINNED_MESSAGES = 4
internal const val MENU_ACTION_FAVORITE_MESSAGES = 5 internal const val MENU_ACTION_FAVORITE_MESSAGES = 5
internal const val MENU_ACTION_FILES = 6 internal const val MENU_ACTION_FILES = 6
class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener { class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiReactionListener,
ChatRoomAdapter.OnActionSelected {
@Inject @Inject
lateinit var presenter: ChatRoomPresenter lateinit var presenter: ChatRoomPresenter
@Inject @Inject
...@@ -200,6 +201,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -200,6 +201,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} else { } else {
requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" } requireNotNull(bundle) { "no arguments supplied when the fragment was instantiated" }
} }
adapter = ChatRoomAdapter(chatRoomType, chatRoomName, this,
reactionListener = this)
} }
override fun onCreateView( override fun onCreateView(
...@@ -295,14 +299,30 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -295,14 +299,30 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
adapter.clearData() adapter.clearData()
} }
if (dataSet.isNotEmpty()) {
var prevMsgModel = dataSet[0]
// track the message sent immediately after the current message // track the message sent immediately after the current message
var prevMessageUiModel: MessageUiModel? = null var prevMessageUiModel: MessageUiModel? = null
// Checking for all messages to assign true to the required showDayMaker
// Loop over received messages to determine first unread // Loop over received messages to determine first unread
var firstUnread = false
for (i in dataSet.indices) { for (i in dataSet.indices) {
val msgModel = dataSet[i] val msgModel = dataSet[i]
if (msgModel is MessageUiModel) { if (i > 0) {
prevMsgModel = dataSet[i - 1]
}
val currentDayMarkerText = msgModel.currentDayMarkerText
val previousDayMarkerText = prevMsgModel.currentDayMarkerText
println("$previousDayMarkerText then $currentDayMarkerText")
if (previousDayMarkerText != currentDayMarkerText) {
prevMsgModel.showDayMarker = true
}
if (!firstUnread && msgModel is MessageUiModel) {
val msg = msgModel.rawData val msg = msgModel.rawData
if (msg.timestamp < chatRoomLastSeen) { if (msg.timestamp < chatRoomLastSeen) {
// This message was sent before the last seen of the room. Hence, it was seen. // This message was sent before the last seen of the room. Hence, it was seen.
...@@ -310,20 +330,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -310,20 +330,15 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
if (prevMessageUiModel != null) { if (prevMessageUiModel != null) {
prevMessageUiModel.isFirstUnread = true prevMessageUiModel.isFirstUnread = true
} }
break // Found first unread message.
firstUnread = true
} }
prevMessageUiModel = msgModel prevMessageUiModel = msgModel
} }
} }
}
if (recycler_view.adapter == null) { if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(
chatRoomType,
chatRoomName,
presenter,
reactionListener = this@ChatRoomFragment,
context = context
)
recycler_view.adapter = adapter recycler_view.adapter = adapter
if (dataSet.size >= 30) { if (dataSet.size >= 30) {
recycler_view.addOnScrollListener(endlessRecyclerViewScrollListener) recycler_view.addOnScrollListener(endlessRecyclerViewScrollListener)
...@@ -427,7 +442,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -427,7 +442,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} else { } else {
if (dy < 0 && !button_fab.isVisible) { if (dy < 0 && !button_fab.isVisible) {
button_fab.show() button_fab.show()
if (newMessageCount !=0) text_count.isVisible = true if (newMessageCount != 0) text_count.isVisible = true
} }
} }
} }
...@@ -492,8 +507,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -492,8 +507,7 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
text_count.text = "99+" text_count.text = "99+"
text_count.isVisible = true text_count.isVisible = true
} } else if (!button_fab.isVisible)
else if (!button_fab.isVisible)
recycler_view.scrollToPosition(0) recycler_view.scrollToPosition(0)
verticalScrollOffset.set(0) verticalScrollOffset.set(0)
empty_chat_view.isVisible = adapter.itemCount == 0 empty_chat_view.isVisible = adapter.itemCount == 0
...@@ -950,4 +964,55 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -950,4 +964,55 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private fun setupToolbar(toolbarTitle: String) { private fun setupToolbar(toolbarTitle: String) {
(activity as ChatRoomActivity).showToolbarTitle(toolbarTitle) (activity as ChatRoomActivity).showToolbarTitle(toolbarTitle)
} }
override fun showMessageInfo(id: String) {
presenter.messageInfo(id)
}
override fun citeMessage(roomName: String, roomType: String, messageId: String, mentionAuthor: Boolean) {
presenter.citeMessage(roomName, roomType, messageId, mentionAuthor)
}
override fun copyMessage(id: String) {
presenter.copyMessage(id)
}
override fun editMessage(roomId: String, messageId: String, text: String) {
presenter.editMessage(roomId, messageId, text)
}
override fun toogleStar(id: String, star: Boolean) {
if (star) {
presenter.starMessage(id)
} else {
presenter.unstarMessage(id)
}
}
override fun tooglePin(id: String, pin: Boolean) {
if (pin) {
presenter.pinMessage(id)
} else {
presenter.unpinMessage(id)
}
}
override fun deleteMessage(roomId: String, id: String) {
ui {
val builder = AlertDialog.Builder(it)
builder.setTitle(it.getString(R.string.msg_delete_message))
.setMessage(it.getString(R.string.msg_delete_description))
.setPositiveButton(it.getString(R.string.msg_ok)) { _, _ -> presenter.deleteMessage(roomId, id) }
.setNegativeButton(it.getString(R.string.msg_cancel)) { _, _ -> }
.show()
}
}
override fun showReactions(id: String) {
presenter.showReactions(id)
}
override fun openDirectMessage(roomName: String, message: String) {
presenter.openDirectMessage(roomName, message)
}
} }
...@@ -14,20 +14,18 @@ import kotlinx.android.synthetic.main.message_bottomsheet.* ...@@ -14,20 +14,18 @@ import kotlinx.android.synthetic.main.message_bottomsheet.*
class MessageActionsBottomSheet : BottomSheetDialogFragment() { class MessageActionsBottomSheet : BottomSheetDialogFragment() {
private lateinit var adapter: MessageActionAdapter private val adapter = MessageActionAdapter()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.message_bottomsheet, container, false) return inflater.inflate(R.layout.message_bottomsheet, container, false)
} }
fun addItems(items: List<MenuItem>, itemClickListener: MenuItem.OnMenuItemClickListener) { fun addItems(items: List<MenuItem>, itemClickListener: MenuItem.OnMenuItemClickListener) {
adapter = MessageActionAdapter()
adapter.addItems(items, ActionItemClickListener(dismissAction = { dismiss() }, adapter.addItems(items, ActionItemClickListener(dismissAction = { dismiss() },
itemClickListener = itemClickListener)) itemClickListener = itemClickListener))
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bottomsheet_recycler_view.layoutManager = LinearLayoutManager(context) bottomsheet_recycler_view.layoutManager = LinearLayoutManager(context)
bottomsheet_recycler_view.adapter = adapter bottomsheet_recycler_view.adapter = adapter
} }
...@@ -58,6 +56,7 @@ class MessageActionsBottomSheet : BottomSheetDialogFragment() { ...@@ -58,6 +56,7 @@ class MessageActionsBottomSheet : BottomSheetDialogFragment() {
this.itemClickListener = itemClickListener this.itemClickListener = itemClickListener
menuItems.clear() menuItems.clear()
menuItems.addAll(items) menuItems.addAll(items)
notifyDataSetChanged()
} }
} }
......
...@@ -16,7 +16,9 @@ data class AudioAttachmentUiModel( ...@@ -16,7 +16,9 @@ data class AudioAttachmentUiModel(
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseFileAttachmentUiModel<AudioAttachment> { ) : BaseFileAttachmentUiModel<AudioAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.AUDIO_ATTACHMENT.viewType get() = BaseUiModel.ViewType.AUDIO_ATTACHMENT.viewType
......
...@@ -18,7 +18,9 @@ data class AuthorAttachmentUiModel( ...@@ -18,7 +18,9 @@ data class AuthorAttachmentUiModel(
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseAttachmentUiModel<AuthorAttachment> { ) : BaseAttachmentUiModel<AuthorAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.AUTHOR_ATTACHMENT.viewType get() = BaseUiModel.ViewType.AUTHOR_ATTACHMENT.viewType
......
...@@ -14,6 +14,8 @@ interface BaseUiModel<out T> { ...@@ -14,6 +14,8 @@ interface BaseUiModel<out T> {
var preview: Message? var preview: Message?
var isTemporary: Boolean var isTemporary: Boolean
var unread: Boolean? var unread: Boolean?
var currentDayMarkerText: String
var showDayMarker: Boolean
var menuItemsToHide: MutableList<Int> var menuItemsToHide: MutableList<Int>
enum class ViewType(val viewType: Int) { enum class ViewType(val viewType: Int) {
......
...@@ -17,7 +17,9 @@ data class ColorAttachmentUiModel( ...@@ -17,7 +17,9 @@ data class ColorAttachmentUiModel(
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean?, override var unread: Boolean?,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseAttachmentUiModel<ColorAttachment> { ) : BaseAttachmentUiModel<ColorAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.COLOR_ATTACHMENT.viewType get() = BaseUiModel.ViewType.COLOR_ATTACHMENT.viewType
......
...@@ -16,7 +16,9 @@ data class GenericFileAttachmentUiModel( ...@@ -16,7 +16,9 @@ data class GenericFileAttachmentUiModel(
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseFileAttachmentUiModel<GenericFileAttachment> { ) : BaseFileAttachmentUiModel<GenericFileAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.GENERIC_FILE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.GENERIC_FILE_ATTACHMENT.viewType
......
...@@ -18,7 +18,9 @@ data class ImageAttachmentUiModel( ...@@ -18,7 +18,9 @@ data class ImageAttachmentUiModel(
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseFileAttachmentUiModel<ImageAttachment> { ) : BaseFileAttachmentUiModel<ImageAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.IMAGE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.IMAGE_ATTACHMENT.viewType
......
...@@ -17,7 +17,9 @@ data class MessageAttachmentUiModel( ...@@ -17,7 +17,9 @@ data class MessageAttachmentUiModel(
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseUiModel<Message> { ) : BaseUiModel<Message> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.MESSAGE_ATTACHMENT.viewType get() = BaseUiModel.ViewType.MESSAGE_ATTACHMENT.viewType
......
...@@ -13,7 +13,9 @@ data class MessageReplyUiModel( ...@@ -13,7 +13,9 @@ data class MessageReplyUiModel(
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override val message: Message, override val message: Message,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseUiModel<MessageReply> { ) : BaseUiModel<MessageReply> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.MESSAGE_REPLY.viewType get() = BaseUiModel.ViewType.MESSAGE_REPLY.viewType
......
...@@ -12,6 +12,8 @@ data class MessageUiModel( ...@@ -12,6 +12,8 @@ data class MessageUiModel(
override val senderName: CharSequence, override val senderName: CharSequence,
override val content: CharSequence, override val content: CharSequence,
override val isPinned: Boolean, override val isPinned: Boolean,
override var currentDayMarkerText: String,
override var showDayMarker: Boolean,
override var reactions: List<ReactionUiModel>, override var reactions: List<ReactionUiModel>,
override var nextDownStreamMessage: BaseUiModel<*>? = null, override var nextDownStreamMessage: BaseUiModel<*>? = null,
override var preview: Message? = null, override var preview: Message? = null,
......
...@@ -265,6 +265,10 @@ class UiModelMapper @Inject constructor( ...@@ -265,6 +265,10 @@ class UiModelMapper @Inject constructor(
val roomName = val roomName =
if (settings.useRealName() && name != null) name else message.sender?.username ?: "" if (settings.useRealName() && name != null) name else message.sender?.username ?: ""
val permalink = messageHelper.createPermalink(message, chatRoom) val permalink = messageHelper.createPermalink(message, chatRoom)
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
return MessageReplyUiModel( return MessageReplyUiModel(
messageId = message.id, messageId = message.id,
isTemporary = false, isTemporary = false,
...@@ -273,7 +277,9 @@ class UiModelMapper @Inject constructor( ...@@ -273,7 +277,9 @@ class UiModelMapper @Inject constructor(
preview = mapMessagePreview(message), preview = mapMessagePreview(message),
rawData = MessageReply(roomName = roomName, permalink = permalink), rawData = MessageReply(roomName = roomName, permalink = permalink),
nextDownStreamMessage = null, nextDownStreamMessage = null,
unread = message.unread unread = message.unread,
currentDayMarkerText = dayMarkerText,
showDayMarker = false
) )
} }
...@@ -285,8 +291,12 @@ class UiModelMapper @Inject constructor( ...@@ -285,8 +291,12 @@ class UiModelMapper @Inject constructor(
val title = url.meta?.title val title = url.meta?.title
val description = url.meta?.description val description = url.meta?.description
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
return UrlPreviewUiModel(message, url, message.id, title, hostname, description, thumb, return UrlPreviewUiModel(message, url, message.id, title, hostname, description, thumb,
getReactions(message), preview = message.copy(message = url.url), unread = message.unread) getReactions(message), preview = message.copy(message = url.url), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText)
} }
private fun mapAttachment(message: Message, attachment: Attachment): BaseUiModel<*>? { private fun mapAttachment(message: Message, attachment: Attachment): BaseUiModel<*>? {
...@@ -304,10 +314,14 @@ class UiModelMapper @Inject constructor( ...@@ -304,10 +314,14 @@ class UiModelMapper @Inject constructor(
val content = stripMessageQuotes(message) val content = stripMessageQuotes(message)
val id = attachmentId(message, attachment) val id = attachmentId(message, attachment)
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
ColorAttachmentUiModel(attachmentUrl = url, id = id, color = color.color, ColorAttachmentUiModel(attachmentUrl = url, id = id, color = color.color,
text = text, message = message, rawData = attachment, text = text, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message), messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message), unread = message.unread) preview = message.copy(message = content.message), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText)
} }
} }
...@@ -332,10 +346,14 @@ class UiModelMapper @Inject constructor( ...@@ -332,10 +346,14 @@ class UiModelMapper @Inject constructor(
} }
val id = attachmentId(message, attachment) val id = attachmentId(message, attachment)
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
AuthorAttachmentUiModel(attachmentUrl = url, id = id, name = authorName, AuthorAttachmentUiModel(attachmentUrl = url, id = id, name = authorName,
icon = authorIcon, fields = fieldsText, message = message, rawData = attachment, icon = authorIcon, fields = fieldsText, message = message, rawData = attachment,
messageId = message.id, reactions = getReactions(message), messageId = message.id, reactions = getReactions(message),
preview = message.copy(message = content.message), unread = message.unread) preview = message.copy(message = content.message), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText)
} }
} }
...@@ -349,11 +367,17 @@ class UiModelMapper @Inject constructor( ...@@ -349,11 +367,17 @@ class UiModelMapper @Inject constructor(
is GenericFileAttachment -> context.getString(R.string.msg_preview_file) is GenericFileAttachment -> context.getString(R.string.msg_preview_file)
else -> attachment.text ?: "" else -> attachment.text ?: ""
} }
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val content = stripMessageQuotes(message) val content = stripMessageQuotes(message)
return MessageAttachmentUiModel(message = content, rawData = message, return MessageAttachmentUiModel(message = content, rawData = message,
messageId = message.id, time = time, senderName = attachmentAuthor, messageId = message.id, time = time, senderName = attachmentAuthor,
content = attachmentText, isPinned = message.pinned, reactions = getReactions(message), content = attachmentText, isPinned = message.pinned, reactions = getReactions(message),
preview = message.copy(message = content.message), unread = message.unread) preview = message.copy(message = content.message), unread = message.unread,
currentDayMarkerText = dayMarkerText, showDayMarker = false)
} }
private fun mapFileAttachment(message: Message, attachment: FileAttachment): BaseUiModel<*>? { private fun mapFileAttachment(message: Message, attachment: FileAttachment): BaseUiModel<*>? {
...@@ -362,19 +386,27 @@ class UiModelMapper @Inject constructor( ...@@ -362,19 +386,27 @@ class UiModelMapper @Inject constructor(
val attachmentText = attachmentText(attachment) val attachmentText = attachmentText(attachment)
val attachmentDescription = attachmentDescription(attachment) val attachmentDescription = attachmentDescription(attachment)
val id = attachmentId(message, attachment) val id = attachmentId(message, attachment)
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
return when (attachment) { return when (attachment) {
is ImageAttachment -> ImageAttachmentUiModel(message, attachment, message.id, is ImageAttachment -> ImageAttachmentUiModel(message, attachment, message.id,
attachmentUrl, attachmentTitle, attachmentText, attachmentDescription, id, getReactions(message), attachmentUrl, attachmentTitle, attachmentText, attachmentDescription, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_photo)), unread = message.unread) preview = message.copy(message = context.getString(R.string.msg_preview_photo)), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText)
is VideoAttachment -> VideoAttachmentUiModel(message, attachment, message.id, is VideoAttachment -> VideoAttachmentUiModel(message, attachment, message.id,
attachmentUrl, attachmentTitle, id, getReactions(message), attachmentUrl, attachmentTitle, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_video)), unread = message.unread) preview = message.copy(message = context.getString(R.string.msg_preview_video)), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText)
is AudioAttachment -> AudioAttachmentUiModel(message, attachment, message.id, is AudioAttachment -> AudioAttachmentUiModel(message, attachment, message.id,
attachmentUrl, attachmentTitle, id, getReactions(message), attachmentUrl, attachmentTitle, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_audio)), unread = message.unread) preview = message.copy(message = context.getString(R.string.msg_preview_audio)), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText)
is GenericFileAttachment -> GenericFileAttachmentUiModel(message, attachment, is GenericFileAttachment -> GenericFileAttachmentUiModel(message, attachment,
message.id, attachmentUrl, attachmentTitle, id, getReactions(message), message.id, attachmentUrl, attachmentTitle, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_file)), unread = message.unread) preview = message.copy(message = context.getString(R.string.msg_preview_file)), unread = message.unread,
showDayMarker = false, currentDayMarkerText = dayMarkerText)
else -> null else -> null
} }
} }
...@@ -434,11 +466,15 @@ class UiModelMapper @Inject constructor( ...@@ -434,11 +466,15 @@ class UiModelMapper @Inject constructor(
null null
} }
val localDateTime = DateTimeHelper.getLocalDateTime(message.timestamp)
val dayMarkerText = DateTimeHelper.getFormattedDateForMessages(localDateTime, context)
val content = getContent(stripMessageQuotes(message)) val content = getContent(stripMessageQuotes(message))
MessageUiModel(message = stripMessageQuotes(message), rawData = message, MessageUiModel(message = stripMessageQuotes(message), rawData = message,
messageId = message.id, avatar = avatar!!, time = time, senderName = sender, messageId = message.id, avatar = avatar!!, time = time, senderName = sender,
content = content, isPinned = message.pinned, reactions = getReactions(message), content = content, isPinned = message.pinned, currentDayMarkerText = dayMarkerText,
isFirstUnread = false, preview = preview, isTemporary = isTemp, unread = unread) showDayMarker = false, reactions = getReactions(message), isFirstUnread = false,
preview = preview, isTemporary = isTemp, unread = unread)
} }
private fun mapMessagePreview(message: Message): Message { private fun mapMessagePreview(message: Message): Message {
......
...@@ -17,7 +17,9 @@ data class UrlPreviewUiModel( ...@@ -17,7 +17,9 @@ data class UrlPreviewUiModel(
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseUiModel<Url> { ) : BaseUiModel<Url> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.URL_PREVIEW.viewType get() = BaseUiModel.ViewType.URL_PREVIEW.viewType
......
...@@ -16,7 +16,9 @@ data class VideoAttachmentUiModel( ...@@ -16,7 +16,9 @@ data class VideoAttachmentUiModel(
override var preview: Message? = null, override var preview: Message? = null,
override var isTemporary: Boolean = false, override var isTemporary: Boolean = false,
override var unread: Boolean? = null, override var unread: Boolean? = null,
override var menuItemsToHide: MutableList<Int> = mutableListOf() override var menuItemsToHide: MutableList<Int> = mutableListOf(),
override var currentDayMarkerText: String,
override var showDayMarker: Boolean
) : BaseFileAttachmentUiModel<VideoAttachment> { ) : BaseFileAttachmentUiModel<VideoAttachment> {
override val viewType: Int override val viewType: Int
get() = BaseUiModel.ViewType.VIDEO_ATTACHMENT.viewType get() = BaseUiModel.ViewType.VIDEO_ATTACHMENT.viewType
......
...@@ -249,7 +249,7 @@ class DatabaseManager(val context: Application, ...@@ -249,7 +249,7 @@ class DatabaseManager(val context: Application,
id = roomId, id = roomId,
subscriptionId = id, subscriptionId = id,
type = type.toString(), type = type.toString(),
name = name ?: "", name = name ?: throw NullPointerException(), // this should be filtered on the SDK
fullname = fullName ?: chatRoom.fullname, fullname = fullName ?: chatRoom.fullname,
userId = userId ?: chatRoom.userId, userId = userId ?: chatRoom.userId,
readonly = readonly ?: chatRoom.readonly, readonly = readonly ?: chatRoom.readonly,
...@@ -330,7 +330,7 @@ class DatabaseManager(val context: Application, ...@@ -330,7 +330,7 @@ class DatabaseManager(val context: Application,
id = room.id, id = room.id,
subscriptionId = subscription.id, subscriptionId = subscription.id,
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
fullname = subscription.fullName ?: room.fullName, fullname = subscription.fullName ?: room.fullName,
userId = userId, userId = userId,
ownerId = room.user?.id, ownerId = room.user?.id,
...@@ -436,6 +436,7 @@ private fun String.databaseName(): String { ...@@ -436,6 +436,7 @@ private fun String.databaseName(): String {
val tmp = this.removePrefix("https://") val tmp = this.removePrefix("https://")
.removePrefix("http://") .removePrefix("http://")
.removeTrailingSlash() .removeTrailingSlash()
.replace("/","-")
.replace(".", "_") .replace(".", "_")
return "$tmp.db" return "$tmp.db"
......
...@@ -35,7 +35,7 @@ private const val INTENT_CHAT_ROOM_ID = "chat_room_id" ...@@ -35,7 +35,7 @@ private const val INTENT_CHAT_ROOM_ID = "chat_room_id"
class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView { class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
private lateinit var adapter: ChatRoomAdapter private val adapter = ChatRoomAdapter(enableActions = false)
@Inject @Inject
lateinit var presenter: FavoriteMessagesPresenter lateinit var presenter: FavoriteMessagesPresenter
...@@ -66,7 +66,6 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView { ...@@ -66,7 +66,6 @@ class FavoriteMessagesFragment : Fragment(), FavoriteMessagesView {
override fun showFavoriteMessages(favoriteMessages: List<BaseUiModel<*>>) { override fun showFavoriteMessages(favoriteMessages: List<BaseUiModel<*>>) {
ui { ui {
if (recycler_view.adapter == null) { if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(enableActions = false)
recycler_view.adapter = adapter recycler_view.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context) val linearLayoutManager = LinearLayoutManager(context)
recycler_view.layoutManager = linearLayoutManager recycler_view.layoutManager = linearLayoutManager
......
...@@ -5,21 +5,19 @@ import android.content.Context ...@@ -5,21 +5,19 @@ import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.graphics.RectF import android.graphics.RectF
import android.net.Uri
import androidx.core.content.res.ResourcesCompat
import android.text.Spanned import android.text.Spanned
import android.text.style.ClickableSpan import android.text.style.ClickableSpan
import android.text.style.ReplacementSpan import android.text.style.ReplacementSpan
import android.text.style.StyleSpan
import android.util.Patterns import android.util.Patterns
import android.view.View import android.view.View
import androidx.core.content.res.ResourcesCompat
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.android.emoji.EmojiParser import chat.rocket.android.emoji.EmojiParser
import chat.rocket.android.emoji.EmojiRepository import chat.rocket.android.emoji.EmojiRepository
import chat.rocket.android.emoji.EmojiTypefaceSpan import chat.rocket.android.emoji.EmojiTypefaceSpan
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.util.extensions.openTabbedUrl
import chat.rocket.common.model.SimpleUser import chat.rocket.common.model.SimpleUser
import chat.rocket.core.model.Message import chat.rocket.core.model.Message
import org.commonmark.node.AbstractVisitor import org.commonmark.node.AbstractVisitor
...@@ -159,7 +157,7 @@ class MessageParser @Inject constructor( ...@@ -159,7 +157,7 @@ class MessageParser @Inject constructor(
if (node is ListItem) { if (node is ListItem) {
newLine() newLine()
builder.append("$number$delimiter ") builder.append("$number$delimiter ")
super.visit(node.firstChild as Paragraph) super.visitChildren(node)
newLine() newLine()
} }
number++ number++
...@@ -187,7 +185,7 @@ class MessageParser @Inject constructor( ...@@ -187,7 +185,7 @@ class MessageParser @Inject constructor(
if (!link.startsWith("@") && link !in consumed) { if (!link.startsWith("@") && link !in consumed) {
builder.setSpan(object : ClickableSpan() { builder.setSpan(object : ClickableSpan() {
override fun onClick(view: View) { override fun onClick(view: View) {
view.openTabbedUrl(getUri(link)) view.openTabbedUrl(link)
} }
}, matcher.start(0), matcher.end(0)) }, matcher.start(0), matcher.end(0))
consumed.add(link) consumed.add(link)
...@@ -195,14 +193,6 @@ class MessageParser @Inject constructor( ...@@ -195,14 +193,6 @@ class MessageParser @Inject constructor(
} }
visitChildren(text) visitChildren(text)
} }
private fun getUri(link: String): Uri {
val uri = Uri.parse(link)
if (uri.scheme == null) {
return Uri.parse("http://$link")
}
return uri
}
} }
class MentionSpan( class MentionSpan(
......
...@@ -92,6 +92,59 @@ object OauthHelper { ...@@ -92,6 +92,59 @@ object OauthHelper {
"&scope=email" "&scope=email"
} }
/**
* Returns the WordPress-Com Oauth URL.
*
* @param clientId The WordPress-Com client ID.
* @param serverUrl The server URL.
* @param state An unguessable random string used to protect against forgery attacks.
* @return The WordPress-Com Oauth URL.
*/
fun getWordpressComOauthUrl(clientId: String, serverUrl: String, state: String): String {
return "https://public-api.wordpress.com/oauth2/authorize" +
"?client_id=$clientId" +
"&redirect_uri=${serverUrl.removeTrailingSlash()}/_oauth/wordpress?close" +
"&state=$state" +
"&response_type=code" +
"&scope=auth"
}
/**
* Returns the WordPress custom Oauth URL.
*
* @param host The WordPress custom OAuth host.
* @param authorizePath The WordPress custom OAuth authorization path.
* @param clientId The WordPress custom OAuth client ID.
* @param serverUrl The server URL.
* @param serviceName The service name.
* @param state An unguessable random string used to protect against forgery attacks.
* @param scope The WordPress custom OAuth scope.
* @return The WordPress custom Oauth URL.
*/
fun getWordpressCustomOauthUrl(
host: String,
authorizePath: String,
clientId: String,
serverUrl: String,
serviceName: String,
state: String,
scope: String
): String {
(authorizePath +
"?client_id=$clientId" +
"&redirect_uri=${serverUrl.removeTrailingSlash()}/_oauth/$serviceName?close" +
"&state=$state" +
"&scope=$scope" +
"&response_type=code"
).let {
return if (it.contains(host)) {
it
} else {
host + it
}
}
}
/** /**
* Returns the Custom Oauth URL. * Returns the Custom Oauth URL.
* *
......
...@@ -5,6 +5,7 @@ import chat.rocket.android.db.DatabaseManagerFactory ...@@ -5,6 +5,7 @@ import chat.rocket.android.db.DatabaseManagerFactory
import chat.rocket.android.infrastructure.LocalRepository import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.main.uimodel.NavHeaderUiModel import chat.rocket.android.main.uimodel.NavHeaderUiModel
import chat.rocket.android.main.uimodel.NavHeaderUiModelMapper import chat.rocket.android.main.uimodel.NavHeaderUiModelMapper
import chat.rocket.android.push.GroupedPush
import chat.rocket.android.server.domain.GetAccountsInteractor import chat.rocket.android.server.domain.GetAccountsInteractor
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
...@@ -52,6 +53,7 @@ class MainPresenter @Inject constructor( ...@@ -52,6 +53,7 @@ class MainPresenter @Inject constructor(
private val getAccountsInteractor: GetAccountsInteractor, private val getAccountsInteractor: GetAccountsInteractor,
private val removeAccountInteractor: RemoveAccountInteractor, private val removeAccountInteractor: RemoveAccountInteractor,
private val factory: RocketChatClientFactory, private val factory: RocketChatClientFactory,
private val groupedPush: GroupedPush,
dbManagerFactory: DatabaseManagerFactory, dbManagerFactory: DatabaseManagerFactory,
getSettingsInteractor: GetSettingsInteractor, getSettingsInteractor: GetSettingsInteractor,
managerFactory: ConnectionManagerFactory managerFactory: ConnectionManagerFactory
...@@ -152,7 +154,7 @@ class MainPresenter @Inject constructor( ...@@ -152,7 +154,7 @@ class MainPresenter @Inject constructor(
} }
fun connect() { fun connect() {
launch { refreshSettingsInteractor.refresh(currentServer) } refreshSettingsInteractor.refreshAsync(currentServer)
manager.connect() manager.connect()
} }
...@@ -176,7 +178,7 @@ class MainPresenter @Inject constructor( ...@@ -176,7 +178,7 @@ class MainPresenter @Inject constructor(
fun changeDefaultStatus(userStatus: UserStatus) { fun changeDefaultStatus(userStatus: UserStatus) {
launchUI(strategy) { launchUI(strategy) {
try { try {
client.setDefaultStatus(userStatus) manager.setDefaultStatus(userStatus)
view.showUserStatus(userStatus) view.showUserStatus(userStatus)
} catch (ex: RocketChatException) { } catch (ex: RocketChatException) {
ex.message?.let { ex.message?.let {
...@@ -232,4 +234,12 @@ class MainPresenter @Inject constructor( ...@@ -232,4 +234,12 @@ class MainPresenter @Inject constructor(
private fun updateMyself(myself: Myself) = private fun updateMyself(myself: Myself) =
view.setupUserAccountInfo(navHeaderMapper.mapToUiModel(myself)) view.setupUserAccountInfo(navHeaderMapper.mapToUiModel(myself))
fun clearNotificationsForChatroom(chatRoomId: String?) {
if (chatRoomId == null) return
groupedPush.hostToPushMessageList[currentServer]?.let { list ->
list.removeAll { it.info.roomId == chatRoomId }
}
}
} }
...@@ -5,13 +5,13 @@ import android.app.Activity ...@@ -5,13 +5,13 @@ import android.app.Activity
import android.app.AlertDialog import android.app.AlertDialog
import android.app.ProgressDialog import android.app.ProgressDialog
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.Gravity import android.view.Gravity
import android.view.MenuItem import android.view.MenuItem
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import chat.rocket.android.BuildConfig import chat.rocket.android.BuildConfig
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.main.adapter.AccountsAdapter import chat.rocket.android.main.adapter.AccountsAdapter
...@@ -55,7 +55,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -55,7 +55,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
private var expanded = false private var expanded = false
private val headerLayout by lazy { view_navigation.getHeaderView(0) } private val headerLayout by lazy { view_navigation.getHeaderView(0) }
private var chatRoomId: String? = null private var chatRoomId: String? = null
private var progressDialog : ProgressDialog? = null private var progressDialog: ProgressDialog? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this) AndroidInjection.inject(this)
...@@ -74,6 +74,9 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -74,6 +74,9 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID) chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID)
println("ChatRoomId: $chatRoomId")
presenter.clearNotificationsForChatroom(chatRoomId)
presenter.connect() presenter.connect()
presenter.loadServerAccounts() presenter.loadServerAccounts()
presenter.loadCurrentInfo() presenter.loadCurrentInfo()
...@@ -169,7 +172,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -169,7 +172,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
} }
headerLayout.image_avatar.setOnClickListener { headerLayout.image_avatar.setOnClickListener {
view_navigation.menu.findItem(R.id.action_update_profile).isChecked = true view_navigation.menu.findItem(R.id.action_profile).isChecked = true
presenter.toUserProfile() presenter.toUserProfile()
drawer_layout.closeDrawer(Gravity.START) drawer_layout.closeDrawer(Gravity.START)
} }
...@@ -218,19 +221,20 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, ...@@ -218,19 +221,20 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector,
private fun setupToolbar() { private fun setupToolbar() {
setSupportActionBar(toolbar) setSupportActionBar(toolbar)
toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp)
toolbar.setNavigationOnClickListener {
openDrawer()
}
} }
private fun setupNavigationView() { fun setupNavigationView() {
view_navigation.setNavigationItemSelectedListener { menuItem -> view_navigation.setNavigationItemSelectedListener { menuItem ->
menuItem.isChecked = true menuItem.isChecked = true
closeDrawer() closeDrawer()
onNavDrawerItemSelected(menuItem) onNavDrawerItemSelected(menuItem)
true true
} }
toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp)
toolbar.setNavigationOnClickListener {
openDrawer()
}
} }
private fun onNavDrawerItemSelected(menuItem: MenuItem) { private fun onNavDrawerItemSelected(menuItem: MenuItem) {
......
...@@ -36,7 +36,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id" ...@@ -36,7 +36,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
class MentionsFragment : Fragment(), MentionsView { class MentionsFragment : Fragment(), MentionsView {
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
private lateinit var adapter: ChatRoomAdapter private val adapter = ChatRoomAdapter(enableActions = false)
@Inject @Inject
lateinit var presenter: MentionsPresenter lateinit var presenter: MentionsPresenter
...@@ -68,7 +68,6 @@ class MentionsFragment : Fragment(), MentionsView { ...@@ -68,7 +68,6 @@ class MentionsFragment : Fragment(), MentionsView {
override fun showMentions(mentions: List<BaseUiModel<*>>) { override fun showMentions(mentions: List<BaseUiModel<*>>) {
ui { ui {
if (recycler_view.adapter == null) { if (recycler_view.adapter == null) {
adapter = ChatRoomAdapter(enableActions = false)
recycler_view.adapter = adapter recycler_view.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context) val linearLayoutManager = LinearLayoutManager(context)
......
...@@ -36,7 +36,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id" ...@@ -36,7 +36,7 @@ private const val BUNDLE_CHAT_ROOM_ID = "chat_room_id"
class PinnedMessagesFragment : Fragment(), PinnedMessagesView { class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
private lateinit var adapter: ChatRoomAdapter private val adapter = ChatRoomAdapter(enableActions = false)
@Inject @Inject
lateinit var presenter: PinnedMessagesPresenter lateinit var presenter: PinnedMessagesPresenter
...@@ -68,7 +68,6 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView { ...@@ -68,7 +68,6 @@ class PinnedMessagesFragment : Fragment(), PinnedMessagesView {
override fun showPinnedMessages(pinnedMessages: List<BaseUiModel<*>>) { override fun showPinnedMessages(pinnedMessages: List<BaseUiModel<*>>) {
ui { ui {
if (recycler_view_pinned.adapter == null) { if (recycler_view_pinned.adapter == null) {
adapter = ChatRoomAdapter(enableActions = false)
recycler_view_pinned.adapter = adapter recycler_view_pinned.adapter = adapter
val linearLayoutManager = LinearLayoutManager(context) val linearLayoutManager = LinearLayoutManager(context)
......
...@@ -18,6 +18,7 @@ import androidx.core.app.NotificationManagerCompat ...@@ -18,6 +18,7 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.app.RemoteInput import androidx.core.app.RemoteInput
import android.text.Html import android.text.Html
import android.text.Spanned import android.text.Spanned
import androidx.core.content.ContextCompat
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.main.ui.MainActivity import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.server.domain.GetAccountInteractor import chat.rocket.android.server.domain.GetAccountInteractor
...@@ -36,10 +37,6 @@ import java.util.* ...@@ -36,10 +37,6 @@ import java.util.*
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject import javax.inject.Inject
/**
* Refer to: https://github.com/RocketChat/Rocket.Chat.Android/blob/9e846b7fde8fe0c74b9e0117c37ce49293308db5/app/src/main/java/chat/rocket/android/push/PushManager.kt
* for old source code.
*/
class PushManager @Inject constructor( class PushManager @Inject constructor(
private val groupedPushes: GroupedPush, private val groupedPushes: GroupedPush,
private val manager: NotificationManager, private val manager: NotificationManager,
...@@ -80,7 +77,7 @@ class PushManager @Inject constructor( ...@@ -80,7 +77,7 @@ class PushManager @Inject constructor(
showNotification(pushMessage) showNotification(pushMessage)
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.d(ex, "Error parsing PUSH message: $data") Timber.e(ex, "Error parsing PUSH message: $data")
ex.printStackTrace() ex.printStackTrace()
} }
} }
...@@ -101,7 +98,7 @@ class PushManager @Inject constructor( ...@@ -101,7 +98,7 @@ class PushManager @Inject constructor(
val groupTuple = getGroupForHost(host) val groupTuple = getGroupForHost(host)
groupTuple.second.incrementAndGet() groupTuple.second.incrementAndGet()
val notIdListForHostname: MutableList<PushMessage>? = groupedPushes.hostToPushMessageList.get(host) val notIdListForHostname: MutableList<PushMessage>? = groupedPushes.hostToPushMessageList[host]
if (notIdListForHostname == null) { if (notIdListForHostname == null) {
groupedPushes.hostToPushMessageList[host] = arrayListOf(pushMessage) groupedPushes.hostToPushMessageList[host] = arrayListOf(pushMessage)
} else { } else {
...@@ -365,14 +362,14 @@ class PushManager @Inject constructor( ...@@ -365,14 +362,14 @@ class PushManager @Inject constructor(
val res = context.resources val res = context.resources
val smallIcon = res.getIdentifier( val smallIcon = res.getIdentifier(
"rocket_chat_notification", "drawable", context.packageName) "rocket_chat_notification", "drawable", context.packageName)
with(this, { with(this) {
setAutoCancel(true) setAutoCancel(true)
setShowWhen(true) setShowWhen(true)
color = context.resources.getColor(R.color.colorPrimary) color = ContextCompat.getColor(context, R.color.colorPrimary)
setDefaults(Notification.DEFAULT_ALL) setDefaults(Notification.DEFAULT_ALL)
setSmallIcon(smallIcon) setSmallIcon(smallIcon)
setSound(alarmSound) setSound(alarmSound)
}) }
return this return this
} }
} }
......
...@@ -4,8 +4,9 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory ...@@ -4,8 +4,9 @@ import chat.rocket.android.server.infraestructure.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.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.async import kotlinx.coroutines.experimental.launch
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class RefreshSettingsInteractor @Inject constructor( class RefreshSettingsInteractor @Inject constructor(
...@@ -14,23 +15,61 @@ class RefreshSettingsInteractor @Inject constructor( ...@@ -14,23 +15,61 @@ class RefreshSettingsInteractor @Inject constructor(
) { ) {
private var settingsFilter = arrayOf( private var settingsFilter = arrayOf(
LDAP_ENABLE, CAS_ENABLE, CAS_LOGIN_URL, LDAP_ENABLE,
CAS_ENABLE,
CAS_LOGIN_URL,
ACCOUNT_REGISTRATION, ACCOUNT_LOGIN_FORM, ACCOUNT_PASSWORD_RESET, ACCOUNT_CUSTOM_FIELDS, ACCOUNT_REGISTRATION,
ACCOUNT_GOOGLE, ACCOUNT_FACEBOOK, ACCOUNT_GITHUB, ACCOUNT_LINKEDIN, ACCOUNT_METEOR, ACCOUNT_LOGIN_FORM,
ACCOUNT_TWITTER, ACCOUNT_WORDPRESS, ACCOUNT_GITLAB, ACCOUNT_GITLAB_URL, ACCOUNT_PASSWORD_RESET,
ACCOUNT_CUSTOM_FIELDS,
ACCOUNT_GOOGLE,
ACCOUNT_FACEBOOK,
ACCOUNT_GITHUB,
ACCOUNT_LINKEDIN,
ACCOUNT_METEOR,
ACCOUNT_TWITTER,
ACCOUNT_GITLAB,
ACCOUNT_GITLAB_URL,
ACCOUNT_WORDPRESS,
ACCOUNT_WORDPRESS_URL,
SITE_URL, SITE_NAME, FAVICON_512, FAVICON_196, USE_REALNAME, ALLOW_ROOM_NAME_SPECIAL_CHARS, SITE_URL,
FAVORITE_ROOMS, UPLOAD_STORAGE_TYPE, UPLOAD_MAX_FILE_SIZE, UPLOAD_WHITELIST_MIMETYPES, SITE_NAME,
HIDE_USER_JOIN, HIDE_USER_LEAVE, FAVICON_512,
HIDE_TYPE_AU, HIDE_MUTE_UNMUTE, HIDE_TYPE_RU, ALLOW_MESSAGE_DELETING, FAVICON_196,
ALLOW_MESSAGE_EDITING, ALLOW_MESSAGE_PINNING, ALLOW_MESSAGE_STARRING, SHOW_DELETED_STATUS, SHOW_EDITED_STATUS, USE_REALNAME,
WIDE_TILE_310, STORE_LAST_MESSAGE, MESSAGE_READ_RECEIPT_ENABLED, MESSAGE_READ_RECEIPT_STORE_USERS) ALLOW_ROOM_NAME_SPECIAL_CHARS,
FAVORITE_ROOMS,
UPLOAD_STORAGE_TYPE,
UPLOAD_MAX_FILE_SIZE,
UPLOAD_WHITELIST_MIMETYPES,
HIDE_USER_JOIN,
HIDE_USER_LEAVE,
HIDE_TYPE_AU,
HIDE_MUTE_UNMUTE,
HIDE_TYPE_RU,
ALLOW_MESSAGE_DELETING,
ALLOW_MESSAGE_EDITING,
ALLOW_MESSAGE_PINNING,
ALLOW_MESSAGE_STARRING,
SHOW_DELETED_STATUS,
SHOW_EDITED_STATUS,
WIDE_TILE_310,
STORE_LAST_MESSAGE,
MESSAGE_READ_RECEIPT_ENABLED,
MESSAGE_READ_RECEIPT_STORE_USERS
)
suspend fun refresh(server: String) { suspend fun refresh(server: String) {
withContext(CommonPool) { withContext(CommonPool) {
factory.create(server).let { client -> factory.create(server).let { client ->
val settings = retryIO(description = "settings", times = 5) { val settings = retryIO(
description = "settings",
times = 5,
maxDelay = 5000,
initialDelay = 300
) {
client.settings(*settingsFilter) client.settings(*settingsFilter)
} }
repository.save(server, settings) repository.save(server, settings)
...@@ -39,11 +78,11 @@ class RefreshSettingsInteractor @Inject constructor( ...@@ -39,11 +78,11 @@ class RefreshSettingsInteractor @Inject constructor(
} }
fun refreshAsync(server: String) { fun refreshAsync(server: String) {
async { launch(CommonPool) {
try { try {
refresh(server) refresh(server)
} catch (ex: Exception) { } catch (ex: Exception) {
ex.printStackTrace() Timber.e(ex, "Error refreshing settings for: $server")
} }
} }
} }
......
...@@ -19,9 +19,10 @@ const val ACCOUNT_GITHUB = "Accounts_OAuth_Github" ...@@ -19,9 +19,10 @@ const val ACCOUNT_GITHUB = "Accounts_OAuth_Github"
const val ACCOUNT_LINKEDIN = "Accounts_OAuth_Linkedin" const val ACCOUNT_LINKEDIN = "Accounts_OAuth_Linkedin"
const val ACCOUNT_METEOR = "Accounts_OAuth_Meteor" const val ACCOUNT_METEOR = "Accounts_OAuth_Meteor"
const val ACCOUNT_TWITTER = "Accounts_OAuth_Twitter" const val ACCOUNT_TWITTER = "Accounts_OAuth_Twitter"
const val ACCOUNT_WORDPRESS = "Accounts_OAuth_Wordpress"
const val ACCOUNT_GITLAB = "Accounts_OAuth_Gitlab" const val ACCOUNT_GITLAB = "Accounts_OAuth_Gitlab"
const val ACCOUNT_GITLAB_URL = "API_Gitlab_URL" const val ACCOUNT_GITLAB_URL = "API_Gitlab_URL"
const val ACCOUNT_WORDPRESS = "Accounts_OAuth_Wordpress"
const val ACCOUNT_WORDPRESS_URL = "API_Wordpress_URL"
const val SITE_URL = "Site_Url" const val SITE_URL = "Site_Url"
const val SITE_NAME = "Site_Name" const val SITE_NAME = "Site_Name"
...@@ -71,6 +72,7 @@ fun PublicSettings.isTwitterAuthenticationEnabled(): Boolean = this[ACCOUNT_TWIT ...@@ -71,6 +72,7 @@ fun PublicSettings.isTwitterAuthenticationEnabled(): Boolean = this[ACCOUNT_TWIT
fun PublicSettings.isGitlabAuthenticationEnabled(): Boolean = this[ACCOUNT_GITLAB]?.value == true fun PublicSettings.isGitlabAuthenticationEnabled(): Boolean = this[ACCOUNT_GITLAB]?.value == true
fun PublicSettings.gitlabUrl(): String? = this[ACCOUNT_GITLAB_URL]?.value as String? fun PublicSettings.gitlabUrl(): String? = this[ACCOUNT_GITLAB_URL]?.value as String?
fun PublicSettings.isWordpressAuthenticationEnabled(): Boolean = this[ACCOUNT_WORDPRESS]?.value == true fun PublicSettings.isWordpressAuthenticationEnabled(): Boolean = this[ACCOUNT_WORDPRESS]?.value == true
fun PublicSettings.wordpressUrl(): String? = this[ACCOUNT_WORDPRESS_URL]?.value as String?
fun PublicSettings.useRealName(): Boolean = this[USE_REALNAME]?.value == true fun PublicSettings.useRealName(): Boolean = this[USE_REALNAME]?.value == true
fun PublicSettings.useSpecialCharsOnRoom(): Boolean = this[ALLOW_ROOM_NAME_SPECIAL_CHARS]?.value == true fun PublicSettings.useSpecialCharsOnRoom(): Boolean = this[ALLOW_ROOM_NAME_SPECIAL_CHARS]?.value == true
......
...@@ -2,10 +2,12 @@ package chat.rocket.android.server.infraestructure ...@@ -2,10 +2,12 @@ package chat.rocket.android.server.infraestructure
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import chat.rocket.android.db.DatabaseManager import chat.rocket.android.db.DatabaseManager
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.common.model.BaseRoom import chat.rocket.common.model.BaseRoom
import chat.rocket.common.model.User import chat.rocket.common.model.User
import chat.rocket.common.model.UserStatus
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.realtime.setDefaultStatus
import chat.rocket.core.internal.realtime.setTemporaryStatus
import chat.rocket.core.internal.realtime.socket.connect import chat.rocket.core.internal.realtime.socket.connect
import chat.rocket.core.internal.realtime.socket.disconnect import chat.rocket.core.internal.realtime.socket.disconnect
import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.model.State
...@@ -49,6 +51,7 @@ class ConnectionManager( ...@@ -49,6 +51,7 @@ class ConnectionManager(
private var roomsId: String? = null private var roomsId: String? = null
private var userDataId: String? = null private var userDataId: String? = null
private var activeUserId: String? = null private var activeUserId: String? = null
private var temporaryStatus: UserStatus? = null
private val activeUsersContext = newSingleThreadContext("activeUsersContext") private val activeUsersContext = newSingleThreadContext("activeUsersContext")
private val roomsContext = newSingleThreadContext("roomsContext") private val roomsContext = newSingleThreadContext("roomsContext")
...@@ -90,6 +93,10 @@ class ConnectionManager( ...@@ -90,6 +93,10 @@ class ConnectionManager(
} }
resubscribeRooms() resubscribeRooms()
temporaryStatus?.let { status ->
client.setTemporaryStatus(status)
}
} }
is State.Waiting -> { is State.Waiting -> {
Timber.d("Connection in: ${status.seconds}") Timber.d("Connection in: ${status.seconds}")
...@@ -176,6 +183,16 @@ class ConnectionManager( ...@@ -176,6 +183,16 @@ class ConnectionManager(
} }
} }
fun setDefaultStatus(userStatus: UserStatus) {
temporaryStatus = null
client.setDefaultStatus(userStatus)
}
fun setTemporaryStatus(userStatus: UserStatus) {
temporaryStatus = userStatus
client.setTemporaryStatus(userStatus)
}
private fun resubscribeRooms() { private fun resubscribeRooms() {
roomMessagesChannels.toList().map { (roomId, channel) -> roomMessagesChannels.toList().map { (roomId, channel) ->
client.subscribeRoomMessages(roomId) { _, id -> client.subscribeRoomMessages(roomId) { _, id ->
...@@ -190,6 +207,7 @@ class ConnectionManager( ...@@ -190,6 +207,7 @@ class ConnectionManager(
client.removeStateChannel(statusChannel) client.removeStateChannel(statusChannel)
client.disconnect() client.disconnect()
connectJob?.cancel() connectJob?.cancel()
temporaryStatus = null
} }
fun addStatusChannel(channel: Channel<State>) = statusChannelList.add(channel) fun addStatusChannel(channel: Channel<State>) = statusChannelList.add(channel)
......
...@@ -10,6 +10,7 @@ import android.view.ViewGroup ...@@ -10,6 +10,7 @@ import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.about.ui.AboutFragment import chat.rocket.android.about.ui.AboutFragment
import chat.rocket.android.main.ui.MainActivity
import chat.rocket.android.settings.password.ui.PasswordActivity import chat.rocket.android.settings.password.ui.PasswordActivity
import chat.rocket.android.settings.presentation.SettingsView import chat.rocket.android.settings.presentation.SettingsView
import chat.rocket.android.util.extensions.addFragmentBackStack import chat.rocket.android.util.extensions.addFragmentBackStack
...@@ -34,6 +35,14 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen ...@@ -34,6 +35,14 @@ class SettingsFragment : Fragment(), SettingsView, AdapterView.OnItemClickListen
setupListView() setupListView()
} }
override fun onResume() {
// FIXME - gambiarra ahead. will fix when moving to new androidx Navigation
(activity as? MainActivity)?.let {
it.setupNavigationView()
}
super.onResume()
}
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
when (parent?.getItemAtPosition(position).toString()) { when (parent?.getItemAtPosition(position).toString()) {
resources.getString(R.string.title_password) -> { resources.getString(R.string.title_password) -> {
......
...@@ -3,14 +3,15 @@ package chat.rocket.android.util.extensions ...@@ -3,14 +3,15 @@ package chat.rocket.android.util.extensions
import android.graphics.Color import android.graphics.Color
import android.util.Patterns import android.util.Patterns
import chat.rocket.common.model.Token import chat.rocket.common.model.Token
import okhttp3.HttpUrl
import timber.log.Timber import timber.log.Timber
fun String.removeTrailingSlash(): String { fun String.removeTrailingSlash(): String {
return if (isNotEmpty() && this[length - 1] == '/') { var removed = this
this.substring(0, length - 1) while (removed.isNotEmpty() && removed[removed.length - 1] == '/') {
} else { removed = removed.substring(0, removed.length - 1)
this
} }
return removed
} }
fun String.sanitize(): String { fun String.sanitize(): String {
...@@ -65,3 +66,10 @@ fun String.parseColor(): Int { ...@@ -65,3 +66,10 @@ fun String.parseColor(): Int {
fun String.userId(userId: String?): String? { fun String.userId(userId: String?): String? {
return userId?.let { this.replace(it, "") } return userId?.let { this.replace(it, "") }
} }
fun String.lowercaseUrl(): String? {
val httpUrl = HttpUrl.parse(this)
val newScheme = httpUrl?.scheme()?.toLowerCase()
return httpUrl?.newBuilder()?.scheme(newScheme)?.build()?.toString()
}
\ No newline at end of file
...@@ -7,15 +7,27 @@ import android.view.View ...@@ -7,15 +7,27 @@ import android.view.View
import chat.rocket.android.R import chat.rocket.android.R
import timber.log.Timber import timber.log.Timber
fun View.openTabbedUrl(url: Uri) { fun View.openTabbedUrl(url: String) {
with(this) { with(this) {
val uri = url.ensureScheme()
val tabsbuilder = CustomTabsIntent.Builder() val tabsbuilder = CustomTabsIntent.Builder()
tabsbuilder.setToolbarColor(ResourcesCompat.getColor(context.resources, R.color.colorPrimary, context.theme)) tabsbuilder.setToolbarColor(ResourcesCompat.getColor(context.resources, R.color.colorPrimary, context.theme))
val customTabsIntent = tabsbuilder.build() val customTabsIntent = tabsbuilder.build()
try { try {
customTabsIntent.launchUrl(context, url) customTabsIntent.launchUrl(context, uri)
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.d(ex, "Unable to launch URL") Timber.d(ex, "Unable to launch URL")
} }
} }
} }
private fun String.ensureScheme(): Uri? {
// check if the URL starts with a http(s) scheme
val url = if (!this.matches(Regex("^([h|H][t|T][t|T][p|P]).*"))) {
"http://$this"
} else {
this
}
return Uri.parse(url.lowercaseUrl())
}
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="290dp"
android:height="40dp"
android:viewportWidth="290"
android:viewportHeight="40">
<path
android:fillColor="#428BBA"
android:fillType="evenOdd"
android:pathData="M2,0L288,0A2,2 0,0 1,290 2L290,38A2,2 0,0 1,288 40L2,40A2,2 0,0 1,0 38L0,2A2,2 0,0 1,2 0z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
<path
android:fillColor="#FFFFFFFF"
android:fillType="evenOdd"
android:pathData="M134.878,23.188L136.628,14.625L138.589,14.625L135.964,26L134.073,26L131.909,17.695L129.698,26L127.8,26L125.175,14.625L127.136,14.625L128.901,23.172L131.073,14.625L132.729,14.625L134.878,23.188ZM139.824,21.695C139.824,20.867 139.988,20.121 140.316,19.457C140.645,18.793 141.105,18.283 141.699,17.926C142.293,17.569 142.975,17.391 143.746,17.391C144.887,17.391 145.813,17.758 146.523,18.492C147.234,19.227 147.618,20.201 147.676,21.414L147.684,21.859C147.684,22.693 147.523,23.437 147.203,24.094C146.883,24.75 146.424,25.258 145.828,25.617C145.232,25.977 144.543,26.156 143.762,26.156C142.569,26.156 141.615,25.759 140.898,24.965C140.182,24.171 139.824,23.112 139.824,21.789L139.824,21.695ZM141.723,21.859C141.723,22.729 141.902,23.41 142.262,23.902C142.621,24.395 143.121,24.641 143.762,24.641C144.402,24.641 144.901,24.391 145.258,23.891C145.615,23.391 145.793,22.659 145.793,21.695C145.793,20.841 145.609,20.164 145.242,19.664C144.875,19.164 144.376,18.914 143.746,18.914C143.126,18.914 142.634,19.16 142.27,19.652C141.905,20.145 141.723,20.88 141.723,21.859ZM154.286,19.281C154.036,19.24 153.778,19.219 153.513,19.219C152.643,19.219 152.057,19.552 151.755,20.219L151.755,26L149.857,26L149.857,17.547L151.669,17.547L151.716,18.492C152.174,17.758 152.81,17.391 153.622,17.391C153.893,17.391 154.117,17.427 154.294,17.5L154.286,19.281ZM155.553,21.711C155.553,20.409 155.855,19.363 156.459,18.574C157.063,17.785 157.873,17.391 158.889,17.391C159.785,17.391 160.509,17.703 161.061,18.328L161.061,14L162.959,14L162.959,26L161.241,26L161.147,25.125C160.579,25.813 159.821,26.156 158.873,26.156C157.884,26.156 157.083,25.758 156.471,24.961C155.859,24.164 155.553,23.081 155.553,21.711ZM157.451,21.875C157.451,22.734 157.617,23.405 157.948,23.887C158.278,24.368 158.748,24.609 159.358,24.609C160.134,24.609 160.701,24.263 161.061,23.57L161.061,19.961C160.712,19.284 160.149,18.945 159.373,18.945C158.759,18.945 158.285,19.189 157.951,19.676C157.618,20.163 157.451,20.896 157.451,21.875ZM167.671,21.773L167.671,26L165.695,26L165.695,14.625L170.046,14.625C171.317,14.625 172.326,14.956 173.074,15.617C173.821,16.279 174.195,17.154 174.195,18.242C174.195,19.357 173.829,20.224 173.097,20.844C172.365,21.464 171.341,21.773 170.023,21.773L167.671,21.773ZM167.671,20.188L170.046,20.188C170.749,20.188 171.286,20.022 171.656,19.691C172.025,19.361 172.21,18.883 172.21,18.258C172.21,17.643 172.023,17.152 171.648,16.785C171.273,16.418 170.757,16.229 170.101,16.219L167.671,16.219L167.671,20.188ZM180.735,19.281C180.485,19.24 180.227,19.219 179.962,19.219C179.092,19.219 178.506,19.552 178.204,20.219L178.204,26L176.305,26L176.305,17.547L178.118,17.547L178.165,18.492C178.623,17.758 179.258,17.391 180.071,17.391C180.342,17.391 180.566,17.427 180.743,17.5L180.735,19.281ZM186.08,26.156C184.877,26.156 183.901,25.777 183.154,25.02C182.407,24.262 182.033,23.253 182.033,21.992L182.033,21.758C182.033,20.914 182.196,20.16 182.521,19.496C182.847,18.832 183.304,18.315 183.892,17.945C184.481,17.576 185.137,17.391 185.861,17.391C187.012,17.391 187.901,17.758 188.529,18.492C189.157,19.227 189.47,20.266 189.47,21.609L189.47,22.375L183.947,22.375C184.004,23.073 184.237,23.625 184.646,24.031C185.055,24.438 185.569,24.641 186.189,24.641C187.059,24.641 187.767,24.289 188.314,23.586L189.338,24.563C188.999,25.068 188.547,25.46 187.982,25.738C187.417,26.017 186.783,26.156 186.08,26.156ZM185.853,18.914C185.332,18.914 184.912,19.096 184.592,19.461C184.271,19.826 184.067,20.333 183.978,20.984L187.595,20.984L187.595,20.844C187.554,20.208 187.384,19.728 187.088,19.402C186.791,19.077 186.379,18.914 185.853,18.914ZM196.253,23.703C196.253,23.365 196.113,23.107 195.835,22.93C195.556,22.753 195.094,22.596 194.448,22.461C193.802,22.326 193.263,22.154 192.831,21.945C191.883,21.487 191.409,20.823 191.409,19.953C191.409,19.224 191.716,18.615 192.331,18.125C192.945,17.635 193.727,17.391 194.675,17.391C195.685,17.391 196.501,17.641 197.124,18.141C197.746,18.641 198.057,19.289 198.057,20.086L196.159,20.086C196.159,19.721 196.024,19.418 195.753,19.176C195.482,18.934 195.123,18.813 194.675,18.813C194.258,18.813 193.918,18.909 193.655,19.102C193.392,19.294 193.261,19.552 193.261,19.875C193.261,20.167 193.383,20.393 193.628,20.555C193.873,20.716 194.367,20.879 195.112,21.043C195.857,21.207 196.442,21.402 196.866,21.629C197.291,21.855 197.606,22.128 197.811,22.445C198.017,22.763 198.12,23.148 198.12,23.602C198.12,24.362 197.805,24.978 197.175,25.449C196.544,25.921 195.719,26.156 194.698,26.156C194.005,26.156 193.388,26.031 192.847,25.781C192.305,25.531 191.883,25.188 191.581,24.75C191.279,24.312 191.128,23.841 191.128,23.336L192.972,23.336C192.998,23.784 193.167,24.129 193.479,24.371C193.792,24.613 194.206,24.734 194.722,24.734C195.222,24.734 195.602,24.639 195.862,24.449C196.123,24.259 196.253,24.01 196.253,23.703ZM205.082,23.703C205.082,23.365 204.943,23.107 204.664,22.93C204.385,22.753 203.923,22.596 203.277,22.461C202.632,22.326 202.092,22.154 201.66,21.945C200.712,21.487 200.238,20.823 200.238,19.953C200.238,19.224 200.546,18.615 201.16,18.125C201.775,17.635 202.556,17.391 203.504,17.391C204.514,17.391 205.331,17.641 205.953,18.141C206.576,18.641 206.887,19.289 206.887,20.086L204.988,20.086C204.988,19.721 204.853,19.418 204.582,19.176C204.311,18.934 203.952,18.813 203.504,18.813C203.087,18.813 202.747,18.909 202.484,19.102C202.221,19.294 202.09,19.552 202.09,19.875C202.09,20.167 202.212,20.393 202.457,20.555C202.702,20.716 203.197,20.879 203.941,21.043C204.686,21.207 205.271,21.402 205.695,21.629C206.12,21.855 206.435,22.128 206.641,22.445C206.846,22.763 206.949,23.148 206.949,23.602C206.949,24.362 206.634,24.978 206.004,25.449C205.374,25.921 204.548,26.156 203.527,26.156C202.835,26.156 202.217,26.031 201.676,25.781C201.134,25.531 200.712,25.188 200.41,24.75C200.108,24.312 199.957,23.841 199.957,23.336L201.801,23.336C201.827,23.784 201.996,24.129 202.309,24.371C202.621,24.613 203.035,24.734 203.551,24.734C204.051,24.734 204.431,24.639 204.691,24.449C204.952,24.259 205.082,24.01 205.082,23.703Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
<path
android:fillColor="#FFFFFFFF"
android:fillType="nonZero"
android:pathData="M104.26,11C99.146,11 95,15.146 95,20.26C95,25.375 99.146,29.521 104.26,29.521C109.375,29.521 113.521,25.375 113.521,20.26C113.521,15.146 109.375,11 104.26,11M104.26,11.556C105.995,11.552 107.69,12.07 109.127,13.042C110.054,13.669 110.852,14.467 111.479,15.394C112.451,16.83 112.969,18.526 112.965,20.26C112.969,21.995 112.451,23.69 111.479,25.127C110.852,26.054 110.054,26.852 109.127,27.479C107.69,28.451 105.995,28.969 104.26,28.965C102.526,28.969 100.83,28.451 99.394,27.479C98.467,26.852 97.669,26.054 97.042,25.127C96.07,23.69 95.552,21.995 95.556,20.26C95.552,18.526 96.07,16.83 97.042,15.394C97.669,14.467 98.467,13.669 99.393,13.042C100.83,12.07 102.526,11.552 104.26,11.556"
android:strokeWidth="1"
android:strokeColor="#00000000" />
<path
android:fillColor="#FFFFFFFF"
android:fillType="nonZero"
android:pathData="M111.032,16.558C111.066,16.804 111.084,17.068 111.084,17.351C111.084,18.134 110.937,19.014 110.497,20.115L108.14,26.93C110.516,25.549 111.978,23.008 111.977,20.26C111.979,18.966 111.654,17.693 111.032,16.559L111.032,16.558ZM104.396,20.935L102.08,27.663C103.635,28.121 105.294,28.078 106.823,27.54C106.802,27.506 106.783,27.471 106.768,27.434L104.396,20.935ZM109.47,19.871C109.47,18.917 109.128,18.257 108.834,17.743C108.443,17.106 108.076,16.569 108.076,15.933C108.076,15.223 108.613,14.563 109.372,14.563C109.406,14.563 109.438,14.567 109.472,14.569C108.05,13.264 106.19,12.541 104.26,12.544C101.662,12.543 99.238,13.851 97.813,16.022C97.994,16.028 98.165,16.032 98.309,16.032C99.116,16.032 100.366,15.934 100.366,15.934C100.782,15.909 100.831,16.52 100.415,16.57C100.415,16.57 99.997,16.618 99.532,16.643L102.343,25.002L104.031,19.937L102.829,16.643C102.414,16.618 102.02,16.57 102.02,16.57C101.604,16.545 101.652,15.909 102.068,15.934C102.068,15.934 103.342,16.032 104.101,16.032C104.908,16.032 106.158,15.934 106.158,15.934C106.574,15.909 106.623,16.52 106.207,16.57C106.207,16.57 105.788,16.618 105.324,16.643L108.113,24.938L108.908,22.415C109.263,21.313 109.47,20.531 109.47,19.872L109.47,19.871ZM96.544,20.26C96.544,23.217 98.233,25.915 100.893,27.205L97.211,17.12C96.77,18.108 96.543,19.178 96.544,20.26Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
layout="@layout/layout_toolbar" layout="@layout/layout_toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
...@@ -51,9 +53,11 @@ ...@@ -51,9 +53,11 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:backgroundTint="@android:color/transparent" android:backgroundTint="@android:color/transparent"
android:hint="@string/msg_search" android:hint="@string/msg_search"
android:paddingBottom="8dp"
android:paddingEnd="8dp"
android:paddingStart="8dp" android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/members_chips" /> app:layout_constraintTop_toBottomOf="@id/members_chips" />
<View <View
...@@ -61,6 +65,8 @@ ...@@ -61,6 +65,8 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0.2dp" android:layout_height="0.2dp"
android:background="@color/colorDividerMessageComposer" android:background="@color/colorDividerMessageComposer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/text_search_member" /> app:layout_constraintTop_toBottomOf="@id/text_search_member" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
...@@ -69,6 +75,8 @@ ...@@ -69,6 +75,8 @@
android:layout_height="0dp" android:layout_height="0dp"
android:scrollbars="vertical" android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/separator_1" /> app:layout_constraintTop_toBottomOf="@id/separator_1" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
android:layout_width="120dp" android:layout_width="120dp"
android:layout_height="120dp" android:layout_height="120dp"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:roundedCornerRadius="2dp" /> app:roundedCornerRadius="2dp" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -59,9 +59,9 @@ ...@@ -59,9 +59,9 @@
<Button <Button
android:id="@+id/button_cas" android:id="@+id/button_cas"
style="@style/Authentication.Button" style="@style/Authentication.Button"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins" android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:text="@string/action_login_or_sign_up" android:text="@string/action_login_or_sign_up"
android:visibility="gone" android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
...@@ -73,9 +73,9 @@ ...@@ -73,9 +73,9 @@
android:id="@+id/text_new_to_rocket_chat" android:id="@+id/text_new_to_rocket_chat"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins" android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:gravity="center" android:gravity="center"
android:textColorLink="@color/colorAccent" android:textColorLink="@color/colorAccent"
android:visibility="gone" android:visibility="gone"
...@@ -88,9 +88,9 @@ ...@@ -88,9 +88,9 @@
android:id="@+id/text_forgot_your_password" android:id="@+id/text_forgot_your_password"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:layout_marginStart="@dimen/screen_edge_left_and_right_margins" android:layout_marginStart="@dimen/screen_edge_left_and_right_margins"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:gravity="center" android:gravity="center"
android:textColorLink="@color/colorAccent" android:textColorLink="@color/colorAccent"
android:visibility="gone" android:visibility="gone"
...@@ -115,14 +115,14 @@ ...@@ -115,14 +115,14 @@
android:id="@+id/social_accounts_container" android:id="@+id/social_accounts_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
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:layout_marginEnd="@dimen/screen_edge_left_and_right_margins"
android:background="@color/colorPrimaryDark" android:background="@color/colorPrimaryDark"
android:gravity="center" android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:paddingBottom="32dp"
android:paddingTop="@dimen/screen_edge_left_and_right_margins" android:paddingTop="@dimen/screen_edge_left_and_right_margins"
android:paddingBottom="32dp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
...@@ -218,6 +218,18 @@ ...@@ -218,6 +218,18 @@
android:src="@drawable/ic_gitlab" android:src="@drawable/ic_gitlab"
android:visibility="gone" android:visibility="gone"
tools:visibility="gone" /> tools:visibility="gone" />
<ImageButton
android:id="@+id/button_wordpress"
android:layout_width="290dp"
android:layout_height="40dp"
android:layout_marginTop="16dp"
android:clickable="false"
android:contentDescription="@string/msg_content_description_log_in_using_gitlab"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_wordpress"
android:visibility="gone"
tools:visibility="gone" />
</LinearLayout> </LinearLayout>
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
...@@ -242,7 +254,9 @@ ...@@ -242,7 +254,9 @@
style="@style/Authentication.Button" style="@style/Authentication.Button"
android:text="@string/title_log_in" android:text="@string/title_log_in"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView> </ScrollView>
\ No newline at end of file
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/text_typing_status" app:layout_constraintBottom_toTopOf="@id/text_typing_status"
app:layout_constraintTop_toBottomOf="@+id/text_connection_status"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"> app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_connection_status">
<include <include
android:id="@+id/layout_message_list" android:id="@+id/layout_message_list"
...@@ -68,25 +68,29 @@ ...@@ -68,25 +68,29 @@
android:id="@+id/empty_chat_view" android:id="@+id/empty_chat_view"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:constraint_referenced_ids="image_chat_icon, text_chat_title, text_chat_description"
android:visibility="gone" android:visibility="gone"
app:constraint_referenced_ids="image_chat_icon, text_chat_title, text_chat_description"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" /> tools:visibility="visible" />
<chat.rocket.android.widget.autocompletion.ui.SuggestionsView <chat.rocket.android.widget.autocompletion.ui.SuggestionsView
android:id="@+id/suggestions_view" android:id="@+id/suggestions_view"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/suggestion_background_color" android:background="@color/suggestion_background_color"
app:layout_constraintBottom_toTopOf="@id/layout_message_composer" /> app:layout_constraintBottom_toTopOf="@id/layout_message_composer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView <TextView
android:id="@+id/text_typing_status" android:id="@+id/text_typing_status"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="5dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="5dp"
android:maxLines="2" android:maxLines="2"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/layout_message_composer" app:layout_constraintBottom_toTopOf="@id/layout_message_composer"
...@@ -95,30 +99,37 @@ ...@@ -95,30 +99,37 @@
<include <include
android:id="@+id/layout_message_composer" android:id="@+id/layout_message_composer"
layout="@layout/message_composer" layout="@layout/message_composer"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent" /> app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<View <View
android:id="@+id/view_dim" android:id="@+id/view_dim"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="0dp"
android:background="@color/colorDim" android:background="@color/colorDim"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/layout_message_composer" /> app:layout_constraintBottom_toTopOf="@id/layout_message_composer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include <include
android:id="@+id/layout_message_attachment_options" android:id="@+id/layout_message_attachment_options"
layout="@layout/message_attachment_options" layout="@layout/message_attachment_options"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_margin="5dp" android:layout_margin="5dp"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/layout_message_composer" /> app:layout_constraintBottom_toTopOf="@id/layout_message_composer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView <TextView
android:id="@+id/text_connection_status" android:id="@+id/text_connection_status"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="32dp" android:layout_height="32dp"
android:alpha="0" android:alpha="0"
android:background="@color/colorPrimary" android:background="@color/colorPrimary"
...@@ -127,6 +138,8 @@ ...@@ -127,6 +138,8 @@
android:textAppearance="@style/TextAppearance.AppCompat.Body2" android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="@color/colorWhite" android:textColor="@color/colorWhite"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:alpha="1" tools:alpha="1"
tools:text="connected" tools:text="connected"
......
...@@ -95,8 +95,8 @@ ...@@ -95,8 +95,8 @@
android:hint="@string/msg_channel_name" android:hint="@string/msg_channel_name"
android:inputType="text" android:inputType="text"
android:maxLines="1" android:maxLines="1"
android:paddingEnd="10dp"
android:paddingStart="24dp" android:paddingStart="24dp"
android:paddingEnd="10dp"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@+id/image_channel_icon" app:layout_constraintBottom_toBottomOf="@+id/image_channel_icon"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
...@@ -120,8 +120,8 @@ ...@@ -120,8 +120,8 @@
android:hint="@string/msg_invite_members" android:hint="@string/msg_invite_members"
android:inputType="text" android:inputType="text"
android:maxLines="1" android:maxLines="1"
android:paddingEnd="10dp"
android:paddingStart="24dp" android:paddingStart="24dp"
android:paddingEnd="10dp"
android:textSize="16sp" android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@+id/image_invite_member" app:layout_constraintBottom_toBottomOf="@+id/image_invite_member"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
...@@ -130,21 +130,27 @@ ...@@ -130,21 +130,27 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/view_member_suggestion" android:id="@+id/view_member_suggestion"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="100dp" android:layout_height="100dp"
android:layout_marginEnd="12dp"
android:layout_marginStart="12dp" android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:background="@color/colorWhite" android:background="@color/colorWhite"
android:elevation="2dp" android:elevation="2dp"
android:orientation="vertical" android:orientation="vertical"
android:visibility="gone" android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/text_invite_members"> app:layout_constraintBottom_toTopOf="@+id/text_invite_members"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="0dp"
android:visibility="gone" /> android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.wang.avi.AVLoadingIndicatorView <com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_member_suggestion_loading" android:id="@+id/view_member_suggestion_loading"
...@@ -173,11 +179,13 @@ ...@@ -173,11 +179,13 @@
<com.google.android.material.chip.ChipGroup <com.google.android.material.chip.ChipGroup
android:id="@+id/chip_group_member" android:id="@+id/chip_group_member"
style="@style/Widget.MaterialComponents.Chip.Entry" style="@style/Widget.MaterialComponents.Chip.Entry"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:visibility="gone" android:visibility="gone"
app:chipSpacing="3dp" app:chipSpacing="3dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_invite_members" /> app:layout_constraintTop_toBottomOf="@+id/text_invite_members" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -8,9 +8,13 @@ ...@@ -8,9 +8,13 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="0dp"
android:scrollbars="vertical" /> android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.wang.avi.AVLoadingIndicatorView <com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading" android:id="@+id/view_loading"
...@@ -72,6 +76,8 @@ ...@@ -72,6 +76,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" android:visibility="gone"
app:constraint_referenced_ids="text_no_favorite_messages_description,image_star,text_no_favorite_messages" app:constraint_referenced_ids="text_no_favorite_messages_description,image_star,text_no_favorite_messages"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" /> tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -9,9 +9,13 @@ ...@@ -9,9 +9,13 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="0dp"
android:scrollbars="vertical" /> android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.wang.avi.AVLoadingIndicatorView <com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading" android:id="@+id/view_loading"
...@@ -68,6 +72,10 @@ ...@@ -68,6 +72,10 @@
android:id="@+id/group_no_file" android:id="@+id/group_no_file"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:visibility="gone" android:visibility="gone"
app:constraint_referenced_ids="image_file,text_no_file,text_all_files_appear_here" app:constraint_referenced_ids="image_file,text_no_file,text_all_files_appear_here"
tools:visibility="visible" /> tools:visibility="visible" />
......
...@@ -10,8 +10,11 @@ ...@@ -10,8 +10,11 @@
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_bottom_sheet_avatar" android:id="@+id/image_bottom_sheet_avatar"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="200dp" /> android:layout_height="200dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout <LinearLayout
android:id="@+id/name_and_username_container" android:id="@+id/name_and_username_container"
...@@ -19,9 +22,9 @@ ...@@ -19,9 +22,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/colorBackgroundMemberContainer" android:background="@color/colorBackgroundMemberContainer"
android:orientation="vertical" android:orientation="vertical"
android:paddingBottom="10dp"
android:paddingStart="16dp" android:paddingStart="16dp"
android:paddingTop="10dp" android:paddingTop="10dp"
android:paddingBottom="10dp"
app:layout_constraintBottom_toBottomOf="@+id/image_bottom_sheet_avatar" app:layout_constraintBottom_toBottomOf="@+id/image_bottom_sheet_avatar"
app:layout_constraintLeft_toLeftOf="parent"> app:layout_constraintLeft_toLeftOf="parent">
......
...@@ -8,9 +8,13 @@ ...@@ -8,9 +8,13 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="0dp"
android:scrollbars="vertical" /> android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.wang.avi.AVLoadingIndicatorView <com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading" android:id="@+id/view_loading"
...@@ -70,6 +74,10 @@ ...@@ -70,6 +74,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" android:visibility="gone"
app:constraint_referenced_ids="image_mention,text_no_mention,text_all_mentions_appear_here" app:constraint_referenced_ids="image_mention,text_no_mention,text_all_mentions_appear_here"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" /> tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -8,17 +8,21 @@ ...@@ -8,17 +8,21 @@
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view_pinned" android:id="@+id/recycler_view_pinned"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="match_parent" android:layout_height="0dp"
android:scrollbars="vertical" /> android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.wang.avi.AVLoadingIndicatorView <com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading" android:id="@+id/view_loading"
android:layout_width="48dp" android:layout_width="48dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerInParent="true" android:layout_centerInParent="true"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:visibility="gone" android:visibility="gone"
app:indicatorColor="@color/colorBlack" app:indicatorColor="@color/colorBlack"
app:indicatorName="BallPulseIndicator" app:indicatorName="BallPulseIndicator"
...@@ -74,6 +78,8 @@ ...@@ -74,6 +78,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" android:visibility="gone"
app:constraint_referenced_ids="tv_pin_description,iv_pin_icon,tv_pin_title" app:constraint_referenced_ids="tv_pin_description,iv_pin_icon,tv_pin_title"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" /> tools:visibility="visible" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
...@@ -8,10 +8,10 @@ ...@@ -8,10 +8,10 @@
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:paddingBottom="@dimen/message_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding" android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/message_item_top_and_bottom_padding"> android:paddingTop="@dimen/message_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingBottom="@dimen/message_item_top_and_bottom_padding">
<View <View
android:id="@+id/quote_bar" android:id="@+id/quote_bar"
...@@ -19,19 +19,20 @@ ...@@ -19,19 +19,20 @@
android:layout_height="0dp" android:layout_height="0dp"
android:layout_marginStart="56dp" android:layout_marginStart="56dp"
android:background="@drawable/quote_vertical_gray_bar" android:background="@drawable/quote_vertical_gray_bar"
app:layout_constraintBottom_toTopOf="@id/recycler_view_reactions"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintBottom_toTopOf="@id/recycler_view_reactions"/>
<TextView <TextView
android:id="@+id/attachment_text" android:id="@+id/attachment_text"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:autoLink="web" android:autoLink="web"
app:layout_constraintStart_toEndOf="@id/quote_bar" android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/quote_bar"
app:layout_constraintTop_toTopOf="parent"
tools:text="#5571 - User profile from SSO must not have password change option" /> tools:text="#5571 - User profile from SSO must not have password change option" />
<include <include
......
...@@ -13,6 +13,47 @@ ...@@ -13,6 +13,47 @@
android:paddingEnd="@dimen/screen_edge_left_and_right_padding" android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingBottom="@dimen/message_item_top_and_bottom_padding"> android:paddingBottom="@dimen/message_item_top_and_bottom_padding">
<LinearLayout
android:id="@+id/day_marker_layout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/new_messages_notif">
<View
android:layout_width="0px"
android:layout_height="1dp"
android:layout_weight="1"
android:background="@color/colorDivider" />
<TextView
android:id="@+id/day"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:textAppearance="@style/Message.DayMarker"
tools:text="Wednesday" />
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"
android:background="@color/colorDivider" />
</LinearLayout>
<include
android:id="@+id/layout_avatar"
layout="@layout/avatar"
android:layout_width="40dp"
android:layout_height="40dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="@+id/text_sender" />
<LinearLayout <LinearLayout
android:id="@+id/new_messages_notif" android:id="@+id/new_messages_notif"
android:layout_width="match_parent" android:layout_width="match_parent"
...@@ -50,7 +91,7 @@ ...@@ -50,7 +91,7 @@
<include <include
android:id="@+id/layout_avatar" android:id="@+id/layout_avatar"
layout="@layout/avatar" layout="@layout/avatar"
android:layout_width="40dp" android:layout_width="38dp"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_marginTop="5dp" android:layout_marginTop="5dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
...@@ -63,8 +104,9 @@ ...@@ -63,8 +104,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
app:layout_constraintHorizontal_bias="0.5" app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toRightOf="@+id/layout_avatar"
app:layout_constraintStart_toEndOf="@+id/layout_avatar" app:layout_constraintStart_toEndOf="@+id/layout_avatar"
app:layout_constraintTop_toBottomOf="@+id/new_messages_notif" app:layout_constraintTop_toBottomOf="@+id/day_marker_layout"
tools:text="Ronald Perkins" /> tools:text="Ronald Perkins" />
<TextView <TextView
......
...@@ -7,24 +7,25 @@ ...@@ -7,24 +7,25 @@
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:paddingBottom="@dimen/message_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingStart="@dimen/screen_edge_left_and_right_padding" android:paddingStart="@dimen/screen_edge_left_and_right_padding"
android:paddingTop="@dimen/message_item_top_and_bottom_padding"> android:paddingTop="@dimen/message_item_top_and_bottom_padding"
android:paddingEnd="@dimen/screen_edge_left_and_right_padding"
android:paddingBottom="@dimen/message_item_top_and_bottom_padding">
<Button <Button
android:id="@+id/button_message_reply" android:id="@+id/button_message_reply"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:layout_marginTop="5dp"
android:layout_marginStart="56dp" android:layout_marginStart="56dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="2dp"
android:background="@drawable/message_reply_button_bg" android:background="@drawable/message_reply_button_bg"
android:text="@string/action_msg_reply" android:text="@string/action_msg_reply"
android:textAllCaps="false" android:textAllCaps="false"
android:textColor="#1D74F5" android:textColor="#1D74F5"
android:textSize="14sp" android:textSize="14sp"
app:layout_constraintLeft_toLeftOf="parent" /> app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<include <include
layout="@layout/layout_reactions" layout="@layout/layout_reactions"
......
...@@ -7,9 +7,12 @@ ...@@ -7,9 +7,12 @@
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="@dimen/toolbar_height" android:layout_height="@dimen/toolbar_height"
android:background="@color/colorPrimary" android:background="@color/colorPrimary"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_scrollFlags="scroll|enterAlways" app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
......
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:background="@color/default_background"
android:background="@color/default_background"> android:orientation="vertical">
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/composer" android:id="@+id/composer"
...@@ -13,19 +13,24 @@ ...@@ -13,19 +13,24 @@
<View <View
android:id="@+id/divider" android:id="@+id/divider"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="1dp" android:layout_height="1dp"
android:background="@color/colorDividerMessageComposer" /> android:background="@color/colorDividerMessageComposer"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:id="@+id/text_room_is_read_only" android:id="@+id/text_room_is_read_only"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="45dp" android:layout_height="45dp"
android:background="@color/colorWhite" android:background="@color/colorWhite"
android:gravity="center" android:gravity="center"
android:text="@string/msg_this_room_is_read_only" android:text="@string/msg_this_room_is_read_only"
android:textColor="@color/colorBlack" android:textColor="@color/colorBlack"
android:visibility="gone" android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider" /> app:layout_constraintTop_toBottomOf="@+id/divider" />
<Button <Button
...@@ -42,13 +47,15 @@ ...@@ -42,13 +47,15 @@
<LinearLayout <LinearLayout
android:id="@+id/input_container" android:id="@+id/input_container"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:orientation="horizontal" android:orientation="horizontal"
android:paddingBottom="10dp"
android:paddingTop="10dp" android:paddingTop="10dp"
android:paddingBottom="10dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider"> app:layout_constraintTop_toBottomOf="@+id/divider">
<ImageButton <ImageButton
...@@ -70,12 +77,12 @@ ...@@ -70,12 +77,12 @@
android:layout_weight="1" android:layout_weight="1"
android:background="@android:color/transparent" android:background="@android:color/transparent"
android:hint="@string/msg_message" android:hint="@string/msg_message"
android:imeOptions="flagNoExtractUi"
android:inputType="textCapSentences|textMultiLine" android:inputType="textCapSentences|textMultiLine"
android:lineSpacingExtra="4dp" android:lineSpacingExtra="4dp"
android:maxLines="4" android:maxLines="4"
android:minHeight="24dp" android:minHeight="24dp"
android:scrollbars="vertical" android:scrollbars="vertical" />
android:imeOptions="flagNoExtractUi" />
<ImageButton <ImageButton
android:id="@+id/button_show_attachment_options" android:id="@+id/button_show_attachment_options"
......
...@@ -6,16 +6,16 @@ ...@@ -6,16 +6,16 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
android:paddingEnd="24dp" android:paddingStart="72dp"
android:paddingStart="72dp"> android:paddingEnd="24dp">
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_preview" android:id="@+id/image_preview"
android:layout_width="70dp" android:layout_width="70dp"
android:layout_height="50dp" android:layout_height="50dp"
app:actualImageScaleType="centerCrop"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent" />
app:actualImageScaleType="centerCrop" />
<TextView <TextView
android:id="@+id/text_host" android:id="@+id/text_host"
...@@ -23,9 +23,10 @@ ...@@ -23,9 +23,10 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:textColor="@color/colorSecondaryText" android:textColor="@color/colorSecondaryText"
android:textDirection="locale"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/image_preview" app:layout_constraintStart_toEndOf="@+id/image_preview"
android:textDirection="locale" app:layout_constraintTop_toTopOf="parent"
tools:text="www.uol.com.br" /> tools:text="www.uol.com.br" />
<TextView <TextView
...@@ -33,20 +34,20 @@ ...@@ -33,20 +34,20 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="@color/colorAccent" android:textColor="@color/colorAccent"
android:textDirection="locale"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/text_host" app:layout_constraintStart_toStartOf="@+id/text_host"
app:layout_constraintTop_toBottomOf="@id/text_host" app:layout_constraintTop_toBottomOf="@id/text_host"
android:textDirection="locale"
tools:text="Web page title" /> tools:text="Web page title" />
<TextView <TextView
android:id="@+id/text_description" android:id="@+id/text_description"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textDirection="locale"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/text_host" app:layout_constraintStart_toStartOf="@+id/text_host"
app:layout_constraintTop_toBottomOf="@id/text_title" app:layout_constraintTop_toBottomOf="@id/text_title"
android:textDirection="locale"
tools:text="description" /> tools:text="description" />
<include <include
......
...@@ -30,30 +30,35 @@ ...@@ -30,30 +30,35 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/account_container" android:id="@+id/account_container"
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:background="?selectableItemBackground" android:background="?selectableItemBackground"
android:elevation="2dp" android:elevation="2dp"
android:paddingBottom="4dp"
android:paddingEnd="12dp"
android:paddingStart="12dp" android:paddingStart="12dp"
android:paddingTop="4dp" android:paddingTop="4dp"
android:paddingEnd="12dp"
android:paddingBottom="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/image_avatar"> app:layout_constraintTop_toBottomOf="@+id/image_avatar">
<ImageView <ImageView
android:id="@+id/image_user_status" android:id="@+id/image_user_status"
android:layout_width="12dp" android:layout_width="12dp"
android:layout_height="12dp" android:layout_height="12dp"
app:layout_constraintStart_toStartOf="parent" /> app:layout_constraintBottom_toTopOf="@+id/text_user_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/text_user_name"
app:layout_constraintTop_toTopOf="parent" />
<TextView <TextView
android:id="@+id/text_user_name" android:id="@+id/text_user_name"
style="@style/Sender.Name.TextView" style="@style/Sender.Name.TextView"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:textColor="@color/colorWhite" android:textColor="@color/colorWhite"
app:layout_constraintBottom_toBottomOf="@+id/image_user_status" app:layout_constraintBottom_toBottomOf="@+id/image_user_status"
app:layout_constraintEnd_toStartOf="@+id/image_account_expand" app:layout_constraintEnd_toStartOf="@+id/image_account_expand"
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
app:roundedCornerRadius="3dp" app:roundedCornerRadius="3dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
<ImageView <ImageView
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AppCompatResource">
<item <item
android:id="@+id/action_search" android:id="@+id/action_search"
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"> xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="AppCompatResource">
<item <item
android:id="@+id/action_save_image" android:id="@+id/action_save_image"
......
<resources>
<!-- Titles -->
<string name="title_sign_in_your_server">Anmelden am Server</string>
<string name="title_log_in">Anmelden</string>
<string name="title_register_username">Registriere Benutzernamen</string>
<string name="title_reset_password">Passwort zurücksetzen</string>
<string name="title_sign_up">registrieren</string>
<string name="title_authentication">Login Daten prüfen</string>
<string name="title_legal_terms">Legal Terms</string>
<string name="title_chats">Chats</string>
<string name="title_profile">Profil</string>
<string name="title_members">Benutzer (%d)</string>
<string name="title_settings">Einstellungen</string>
<string name="title_password">Ändere Passwort</string>
<string name="title_update_profile">Update Profil</string>
<string name="title_about">Über</string>
<string name="title_create_channel">Erstelle Raum</string>
<!-- Actions -->
<string name="action_connect">Verbinde</string>
<string name="action_use_this_username">Benutze den Benutzernamen</string>
<string name="action_login_or_sign_up">Klick diesen Knopf um sich anzumelden oder einen Account zu erstellen</string>
<string name="action_terms_of_service">Nutzungsbedingungen</string>
<string name="action_privacy_policy">Datenschutz</string>
<string name="action_search">Suche</string>
<string name="action_update">Updaten</string>
<string name="action_settings">Einstellungen</string>
<string name="action_create_channel">Erstelle Raum</string>
<string name="action_create">Erstelle</string>
<string name="action_logout">Abmelden</string>
<string name="action_files">Dateien</string>
<string name="action_confirm_password">Bestätige Passwort Änderung</string>
<string name="action_join_chat">Trete Chat bei</string>
<string name="action_add_account">Erstelle Account</string>
<string name="action_online">Online</string>
<string name="action_away">Abwesend</string>
<string name="action_busy">Beschäftigt</string>
<string name="action_invisible">Unsichtbar</string>
<string name="action_drawing">Zeichnung</string>
<string name="action_save_to_gallery">Sichern in Gallerie</string>
<string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation -->
<!-- Settings List -->
<string-array name="settings_actions">
<item name="item_password">Ändere Passwort</item>
<item name="item_password">Über</item>
</string-array>
<!-- Regular information messages -->
<string name="msg_generic_error">Entschuldigung, ein Fehler ist aufgetreten, bitte versuchen Sie es noch einmal.</string>
<string name="msg_no_data_to_display">Keine Anzeigedaten vorhanden</string>
<string name="msg_profile_update_successfully">Profil update erfolgreich</string>
<string name="msg_username">Benutzername</string>
<string name="msg_username_or_email">Benutzername oder E-Mail</string>
<string name="msg_password">Passwort</string>
<string name="msg_name">Name</string>
<string name="msg_email">E-Mail</string>
<string name="msg_avatar_url">Avatar URL</string>
<string name="msg_or_continue_using_social_accounts">Oder weiter mit einem Social Account</string>
<string name="msg_new_user">Neuer Benutzer? %1$s</string>
<string name="msg_forgot_password">Passwort vergessen? %1$s</string>
<string name="msg_reset">Zurücksetzen</string>
<string name="msg_check_your_email_to_reset_your_password">E-Mail gesendet! Prüfe dein E-Mail Posteingang um dein Passwort zurückzusetzen.</string>
<string name="msg_invalid_email">Bitte eine korrekte E-Mail Adresse eingeben</string>
<string name="msg_new_user_agreement">Beim weitergehen akzeptieren Sie usere\n%1$s und %2$s</string>
<string name="msg_2fa_code">2FA Code</string>
<!-- <string name="msg_more_than_ninety_nine_unread_messages" translatable="false">99+</string> -->
<string name="msg_yesterday">Gestern</string>
<string name="msg_today">Heute</string>
<string name="msg_message">Nachricht</string>
<string name="msg_this_room_is_read_only">Dieser Raum ist nur lesen</string>
<string name="msg_invalid_2fa_code">Falscher 2FA Code</string>
<string name="msg_invalid_file">Falsche Datei</string>
<string name="msg_invalid_server_url">Falsche Server URL</string>
<string name="msg_content_description_log_in_using_facebook">Login mit Facebook</string>
<string name="msg_content_description_log_in_using_github">Login mit Github</string>
<string name="msg_content_description_log_in_using_google">Login mit Google</string>
<string name="msg_content_description_log_in_using_linkedin">Login mit Linkedin</string>
<string name="msg_content_description_log_in_using_meteor">Login mit Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Login mit Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Login mit Gitlab</string>
<string name="msg_content_description_log_in_using_wordprees">Login using WordPress</string> <!-- TODO Translate-->
<string name="msg_content_description_send_message">Sende Nachricht</string>
<string name="msg_content_description_show_attachment_options">Zeige Anhang Optionen</string>
<string name="msg_you">Du</string>
<string name="msg_unknown">Unbekannt</string>
<string name="msg_email_address">E-Mail Addresse</string>
<string name="msg_utc_offset">UTC Offset</string>
<string name="msg_new_password">Neues Passwort eingeben</string>
<string name="msg_confirm_password">Bestätige neues Passwort</string>
<string name="msg_channel_name">Raum Name</string>
<string name="msg_search">Suche</string>
<string name="msg_unread_messages">Ungelesene Nachrichten</string>
<string name="msg_preview_video">Video</string>
<string name="msg_preview_audio">Audio</string>
<string name="msg_preview_photo">Bild</string>
<string name="msg_preview_file">Datei</string>
<string name="msg_no_messages_yet">Noch keine Nachrichten</string>
<string name="msg_version">Version %1$s</string>
<string name="msg_build">Build %1$d</string>
<string name="msg_ok">OK</string>
<string name="msg_update_app_version_in_order_to_continue">Server Version veraltet. Bitte kontaktieren Sie ihren Server Administrator.</string>
<string name="msg_ver_not_recommended">
Die Server Version scheint älter als die empfolene Version %1$s zu sein.\nSie können sich trotzdem einloggen, aber es kann zu einem unerwartetem Verhalten kommen.</string>
<string name="msg_ver_not_minimum">
Die Server Version scheint älter als die minimale Version %1$s zu sein.\nBitte updaten Sie Ihren Server um sich einloggen zu können!
</string>
<string name="msg_no_chat_title">Keine Chat Nachrichten</string>
<string name="msg_no_chat_description">Starte die Konversation um Ihre \nNachrichten hier zu sehen.</string>
<string name="msg_proceed">WEITER</string>
<string name="msg_cancel">ABBRUCH</string>
<string name="msg_warning">WARNUNG</string>
<string name="msg_http_insecure">Bei HTTP verbinden Sie sich usicher zu einem Server. Wir empfehlen HTTPS zu benutzen.</string>
<string name="msg_error_checking_server_version">Ein Fehler ist aufgetreten beim prüfen der Server Version, bitte versuchen Sie es noch einmal</string>
<string name="msg_invalid_server_protocol">Das ausgewählte Protokoll wird vom Server nicht akzeptiert, versuchen Sie HTTPS</string>
<string name="msg_image_saved_successfully">Bild wurde in der Gallerie gespeichert</string>
<string name="msg_image_saved_failed">Bild speichern fehlgeschlagen</string>
<string name="msg_edited">(bearbeitet)</string>
<string name="msg_and">\u0020und\u0020</string>
<string name="msg_is_typing">\u0020 schreibt…</string>
<string name="msg_are_typing">\u0020 schreiben…</string>
<string name="msg_several_users_are_typing">Mehrere Benutzer schreiben…</string>
<string name="msg_no_search_found">Kein Ergebnis gefunden</string>
<string name="msg_log_out">Ausloggen…</string>
<string name="msg_upload_file">Lade Datei hoch</string>
<string name="msg_file_description">Datei Beschreibung</string>
<string name="msg_send">Sende</string>
<string name="msg_sent_attachment">Sende Anhang</string>
<!-- Create channel messages -->
<string name="msg_private_channel">Privat</string>
<string name="msg_public_channel">Öffentlich</string>
<string name="msg_private_channel_description">Nur Sie und eingeladene Benutzer haben Zugriff auf den Raum</string>
<string name="msg_public_channel_description">Jeder hat Zugriff auf diesen Raum</string>
<string name="msg_ready_only_channel">Nur lesen Raum</string>
<string name="msg_ready_only_channel_description">Nur der Admin kann neue Nachrichten schreiben</string>
<string name="msg_invite_members">Lade Benutzer in diesen Raum ein</string>
<string name="msg_member_already_added">Sie haben diesen Benutzer bereits selektiert</string>
<string name="msg_member_not_found">Benutzer nicht gefunden</string>
<string name="msg_channel_created_successfully">Raum erfolgreich erstellt</string>
<string name="msg_message_copied">Nachricht kopiert</string>
<string name="msg_delete_message">Lösche Nachricht</string>
<string name="msg_delete_description">Sind Sie sicher, dass Sie diese Nachricht löschen wollen?</string>
<!-- System messages -->
<string name="message_room_name_changed">Raum Namen geändert zu: %1$s von %2$s</string>
<string name="message_user_added_by">Benutzer %1$s hinzugefügt von %2$s</string>
<string name="message_user_removed_by">Benutzer %1$s entfernt von %2$s</string>
<string name="message_user_left">Hat den Raum verlassen.</string>
<string name="message_user_joined_channel">Hat den Raum betreten.</string>
<string name="message_welcome">Willkommen %s</string>
<string name="message_removed">Nachricht entfernt</string>
<string name="message_pinned">Nachricht angeheftet:</string>
<string name="message_muted">Benutzer %1$s stumm geschaltet von %2$s</string>
<string name="message_unmuted">Benutzer %1$s nicht mehr stumm geschaltet von %2$s</string>
<string name="message_role_add">%1$s wurde gesetzt %2$s von %3$s</string>
<string name="message_role_removed">%1$s ist nicht länger %2$s von %3$s</string>
<string name="message_credentials_saved_successfully">Login-Daten erfolgreich gespeichert</string>
<!-- Message actions -->
<string name="action_msg_reply">Antworten</string>
<string name="action_msg_info">Nachrichten Info</string>
<string name="action_msg_edit">Bearbeiten</string>
<string name="action_msg_copy">Kopieren</string>
<string name="action_msg_quote">Zitieren</string>
<string name="action_msg_delete">Löschen</string>
<string name="action_msg_pin">Nachricht anheften</string>
<string name="action_msg_unpin">Nachricht nicht mehr anheften</string>
<string name="action_msg_star">Nachricht favorisieren</string>
<string name="action_msg_unstar">Nachricht nicht mehr favorisieren</string>
<string name="action_msg_share">Teilen</string>
<string name="action_title_editing">Nachricht bearbeiten</string>
<string name="action_msg_add_reaction">Reaktion hinzufügen</string>
<string name="action_share">Teilen</string>
<!-- Permission messages -->
<string name="permission_editing_not_allowed">Bearbeiten nicht erlaubt</string>
<string name="permission_deleting_not_allowed">Löschen nicht erlaubt</string>
<string name="permission_pinning_not_allowed">Anheften nicht erlaubt</string>
<string name="permission_starring_not_allowed">Favorisieren nicht erlaubt</string>
<!-- Search message -->
<string name="title_search_message">Suche Nachricht</string>
<!-- Favorite/Unfavorite chat room -->
<string name="title_favorite_chat">Chat favorisieren</string>
<string name="title_unfavorite_chat">Chat nicht favorisieren</string>
<!-- Members List -->
<string name="title_members_list">Benutzer</string>
<!-- Mentions -->
<string name="msg_mentions">Erwähnungen</string>
<string name="msg_no_mention">Keine Erwähnung</string>
<string name="msg_all_the_mentions_appear_here">Alle Erwähnungen\nerscheinen hier</string>
<!-- Pinned Messages -->
<string name="title_pinned_messages">Angeheftete Nachrichten</string>
<string name="no_pinned_messages">Keine angehefteten Nachrichten vorhanden</string>
<string name="no_pinned_description">Alle angehefteten Nachrichten\nerscheinen hier</string>
<!-- Favorite Messages -->
<string name="title_favorite_messages">Favorisierte Nachrichten</string>
<string name="no_favorite_messages">Keine favorisierten Nachrichten vorhanden</string>
<string name="no_favorite_description">Alle favorisierten Nachrichten\nerscheinen hier</string>
<!-- Files -->
<string name="title_files">Dateien</string>
<string name="title_files_total">Dateien (%d)</string>
<string name="msg_no_files">Keine Dateien vorhanden</string>
<string name="msg_all_files_appear_here">Alle Dateien erscheinen hier</string>
<!-- Upload Messages -->
<string name="max_file_size_exceeded">Dateigröße von %1$d Bytes überschreitet maximale Hochladegröße von %2$d Bytes</string>
<!-- Socket status -->
<string name="status_connected">Verbunden</string>
<string name="status_disconnected">Getrennt</string>
<string name="status_connecting">Verbinde</string>
<string name="status_authenticating">Authentifiziere</string>
<string name="status_disconnecting">Trenne</string>
<string name="status_waiting">Verbinde in %d Sekunden</string>
<!--Suggestions-->
<string name="suggest_all_description">Benachrichtige alle in diesem Raum</string>
<string name="suggest_here_description">Benachrichtige aktive Benutzer in diesem Raum</string>
<!-- Slash Commands -->
<string name="Slash_Gimme_Description">Zeige ༼ つ ◕_◕ ༽つ vor deiner Nachricht</string>
<string name="Slash_LennyFace_Description">Zeige ( ͡° ͜ʖ ͡°) nach deiner Nachricht</string>
<string name="Slash_Shrug_Description">Zeige ¯\_(ツ)_/¯ nach deiner Nachricht</string>
<string name="Slash_Tableflip_Description">Zeige (╯°□°)╯︵ ┻━┻</string>
<string name="Slash_TableUnflip_Description">Zeige ┬─┬ ノ( ゜-゜ノ)</string>
<string name="Create_A_New_Channel">Erstelle einen neuen Raum</string>
<string name="Show_the_keyboard_shortcut_list">Zeige Tasterturkürzel</string>
<string name="Invite_user_to_join_channel_all_from">Lade alle Benutzer von [#channel] in diesen Raum ein</string>
<string name="Invite_user_to_join_channel_all_to">Lade alle Benutzer von diesem Raum in [#channel] ein</string>
<string name="Archive">Archivieren</string>
<string name="Remove_someone_from_room">Entferne jemanden vom Raum</string>
<string name="Leave_the_current_channel">Verlasse diesen Raum</string>
<string name="Displays_action_text">Zeige Aktions Text</string>
<string name="Direct_message_someone">Schicke eine Direktnachricht an jemanden</string>
<string name="Mute_someone_in_room">Schalte jemanden im Raum auf Stumm</string>
<string name="Unmute_someone_in_room">Schalte jemanden im Raum nicht mehr auf Stumm</string>
<string name="Invite_user_to_join_channel">Lade jemanden in diesen Raum ein</string>
<string name="Unarchive">Dearchivieren</string>
<string name="Join_the_given_channel">Trete diesem Raum bei</string>
<string name="Guggy_Command_Description">Erstelle ein Gif, basierend auf den eingegebenen Text</string>
<string name="Slash_Topic_Description">Setze Topic</string>
<!-- Emoji message-->
<string name="msg_no_recent_emoji">Keine letzten Emojis</string>
<string name="alert_title_default_skin_tone">Standart Hautton</string>
<!-- Sorting and grouping-->
<string name="menu_chatroom_sort">Sortiere</string>
<string name="dialog_sort_title">Sortieren nach</string>
<string name="dialog_sort_by_alphabet">Alphabetisch</string>
<string name="dialog_sort_by_activity">Aktivität</string>
<string name="dialog_group_by_type">Räume nach Typ</string>
<string name="dialog_group_favourites">Räume nach Favoriten</string>
<string name="chatroom_header">Kopf</string>
<!--ChatRooms Headers-->
<string name="header_channel">Räume</string>
<string name="header_private_groups">Private Räume</string>
<string name="header_direct_messages">Direkt Nachrichten</string>
<string name="header_live_chats">Live Chats</string>
<string name="header_unknown">Unbekannt</string>
<!--Notifications-->
<string name="share_label">Bearbeite geteilte Nachricht</string>
<string name="notif_action_reply_hint">Antworten</string>
<string name="notif_error_sending">Antworten fehlgeschlagen. Bitte versuchen Sie es noch einmal.</string>
<string name="notif_success_sending">Nachricht gesendet nach %1$s!</string>
<string name="read_by">Gelesen von</string>
<string name="message_information_title">Nachricht Information</string>
</resources>
\ No newline at end of file
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
<string name="action_away">Ausente</string> <string name="action_away">Ausente</string>
<string name="action_busy">Ocupado</string> <string name="action_busy">Ocupado</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
<string name="action_drawing">Drawing</string> <!-- TODO Add translation --> <string name="action_drawing">Dibujo</string>
<string name="action_save_to_gallery">Guardar en la galería</string> <string name="action_save_to_gallery">Guardar en la galería</string>
<string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation --> <string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation --> <string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
<string name="msg_new_user_agreement">Al continuar estás aceptando nuestra\n%1$s y %2$s</string> <string name="msg_new_user_agreement">Al continuar estás aceptando nuestra\n%1$s y %2$s</string>
<string name="msg_2fa_code">Código 2FA</string> <string name="msg_2fa_code">Código 2FA</string>
<string name="msg_yesterday">Ayer</string> <string name="msg_yesterday">Ayer</string>
<string name="msg_today">Hoy</string>
<string name="msg_message">Mensaje</string> <string name="msg_message">Mensaje</string>
<string name="msg_this_room_is_read_only">Esta sala es de solo lectura</string> <string name="msg_this_room_is_read_only">Esta sala es de solo lectura</string>
<string name="msg_invalid_2fa_code">Código 2FA no válido</string> <string name="msg_invalid_2fa_code">Código 2FA no válido</string>
...@@ -79,6 +80,7 @@ ...@@ -79,6 +80,7 @@
<string name="msg_content_description_log_in_using_meteor">Inicia sesión usando Meteor</string> <string name="msg_content_description_log_in_using_meteor">Inicia sesión usando Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Inicia sesión usando Twitter</string> <string name="msg_content_description_log_in_using_twitter">Inicia sesión usando Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Inicia sesión usando Gitlab</string> <string name="msg_content_description_log_in_using_gitlab">Inicia sesión usando Gitlab</string>
<string name="msg_content_description_log_in_using_wordprees">Login using WordPress</string> <!-- TODO Translate-->
<string name="msg_content_description_send_message">Enviar mensaje</string> <string name="msg_content_description_send_message">Enviar mensaje</string>
<string name="msg_content_description_show_attachment_options">Mostrar opciones de archivo adjunto</string> <string name="msg_content_description_show_attachment_options">Mostrar opciones de archivo adjunto</string>
<string name="msg_you"></string> <string name="msg_you"></string>
...@@ -123,12 +125,6 @@ ...@@ -123,12 +125,6 @@
<string name="msg_delete_message">Borrar mensaje</string> <string name="msg_delete_message">Borrar mensaje</string>
<string name="msg_delete_description">Seguro que quieres borrar este mensaje</string> <string name="msg_delete_description">Seguro que quieres borrar este mensaje</string>
<string name="msg_no_search_found">No se han encontrado resultados</string> <string name="msg_no_search_found">No se han encontrado resultados</string>
<!-- TODO Add translation -->
<string name="msg_upload_file">Upload file</string>
<!-- TODO Add translation -->
<string name="msg_file_description">File description</string>
<!-- TODO Add translation -->
<string name="msg_send">Send</string>
<!-- Create channel messages --> <!-- Create channel messages -->
<string name="msg_private_channel">Privado</string> <string name="msg_private_channel">Privado</string>
...@@ -180,7 +176,7 @@ ...@@ -180,7 +176,7 @@
<string name="permission_starring_not_allowed">Starring is not allowed</string> <string name="permission_starring_not_allowed">Starring is not allowed</string>
<!-- Search message --> <!-- Search message -->
<string name="title_search_message">Search message</string> <string name="title_search_message">Búsqueda de mensajes</string>
<!-- Favorite/Unfavorite chat room --> <!-- Favorite/Unfavorite chat room -->
<string name="title_favorite_chat">Chat favorito</string> <string name="title_favorite_chat">Chat favorito</string>
...@@ -250,8 +246,7 @@ ...@@ -250,8 +246,7 @@
<!-- Emoji message--> <!-- Emoji message-->
<string name="msg_no_recent_emoji">Sin emojis recientes</string> <string name="msg_no_recent_emoji">Sin emojis recientes</string>
<!-- TODO Add translation --> <string name="alert_title_default_skin_tone">Tono de piel predeterminado</string>
<string name="alert_title_default_skin_tone">Default skin tone</string>
<!-- Sorting and grouping--> <!-- Sorting and grouping-->
<string name="menu_chatroom_sort">Ordenar</string> <string name="menu_chatroom_sort">Ordenar</string>
...@@ -270,11 +265,16 @@ ...@@ -270,11 +265,16 @@
<string name="header_unknown">Desconocido</string> <string name="header_unknown">Desconocido</string>
<!--Notifications--> <!--Notifications-->
<string name="share_label">Edita mensaje compartido</string>
<string name="notif_action_reply_hint">RESPUESTA</string> <string name="notif_action_reply_hint">RESPUESTA</string>
<string name="notif_error_sending">La respuesta ha fallado. Inténtalo de nuevo.</string> <string name="notif_error_sending">La respuesta ha fallado. Inténtalo de nuevo.</string>
<string name="notif_success_sending">Mensaje enviado a %1$s!</string> <string name="notif_success_sending">Mensaje enviado a %1$s!</string>
<string name="read_by">Leído por</string> <string name="read_by">Leído por</string>
<string name="message_information_title">Información del mensaje</string> <string name="message_information_title">Información del mensaje</string>
<string name="msg_log_out">Saliendo de tu cuenta…</string> <string name="msg_log_out">Saliendo de tu cuenta…</string>
<string name="msg_upload_file">Subir archivo</string>
<string name="msg_file_description">Descripción del archivo</string>
<string name="msg_send">Enviar</string>
<string name="msg_sent_attachment">Envió un archivo</string> <string name="msg_sent_attachment">Envió un archivo</string>
</resources> </resources>
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
<string name="msg_new_user_agreement">En procédant, vous acceptez notre\n%1$s et %2$s</string> <string name="msg_new_user_agreement">En procédant, vous acceptez notre\n%1$s et %2$s</string>
<string name="msg_2fa_code">Code 2FA</string> <string name="msg_2fa_code">Code 2FA</string>
<string name="msg_yesterday">Hier</string> <string name="msg_yesterday">Hier</string>
<string name="msg_today">Aujourd\'hui</string>
<string name="msg_message">Message</string> <string name="msg_message">Message</string>
<string name="msg_this_room_is_read_only">Cette salle est seulement de lecture</string> <string name="msg_this_room_is_read_only">Cette salle est seulement de lecture</string>
<string name="msg_invalid_2fa_code">Code 2FA non valide</string> <string name="msg_invalid_2fa_code">Code 2FA non valide</string>
...@@ -85,6 +86,7 @@ ...@@ -85,6 +86,7 @@
<string name="msg_content_description_log_in_using_meteor">Connectez-vous en utilisant Meteor</string> <string name="msg_content_description_log_in_using_meteor">Connectez-vous en utilisant Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Connectez-vous en utilisant Twitter</string> <string name="msg_content_description_log_in_using_twitter">Connectez-vous en utilisant Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Connectez-vous en utilisant Gitlab</string> <string name="msg_content_description_log_in_using_gitlab">Connectez-vous en utilisant Gitlab</string>
<string name="msg_content_description_log_in_using_wordprees">Login using WordPress</string> <!-- TODO Translate-->
<string name="msg_content_description_send_message">Envoyer message</string> <string name="msg_content_description_send_message">Envoyer message</string>
<string name="msg_content_description_show_attachment_options">Afficher les options de fichiers</string> <string name="msg_content_description_show_attachment_options">Afficher les options de fichiers</string>
<string name="msg_you">Toi</string> <string name="msg_you">Toi</string>
...@@ -185,6 +187,7 @@ ...@@ -185,6 +187,7 @@
<string name="action_msg_share">Partager</string> <string name="action_msg_share">Partager</string>
<string name="action_title_editing">Modification du message</string> <string name="action_title_editing">Modification du message</string>
<string name="action_msg_add_reaction">Ajouter une réaction</string> <string name="action_msg_add_reaction">Ajouter une réaction</string>
<string name="action_share">Partager</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">L\'édition n\'est pas autorisée</string> <string name="permission_editing_not_allowed">L\'édition n\'est pas autorisée</string>
...@@ -288,6 +291,7 @@ ...@@ -288,6 +291,7 @@
<string name="header_unknown">Inconnu</string> <string name="header_unknown">Inconnu</string>
<!--Notifications--> <!--Notifications-->
<string name="share_label">Modifier le message partagé</string>
<string name="notif_action_reply_hint">RÉPONDRE</string> <string name="notif_action_reply_hint">RÉPONDRE</string>
<string name="notif_error_sending">La réponse a échoué. Veuillez réessayer.</string> <string name="notif_error_sending">La réponse a échoué. Veuillez réessayer.</string>
<string name="notif_success_sending">Message envoyé à %1$s!</string> <string name="notif_success_sending">Message envoyé à %1$s!</string>
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
<string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation --> <string name="action_select_photo_from_gallery">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation --> <string name="action_take_photo">Select photo from gallery</string> <!-- TODO Add translation -->
<string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation --> <string name="action_reset_avatar">Reset avatar</string> <!-- TODO Add translation -->
<string name="action_share">शेयर</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
...@@ -68,6 +69,7 @@ ...@@ -68,6 +69,7 @@
<string name="msg_new_user_agreement">आगे बढ़कर आप हमारे %1$s और %2$s से सहमत हो रहे हैं</string> <string name="msg_new_user_agreement">आगे बढ़कर आप हमारे %1$s और %2$s से सहमत हो रहे हैं</string>
<string name="msg_2fa_code">कोड 2FA</string> <string name="msg_2fa_code">कोड 2FA</string>
<string name="msg_yesterday">कल</string> <string name="msg_yesterday">कल</string>
<string name="msg_today">आज</string>
<string name="msg_message">संदेश</string> <string name="msg_message">संदेश</string>
<string name="msg_this_room_is_read_only">यह रूम केवल पढ़ने के लिए है</string> <string name="msg_this_room_is_read_only">यह रूम केवल पढ़ने के लिए है</string>
<string name="msg_invalid_2fa_code">अमान्य 2FA कोड</string> <string name="msg_invalid_2fa_code">अमान्य 2FA कोड</string>
...@@ -80,6 +82,7 @@ ...@@ -80,6 +82,7 @@
<string name="msg_content_description_log_in_using_meteor">Meteor द्वारा लॉगिन करें</string> <string name="msg_content_description_log_in_using_meteor">Meteor द्वारा लॉगिन करें</string>
<string name="msg_content_description_log_in_using_twitter">Twitter द्वारा लॉगिन करें</string> <string name="msg_content_description_log_in_using_twitter">Twitter द्वारा लॉगिन करें</string>
<string name="msg_content_description_log_in_using_gitlab">Gitlab द्वारा लॉगिन करें</string> <string name="msg_content_description_log_in_using_gitlab">Gitlab द्वारा लॉगिन करें</string>
<string name="msg_content_description_log_in_using_wordprees">Login using WordPress</string> <!-- TODO Translate-->
<string name="msg_content_description_send_message">मेसेज भेजें</string> <string name="msg_content_description_send_message">मेसेज भेजें</string>
<string name="msg_content_description_show_attachment_options">अटैचमेंट विकल्प दिखाएं</string> <string name="msg_content_description_show_attachment_options">अटैचमेंट विकल्प दिखाएं</string>
<string name="msg_you">आप</string> <string name="msg_you">आप</string>
...@@ -126,6 +129,7 @@ ...@@ -126,6 +129,7 @@
<string name="msg_upload_file">फाइल अपलोड करें</string> <string name="msg_upload_file">फाइल अपलोड करें</string>
<string name="msg_file_description">फाइल विवरण</string> <string name="msg_file_description">फाइल विवरण</string>
<string name="msg_send">भेजें</string> <string name="msg_send">भेजें</string>
<string name="msg_sent_attachment">एक अनुलग्नक भेजा</string>
<string name="msg_delete_message">संदेश को हटाएं</string> <string name="msg_delete_message">संदेश को हटाएं</string>
<string name="msg_delete_description">क्या आप निश्चित रूप से यह संदेश हटाना चाहते हैं</string> <string name="msg_delete_description">क्या आप निश्चित रूप से यह संदेश हटाना चाहते हैं</string>
...@@ -269,6 +273,7 @@ ...@@ -269,6 +273,7 @@
<string name="header_unknown">अज्ञात</string> <string name="header_unknown">अज्ञात</string>
<!--Notifications--> <!--Notifications-->
<string name="share_label">साझा संदेश संपादित करें</string>
<string name="notif_action_reply_hint">जवाब</string> <string name="notif_action_reply_hint">जवाब</string>
<string name="notif_error_sending">उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।</string> <string name="notif_error_sending">उत्तर विफल हुआ है। कृपया फिर से प्रयास करें।</string>
<string name="notif_success_sending">संदेश भेजा गया %1$s!</string> <string name="notif_success_sending">संदेश भेजा गया %1$s!</string>
......
...@@ -67,7 +67,8 @@ ...@@ -67,7 +67,8 @@
<string name="msg_invalid_email">Por favor informe um e-mail válido</string> <string name="msg_invalid_email">Por favor informe um e-mail válido</string>
<string name="msg_new_user_agreement">Ao proceder você concorda com nossos %1$s e %2$s</string> <string name="msg_new_user_agreement">Ao proceder você concorda com nossos %1$s e %2$s</string>
<string name="msg_2fa_code">Código 2FA</string> <string name="msg_2fa_code">Código 2FA</string>
<string name="msg_yesterday">ontem</string> <string name="msg_yesterday">Ontem</string>
<string name="msg_today">Hoje</string>
<string name="msg_message">Mensagem</string> <string name="msg_message">Mensagem</string>
<string name="msg_this_room_is_read_only">Este chat é apenas de leitura</string> <string name="msg_this_room_is_read_only">Este chat é apenas de leitura</string>
<string name="msg_invalid_2fa_code">Código 2FA inválido</string> <string name="msg_invalid_2fa_code">Código 2FA inválido</string>
...@@ -80,6 +81,7 @@ ...@@ -80,6 +81,7 @@
<string name="msg_content_description_log_in_using_meteor">Fazer login através do Meteor</string> <string name="msg_content_description_log_in_using_meteor">Fazer login através do Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Fazer login através do Twitter</string> <string name="msg_content_description_log_in_using_twitter">Fazer login através do Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Fazer login através do Gitlab</string> <string name="msg_content_description_log_in_using_gitlab">Fazer login através do Gitlab</string>
<string name="msg_content_description_log_in_using_wordprees">Fazer login através do WordPress</string>
<string name="msg_content_description_send_message">Enviar mensagem</string> <string name="msg_content_description_send_message">Enviar mensagem</string>
<string name="msg_content_description_show_attachment_options">Mostrar opções de anexo</string> <string name="msg_content_description_show_attachment_options">Mostrar opções de anexo</string>
<string name="msg_you">Você</string> <string name="msg_you">Você</string>
...@@ -269,9 +271,11 @@ ...@@ -269,9 +271,11 @@
<string name="header_unknown">Desconhecido</string> <string name="header_unknown">Desconhecido</string>
<!--Notifications--> <!--Notifications-->
<string name="share_label">Editar mensagem compartilhada</string>
<string name="notif_action_reply_hint">RESPONDER</string> <string name="notif_action_reply_hint">RESPONDER</string>
<string name="notif_error_sending">Falha ao enviar a mensagem.</string> <string name="notif_error_sending">Falha ao enviar a mensagem.</string>
<string name="notif_success_sending">Mensagem enviada para %1$s!</string> <string name="notif_success_sending">Mensagem enviada para %1$s!</string>
<string name="action_share">Compartilhar</string>
<string name="read_by">Lida por</string> <string name="read_by">Lida por</string>
<string name="message_information_title">Informações da mensagem</string> <string name="message_information_title">Informações da mensagem</string>
<string name="msg_log_out">Deslogando…</string> <string name="msg_log_out">Deslogando…</string>
......
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
<string name="msg_new_user_agreement">Продолжая, вы соглашаетесь с нашими\n%1$s и %2$s</string> <string name="msg_new_user_agreement">Продолжая, вы соглашаетесь с нашими\n%1$s и %2$s</string>
<string name="msg_2fa_code">Код 2FA</string> <string name="msg_2fa_code">Код 2FA</string>
<string name="msg_yesterday">Вчера</string> <string name="msg_yesterday">Вчера</string>
<string name="msg_today">Сегодня</string>
<string name="msg_message">Сообщение</string> <string name="msg_message">Сообщение</string>
<string name="msg_this_room_is_read_only">Этот канал только для чтения</string> <string name="msg_this_room_is_read_only">Этот канал только для чтения</string>
<string name="msg_invalid_2fa_code">Неверный код 2FA</string> <string name="msg_invalid_2fa_code">Неверный код 2FA</string>
...@@ -80,6 +81,7 @@ ...@@ -80,6 +81,7 @@
<string name="msg_content_description_log_in_using_meteor">Войти используя Meteor</string> <string name="msg_content_description_log_in_using_meteor">Войти используя Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Войти используя Twitter</string> <string name="msg_content_description_log_in_using_twitter">Войти используя Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Войти используя Gitlab</string> <string name="msg_content_description_log_in_using_gitlab">Войти используя Gitlab</string>
<string name="msg_content_description_log_in_using_wordprees">Login using WordPress</string> <!-- TODO Translate-->
<string name="msg_content_description_send_message">Отправить сообщение</string> <string name="msg_content_description_send_message">Отправить сообщение</string>
<string name="msg_content_description_show_attachment_options">Показать параметры вложения</string> <string name="msg_content_description_show_attachment_options">Показать параметры вложения</string>
<string name="msg_you">Вы</string> <string name="msg_you">Вы</string>
...@@ -123,6 +125,7 @@ ...@@ -123,6 +125,7 @@
<string name="msg_upload_file">Загрузить файл</string> <string name="msg_upload_file">Загрузить файл</string>
<string name="msg_file_description">Описание файла</string> <string name="msg_file_description">Описание файла</string>
<string name="msg_send">послать</string> <string name="msg_send">послать</string>
<string name="msg_sent_attachment">Отправить вложение</string>
<string name="msg_delete_message">Удалить сообщение</string> <string name="msg_delete_message">Удалить сообщение</string>
<string name="msg_delete_description">Вы уверены, что хотите удалить это сообщение?</string> <string name="msg_delete_description">Вы уверены, что хотите удалить это сообщение?</string>
<string name="msg_channel_name">Название канала</string> <string name="msg_channel_name">Название канала</string>
...@@ -169,6 +172,7 @@ ...@@ -169,6 +172,7 @@
<string name="action_msg_share">Поделиться</string> <string name="action_msg_share">Поделиться</string>
<string name="action_title_editing">Редактирование сообщения</string> <string name="action_title_editing">Редактирование сообщения</string>
<string name="action_msg_add_reaction">Добавить реакцию</string> <string name="action_msg_add_reaction">Добавить реакцию</string>
<string name="action_share">Поделиться</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Редактирование запрещено</string> <string name="permission_editing_not_allowed">Редактирование запрещено</string>
...@@ -266,6 +270,7 @@ ...@@ -266,6 +270,7 @@
<string name="header_unknown">Неизвестные</string> <string name="header_unknown">Неизвестные</string>
<!--Notifications--> <!--Notifications-->
<string name="share_label">Изменить общее сообщение</string>
<string name="notif_action_reply_hint">ОТВЕТИТЬ</string> <string name="notif_action_reply_hint">ОТВЕТИТЬ</string>
<string name="notif_error_sending">Ошибка ответа. Пожалуйста, попробуйте еще раз.</string> <string name="notif_error_sending">Ошибка ответа. Пожалуйста, попробуйте еще раз.</string>
<string name="notif_success_sending">Сообщение отправлено %1$s!</string> <string name="notif_success_sending">Сообщение отправлено %1$s!</string>
......
...@@ -44,6 +44,8 @@ ...@@ -44,6 +44,8 @@
<color name="quoteBar">#A0A0A0</color> <color name="quoteBar">#A0A0A0</color>
<color name="colorDivider">#1F000000</color>
<!-- Suggestions --> <!-- Suggestions -->
<color name="suggestion_background_color">@color/colorWhite</color> <color name="suggestion_background_color">@color/colorWhite</color>
......
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="font_fontFamily_medium" translatable="false">sans-serif-medium</string>
</resources>
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
<string name="msg_2fa_code">2FA Code</string> <string name="msg_2fa_code">2FA Code</string>
<string name="msg_more_than_ninety_nine_unread_messages" translatable="false">99+</string> <string name="msg_more_than_ninety_nine_unread_messages" translatable="false">99+</string>
<string name="msg_yesterday">Yesterday</string> <string name="msg_yesterday">Yesterday</string>
<string name="msg_today">Today</string>
<string name="msg_message">Message</string> <string name="msg_message">Message</string>
<string name="msg_this_room_is_read_only">This room is read only</string> <string name="msg_this_room_is_read_only">This room is read only</string>
<string name="msg_invalid_2fa_code">Invalid 2FA Code</string> <string name="msg_invalid_2fa_code">Invalid 2FA Code</string>
...@@ -82,6 +83,7 @@ ...@@ -82,6 +83,7 @@
<string name="msg_content_description_log_in_using_meteor">Login using Meteor</string> <string name="msg_content_description_log_in_using_meteor">Login using Meteor</string>
<string name="msg_content_description_log_in_using_twitter">Login using Twitter</string> <string name="msg_content_description_log_in_using_twitter">Login using Twitter</string>
<string name="msg_content_description_log_in_using_gitlab">Login using Gitlab</string> <string name="msg_content_description_log_in_using_gitlab">Login using Gitlab</string>
<string name="msg_content_description_log_in_using_wordprees">Login using WordPress</string>
<string name="msg_content_description_send_message">Send message</string> <string name="msg_content_description_send_message">Send message</string>
<string name="msg_content_description_show_attachment_options">Show attachment options</string> <string name="msg_content_description_show_attachment_options">Show attachment options</string>
<string name="msg_you">You</string> <string name="msg_you">You</string>
...@@ -173,6 +175,7 @@ ...@@ -173,6 +175,7 @@
<string name="action_msg_share">Share</string> <string name="action_msg_share">Share</string>
<string name="action_title_editing">Editing Message</string> <string name="action_title_editing">Editing Message</string>
<string name="action_msg_add_reaction">Add reaction</string> <string name="action_msg_add_reaction">Add reaction</string>
<string name="action_share">Share</string>
<!-- Permission messages --> <!-- Permission messages -->
<string name="permission_editing_not_allowed">Editing is not allowed</string> <string name="permission_editing_not_allowed">Editing is not allowed</string>
...@@ -270,6 +273,7 @@ ...@@ -270,6 +273,7 @@
<string name="header_unknown">Unknown</string> <string name="header_unknown">Unknown</string>
<!--Notifications--> <!--Notifications-->
<string name="share_label">Edit shared message</string>
<string name="notif_action_reply_hint">REPLY</string> <string name="notif_action_reply_hint">REPLY</string>
<string name="notif_error_sending">Reply has failed. Please try again.</string> <string name="notif_error_sending">Reply has failed. Please try again.</string>
<string name="notif_success_sending">Message sent to %1$s!</string> <string name="notif_success_sending">Message sent to %1$s!</string>
......
...@@ -101,6 +101,12 @@ ...@@ -101,6 +101,12 @@
<item name="android:textColor">@color/colorPrimaryText</item> <item name="android:textColor">@color/colorPrimaryText</item>
</style> </style>
<style name="Message.DayMarker" parent="TextAppearance.AppCompat">
<item name="android:textSize">14sp</item>
<item name="android:textColor">@color/colorPrimaryText</item>
<item name="android:fontFamily">@string/font_fontFamily_medium</item>
</style>
<style name="Message.Quote.TextView" parent="Message.TextView"> <style name="Message.Quote.TextView" parent="Message.TextView">
<item name="android:textColor">@color/colorPrimaryText</item> <item name="android:textColor">@color/colorPrimaryText</item>
</style> </style>
......
...@@ -13,7 +13,7 @@ buildscript { ...@@ -13,7 +13,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:3.3.0-alpha03' classpath 'com.android.tools.build:gradle:3.3.0-alpha03'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}"
classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}" classpath "org.jetbrains.dokka:dokka-gradle-plugin:${versions.dokka}"
classpath 'com.google.gms:google-services:3.2.0' classpath 'com.google.gms:google-services:4.0.2'
classpath 'io.fabric.tools:gradle:1.25.4' classpath 'io.fabric.tools:gradle:1.25.4'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
......
...@@ -18,6 +18,11 @@ android { ...@@ -18,6 +18,11 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
packagingOptions {
exclude 'META-INF/core.kotlin_module'
exclude 'META-INF/main.kotlin_module'
}
} }
dependencies { dependencies {
......
...@@ -5,12 +5,12 @@ ext { ...@@ -5,12 +5,12 @@ ext {
compileSdk : 28, compileSdk : 28,
targetSdk : 28, targetSdk : 28,
minSdk : 21, minSdk : 21,
buildTools : '28.0.0-rc2', buildTools : '28.0.1',
dokka : '0.9.16', dokka : '0.9.16',
// For app // For app
kotlin : '1.2.51', kotlin : '1.2.51',
coroutine : '0.23.1', coroutine : '0.24.0',
appCompat : '1.0.0-beta01', appCompat : '1.0.0-beta01',
recyclerview : '1.0.0-beta01', recyclerview : '1.0.0-beta01',
...@@ -21,9 +21,9 @@ ext { ...@@ -21,9 +21,9 @@ ext {
dagger : '2.16', dagger : '2.16',
firebase : '15.0.0', firebase : '15.0.0',
playServices : '15.0.0', playServices : '15.0.1',
exoPlayer : '2.6.0', exoPlayer : '2.8.2',
flexbox : '0.3.2', flexbox : '1.0.0',
material : '1.0.0-beta01', material : '1.0.0-beta01',
room : '2.0.0-beta01', room : '2.0.0-beta01',
...@@ -33,30 +33,30 @@ ext { ...@@ -33,30 +33,30 @@ ext {
rxAndroid : '2.0.2', rxAndroid : '2.0.2',
moshi : '1.6.0', moshi : '1.6.0',
okhttp : '3.10.0', okhttp : '3.11.0',
timber : '4.7.0', timber : '4.7.1',
threeTenABP : '1.0.5', threeTenABP : '1.1.0',
rxBinding : '2.0.0', rxBinding : '2.1.1',
fresco : '1.9.0', fresco : '1.10.0',
kotshi : '1.0.2', kotshi : '1.0.4',
frescoImageViewer : '0.5.1', frescoImageViewer : '0.5.1',
markwon : '1.0.6', markwon : '1.1.0',
aVLoadingIndicatorView: '2.1.3', aVLoadingIndicatorView: '2.1.3',
// For wearable // For wearable
wear : '2.3.0', wear : '2.3.0',
playServicesWearable : '15.0.1', playServicesWearable : '15.0.1',
supportWearable : '26.1.0', supportWearable : '27.1.1',
// For testing // For testing
junit : '4.12', junit : '4.12',
truth : '0.36', truth : '0.42',
espresso : '3.1.0-alpha2', espresso : '3.1.0-alpha4',
mockito : '2.10.0' mockito : '2.21.0'
] ]
libraries = [ libraries = [
kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}", kotlin : "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${versions.kotlin}",
...@@ -121,10 +121,10 @@ ext { ...@@ -121,10 +121,10 @@ ext {
wearSupport : "com.android.support:wear:${versions.supportWearable}", wearSupport : "com.android.support:wear:${versions.supportWearable}",
// For testing // For testing
junit : "junit:junit:$versions.junit", junit : "junit:junit:${versions.junit}",
espressoCore : "androidx.test.espresso:espresso-core:${versions.espresso}", espressoCore : "androidx.test.espresso:espresso-core:${versions.espresso}",
espressoIntents : "androidx.test.espresso:espresso-intents:${versions.espresso}", espressoIntents : "androidx.test.espresso:espresso-intents:${versions.espresso}",
roomTest : "android.arch.persistence.room:testing:${versions.room}", roomTest : "android.arch.persistence.room:testing:${versions.room}",
truth : "com.google.truth:truth:$versions.truth" truth : "com.google.truth:truth:${versions.truth}"
] ]
} }
...@@ -111,6 +111,12 @@ class DrawingActivity : DaggerAppCompatActivity(), DrawView { ...@@ -111,6 +111,12 @@ class DrawingActivity : DaggerAppCompatActivity(), DrawView {
} }
private fun colorSelector() { private fun colorSelector() {
image_color_black.setOnClickListener {
custom_draw_view.setColor(
ResourcesCompat.getColor(resources, R.color.color_black, null)
)
scaleColorView(image_color_black)
}
image_color_red.setOnClickListener { image_color_red.setOnClickListener {
custom_draw_view.setColor( custom_draw_view.setColor(
ResourcesCompat.getColor(resources, R.color.color_red, null) ResourcesCompat.getColor(resources, R.color.color_red, null)
......
...@@ -55,8 +55,10 @@ ...@@ -55,8 +55,10 @@
android:padding="8dp" android:padding="8dp"
android:src="@drawable/ic_search_gray_24px" android:src="@drawable/ic_search_gray_24px"
android:visibility="invisible" android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/emoji_backspace" app:layout_constraintEnd_toStartOf="@+id/emoji_backspace"
app:layout_constraintStart_toEndOf="@+id/color_change_view" /> app:layout_constraintStart_toEndOf="@+id/color_change_view"
app:layout_constraintTop_toTopOf="parent" />
<ImageView <ImageView
android:id="@+id/emoji_backspace" android:id="@+id/emoji_backspace"
......
#Fri May 18 17:08:16 IST 2018 #Wed Aug 01 22:00:00 EDT 2018
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-rc-2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-all.zip
distributionSha256Sum=9bc16f929e5920a9a27fef22c65a8ab8140d705e418de0159ca6eb7f08a74200 distributionSha256Sum=39e2d5803bbd5eaf6c8efe07067b0e5a00235e8c71318642b2ed262920b27721
...@@ -2,7 +2,7 @@ apply plugin: 'com.android.application' ...@@ -2,7 +2,7 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
android { android {
compileSdkVersion 26 compileSdkVersion 27
buildToolsVersion versions.buildTools buildToolsVersion versions.buildTools
defaultConfig { defaultConfig {
......
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