Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<!-- zoom in drawable -->
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">

<path android:fillColor="#ffffff" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>

</vector>

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">

<path android:fillColor="#ffffff" android:pathData="M240,520L240,440L720,440L720,520L240,520Z"/>

</vector>
173 changes: 111 additions & 62 deletions composeApp/src/commonMain/kotlin/com/farimarwat/krossmapdemo/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import krossmapdemo.composeapp.generated.resources.ic_3d_view_cross
import krossmapdemo.composeapp.generated.resources.ic_current_location
import krossmapdemo.composeapp.generated.resources.ic_direction
import krossmapdemo.composeapp.generated.resources.ic_direction_cross
import krossmapdemo.composeapp.generated.resources.ic_zoom_in
import krossmapdemo.composeapp.generated.resources.ic_zoom_out
import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.ui.tooling.preview.Preview

Expand All @@ -49,7 +51,7 @@ fun App() {
MaterialTheme {
val latitude = 32.60370
val longitude = 70.92179
val zoom = 17f
var zoomValue by remember { mutableStateOf(17f) }
val currentLocationMarker = remember {
mutableStateOf<KrossMarker?>(null)
}
Expand All @@ -73,34 +75,16 @@ fun App() {
BindEffect(permissionController)
LaunchedEffect(Unit) {
permissionGranted = permissionController.isPermissionGranted(Permission.LOCATION)
if (!permissionGranted) {
try {
permissionController.providePermission(Permission.LOCATION)
permissionGranted =
permissionController.isPermissionGranted(Permission.LOCATION)
} catch (ex: DeniedException) {
permissionController.openAppSettings()
println(ex)
} catch (ex: DeniedAlwaysException) {
permissionController.openAppSettings()
println(ex)
} catch (ex: RequestCanceledException) {
println(ex)
}
} else {
println("Permission already granted")
}
}


//Create Map State
val mapState = rememberKrossMapState()
var cameraFollow by remember { mutableStateOf(true)}
//Create Camera State
val cameraState = rememberKrossCameraPositionState(
latitude = latitude,
longitude = longitude,
zoom = zoom,
zoom = zoomValue,
cameraFollow = cameraFollow
)

Expand All @@ -112,17 +96,18 @@ fun App() {
icon = Res.readBytes("drawable/ic_tracker.png")
)
}

LaunchedEffect(Unit) {
mapState.onUpdateLocation = {
currentLocationMarker.value = currentLocationMarker.value?.copy(coordinate = it)
currentLocationMarker.value?.let { cm ->
mapState.addOrUpdateMarker(cm)
}

}
}
LaunchedEffect(navigation) {
if (navigation) {

LaunchedEffect(navigation, permissionGranted) {
if (navigation && permissionGranted) {
mapState.startLocationUpdate()
} else {
mapState.stopLocationUpdate()
Expand Down Expand Up @@ -152,47 +137,75 @@ fun App() {
mapState.addPolyLine(polyline)
}

if (permissionGranted) {
//Create Map
KrossMap(
modifier = Modifier.fillMaxSize(),
mapState = mapState,
cameraPositionState = cameraState,
mapSettings = {
MapSettings(
tilt = cameraState.tilt,
navigation = navigation,
onCurrentLocationClicked = {
mapState.requestCurrentLocation()
scope.launch {
mapState.currentLocation?.let{
cameraState.animateCamera(it.latitude, it.longitude)
}
}
},
toggle3DViewClicked = {
scope.launch {
cameraState.tilt = if (cameraState.tilt > 0) {
0f
} else {
45f
//Create Map (always render; location permission requested only on demand)
KrossMap(
modifier = Modifier.fillMaxSize(),
mapState = mapState,
cameraPositionState = cameraState,
mapSettings = {
MapSettings(
tilt = cameraState.tilt,
navigation = navigation,
onCurrentLocationClicked = {
scope.launch {
var granted =
permissionController.isPermissionGranted(Permission.LOCATION)
if (!granted) {
try {
permissionController.providePermission(Permission.LOCATION)
} catch (ex: DeniedException) {
permissionController.openAppSettings()
println(ex)
} catch (ex: DeniedAlwaysException) {
permissionController.openAppSettings()
println(ex)
} catch (ex: RequestCanceledException) {
println(ex)
}
granted =
permissionController.isPermissionGranted(Permission.LOCATION)
}
permissionGranted = granted
if (granted) {
mapState.requestCurrentLocation()
mapState.currentLocation?.let { loc ->
cameraState.animateCamera(loc.latitude, loc.longitude)
}

//Pause navigation for a second because it will effectly change the 3d mode.
val oldNavigation = navigation
navigation = false
delay(500)
cameraState.animateCamera(tilt = cameraState.tilt)
navigation = oldNavigation
}
},
toggleNavigation = {
navigation = !navigation
}
)
}
)
}
},
toggle3DViewClicked = {
scope.launch {
cameraState.tilt = if (cameraState.tilt > 0) {
0f
} else {
45f
}
val oldNavigation = navigation
navigation = false
delay(500)
cameraState.animateCamera(tilt = cameraState.tilt)
navigation = oldNavigation
}
},
toggleNavigation = {
navigation = !navigation
},
onZoomInClicked = {
scope.launch {
zoomValue++
cameraState.animateCamera(zoom = zoomValue)
}
},
onZoomOutClicked = {
scope.launch {
zoomValue--
cameraState.animateCamera(zoom = zoomValue)
}
}
)
}
)

}
}
Expand All @@ -204,7 +217,9 @@ fun MapSettings(
navigation: Boolean,
onCurrentLocationClicked: () -> Unit = {},
toggle3DViewClicked: () -> Unit = {},
toggleNavigation: () -> Unit = {}
toggleNavigation: () -> Unit = {},
onZoomInClicked: () -> Unit = {},
onZoomOutClicked: () -> Unit = {},
) {
Column(
modifier = Modifier.padding(16.dp),
Expand Down Expand Up @@ -267,6 +282,40 @@ fun MapSettings(
tint = Color.White
)
}
IconButton(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(Color.Blue),
onClick = onZoomInClicked
) {
Icon(
modifier = Modifier
.size(24.dp),
painter = painterResource(
Res.drawable.ic_zoom_in
),
contentDescription = "Zoom In",
tint = Color.White
)
}
IconButton(
modifier = Modifier
.size(48.dp)
.clip(CircleShape)
.background(Color.Blue),
onClick = onZoomOutClicked
) {
Icon(
modifier = Modifier
.size(24.dp),
painter = painterResource(
Res.drawable.ic_zoom_out
),
contentDescription = "Current Location",
tint = Color.White
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,25 @@ import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.maps.android.compose.CameraPositionState
import com.google.maps.android.compose.rememberCameraPositionState
import com.farimarwat.krossmap.model.KrossCoordinate

actual class KrossCameraPositionState(
internal val googleCameraPositionState: CameraPositionState?
) {

actual var tilt by mutableStateOf(0f)
actual var cameraFollow by mutableStateOf(true)

actual val center: KrossCoordinate?
get() {
val position = googleCameraPositionState?.position ?: return null
val target = position.target
return KrossCoordinate(
latitude = target.latitude,
longitude = target.longitude,
bearing = position.bearing
)
}
actual suspend fun animateCamera(
latitude: Double?,
longitude: Double?,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.farimarwat.krossmap.core

import androidx.compose.runtime.Composable
import com.farimarwat.krossmap.model.KrossCoordinate

/**
* A multiplatform representation of a map camera controller and its state.
Expand All @@ -25,6 +26,12 @@ expect class KrossCameraPositionState {
*/
var cameraFollow: Boolean

/**
* Current center of the visible map region (camera target), if available.
* Returns null if the underlying map view/state is not yet ready.
*/
val center: KrossCoordinate?

/**
* Animates the camera to the specified location and orientation.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,21 @@ actual class KrossCameraPositionState(

actual var tilt by mutableStateOf(0f)
private var mapView: MKMapView? = null
private var baseDistance: Double = 10000.0

actual var cameraFollow by mutableStateOf(false)

actual val center: KrossCoordinate?
@OptIn(ExperimentalForeignApi::class)
get() {
val currentCamera = mapView?.camera ?: camera
val coord = currentCamera.centerCoordinate ?: return null
val (lat, lng) = coord.useContents { this.latitude to this.longitude }
return KrossCoordinate(
latitude = lat,
longitude = lng,
bearing = currentCamera.heading.toFloat()
)
}

@OptIn(ExperimentalForeignApi::class)
actual suspend fun animateCamera(
latitude: Double?,
Expand All @@ -45,8 +56,7 @@ actual class KrossCameraPositionState(

val coordinate = CLLocationCoordinate2DMake(latitude ?: lat, longitude ?: lng)

// Always calculate distance from base distance, not current distance
val distance = zoom?.let { zoomToDistanceFromBase(it) } ?: currentCamera.centerCoordinateDistance
val distance = zoom?.let { zoomToDistance(it) } ?: currentCamera.centerCoordinateDistance

val newCamera = MKMapCamera.cameraLookingAtCenterCoordinate(
centerCoordinate = coordinate,
Expand All @@ -58,18 +68,11 @@ actual class KrossCameraPositionState(
mapView?.setCamera(newCamera, animated = true)
}

private fun zoomToDistanceFromBase(zoom: Float): Double {
// Calculate distance based on base distance, not current distance
// Adjust this formula based on your zoom scale
return baseDistance / (2.0.pow(zoom.toDouble() - 10.0)) // Assuming zoom 10 = base distance
}


@OptIn(ExperimentalForeignApi::class)
internal fun setMapView(map: MKMapView) {
mapView = map
mapView?.setCamera(camera)
baseDistance = mapView?.camera?.centerCoordinateDistance ?: 15000.0
}


Expand Down Expand Up @@ -103,6 +106,7 @@ actual fun rememberKrossCameraPositionState(
}
return state
}

fun zoomToDistance(zoom: Float): Double {
val baseDistance = when {
zoom >= 20 -> 200.0 // was 170.0
Expand Down