Skip to content

Rough proposed new API surface for marker dragging - #150

Closed
bubenheimer wants to merge 0 commit into
googlemaps:mainfrom
bubenheimer:main
Closed

Rough proposed new API surface for marker dragging#150
bubenheimer wants to merge 0 commit into
googlemaps:mainfrom
bubenheimer:main

Conversation

@bubenheimer

Copy link
Copy Markdown
Contributor

Fixes #149 🦕

This is primarily intended at this point to share the changed API surface I have in mind. Underlying rationale is in linked issue.

@arriolac arriolac left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Some questions on your rough design. I'm hoping the addition of an event lambda specific for drag events will resolve the main issue you're encountering with the current design.

I would expect a design closer to this:

@Composable
fun Marker(
  // ...
+ onDragEvent: ((DragState) -> Unit)? = null,
)

public class MarkerState(
   position: LatLng = LatLng(0.0, 0.0)
) {
   public var position: LatLng by mutableStateOf(position)

- public var dragState: DragState by mutableStateOf(DragState.END)
+ public var dragging: Boolean by mutableStateOf(false)
}

The reason the position still has to be encapsulated within MarkerState is because the Maps SDK is the owner of the marker's position, which is not the Compose way of doing this. This solution is a workaround that behavior (this is similar to why we have CameraPositionState). Let me know if this makes sense and if I'm missing something.

state: MarkerState = rememberMarkerState(),
alpha: Float = 1.0f,
anchor: Offset = Offset(0.5f, 1.0f),
draggable: Boolean = false,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What's the reason for removing this param? I would expect this to still be here.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I was thinking the same thing - we still need it to indicate if the user can drag a marker

@bubenheimer bubenheimer Nov 7, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, having DragState available via an event handler will be useful.

In #149 I laid out in detail why I find it both necessary and feasible to also eliminate position from MarkerState. In summary, it is true that the Maps SDK owns the marker's position, but closely aligning the Compose API design with that ownership model is barely usable except in toy apps. I linked several issues caused by this design that came up since I created #149, and I am certain that this pattern will repeat until the design changes.

I agree that it is not ideal and means taking a small risk to turn the ownership model on its head, but the current approach is just too awful to use, every time I look at my workarounds there I get a stomach ache. A design change here could be confined to an experimental playground somehow. It is the lesser evil from a usability perspective.

I'd likely try to run my own fork if it cannot be resolved within the main project.

CameraPositionState is very different because there is only one camera. Hoisting it into a State object does not have a great impact on usability.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

When position is removed from MarkerState, the only way to keep track of user-changed marker position is via the onDragEvent callback. It would be rather odd to have a draggable marker without wanting to be informed about position changes via the callback, and even in that unusual case the callback can just be.an empty lambda. So the draggable parameter ends up just duplicating the presence of the callback.

@bubenheimer bubenheimer Nov 8, 2022

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I do think that onDragEvent should receive the current Marker position as a parameter in any case, as I suggested in my original PR. Otherwise the onDragEvent lambda would need to rely on an implicit promise that MarkerState is timely updated to the position tied to the corresponding drag event. This is obscure on the API consumer's side, and would seem error-prone on the API implementation side.

@Composable
@GoogleMapComposable
public fun Marker(
position: LatLng,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is definitely the Compose way of representing a marker's position. However, since this is an interop library, the issue with this design is that the marker's position is owned by the Maps SDK. So when you drag the marker to a new location, this value is no longer correct. This is why MarkerState was introduced and needed as a workaround to the internal behavior of the Maps SDK.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Please see my comments in #149 regarding how to keep marker position up-to-date.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Moving position here would definitely match the mental model of Compose though I think changing the behavior of what the Maps SDK is doing under the hood to create a better Compose API might create more problems down the line.

I see your comment below about reworking a solution. My 2c of a summary of proposed changes that would solve your particular use case is:

  • Add onDrag: (LatLng, DragEvent) -> lambda to Marker
  • Deprecate MarkerState.dragState
  • Add MarkerState.isDragging

@bubenheimer

bubenheimer commented Oct 20, 2022 via email

Copy link
Copy Markdown
Contributor Author

title: String? = null,
visible: Boolean = true,
zIndex: Float = 0.0f,
onDragEvent: ((DragState, LatLng) -> Unit)? = null,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

maybe just onDrag(...)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not really opposed to it, except for English semantics, which are debatable. To me onDrag sounds like a singular complete drag action to a new position. Marker dragging is a sequence of events, at least 2, usually many more. onDragEvent carries a less succinct meaning to me, it could mean anything. onDragSequenceEvent would be better from that perspective, but is verbose.

@bubenheimer

Copy link
Copy Markdown
Contributor Author

After thinking about it some more I will take another shot at reworking my code under the assumption of MarkerState continuing to encapsulate the marker position. I expect to have an update in a few days.

bubenheimer added a commit to bubenheimer/android-maps-compose that referenced this pull request May 27, 2024
This is a non-breaking change following suggestions from @arriolac for addressing googlemaps#149: googlemaps#150 (comment)

This PR does not add an `onDrag` callback parameter to `Marker()`, which would be a somewhat breaking change; this functionality is not strictly necessary and I see alternatives that may be preferable.

Summary of changes:

1. Deprecate MarkerState.dragState and DragState enum. These were carried over from GoogleMap SDK; they are events that were mischaracterized as states.
2. Replace with MarkerState.isDragging boolean.
3. Clarify KDoc in several places.
4. Add several examples providing patterns for common use cases.
5. Organize Marker-related examples into their own folder.

Fixes googlemaps#149
dkhawk pushed a commit that referenced this pull request Jun 6, 2024
* fix: improve MarkerState API

This is a non-breaking change following suggestions from @arriolac for addressing #149: #150 (comment)

This PR does not add an `onDrag` callback parameter to `Marker()`, which would be a somewhat breaking change; this functionality is not strictly necessary and I see alternatives that may be preferable.

Summary of changes:

1. Deprecate MarkerState.dragState and DragState enum. These were carried over from GoogleMap SDK; they are events that were mischaracterized as states.
2. Replace with MarkerState.isDragging boolean.
3. Clarify KDoc in several places.
4. Add several examples providing patterns for common use cases.
5. Organize Marker-related examples into their own folder.

Fixes #149

* Add an example for how to efficiently create a derived list of MarkerStates from a changing model list of marker positions by collecting results from key() composable

Rename marker examples folder to markerexamples for clarity

* Refine example

* Improve KDoc for example

* Improve KDoc for example

* Simplify and improve example

---------

Co-authored-by: Uli Bubenheimer <bubenheimer@users.noreply.github.com>
googlemaps-bot pushed a commit that referenced this pull request Jun 6, 2024
## [5.0.3](v5.0.2...v5.0.3) (2024-06-06)

### Bug Fixes

* improve MarkerState API ([#515](#515)) ([3b40b92](3b40b92)), closes [#149](#149) [/github.com//pull/150#discussion_r1016963262](https://github.com//github.com/googlemaps/android-maps-compose/pull/150/issues/discussion_r1016963262) [#149](#149)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Marker dragging: fix loss of drag events and difficulty observing marker positions

3 participants