diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 0c9bac61a1..5f1687c9c9 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -33,7 +33,9 @@ - + addFragmentToBackstack(R.id.simpleFragmentContainer, LoginSignUpSignInSelectionFragment::class.java) ServerType.Modular, - ServerType.Other -> Unit // TODO addFragmentToBackstack(R.id.simpleFragmentContainer, LoginEnterHomeServerFragment::class.java) + ServerType.Other -> addFragmentToBackstack(R.id.simpleFragmentContainer, LoginServerUrlFormFragment::class.java) + } + } + + private fun onSignModeSelected() = withState(loginViewModel) { + when (it.signMode) { + SignMode.SignUp -> Unit // TODO addFragmentToBackstack(R.id.simpleFragmentContainer, SignUpFragment::class.java) + SignMode.SignIn -> addFragmentToBackstack(R.id.simpleFragmentContainer, LoginFragment::class.java) } } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt index 4f918baa8a..582567aba5 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginFragment.kt @@ -18,20 +18,15 @@ package im.vector.riotx.features.login import android.os.Bundle import android.view.View -import android.view.inputmethod.EditorInfo import android.widget.Toast import androidx.core.view.isVisible import androidx.transition.TransitionManager import com.airbnb.mvrx.* -import com.jakewharton.rxbinding3.view.focusChanges import com.jakewharton.rxbinding3.widget.textChanges import im.vector.riotx.R -import im.vector.riotx.core.extensions.setTextWithColoredPart import im.vector.riotx.core.extensions.showPassword -import im.vector.riotx.core.utils.openUrlInExternalBrowser -import im.vector.riotx.features.homeserver.ServerUrlsRepository import io.reactivex.Observable -import io.reactivex.functions.Function3 +import io.reactivex.functions.BiFunction import io.reactivex.rxkotlin.subscribeBy import kotlinx.android.synthetic.main.fragment_login.* import javax.inject.Inject @@ -49,41 +44,8 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - setupNotice() - setupAuthButton() + setupLoginButton() setupPasswordReveal() - - homeServerField.focusChanges() - .subscribe { - if (!it) { - viewModel.handle(LoginAction.UpdateHomeServer(homeServerField.text.toString())) - } - } - .disposeOnDestroyView() - - homeServerField.setOnEditorActionListener { _, actionId, _ -> - if (actionId == EditorInfo.IME_ACTION_DONE) { - viewModel.handle(LoginAction.UpdateHomeServer(homeServerField.text.toString())) - return@setOnEditorActionListener true - } - return@setOnEditorActionListener false - } - - val initHsUrl = viewModel.getInitialHomeServerUrl() - if (initHsUrl != null) { - homeServerField.setText(initHsUrl) - } else { - homeServerField.setText(ServerUrlsRepository.getDefaultHomeServerUrl(requireContext())) - } - viewModel.handle(LoginAction.UpdateHomeServer(homeServerField.text.toString())) - } - - private fun setupNotice() { - riotx_no_registration_notice.setTextWithColoredPart(R.string.riotx_no_registration_notice, R.string.riotx_no_registration_notice_colored_part) - - riotx_no_registration_notice.setOnClickListener { - openUrlInExternalBrowser(requireActivity(), "https://about.riot.im/downloads") - } } private fun authenticate() { @@ -93,23 +55,21 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { viewModel.handle(LoginAction.Login(login, password)) } - private fun setupAuthButton() { + private fun setupLoginButton() { Observable .combineLatest( loginField.textChanges().map { it.trim().isNotEmpty() }, passwordField.textChanges().map { it.trim().isNotEmpty() }, - homeServerField.textChanges().map { it.trim().isNotEmpty() }, - Function3 { isLoginNotEmpty, isPasswordNotEmpty, isHomeServerNotEmpty -> - isLoginNotEmpty && isPasswordNotEmpty && isHomeServerNotEmpty + BiFunction { isLoginNotEmpty, isPasswordNotEmpty -> + isLoginNotEmpty && isPasswordNotEmpty } ) .subscribeBy { authenticateButton.isEnabled = it } .disposeOnDestroyView() authenticateButton.setOnClickListener { authenticate() } - - authenticateButtonSso.setOnClickListener { openSso() } } + // TODO Move to server selection screen private fun openSso() { loginSharedActionViewModel.post(LoginNavigation.OpenSsoLoginFallback) } @@ -148,7 +108,6 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { loginField.isVisible = false passwordContainer.isVisible = false authenticateButton.isVisible = false - authenticateButtonSso.isVisible = false passwordShown = false renderPasswordField() } @@ -158,7 +117,6 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { loginField.isVisible = false passwordContainer.isVisible = false authenticateButton.isVisible = false - authenticateButtonSso.isVisible = false Toast.makeText(requireActivity(), "Authenticate failure: ${state.asyncHomeServerLoginFlowRequest.error}", Toast.LENGTH_LONG).show() } is Success -> { @@ -170,7 +128,6 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { loginField.isVisible = true passwordContainer.isVisible = true authenticateButton.isVisible = true - authenticateButtonSso.isVisible = false if (loginField.text.isNullOrBlank() && passwordField.text.isNullOrBlank()) { // Jump focus to login loginField.requestFocus() @@ -180,13 +137,11 @@ class LoginFragment @Inject constructor() : AbstractLoginFragment() { loginField.isVisible = false passwordContainer.isVisible = false authenticateButton.isVisible = false - authenticateButtonSso.isVisible = true } LoginMode.Unsupported -> { loginField.isVisible = false passwordContainer.isVisible = false authenticateButton.isVisible = false - authenticateButtonSso.isVisible = false Toast.makeText(requireActivity(), "None of the homeserver login mode is supported by RiotX", Toast.LENGTH_LONG).show() } } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt index 011100a6f5..7be5223ac7 100644 --- a/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginServerSelectionFragment.kt @@ -21,6 +21,7 @@ import android.view.View import butterknife.OnClick import com.airbnb.mvrx.withState import im.vector.riotx.R +import im.vector.riotx.core.utils.openUrlInExternalBrowser import kotlinx.android.synthetic.main.fragment_login_server_selection.* import me.gujun.android.span.span import javax.inject.Inject @@ -50,6 +51,7 @@ class LoginServerSelectionFragment @Inject constructor() : AbstractLoginFragment textDecorationLine = "underline" onClick = { // TODO + openUrlInExternalBrowser(requireActivity(), "https://example.org") } } diff --git a/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt b/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt new file mode 100644 index 0000000000..bf5a6b9866 --- /dev/null +++ b/vector/src/main/java/im/vector/riotx/features/login/LoginServerUrlFormFragment.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotx.features.login + +import android.os.Bundle +import android.view.View +import android.view.inputmethod.EditorInfo +import androidx.core.view.isVisible +import butterknife.OnClick +import com.airbnb.mvrx.withState +import com.jakewharton.rxbinding3.widget.textChanges +import im.vector.riotx.R +import im.vector.riotx.core.utils.openUrlInExternalBrowser +import kotlinx.android.synthetic.main.fragment_login_server_url_form.* +import javax.inject.Inject + +/** + * + */ +class LoginServerUrlFormFragment @Inject constructor() : AbstractLoginFragment() { + + override fun getLayoutResId() = R.layout.fragment_login_server_url_form + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // TODO Import code from Riot to clear error on TIL + loginServerUrlFormHomeServerUrl.textChanges() + .subscribe( + { + loginServerUrlFormHomeServerUrlTil.error = null + }, + { + // Ignore error + }) + .disposeOnDestroy() + + loginServerUrlFormHomeServerUrl.setOnEditorActionListener { _, actionId, _ -> + if (actionId == EditorInfo.IME_ACTION_DONE) { + submit() + return@setOnEditorActionListener true + } + return@setOnEditorActionListener false + } + } + + @OnClick(R.id.loginServerUrlFormLearnMore) + fun learMore() { + // TODO + openUrlInExternalBrowser(requireActivity(), "https://example.org") + } + + @OnClick(R.id.loginServerUrlFormSubmit) + fun submit() { + // TODO Static check of homeserver url, empty, malformed, etc. + viewModel.handle(LoginAction.InitWith(LoginConfig(loginServerUrlFormHomeServerUrl.text.toString(), null))) + } + + override fun invalidate() = withState(viewModel) { state -> + when (state.serverType) { + ServerType.Modular -> { + loginServerUrlFormIcon.isVisible = true + loginServerUrlFormTitle.text = getString(R.string.login_connect_to_modular) + loginServerUrlFormText.text = getString(R.string.login_server_url_form_modular_text) + loginServerUrlFormLearnMore.isVisible = true + loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_modular_hint) + loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_modular_notice) + } + ServerType.Other -> { + loginServerUrlFormIcon.isVisible = false + loginServerUrlFormTitle.text = getString(R.string.login_server_other_title) + loginServerUrlFormText.text = getString(R.string.login_connect_to_a_custom_server) + loginServerUrlFormLearnMore.isVisible = false + loginServerUrlFormHomeServerUrlTil.hint = getText(R.string.login_server_url_form_other_hint) + loginServerUrlFormNotice.text = getString(R.string.login_server_url_form_other_notice) + } + else -> error("This fragment should not be display in matrix.org mode") + } + } +} diff --git a/vector/src/main/res/layout/fragment_login.xml b/vector/src/main/res/layout/fragment_login.xml index 3dde5e1748..94340cb97c 100644 --- a/vector/src/main/res/layout/fragment_login.xml +++ b/vector/src/main/res/layout/fragment_login.xml @@ -1,3 +1,4 @@ + - + style="@style/LoginTopIcon" + android:layout_gravity="center_horizontal" /> + android:layout_marginTop="84dp" + android:textAppearance="@style/TextAppearance.Vector.Login.Title" + tools:text="@string/login_signin_to" /> + + + android:layout_marginTop="32dp" + android:hint="@string/auth_user_name_placeholder" + app:errorEnabled="true"> + android:hint="@string/auth_password_placeholder" + app:errorEnabled="true"> - + android:layout_marginTop="22dp" + android:orientation="horizontal"> - + android:layout_gravity="start" + android:text="@string/auth_forgot_password" /> - + - - - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vector/src/main/res/layout/fragment_login_signup_signin_selection.xml b/vector/src/main/res/layout/fragment_login_signup_signin_selection.xml index 21835a864c..240e8866f3 100644 --- a/vector/src/main/res/layout/fragment_login_signup_signin_selection.xml +++ b/vector/src/main/res/layout/fragment_login_signup_signin_selection.xml @@ -1,3 +1,4 @@ + - - - https://matrix.org - https://matrix.org https://piwik.riot.im https://riot.im/bugreports/submit diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index 36318ec52d..cfd1b6721c 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -36,10 +36,20 @@ Learn more Other Custom & advanced settings - Continue + Continue Connect to %1$s + Connect to Modular + Connect to a custom server + Sign in to %1$s Sign Up Sign In + Modular Address + Address + Premium hosting for organisations + + Enter the address of the Modular Riot or Server you want to use + Enter the address of a server or a Riot you want to connect to + diff --git a/vector/src/main/res/values/styles_login.xml b/vector/src/main/res/values/styles_login.xml index cac4351c3f..81964377bd 100644 --- a/vector/src/main/res/values/styles_login.xml +++ b/vector/src/main/res/values/styles_login.xml @@ -8,10 +8,12 @@