Skip to content

Commit

Permalink
Re-jig the welcome modal shown to 1st time users
Browse files Browse the repository at this point in the history
This allows some configuration directly in the modal including starting
the authorization process when the modal is closed.

Fixes #1506
Fixes #2430
  • Loading branch information
simonpoole committed Feb 28, 2024
1 parent b2fcf5c commit c67225b
Show file tree
Hide file tree
Showing 6 changed files with 389 additions and 30 deletions.
6 changes: 5 additions & 1 deletion src/androidTest/java/de/blau/android/TestUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ public static void grantPermissons(@NonNull UiDevice device) {
* @param ctx Android context
*/
public static void dismissStartUpDialogs(@NonNull UiDevice device, @NonNull Context ctx) {
clickText(device, true, ctx.getResources().getString(R.string.okay), false, false);
if (findText(device, false, ctx.getResources().getString(R.string.welcome_title))) {
clickText(device, true, ctx.getResources().getString(R.string.next), true, false);
clickResource(device, false, device.getCurrentPackageName() + ":id/authorize", false);
clickText(device, true, ctx.getResources().getString(R.string.welcome_start), true, false);
}
}

/**
Expand Down
171 changes: 149 additions & 22 deletions src/main/java/de/blau/android/dialogs/Newbie.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,59 @@
package de.blau.android.dialogs;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AlertDialog.Builder;
import androidx.appcompat.app.AppCompatDialog;
import androidx.appcompat.widget.SwitchCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.preference.PreferenceManager;
import de.blau.android.App;
import de.blau.android.Authorize;
import de.blau.android.HelpViewer;
import de.blau.android.Main;
import de.blau.android.R;
import de.blau.android.osm.ViewBox;
import de.blau.android.prefs.AdvancedPrefDatabase;
import de.blau.android.prefs.Preferences;
import de.blau.android.resources.DataStyle;
import de.blau.android.resources.TileLayerSource;
import de.blau.android.resources.TileLayerSource.Category;
import de.blau.android.resources.TileLayerSource.TileType;
import de.blau.android.util.ImmersiveDialogFragment;
import de.blau.android.util.OnPageSelectedListener;
import de.blau.android.util.ThemeUtils;
import de.blau.android.util.Util;
import de.blau.android.views.ExtendedViewPager;
import de.blau.android.views.layers.MapTilesLayer;

/**
* Display a dialog giving new users minimal instructions
*
*/
public class Newbie extends ImmersiveDialogFragment {

private static final String DEBUG_TAG = Newbie.class.getSimpleName();

private static final String TAG = "fragment_newbie";

private Main main;
private static final String PAGER_POS_KEY = "pagerPos";
private static final String AUTHORIZE_KEY = "authorize";
private static final String PEN_SETUP_KEY = "penSetup";
private static final String AUTO_DOWNLOAD_KEY = "autoDownload";
private static final String USE_IMAGERY_KEY = "useImagery";

private static final int SETTINGS_PAGE_INDEX = 1;
private static final int WELCOME_PAGE_INDEX = 0;

/**
* Display a dialog giving new users minimal instructions
Expand Down Expand Up @@ -71,37 +99,136 @@ public void onAttach(Context context) {
if (!(context instanceof Main)) {
throw new ClassCastException(context.toString() + " can only be called from Main");
}
main = (Main) context;
}

@NonNull
@Override
public AppCompatDialog onCreateDialog(Bundle savedInstanceState) {
Builder builder = new AlertDialog.Builder(getActivity());
final FragmentActivity activity = getActivity();
if (!(activity instanceof Main)) {
throw new ClassCastException(activity.toString() + " can only be called from Main");
}
Builder builder = new AlertDialog.Builder(activity);
builder.setIcon(null);
builder.setTitle(R.string.welcome_title);
final LayoutInflater inflater = ThemeUtils.getLayoutInflater(activity);
final View layout = inflater.inflate(R.layout.welcome_tabs, null);
final SwitchCompat displayImagery = layout.findViewById(R.id.use_imagery);
final SwitchCompat autoDownload = layout.findViewById(R.id.auto_download);
final SwitchCompat penSetup = layout.findViewById(R.id.pen_setup);
final SwitchCompat authorize = layout.findViewById(R.id.authorize);
final ExtendedViewPager pager = (ExtendedViewPager) layout.findViewById(R.id.pager);
pager.setAdapter(new ViewPagerAdapter(activity, layout, new int[] { R.id.welcome_page, R.id.settings_page },
new int[] { R.string.confirm_upload_edits_page, R.string.menu_tags }));
// set saved state before the on page change listener is set
if (savedInstanceState != null) {
displayImagery.setChecked(savedInstanceState.getBoolean(USE_IMAGERY_KEY));
autoDownload.setChecked(savedInstanceState.getBoolean(AUTO_DOWNLOAD_KEY));
penSetup.setChecked(savedInstanceState.getBoolean(PEN_SETUP_KEY));
authorize.setChecked(savedInstanceState.getBoolean(AUTHORIZE_KEY, true));
pager.setCurrentItem(savedInstanceState.getInt(PAGER_POS_KEY, 0));
}
pager.addOnPageChangeListener((OnPageSelectedListener) position -> {
AlertDialog dialog = ((AlertDialog) getDialog());
if (dialog == null) {
Log.e(DEBUG_TAG, "Dialog null");
return;
}
Button positive = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
Button negative = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
positive.clearFocus();
if (position == WELCOME_PAGE_INDEX) {
positive.setText(R.string.next);
positive.setOnClickListener((View v) -> pager.setCurrentItem(SETTINGS_PAGE_INDEX));
negative.setText(R.string.skip);
negative.setOnClickListener((View v) -> getDialog().dismiss());
}
if (position == SETTINGS_PAGE_INDEX) {
positive.setText(R.string.welcome_start);
positive.setOnClickListener((View v) -> {
((Main) activity).gotoCurrentLocation();
((Main) activity).setFollowGPS(true);

Preferences prefs = App.getPreferences(activity);
if (displayImagery.isChecked()) {
setBestBackground(activity);
}

prefs.setPanAndZoomAutoDownload(autoDownload.isChecked());

boolean penConfig = penSetup.isChecked();
prefs.setLargeDragArea(!penConfig);
prefs.setWayNodeDragging(penConfig);
prefs.setDataStyle(penConfig ? Preferences.DEFAULT_PEN_MAP_STYLE : Preferences.DEFAULT_MAP_STYLE);

((Main) activity).getMap().setPrefs(activity, prefs);

Newbie.dismissDialog(activity);

if (authorize.isChecked()) {
Authorize.startForResult(activity, null);
}
});
negative.setText(R.string.back);
negative.setOnClickListener((View v) -> pager.setCurrentItem(0));
}
});

String message = getString(R.string.welcome_message);
if (main.isFullScreen()) {
if (((Main) activity).isFullScreen()) {
message = message + getString(R.string.welcome_message_fullscreen);
}
builder.setMessage(Util.fromHtml(message));
builder.setPositiveButton(R.string.okay, (dialog, which) -> {
FragmentActivity activity = getActivity();
if (activity instanceof Main) {
main.gotoCurrentLocation();
main.setFollowGPS(true);
} else {
Log.e(DEBUG_TAG, "getActivity returned null in onClick");
}
((TextView) layout.findViewById(R.id.welcome_message)).setText(Util.fromHtml(message));
builder.setView(layout);

builder.setNegativeButton(R.string.skip, null);
builder.setPositiveButton(R.string.next, null);
builder.setNeutralButton(R.string.read_introduction, null);
AlertDialog dialog = builder.create();
dialog.setOnShowListener((DialogInterface d) -> {
Button neutral = dialog.getButton(DialogInterface.BUTTON_NEUTRAL);
neutral.setOnClickListener((View v) -> {
Context ctx = getActivity();
if (ctx instanceof FragmentActivity) {
HelpViewer.start((FragmentActivity) ctx, R.string.help_introduction);
return;
}
Log.e(DEBUG_TAG, "Not a fragment activity");
});
Button positive = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
positive.setOnClickListener((View v) -> pager.setCurrentItem(SETTINGS_PAGE_INDEX));
});
builder.setNeutralButton(R.string.read_introduction, (dialog, which) -> {
FragmentActivity activity = getActivity();
if (activity != null) {
HelpViewer.start(activity, R.string.help_introduction);
} else {
Log.e(DEBUG_TAG, "getActivity returned null in onClick");
return dialog;
}

/**
* Set the best background for the current ViewBox
*
* @param activity the current activity
*/
private void setBestBackground(@NonNull final FragmentActivity activity) {
final String[] ids = TileLayerSource.getIds(App.getLogic().getMap().getViewBox(), true, Category.photo, null);
if (ids.length > 0) {
TileLayerSource tileSource = TileLayerSource.get(activity, ids[0], false);
MapTilesLayer<?> tileLayer = ((Main) activity).getMap().getBackgroundLayer();
tileLayer.setRendererInfo(tileSource);
try (AdvancedPrefDatabase db = new AdvancedPrefDatabase(activity)) {
db.setLayerContentId(tileLayer.getIndex(), tileSource.getId());
}
});
return builder.create();
} else {
Log.w(DEBUG_TAG, "No applicable imagery found!");
}
}

