Skip to content

Commit 295d03e

Browse files
Implement mapView.setMapDesign() function. (#59)
* TempSave * TempSave3 * Resolve merge conflicts. * WIP: GroundImage bounds change detection in progress. * WIP: GroundImage rendered; modification handling not yet done. * Add support for swapping GroundImage (Google Maps API GroundOverlay) image on touch event * Impliment edit opacity slider'. * update README.md * Changes groundImageState.opacity following the slider value * Initial implementation of GroundImage (GroundOverlay). NE and SW markers are not yet linked with bounds, but committing as instructed. * WIP: GroundImage feature implementation. Known issue: recomposition does not occur, committing current state. * Fix: GroundImage does not update by following markers * Fix: GeoRectBounds.extend is incorrect * Update: Marker labels based on the relative positions * Prepared initial implementation setup of MapDesignType for Google Maps API. * Prepared initial implementation setup of MapDesignType for Google Maps API. * Resolve conflicts and add MapDesign demo with Google Maps SDK. * Add MapDesign change demo for Google Maps API and initial Here Map support with list display (WIP). * feat(here): add MapDesign support for HereMap with runtime style switching. * feat(Mapbox): add MapDesign support for Mapbox with runtime style switching. * feat(ArcGIS): add MapDesign support for ArcGIS with runtime style switching. * Refactor MapDesign selection UI: replace button controls with dropdown list. * Refactor: update variable names to match dropdown list usage. * Update MapDesign list handling to show all available designs instead of a sample subset. * Refactor: move design data definition out of onMapViewChanged() and decouple from list display. * Refactored code based on review feedback.(1st) * Refactored code based on review feedback.(2nd) * Refactored code based on review feedback.(3rd) * Refactored code based on review feedback.(4th) --------- Co-authored-by: Masashi Katsumata <wf9a5m75@gmail.com>
1 parent cfffc4e commit 295d03e

46 files changed

Lines changed: 1805 additions & 444 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ KtLintに従います。ローカルで実行する場合は、下記コマン
2424
| Map | &#x2611; | &#x2611; | &#x2611; | &#x2611; |
2525
| Marker | &#x2611; | &#x2611; | &#x2611; | &#x2611; |
2626
| Circle | &#x2611; | &#x2611; | &#x2610; | &#x2610; (wip) |
27-
| Polyline | &#x2610; | &#x2610; | &#x2610; | &#x2610; |
28-
| Polygon | &#x2610; | &#x2610; | &#x2610; | &#x2610; |
29-
| GroundOverlay | &#x2610; | &#x2610; | &#x2610; | &#x2610; |
30-
| RasterTileLayer | &#x2610; | &#x2610; | &#x2610; | &#x2610; |
31-
| VectorTileLayer | &#x2610; | &#x2610; | &#x2610; | &#x2610; |
27+
| Polyline | &#x2611; | &#x2611; | &#x2611; | &#x2611; |
28+
| Polygon | &#x2610; | &#x2610; | &#x2610; | &#x2610; |
29+
| GroundOverlay | &#x2610; | &#x2610; | &#x2610; | &#x2610; |
30+
| RasterTileLayer | &#x2610; | &#x2610; | &#x2610; | &#x2610; |
31+
| VectorTileLayer | &#x2610; | &#x2610; | &#x2610; | &#x2610; |

example-app/src/main/java/com/mapconductor/example/DemoAppScreen.kt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package com.mapconductor.example
33
import androidx.compose.foundation.layout.Box
44
import androidx.compose.foundation.layout.fillMaxSize
55
import androidx.compose.material.icons.Icons
6+
import androidx.compose.material.icons.filled.Build
67
import androidx.compose.material.icons.filled.CheckCircle
8+
import androidx.compose.material.icons.filled.Favorite
79
import androidx.compose.material.icons.filled.Home
810
import androidx.compose.material.icons.filled.PlayArrow
911
import androidx.compose.material3.Text
@@ -17,8 +19,11 @@ import androidx.core.content.ContextCompat
1719
import androidx.lifecycle.viewmodel.compose.viewModel
1820
import com.mapconductor.example.navigation.NavigationViewModel
1921
import com.mapconductor.example.pages.circle.CircleMapPage
22+
import com.mapconductor.example.pages.groundimage.GroundImageMapPage
23+
import com.mapconductor.example.pages.groundimage.GroundImageResources
2024
import com.mapconductor.example.pages.map.flyto.FlyToMapIcons
2125
import com.mapconductor.example.pages.map.flyto.FlyToMapPage
26+
import com.mapconductor.example.pages.mapDesign.MapDesignMapPage
2227
import com.mapconductor.example.pages.polyline.PolylineMapPage
2328
import com.mapconductor.example.pages.stores.StoreMapPage
2429
import com.mapconductor.example.ui.sidebar.Sidebar
@@ -42,6 +47,14 @@ fun DemoAppScreen() {
4247
)
4348
}
4449

50+
val groundImageResources =
51+
remember {
52+
GroundImageResources(
53+
image = ContextCompat.getDrawable(context, R.drawable.newark_nj_1922_0)!!,
54+
clickedImage = ContextCompat.getDrawable(context, R.drawable.newark_nj_1922_1)!!,
55+
)
56+
}
57+
4558
val sidebarItems =
4659
listOf(
4760
SidebarItem(
@@ -62,12 +75,24 @@ fun DemoAppScreen() {
6275
icon = Icons.Default.CheckCircle,
6376
route = "circle",
6477
),
78+
SidebarItem(
79+
id = "groundImage",
80+
title = "GroundImage",
81+
icon = Icons.Default.Favorite,
82+
route = "groundImage",
83+
),
6584
SidebarItem(
6685
id = "polyline",
6786
title = "Polyline ",
6887
icon = Icons.Default.PlayArrow,
6988
route = "polyline",
7089
),
90+
SidebarItem(
91+
id = "mapDesign",
92+
title = "MapDesign Demo",
93+
icon = Icons.Default.Build,
94+
route = "mapDesign",
95+
),
7196
// SidebarItem(
7297
// id = "examples",
7398
// title = "Map Examples",
@@ -108,6 +133,17 @@ fun DemoAppScreen() {
108133
onToggleSidebar = navigationViewModel::toggleSidebar,
109134
)
110135
}
136+
"groundImage" -> {
137+
GroundImageMapPage(
138+
groundImageResources = groundImageResources,
139+
onToggleSidebar = navigationViewModel::toggleSidebar,
140+
)
141+
}
142+
"mapDesign" -> {
143+
MapDesignMapPage(
144+
onToggleSidebar = navigationViewModel::toggleSidebar,
145+
)
146+
}
111147
"settings" -> {
112148
// Placeholder for settings page
113149
Box(

example-app/src/main/java/com/mapconductor/example/MapViewContainer.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.mapconductor.arcgis.ArcGISMapView
66
import com.mapconductor.arcgis.ArcGISMapViewState
77
import com.mapconductor.core.MapViewScope
88
import com.mapconductor.core.circle.OnCircleEventHandler
9+
import com.mapconductor.core.groundimage.OnGroundImageEventHandler
910
import com.mapconductor.core.map.MapViewState
1011
import com.mapconductor.core.map.OnMapEventHandler
1112
import com.mapconductor.core.marker.OnMarkerEventHandler
@@ -30,6 +31,7 @@ fun MapViewContainer(
3031
onMarkerAnimateEnd: OnMarkerEventHandler? = null,
3132
onCircleClick: OnCircleEventHandler? = null,
3233
onPolylineClick: OnPolylineEventHandler? = null,
34+
onGroundImageClick: OnGroundImageEventHandler? = null,
3335
content: @Composable MapViewScope.() -> Unit,
3436
) {
3537
when (state) {
@@ -46,6 +48,7 @@ fun MapViewContainer(
4648
onMarkerAnimateEnd = onMarkerAnimateEnd,
4749
onCircleClick = onCircleClick,
4850
onPolylineClick = onPolylineClick,
51+
onGroundImageClick = onGroundImageClick,
4952
content = content,
5053
)
5154

@@ -60,6 +63,7 @@ fun MapViewContainer(
6063
onMarkerDragEnd = onMarkerDragEnd,
6164
onMarkerAnimateStart = onMarkerAnimateStart,
6265
onMarkerAnimateEnd = onMarkerAnimateEnd,
66+
onGroundImageClick = onGroundImageClick,
6367
onCircleClick = onCircleClick,
6468
onPolylineClick = onPolylineClick,
6569
content = content,
@@ -78,6 +82,7 @@ fun MapViewContainer(
7882
onMarkerAnimateEnd = onMarkerAnimateEnd,
7983
onCircleClick = onCircleClick,
8084
onPolylineClick = onPolylineClick,
85+
onGroundImageClick = onGroundImageClick,
8186
content = content,
8287
)
8388

@@ -93,6 +98,7 @@ fun MapViewContainer(
9398
onMarkerAnimateStart = onMarkerAnimateStart,
9499
onMarkerAnimateEnd = onMarkerAnimateEnd,
95100
onCircleClick = onCircleClick,
101+
onGroundImageClick = onGroundImageClick,
96102
onPolylineClick = onPolylineClick,
97103
content = content,
98104
)

example-app/src/main/java/com/mapconductor/example/navigation/NavigationViewModel.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import androidx.compose.runtime.mutableStateOf
55
import androidx.lifecycle.ViewModel
66

77
class NavigationViewModel : ViewModel() {
8-
private val _currentPage = mutableStateOf("flyTo")
8+
private val _currentPage = mutableStateOf("groundImage")
99
val currentPage: State<String> = _currentPage
1010

1111
private val _isSidebarExpanded = mutableStateOf(false)

example-app/src/main/java/com/mapconductor/example/pages/circle/CircleMapComponent.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,7 @@ fun CircleMapComponent(
3131
onMarkerDrag = onMarkerDrag,
3232
) {
3333
// Circle
34-
key(viewModel.circleState.id) {
35-
Circle(viewModel.circleState)
36-
}
34+
Circle(viewModel.circleState)
3735

3836
// Center marker (not draggable)
3937
key(viewModel.centerMarker.id) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.mapconductor.example.pages.groundimage
2+
3+
import androidx.compose.runtime.Composable
4+
import androidx.compose.ui.Modifier
5+
import com.mapconductor.core.groundimage.GroundImage
6+
import com.mapconductor.core.groundimage.OnGroundImageEventHandler
7+
import com.mapconductor.core.map.MapViewState
8+
import com.mapconductor.core.marker.Marker
9+
import com.mapconductor.core.marker.OnMarkerEventHandler
10+
import com.mapconductor.example.MapViewContainer
11+
12+
@Composable
13+
fun GroundImageMapComponent(
14+
mapViewState: MapViewState<*>?,
15+
viewModel: GroundImageMapPageViewModel,
16+
modifier: Modifier = Modifier,
17+
onGroundImageClick: OnGroundImageEventHandler = {},
18+
onMarkerDrag: OnMarkerEventHandler = {},
19+
) {
20+
mapViewState?.let { mapViewState ->
21+
MapViewContainer(
22+
modifier = modifier,
23+
state = mapViewState,
24+
onGroundImageClick = onGroundImageClick,
25+
onMarkerDrag = onMarkerDrag,
26+
) {
27+
// GroundImage
28+
GroundImage(viewModel.groundImageState)
29+
30+
// BoundsMarkers
31+
viewModel.markers.forEach { marker ->
32+
Marker(marker)
33+
}
34+
}
35+
}
36+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.mapconductor.example.pages.groundimage
2+
3+
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.foundation.layout.calculateEndPadding
5+
import androidx.compose.foundation.layout.calculateStartPadding
6+
import androidx.compose.foundation.layout.padding
7+
import androidx.compose.material3.Slider
8+
import androidx.compose.material3.SliderDefaults
9+
import androidx.compose.material3.Text
10+
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.collectAsState
12+
import androidx.compose.ui.Alignment
13+
import androidx.compose.ui.Modifier
14+
import androidx.compose.ui.graphics.Color
15+
import androidx.compose.ui.unit.LayoutDirection
16+
import androidx.compose.ui.unit.dp
17+
import androidx.lifecycle.ViewModel
18+
import androidx.lifecycle.ViewModelProvider
19+
import androidx.lifecycle.viewmodel.compose.viewModel
20+
import com.mapconductor.example.toast.ToastHost
21+
import com.mapconductor.example.ui.DemoMapPageScaffold
22+
import com.mapconductor.example.ui.MessageCard
23+
24+
@Composable
25+
fun GroundImageMapPage(
26+
groundImageResources: GroundImageResources,
27+
onToggleSidebar: () -> Unit = {},
28+
) {
29+
val viewModel: GroundImageMapPageViewModel =
30+
viewModel<GroundImageMapPageViewModelImpl>(
31+
factory =
32+
object : ViewModelProvider.Factory {
33+
override fun <T : ViewModel> create(modelClass: Class<T>): T {
34+
if (modelClass.isAssignableFrom(GroundImageMapPageViewModelImpl::class.java)) {
35+
@Suppress("UNCHECKED_CAST")
36+
return GroundImageMapPageViewModelImpl(groundImageResources) as T
37+
}
38+
throw IllegalArgumentException("Unknown ViewModel class")
39+
}
40+
},
41+
)
42+
43+
DemoMapPageScaffold(
44+
initCameraPosition = viewModel.initCameraPosition,
45+
onToggleSidebar = onToggleSidebar,
46+
onMapViewStateChanged = viewModel::onMapViewChanged,
47+
) { paddingValues ->
48+
val mapViewState = viewModel.mapViewState.collectAsState()
49+
50+
GroundImageMapComponent(
51+
mapViewState = mapViewState.value,
52+
viewModel = viewModel,
53+
onGroundImageClick = viewModel::onGroundImageClick,
54+
onMarkerDrag = viewModel::onMarkerDrag,
55+
)
56+
57+
// Message Card
58+
MessageCard(
59+
modifier =
60+
Modifier
61+
.align(Alignment.BottomStart)
62+
.padding(
63+
bottom = paddingValues.calculateBottomPadding() + 16.dp,
64+
start = paddingValues.calculateStartPadding(LayoutDirection.Ltr) + 16.dp,
65+
end = paddingValues.calculateEndPadding(LayoutDirection.Ltr) + 16.dp,
66+
),
67+
title = "Messages",
68+
) {
69+
Column {
70+
Text("opacity: ${"%.2f".format(viewModel.opacity)}", color = Color.Black)
71+
Slider(
72+
value = viewModel.opacity,
73+
onValueChange = { newValue ->
74+
viewModel.opacity = newValue
75+
},
76+
valueRange = 0.0f..1.0f, // スライダー範囲
77+
steps = 0,
78+
colors =
79+
SliderDefaults.colors(
80+
thumbColor = Color.Black, // つまみの色
81+
activeTrackColor = Color.DarkGray, // 値までのトラック
82+
inactiveTrackColor = Color.LightGray, // 残りのトラック
83+
activeTickColor = Color.Black, // 有効ステップの目盛り
84+
inactiveTickColor = Color.White, // 無効ステップの目盛り
85+
),
86+
)
87+
}
88+
}
89+
90+
ToastHost(
91+
messages = viewModel.messages.collectAsState().value,
92+
onDismiss = { viewModel.removeToast(it) },
93+
)
94+
}
95+
}

0 commit comments

Comments
 (0)