Unverified Commit 226e069b authored by Lucio Maciel's avatar Lucio Maciel Committed by GitHub

Merge pull request #682 from RocketChat/v2-use-public-settings

Retrieve public settings on login screens
parents e6fb0c95 048be2a3
...@@ -3,20 +3,79 @@ package chat.rocket.android.authentication.login.presentation ...@@ -3,20 +3,79 @@ package chat.rocket.android.authentication.login.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.server.domain.*
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 javax.inject.Inject import javax.inject.Inject
class LoginPresenter @Inject constructor(private val view: LoginView, class LoginPresenter @Inject constructor(private val view: LoginView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator) { private val navigator: AuthenticationNavigator,
@Inject lateinit var client: RocketChatClient private val settingsInteractor: GetSettingsInteractor,
private val serverInteractor: GetCurrentServerInteractor,
factory: RocketChatClientFactory) {
// TODO - we should validate the current server when opening the app, and have a nonnull get()
private val client: RocketChatClient = factory.create(serverInteractor.get()!!)
fun setup() {
val server = serverInteractor.get()
if (server == null) {
navigator.toServerScreen()
return
}
val settings = settingsInteractor.get(server)
if (settings == null) {
navigator.toServerScreen()
return
}
var hasSocial = false
if (settings.facebookEnabled()) {
view.enableLoginByFacebook()
hasSocial = true
}
if (settings.githubEnabled()) {
view.enableLoginByGithub()
hasSocial = true
}
if (settings.googleEnabled()) {
view.enableLoginByGoogle()
hasSocial = true
}
if (settings.linkedinEnabled()) {
view.enableLoginByLinkedin()
hasSocial = true
}
if (settings.meteorEnabled()) {
view.enableLoginByMeteor()
hasSocial = true
}
if (settings.twitterEnabled()) {
view.enableLoginByTwitter()
hasSocial = true
}
if (settings.gitlabEnabled()) {
view.enableLoginByGitlab()
hasSocial = true
}
view.showSignUpView(settings.registrationEnabled())
view.showOauthView(hasSocial)
}
fun authenticate(usernameOrEmail: String, password: String) { fun authenticate(usernameOrEmail: String, password: String) {
val server = serverInteractor.get()
when { when {
server == null -> {
navigator.toServerScreen()
}
usernameOrEmail.isBlank() -> { usernameOrEmail.isBlank() -> {
view.alertWrongUsernameOrEmail() view.alertWrongUsernameOrEmail()
} }
...@@ -32,17 +91,19 @@ class LoginPresenter @Inject constructor(private val view: LoginView, ...@@ -32,17 +91,19 @@ class LoginPresenter @Inject constructor(private val view: LoginView,
client.login(usernameOrEmail, password) // TODO This function returns a user token so should we save it? client.login(usernameOrEmail, password) // TODO This function returns a user token so should we save it?
navigator.toChatList() navigator.toChatList()
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
if (exception is RocketChatTwoFactorException) { when (exception) {
is RocketChatTwoFactorException -> {
navigator.toTwoFA(usernameOrEmail, password) navigator.toTwoFA(usernameOrEmail, password)
} else { }
val message = exception.message else -> {
if (message != null) { exception.message?.let {
view.showMessage(message) view.showMessage(it)
} else { }.ifNull {
view.showGenericErrorMessage() view.showGenericErrorMessage()
} }
} }
} }
}
view.hideLoading() view.hideLoading()
} else { } else {
......
...@@ -7,6 +7,7 @@ import android.os.Bundle ...@@ -7,6 +7,7 @@ import android.os.Bundle
import android.support.v4.app.Fragment 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.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.ScrollView import android.widget.ScrollView
import android.widget.Toast import android.widget.Toast
...@@ -27,7 +28,6 @@ class LoginFragment : Fragment(), LoginView { ...@@ -27,7 +28,6 @@ class LoginFragment : Fragment(), LoginView {
@Inject lateinit var presenter: LoginPresenter @Inject lateinit var presenter: LoginPresenter
@Inject lateinit var appContext: Context // TODO we really need it? Check alternatives... @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)) {
showSignUpView(false) showSignUpView(false)
...@@ -42,7 +42,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -42,7 +42,7 @@ class LoginFragment : Fragment(), LoginView {
} }
} }
private var isGlobalLayoutListenerSetUp = false private var isGlobalLayoutListenerSetUp = false
*/
companion object { companion object {
fun newInstance() = LoginFragment() fun newInstance() = LoginFragment()
} }
...@@ -67,29 +67,28 @@ class LoginFragment : Fragment(), LoginView { ...@@ -67,29 +67,28 @@ class LoginFragment : Fragment(), LoginView {
tintEditTextDrawableStart() tintEditTextDrawableStart()
} }
presenter.setup()
showThreeSocialMethods()
button_log_in.setOnClickListener { button_log_in.setOnClickListener {
presenter.authenticate(text_username_or_email.textContent, text_password.textContent) presenter.authenticate(text_username_or_email.textContent, text_password.textContent)
} }
/*
// TODO: THIS IS A PRESENTER CONCERN - REMOVE THAT ! WE SHOULD GET THE SERVER SETTINGS!
// -------------------------------------------------------------------------------------------------------------------
showOauthView(true)
// Show the first three social account's ImageButton (REMARK: we must show at maximum *three* views)
enableLoginByFacebook()
enableLoginByGithub()
enableLoginByGoogle()
setupFabListener() setupFabListener()
// Just an example: if the server allow the new users registration then show the respective interface.
setupSignUpListener() setupSignUpListener()
showSignUpView(true)
// -------------------------------------------------------------------------------------------------------------------
*/
} }
/*
private fun showThreeSocialMethods() {
var count = 0
for (i in 0..social_accounts_container.childCount) {
val view = social_accounts_container.getChildAt(i) as? ImageButton ?: continue
if (view.isEnabled && count < 3) {
view.visibility = View.VISIBLE
count++
}
}
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
if (isGlobalLayoutListenerSetUp) { if (isGlobalLayoutListenerSetUp) {
...@@ -97,58 +96,58 @@ class LoginFragment : Fragment(), LoginView { ...@@ -97,58 +96,58 @@ class LoginFragment : Fragment(), LoginView {
isGlobalLayoutListenerSetUp = false isGlobalLayoutListenerSetUp = false
} }
} }
*/
override fun showOauthView(value: Boolean) { override fun showOauthView(value: Boolean) {
// if (value) { if (value) {
// social_accounts_container.setVisibility(true) social_accounts_container.setVisibility(true)
// button_fab.setVisibility(true) button_fab.setVisibility(true)
//
// // We need to setup the layout to hide and show the oauth interface when the soft keyboard is shown // We need to setup the layout to hide and show the oauth interface when the soft keyboard is shown
// // (means that the user touched the text_username_or_email or text_password EditText to fill that respective fields). // (means that the user touched the text_username_or_email or text_password EditText to fill that respective fields).
// if (!isGlobalLayoutListenerSetUp) { if (!isGlobalLayoutListenerSetUp) {
// scroll_view.viewTreeObserver.addOnGlobalLayoutListener(layoutListener) scroll_view.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
// isGlobalLayoutListenerSetUp = true isGlobalLayoutListenerSetUp = true
// } }
// } else { } else {
// social_accounts_container.setVisibility(false) social_accounts_container.setVisibility(false)
// button_fab.setVisibility(false) button_fab.setVisibility(false)
// } }
} }
override fun setupFabListener() { override fun setupFabListener() {
// button_fab.setOnClickListener({ button_fab.setOnClickListener({
// button_fab.hide() button_fab.hide()
// showRemainingSocialAccountsView() showRemainingSocialAccountsView()
// scrollToBottom() scrollToBottom()
// }) })
} }
override fun enableLoginByFacebook() { override fun enableLoginByFacebook() {
button_facebook.setVisibility(true) button_facebook.isEnabled = true
} }
override fun enableLoginByGithub() { override fun enableLoginByGithub() {
button_github.setVisibility(true) button_github.isEnabled = true
} }
override fun enableLoginByGoogle() { override fun enableLoginByGoogle() {
button_google.setVisibility(true) button_google.isEnabled = true
} }
override fun enableLoginByLinkedin() { override fun enableLoginByLinkedin() {
button_linkedin.setVisibility(true) button_linkedin.isEnabled = true
} }
override fun enableLoginByMeteor() { override fun enableLoginByMeteor() {
button_meteor.setVisibility(true) button_meteor.isEnabled = true
} }
override fun enableLoginByTwitter() { override fun enableLoginByTwitter() {
button_twitter.setVisibility(true) button_twitter.isEnabled = true
} }
override fun enableLoginByGitlab() { override fun enableLoginByGitlab() {
button_gitlab.setVisibility(true) button_gitlab.isEnabled = true
} }
override fun showSignUpView(value: Boolean) = text_new_to_rocket_chat.setVisibility(value) override fun showSignUpView(value: Boolean) = text_new_to_rocket_chat.setVisibility(value)
...@@ -195,7 +194,7 @@ class LoginFragment : Fragment(), LoginView { ...@@ -195,7 +194,7 @@ class LoginFragment : Fragment(), LoginView {
DrawableHelper.compoundDrawables(arrayOf(text_username_or_email, text_password), drawables) DrawableHelper.compoundDrawables(arrayOf(text_username_or_email, text_password), drawables)
} }
} }
/*
private fun showLoginButton(value: Boolean) { private fun showLoginButton(value: Boolean) {
button_log_in.setVisibility(value) button_log_in.setVisibility(value)
} }
...@@ -212,26 +211,26 @@ class LoginFragment : Fragment(), LoginView { ...@@ -212,26 +211,26 @@ class LoginFragment : Fragment(), LoginView {
TextHelper.addLink(text_new_to_rocket_chat, arrayOf(signUp), arrayOf(signUpListener)) TextHelper.addLink(text_new_to_rocket_chat, arrayOf(signUp), arrayOf(signUpListener))
} }
*/
private fun enableUserInput(value: Boolean) { private fun enableUserInput(value: Boolean) {
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()) { if (isEditTextEmpty()) {
// showSignUpView(value) showSignUpView(value)
// showOauthView(value) showOauthView(value)
// } }
} }
/*
// Returns true if *all* EditTexts are empty. // Returns true if *all* EditTexts are empty.
private fun isEditTextEmpty(): Boolean = text_username_or_email.textContent.isBlank() && text_password.textContent.isEmpty() private fun isEditTextEmpty(): Boolean = text_username_or_email.textContent.isBlank() && text_password.textContent.isEmpty()
private fun showRemainingSocialAccountsView() { private fun showRemainingSocialAccountsView() {
social_accounts_container.postDelayed({ social_accounts_container.postDelayed({
enableLoginByLinkedin() for (i in 0..social_accounts_container.childCount) {
enableLoginByMeteor() val view = social_accounts_container.getChildAt(i) as? ImageButton ?: continue
enableLoginByTwitter() if (view.isEnabled) view.visibility = View.VISIBLE
enableLoginByGitlab() }
}, 1000) }, 1000)
} }
...@@ -240,5 +239,4 @@ class LoginFragment : Fragment(), LoginView { ...@@ -240,5 +239,4 @@ class LoginFragment : Fragment(), LoginView {
scroll_view.fullScroll(ScrollView.FOCUS_DOWN) scroll_view.fullScroll(ScrollView.FOCUS_DOWN)
}, 1250) }, 1250)
} }
*/
} }
\ No newline at end of file
...@@ -3,31 +3,24 @@ package chat.rocket.android.authentication.presentation ...@@ -3,31 +3,24 @@ package chat.rocket.android.authentication.presentation
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatrooms.ui.MainActivity
import chat.rocket.android.authentication.login.ui.LoginFragment import chat.rocket.android.authentication.login.ui.LoginFragment
import chat.rocket.android.authentication.signup.ui.SignupFragment import chat.rocket.android.authentication.signup.ui.SignupFragment
import chat.rocket.android.authentication.twofactor.ui.TwoFAFragment import chat.rocket.android.authentication.twofactor.ui.TwoFAFragment
import chat.rocket.android.authentication.ui.AuthenticationActivity import chat.rocket.android.authentication.ui.AuthenticationActivity
import chat.rocket.android.chatrooms.ui.MainActivity
import chat.rocket.android.util.addFragmentBackStack import chat.rocket.android.util.addFragmentBackStack
import chat.rocket.android.webview.webViewIntent import chat.rocket.android.webview.webViewIntent
class AuthenticationNavigator(internal val activity: AuthenticationActivity, internal val context: Context) { class AuthenticationNavigator(internal val activity: AuthenticationActivity, internal val context: Context) {
lateinit var server: String fun toLogin() {
lateinit var usernameOrEmail: String
lateinit var password: String
fun toLogin(server: String) {
this.server = server
activity.addFragmentBackStack("loginFragment", R.id.fragment_container) { activity.addFragmentBackStack("loginFragment", R.id.fragment_container) {
LoginFragment.newInstance() LoginFragment.newInstance()
} }
} }
fun toTwoFA(usernameOrEmail: String, password: String) { fun toTwoFA(username: String, password: String) {
this.usernameOrEmail = usernameOrEmail
this.password = password
activity.addFragmentBackStack("twoFAFragment", R.id.fragment_container) { activity.addFragmentBackStack("twoFAFragment", R.id.fragment_container) {
TwoFAFragment.newInstance() TwoFAFragment.newInstance(username, password)
} }
} }
...@@ -37,16 +30,8 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity, int ...@@ -37,16 +30,8 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity, int
} }
} }
fun toTermsOfService() { fun toWebPage(url: String) {
val webPageUrl = server + "/terms-of-service" // TODO Move to UrlHelper activity.startActivity(context.webViewIntent(url))
activity.startActivity(context.webViewIntent(webPageUrl))
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
}
fun toPrivacyPolicy() {
val webPageUrl = server + "/privacy-policy" // TODO Move to UrlHelper
activity.startActivity(context.webViewIntent(webPageUrl))
activity.overridePendingTransition(R.anim.slide_up, R.anim.hold)
} }
fun toChatList() { fun toChatList() {
...@@ -56,4 +41,8 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity, int ...@@ -56,4 +41,8 @@ class AuthenticationNavigator(internal val activity: AuthenticationActivity, int
activity.startActivity(chatList) activity.startActivity(chatList)
activity.finish() activity.finish()
} }
fun toServerScreen() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
} }
...@@ -3,28 +3,57 @@ package chat.rocket.android.authentication.server.presentation ...@@ -3,28 +3,57 @@ package chat.rocket.android.authentication.server.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.server.domain.*
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.launchUI import chat.rocket.android.util.launchUI
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.settings
import java.security.InvalidParameterException
import javax.inject.Inject import javax.inject.Inject
class ServerPresenter @Inject constructor(private val view: ServerView, class ServerPresenter @Inject constructor(private val view: ServerView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator) { private val navigator: AuthenticationNavigator,
@Inject lateinit var client: RocketChatClient private val serverInteractor: SaveCurrentServerInteractor,
private val settingsInteractor: SaveSettingsInteractor,
private val factory: RocketChatClientFactory) {
private var settingsFilter = arrayOf(SITE_URL, SITE_NAME,
FAVICON_512, USE_REALNAME, ALLOW_ROOM_NAME_SPECIAL_CHARS, FAVORITE_ROOMS,
ACCOUNT_LOGIN_FORM, ACCOUNT_GOOGLE, ACCOUNT_FACEBOOK, ACCOUNT_GITHUB, ACCOUNT_GITLAB,
ACCOUNT_LINKEDIN, ACCOUNT_METEOR, ACCOUNT_TWITTER, ACCOUNT_WORDPRESS, LDAP_ENABLE,
ACCOUNT_REGISTRATION, STORAGE_TYPE, HIDE_USER_JOIN, HIDE_USER_LEAVE, HIDE_TYPE_AU,
HIDE_MUTE_UNMUTE, HIDE_TYPE_RU, ACCOUNT_CUSTOM_FIELDS)
fun connect(server: String) { fun connect(server: String) {
var cli: RocketChatClient? = null
try {
cli = factory.create(server)
} catch (ex: InvalidParameterException) {
view.showMessage(ex.message!!)
}
cli?.let { client ->
launchUI(strategy) { launchUI(strategy) {
if (NetworkHelper.hasInternetAccess()) { if (NetworkHelper.hasInternetAccess()) {
view.showLoading() view.showLoading()
// TODO - validate server URL and get server settings and info before going to Login screen try {
//client.connect(server) val settings = client.settings(*settingsFilter)
navigator.toLogin(server) settingsInteractor.save(server, settings)
serverInteractor.save(server)
navigator.toLogin()
} catch (ex: Exception) {
ex.printStackTrace()
view.showMessage(ex.message!!)
} finally {
view.hideLoading() view.hideLoading()
}
} else { } else {
view.showNoInternetConnection() view.showNoInternetConnection()
} }
} }
} }
}
} }
\ No newline at end of file
...@@ -3,20 +3,26 @@ package chat.rocket.android.authentication.signup.presentation ...@@ -3,20 +3,26 @@ package chat.rocket.android.authentication.signup.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.NetworkHelper import chat.rocket.android.helper.NetworkHelper
import chat.rocket.android.server.domain.GetCurrentServerInteractor
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.core.RocketChatClient
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 javax.inject.Inject import javax.inject.Inject
class SignupPresenter @Inject constructor(private val view: SignupView, class SignupPresenter @Inject constructor(private val view: SignupView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator) { private val navigator: AuthenticationNavigator,
@Inject lateinit var client: RocketChatClient private val serverInteractor: GetCurrentServerInteractor,
private val factory: RocketChatClientFactory) {
fun signup(name: String, username: String, password: String, email: String) { fun signup(name: String, username: String, password: String, email: String) {
val server = serverInteractor.get()
when { when {
server == null -> {
navigator.toServerScreen()
}
name.isBlank() -> { name.isBlank() -> {
view.alertBlankName() view.alertBlankName()
} }
...@@ -30,6 +36,7 @@ class SignupPresenter @Inject constructor(private val view: SignupView, ...@@ -30,6 +36,7 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
view.alertBlankEmail() view.alertBlankEmail()
} }
else -> { else -> {
val client = factory.create(server)
launchUI(strategy) { launchUI(strategy) {
if (NetworkHelper.hasInternetAccess()) { if (NetworkHelper.hasInternetAccess()) {
view.showLoading() view.showLoading()
...@@ -57,10 +64,14 @@ class SignupPresenter @Inject constructor(private val view: SignupView, ...@@ -57,10 +64,14 @@ class SignupPresenter @Inject constructor(private val view: SignupView,
} }
fun termsOfService() { fun termsOfService() {
navigator.toTermsOfService() serverInteractor.get()?.let {
navigator.toWebPage("/terms-of-service")
}
} }
fun privacyPolicy() { fun privacyPolicy() {
navigator.toPrivacyPolicy() serverInteractor.get()?.let {
navigator.toWebPage("/privacy-policy")
}
} }
} }
\ No newline at end of file
...@@ -2,29 +2,38 @@ package chat.rocket.android.authentication.twofactor.presentation ...@@ -2,29 +2,38 @@ package chat.rocket.android.authentication.twofactor.presentation
import chat.rocket.android.authentication.presentation.AuthenticationNavigator import chat.rocket.android.authentication.presentation.AuthenticationNavigator
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.infraestructure.RocketChatClientFactory
import chat.rocket.android.helper.NetworkHelper 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.RocketChatAuthException
import chat.rocket.common.RocketChatException import chat.rocket.common.RocketChatException
import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.login import chat.rocket.core.internal.rest.login
import javax.inject.Inject import javax.inject.Inject
class TwoFAPresenter @Inject constructor(private val view: TwoFAView, class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
private val strategy: CancelStrategy, private val strategy: CancelStrategy,
private val navigator: AuthenticationNavigator) { private val navigator: AuthenticationNavigator,
@Inject lateinit var client: RocketChatClient private val serverInteractor: GetCurrentServerInteractor,
private val factory: RocketChatClientFactory) {
fun authenticate(twoFactorAuthenticationCode: String) { // TODO: If the usernameOrEmail and password was informed by the user on the previous screen, then we should pass only the pin, like this: fun authenticate(pin: EditText)
fun authenticate(usernameOrEmail: String, password: String, twoFactorAuthenticationCode: String) {
val server = serverInteractor.get()
if (twoFactorAuthenticationCode.isBlank()) { if (twoFactorAuthenticationCode.isBlank()) {
view.alertBlankTwoFactorAuthenticationCode() view.alertBlankTwoFactorAuthenticationCode()
} else if (server == null) {
navigator.toServerScreen()
} else { } else {
launchUI(strategy) { launchUI(strategy) {
val client = factory.create(server)
if (NetworkHelper.hasInternetAccess()) { if (NetworkHelper.hasInternetAccess()) {
view.showLoading() view.showLoading()
try { try {
client.login(navigator.usernameOrEmail, navigator.password, twoFactorAuthenticationCode) // TODO This function returns a user token so should we save it? // The token is saved via the client TokenProvider
client.login(usernameOrEmail, password, twoFactorAuthenticationCode)
navigator.toChatList() navigator.toChatList()
} catch (exception: RocketChatException) { } catch (exception: RocketChatException) {
if (exception is RocketChatAuthException) { if (exception is RocketChatAuthException) {
...@@ -38,7 +47,6 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView, ...@@ -38,7 +47,6 @@ class TwoFAPresenter @Inject constructor(private val view: TwoFAView,
} }
} }
} }
view.hideLoading() view.hideLoading()
} else { } else {
view.showNoInternetConnection() view.showNoInternetConnection()
......
...@@ -22,15 +22,29 @@ import javax.inject.Inject ...@@ -22,15 +22,29 @@ 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 // TODO we really need it? Check alternatives... lateinit var username: String
lateinit var password: String
// TODO - we could create an in memory repository to save username and password.
companion object { companion object {
fun newInstance() = TwoFAFragment() private const val USERNAME = "username"
private const val PASSWORD = "password"
fun newInstance(username: String, password: String) = TwoFAFragment().apply {
arguments = Bundle(1).apply {
putString(USERNAME, username)
putString(PASSWORD, password)
}
}
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
// TODO - research a better way to initialize parameters on fragments.
username = arguments?.getString(USERNAME) ?: ""
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? = inflater.inflate(R.layout.fragment_authentication_two_fa, container, false)
...@@ -51,9 +65,11 @@ class TwoFAFragment : Fragment(), TwoFAView { ...@@ -51,9 +65,11 @@ class TwoFAFragment : Fragment(), TwoFAView {
} }
override fun alertBlankTwoFactorAuthenticationCode() { override fun alertBlankTwoFactorAuthenticationCode() {
AnimationHelper.vibrateSmartPhone(appContext) activity?.let {
AnimationHelper.vibrateSmartPhone(it)
AnimationHelper.shakeView(text_two_factor_auth) AnimationHelper.shakeView(text_two_factor_auth)
} }
}
override fun alertInvalidTwoFactorAuthenticationCode() = showMessage(getString(R.string.msg_invalid_2fa_code)) override fun alertInvalidTwoFactorAuthenticationCode() = showMessage(getString(R.string.msg_invalid_2fa_code))
...@@ -89,7 +105,7 @@ class TwoFAFragment : Fragment(), TwoFAView { ...@@ -89,7 +105,7 @@ class TwoFAFragment : Fragment(), TwoFAView {
private fun setupOnClickListener() { private fun setupOnClickListener() {
button_log_in.setOnClickListener { button_log_in.setOnClickListener {
presenter.authenticate(text_two_factor_auth.textContent) presenter.authenticate(username, password, text_two_factor_auth.textContent)
} }
} }
} }
\ No newline at end of file
package chat.rocket.android.chatrooms.presentation package chat.rocket.android.chatrooms.presentation
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.infraestructure.RocketChatClientFactory
import chat.rocket.android.util.launchUI import chat.rocket.android.util.launchUI
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.chatRooms import chat.rocket.core.internal.rest.chatRooms
import chat.rocket.core.model.ChatRoom import chat.rocket.core.model.ChatRoom
import javax.inject.Inject import javax.inject.Inject
class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView, private val strategy: CancelStrategy) { class ChatRoomsPresenter @Inject constructor(private val view: ChatRoomsView,
@Inject lateinit var client: RocketChatClient private val strategy: CancelStrategy,
private val serverInteractor: GetCurrentServerInteractor,
private val factory: RocketChatClientFactory) {
lateinit var client: RocketChatClient
fun chatRooms() { fun chatRooms() {
// TODO - check for current server
client = factory.create(serverInteractor.get()!!)
launchUI(strategy) { launchUI(strategy) {
view.showLoading() view.showLoading()
val chatRooms = client.chatRooms().update val chatRooms = client.chatRooms().update
......
...@@ -30,7 +30,7 @@ class ChatRoomsAdapter(private var dataSet: MutableList<ChatRoom>, private val c ...@@ -30,7 +30,7 @@ class ChatRoomsAdapter(private var dataSet: MutableList<ChatRoom>, private val c
if (chatRoom.type == RoomType.ONE_TO_ONE) { if (chatRoom.type == RoomType.ONE_TO_ONE) {
// TODO Check the best way to get the current server url. // TODO Check the best way to get the current server url.
val canonicalUrl = chatRoom.client.restUrl.toString() val canonicalUrl = chatRoom.client.url
holder.userAvatar.setImageURI(UrlHelper.getAvatarUrl(canonicalUrl, chatRoomName)) holder.userAvatar.setImageURI(UrlHelper.getAvatarUrl(canonicalUrl, chatRoomName))
holder.userAvatar.setVisibility(true) holder.userAvatar.setVisibility(true)
} else { } else {
......
...@@ -3,16 +3,20 @@ package chat.rocket.android.dagger.module ...@@ -3,16 +3,20 @@ package chat.rocket.android.dagger.module
import android.app.Application import android.app.Application
import android.arch.persistence.room.Room import android.arch.persistence.room.Room
import android.content.Context import android.content.Context
import android.content.SharedPreferences
import chat.rocket.android.BuildConfig import chat.rocket.android.BuildConfig
import chat.rocket.android.app.RocketChatDatabase import chat.rocket.android.app.RocketChatDatabase
import chat.rocket.android.authentication.infraestructure.AuthTokenRepository import chat.rocket.android.authentication.infraestructure.AuthTokenRepository
import chat.rocket.android.server.domain.CurrentServerRepository
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.android.server.infraestructure.MemorySettingsRepository
import chat.rocket.android.server.infraestructure.ServerDao import chat.rocket.android.server.infraestructure.ServerDao
import chat.rocket.android.server.infraestructure.SharedPrefsCurrentServerRepository
import chat.rocket.android.util.TimberLogger import chat.rocket.android.util.TimberLogger
import chat.rocket.common.util.PlatformLogger import chat.rocket.common.util.PlatformLogger
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import javax.inject.Singleton import javax.inject.Singleton
...@@ -29,8 +33,7 @@ class AppModule { ...@@ -29,8 +33,7 @@ class AppModule {
platformLogger = logger platformLogger = logger
// TODO remove // TODO remove
restUrl = HttpUrl.parse("https://open.rocket.chat")!! restUrl = "https://open.rocket.chat"
websocketUrl = "https://open.rocket.chat"
} }
} }
...@@ -84,4 +87,21 @@ class AppModule { ...@@ -84,4 +87,21 @@ class AppModule {
fun providePlatformLogger(): PlatformLogger { fun providePlatformLogger(): PlatformLogger {
return TimberLogger return TimberLogger
} }
@Provides
fun provideSharedPreferences(context: Application): SharedPreferences {
return context.getSharedPreferences("rocket.chat", Context.MODE_PRIVATE)
}
@Provides
@Singleton
fun provideCurrentServerRepository(prefs: SharedPreferences): CurrentServerRepository {
return SharedPrefsCurrentServerRepository(prefs)
}
@Provides
@Singleton
fun provideSettingsRepository(): SettingsRepository {
return MemorySettingsRepository()
}
} }
package chat.rocket.android.helper package chat.rocket.android.helper
import kotlinx.coroutines.experimental.CommonPool import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.run import kotlinx.coroutines.experimental.withContext
import java.io.IOException import java.io.IOException
import java.net.InetSocketAddress import java.net.InetSocketAddress
import java.net.Socket import java.net.Socket
...@@ -15,7 +15,7 @@ object NetworkHelper { ...@@ -15,7 +15,7 @@ object NetworkHelper {
* *
* @return true if there is internet access, false otherwise. * @return true if there is internet access, false otherwise.
*/ */
suspend fun hasInternetAccess(): Boolean = run(CommonPool) { suspend fun hasInternetAccess(): Boolean = withContext(CommonPool) {
try { try {
val socket = Socket() val socket = Socket()
val inetSocketAddress = InetSocketAddress("8.8.8.8", 53) val inetSocketAddress = InetSocketAddress("8.8.8.8", 53)
......
package chat.rocket.android.server.domain
interface CurrentServerRepository {
fun save(url: String)
fun get(): String?
}
\ No newline at end of file
package chat.rocket.android.server.domain
import javax.inject.Inject
class GetCurrentServerInteractor @Inject constructor(private val repository: CurrentServerRepository) {
fun get(): String? = repository.get()
}
\ No newline at end of file
package chat.rocket.android.server.domain
import javax.inject.Inject
class GetSettingsInteractor @Inject constructor(private val repository: SettingsRepository) {
fun get(url: String) = repository.get(url)
}
\ No newline at end of file
package chat.rocket.android.server.domain
import javax.inject.Inject
class SaveCurrentServerInteractor @Inject constructor(private val repository: CurrentServerRepository) {
fun save(url: String) = repository.save(url)
}
\ No newline at end of file
package chat.rocket.android.server.domain
import chat.rocket.core.model.Value
import javax.inject.Inject
class SaveSettingsInteractor @Inject constructor(private val repository: SettingsRepository) {
fun save(url: String, settings: Map<String, Value<Any>>) = repository.save(url, settings)
}
\ No newline at end of file
package chat.rocket.android.server.domain
import chat.rocket.core.model.Value
interface SettingsRepository {
fun save(url: String, settings: Map<String, Value<Any>>)
fun get(url: String): Map<String, Value<Any>>?
}
fun Map<String, Value<Any>>.googleEnabled(): Boolean = (this[ACCOUNT_GOOGLE] as Value<Boolean>?)?.value == true
fun Map<String, Value<Any>>.facebookEnabled(): Boolean = (this[ACCOUNT_FACEBOOK] as Value<Boolean>?)?.value == true
fun Map<String, Value<Any>>.githubEnabled(): Boolean = (this[ACCOUNT_GITHUB] as Value<Boolean>?)?.value == true
fun Map<String, Value<Any>>.linkedinEnabled(): Boolean = (this[ACCOUNT_LINKEDIN] as Value<Boolean>?)?.value == true
fun Map<String, Value<Any>>.meteorEnabled(): Boolean = (this[ACCOUNT_METEOR] as Value<Boolean>?)?.value == true
fun Map<String, Value<Any>>.twitterEnabled(): Boolean = (this[ACCOUNT_TWITTER] as Value<Boolean>?)?.value == true
fun Map<String, Value<Any>>.gitlabEnabled(): Boolean = (this[ACCOUNT_GITLAB] as Value<Boolean>?)?.value == true
fun Map<String, Value<Any>>.wordpressEnabled(): Boolean = (this[ACCOUNT_WORDPRESS] as Value<Boolean>?)?.value == true
fun Map<String, Value<Any>>.registrationEnabled(): Boolean {
val value = this[ACCOUNT_REGISTRATION] as Value<String>?
return value?.value == "Public"
}
const val ACCOUNT_FACEBOOK = "Accounts_OAuth_Facebook"
const val ACCOUNT_GITHUB = "Accounts_OAuth_Github"
const val ACCOUNT_GITLAB = "Accounts_OAuth_Gitlab"
const val ACCOUNT_GOOGLE = "Accounts_OAuth_Google"
const val ACCOUNT_LINKEDIN = "Accounts_OAuth_Linkedin"
const val ACCOUNT_METEOR = "Accounts_OAuth_Meteor"
const val ACCOUNT_TWITTER = "Accounts_OAuth_Twitter"
const val ACCOUNT_WORDPRESS = "Accounts_OAuth_Wordpress"
const val ACCOUNT_REGISTRATION = "Accounts_RegistrationForm"
const val ACCOUNT_LOGIN_FORM = "Accounts_ShowFormLogin"
const val ACCOUNT_CUSTOM_FIELDS = "Accounts_CustomFields"
const val SITE_URL = "Site_Url"
const val SITE_NAME = "Site_Name"
const val FAVICON_512 = "Assets_favicon_512"
const val USE_REALNAME = "UI_Use_Real_Name"
const val ALLOW_ROOM_NAME_SPECIAL_CHARS = "UI_Allow_room_names_with_special_chars"
const val FAVORITE_ROOMS = "Favorite_Rooms"
const val LDAP_ENABLE = "LDAP_Enable"
const val STORAGE_TYPE = "FileUpload_Storage_Type"
const val HIDE_USER_JOIN = "Message_HideType_uj"
const val HIDE_USER_LEAVE = "Message_HideType_ul"
const val HIDE_TYPE_AU = "Message_HideType_au"
const val HIDE_TYPE_RU = "Message_HideType_ru"
const val HIDE_MUTE_UNMUTE = "Message_HideType_mute_unmute"
\ No newline at end of file
package chat.rocket.android.server.infraestructure
import chat.rocket.android.server.domain.SettingsRepository
import chat.rocket.core.model.Value
class MemorySettingsRepository : SettingsRepository {
val cache = HashMap<String, Map<String, Value<Any>>>()
override fun save(url: String, settings: Map<String, Value<Any>>) {
cache.put(url, settings)
}
override fun get(url: String): Map<String, Value<Any>>? {
return cache[url]
}
}
\ No newline at end of file
package chat.rocket.android.server.infraestructure
import chat.rocket.android.authentication.infraestructure.AuthTokenRepository
import chat.rocket.common.util.PlatformLogger
import chat.rocket.core.RocketChatClient
import okhttp3.OkHttpClient
import javax.inject.Inject
class RocketChatClientFactory @Inject constructor(val okHttpClient: OkHttpClient,
val repository: AuthTokenRepository,
val logger: PlatformLogger) {
private val cache = HashMap<String, RocketChatClient>()
fun create(url: String): RocketChatClient {
cache[url]?.let {
return it
}
val client = RocketChatClient.create {
httpClient = okHttpClient
restUrl = url
tokenRepository = repository
platformLogger = logger
}
cache.put(url, client)
return client
}
}
\ No newline at end of file
...@@ -4,7 +4,7 @@ import android.arch.persistence.room.Entity ...@@ -4,7 +4,7 @@ import android.arch.persistence.room.Entity
import android.arch.persistence.room.Index import android.arch.persistence.room.Index
import android.arch.persistence.room.PrimaryKey import android.arch.persistence.room.PrimaryKey
@Entity(tableName = "server", indices = arrayOf(Index(value = "host", unique = true))) @Entity(tableName = "server", indices = [(Index(value = ["host"], unique = true))])
data class ServerEntity( data class ServerEntity(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
val id: Long, val id: Long,
......
package chat.rocket.android.server.infraestructure
import android.content.SharedPreferences
import chat.rocket.android.server.domain.CurrentServerRepository
class SharedPrefsCurrentServerRepository(private val preferences: SharedPreferences) : CurrentServerRepository {
private val CURRENT_SERVER = "current_server"
override fun save(url: String) {
preferences.edit().putString(CURRENT_SERVER, url).apply()
}
override fun get(): String? {
return preferences.getString(CURRENT_SERVER, null)
}
}
\ No newline at end of file
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