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

[google_maps_flutter] Add a new zIndexInt param to marker and deprecate zIndex #8012

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

Hari-07
Copy link
Contributor

@Hari-07 Hari-07 commented Nov 3, 2024

Replace this paragraph with a description of what this PR is changing or adding, and why. Consider including before/after screenshots.
zIndex on marker is currently a double. This introduces inconsistency between its behaviours on android and ios since ios truncates it to an int. This PR aims to smooth out that difference by accepting an int param instead through the marker API in dart

List which issues are fixed by this PR. You must list at least one issue.
Fixes flutter/flutter#155897

Pre-launch Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@Hari-07
Copy link
Contributor Author

Hari-07 commented Nov 4, 2024

The checking for default value in native code feels a little weird, but since this is a parameter we have a default value for in the dart layer, not sure what other option is there.

The only other one I could think of was checking for 0 in dart itself and then passing down null, for zIndex if that was the case which would mean making it nullable . That might need a bunch of changes and wasn't sure if it's worth it for a deprecation


int zIndexInt = marker.getZIndexInt().intValue();
float zIndex = marker.getZIndex().floatValue();
if (zIndexInt != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a comment here that the reason we check for zero is that zIndexInt is supposed to take priority over zindex? |

Please also add a test in https://github.com/flutter/packages/blob/2c8f22670812996a00e45e6304f79f1fd9b02fa1/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ConvertTest.java to verify the behavior.

@@ -150,7 +150,12 @@ class Marker implements MapsObject<Marker> {
this.position = const LatLng(0.0, 0.0),
this.rotation = 0.0,
this.visible = true,
@Deprecated(
'Use zIndexInt instead. '
'Use of zIndex was deprecated as it gets truncated to int on iOS.',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'Use of zIndex was deprecated as it gets truncated to int on iOS.',
'On iOS zIndex is truncated to an int, which can lead to incorrect/unstable ordering.',

@@ -219,8 +224,19 @@ class Marker implements MapsObject<Marker> {
///
/// Overlays are drawn in order of z-index, so that lower values means drawn
/// earlier, and thus appearing to be closer to the surface of the Earth.
@Deprecated(
'Use zIndexInt instead. '
'Use of zIndex was deprecated as it gets truncated to int on iOS.',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'Use of zIndex was deprecated as it gets truncated to int on iOS.',
'On iOS zIndex is truncated to an int, which can lead to incorrect/unstable ordering.',

@@ -246,7 +262,12 @@ class Marker implements MapsObject<Marker> {
LatLng? positionParam,
double? rotationParam,
bool? visibleParam,
@Deprecated(
'Use zIndexIntParam instead. '
'Use of zIndex was deprecated as it gets truncated to int on iOS.',
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
'Use of zIndex was deprecated as it gets truncated to int on iOS.',
'On iOS zIndex is truncated to an int, which can lead to incorrect/unstable ordering.',

Copy link
Member

@ditman ditman left a comment

Choose a reason for hiding this comment

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

This is probably minor, but the web version is not handling the new zIndexInt value. We should address that, or create a follow-up ticket so somebody else can implement the desired behavior there.

Comment on lines 1 to 3
## NEXT
## 0.5.10+1

* Deprecate zIndex parameter in Marker and replace with zIndexInt.
Copy link
Member

Choose a reason for hiding this comment

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

I'd expect to see a change here for the web?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you for the reminder, didn't think about web. I can just add that in right away

Copy link
Member

Choose a reason for hiding this comment

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

Please, remember the PR styleguide. This changelog entry should be "Deprecates zIndex parameter..."

@@ -205,5 +206,21 @@ void main() {
}, throwsAssertionError);
});
});

testWidgets('interpretCorrectZIndexInConversion',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't find any conversion tests in the web package, so Im not 100% sure if this is in the right place. Maybe it should be in a dedicated convert_test file

Future<gmaps.MarkerOptions> _markerOptionsFromMarker(
/// Computes the options for a new [gmaps.Marker] from an incoming set of options
/// [marker], and the existing marker registered with the map: [currentMarker].
@visibleForTesting
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This feels a little weird, and I think maybe all the methods here could be static methods of a class

Copy link
Member

@ditman ditman Nov 12, 2024

Choose a reason for hiding this comment

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

Yeah, this file started up being small, then grew to epic proportions. It should eventually disappear, but there's still some "stringly typed" API coming from the core plugin (everything that is backed by a JSON object, for example).

Thanks for adding a convert_test. We normally tested this as an integration test, by inderectly looking at the properties that we can read back from the google maps sdk if I'm not mistaken.

Copy link
Contributor Author

@Hari-07 Hari-07 Nov 12, 2024

Choose a reason for hiding this comment

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

this file started up being small, then grew to epic proportions. It should eventually disappear

Haha, classic!

Copy link
Member

@ditman ditman Nov 12, 2024

Choose a reason for hiding this comment

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

In order to not have to modify this method, I'd suggest you add the test to markers_test.dart, which is calling all the conversion methods when doing controller.addMarkers.

See this:

  • testWidgets('changeMarkers', (WidgetTester tester) async {
    gmaps.Marker? marker;
    gmaps.LatLng? position;
    final Set<Marker> markers = <Marker>{
    const Marker(markerId: MarkerId('1')),
    };
    await controller.addMarkers(markers);
    marker = controller.markers[const MarkerId('1')]?.marker;
    expect(marker, isNotNull);
    expect(marker!.draggable, isFalse);
    // By default, markers fall in LatLng(0, 0)
    position = marker.position;
    expect(position, isNotNull);
    expect(position!.lat, equals(0));
    expect(position.lng, equals(0));
    // Update the marker with draggable and position
    final Set<Marker> updatedMarkers = <Marker>{
    const Marker(
    markerId: MarkerId('1'),
    draggable: true,
    position: LatLng(42, 54),
    ),
    };
    await controller.changeMarkers(updatedMarkers);
    expect(controller.markers.length, 1);
    marker = controller.markers[const MarkerId('1')]?.marker;
    expect(marker, isNotNull);
    expect(marker!.draggable, isTrue);
    position = marker.position;
    expect(position, isNotNull);
    expect(position!.lat, equals(42));
    expect(position.lng, equals(54));
    });

(You'd just need to add the marker to the controller, then retrieve it by its MarkerId, and then check the zIndex property, similarly to how you're doing it now)


// We compare with zero because zIndexInt if non zero should get higher priority than zIndex
int zIndexInt = marker.getZIndexInt().intValue();
float zIndex = marker.getZIndex().floatValue();
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 not be sending both values; see comments in platform_interface.

Copy link
Contributor

Choose a reason for hiding this comment

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

In fact, I believe once the other changes have been made, you can revert all of the Java changes in this PR.

@@ -1,3 +1,7 @@
## 2.9.6
Copy link
Contributor

Choose a reason for hiding this comment

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

Deprecations are defined to be minor version bumps in semver.

@@ -1,3 +1,7 @@
## 2.9.6

* Deprecates zIndex parameter in Marker and replace with zIndexInt.
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comments as in the other packages.

this.zIndex = 0.0,
this.zIndexInt = 0,
Copy link
Contributor

Choose a reason for hiding this comment

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

zIndexInt should not be a new field, as this creates the possibility of inconsistent values in the same marker. Instead, it can be:

  const Marker({
    ...
    double zIndex = 0.0,
    int zIndexInt = 0,
    ...
  }): assert(zIndex == 0.0 || zIndexInt == 0, 'Only one of zIndex and zIndexInt can be provided'), zIndex = zIndexInt == 0 ? zIndex : zIndexInt.toDouble();

  ...
  /// ...
  // TODO(stuartmorgan): Make this an int when removing the deprecated double zIndex parameter.
  @Deprecated(...)
  final double zIndex;

  /// ...
  int get zIndexInt => zIndex.round();

Then there is only a single value. iOS can read zIndexInt since it will be truncated anyway, and Android can read zIndex with a comment explaining that it's using a deprecated parameter for backward compatibility.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

zIndex = zIndexInt == 0 ? zIndex : zIndexInt.toDouble()

This would need making Marker non -const

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, so it would.

We'll need to go the slightly clunkier route of using a num then:

  const Marker({
    ...
    double zIndex = 0.0,
    int zIndexInt = 0,
    ...
  }): assert(zIndex == 0.0 || zIndexInt == 0, 'Only one of zIndex and zIndexInt can be provided'), _zIndexNum = zIndexInt == 0 ? zIndex : zIndexInt;

  final num _zIndexNum;

  double get zIndex => _zIndexNum.toDouble();

  int get zIndexInt => _zIndex.round();

@@ -198,6 +199,7 @@ class PlatformMarker {
final double rotation;
final bool visible;
final double zIndex;
final int zIndexInt;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be removed; we don't need to send two values.

@@ -1503,6 +1503,7 @@ Marker _copyMarkerWithClusterManagerId(
rotation: marker.rotation,
visible: marker.visible,
zIndex: marker.zIndex,
zIndexInt: marker.zIndexInt,
Copy link
Contributor

Choose a reason for hiding this comment

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

This won't be needed after the suggested change in the platform interface. The zIndex will just need a comment saying that the deprecated parameter is being used to avoid losing precision.

@stuartmorgan
Copy link
Contributor

From triage: @Hari-07 Are you still planning on updating this based on the latest review?

@Hari-07
Copy link
Contributor Author

Hari-07 commented Dec 10, 2024

I have been on a small break, will get back to this next week. Is the packages repo also affected by the flutter code style change and require a rebase?

@stuartmorgan
Copy link
Contributor

No, flutter/packages already uses dart format, so is unaffected.

@Hari-07
Copy link
Contributor Author

Hari-07 commented Jan 10, 2025

@stuartmorgan Sorry for further delays, got busy with the holiday season, will try and get to this at the earliest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[google_maps_flutter] zIndex is silently truncated on iOS
4 participants