Skip to content

Commit

Permalink
[compose] Use Slot content DSL for GenericStyle instead of generic Ha…
Browse files Browse the repository at this point in the history
…shMaps (#2388)


---------

Co-authored-by: Peng Liu <[email protected]>
  • Loading branch information
jush and pengdev authored Apr 26, 2024
1 parent 7d24f33 commit e276ad5
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Mapbox welcomes participation and contributions from everyone.
* [compose] Remove `TileCacheBudget(com.mapbox.maps.TileCacheBudget)` constructor and introduce `TileCacheBudget(TileCacheBudgetInMegabytes)` and `TileCacheBudget(TileCacheBudgetInTiles)` constructor instead.
* [compose] Remove `layoutParams` from `ViewAnnotation` composable function, the internal `ComposeView` wrapping the `ViewAnnotation.content` will always use `WRAP_CONTENT`; In case of tests where the assertion happens before the measure, user can force the content size using `ViewAnnotationOptions.width/height` APIs.
* [compose] Constructor in `PromoteId` data class from compose now takes `PropertyName` and optional `SourceId` instead of itself.
* [compose] Use new `SlotsContent` instead of generic `Map` to handle the style content for slots. Introduced `slotsContent` builder function.

## Features ✨ and improvements 🏁
* [compose] Add `AtmosphereState` parameter to `GenericStyle` composable function.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import com.mapbox.maps.extension.compose.style.layers.generated.TextColor
import com.mapbox.maps.extension.compose.style.layers.generated.TextField
import com.mapbox.maps.extension.compose.style.layers.generated.TextSize
import com.mapbox.maps.extension.compose.style.layers.generated.Transition
import com.mapbox.maps.extension.compose.style.slotsContent
import com.mapbox.maps.extension.compose.style.sources.generated.GeoJSONData
import com.mapbox.maps.extension.compose.style.sources.generated.rememberGeoJsonSourceState
import com.mapbox.maps.extension.style.expressions.generated.Expression
Expand All @@ -67,6 +68,10 @@ public class StyleCompositionActivity : ComponentActivity() {
mutableStateOf(Style.LIGHT)
}

var showBackground by remember {
mutableStateOf(true)
}

var centerLocation by rememberSaveable {
mutableStateOf(CityLocations.HELSINKI)
}
Expand Down Expand Up @@ -141,6 +146,15 @@ public class StyleCompositionActivity : ComponentActivity() {
) {
Text(modifier = Modifier.padding(10.dp), text = "Toggle Style")
}
FloatingActionButton(
modifier = Modifier.padding(bottom = 10.dp),
onClick = {
showBackground = !showBackground
},
shape = RoundedCornerShape(16.dp),
) {
Text(modifier = Modifier.padding(10.dp), text = "Toggle BG Layer")
}
}
}
) {
Expand All @@ -150,27 +164,37 @@ public class StyleCompositionActivity : ComponentActivity() {
style = {
GenericStyle(
style = styleUri,
slots = mapOf(
"top" to {
// Only add background layer in top slot for standard style, where the top slot
// is available.
if (styleUri == Style.STANDARD) {
slots = slotsContent {
if (styleUri == Style.STANDARD) {
if (showBackground) {
slot("top") {
// Only add background layer in top slot for standard style, where the top slot
// is available.
BackgroundLayer(
backgroundColor = BackgroundColor(Color.Yellow),
backgroundOpacity = BackgroundOpacity(0.3)
)
}
}
slot("middle") {
BackgroundLayer(
backgroundColor = BackgroundColor(Color.Yellow),
backgroundColor = BackgroundColor(Color.Red),
backgroundOpacity = BackgroundOpacity(0.3)
)
}
}
),
},
layerPositions = mapOf(
LayerPosition(null, "building", null) to {
// only add background layer below building layer if the style is not standard
// style, where layers are available in runtime styling.
if (styleUri != Style.STANDARD) {
BackgroundLayer(
backgroundColor = BackgroundColor(Color.Red),
backgroundOpacity = BackgroundOpacity(0.3)
)
if (showBackground) {
BackgroundLayer(
backgroundColor = BackgroundColor(Color.Red),
backgroundOpacity = BackgroundOpacity(0.3)
)
}
}
}
),
Expand Down
8 changes: 7 additions & 1 deletion extension-compose/api/Release/metalava.txt
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,16 @@ package com.mapbox.maps.extension.compose.style {
@androidx.compose.runtime.ComposableTargetMarker(description="Mapbox Style Composable") @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget.FILE, kotlin.annotation.AnnotationTarget.FUNCTION, kotlin.annotation.AnnotationTarget.PROPERTY_GETTER, kotlin.annotation.AnnotationTarget.TYPE, kotlin.annotation.AnnotationTarget.TYPE_PARAMETER}) public @interface MapboxStyleComposable {
}

@androidx.compose.runtime.Stable @com.mapbox.maps.MapboxExperimental public final class SlotsContent {
method public com.mapbox.maps.extension.compose.style.SlotsContent copy(java.util.Map<java.lang.String,kotlin.jvm.functions.Function0<kotlin.Unit>> entries);
method public void slot(String name, kotlin.jvm.functions.Function0<kotlin.Unit> content);
}

public final class StyleKt {
method @androidx.compose.runtime.Composable @com.mapbox.maps.MapboxExperimental @com.mapbox.maps.extension.compose.style.MapboxStyleComposable public static void GenericStyle(String style, java.util.Map<java.lang.String,? extends kotlin.jvm.functions.Function0<kotlin.Unit>> slots = emptyMap(), java.util.Map<com.mapbox.maps.LayerPosition,? extends kotlin.jvm.functions.Function0<kotlin.Unit>> layerPositions = emptyMap(), java.util.Map<java.lang.String,? extends java.util.Map<java.lang.String,? extends com.mapbox.bindgen.Value>> configs = emptyMap(), com.mapbox.maps.extension.compose.style.projection.Projection projection = Projection.default, com.mapbox.maps.extension.compose.style.atmosphere.generated.AtmosphereState atmosphereState = AtmosphereState.default);
method @androidx.compose.runtime.Composable @com.mapbox.maps.MapboxExperimental @com.mapbox.maps.extension.compose.style.MapboxStyleComposable public static void GenericStyle(String style, com.mapbox.maps.extension.compose.style.SlotsContent slots = com.mapbox.maps.extension.compose.style.SlotsContent(), java.util.Map<com.mapbox.maps.LayerPosition,? extends kotlin.jvm.functions.Function0<kotlin.Unit>> layerPositions = emptyMap(), java.util.Map<java.lang.String,? extends java.util.Map<java.lang.String,? extends com.mapbox.bindgen.Value>> configs = emptyMap(), com.mapbox.maps.extension.compose.style.projection.Projection projection = Projection.default, com.mapbox.maps.extension.compose.style.atmosphere.generated.AtmosphereState atmosphereState = AtmosphereState.default);
method @androidx.compose.runtime.Composable @com.mapbox.maps.MapboxExperimental @com.mapbox.maps.extension.compose.style.MapboxStyleComposable public static void MapStyle(String style);
method @androidx.compose.runtime.Composable @com.mapbox.maps.MapboxExperimental @com.mapbox.maps.extension.compose.style.MapboxStyleComposable public static void MapboxStandardStyle(kotlin.jvm.functions.Function0<kotlin.Unit>? topSlot = null, kotlin.jvm.functions.Function0<kotlin.Unit>? middleSlot = null, kotlin.jvm.functions.Function0<kotlin.Unit>? bottomSlot = null, com.mapbox.bindgen.Value lightPreset = Value.nullValue());
method @com.mapbox.maps.MapboxExperimental public static com.mapbox.maps.extension.compose.style.SlotsContent slotsContent(kotlin.jvm.functions.Function1<? super com.mapbox.maps.extension.compose.style.SlotsContent,kotlin.Unit> init);
}

}
Expand Down
13 changes: 12 additions & 1 deletion extension-compose/api/extension-compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,21 @@ public final class com/mapbox/maps/extension/compose/style/IdGenerator {
public abstract interface annotation class com/mapbox/maps/extension/compose/style/MapboxStyleComposable : java/lang/annotation/Annotation {
}

public final class com/mapbox/maps/extension/compose/style/SlotsContent {
public fun <init> ()V
public final fun copy (Ljava/util/Map;)Lcom/mapbox/maps/extension/compose/style/SlotsContent;
public static synthetic fun copy$default (Lcom/mapbox/maps/extension/compose/style/SlotsContent;Ljava/util/Map;ILjava/lang/Object;)Lcom/mapbox/maps/extension/compose/style/SlotsContent;
public fun equals (Ljava/lang/Object;)Z
public fun hashCode ()I
public final fun slot (Ljava/lang/String;Lkotlin/jvm/functions/Function2;)V
public fun toString ()Ljava/lang/String;
}

public final class com/mapbox/maps/extension/compose/style/StyleKt {
public static final fun GenericStyle (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;Ljava/util/Map;Lcom/mapbox/maps/extension/compose/style/projection/Projection;Lcom/mapbox/maps/extension/compose/style/atmosphere/generated/AtmosphereState;Landroidx/compose/runtime/Composer;II)V
public static final fun GenericStyle (Ljava/lang/String;Lcom/mapbox/maps/extension/compose/style/SlotsContent;Ljava/util/Map;Ljava/util/Map;Lcom/mapbox/maps/extension/compose/style/projection/Projection;Lcom/mapbox/maps/extension/compose/style/atmosphere/generated/AtmosphereState;Landroidx/compose/runtime/Composer;II)V
public static final fun MapStyle (Ljava/lang/String;Landroidx/compose/runtime/Composer;I)V
public static final fun MapboxStandardStyle (Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lcom/mapbox/bindgen/Value;Landroidx/compose/runtime/Composer;II)V
public static final fun slotsContent (Lkotlin/jvm/functions/Function1;)Lcom/mapbox/maps/extension/compose/style/SlotsContent;
}

public final class com/mapbox/maps/extension/compose/style/atmosphere/generated/AtmosphereState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.mapbox.maps.extension.compose.style

import androidx.compose.runtime.Composable
import androidx.compose.runtime.ComposeNode
import androidx.compose.runtime.Stable
import androidx.compose.runtime.currentComposer
import androidx.compose.runtime.key
import com.mapbox.bindgen.Value
Expand Down Expand Up @@ -37,11 +38,11 @@ public fun MapboxStandardStyle(
) {
GenericStyle(
style = Style.STANDARD,
slots = mapOf(
"top" to topSlot,
"middle" to middleSlot,
"bottom" to bottomSlot,
),
slots = slotsContent {
topSlot?.let { slot("top", it) }
middleSlot?.let { slot("middle", it) }
bottomSlot?.let { slot("bottom", it) }
},
configs = mapOf(
"basemap" to mapOf(
"lightPreset" to lightPreset
Expand All @@ -62,6 +63,36 @@ public fun MapStyle(style: String) {
GenericStyle(style = style)
}

/**
* Class that holds [MapboxMapComposable] content per each slot.
*/
@Stable
@MapboxExperimental
public data class SlotsContent internal constructor(
internal val entries: MutableMap<String, @Composable @MapboxMapComposable (() -> Unit)> = mutableMapOf()
) {
/**
* Assign a new [MapboxMapComposable] [content] to the given slot [name].
*
* @param name The name of the slot.
* @param content a [MapboxMapComposable] to be applied to the slot.
*
* @throws IllegalArgumentException if [name] slot already has [content].
*/
public fun slot(name: String, content: @Composable @MapboxMapComposable (() -> Unit)) {
if (entries.containsKey(name)) {
throw IllegalArgumentException("Slot [$name] already has content.")
}
entries[name] = content
}
}

/**
* Type-safe builder for slot based [MapboxMapComposable] content.
*/
@MapboxExperimental
public fun slotsContent(init: SlotsContent.() -> Unit): SlotsContent = SlotsContent().apply(init)

/**
* Generic Style that you can insert [MapboxMapComposable] functions in any slot you defined as a
* plain string, or set any map import configs given as plain string and [Value] pairs.
Expand All @@ -72,7 +103,7 @@ public fun MapStyle(style: String) {
* Always prefer strongly typed [MapboxStyleComposable] over the [GenericStyle].
*
* @param style The Style JSON or Style Uri to be set to the map.
* @param slots The slot name and [MapboxStyleComposable] pairs that would be inserted to the corresponding slots in the style.
* @param slots The slots and their [MapboxMapComposable] that would be inserted to the corresponding slots in the style. You can use [slotsContent] to create it.
* @param configs The map of importId and the config name/value pairs that would be applied to the style as style import configs.
* @param projection The projection to be set to the map. Defaults to [Projection.default] meaning that projection value is taken from the [style] definition.
*/
Expand All @@ -81,7 +112,7 @@ public fun MapStyle(style: String) {
@MapboxExperimental
public fun GenericStyle(
style: String,
slots: Map<String, (@Composable @MapboxMapComposable () -> Unit)?> = emptyMap(),
slots: SlotsContent = SlotsContent(),
layerPositions: Map<LayerPosition, (@Composable @MapboxMapComposable () -> Unit)?> = emptyMap(),
configs: Map<String, Map<String, Value>> = emptyMap(),
projection: Projection = Projection.default,
Expand Down Expand Up @@ -111,7 +142,7 @@ public fun GenericStyle(
}
}
) {
slots.entries.filter { it.value != null }.forEach {
slots.entries.forEach {
key(it.key) {
StyleSlot(name = it.key, content = it.value)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ internal fun StyleSlot(
factory = {
StyleSlotNode(name)
},
update = { }
update = {}
) {
content?.invoke()
}
Expand Down

0 comments on commit e276ad5

Please sign in to comment.