Skip to content

Commit

Permalink
Merge pull request #43 from Rallista/feat/compose-free-init-with-padding
Browse files Browse the repository at this point in the history
Feat: init with padding with static context to avoid @composable requirement
  • Loading branch information
Archdoog authored Sep 1, 2024
2 parents 24af174 + 465289b commit 544554e
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@ import android.view.Gravity
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import com.mapbox.mapboxsdk.geometry.LatLng
import com.maplibre.compose.MapView
import com.maplibre.compose.camera.MapViewCamera
import com.maplibre.compose.rememberSaveableMapViewCamera
import com.maplibre.compose.runtime.localLayoutDirection
import com.maplibre.compose.settings.AttributionSettings
import com.maplibre.compose.settings.CompassSettings
import com.maplibre.compose.settings.LogoSettings
import com.maplibre.compose.settings.MapControlPosition
import com.maplibre.compose.settings.MapControls
import com.maplibre.compose.settings.MarginInsets
import com.maplibre.compose.symbols.Polyline
import kotlinx.coroutines.delay

/**
* MapControls modify the UiSettings for controls on the map including the compass, logo, and
Expand All @@ -23,28 +31,64 @@ import com.maplibre.compose.settings.MarginInsets
@Composable
fun MapControlsExample() {

val density = LocalDensity.current
val layoutDirection = localLayoutDirection()

// Create an initial set of map controls
val initialMapControls =
MapControls(
attribution =
AttributionSettings.initWithPosition(
position = MapControlPosition.TopEnd(horizontal = 64.dp, vertical = 64.dp)),
compass =
// Using margins directly is possible, but it's better to use
// [MapControlPosition] as seen above in with AttributionSettings
CompassSettings(
fadeFacingNorth = false,
gravity = Gravity.START or Gravity.BOTTOM,
margins =
MarginInsets.createFromPadding(PaddingValues(start = 64.dp, bottom = 128.dp)),
),
logo = LogoSettings(enabled = false))

// Remember the map controls and color as mutable state to update them in the LaunchedEffect.
val mapControls = remember { mutableStateOf(initialMapControls) }
val color = remember { mutableStateOf("#000") }

// Dynamically update the map controls and polyline after a delay
LaunchedEffect(Unit) {
delay(2000)

mapControls.value =
MapControls(
attribution =
AttributionSettings.initWithLayoutAndPosition(
layoutDirection = layoutDirection,
density = density,
enabled = true,
position = MapControlPosition.TopCenter(vertical = 64.dp)),
compass = CompassSettings(enabled = false),
logo = LogoSettings(enabled = true))

color.value = "#fff"
}

val mapViewCamera =
rememberSaveableMapViewCamera(
initialCamera = MapViewCamera.Centered(latitude = -50.04, longitude = -73.71, zoom = 7.0))

val latLngs =
listOf(
LatLng(-50.20, -73.69),
LatLng(-50.10, -73.71),
LatLng(-50.00, -73.73),
)

MapView(
modifier = Modifier.fillMaxSize(),
styleUrl = "https://demotiles.maplibre.org/style.json",
camera = mapViewCamera,
mapControls =
MapControls(
attribution =
AttributionSettings.initWithPosition(
position = MapControlPosition.TopEnd(horizontal = 64.dp, vertical = 64.dp)),
compass =
// Using margins directly is possible, but it's better to use
// [MapControlPosition] as seen above in with AttributionSettings
CompassSettings(
fadeFacingNorth = false,
gravity = Gravity.START or Gravity.BOTTOM,
margins =
MarginInsets.createFromPadding(
PaddingValues(start = 64.dp, bottom = 128.dp)),
),
logo = LogoSettings(enabled = false)))
mapControls = mapControls.value) {
Polyline(points = latLngs, color = color.value, lineWidth = 12f)
}
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ plugins {
}

allprojects {
version = "0.0.17"
version = "0.0.18"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.maplibre.compose.runtime

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.LayoutDirection

/**
* Get the layout direction of the screen as a [LayoutDirection].
*
* @return The current layout direction of the screen.
*/
@Composable
fun localLayoutDirection(): LayoutDirection {
val direction = LocalConfiguration.current.layoutDirection
return LayoutDirection.entries[direction]
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package com.maplibre.compose.settings

import android.os.Parcelable
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import com.maplibre.compose.runtime.localLayoutDirection
import kotlinx.parcelize.Parcelize

/**
Expand All @@ -22,12 +26,45 @@ data class AttributionSettings(
) : Parcelable {

companion object {

/**
* Configure the attribution view.
*
* @param enabled Whether the attribution view is enabled.
* @param position The position of the attribution view.
* @param tintColor The tint color of the attribution view.
* @return The attribution settings.
*/
@Composable
fun initWithPosition(
enabled: Boolean? = null,
position: MapControlPosition = MapControlPosition.TopStart(),
tintColor: Int? = null
): AttributionSettings =
AttributionSettings(enabled, position.asGravity(), position.asMarginInsets(), tintColor)
initWithLayoutAndPosition(
localLayoutDirection(), LocalDensity.current, enabled, position, tintColor)

/**
* Configure the attribution view.
*
* @param layoutDirection The layout direction of the screen.
* @param density The layout density (e.g. [LocalDensity.current]).
* @param enabled Whether the attribution view is enabled.
* @param position The position of the attribution view.
* @param tintColor The tint color of the attribution view.
* @return The attribution settings.
*/
fun initWithLayoutAndPosition(
layoutDirection: LayoutDirection,
density: Density,
enabled: Boolean? = null,
position: MapControlPosition = MapControlPosition.TopStart(),
tintColor: Int? = null
): AttributionSettings =
AttributionSettings(
enabled,
position.asGravity(),
position.asMarginInsets(layoutDirection, density),
tintColor)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package com.maplibre.compose.settings

import android.os.Parcelable
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import com.maplibre.compose.runtime.localLayoutDirection
import kotlinx.parcelize.Parcelize

/**
Expand Down Expand Up @@ -36,6 +40,30 @@ data class CompassSettings(
isFacingNorth: Boolean? = null,
position: MapControlPosition = MapControlPosition.TopStart()
): CompassSettings =
CompassSettings(enabled, isFacingNorth, position.asGravity(), position.asMarginInsets())
initWithLayoutAndPosition(
localLayoutDirection(), LocalDensity.current, enabled, isFacingNorth, position)

/**
* Configure the compass.
*
* @param layoutDirection The layout direction of the screen.
* @param density The layout density (e.g. [LocalDensity.current]).
* @param enabled Whether the compass is enabled.
* @param isFacingNorth
* @param position The position of the compass.
* @return The compass settings.
*/
fun initWithLayoutAndPosition(
layoutDirection: LayoutDirection,
density: Density,
enabled: Boolean? = null,
isFacingNorth: Boolean? = null,
position: MapControlPosition = MapControlPosition.TopStart()
): CompassSettings =
CompassSettings(
enabled,
isFacingNorth,
position.asGravity(),
position.asMarginInsets(layoutDirection, density))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package com.maplibre.compose.settings

import android.os.Parcelable
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.LayoutDirection
import com.maplibre.compose.runtime.localLayoutDirection
import kotlinx.parcelize.Parcelize

/**
Expand Down Expand Up @@ -33,6 +37,28 @@ data class LogoSettings(
fun initWithPosition(
enabled: Boolean? = null,
position: MapControlPosition = MapControlPosition.TopStart()
): LogoSettings = LogoSettings(enabled, position.asGravity(), position.asMarginInsets())
): LogoSettings =
LogoSettings(
enabled,
position.asGravity(),
position.asMarginInsets(localLayoutDirection(), LocalDensity.current))

/**
* Configure the logo.
*
* @param layoutDirection The layout direction of the logo.
* @param density The density of the logo.
* @param enabled Whether the logo is enabled.
* @param position The position of the logo.
* @return The logo settings.
*/
fun initWithLayoutAndPosition(
layoutDirection: LayoutDirection,
density: Density,
enabled: Boolean? = null,
position: MapControlPosition = MapControlPosition.TopStart()
): LogoSettings =
LogoSettings(
enabled, position.asGravity(), position.asMarginInsets(layoutDirection, density))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import com.maplibre.compose.runtime.localLayoutDirection
import kotlinx.parcelize.Parcelize

sealed class MapControlPosition(open val horizontal: Dp = 0.dp, open val vertical: Dp = 0.dp) {
Expand Down Expand Up @@ -100,9 +101,10 @@ sealed class MapControlPosition(open val horizontal: Dp = 0.dp, open val vertica
}
}

@Composable
internal fun asMarginInsets(): MarginInsets {
return MarginInsets.createFromPadding(
internal fun asMarginInsets(layoutDirection: LayoutDirection, density: Density): MarginInsets {
return MarginInsets.createFromLayoutAndPadding(
layoutDirection = layoutDirection,
density = density,
padding =
PaddingValues(start = horizontal, top = vertical, end = horizontal, bottom = vertical))
}
Expand Down Expand Up @@ -139,11 +141,27 @@ data class MarginInsets(
*/
@Composable
fun createFromPadding(padding: PaddingValues): MarginInsets {
val rawLayoutDirection = LocalConfiguration.current.layoutDirection
val layoutDirection: LayoutDirection = LayoutDirection.entries[rawLayoutDirection]

val density = LocalDensity.current
return createFromLayoutAndPadding(
layoutDirection = localLayoutDirection(),
density = LocalDensity.current,
padding = padding)
}

/**
* Manually position the control on the map using dp padding, a layout direction, and a density.
*
* To more easily position the control on a map use the control's `initWithPosition` and
* [MapControlPosition] as it safely handles the nuances of map control positioning.
*
* @param layoutDirection The layout direction to use
* @param density The screen density to use (e.g. LocalDensity.current).
* @param padding The padding values to use.
*/
fun createFromLayoutAndPadding(
layoutDirection: LayoutDirection,
density: Density,
padding: PaddingValues
): MarginInsets {
val start = padding.calculateStartPadding(layoutDirection)
val top = padding.calculateTopPadding()
val end = padding.calculateEndPadding(layoutDirection)
Expand Down

0 comments on commit 544554e

Please sign in to comment.