Changed OSM login UI with 2 options: login+password or via browser.

Signed-off-by: Sergiy Kozyr <s.trump@gmail.com>
This commit is contained in:
Sergiy Kozyr 2024-08-07 14:24:14 +03:00
parent 558b65398e
commit c6a0ad53c3
4 changed files with 235 additions and 132 deletions

View file

@ -0,0 +1,104 @@
package app.organicmaps.editor;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.textfield.TextInputEditText;
import app.organicmaps.R;
import app.organicmaps.util.Constants;
import app.organicmaps.util.InputUtils;
import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.util.concurrency.ThreadPool;
import app.organicmaps.util.concurrency.UiThread;
public class OsmLoginBottomFragment extends BottomSheetDialogFragment {
final private OsmLoginFragment parentFragment;
private TextInputEditText mLoginInput;
private TextInputEditText mPasswordInput;
private Button mLoginButton;
private Button mLostPasswordButton;
private Button mRegisterButton;
private ProgressBar mProgress;
public OsmLoginBottomFragment(OsmLoginFragment parentFragment) {
super();
this.parentFragment = parentFragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_osm_login_bottom, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
mLoginInput = view.findViewById(R.id.osm_username);
mPasswordInput = view.findViewById(R.id.osm_password);
mLoginButton = view.findViewById(R.id.login);
mLoginButton.setOnClickListener((v) -> doLogin());
mLostPasswordButton = view.findViewById(R.id.lost_password);
mLostPasswordButton.setOnClickListener((v) -> Utils.openUrl(requireActivity(), Constants.Url.OSM_RECOVER_PASSWORD));
mRegisterButton = view.findViewById(R.id.register);
mRegisterButton.setOnClickListener((v) -> Utils.openUrl(requireActivity(), Constants.Url.OSM_REGISTER));
mProgress = view.findViewById(R.id.osm_login_progress);
}
private void doLogin() {
InputUtils.hideKeyboard(mLoginInput);
final String username = mLoginInput.getText().toString().trim();
final String password = mPasswordInput.getText().toString();
enableInput(false);
UiUtils.show(mProgress);
mLoginButton.setText("");
ThreadPool.getWorker().execute(() -> {
final String oauthToken = OsmOAuth.nativeAuthWithPassword(username, password);
final String username1 = (oauthToken == null) ? null : OsmOAuth.nativeGetOsmUsername(oauthToken);
UiThread.run(() -> processAuth(oauthToken, username1));
});
}
private void processAuth(String oauthToken, String username)
{
if (!isAdded())
return;
enableInput(true);
UiUtils.hide(mProgress);
mLoginButton.setText(R.string.login_osm);
if (oauthToken == null)
parentFragment.onAuthFail();
else {
this.dismiss();
parentFragment.onAuthSuccess(oauthToken, username);
}
}
private void enableInput(boolean enable)
{
mPasswordInput.setEnabled(enable);
mLoginInput.setEnabled(enable);
mLoginButton.setEnabled(enable);
mLostPasswordButton.setEnabled(enable);
mRegisterButton.setEnabled(enable);
}
}

View file

