mirror of
				https://github.com/commons-app/apps-android-commons.git
				synced 2025-10-31 06:43:56 +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
							
								
									aca3f0f832
								
							
						
					
					
						commit
						8eed630ee5
					
				
					 6 changed files with 150 additions and 3 deletions
				
			
		|  | @ -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 | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 neslihanturan
						neslihanturan