Commit 2a85aef4 authored by Aniket Singh's avatar Aniket Singh

Merge branch 'develop-2.x' into aniket/feat/create-new-channel

parents eaaf6d63 6f0cc896
......@@ -13,8 +13,8 @@ android {
applicationId "chat.rocket.android"
minSdkVersion 21
targetSdkVersion versions.targetSdk
versionCode 2002
versionName "2.0.0-beta2"
versionCode 2003
versionName "2.0.0-beta3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
......
......@@ -117,4 +117,32 @@ object DrawableHelper {
}
return userStatusDrawable
}
// TODO Why we need to UserStatus?
/**
* Returns the user status drawable.
*
* @param userStatus The user status.
* @param context The context.
* @sse [chat.rocket.core.internal.realtime.UserStatus]
* @return The user status drawable.
*/
fun getUserStatusDrawable(
userStatus: chat.rocket.core.internal.realtime.UserStatus,
context: Context
): Drawable {
return when (userStatus) {
is chat.rocket.core.internal.realtime.UserStatus.Online -> {
getDrawableFromId(R.drawable.ic_status_online_24dp, context)
}
is chat.rocket.core.internal.realtime.UserStatus.Away -> {
getDrawableFromId(R.drawable.ic_status_away_24dp, context)
}
is chat.rocket.core.internal.realtime.UserStatus.Busy -> {
getDrawableFromId(R.drawable.ic_status_busy_24dp, context)
}
else -> getDrawableFromId(R.drawable.ic_status_invisible_24dp, context)
}
}
}
\ No newline at end of file
......@@ -226,7 +226,7 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
registerPushToken()
navigator.toChatList()
} else if (loginType == TYPE_LOGIN_OAUTH) {
view.alertRequiresUsername()
navigator.toRegisterUsername(token.userId, token.authToken)
}
} catch (exception: RocketChatException) {
when (exception) {
......
......@@ -187,9 +187,4 @@ interface LoginView : LoadingView, MessageView, InternetView, VersionCheckView {
* Alerts the user about a wrong inputted password.
*/
fun alertWrongPassword()
/**
* Alerts the user about the need of creating an username using the web app when creating an user through OAuth.
*/
fun alertRequiresUsername()
}
\ No newline at end of file
......@@ -14,7 +14,6 @@ import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.widget.ImageButton
import android.widget.ScrollView
import android.widget.Toast
import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.authentication.login.presentation.LoginPresenter
......@@ -292,10 +291,6 @@ class LoginFragment : Fragment(), LoginView {
text_password.requestFocus()
}
override fun alertRequiresUsername() {
showToast(getString(R.string.msg_requires_username), Toast.LENGTH_LONG)
}
override fun alertNotRecommendedVersion() {
context?.let {
AlertDialog.Builder(it)
......
......@@ -3,6 +3,7 @@ package chat.rocket.android.authentication.presentation
import android.content.Intent
import chat.rocket.android.R
import chat.rocket.android.authentication.login.ui.LoginFragment
import chat.rocket.android.authentication.registerusername.ui.RegisterUsernameFragment
import chat.rocket.android.authentication.signup.ui.SignupFragment
import chat.rocket.android.authentication.twofactor.ui.TwoFAFragment
import chat.rocket.android.authentication.ui.AuthenticationActivity
......@@ -37,6 +38,12 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity) {
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
fun toRegisterUsername(userId: String, authToken: String) {
activity.addFragmentBackStack("RegisterUsernameFragment", R.id.fragment_container) {
RegisterUsernameFragment.newInstance(userId, authToken)
}
}
fun toChatList() {
activity.startActivity(Intent(activity, MainActivity::class.java))
activity.finish()
......
......@@ -25,7 +25,7 @@ class AuthenticationPresenter @Inject constructor(
localRepository.save(LocalRepository.CURRENT_USERNAME_KEY, account.userName)
}
if (newServer || currentServer == null || serverToken == null || settings == null) {
if (newServer || currentServer == null || serverToken == null || settings == null || account?.userName == null) {
callback(false)
} else {
callback(true)
......
package chat.rocket.android.authentication.registerusername.di
import android.arch.lifecycle.LifecycleOwner
import chat.rocket.android.authentication.registerusername.presentation.RegisterUsernameView
import chat.rocket.android.authentication.registerusername.ui.RegisterUsernameFragment
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.dagger.scope.PerFragment
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.experimental.Job
@Module
@PerFragment
class RegisterUsernameFragmentModule {
@Provides
fun registerUsernameView(frag: RegisterUsernameFragment): RegisterUsernameView {
return frag
}
@Provides
fun provideLifecycleOwner(frag: RegisterUsernameFragment): LifecycleOwner {
return frag
}
@Provides
fun provideCancelStrategy(owner: LifecycleOwner, jobs: Job): CancelStrategy {
return CancelStrategy(owner, jobs)
}
}
\ No newline at end of file
package chat.rocket.android.authentication.registerusername.di
import chat.rocket.android.authentication.registerusername.ui.RegisterUsernameFragment
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
abstract class RegisterUsernameFragmentProvider {
@ContributesAndroidInjector(modules = [RegisterUsernameFragmentModule::class])
abstract fun provideRegisterUsernameFragment(): RegisterUsernameFragment
}
\ No newline at end of file
package chat.rocket.android.authentication.registerusername.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.helper.UrlHelper
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.extensions.launchUI
import chat.rocket.android.util.extensions.registerPushToken
import chat.rocket.common.RocketChatException
import chat.rocket.common.model.Token
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.updateOwnBasicInformation
import javax.inject.Inject
class RegisterUsernamePresenter @Inject constructor(
private val view: RegisterUsernameView,
private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator,
private val tokenRepository: TokenRepository,
private val localRepository: LocalRepository,
private val factory: RocketChatClientFactory,
private val saveAccountInteractor: SaveAccountInteractor,
private val getAccountsInteractor: GetAccountsInteractor,
serverInteractor: GetCurrentServerInteractor,
settingsInteractor: GetSettingsInteractor
) {
private val currentServer = serverInteractor.get()!!
private val client: RocketChatClient = factory.create(currentServer)
private var settings: PublicSettings = settingsInteractor.get(serverInteractor.get()!!)
fun registerUsername(username: String, userId: String, authToken: String) {
if (username.isBlank()) {
view.alertBlankUsername()
} else {
launchUI(strategy) {
if (NetworkHelper.hasInternetAccess()) {
view.showLoading()
try {
val me = client.updateOwnBasicInformation(username = username)
val registeredUsername = me.username
if (registeredUsername != null) {
saveAccount(registeredUsername)
tokenRepository.save(currentServer, Token(userId, authToken))
registerPushToken()
navigator.toChatList()
}
} catch (exception: RocketChatException) {
exception.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.hideLoading()
}
} else {
view.showNoInternetConnection()
}
}
}
}
private suspend fun registerPushToken() {
localRepository.get(LocalRepository.KEY_PUSH_TOKEN)?.let {
client.registerPushToken(it, getAccountsInteractor.get(), factory)
}
// TODO: When the push token is null, at some point we should receive it with
// onTokenRefresh() on FirebaseTokenService, we need to confirm it.
}
private suspend fun saveAccount(username: String) {
val icon = settings.favicon()?.let {
UrlHelper.getServerLogoUrl(currentServer, it)
}
val logo = settings.wideTile()?.let {
UrlHelper.getServerLogoUrl(currentServer, it)
}
val thumb = UrlHelper.getAvatarUrl(currentServer, username)
val account = Account(currentServer, icon, logo, username, thumb)
saveAccountInteractor.save(account)
}
}
\ No newline at end of file
package chat.rocket.android.authentication.registerusername.presentation
import chat.rocket.android.core.behaviours.InternetView
import chat.rocket.android.core.behaviours.LoadingView
import chat.rocket.android.core.behaviours.MessageView
interface RegisterUsernameView : LoadingView, MessageView, InternetView {
/**
* Alerts the user about a blank username.
*/
fun alertBlankUsername()
}
\ No newline at end of file
package chat.rocket.android.authentication.registerusername.ui
import DrawableHelper
import android.os.Build
import android.os.Bundle
import android.support.v4.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import chat.rocket.android.R
import chat.rocket.android.authentication.registerusername.presentation.RegisterUsernamePresenter
import chat.rocket.android.authentication.registerusername.presentation.RegisterUsernameView
import chat.rocket.android.util.extensions.*
import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_register_username.*
import javax.inject.Inject
class RegisterUsernameFragment : Fragment(), RegisterUsernameView {
@Inject lateinit var presenter: RegisterUsernamePresenter
private lateinit var userId: String
private lateinit var authToken: String
companion object {
private const val USER_ID = "user_id"
private const val AUTH_TOKEN = "auth_token"
fun newInstance(userId: String, authToken: String) = RegisterUsernameFragment().apply {
arguments = Bundle(1).apply {
putString(USER_ID, userId)
putString(AUTH_TOKEN, authToken)
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
// TODO - research a better way to initialize parameters on fragments.
userId = arguments?.getString(USER_ID) ?: ""
authToken = arguments?.getString(AUTH_TOKEN) ?: ""
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_authentication_register_username)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
activity?.apply {
text_username.requestFocus()
showKeyboard(text_username)
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
tintEditTextDrawableStart()
}
setupOnClickListener()
}
override fun alertBlankUsername() {
vibrateSmartPhone()
text_username.shake()
}
override fun showLoading() {
disableUserInput()
view_loading.setVisible(true)
}
override fun hideLoading() {
view_loading.setVisible(false)
enableUserInput()
}
override fun showMessage(resId: Int) {
showToast(resId)
}
override fun showMessage(message: String) {
showToast(message)
}
override fun showGenericErrorMessage() {
showMessage(getString(R.string.msg_generic_error))
}
override fun showNoInternetConnection() {
showMessage(getString(R.string.msg_no_internet_connection))
}
private fun tintEditTextDrawableStart() {
activity?.apply {
val atDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_at_black_24dp, this)
DrawableHelper.wrapDrawable(atDrawable)
DrawableHelper.tintDrawable(atDrawable, this, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawable(text_username, atDrawable)
}
}
private fun enableUserInput() {
button_use_this_username.isEnabled = true
text_username.isEnabled = true
}
private fun disableUserInput() {
button_use_this_username.isEnabled = false
text_username.isEnabled = true
}
private fun setupOnClickListener() {
button_use_this_username.setOnClickListener {
presenter.registerUsername(text_username.textContent, userId, authToken)
}
}
}
\ No newline at end of file
......@@ -44,7 +44,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
password = arguments?.getString(PASSWORD) ?: ""
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_authentication_two_fa, container, false)
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_authentication_two_fa)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
......@@ -58,6 +58,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
tintEditTextDrawableStart()
}
setupOnClickListener()
}
......
......@@ -34,6 +34,7 @@ import kotlinx.coroutines.experimental.channels.Channel
import kotlinx.coroutines.experimental.launch
import org.threeten.bp.Instant
import timber.log.Timber
import java.util.*
import javax.inject.Inject
class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
......@@ -102,19 +103,19 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
try {
// ignore message for now, will receive it on the stream
val message = if (messageId == null) {
client.sendMessage(chatRoomId, text)
val id = UUID.randomUUID().toString()
client.sendMessage(id, chatRoomId, text)
} else {
client.updateMessage(chatRoomId, messageId, text)
}
view.clearMessageComposition()
view.enableSendMessageButton(false)
} catch (ex: Exception) {
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
} finally {
view.enableSendMessageButton()
view.enableSendMessageButton(true)
}
}
}
......@@ -218,7 +219,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
}
if (messages.result.size == 50) {
// we loade at least count messages, try one more to fetch more messages
// we loaded at least count messages, try one more to fetch more messages
loadMissingMessages()
}
}
......@@ -511,9 +512,11 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
launchUI(strategy) {
try {
if (text.length == 1) {
view.disableSendMessageButton()
// we have just the slash, post it anyway
sendMessage(roomId, text, null)
} else {
view.disableSendMessageButton()
val command = text.split(" ")
val name = command[0].substring(1)
var params: String = ""
......@@ -527,6 +530,7 @@ class ChatRoomPresenter @Inject constructor(private val view: ChatRoomView,
// failed, command is not valid so post it
sendMessage(roomId, text, null)
}
view.enableSendMessageButton(false)
}
} catch (ex: RocketChatException) {
Timber.e(ex)
......
......@@ -92,8 +92,10 @@ interface ChatRoomView : LoadingView, MessageView {
/**
* Enables the send message button.
*
* @param sendFailed Whether the sent message has failed.
*/
fun enableSendMessageButton()
fun enableSendMessageButton(sendFailed: Boolean)
/**
* Clears the message composition.
......
......@@ -35,10 +35,8 @@ import kotlinx.android.synthetic.main.fragment_chat_room.*
import kotlinx.android.synthetic.main.message_attachment_options.*
import kotlinx.android.synthetic.main.message_composer.*
import kotlinx.android.synthetic.main.message_list.*
import timber.log.Timber
import java.util.concurrent.atomic.AtomicInteger
import javax.inject.Inject
import kotlin.math.absoluteValue
fun newInstance(chatRoomId: String,
chatRoomName: String,
......@@ -126,7 +124,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
activity?.apply {
(this as? ChatRoomActivity)?.showRoomTypeIcon(true)
}
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
......@@ -217,10 +214,10 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
recycler_view.addOnLayoutChangeListener { _, _, _, _, bottom, _, _, _, oldBottom ->
val y = oldBottom - bottom
if (y.absoluteValue > 0) {
if (Math.abs(y) > 0) {
// if y is positive the keyboard is up else it's down
recycler_view.post {
if (y > 0 || verticalScrollOffset.get().absoluteValue >= y.absoluteValue) {
if (y > 0 || Math.abs(verticalScrollOffset.get()) >= Math.abs(y)) {
recycler_view.scrollBy(0, y)
} else {
recycler_view.scrollBy(0, verticalScrollOffset.get())
......@@ -296,10 +293,12 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
button_send.isEnabled = false
}
override fun enableSendMessageButton() {
override fun enableSendMessageButton(sendFailed: Boolean) {
button_send.isEnabled = true
text_message.isEnabled = true
text_message.erase()
if (!sendFailed) {
clearMessageComposition()
}
}
override fun clearMessageComposition() {
......@@ -465,7 +464,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
private fun setupRecyclerView() {
recycler_view.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
Timber.i("Scrolling vertically: $dy")
if (!recyclerView.canScrollVertically(1)) {
button_fab.hide()
} else {
......@@ -522,8 +520,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
var textMessage = citation ?: ""
textMessage += text_message.textContent
sendMessage(textMessage)
clearMessageComposition()
}
button_show_attachment_options.setOnClickListener {
......@@ -588,7 +584,6 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
text_message.requestFocus()
emojiKeyboardPopup.showAtBottomPending()
KeyboardHelper.showSoftKeyboard(text_message)
}
setReactionButtonIcon(R.drawable.ic_keyboard_black_24dp)
} else {
......
......@@ -2,6 +2,7 @@ package chat.rocket.android.dagger.module
import chat.rocket.android.authentication.di.AuthenticationModule
import chat.rocket.android.authentication.login.di.LoginFragmentProvider
import chat.rocket.android.authentication.registerusername.di.RegisterUsernameFragmentProvider
import chat.rocket.android.authentication.server.di.ServerFragmentProvider
import chat.rocket.android.authentication.signup.di.SignupFragmentProvider
import chat.rocket.android.authentication.twofactor.di.TwoFAFragmentProvider
......@@ -32,6 +33,7 @@ abstract class ActivityBuilder {
@ContributesAndroidInjector(modules = [AuthenticationModule::class,
ServerFragmentProvider::class,
LoginFragmentProvider::class,
RegisterUsernameFragmentProvider::class,
SignupFragmentProvider::class,
TwoFAFragmentProvider::class
])
......
......@@ -6,6 +6,7 @@ import chat.rocket.android.server.domain.model.Account
import kotlinx.android.synthetic.main.item_account.view.*
class AccountViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(account: Account) {
with(itemView) {
server_logo.setImageURI(account.serverLogo)
......
......@@ -5,50 +5,64 @@ import android.view.ViewGroup
import chat.rocket.android.R
import chat.rocket.android.server.domain.model.Account
import chat.rocket.android.util.extensions.inflate
import chat.rocket.core.internal.realtime.UserStatus
private const val VIEW_TYPE_CHANGE_STATUS = 0
private const val VIEW_TYPE_ACCOUNT = 1
private const val VIEW_TYPE_ADD_ACCOUNT = 2
class AccountsAdapter(
private val accounts: List<Account>,
private val selector: AccountSelector
private val selector: Selector
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
VIEW_TYPE_CHANGE_STATUS -> StatusViewHolder(parent.inflate(R.layout.item_change_status))
VIEW_TYPE_ACCOUNT -> AccountViewHolder(parent.inflate(R.layout.item_account))
else -> AddAccountViewHolder(parent.inflate(R.layout.item_add_account))
}
}
override fun getItemCount() = accounts.size + 1
override fun getItemCount() = accounts.size + 2
override fun getItemViewType(position: Int) =
if (position == accounts.size) VIEW_TYPE_ADD_ACCOUNT else VIEW_TYPE_ACCOUNT
override fun getItemViewType(position: Int): Int {
return when {
position == 0 -> VIEW_TYPE_CHANGE_STATUS
position <= accounts.size -> VIEW_TYPE_ACCOUNT
else -> VIEW_TYPE_ADD_ACCOUNT
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is StatusViewHolder -> bindStatusViewHolder(holder)
is AccountViewHolder -> bindAccountViewHolder(holder, position)
is AddAccountViewHolder -> bindAddAccountViewHolder(holder, position)
is AddAccountViewHolder -> bindAddAccountViewHolder(holder)
}
}
private fun bindStatusViewHolder(holder: StatusViewHolder) {
holder.bind { userStatus -> selector.onStatusSelected(userStatus) }
}
private fun bindAccountViewHolder(holder: AccountViewHolder, position: Int) {
val account = accounts[position]
val account = accounts[position - 1]
holder.bind(account)
holder.itemView.setOnClickListener {
selector.onAccountSelected(account.serverUrl)
}
}
private fun bindAddAccountViewHolder(holder: AddAccountViewHolder, position: Int) {
private fun bindAddAccountViewHolder(holder: AddAccountViewHolder) {
holder.itemView.setOnClickListener {
selector.onAddedAccountSelected()
}
}
}
interface AccountSelector {
interface Selector {
fun onStatusSelected(userStatus: UserStatus)
fun onAccountSelected(serverUrl: String)
fun onAddedAccountSelected()
}
private const val VIEW_TYPE_ACCOUNT = 0
private const val VIEW_TYPE_ADD_ACCOUNT = 1
\ No newline at end of file
}
\ No newline at end of file
package chat.rocket.android.main.adapter
import android.support.v7.widget.RecyclerView
import android.view.View
import chat.rocket.core.internal.realtime.UserStatus
import kotlinx.android.synthetic.main.item_change_status.view.*
class StatusViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(listener: (UserStatus) -> Unit) {
with(itemView) {
text_online.setOnClickListener { listener(UserStatus.Online) }
text_away.setOnClickListener { listener(UserStatus.Away) }
text_busy.setOnClickListener { listener(UserStatus.Busy) }
text_invisible.setOnClickListener { listener(UserStatus.Offline) }
}
}
}
\ No newline at end of file
......@@ -16,6 +16,8 @@ import chat.rocket.common.RocketChatAuthException
import chat.rocket.common.RocketChatException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.realtime.UserStatus
import chat.rocket.core.internal.realtime.setDefaultStatus
import chat.rocket.core.internal.rest.logout
import chat.rocket.core.internal.rest.me
import chat.rocket.core.internal.rest.unregisterPushToken
......@@ -142,6 +144,21 @@ class MainPresenter @Inject constructor(
navigator.toServerScreen()
}
fun changeStatus(userStatus: UserStatus) {
launchUI(strategy) {
try {
client.setDefaultStatus(userStatus)
view.showUserStatus(userStatus)
} catch (ex: RocketChatException) {
ex.message?.let {
view.showMessage(it)
}.ifNull {
view.showGenericErrorMessage()
}
}
}
}
suspend fun refreshToken(token: String?) {
token?.let {
localRepository.save(LocalRepository.KEY_PUSH_TOKEN, token)
......
......@@ -4,8 +4,24 @@ import chat.rocket.android.authentication.server.presentation.VersionCheckView
import chat.rocket.android.core.behaviours.MessageView
import chat.rocket.android.main.viewmodel.NavHeaderViewModel
import chat.rocket.android.server.domain.model.Account
import chat.rocket.core.internal.realtime.UserStatus
interface MainView : MessageView, VersionCheckView {
/**
* Shows the current user status.
*
* @see [UserStatus]
*/
fun showUserStatus(userStatus: UserStatus)
/**
* Setups the navigation header.
*
* @param model The [NavHeaderViewModel].
* @param accounts The list of accounts.
*/
fun setupNavHeader(model: NavHeaderViewModel, accounts: List<Account>)
fun closeServerSelection()
}
\ No newline at end of file
......@@ -13,6 +13,7 @@ import chat.rocket.android.BuildConfig
import chat.rocket.android.R
import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.main.adapter.AccountSelector
import chat.rocket.android.main.adapter.Selector
import chat.rocket.android.main.adapter.AccountsAdapter
import chat.rocket.android.main.presentation.MainPresenter
import chat.rocket.android.main.presentation.MainView
......@@ -22,6 +23,7 @@ import chat.rocket.android.util.extensions.fadeIn
import chat.rocket.android.util.extensions.fadeOut
import chat.rocket.android.util.extensions.rotateBy
import chat.rocket.android.util.extensions.showToast
import chat.rocket.core.internal.realtime.UserStatus
import com.google.android.gms.gcm.GoogleCloudMessaging
import com.google.android.gms.iid.InstanceID
import dagger.android.AndroidInjection
......@@ -43,6 +45,7 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
@Inject lateinit var presenter: MainPresenter
private var isFragmentAdded: Boolean = false
private var expanded = false
private val headerLayout by lazy { view_navigation.getHeaderView(0) }
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
......@@ -78,14 +81,26 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
}
}
override fun showUserStatus(userStatus: UserStatus) {
headerLayout.apply {
image_user_status.setImageDrawable(
DrawableHelper.getUserStatusDrawable(
userStatus,
this.context
)
)
}
}
override fun setupNavHeader(model: NavHeaderViewModel, accounts: List<Account>) {
Timber.d("Setting up nav header: $model")
val headerLayout = view_navigation.getHeaderView(0)
headerLayout.text_name.text = model.username
headerLayout.text_server.text = model.server
headerLayout.image_avatar.setImageURI(model.avatar)
headerLayout.server_logo.setImageURI(model.serverLogo)
setupAccountsList(headerLayout, accounts)
with(headerLayout) {
text_user_name.text = model.username
text_server_url.text = model.server
image_avatar.setImageURI(model.avatar)
server_logo.setImageURI(model.serverLogo)
setupAccountsList(headerLayout, accounts)
}
}
override fun closeServerSelection() {
......@@ -111,7 +126,11 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
private fun setupAccountsList(header: View, accounts: List<Account>) {
accounts_list.layoutManager = LinearLayoutManager(this)
accounts_list.adapter = AccountsAdapter(accounts, object : AccountSelector {
accounts_list.adapter = AccountsAdapter(accounts, object : Selector {
override fun onStatusSelected(userStatus: UserStatus) {
presenter.changeStatus(userStatus)
}
override fun onAccountSelected(serverUrl: String) {
presenter.changeServer(serverUrl)
}
......@@ -119,11 +138,10 @@ class MainActivity : AppCompatActivity(), MainView, HasActivityInjector, HasSupp
override fun onAddedAccountSelected() {
presenter.addNewServer()
}
})
header.account_container.setOnClickListener {
header.account_expand.rotateBy(180f)
header.image_account_expand.rotateBy(180f)
if (expanded) {
accounts_list.fadeOut()
} else {
......
......@@ -55,6 +55,11 @@ fun Activity.hideKeyboard() {
}
}
fun Activity.showKeyboard(view: View) {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(view, InputMethodManager.RESULT_UNCHANGED_SHOWN)
}
fun Activity.showToast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT) =
showToast(getString(resource), duration)
......
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="90"
android:endColor="#00000000"
android:centerColor="#30000000"
android:endColor="#00000000"
android:startColor="#C0000000"
android:type="linear" />
</shape>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FFFFD100"
android:fillType="evenOdd"
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeColor="#00000000"
android:strokeWidth="1" />
<path
android:fillColor="#00000000"
android:fillType="evenOdd"
android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="2" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FFFF2A57"
android:fillType="evenOdd"
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeColor="#00000000"
android:strokeWidth="1" />
<path
android:fillColor="#00000000"
android:fillType="evenOdd"
android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="2" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FFCBCED1"
android:fillType="evenOdd"
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeColor="#00000000"
android:strokeWidth="1" />
<path
android:fillColor="#00000000"
android:fillType="evenOdd"
android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="2" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24">
<path
android:fillColor="#FF2DE0A5"
android:fillType="evenOdd"
android:pathData="M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0"
android:strokeColor="#00000000"
android:strokeWidth="1" />
<path
android:fillColor="#00000000"
android:fillType="evenOdd"
android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0"
android:strokeColor="#FFFFFFFF"
android:strokeWidth="2" />
</vector>
......@@ -28,21 +28,23 @@
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start">
<android.support.design.widget.NavigationView
android:id="@+id/view_navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
app:menu="@menu/navigation"
app:headerLayout="@layout/nav_header" />
app:headerLayout="@layout/nav_header"
app:menu="@menu/navigation" />
<android.support.v7.widget.RecyclerView
android:id="@+id/accounts_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/nav_header_height"
android:elevation="20dp"
android:background="@color/white"
android:alpha="0"
android:visibility="gone"/>
android:background="@color/white"
android:elevation="20dp"
android:visibility="gone" />
</FrameLayout>
</android.support.v4.widget.DrawerLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".authentication.registerusername.ui.RegisterUsernameFragment">
<TextView
android:id="@+id/text_headline"
style="@style/Authentication.Headline.TextView"
android:layout_centerHorizontal="true"
android:text="@string/title_register_username" />
<EditText
android:id="@+id/text_username"
style="@style/Authentication.EditText"
android:layout_below="@id/text_headline"
android:layout_marginTop="32dp"
android:drawableStart="@drawable/ic_at_black_24dp"
android:hint="@string/msg_username"
android:imeOptions="actionDone"
android:inputType="text" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"
app:indicatorName="BallPulseIndicator"
tools:visibility="visible" />
<Button
android:id="@+id/button_use_this_username"
style="@style/Authentication.Button"
android:layout_alignParentBottom="true"
android:text="@string/action_use_this_username" />
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground" >
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:paddingTop="16dp"
android:background="?selectableItemBackground">
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/server_logo"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:actualImageScaleType="centerInside"
app:layout_constraintBottom_toBottomOf="parent"
app:actualImageScaleType="centerInside" />
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_server_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="1"
android:textStyle="bold"
app:layout_constraintTop_toTopOf="@id/server_logo"
app:layout_constraintStart_toEndOf="@id/server_logo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/server_logo"
app:layout_constraintTop_toTopOf="@id/server_logo"
tools:text="https://open.rocket.chat" />
<TextView
......@@ -36,10 +36,11 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:ellipsize="end"
android:maxLines="1"
app:layout_constraintBottom_toBottomOf="@id/server_logo"
app:layout_constraintStart_toEndOf="@id/server_logo"
app:layout_constraintEnd_toEndOf="parent"
tools:text="Lucio Maciel"/>
app:layout_constraintStart_toEndOf="@id/server_logo"
tools:text="Lucio Maciel" />
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?selectableItemBackground" >
android:padding="16dp"
android:background="?selectableItemBackground">
<ImageView
android:id="@+id/server_logo"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="8dp"
android:layout_marginStart="16dp"
android:layout_marginBottom="8dp"
android:src="@drawable/ic_add_24dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
......@@ -23,8 +19,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:text="@string/action_add_account"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="?android:dividerHorizontal"
android:orientation="vertical"
android:showDividers="end">
<TextView
android:id="@+id/text_online"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_status_online_24dp"
android:text="@string/action_online" />
<TextView
android:id="@+id/text_away"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_status_away_24dp"
android:text="@string/action_away" />
<TextView
android:id="@+id/text_busy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_status_busy_24dp"
android:text="@string/action_busy" />
<TextView
android:id="@+id/text_invisible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:drawablePadding="10dp"
android:drawableStart="@drawable/ic_status_invisible_24dp"
android:text="@string/action_invisible" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
......@@ -11,11 +10,11 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:foreground="@drawable/black_gradient"
app:actualImageScaleType="centerCrop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:actualImageScaleType="centerCrop"
tools:src="@tools:sample/backgrounds/scenic" />
<com.facebook.drawee.view.SimpleDraweeView
......@@ -33,50 +32,58 @@
android:id="@+id/account_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:layout_marginTop="16dp"
android:padding="4dp"
android:elevation="2dp"
android:background="?selectableItemBackground"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/image_avatar"
android:elevation="2dp"
android:paddingBottom="4dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:paddingTop="4dp"
app:layout_constraintTop_toBottomOf="@+id/image_avatar">
<ImageView
android:id="@+id/image_user_status"
android:layout_width="14dp"
android:layout_height="14dp"
android:src="@drawable/ic_status_online_24dp"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/text_name"
android:id="@+id/text_user_name"
style="@style/Sender.Name.TextView"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:layout_marginEnd="10dp"
android:layout_marginStart="10dp"
android:textColor="@color/white"
app:layout_constraintEnd_toStartOf="@+id/account_expand"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="@+id/image_user_status"
app:layout_constraintEnd_toStartOf="@+id/image_account_expand"
app:layout_constraintStart_toEndOf="@+id/image_user_status"
app:layout_constraintTop_toTopOf="@+id/image_user_status"
tools:text="Lucio Maciel" />
<TextView
android:id="@+id/text_server"
android:id="@+id/text_server_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textColor="@color/white"
app:layout_constraintEnd_toStartOf="@+id/account_expand"
app:layout_constraintEnd_toStartOf="@+id/image_account_expand"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_name"
app:layout_constraintTop_toBottomOf="@+id/text_user_name"
tools:text="https://open.rocket.chat" />
<ImageView
android:id="@+id/account_expand"
android:id="@+id/image_account_expand"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:src="@drawable/ic_expand_more_24dp"
android:tint="@color/whitesmoke"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
android:tint="@color/white"
app:layout_constraintBottom_toBottomOf="@+id/text_server_url"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
......@@ -3,6 +3,7 @@
<!-- Titles -->
<string name="title_sign_in_your_server">अपने सर्वर में साइन इन करें</string>
<string name="title_log_in">लॉग इन करें</string>
<string name="title_register_username">रजिस्टर उपयोगकर्ता नाम</string>
<string name="title_sign_up">साइन अप करें</string>
<string name="title_authentication">प्रमाणीकरण</string>
<string name="title_legal_terms">कानूनी शर्तें</string>
......@@ -15,6 +16,7 @@
<!-- Actions -->
<string name="action_connect">जुडिये</string>
<string name="action_use_this_username">इस उपयोगकर्ता नाम का उपयोग करें</string>
<string name="action_login_or_sign_up">लॉग इन करने या खाता बनाने के लिए इस बटन को टैप करें</string>
<string name="action_terms_of_service">सेवा की शर्तें</string>
<string name="action_privacy_policy">गोपनीयता नीति</string>
......@@ -26,6 +28,10 @@
<string name="action_confirm_password">पासवर्ड परिवर्तन की पुष्टि करें</string>
<string name="action_join_chat">चैट में शामिल हों</string>
<string name="action_add_account">खाता जोड़ो</string>
<string name="action_online">ऑनलाइन</string>
<string name="action_away">दूर</string>
<string name="action_busy">व्यस्त</string>
<string name="action_invisible">अदृश्य</string>
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -73,7 +79,6 @@
<string name="msg_preview_photo">तस्वीरें</string>
<string name="msg_unread_messages">अपठित संदेश</string>
<string name="msg_no_messages_yet">अभी तक कोई पोस्ट नहीं</string>
<string name="msg_requires_username">उपयोगकर्ता नाम आवश्यक है: कृपया, वेब संस्करण के माध्यम से एक उपयोगकर्ता नाम बनाएं और लॉग इन करने के लिए वापस आएँ</string>
<string name="msg_ok">OK</string>
<string name="msg_ver_not_recommended">
ऐसा लगता है कि आपका सर्वर संस्करण अनुशंसित संस्करण %1$s के नीचे है।\nआप अभी भी लॉगिन कर सकते हैं लेकिन आप अप्रत्याशित व्यवहार का अनुभव कर सकते हैं
......
......@@ -3,6 +3,7 @@
<!-- Titles -->
<string name="title_sign_in_your_server">Faça login no seu servidor</string>
<string name="title_log_in">Entrar</string>
<string name="title_register_username">Registre o nome de usuário</string>
<string name="title_sign_up">Inscreva-se</string>
<string name="title_authentication">Autenticação</string>
<string name="title_legal_terms">Termos Legais</string>
......@@ -15,6 +16,7 @@
<!-- Actions -->
<string name="action_connect">Conectar</string>
<string name="action_use_this_username">Usar este nome de usuário</string>
<string name="action_login_or_sign_up">Toque este botão para fazer login ou criar uma conta</string>
<string name="action_terms_of_service">Termos de Serviço</string>
<string name="action_privacy_policy">Política de Privacidade</string>
......@@ -25,7 +27,11 @@
<string name="action_files">Arquivos</string>
<string name="action_confirm_password">Confirme a nova senha</string>
<string name="action_join_chat">Entrar no Chat</string>
<string name="action_add_account">Adicionar Conta</string>
<string name="action_add_account">Adicionar conta</string>
<string name="action_online">Online</string>
<string name="action_away">Ausente</string>
<string name="action_busy">Ocupado</string>
<string name="action_invisible">Invisível</string>
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -48,7 +54,7 @@
<string name="msg_new_user_agreement">Ao proceder você concorda com nossos %1$s e %2$s</string>
<string name="msg_2fa_code">Código 2FA</string>
<string name="msg_yesterday">ontem</string>
<string name="msg_message">Messagem</string>
<string name="msg_message">Mensagem</string>
<string name="msg_this_room_is_read_only">Este chat é apenas de leitura</string>
<string name="msg_invalid_2fa_code">Código 2FA inválido</string>
<string name="msg_invalid_file">Arquivo inválido</string>
......@@ -73,7 +79,6 @@
<string name="msg_preview_audio">Audio</string>
<string name="msg_preview_photo">Foto</string>
<string name="msg_no_messages_yet">Nenhuma mensagem ainda</string>
<string name="msg_requires_username">Nome de usuário requerido: Por favor, crie um nome de usuário através da versão web e volte para fazer login.</string>
<string name="msg_ok">OK</string>
<string name="msg_ver_not_recommended">
Parece que a versão do seu servidor está abaixo da recomendada %1$s.\nVocê ainda assim pode logar e continuar mas podem ocorrer alguns problemas inesperados.
......
......@@ -21,6 +21,8 @@
<dimen name="message_time_text_size">12sp</dimen>
<dimen name="nav_header_height">140dp</dimen>
<!-- Emoji -->
<dimen name="picker_padding_bottom">16dp</dimen>
<dimen name="supposed_keyboard_height">252dp</dimen>
......@@ -38,6 +40,5 @@
<!-- Autocomplete Popup -->
<dimen name="popup_max_height">150dp</dimen>
<dimen name="suggestions_box_max_height">250dp</dimen>
<dimen name="nav_header_height">160dp</dimen>
</resources>
\ No newline at end of file
......@@ -4,6 +4,7 @@
<!-- Titles -->
<string name="title_sign_in_your_server">Sign in your server</string>
<string name="title_log_in">Log in</string>
<string name="title_register_username">Register username</string>
<string name="title_sign_up">Sign up</string>
<string name="title_authentication">Authentication</string>
<string name="title_legal_terms">Legal Terms</string>
......@@ -18,6 +19,7 @@
<!-- Actions -->
<string name="action_connect">Connect</string>
<string name="action_use_this_username">Use this username</string>
<string name="action_login_or_sign_up">Tap this button to log in or create an account</string>
<string name="action_terms_of_service">Terms of Service</string>
<string name="action_privacy_policy">Privacy Policy</string>
......@@ -30,7 +32,11 @@
<string name="action_create_new_channel">Create</string>
<string name="action_select_members">Done</string>
<string name="action_join_chat">Join Chat</string>
<string name="action_add_account">Add Account</string>
<string name="action_add_account">Add account</string>
<string name="action_online">Online</string>
<string name="action_away">Away</string>
<string name="action_busy">Busy</string>
<string name="action_invisible">Invisible</string>
<!-- Settings List -->
<string-array name="settings_actions">
......@@ -82,7 +88,6 @@
<string name="msg_preview_audio">Audio</string>
<string name="msg_preview_photo">Photo</string>
<string name="msg_no_messages_yet">No messages yet</string>
<string name="msg_requires_username">Username required: Please, create an username through the web version and come back to log in.</string>
<string name="msg_ok">OK</string>
<string name="msg_ver_not_recommended">
Looks like your server version is below the recommended version %1$s.\nYou can still login but you may experience unexpected behaviors.</string>
......
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