Commit 048be2a3 authored by Lucio Maciel's avatar Lucio Maciel

Merge branch 'develop-2.x' into v2-use-public-settings

parents f8419f5c e6fb0c95
...@@ -19,7 +19,8 @@ ...@@ -19,7 +19,8 @@
android:name=".authentication.ui.AuthenticationActivity" android:name=".authentication.ui.AuthenticationActivity"
android:configChanges="orientation" android:configChanges="orientation"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:theme="@style/AuthenticationTheme"> android:theme="@style/AuthenticationTheme"
android:windowSoftInputMode="adjustResize">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
......
...@@ -8,9 +8,9 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory ...@@ -8,9 +8,9 @@ import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.launchUI import chat.rocket.android.util.launchUI
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.common.RocketChatTwoFactorException import chat.rocket.common.RocketChatTwoFactorException
import chat.rocket.common.util.ifNull
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login import chat.rocket.core.internal.rest.login
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class LoginPresenter @Inject constructor(private val view: LoginView, class LoginPresenter @Inject constructor(private val view: LoginView,
...@@ -84,27 +84,28 @@ class LoginPresenter @Inject constructor(private val view: LoginView, ...@@ -84,27 +84,28 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
} }
else -> { else -> {
launchUI(strategy) { launchUI(strategy) {
view.showLoading()
if (NetworkHelper.hasInternetAccess()) { if (NetworkHelper.hasInternetAccess()) {
view.showLoading()
try { try {
val token = client.login(usernameOrEmail, password) client.login(usernameOrEmail, password) // TODO This function returns a user token so should we save it?
Timber.d("Created token: $token")
navigator.toChatList() navigator.toChatList()
} catch (rocketChatException: RocketChatException) { } catch (exception: RocketChatException) {
when (rocketChatException) { when (exception) {
is RocketChatTwoFactorException -> { is RocketChatTwoFactorException -> {
navigator.toTwoFA(usernameOrEmail, password) navigator.toTwoFA(usernameOrEmail, password)
} }
else -> { else -> {
val errorMessage = rocketChatException.message exception.message?.let {
if (errorMessage != null) { view.showMessage(it)
view.showMessage(errorMessage) }.ifNull {
view.showGenericErrorMessage()
} }
} }
} }
} finally {
view.hideLoading()
} }
view.hideLoading()
} else { } else {
view.showNoInternetConnection() view.showNoInternetConnection()
} }
...@@ -114,7 +115,6 @@ class LoginPresenter @Inject constructor(private val view: LoginView, ...@@ -114,7 +115,6 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
} }
fun signup() { fun signup() {
// TODO - remove the server parameter here, signup screen should use the interactor too
navigator.toSignUp() navigator.toSignUp()
} }
} }
\ No newline at end of file
...@@ -8,6 +8,7 @@ import android.support.v4.app.Fragment ...@@ -8,6 +8,7 @@ import android.support.v4.app.Fragment
import android.text.style.ClickableSpan import android.text.style.ClickableSpan
import android.view.* import android.view.*
import android.widget.ImageButton import android.widget.ImageButton
import android.view.inputmethod.InputMethodManager
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.Toast import android.widget.Toast
import chat.rocket.android.R import chat.rocket.android.R
...@@ -16,6 +17,7 @@ import chat.rocket.android.authentication.login.presentation.LoginView ...@@ -16,6 +17,7 @@ import chat.rocket.android.authentication.login.presentation.LoginView
import chat.rocket.android.helper.AnimationHelper import chat.rocket.android.helper.AnimationHelper
import chat.rocket.android.helper.KeyboardHelper import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.helper.TextHelper import chat.rocket.android.helper.TextHelper
import chat.rocket.android.util.inflate
import chat.rocket.android.util.setVisibility import chat.rocket.android.util.setVisibility
import chat.rocket.android.util.textContent import chat.rocket.android.util.textContent
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
...@@ -24,17 +26,17 @@ import javax.inject.Inject ...@@ -24,17 +26,17 @@ import javax.inject.Inject
class LoginFragment : Fragment(), LoginView { class LoginFragment : Fragment(), LoginView {
@Inject lateinit var presenter: LoginPresenter @Inject lateinit var presenter: LoginPresenter
@Inject lateinit var appContext: Context @Inject lateinit var appContext: Context // TODO we really need it? Check alternatives...
private val layoutListener = ViewTreeObserver.OnGlobalLayoutListener { private val layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
if (KeyboardHelper.isSoftKeyboardShown(scroll_view.rootView)) { if (KeyboardHelper.isSoftKeyboardShown(scroll_view.rootView)) {
showOauthView(false)
showSignUpView(false) showSignUpView(false)
showOauthView(false)
showLoginButton(true) showLoginButton(true)
} else { } else {
if (isEditTextEmpty()) { if (isEditTextEmpty()) {
showOauthView(true)
showSignUpView(true) showSignUpView(true)
showOauthView(true)
showLoginButton(false) showLoginButton(false)
} }
} }
...@@ -46,16 +48,20 @@ class LoginFragment : Fragment(), LoginView { ...@@ -46,16 +48,20 @@ class LoginFragment : Fragment(), LoginView {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_authentication_log_in, container, false) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_authentication_log_in)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
activity?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) activity?.apply {
text_username_or_email.requestFocus()
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(text_username_or_email, InputMethodManager.SHOW_IMPLICIT)
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
tintEditTextDrawableStart() tintEditTextDrawableStart()
...@@ -64,14 +70,12 @@ class LoginFragment : Fragment(), LoginView { ...@@ -64,14 +70,12 @@ class LoginFragment : Fragment(), LoginView {
presenter.setup() presenter.setup()
showThreeSocialMethods() showThreeSocialMethods()
setupFabListener() button_log_in.setOnClickListener {
presenter.authenticate(text_username_or_email.textContent, text_password.textContent)
}
// Just an example: if the server allow the new users registration then show the respective interface. setupFabListener()
setupSignUpListener() setupSignUpListener()
showSignUpView(true)
// -------------------------------------------------------------------------------------------------------------------
button_log_in.setOnClickListener { presenter.authenticate(text_username_or_email.textContent, text_password.textContent) }
} }
private fun showThreeSocialMethods() { private fun showThreeSocialMethods() {
...@@ -146,9 +150,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -146,9 +150,7 @@ class LoginFragment : Fragment(), LoginView {
button_gitlab.isEnabled = true button_gitlab.isEnabled = true
} }
override fun showSignUpView(value: Boolean) { override fun showSignUpView(value: Boolean) = text_new_to_rocket_chat.setVisibility(value)
text_new_to_rocket_chat.setVisibility(value)
}
override fun alertWrongUsernameOrEmail() { override fun alertWrongUsernameOrEmail() {
AnimationHelper.vibrateSmartPhone(appContext) AnimationHelper.vibrateSmartPhone(appContext)
...@@ -164,24 +166,25 @@ class LoginFragment : Fragment(), LoginView { ...@@ -164,24 +166,25 @@ class LoginFragment : Fragment(), LoginView {
override fun showLoading() { override fun showLoading() {
enableUserInput(false) enableUserInput(false)
view_loading.show() view_loading.setVisibility(true)
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.hide() view_loading.setVisibility(false)
enableUserInput(true) enableUserInput(true)
} }
override fun showMessage(message: String) { override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
}
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun showNoInternetConnection() = showMessage(getString(R.string.msg_no_internet_connection))
override fun showNoInternetConnection() {
Toast.makeText(activity, getString(R.string.msg_no_internet_connection), Toast.LENGTH_SHORT).show()
}
private fun tintEditTextDrawableStart() { private fun tintEditTextDrawableStart() {
activity?.applicationContext?.apply { activity?.apply {
val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_assignment_ind_black_24dp, this) val personDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_assignment_ind_black_24dp, this)
val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_lock_black_24dp, this) val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_lock_black_24dp, this)
...@@ -213,12 +216,14 @@ class LoginFragment : Fragment(), LoginView { ...@@ -213,12 +216,14 @@ class LoginFragment : Fragment(), LoginView {
button_log_in.isEnabled = value button_log_in.isEnabled = value
text_username_or_email.isEnabled = value text_username_or_email.isEnabled = value
text_password.isEnabled = value text_password.isEnabled = value
if (isEditTextEmpty()) {
showSignUpView(value)
showOauthView(value)
}
} }
// Returns true if *all* EditTexts are empty. // Returns true if *all* EditTexts are empty.
private fun isEditTextEmpty(): Boolean { private fun isEditTextEmpty(): Boolean = text_username_or_email.textContent.isBlank() && text_password.textContent.isEmpty()
return text_username_or_email.textContent.isBlank() && text_password.textContent.isEmpty()
}
private fun showRemainingSocialAccountsView() { private fun showRemainingSocialAccountsView() {
social_accounts_container.postDelayed({ social_accounts_container.postDelayed({
......
...@@ -11,10 +11,7 @@ import chat.rocket.android.R ...@@ -11,10 +11,7 @@ import chat.rocket.android.R
import chat.rocket.android.authentication.server.presentation.ServerPresenter import chat.rocket.android.authentication.server.presentation.ServerPresenter
import chat.rocket.android.authentication.server.presentation.ServerView import chat.rocket.android.authentication.server.presentation.ServerView
import chat.rocket.android.helper.KeyboardHelper import chat.rocket.android.helper.KeyboardHelper
import chat.rocket.android.util.hintContent import chat.rocket.android.util.*
import chat.rocket.android.util.ifEmpty
import chat.rocket.android.util.setVisibility
import chat.rocket.android.util.textContent
import dagger.android.support.AndroidSupportInjection import dagger.android.support.AndroidSupportInjection
import kotlinx.android.synthetic.main.fragment_authentication_server.* import kotlinx.android.synthetic.main.fragment_authentication_server.*
import javax.inject.Inject import javax.inject.Inject
...@@ -34,18 +31,12 @@ class ServerFragment : Fragment(), ServerView { ...@@ -34,18 +31,12 @@ class ServerFragment : Fragment(), ServerView {
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_authentication_server, container, false) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = container?.inflate(R.layout.fragment_authentication_server)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
relative_layout.viewTreeObserver.addOnGlobalLayoutListener(layoutListener) relative_layout.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
setupOnClickListener()
activity?.applicationContext?.apply {
button_connect.setOnClickListener {
val url = text_server_url.textContent.ifEmpty(text_server_url.hintContent)
presenter.connect(text_server_protocol.textContent + url)
}
}
} }
override fun onDestroyView() { override fun onDestroyView() {
...@@ -54,22 +45,30 @@ class ServerFragment : Fragment(), ServerView { ...@@ -54,22 +45,30 @@ class ServerFragment : Fragment(), ServerView {
} }
override fun showLoading() { override fun showLoading() {
text_server_url.isEnabled = false enableUserInput(false)
button_connect.isEnabled = false
view_loading.setVisibility(true) view_loading.setVisibility(true)
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.setVisibility(false) view_loading.setVisibility(false)
button_connect.isEnabled = true enableUserInput(true)
text_server_url.isEnabled = true
} }
override fun showMessage(message: String) { override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
override fun showNoInternetConnection() = showMessage(getString(R.string.msg_no_internet_connection))
private fun enableUserInput(value: Boolean) {
button_connect.isEnabled = value
text_server_url.isEnabled = value
} }
override fun showNoInternetConnection() { private fun setupOnClickListener() {
Toast.makeText(activity, getString(R.string.msg_no_internet_connection), Toast.LENGTH_SHORT).show() button_connect.setOnClickListener {
val url = text_server_url.textContent.ifEmpty(text_server_url.hintContent)
presenter.connect(text_server_protocol.textContent + url)
}
} }
} }
\ No newline at end of file
...@@ -9,7 +9,6 @@ import chat.rocket.android.util.launchUI ...@@ -9,7 +9,6 @@ import chat.rocket.android.util.launchUI
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.core.internal.rest.login import chat.rocket.core.internal.rest.login
import chat.rocket.core.internal.rest.signup import chat.rocket.core.internal.rest.signup
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class SignupPresenter @Inject constructor(private val view: SignupView, class SignupPresenter @Inject constructor(private val view: SignupView,
...@@ -41,22 +40,21 @@ class SignupPresenter @Inject constructor(private val view: SignupView, ...@@ -41,22 +40,21 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
launchUI(strategy) { launchUI(strategy) {
if (NetworkHelper.hasInternetAccess()) { if (NetworkHelper.hasInternetAccess()) {
view.showLoading() view.showLoading()
try {
val user = client.signup(email, name, username, password)
Timber.d("Created user: $user")
val token = client.login(username, password)
Timber.d("Logged in. Token: $token")
try {
client.signup(email, name, username, password) // TODO This function returns a user so should we save it?
client.login(username, password) // TODO This function returns a user token so should we save it?
navigator.toChatList() navigator.toChatList()
} catch (ex: RocketChatException) { } catch (exception: RocketChatException) {
val errorMessage = ex.message val errorMessage = exception.message
if (errorMessage != null) { if (errorMessage != null) {
view.showMessage(errorMessage) view.showMessage(errorMessage)
} else {
view.showGenericErrorMessage()
} }
} finally {
view.hideLoading()
} }
view.hideLoading()
} else { } else {
view.showNoInternetConnection() view.showNoInternetConnection()
} }
......
...@@ -37,9 +37,8 @@ class SignupFragment : Fragment(), SignupView { ...@@ -37,9 +37,8 @@ class SignupFragment : Fragment(), SignupView {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_authentication_sign_up, container, false) override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = inflater.inflate(R.layout.fragment_authentication_sign_up, container, false)
...@@ -93,11 +92,11 @@ class SignupFragment : Fragment(), SignupView { ...@@ -93,11 +92,11 @@ class SignupFragment : Fragment(), SignupView {
override fun showLoading() { override fun showLoading() {
enableUserInput(false) enableUserInput(false)
view_loading.show() view_loading.setVisibility(true)
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.hide() view_loading.setVisibility(false)
enableUserInput(true) enableUserInput(true)
} }
...@@ -105,6 +104,10 @@ class SignupFragment : Fragment(), SignupView { ...@@ -105,6 +104,10 @@ class SignupFragment : Fragment(), SignupView {
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show() Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
} }
override fun showGenericErrorMessage() {
showMessage(getString(R.string.msg_generic_error))
}
override fun showNoInternetConnection() { override fun showNoInternetConnection() {
Toast.makeText(activity, getString(R.string.msg_no_internet_connection), Toast.LENGTH_SHORT).show() Toast.makeText(activity, getString(R.string.msg_no_internet_connection), Toast.LENGTH_SHORT).show()
} }
......
...@@ -4,10 +4,11 @@ import chat.rocket.android.authentication.presentation.AuthenticationNavigator ...@@ -4,10 +4,11 @@ import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetCurrentServerInteractor import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.util.launchUI import chat.rocket.android.util.launchUI
import chat.rocket.common.RocketChatAuthException
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.core.internal.rest.login import chat.rocket.core.internal.rest.login
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class TwoFAPresenter @Inject constructor(private val view: TwoFAView, class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
...@@ -25,20 +26,30 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView, ...@@ -25,20 +26,30 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
navigator.toServerScreen() navigator.toServerScreen()
} else { } else {
launchUI(strategy) { launchUI(strategy) {
val client = factory.create(server) val client = factory.create(server)
view.showLoading() if (NetworkHelper.hasInternetAccess()) {
try { view.showLoading()
val token = client.login(usernameOrEmail, password, twoFactorAuthenticationCode)
Timber.d("Created token: $token") try {
// Todo Salve token?. // The token is saved via the client TokenProvider
navigator.toChatList() client.login(usernameOrEmail, password, twoFactorAuthenticationCode)
} catch (ex: RocketChatException) { navigator.toChatList()
val errorMessage = ex.message } catch (exception: RocketChatException) {
if (errorMessage != null) { if (exception is RocketChatAuthException) {
view.showMessage(errorMessage) view.alertInvalidTwoFactorAuthenticationCode()
} else {
val message = exception.message
if (message != null) {
view.showMessage(message)
} else {
view.showGenericErrorMessage()
}
}
} }
} finally {
view.hideLoading() view.hideLoading()
} else {
view.showNoInternetConnection()
} }
} }
} }
......
...@@ -7,7 +7,12 @@ import chat.rocket.android.core.behaviours.MessageView ...@@ -7,7 +7,12 @@ import chat.rocket.android.core.behaviours.MessageView
interface TwoFAView : LoadingView, MessageView, InternetView { interface TwoFAView : LoadingView, MessageView, InternetView {
/** /**
* Alerts the user about a blank two factor authentication code. * Alerts the user about a blank Two Factor Authentication code.
*/ */
fun alertBlankTwoFactorAuthenticationCode() fun alertBlankTwoFactorAuthenticationCode()
/**
* Alerts the user about an invalid inputted Two Factor Authentication code.
*/
fun alertInvalidTwoFactorAuthenticationCode()
} }
\ No newline at end of file
...@@ -8,7 +8,7 @@ import android.support.v4.app.Fragment ...@@ -8,7 +8,7 @@ import android.support.v4.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowManager import android.view.inputmethod.InputMethodManager
import android.widget.Toast import android.widget.Toast
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.authentication.twofactor.presentation.TwoFAPresenter import chat.rocket.android.authentication.twofactor.presentation.TwoFAPresenter
...@@ -22,10 +22,10 @@ import javax.inject.Inject ...@@ -22,10 +22,10 @@ import javax.inject.Inject
class TwoFAFragment : Fragment(), TwoFAView { class TwoFAFragment : Fragment(), TwoFAView {
@Inject lateinit var presenter: TwoFAPresenter @Inject lateinit var presenter: TwoFAPresenter
@Inject lateinit var appContext: Context
lateinit var username: String lateinit var username: String
lateinit var password: String lateinit var password: String
// TODO - we could create an in memory repository to save username and password.
companion object { companion object {
private const val USERNAME = "username" private const val USERNAME = "username"
private const val PASSWORD = "password" private const val PASSWORD = "password"
...@@ -39,8 +39,8 @@ class TwoFAFragment : Fragment(), TwoFAView { ...@@ -39,8 +39,8 @@ class TwoFAFragment : Fragment(), TwoFAView {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this)
// TODO - research a better way to initialize parameters on fragments. // TODO - research a better way to initialize parameters on fragments.
username = arguments?.getString(USERNAME) ?: "" username = arguments?.getString(USERNAME) ?: ""
...@@ -52,45 +52,60 @@ class TwoFAFragment : Fragment(), TwoFAView { ...@@ -52,45 +52,60 @@ class TwoFAFragment : Fragment(), TwoFAView {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
activity?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) activity?.apply {
text_two_factor_auth.requestFocus()
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(text_two_factor_auth, InputMethodManager.SHOW_IMPLICIT)
}
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
tintEditTextDrawableStart() tintEditTextDrawableStart()
} }
setupOnClickListener()
button_log_in.setOnClickListener {
presenter.authenticate(username, password, text_two_factor_auth.textContent)
}
} }
override fun alertBlankTwoFactorAuthenticationCode() { override fun alertBlankTwoFactorAuthenticationCode() {
AnimationHelper.vibrateSmartPhone(appContext) activity?.let {
AnimationHelper.shakeView(text_two_factor_auth) AnimationHelper.vibrateSmartPhone(it)
AnimationHelper.shakeView(text_two_factor_auth)
}
} }
override fun alertInvalidTwoFactorAuthenticationCode() = showMessage(getString(R.string.msg_invalid_2fa_code))
override fun showLoading() { override fun showLoading() {
enableUserInput(false)
view_loading.setVisibility(true) view_loading.setVisibility(true)
} }
override fun hideLoading() { override fun hideLoading() {
view_loading.setVisibility(false) view_loading.setVisibility(false)
enableUserInput(true)
} }
override fun showMessage(message: String) { override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
}
override fun showNoInternetConnection() { override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
Toast.makeText(activity, getString(R.string.msg_no_internet_connection), Toast.LENGTH_SHORT).show()
} override fun showNoInternetConnection() = showMessage(getString(R.string.msg_no_internet_connection))
private fun tintEditTextDrawableStart() { private fun tintEditTextDrawableStart() {
activity?.applicationContext?.apply { activity?.apply {
val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_vpn_key_black_24dp, this) val lockDrawable = DrawableHelper.getDrawableFromId(R.drawable.ic_vpn_key_black_24dp, this)
DrawableHelper.wrapDrawable(lockDrawable) DrawableHelper.wrapDrawable(lockDrawable)
DrawableHelper.tintDrawable(lockDrawable, this, R.color.colorDrawableTintGrey) DrawableHelper.tintDrawable(lockDrawable, this, R.color.colorDrawableTintGrey)
DrawableHelper.compoundDrawable(text_two_factor_auth, lockDrawable) DrawableHelper.compoundDrawable(text_two_factor_auth, lockDrawable)
} }
} }
private fun enableUserInput(value: Boolean) {
button_log_in.isEnabled = value
text_two_factor_auth.isEnabled = value
}
private fun setupOnClickListener() {
button_log_in.setOnClickListener {
presenter.authenticate(username, password, text_two_factor_auth.textContent)
}
}
} }
\ No newline at end of file
...@@ -5,7 +5,6 @@ import android.support.v4.app.Fragment ...@@ -5,7 +5,6 @@ import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.authentication.server.ui.ServerFragment import chat.rocket.android.authentication.server.ui.ServerFragment
import chat.rocket.android.helper.LayoutHelper
import chat.rocket.android.util.addFragment import chat.rocket.android.util.addFragment
import dagger.android.AndroidInjection import dagger.android.AndroidInjection
import dagger.android.AndroidInjector import dagger.android.AndroidInjector
...@@ -15,25 +14,18 @@ import javax.inject.Inject ...@@ -15,25 +14,18 @@ import javax.inject.Inject
class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector { class AuthenticationActivity : AppCompatActivity(), HasSupportFragmentInjector {
@Inject lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment> @Inject lateinit var fragmentDispatchingAndroidInjector: DispatchingAndroidInjector<Fragment>
private val layoutHelper = LayoutHelper()
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_authentication) setContentView(R.layout.activity_authentication)
AndroidInjection.inject(this) AndroidInjection.inject(this)
layoutHelper.install(this)
addFragment("authenticationServerFragment", R.id.fragment_container) { addFragment("authenticationServerFragment", R.id.fragment_container) {
ServerFragment.newInstance() ServerFragment.newInstance()
} }
} }
override fun onDestroy() {
super.onDestroy()
layoutHelper.remove()
}
override fun supportFragmentInjector(): AndroidInjector<Fragment> { override fun supportFragmentInjector(): AndroidInjector<Fragment> {
return fragmentDispatchingAndroidInjector return fragmentDispatchingAndroidInjector
} }
......
...@@ -48,4 +48,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView { ...@@ -48,4 +48,6 @@ class ChatRoomsFragment : Fragment(), ChatRoomsView {
override fun hideLoading() = view_loading.hide() override fun hideLoading() = view_loading.hide()
override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show() override fun showMessage(message: String) = Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
override fun showGenericErrorMessage() = showMessage(getString(R.string.msg_generic_error))
} }
\ No newline at end of file
...@@ -3,4 +3,6 @@ package chat.rocket.android.core.behaviours ...@@ -3,4 +3,6 @@ package chat.rocket.android.core.behaviours
interface MessageView { interface MessageView {
fun showMessage(message: String) fun showMessage(message: String)
fun showGenericErrorMessage()
} }
\ No newline at end of file
package chat.rocket.android.helper
import android.app.Activity
import android.graphics.Rect
import android.view.View
import android.view.ViewTreeObserver
import android.widget.FrameLayout
import chat.rocket.android.util.TimberLogger
class LayoutHelper {
private var childOfContent: View? = null
private var usableHeightPrevious: Int = 0
private var frameLayoutParams: FrameLayout.LayoutParams? = null
private val listener = ViewTreeObserver.OnGlobalLayoutListener { resizeChildOfContent() }
/**
* Workaround to adjust the layout when in the full screen mode.
*
* The original author of this code is Joseph Johnson and you can see his answer here: https://stackoverflow.com/a/19494006/4744263
*
* Note that this function has some differences from the original, like using *frameLayoutParams.height = usableHeightNow* instead of
* *frameLayoutParams.height = usableHeightSansKeyboard* (RobertoAllende's comment - from the same link above).
*
* @param activity The Activity to adjust the layout.
*/
fun install(activity: Activity) {
try {
val content = activity.findViewById<View>(android.R.id.content) as FrameLayout
childOfContent = content.getChildAt(0)
childOfContent?.viewTreeObserver?.addOnGlobalLayoutListener(listener)
frameLayoutParams = childOfContent?.layoutParams as FrameLayout.LayoutParams
} catch (exception: ClassCastException) {
TimberLogger.warn(exception.message.toString())
}
}
fun remove() {
childOfContent?.viewTreeObserver?.removeOnGlobalLayoutListener(listener)
childOfContent = null
frameLayoutParams = null
}
private fun resizeChildOfContent() {
val usableHeightNow = computeUsableHeight()
if (usableHeightNow != usableHeightPrevious) {
val usableHeightSansKeyboard = childOfContent?.rootView?.height ?: 0
val heightDifference = usableHeightSansKeyboard - usableHeightNow
if (heightDifference > usableHeightSansKeyboard / 4) {
// keyboard probably just became visible
frameLayoutParams?.height = usableHeightSansKeyboard - heightDifference
} else {
// keyboard probably just became hidden
frameLayoutParams?.height = usableHeightNow
}
childOfContent?.requestLayout()
usableHeightPrevious = usableHeightNow
}
}
private fun computeUsableHeight(): Int {
val rect = Rect()
childOfContent?.getWindowVisibleDisplayFrame(rect)
return rect.bottom - rect.top
}
}
\ No newline at end of file
package chat.rocket.android.util package chat.rocket.android.util
import android.support.annotation.LayoutRes import android.support.annotation.LayoutRes
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
......
...@@ -5,6 +5,7 @@ import android.content.Context ...@@ -5,6 +5,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import android.webkit.WebView
import android.webkit.WebViewClient import android.webkit.WebViewClient
import chat.rocket.android.R import chat.rocket.android.R
import kotlinx.android.synthetic.main.activity_web_view.* import kotlinx.android.synthetic.main.activity_web_view.*
...@@ -40,7 +41,7 @@ class WebViewActivity : AppCompatActivity() { ...@@ -40,7 +41,7 @@ class WebViewActivity : AppCompatActivity() {
if (web_view.canGoBack()) { if (web_view.canGoBack()) {
web_view.goBack() web_view.goBack()
} else { } else {
super.onBackPressed() finishActivity()
} }
} }
...@@ -48,14 +49,24 @@ class WebViewActivity : AppCompatActivity() { ...@@ -48,14 +49,24 @@ class WebViewActivity : AppCompatActivity() {
toolbar.title = getString(R.string.title_legal_terms) toolbar.title = getString(R.string.title_legal_terms)
toolbar.setNavigationIcon(R.drawable.ic_close_white_24dp) toolbar.setNavigationIcon(R.drawable.ic_close_white_24dp)
toolbar.setNavigationOnClickListener { toolbar.setNavigationOnClickListener {
finish() finishActivity()
} }
} }
@SuppressLint("SetJavaScriptEnabled") @SuppressLint("SetJavaScriptEnabled")
private fun setupWebView() { private fun setupWebView() {
web_view.settings.javaScriptEnabled = true web_view.settings.javaScriptEnabled = true
web_view.webViewClient = WebViewClient() web_view.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
view_loading.hide()
}
}
web_view.loadUrl(webPageUrl) web_view.loadUrl(webPageUrl)
} }
private fun finishActivity() {
super.onBackPressed()
overridePendingTransition(R.anim.hold, R.anim.slide_down)
}
} }
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="800"
android:fromYDelta="0.0%p"
android:toYDelta="0.0%p" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="350"
android:fromYDelta="0.0%"
android:toYDelta="100.0%" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="350"
android:fromYDelta="100.0%"
android:toYDelta="0.0%" />
</set>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <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" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
...@@ -14,4 +15,13 @@ ...@@ -14,4 +15,13 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_below="@+id/layout_app_bar" /> android:layout_below="@+id/layout_app_bar" />
<com.wang.avi.AVLoadingIndicatorView
android:id="@+id/view_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
app:indicatorColor="@color/black"
app:indicatorName="BallPulseIndicator" />
</RelativeLayout> </RelativeLayout>
\ No newline at end of file
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
android:id="@+id/relative_layout" android:id="@+id/relative_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:focusableInTouchMode="true"
tools:context=".authentication.server.ui.ServerFragment"> tools:context=".authentication.server.ui.ServerFragment">
<TextView <TextView
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
<!-- Regular information messages --> <!-- Regular information messages -->
<string name="msg_no_internet_connection">Sem conexão à internet</string> <string name="msg_no_internet_connection">Sem conexão à internet</string>
<string name="msg_generic_error">Desculpe, ocorreu um erro, tente novamente</string>
<string name="msg_username">nome de usuário</string> <string name="msg_username">nome de usuário</string>
<string name="msg_username_or_email">nome de usuário ou email</string> <string name="msg_username_or_email">nome de usuário ou email</string>
<string name="msg_password">senha</string> <string name="msg_password">senha</string>
...@@ -23,6 +24,7 @@ ...@@ -23,6 +24,7 @@
<string name="msg_new_to_rocket_chat">Novo no Rocket Chat? %1$s</string> <string name="msg_new_to_rocket_chat">Novo no Rocket Chat? %1$s</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_invalid_2fa_code">Código 2FA inválido</string>
<string name="msg_yesterday">ontem</string> <string name="msg_yesterday">ontem</string>
<string name="msg_message">Messagem</string> <string name="msg_message">Messagem</string>
<string name="msg_content_description_log_in_using_facebook">Fazer login através do Facebook</string> <string name="msg_content_description_log_in_using_facebook">Fazer login através do Facebook</string>
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
<!-- Regular information messages --> <!-- Regular information messages -->
<string name="msg_no_internet_connection">No internet connection</string> <string name="msg_no_internet_connection">No internet connection</string>
<string name="msg_generic_error">Sorry, an error has occurred, please try again</string>
<string name="msg_username">username</string> <string name="msg_username">username</string>
<string name="msg_username_or_email">username or email</string> <string name="msg_username_or_email">username or email</string>
<string name="msg_password">password</string> <string name="msg_password">password</string>
...@@ -24,6 +25,7 @@ ...@@ -24,6 +25,7 @@
<string name="msg_new_to_rocket_chat">New to Rocket Chat? %1$s</string> <string name="msg_new_to_rocket_chat">New to Rocket Chat? %1$s</string>
<string name="msg_new_user_agreement">By proceeding you are agreeing to our\n%1$s and %2$s</string> <string name="msg_new_user_agreement">By proceeding you are agreeing to our\n%1$s and %2$s</string>
<string name="msg_2fa_code">2FA Code</string> <string name="msg_2fa_code">2FA Code</string>
<string name="msg_invalid_2fa_code">Invalid 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_message">Message</string> <string name="msg_message">Message</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