@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.d(DEBUG_TAG, "onSaveInstanceState");
Dialog dialog = getDialog();
outState.putBoolean(USE_IMAGERY_KEY, ((SwitchCompat) dialog.findViewById(R.id.use_imagery)).isChecked());
outState.putBoolean(AUTO_DOWNLOAD_KEY, ((SwitchCompat) dialog.findViewById(R.id.auto_download)).isChecked());
outState.putBoolean(PEN_SETUP_KEY, ((SwitchCompat) dialog.findViewById(R.id.pen_setup)).isChecked());
outState.putBoolean(AUTHORIZE_KEY, ((SwitchCompat) dialog.findViewById(R.id.authorize)).isChecked());
outState.putInt(PAGER_POS_KEY, ((ExtendedViewPager) dialog.findViewById(R.id.pager)).getCurrentItem());
}
}
29 changes: 25 additions & 4 deletions src/main/java/de/blau/android/prefs/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public class Preferences {
private final boolean isAntiAliasingEnabled;
private final boolean isKeepScreenOnEnabled;
private final boolean useBackForUndo;
private final boolean largeDragArea;
private boolean largeDragArea;
private final boolean tagFormEnabled;
private String scaleLayer;
private String mapProfile;
Expand Down Expand Up @@ -122,7 +122,7 @@ public class Preferences {
private final int maxOffsetDistance;
private final Set<String> enabledValidations;
private final int autoNameCap;
private final boolean wayNodeDragging;
private boolean wayNodeDragging;
private final boolean splitWindowForPropertyEditor;
private final boolean useImperialUnits;
private final boolean supportPresetLabels;
Expand All @@ -140,7 +140,8 @@ public class Preferences {
private final double maxCircleSegment;
private final double minCircleSegment;

private static final String DEFAULT_MAP_PROFILE = "Color Round Nodes";
public static final String DEFAULT_MAP_STYLE = "Color Round Nodes";
public static final String DEFAULT_PEN_MAP_STYLE = "Pen Round Nodes";

private final SharedPreferences prefs;

Expand Down Expand Up @@ -434,6 +435,16 @@ public boolean largeDragArea() {
return largeDragArea;
}

/**
* Enable or disable the large drag area
*
* @param enabled if true enable the large drag area
*/
public void setLargeDragArea(boolean enabled) {
largeDragArea = enabled;
prefs.edit().putBoolean(r.getString(R.string.config_largeDragArea_key), enabled).commit();
}

/**
* Get kind of scale that should be displayed
*
Expand Down Expand Up @@ -463,7 +474,7 @@ public String getDataStyle() {
// check if we actually still have the profile
if (DataStyle.getStyle(mapProfile) == null) {
Log.w(DEBUG_TAG, "Style " + mapProfile + " missing, replacing by default");
setDataStyle(DataStyle.getStyle(DEFAULT_MAP_PROFILE) == null ? DataStyle.getBuiltinStyleName() : DEFAULT_MAP_PROFILE);
setDataStyle(DataStyle.getStyle(DEFAULT_MAP_STYLE) == null ? DataStyle.getBuiltinStyleName() : DEFAULT_MAP_STYLE);
}
return mapProfile;
}
Expand Down Expand Up @@ -1674,6 +1685,16 @@ public boolean isWayNodeDraggingEnabled() {
return wayNodeDragging;
}

/**
* Enable or disable the way node dragging
*
* @param enabled if true enable way node dragging
*/
public void setWayNodeDragging(boolean enabled) {
wayNodeDragging = enabled;
prefs.edit().putBoolean(r.getString(R.string.config_wayNodeDragging_key), enabled).commit();
}

/**
* Check if we should try to use split window functionality for the PropertyEditor
*
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/de/blau/android/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ public void handleTag(boolean opening, String tag, Editable output, XMLReader xm
output.append("\n");
}
if ("li".equals(tag) && opening) {
output.append("\n\t");
output.append("\n\t<b>&bull;</b>");
}
}
}
Expand Down
Loading

0 comments on commit c67225b

Please sign in to comment.