@ -8,33 +8,27 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.FrameLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import app.organicmaps.Framework;
import app.organicmaps.R;
import app.organicmaps.base.BaseMwmToolbarFragment;
import app.organicmaps.util.Constants;
import app.organicmaps.util.DateUtils;
import app.organicmaps.util.InputUtils;
import app.organicmaps.util.UiUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.util.concurrency.ThreadPool;
import app.organicmaps.util.concurrency.UiThread;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputEditText;
public class OsmLoginFragment extends BaseMwmToolbarFragment
{
private ProgressBar mProgress;
private Button mLoginButton;
private FrameLayout loginBottomSheet;
//private BottomSheetBehavior<FrameLayout> standardBottomSheetBehavior;
private Button mLoginUsernameButton;
private Button mLoginWebsiteButton;
private Button mLostPasswordButton;
private TextInputEditText mLoginInput;
private TextInputEditText mPasswordInput;
private String mArgOAuth2Code;
@ -50,17 +44,11 @@ public class OsmLoginFragment extends BaseMwmToolbarFragment
{
super.onViewCreated(view, savedInstanceState);
getToolbarController().setTitle(R.string.login);
mLoginInput = view.findViewById(R.id.osm_username);
mPasswordInput = view.findViewById(R.id.osm_password);
mLoginWebsiteButton = view.findViewById(R.id.login_website);
mLoginWebsiteButton.setOnClickListener((v) -> loginWithBrowser());
mLoginButton = view.findViewById(R.id.login);
mLoginButton.setOnClickListener((v) -> login());
mLostPasswordButton = view.findViewById(R.id.lost_password);
mLostPasswordButton.setOnClickListener((v) -> Utils.openUrl(requireActivity(), Constants.Url.OSM_RECOVER_PASSWORD));
Button registerButton = view.findViewById(R.id.register);
registerButton.setOnClickListener((v) -> Utils.openUrl(requireActivity(), Constants.Url.OSM_REGISTER));
mProgress = view.findViewById(R.id.osm_login_progress);
mLoginUsernameButton = view.findViewById(R.id.login_username);
mLoginUsernameButton.setOnClickListener((v) -> loginUsername());
final String dataVersion = DateUtils.getShortDateFormatter().format(Framework.getDataVersion());
((TextView) view.findViewById(R.id.osm_presentation))
.setText(getString(R.string.osm_presentation, dataVersion));
@ -79,26 +67,14 @@ public class OsmLoginFragment extends BaseMwmToolbarFragment
mArgOAuth2Code = arguments.getString(OsmLoginActivity.EXTRA_OAUTH2CODE);
}
private void login()
private void loginUsername()
{
InputUtils.hideKeyboard(mLoginInput);
final String username = mLoginInput.getText().toString().trim();
final String password = mPasswordInput.getText().toString();
enableInput(false);
UiUtils.show(mProgress);
mLoginButton.setText("");
ThreadPool.getWorker().execute(() -> {
final String oauthToken = OsmOAuth.nativeAuthWithPassword(username, password);
final String username1 = (oauthToken == null) ? null : OsmOAuth.nativeGetOsmUsername(oauthToken);
UiThread.run(() -> processAuth(oauthToken, username1));
});
OsmLoginBottomFragment bottomSheetFragment = new OsmLoginBottomFragment(this);
bottomSheetFragment.show(requireActivity().getSupportFragmentManager(), bottomSheetFragment.getTag());
}
private void loginWithBrowser()
{
enableInput(false);
String[] oauthParams = OsmOAuth.nativeOAuthParams();
Uri oauth2url = Uri.parse(oauthParams[0] + "/oauth2/authorize")
.buildUpon()
@ -117,66 +93,49 @@ public class OsmLoginFragment extends BaseMwmToolbarFragment
}
}
private void enableInput(boolean enable)
{
mPasswordInput.setEnabled(enable);
mLoginInput.setEnabled(enable);
mLoginButton.setEnabled(enable);
mLostPasswordButton.setEnabled(enable);
mLoginWebsiteButton.setEnabled(enable);
}
// This method is called by MwmActivity & UrlProcessor when "om://oauth2/osm/callback?code=XXX" is handled
private void continueOAuth2Flow(String oauth2code)
{
if (!isAdded())
return;
if (oauth2code == null || oauth2code.length()==0)
if (oauth2code == null || oauth2code.isEmpty())
{
enableInput(true);
onAuthFail();
}
else
{
// Do not enable UI until we finish interaction with OAuth2 API
enableInput(false);
ThreadPool.getWorker().execute(() -> {
// Finish OAuth2 auth flow and get username for UI.
final String oauthToken = OsmOAuth.nativeAuthWithOAuth2Code(oauth2code);
final String username = (oauthToken == null) ? null : OsmOAuth.nativeGetOsmUsername(oauthToken);
UiThread.run(() -> {
enableInput(true);
processAuth(oauthToken, username);
});
});
}
}
private void processAuth(String oauthToken, String username)
public void processAuth(String oauthToken, String username)
{
if (!isAdded())
return;
enableInput(true);
UiUtils.hide(mProgress);
mLoginButton.setText(R.string.login_osm);
if (oauthToken == null)
onAuthFail();
else
onAuthSuccess(oauthToken, username);
}
private void onAuthFail()
public void onAuthFail()
{
new MaterialAlertDialogBuilder(requireActivity(), R.style.MwmTheme_AlertDialog)
.setTitle(R.string.editor_login_error_dialog)
.setPositiveButton(R.string.ok, null)
.show();
.setTitle(R.string.editor_login_error_dialog)
.setPositiveButton(R.string.ok, null)
.show();
}
private void onAuthSuccess(String oauthToken, String username)
public void onAuthSuccess(String oauthToken, String username)
{
OsmOAuth.setAuthorization(requireContext(), oauthToken, username);
final Bundle extras = requireActivity().getIntent().getExtras();

View file

@ -63,87 +63,19 @@
<Button
android:id="@+id/login_website"
style="@style/MwmWidget.Button.Accent"
android:layout_marginTop="@dimen/margin_base"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login with OSM website"
android:textAppearance="@style/MwmTextAppearance.Body2.Light" />
<com.google.android.material.textfield.TextInputLayout
style="@style/MwmWidget.Editor.CustomTextInput"
android:layout_marginTop="@dimen/margin_half"
android:textColorHint="?android:textColorSecondary"
app:endIconMode="custom">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/osm_username"
style="@style/MwmWidget.Editor.FieldLayout.EditText"
android:autofillHints="emailAddress"
android:hint="@string/email_or_username" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/MwmWidget.Editor.CustomTextInput"
android:layout_marginTop="@dimen/margin_base"
android:textColorHint="?android:textColorSecondary"
app:endIconMode="password_toggle"
app:endIconTint="?android:textColorSecondary">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/osm_password"
style="@style/MwmWidget.Editor.FieldLayout.EditText"
android:autofillHints="password"
android:hint="@string/password"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/margin_base">
<Button
android:id="@+id/login"
style="@style/MwmWidget.Button.Accent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/login_osm"
android:textAppearance="@style/MwmTextAppearance.Body2.Light" />
<ProgressBar
android:id="@+id/osm_login_progress"
android:layout_width="@dimen/editor_auth_btn_height"
android:layout_height="@dimen/editor_auth_btn_height"
android:layout_gravity="center"
android:elevation="@dimen/design_fab_elevation"
android:visibility="gone" />
</FrameLayout>
<Button
android:id="@+id/lost_password"
style="@style/MwmWidget.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:background="?clickableBackground"
android:padding="@dimen/margin_half"
android:text="@string/forgot_password"
android:textAppearance="@style/MwmTextAppearance.Body3" />
<com.google.android.material.divider.MaterialDivider
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base"
android:layout_marginBottom="@dimen/margin_base" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@string/robotoRegular"
android:text="@string/no_osm_account"
android:textAppearance="@style/MwmTextAppearance.Body2"
android:textColor="?android:textColorPrimary" />
<Button
android:id="@+id/register"
android:id="@+id/login_username"
style="@style/MwmWidget.Button.Accent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login with username"
android:layout_marginTop="@dimen/margin_base"
android:background="@drawable/button_editor_light"
android:fontFamily="@string/robotoMedium"
android:padding="@dimen/margin_quarter"
android:text="@string/register_at_openstreetmap"
android:textAppearance="@style/MwmTextAppearance.Body2"
android:textColor="@color/text_dark" />
android:textAppearance="@style/MwmTextAppearance.Body2.Light" />
</LinearLayout>
</ScrollView>
</LinearLayout>

View file

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?cardBackground"
android:fadeScrollbars="false"
android:fillViewport="true"
tools:ignore="DuplicateIds">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
android:padding="@dimen/margin_base"
tools:ignore="ScrollViewSize">
<LinearLayout
android:id="@+id/login_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.google.android.material.textfield.TextInputLayout
style="@style/MwmWidget.Editor.CustomTextInput"
android:layout_marginTop="@dimen/margin_half"
android:textColorHint="?android:textColorSecondary"
app:endIconMode="custom">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/osm_username"
style="@style/MwmWidget.Editor.FieldLayout.EditText"
android:padding="@dimen/margin_half_double_plus"
android:autofillHints="emailAddress"
android:hint="@string/email_or_username" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/MwmWidget.Editor.CustomTextInput"
android:textColorHint="?android:textColorSecondary"
app:endIconMode="password_toggle"
app:endIconTint="?android:textColorSecondary">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/osm_password"
style="@style/MwmWidget.Editor.FieldLayout.EditText"
android:padding="@dimen/margin_half_double_plus"
android:autofillHints="password"
android:hint="@string/password"
android:inputType="textPassword" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_base">
<Button
android:id="@+id/login"
style="@style/MwmWidget.Button.Accent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Login with username"
android:layout_marginTop="@dimen/margin_half"
android:textAppearance="@style/MwmTextAppearance.Body2.Light" />
<ProgressBar
android:id="@+id/osm_login_progress"
android:layout_width="@dimen/editor_auth_btn_height"
android:layout_height="@dimen/editor_auth_btn_height"
android:layout_gravity="center"
android:elevation="@dimen/design_fab_elevation"
android:visibility="gone" />
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="@dimen/margin_base">
<Button
android:id="@+id/lost_password"
style="@style/MwmWidget.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_weight="1"
android:background="?clickableBackground"
android:padding="@dimen/margin_quarter"
android:text="@string/forgot_password"
android:textAppearance="@style/MwmTextAppearance.Body3" />
<Button
android:id="@+id/register"
style="@style/MwmWidget.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="end"
android:background="?clickableBackground"
android:padding="@dimen/margin_quarter"
android:text="@string/register_at_openstreetmap"
android:textAppearance="@style/MwmTextAppearance.Body3" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>