mirror of
https://github.com/commons-app/apps-android-commons.git
synced 2025-10-26 12:23:58 +01:00
Add nearby tutorial (#1467)
* Add dependency for MaterialShowcase * Add actionview class to get a reference to material showcase * Create a NearbyMaterialShowcaseSequence class * Apply sequence steps * Add first three steps of nearby showcase * Add sequence id constants to make sure they will be displayed only once * Add last step of sequence to explain plus fab * Create an object to prevent customize all sequences every time * Fix typo * Code cleanup * Add strings to strings.xml * Code cleanup * Revert irrelevant change * Revert irrelevant change * Remove showcaseview for recenter button * Use single showcaseView instead of sequence * Add single showcase view insted of sequence to be able to edit text style * Make sure it will be displayed only once * Cleanup * Update strings * Change dismiss text style
This commit is contained in:
parent
4f6b791c93
commit
2a98bd21ce
6 changed files with 150 additions and 3 deletions
|
|
@ -25,6 +25,8 @@ dependencies {
|
|||
transitive=true
|
||||
}
|
||||
|
||||
implementation "com.github.deano2390:MaterialShowcaseView:1.2.0"
|
||||
|
||||
implementation "com.android.support:support-v4:$SUPPORT_LIB_VERSION"
|
||||
implementation "com.android.support:appcompat-v7:$SUPPORT_LIB_VERSION"
|
||||
implementation "com.android.support:design:$SUPPORT_LIB_VERSION"
|
||||
|
|
|
|||
|
|
@ -4,14 +4,18 @@ import android.content.BroadcastReceiver;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.BottomSheetBehavior;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
|
@ -25,6 +29,7 @@ import com.google.gson.GsonBuilder;
|
|||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
|
@ -41,6 +46,8 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
|||
import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
import timber.log.Timber;
|
||||
import uk.co.deanwild.materialshowcaseview.IShowcaseListener;
|
||||
import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView;
|
||||
|
||||
|
||||
public class NearbyActivity extends NavigationBaseActivity implements LocationUpdateListener {
|
||||
|
|
@ -56,12 +63,15 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
|||
LinearLayout bottomSheetDetails;
|
||||
@BindView(R.id.transparentView)
|
||||
View transparentView;
|
||||
@BindView(R.id.fab_recenter)
|
||||
View fabRecenter;
|
||||
|
||||
@Inject
|
||||
LocationServiceManager locationManager;
|
||||
@Inject
|
||||
NearbyController nearbyController;
|
||||
|
||||
@Inject
|
||||
@Named("application_preferences") SharedPreferences applicationPrefs;
|
||||
private LatLng curLatLng;
|
||||
private Bundle bundle;
|
||||
private Disposable placesDisposable;
|
||||
|
|
@ -72,11 +82,18 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
|||
private NearbyListFragment nearbyListFragment;
|
||||
private static final String TAG_RETAINED_MAP_FRAGMENT = NearbyMapFragment.class.getSimpleName();
|
||||
private static final String TAG_RETAINED_LIST_FRAGMENT = NearbyListFragment.class.getSimpleName();
|
||||
private View listButton; // Reference to list button to use in tutorial
|
||||
|
||||
private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
|
||||
private BroadcastReceiver broadcastReceiver;
|
||||
|
||||
private boolean isListShowcaseAdded = false;
|
||||
private boolean isMapShowCaseAdded = false;
|
||||
|
||||
private LatLng lastKnownLocation;
|
||||
|
||||
private MaterialShowcaseView secondSingleShowCaseView;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
|
@ -126,6 +143,39 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
|||
MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.menu_nearby, menu);
|
||||
|
||||
new Handler().post(() -> {
|
||||
|
||||
listButton = findViewById(R.id.action_display_list);
|
||||
|
||||
secondSingleShowCaseView = new MaterialShowcaseView.Builder(this)
|
||||
.setTarget(listButton)
|
||||
.setDismissText(getString(R.string.showcase_view_got_it_button))
|
||||
.setContentText(getString(R.string.showcase_view_list_icon))
|
||||
.setDelay(500) // optional but starting animations immediately in onCreate can make them choppy
|
||||
.singleUse(ViewUtil.SHOWCASE_VIEW_ID_1) // provide a unique ID used to ensure it is only shown once
|
||||
.setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD))
|
||||
.setListener(new IShowcaseListener() {
|
||||
@Override
|
||||
public void onShowcaseDisplayed(MaterialShowcaseView materialShowcaseView) {
|
||||
|
||||
}
|
||||
|
||||
// If dismissed, we can inform fragment to start showcase sequence there
|
||||
@Override
|
||||
public void onShowcaseDismissed(MaterialShowcaseView materialShowcaseView) {
|
||||
nearbyMapFragment.onNearbyMaterialShowcaseDismissed();
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
isListShowcaseAdded = true;
|
||||
|
||||
if (isMapShowCaseAdded) { // If map showcase is also ready, start ShowcaseSequence
|
||||
// Probably this case is not possible. Just added to be careful
|
||||
setMapViewTutorialShowCase();
|
||||
}
|
||||
});
|
||||
|
||||
return super.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
|
|
@ -420,6 +470,45 @@ public class NearbyActivity extends NavigationBaseActivity implements LocationUp
|
|||
updateMapFragment(false);
|
||||
updateListFragment();
|
||||
}
|
||||
|
||||
isMapShowCaseAdded = true;
|
||||
}
|
||||
|
||||
public void setMapViewTutorialShowCase() {
|
||||
/*
|
||||
*This showcase view will be the first step of our nearbyMaterialShowcaseSequence. The reason we use a
|
||||
* single item instead of adding another step to nearbyMaterialShowcaseSequence is that we are not able to
|
||||
* call withoutShape() method on steps. For mapView we need an showcase view without
|
||||
* any circle on it, it should cover the whole page.
|
||||
* */
|
||||
MaterialShowcaseView firstSingleShowCaseView = new MaterialShowcaseView.Builder(this)
|
||||
.setTarget(nearbyMapFragment.mapView)
|
||||
.setDismissText(getString(R.string.showcase_view_got_it_button))
|
||||
.setContentText(getString(R.string.showcase_view_whole_nearby_activity))
|
||||
.setDelay(500) // optional but starting animations immediately in onCreate can make them choppy
|
||||
.singleUse(ViewUtil.SHOWCASE_VIEW_ID_2) // provide a unique ID used to ensure it is only shown once
|
||||
.withoutShape() // no shape on map view since there are no view to focus on
|
||||
.setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD))
|
||||
.setListener(new IShowcaseListener() {
|
||||
@Override
|
||||
public void onShowcaseDisplayed(MaterialShowcaseView materialShowcaseView) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowcaseDismissed(MaterialShowcaseView materialShowcaseView) {
|
||||
/* Add other nearbyMaterialShowcaseSequence here, it will make the user feel as they are a
|
||||
* nearbyMaterialShowcaseSequence whole together.
|
||||
* */
|
||||
secondSingleShowCaseView.show(NearbyActivity.this);
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
if (applicationPrefs.getBoolean("firstRunNearby", true)) {
|
||||
applicationPrefs.edit().putBoolean("firstRunNearby", false).apply();
|
||||
firstSingleShowCaseView.show(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void lockNearbyView(boolean lock) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.content.Intent;
|
|||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
|
|
@ -58,13 +59,14 @@ import fr.free.nrw.commons.contributions.ContributionController;
|
|||
import fr.free.nrw.commons.utils.UriDeserializer;
|
||||
import fr.free.nrw.commons.utils.ViewUtil;
|
||||
import timber.log.Timber;
|
||||
import uk.co.deanwild.materialshowcaseview.MaterialShowcaseView;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
|
||||
public class NearbyMapFragment extends DaggerFragment {
|
||||
|
||||
private MapView mapView;
|
||||
public MapView mapView;
|
||||
private List<NearbyBaseMarker> baseMarkerOptions;
|
||||
private fr.free.nrw.commons.location.LatLng curLatLng;
|
||||
public fr.free.nrw.commons.location.LatLng[] boundaryCoordinates;
|
||||
|
|
@ -111,6 +113,10 @@ public class NearbyMapFragment extends DaggerFragment {
|
|||
private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06;
|
||||
private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04;
|
||||
|
||||
private boolean isSecondMaterialShowcaseDismissed;
|
||||
private boolean isMapReady;
|
||||
private MaterialShowcaseView thirdSingleShowCaseView;
|
||||
|
||||
private Bundle bundleForUpdtes;// Carry information from activity about changed nearby places and current location
|
||||
|
||||
@Inject
|
||||
|
|
@ -163,7 +169,6 @@ public class NearbyMapFragment extends DaggerFragment {
|
|||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
Timber.d("onCreateView called");
|
||||
if (curLatLng != null) {
|
||||
Timber.d("curLatLng found, setting up map view...");
|
||||
|
|
@ -476,6 +481,7 @@ public class NearbyMapFragment extends DaggerFragment {
|
|||
mapView.getMapAsync(new OnMapReadyCallback() {
|
||||
@Override
|
||||
public void onMapReady(MapboxMap mapboxMap) {
|
||||
((NearbyActivity)getActivity()).setMapViewTutorialShowCase();
|
||||
NearbyMapFragment.this.mapboxMap = mapboxMap;
|
||||
updateMapSignificantly();
|
||||
}
|
||||
|
|
@ -519,6 +525,7 @@ public class NearbyMapFragment extends DaggerFragment {
|
|||
private void addNearbyMarkerstoMapBoxMap() {
|
||||
|
||||
mapboxMap.addMarkers(baseMarkerOptions);
|
||||
|
||||
mapboxMap.setOnInfoWindowCloseListener(marker -> {
|
||||
if (marker == selected) {
|
||||
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
|
|
@ -534,6 +541,7 @@ public class NearbyMapFragment extends DaggerFragment {
|
|||
});
|
||||
|
||||
mapboxMap.setOnMarkerClickListener(marker -> {
|
||||
|
||||
if (marker instanceof NearbyMarker) {
|
||||
this.selected = marker;
|
||||
NearbyMarker nearbyMarker = (NearbyMarker) marker;
|
||||
|
|
@ -541,6 +549,7 @@ public class NearbyMapFragment extends DaggerFragment {
|
|||
passInfoToSheet(place);
|
||||
bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
|
||||
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
|
@ -634,7 +643,19 @@ public class NearbyMapFragment extends DaggerFragment {
|
|||
addAnchorToSmallFABs(fabGallery, getActivity().findViewById(R.id.empty_view).getId());
|
||||
|
||||
addAnchorToSmallFABs(fabCamera, getActivity().findViewById(R.id.empty_view1).getId());
|
||||
thirdSingleShowCaseView = new MaterialShowcaseView.Builder(this.getActivity())
|
||||
.setTarget(fabPlus)
|
||||
.setDismissText(getString(R.string.showcase_view_got_it_button))
|
||||
.setContentText(getString(R.string.showcase_view_plus_fab))
|
||||
.setDelay(500) // optional but starting animations immediately in onCreate can make them choppy
|
||||
.singleUse(ViewUtil.SHOWCASE_VIEW_ID_3) // provide a unique ID used to ensure it is only shown once
|
||||
.setDismissStyle(Typeface.defaultFromStyle(Typeface.BOLD))
|
||||
.build();
|
||||
|
||||
isMapReady = true;
|
||||
if (isSecondMaterialShowcaseDismissed) {
|
||||
thirdSingleShowCaseView.show(getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -791,6 +812,13 @@ public class NearbyMapFragment extends DaggerFragment {
|
|||
this.bundleForUpdtes = bundleForUpdtes;
|
||||
}
|
||||
|
||||
public void onNearbyMaterialShowcaseDismissed() {
|
||||
isSecondMaterialShowcaseDismissed = true;
|
||||
if (isMapReady) {
|
||||
thirdSingleShowCaseView.show(getActivity());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
package fr.free.nrw.commons.nearby;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import uk.co.deanwild.materialshowcaseview.MaterialShowcaseSequence;
|
||||
import uk.co.deanwild.materialshowcaseview.ShowcaseConfig;
|
||||
|
||||
|
||||
public class NearbyMaterialShowcaseSequence extends MaterialShowcaseSequence {
|
||||
|
||||
public NearbyMaterialShowcaseSequence(Activity activity, String sequenceID) {
|
||||
super(activity, sequenceID);
|
||||
ShowcaseConfig config = new ShowcaseConfig();
|
||||
config.setDelay(500); // half second between each showcase view
|
||||
this.setConfig(config);
|
||||
this.singleUse(sequenceID); // Display tutorial only once
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,10 @@ import android.widget.Toast;
|
|||
|
||||
public class ViewUtil {
|
||||
|
||||
public static final String SHOWCASE_VIEW_ID_1 = "SHOWCASE_VIEW_ID_1";
|
||||
public static final String SHOWCASE_VIEW_ID_2 = "SHOWCASE_VIEW_ID_2";
|
||||
public static final String SHOWCASE_VIEW_ID_3 = "SHOWCASE_VIEW_ID_3";
|
||||
|
||||
public static void showSnackbar(View view, int messageResourceId) {
|
||||
Snackbar.make(view, messageResourceId, Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,9 +271,15 @@
|
|||
<string name="about_translate_cancel">Cancel</string>
|
||||
<string name="retry">Retry</string>
|
||||
|
||||
<string name="showcase_view_got_it_button">Got it!</string>
|
||||
<string name="showcase_view_whole_nearby_activity">These are the places near you that need pictures to illustrate their Wikipedia articles</string>
|
||||
<string name="showcase_view_list_icon">Tapping this button brings up a list of these places</string>
|
||||
<string name="showcase_view_plus_fab">You can upload a picture for any place from your gallery or camera</string>
|
||||
|
||||
<string name="no_images_found">No images found!</string>
|
||||
<string name="error_loading_images">Error occurred while loading images.</string>
|
||||
<string name="image_uploaded_by">Uploaded by: %1$s</string>
|
||||
|
||||
<string name="share_app_title">Share App</string>
|
||||
<string name="share_coordinates_not_present">Coordinates were not specified during image selection</string>
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue