Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add route overview button and animation to NavigationView #967

Merged
merged 1 commit into from
Jun 19, 2018

Conversation

danesfeder
Copy link
Contributor

@danesfeder danesfeder commented May 23, 2018

Closes #950

TODO:

  • Add button with chosen asset from @cjballard
  • Show resume button after overview clicked
  • Add test for dynamic camera providing list of Point

Animation running wired up to the X button:
ezgif com-video-to-gif 1

cc @brsbl

@danesfeder danesfeder added ⚠️ DO NOT MERGE PR should not be merged! platform parity Required to keep on par with iOS. topic: camera labels May 23, 2018
@danesfeder danesfeder added this to the 0.14.0 milestone May 23, 2018
@danesfeder danesfeder self-assigned this May 23, 2018
@Cjballard-zz
Copy link

routepreview_icons.zip

Attaching light and dark icons for route preview. @danesfeder

@brsbl-zz
Copy link

brsbl-zz commented May 24, 2018

Love the dynamic camera.

@danesfeder is it easy enough to adjust the spacing between the sound and feedback icons in this PR as well so they better match iOS? the thinking being grouping things that obscure the map together makes them less intrusive overall -- thoughts @cjballard?

also:

  • Cut a ticket in /mapbox-navigation-ios to mirror this behavior 🙂

@danesfeder
Copy link
Contributor Author

danesfeder commented May 24, 2018

@brsbl sure thing and thanks! - would like @cjballard 👀 on this as well. I have them spaced a little more to create larger touch points. Hitting that feedback button accidentally when you're trying to mute is pretty jarring

@Cjballard-zz
Copy link

@brsbl @danesfeder Agreed. I think there's a middle ground we can hit that still reserves those touchpoints while grouping them more tightly and revealing more of the map. Maybe 10-20dp closer together could work.

@danesfeder
Copy link
Contributor Author

@cjballard Here's what the current setup looks like, let me know what you think / want to tweak 👍

Portrait

ezgif com-video-to-gif

Landscape

ezgif com-video-to-gif 1

@Cjballard-zz
Copy link

@danesfeder Looks good to me! Only adjustment I might make is to make the separating line a bit shorter, closer to the height (but still a little taller) than the route preview icon:

tt-example

@danesfeder
Copy link
Contributor Author

@cjballard Updated:
device-2018-06-05-164139

device-2018-06-05-164333

@Cjballard-zz
Copy link

@danesfeder Looks good to me 👍

@danesfeder
Copy link
Contributor Author

@cjballard awesome, thank you!

@Guardiola31337 @devotaaabel will add tests to this PR tomorrow then will be good for 👀

@danesfeder danesfeder force-pushed the dan-route-overview branch 3 times, most recently from 386c01d to d0236e2 Compare June 6, 2018 14:23
@danesfeder
Copy link
Contributor Author

Tests added - this is good for 👀

@danesfeder danesfeder removed the ⚠️ DO NOT MERGE PR should not be merged! label Jun 6, 2018
@danesfeder danesfeder changed the title [WIP] Add route overview button and animation to NavigationView Add route overview button and animation to NavigationView Jun 6, 2018
@danesfeder
Copy link
Contributor Author

Merge is causing issues with padding adjustments - this PR is no longer ready for review until these issues are fixed.

@danesfeder danesfeder added ⚠️ DO NOT MERGE PR should not be merged! and removed ✓ ready for review labels Jun 7, 2018
@danesfeder danesfeder force-pushed the dan-route-overview branch 4 times, most recently from c6c9676 to 35966d2 Compare June 8, 2018 20:11
@danesfeder danesfeder added ✓ ready for review and removed ⚠️ DO NOT MERGE PR should not be merged! labels Jun 11, 2018
@danesfeder danesfeder force-pushed the dan-route-overview branch 2 times, most recently from 1ccb3e9 to 717f146 Compare June 13, 2018 16:23
Copy link
Contributor

@Guardiola31337 Guardiola31337 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this look awesome 💯 Great job @danesfeder 👏
Really nice test coverage ❤️

Some minor comments.

@@ -509,6 +499,12 @@ public void onClick(View view) {
navigationPresenter.onRecenterClick();
}
});
routeOverviewBtn.setOnClickListener(new OnClickListener() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about extracting the listeners into class properties?

@@ -187,6 +200,14 @@ private RouteInformation buildRouteInformationFromLocation(Location location, Ro
return RouteInformation.create(null, location, routeProgress);
}

@NonNull
private RouteInformation buildRouteInformationFromRouteProgress(RouteProgress routeProgress) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor thing - IMO buildRouteInformationFrom(RouteProgress routeProgress) would be clearer and to the point. What do you think?

private void animateCameraForRouteOverview(RouteInformation routeInformation, int[] padding) {
Camera cameraEngine = navigation.getCameraEngine();

CameraPosition resetPosition = new CameraPosition.Builder().tilt(0).bearing(0).build();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can move these two lines after the guard clause avoiding instantiating them if invalidPoints is true.

if (invalidPoints) {
return;
}
final LatLngBounds routeBounds = convertRoutePointsToLatLngBounds(routePoints);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about extracting this preparation block of code into a well-named private method? (Including the two lines mentioned above ☝️)

ImageButton routeOverviewBtn = findViewById(R.id.routeOverviewBtn);
boolean isDarkThemeEnabled = ThemeSwitcher.isDarkThemeEnabled(getContext());
Drawable routeOverviewDrawable;
if (isDarkThemeEnabled) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a custom attribute to the nav theme so it's just added upon inflation and remove the if else check?

LineString lineString = LineString.fromPolyline(route.geometry(), Constants.PRECISION_6);
return lineString.coordinates();
}
return null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should consider returning a Null Object instead or even better try to getting rid of it at all (maybe returning an empty list?). If not, code becomes defensive and full of null checks.

👀 Null References: The Billion Dollar Mistake

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually if the route in setupLineStringAndBearing is null L#85 will cause a NPE right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In any case, guard clauses normally are at the beginning of the method representing the unexpected behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also saw the same exact code in DynamicCameraTest.java (generateRouteCoordinates). Should be abstracted and accessible to the implementation classes?

@@ -145,6 +149,44 @@ public void onInformationFromLocationAndProgress_engineCreatesCorrectBearing() t
assertEquals(100f, bearing, DELTA);
}

@Test
public void onInformationFromRoute_engineCreatesOverviewPointList() throws Exception {
MapboxMap mapboxMap = mock(MapboxMap.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor thing - Could we extract some shared "arrangement" code into private methods and used it across the tests? This applies to MapWaynameTest as well.

@danesfeder danesfeder force-pushed the dan-route-overview branch 4 times, most recently from 5cb0ecc to 74d0d02 Compare June 18, 2018 20:58
@danesfeder
Copy link
Contributor Author

@Guardiola31337 Updated - I skipped your comment on MapWaynameTest - the variables that are out of the builders are being used to provide context / used in the actual tests so they cannot be pushed into the builders.

Copy link
Contributor

@Guardiola31337 Guardiola31337 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danesfeder Some minor new comments from the latest changes.

import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.services.android.navigation.ui.v5.utils.ViewUtils;

public class NavigationSnapshotReadyCallback implements MapboxMap.SnapshotReadyCallback {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Access can be package-private

private NavigationView navigationView;
private NavigationViewModel navigationViewModel;

public NavigationSnapshotReadyCallback(NavigationView navigationView, NavigationViewModel navigationViewModel) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Access can be package-private

int uiMode = context.getResources().getConfiguration().uiMode
& Configuration.UI_MODE_NIGHT_MASK;
boolean darkThemeEnabled = uiMode == Configuration.UI_MODE_NIGHT_YES;
boolean darkThemeEnabled = isDarkThemeEnabled(context);
updatePreferencesDarkEnabled(context, darkThemeEnabled);

// Check for custom theme from NavigationLauncher
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this comment necessary?

@@ -187,6 +200,14 @@ private RouteInformation buildRouteInformationFromLocation(Location location, Ro
return RouteInformation.create(null, location, routeProgress);
}

@NonNull
private RouteInformation buildRouteInformationFrom(RouteProgress routeProgress) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#967 (comment)

Didn't see that we had other buildRouteInformationFrom methods. Maybe we should leave as it was. Sorry for the confusion.

if (invalidPoints) {
return;
}
CameraUpdate resetUpdate = buildResetCameraUpdate();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CameraUpdate resetUpdate = buildResetCameraUpdate();
final CameraUpdate overviewUpdate = buildOverviewCameraUpdate(padding, routePoints);

mapboxMap.animateCamera(resetUpdate, 150, new MapboxMap.CancelableCallback() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about extracting the listeners into class properties?

@@ -173,4 +214,12 @@ private DirectionsRoute buildDirectionsRoute() throws IOException {
DirectionsResponse response = gson.fromJson(body, DirectionsResponse.class);
return response.routes().get(0);
}

private List<Point> generateRouteCoordinates(DirectionsRoute route) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@@ -48,8 +49,12 @@ public static Bitmap loadBitmapFromView(View view) {
return null;
}

public static float dpToPx(Context context, int dp) {
public static int[] buildRouteOverviewPadding(Context context) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't sound like a View utility. It's only used in NavigationView. IMO, objects and methods should live/be where their context is. From my experience utility classes become a drawer easily and we should treat them carefully.

@@ -59,20 +63,36 @@ public double zoom(RouteInformation routeInformation) {
return CAMERA_ZOOM;
}

@Override
public List<Point> overview(RouteInformation routeInformation) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO overview is getting too long.
What about extracting blocks of code into well-named private methods and simplifying conditional expressions somehow?

We should keep public methods as clean as possible so they read like pseudocode (i.e. no conditionals, fors, etc.).

@danesfeder danesfeder force-pushed the dan-route-overview branch 2 times, most recently from 63409b0 to 47c98ea Compare June 19, 2018 14:14
Copy link
Contributor

@Guardiola31337 Guardiola31337 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well done @danesfeder :shipit:

@danesfeder danesfeder merged commit abe86a5 into master Jun 19, 2018
@danesfeder danesfeder deleted the dan-route-overview branch June 19, 2018 14:46
@danesfeder danesfeder mentioned this pull request Jun 21, 2018
11 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform parity Required to keep on par with iOS.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants