Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#Android
accompanistPermissions = "0.34.0"
glide = "4.15.1"
kotlinxCollectionsImmutable = "0.3.5"
minSdk = "24"
compileSdk = "34"
compose-compiler = "1.4.6"
Expand Down Expand Up @@ -53,6 +54,7 @@ dokka = "1.5.0"
#Kotlin
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" }
glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" }
kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutable" }
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTest" }
Expand Down
1 change: 1 addition & 0 deletions lib-compose/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ dependencies {
implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.android)
testImplementation(libs.kotlinx.coroutines.test)
implementation(libs.kotlinx.collections.immutable)

implementation(libs.glide)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,24 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.rememberUpdatedState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import com.what3words.components.compose.maps.buttons.W3WMapButtons
import com.what3words.components.compose.maps.models.W3WLocationSource
import com.what3words.components.compose.maps.models.W3WMapType
import com.what3words.components.compose.maps.models.W3WMarker
import com.what3words.components.compose.maps.providers.googlemap.W3WGoogleMap
import com.what3words.components.compose.maps.providers.mapbox.W3WMapBox
import com.what3words.components.compose.maps.state.W3WButtonsState
import com.what3words.components.compose.maps.state.W3WMapState
import com.what3words.components.compose.maps.state.camera.W3WCameraState
import com.what3words.components.compose.maps.state.camera.W3WGoogleCameraState
import com.what3words.components.compose.maps.state.camera.W3WMapboxCameraState
import com.what3words.core.types.common.W3WError
import com.what3words.core.types.geometry.W3WCoordinates
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -57,6 +62,14 @@ fun W3WMapComponent(
val buttonState by mapManager.buttonState.collectAsState()
val coroutineScope = rememberCoroutineScope { Dispatchers.IO }

val onMarkerClicked = remember(mapManager) {
{ marker: W3WMarker ->
mapManager.setSelectedMarker(marker)
}
}

val currentOnMarkerClicked by rememberUpdatedState(onMarkerClicked)

W3WMapContent(
modifier = modifier,
layoutConfig = layoutConfig,
Expand All @@ -83,6 +96,7 @@ fun W3WMapComponent(
coroutineScope = coroutineScope
)
},
onMarkerClicked = currentOnMarkerClicked,
onError = onError
)
}
Expand Down Expand Up @@ -114,6 +128,7 @@ fun W3WMapComponent(
buttonState: W3WButtonsState,
mapProvider: MapProvider,
content: (@Composable () -> Unit)? = null,
onMarkerClicked: ((W3WMarker) -> Unit)? = null,
onMapTypeClicked: ((W3WMapType) -> Unit)? = null,
onMyLocationClicked: (() -> Unit)? = null,
onMapClicked: ((W3WCoordinates) -> Unit)? = null,
Expand All @@ -140,6 +155,9 @@ fun W3WMapComponent(
onCameraUpdated = {
onCameraUpdated.invoke(it)
},
onMarkerClicked = {
onMarkerClicked?.invoke(it)
},
onError = onError
)
}
Expand Down Expand Up @@ -172,6 +190,7 @@ internal fun W3WMapContent(
buttonState: W3WButtonsState,
mapProvider: MapProvider,
content: (@Composable () -> Unit)? = null,
onMarkerClicked: ((W3WMarker) -> Unit),
onMapTypeClicked: ((W3WMapType) -> Unit),
onMyLocationClicked: () -> Unit,
onMapClicked: (W3WCoordinates) -> Unit,
Expand All @@ -195,6 +214,7 @@ internal fun W3WMapContent(
mapConfig = mapConfig,
mapProvider = mapProvider,
mapState = mapState,
onMarkerClicked = onMarkerClicked,
onMapClicked = onMapClicked,
content = content,
onCameraUpdated = {
Expand Down Expand Up @@ -287,6 +307,7 @@ internal fun W3WMapView(
mapProvider: MapProvider,
mapState: W3WMapState,
content: (@Composable () -> Unit)? = null,
onMarkerClicked: ((W3WMarker) -> Unit),
onMapClicked: ((W3WCoordinates) -> Unit),
onCameraUpdated: (W3WCameraState<*>) -> Unit
) {
Expand All @@ -298,6 +319,7 @@ internal fun W3WMapView(
mapConfig = mapConfig,
state = mapState,
onMapClicked = onMapClicked,
onMarkerClicked = onMarkerClicked,
content = content,
onCameraUpdated = {
onCameraUpdated.invoke(it)
Expand Down Expand Up @@ -341,7 +363,16 @@ private fun fetchCurrentLocation(
// Update camera state
withContext(Main) {
mapManager.moveToPosition(
coordinates = W3WCoordinates(location.latitude, location.longitude),
coordinates = W3WCoordinates(location.latitude,location.longitude),
zoom = when (mapManager.mapProvider) {
MapProvider.GOOGLE_MAP -> {
W3WGoogleCameraState.MY_LOCATION_ZOOM
}

MapProvider.MAPBOX -> {
W3WMapboxCameraState.MY_LOCATION_ZOOM.toFloat()
}
},
animate = true
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.what3words.components.compose.maps.models.DarkModeStyle
import com.what3words.components.compose.maps.models.W3WLatLng
import com.what3words.components.compose.maps.models.W3WMarkerColor

enum class MapProvider {
GOOGLE_MAP,
Expand All @@ -19,6 +21,9 @@ enum class MapProvider {
* including map configuration, grid lines, layout, and buttons.
*/
object W3WMapDefaults {
val LOCATION_DEFAULT = W3WLatLng(51.521251, -0.203586)
val MAKER_COLOR_DEFAULT = W3WMarkerColor(background = Color.Red, slash = Color.White)
val MUlTI_MAKERS_COLOR_DEFAULT = W3WMarkerColor(background = Color.Blue, slash = Color.White)

/**
* Data class representing the configuration for the map.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,21 @@ package com.what3words.components.compose.maps

import android.annotation.SuppressLint
import androidx.annotation.RequiresPermission
import androidx.compose.ui.graphics.Color
import androidx.core.util.Consumer
import com.google.android.gms.maps.model.CameraPosition
import com.google.maps.android.compose.CameraPositionState
import com.mapbox.geojson.Point
import com.mapbox.maps.CameraState
import com.mapbox.maps.EdgeInsets
import com.mapbox.maps.extension.compose.animation.viewport.MapViewportState
import com.what3words.androidwrapper.datasource.text.api.error.BadBoundingBoxTooBigError
import com.what3words.components.compose.maps.W3WMapDefaults.LOCATION_DEFAULT
import com.what3words.components.compose.maps.W3WMapDefaults.MAKER_COLOR_DEFAULT
import com.what3words.components.compose.maps.extensions.computeHorizontalLines
import com.what3words.components.compose.maps.extensions.computeVerticalLines
import com.what3words.components.compose.maps.mapper.toGoogleCameraPosition
import com.what3words.components.compose.maps.models.W3WCameraPosition
import com.what3words.components.compose.maps.mapper.toGoogleLatLng
import com.what3words.components.compose.maps.mapper.toW3WLatLong
import com.what3words.components.compose.maps.mapper.toW3WSquare
import com.what3words.components.compose.maps.models.W3WGridLines
import com.what3words.components.compose.maps.models.W3WMapType
import com.what3words.components.compose.maps.models.W3WMarker
Expand Down Expand Up @@ -80,13 +83,13 @@ class W3WMapManager(
MapViewportState(
initialCameraState = CameraState(
Point.fromLngLat(
CAMERA_POSITION_DEFAULT.coordinates.lng,
CAMERA_POSITION_DEFAULT.coordinates.lat
LOCATION_DEFAULT.lng,
LOCATION_DEFAULT.lat
),
EdgeInsets(0.0, 0.0, 0.0, 0.0),
CAMERA_POSITION_DEFAULT.zoom.toDouble(),
CAMERA_POSITION_DEFAULT.bearing.toDouble(),
CAMERA_POSITION_DEFAULT.tilt.toDouble(),
W3WMapboxCameraState.MY_LOCATION_ZOOM,
0.0,
0.0
)
)
)
Expand All @@ -97,7 +100,12 @@ class W3WMapManager(
it.copy(
cameraState = W3WGoogleCameraState(
CameraPositionState(
position = CAMERA_POSITION_DEFAULT.toGoogleCameraPosition()
position = CameraPosition(
LOCATION_DEFAULT.toGoogleLatLng(),
W3WGoogleCameraState.MY_LOCATION_ZOOM,
0f,
0f
)
)
)
)
Expand Down Expand Up @@ -170,8 +178,20 @@ class W3WMapManager(
mapState.value.cameraState?.orientCamera()
}

fun moveToPosition(coordinates: W3WCoordinates, animate: Boolean) {
mapState.value.cameraState?.moveToPosition(coordinates, animate)
fun moveToPosition(
coordinates: W3WCoordinates,
zoom: Float? = null,
bearing: Float? = null,
tilt: Float? = null,
animate: Boolean = false,
) {
mapState.value.cameraState?.moveToPosition(
coordinates = coordinates,
zoom,
bearing,
tilt,
animate
)
}

fun updateCameraState(newCameraState: W3WCameraState<*>) {
Expand All @@ -188,8 +208,14 @@ class W3WMapManager(
//endregion

//region Selected Address
fun getSelectedMarker(): W3WAddress? {
return mapState.value.selectedAddress?.address
fun setSelectedMarker(marker: W3WMarker) {
_mapState.value = mapState.value.copy(
selectedAddress = marker
)
}

fun getSelectedMarker(): W3WMarker? {
return mapState.value.selectedAddress
}

fun unselect() {
Expand All @@ -215,7 +241,12 @@ class W3WMapManager(
when (val c23wa = textDataSource.convertToCoordinates(words)) {
is W3WResult.Success -> {
_mapState.value = mapState.value.addOrUpdateMarker(
marker = W3WMarker(address = c23wa.value, color = markerColor)
marker = W3WMarker(
words = c23wa.value.words,
square = c23wa.value.square?.toW3WSquare(),
latLng = c23wa.value.center?.toW3WLatLong() ?: LOCATION_DEFAULT,
color = markerColor
)
)
onSuccess?.accept(c23wa.value)
}
Expand Down Expand Up @@ -249,7 +280,12 @@ class W3WMapManager(
when (val c23wa = textDataSource.convertTo3wa(coordinates, language)) {
is W3WResult.Success -> {
_mapState.value = mapState.value.addOrUpdateMarker(
marker = W3WMarker(address = c23wa.value, color = markerColor)
marker = W3WMarker(
words = c23wa.value.words,
square = c23wa.value.square?.toW3WSquare(),
latLng = c23wa.value.center?.toW3WLatLong() ?: LOCATION_DEFAULT,
color = markerColor
)
)
onSuccess?.accept(c23wa.value)
}
Expand All @@ -272,7 +308,12 @@ class W3WMapManager(
when (val c23wa = textDataSource.convertTo3wa(coordinates, language)) {
is W3WResult.Success -> {
_mapState.value = mapState.value.copy(
selectedAddress = W3WMarker(address = c23wa.value, color = MAKER_COLOR_DEFAULT)
selectedAddress = W3WMarker(
words = c23wa.value.words,
square = c23wa.value.square?.toW3WSquare(),
latLng = c23wa.value.center?.toW3WLatLong() ?: LOCATION_DEFAULT,
color = MAKER_COLOR_DEFAULT
)
)
onSuccess?.accept(c23wa.value)
}
Expand Down Expand Up @@ -320,10 +361,4 @@ class W3WMapManager(
it.copy(isLocationActive = isActive)
}
}

companion object {
val CAMERA_POSITION_DEFAULT =
W3WCameraPosition(W3WCoordinates(51.521251, -0.203586), 19f, 0f, 0f)
val MAKER_COLOR_DEFAULT = W3WMarkerColor(background = Color.Red, slash = Color.Yellow)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.what3words.components.compose.maps.extensions

import com.google.maps.android.collections.PolylineManager
import com.what3words.androidwrapper.What3WordsAndroidWrapper
import com.what3words.components.compose.maps.mapper.toW3WLatLong
import com.what3words.components.compose.maps.models.W3WLatLng
import com.what3words.core.types.geometry.W3WCoordinates
import com.what3words.core.types.geometry.W3WLine
import com.what3words.core.types.geometry.W3WRectangle
Expand Down Expand Up @@ -52,9 +54,9 @@ fun Long.toCoordinates(): W3WCoordinates {
* | | |
* 2-----3 6 ..
*/
internal fun List<W3WLine>.computeVerticalLines(): List<W3WCoordinates> {
internal fun List<W3WLine>.computeVerticalLines(): List<W3WLatLng> {
val computedVerticalLines =
mutableListOf<W3WCoordinates>()
mutableListOf<W3WLatLng>()

// all vertical lines
val verticalLines = mutableListOf<W3WLine>()
Expand All @@ -64,11 +66,11 @@ internal fun List<W3WLine>.computeVerticalLines(): List<W3WCoordinates> {
while (verticalLines.isNotEmpty()) {
verticalLines.maxByOrNull { it.start.lat }?.let { topLeftGrid ->
if (t % 2 == 0) {
computedVerticalLines.add(topLeftGrid.start)
computedVerticalLines.add(topLeftGrid.end)
computedVerticalLines.add(topLeftGrid.start.toW3WLatLong())
computedVerticalLines.add(topLeftGrid.end.toW3WLatLong())
} else {
computedVerticalLines.add(topLeftGrid.end)
computedVerticalLines.add(topLeftGrid.start)
computedVerticalLines.add(topLeftGrid.end.toW3WLatLong())
computedVerticalLines.add(topLeftGrid.start.toW3WLatLong())
}
verticalLines.remove(topLeftGrid)
}
Expand All @@ -92,9 +94,9 @@ internal fun List<W3WLine>.computeVerticalLines(): List<W3WCoordinates> {
* |
* E-----F
*/
internal fun List<W3WLine>.computeHorizontalLines(): List<W3WCoordinates> {
internal fun List<W3WLine>.computeHorizontalLines(): List<W3WLatLng> {
val computedHorizontalLines =
mutableListOf<W3WCoordinates>()
mutableListOf<W3WLatLng>()

// all horizontal lines
val horizontalLines = mutableListOf<W3WLine>()
Expand All @@ -104,11 +106,11 @@ internal fun List<W3WLine>.computeHorizontalLines(): List<W3WCoordinates> {
while (horizontalLines.isNotEmpty()) {
horizontalLines.minByOrNull { it.start.lng }?.let { topLeftGrid ->
if (t % 2 == 0) {
computedHorizontalLines.add(topLeftGrid.start)
computedHorizontalLines.add(topLeftGrid.end)
computedHorizontalLines.add(topLeftGrid.start.toW3WLatLong())
computedHorizontalLines.add(topLeftGrid.end.toW3WLatLong())
} else {
computedHorizontalLines.add(topLeftGrid.end)
computedHorizontalLines.add(topLeftGrid.start)
computedHorizontalLines.add(topLeftGrid.end.toW3WLatLong())
computedHorizontalLines.add(topLeftGrid.start.toW3WLatLong())
}
horizontalLines.remove(topLeftGrid)
t += 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.what3words.components.compose.maps.mapper

import com.what3words.components.compose.maps.models.W3WLatLng
import com.what3words.components.compose.maps.models.W3WSquare
import com.what3words.core.types.geometry.W3WCoordinates
import com.what3words.core.types.geometry.W3WRectangle

fun W3WRectangle.toW3WSquare(): W3WSquare {
return W3WSquare(this.southwest.toW3WLatLong(), this.northeast.toW3WLatLong())
}

fun W3WCoordinates.toW3WLatLong(): W3WLatLng {
return W3WLatLng(this.lat, this.lng)
}
Loading