-
Notifications
You must be signed in to change notification settings - Fork 39
Show Callout Sample #137
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
Show Callout Sample #137
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice sample @prupani-7, just a few minor comments mainly to use the MapViewModel
to update and show the callout on the MapView
show-callout/src/main/java/com/esri/arcgismaps/sample/showcallout/components/ComposeMapView.kt
Outdated
Show resolved
Hide resolved
show-callout/src/main/java/com/esri/arcgismaps/sample/showcallout/components/ComposeMapView.kt
Outdated
Show resolved
Hide resolved
@Composable | ||
fun ComposeMapView( | ||
modifier: Modifier = Modifier, | ||
mapViewModel: MapViewModel, | ||
application: Application | ||
) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think with this sample we should keep the business logic in the MapViewModel
, where the mapPoint
and the TextView
would be set. The ComposeMapView
should return a lambda on every tap event which is then consumed by the MainScreen
similar to the Show coordinates in multiple formats sample. Would probably be helpful to have the Callout and viewpoint as properties of the MapViewState
Lines 51 to 53 in 5692022
onSingleTap = { singleTapConfirmedEvent -> | |
mapViewModel.onMapTapped(singleTapConfirmedEvent.mapPoint) | |
} |
@Composable | |
fun ComposeMapView( | |
modifier: Modifier = Modifier, | |
mapViewModel: MapViewModel, | |
application: Application | |
) { | |
@Composable | |
fun ComposeMapView( | |
modifier: Modifier = Modifier, | |
mapViewModel: MapViewModel, | |
onSingleTap: (SingleTapConfirmedEvent) -> Unit = {}) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, aware that the business logic goes in MapViewModel, and I tried that approach first, i.e. to add a new property callout
to the MapViewState. But we cannot initialize Callout, as it has no constructors
Which is why I adapted the above implemented approach
If you have thoughts on the MapViewState callout property approach , we could discuss on a call
83d5e1c
to
62203e8
Compare
@shubham7109 as Discussed in a call, the logic is now in mapViewModel with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the MapViewModel
here looks nice! Just two minor comments, but good to approve 👍
// launch coroutine functions in the composition's CoroutineContext | ||
LaunchedEffect(Unit) { | ||
launch { | ||
mapView.onSingleTapConfirmed.collect { | ||
onSingleTap(it) | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// launch coroutine functions in the composition's CoroutineContext | |
LaunchedEffect(Unit) { | |
launch { | |
mapView.onSingleTapConfirmed.collect { | |
onSingleTap(it) | |
} | |
} | |
} | |
// launch a coroutine to detect a map tap | |
LaunchedEffect(Unit) { | |
mapView.onSingleTapConfirmed.collect { | |
onSingleTap(it) | |
} | |
} |
I think it's creating two coroutine scopes here as the LaunchedEffect
should launch a new coroutine. This seems to have been glossed over before since it is generated by the script. 😅 Maybe in the future I would like to show you the old-school Java project for the new module script and we could chat about how it works.
arcgis-maps-sdk-kotlin-samples/tools/NewModuleScript/ComposeMapViewTemplate.kt
Lines 62 to 69 in 5692022
// launch coroutine functions in the composition's CoroutineContext | |
LaunchedEffect(Unit) { | |
launch { | |
mapView.onSingleTapConfirmed.collect { | |
onSingleTap(it) | |
} | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to have been glossed over before since it is generated by the script.
Shouldn't launch
be removed from the template then?
// create a textview for the callout | ||
mapViewState.value.calloutContent.text = application.getString( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The TextView
is created in the MapViewState
// create a textview for the callout | |
mapViewState.value.calloutContent.text = application.getString( | |
// set the callout text to display point coordinates | |
mapViewState.value.calloutContent.text = application.getString( |
|
||
fun onMapTapped(mapPoint: Point?) { | ||
// get map point from the Single tap event | ||
mapPoint?.let { mapPoint -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument mapPoint
of Lamda closure shadows the mapPoint
, it'd better change a different name, e.g 'point'
modifier = modifier, | ||
factory = { mapView }, | ||
// recomposes the MapView on changes in the MapViewState | ||
update = { mapView -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, The argument mapView
of Lamda closure shadows the variable mapView, it'd better change a different name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if I understand this completely.
By shadows the mapView variable
do you mean the one created above val mapView = createMapViewInstance()
on line 48?
This is something we follow across all samples, and part of the sample template.
To me mapView
name still holds valid in the update block.
If at all, we decide to make a change, I would vote for making change to the mapView var created using createMapViewInstance() to something like mapViewInstance
or mapViewObject
CC: @shubham7109 since you spearheaded these changes in the initial sample design phase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean the line 60, the mapView
overshadows the outside variable mapView
fun ComposeMapView( | ||
modifier: Modifier = Modifier, | ||
mapViewModel: MapViewModel, | ||
onSingleTap: (SingleTapConfirmedEvent) -> Unit = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could it be better for the callback be a suspend
function, onSingleTap: suspend (SingleTapConfirmedEvent) -> Unit = {}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@changanxian I don't think I understand, what value will it bring in current samples, making the onSingleTap callback a suspend function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may not be necessary in this case, and keep the current implementation. But it will be an asynchronous call. Imagine if the onSingleTap
is called in a loop, it will be different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay!
data class MapViewState(val application: Application) { | ||
var arcGISMap: ArcGISMap = ArcGISMap(BasemapStyle.ArcGISNavigationNight) | ||
var viewpoint: Viewpoint = Viewpoint(34.056295, -117.195800, 1000000.0) | ||
var calloutContent: TextView by mutableStateOf(TextView(application)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a little odd for me to have a UI TextView
in the class mix in other non-UI classes, could it be refactored into a String? Keep the UI TextView outside of the class, we only need to keep track of the state of the contents, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, this got me thinking that the 2 variables calloutContent
and latLonPoint
could be MapViewModel properties instead of MapViewState
properties.
change to
TextView needs an applicationContext available in the viewmodel class
@shubham7109 Since we worked on this change together, tagging you for review.
@prupani-7 a few comments. |
// launch coroutine functions in the composition's CoroutineContext | ||
LaunchedEffect(Unit) { | ||
mapView.onSingleTapConfirmed.collect { | ||
onSingleTap(it) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After this Friday's coffee meeting(9/29), I think you need to change this line to
launch {
onSingleTap(it)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is OK for this case, onSingleTap
doesn't block anything
) | ||
|
||
// launch coroutine functions in the composition's CoroutineContext | ||
LaunchedEffect(Unit) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a little better to change this to LaunchedEffect(mapView)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it may be not necessary.
@prupani-7 Looks good |
Thanks @changanxian @shubham7109 for your reviews. Merging... |
Description
PR to add a new Kotlin sample "Show Callout" in
Maps
category.Links and Data
Sample Epic:
runtime/kotlin/issues/1117
What To Review
README.md
andREADME.metadata.json
filesHow to Test
Run the sample on the sample viewer or the repo.