Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed crash when style is not fully loaded #265

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
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
Expand Up @@ -18,6 +18,8 @@ import org.maplibre.android.style.sources.VectorSource as MLNVectorSource
internal class AndroidStyle(style: MLNStyle) : Style {
private var impl: MLNStyle = style

override var isLoaded: Boolean = true

override fun addImage(id: String, image: ImageBitmap, sdf: Boolean) {
impl.addImage(id, image.asAndroidBitmap(), sdf)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public fun MaplibreMap(
object : MaplibreMap.Callbacks {
override fun onStyleChanged(map: MaplibreMap, style: Style?) {
map as StandardMaplibreMap

if (style == null) rememberedStyle?.isLoaded = false

styleState.attach(style)
rememberedStyle = style
cameraState.metersPerDpAtTargetState.value =
Expand All @@ -133,6 +136,8 @@ public fun MaplibreMap(
override fun onCameraMoveEnded(map: MaplibreMap) {}

private fun layerNodesInOrder(): List<LayerNode<*>> {
if (styleComposition?.style?.isLoaded != true) return emptyList()

val layerNodes =
(styleComposition?.children?.filterIsInstance<LayerNode<*>>() ?: emptyList())
.associateBy { node -> node.layer.id }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,26 @@ public class StyleState internal constructor() {

public fun queryAttributionLinks(): List<AttributionLink> {
// TODO expose this as State somehow?
return style?.getSources()?.flatMap { it.attributionLinks } ?: emptyList()
return getStyleIfLoaded()?.getSources()?.flatMap { it.attributionLinks } ?: emptyList()
}

/**
* Retrieves all sources from the style.
*
* @return A list of sources, or an empty list if the style is null or has no sources.
* @return A list of sources, or an empty list if the style is not fully loaded or has no sources.
*/
public fun getSources(): List<Source> = style?.getSources() ?: emptyList()
public fun getSources(): List<Source> = getStyleIfLoaded()?.getSources() ?: emptyList()

/**
* Retrieves a source by its [id].
*
* @param id The ID of the source to retrieve.
* @return The source with the specified ID, or null if no such source exists.
* @return The source with the specified ID, or null if no such source exists, or the style is not
* fully loaded.
*/
public fun getSource(id: String): Source? = style?.getSource(id)
public fun getSource(id: String): Source? = getStyleIfLoaded()?.getSource(id)

private fun getStyleIfLoaded(): Style? {
return if (style?.isLoaded == true) style else null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ internal class ImageManager(private val node: StyleNode) {
private val painterBitmaps = mutableMapOf<PainterKey, ImageBitmap>()

internal fun acquireBitmap(key: BitmapKey): String {
if (!node.style.isLoaded) return ""

bitmapCounter.increment(key) {
val id = bitmapIds.addId(key)
node.logger?.i { "Adding bitmap $id" }
Expand All @@ -29,6 +31,8 @@ internal class ImageManager(private val node: StyleNode) {
}

internal fun releaseBitmap(key: BitmapKey) {
if (!node.style.isLoaded) return

bitmapCounter.decrement(key) {
val id = bitmapIds.removeId(key)
node.logger?.i { "Removing bitmap $id" }
Expand All @@ -50,6 +54,8 @@ internal class ImageManager(private val node: StyleNode) {
}

internal fun acquirePainter(key: PainterKey): String {
if (!node.style.isLoaded) return ""

painterCounter.increment(key) {
val id = painterIds.addId(key)
node.logger?.i { "Adding painter $id" }
Expand All @@ -62,6 +68,8 @@ internal class ImageManager(private val node: StyleNode) {
}

internal fun releasePainter(key: PainterKey) {
if (!node.style.isLoaded) return

painterCounter.decrement(key) {
val id = painterIds.removeId(key)
node.logger?.i { "Removing painter $id" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import dev.sargunv.maplibrecompose.compose.layer.Anchor
import dev.sargunv.maplibrecompose.core.layer.Layer

internal class LayerManager(private val styleNode: StyleNode) {
private val baseLayers = styleNode.style.getLayers().associateBy { it.id }
private val baseLayers = getLayers().associateBy { it.id }

private val userLayers = mutableListOf<LayerNode<*>>()

Expand All @@ -13,6 +13,8 @@ internal class LayerManager(private val styleNode: StyleNode) {
private val replacementCounters = mutableMapOf<Anchor.Replace, Int>()

internal fun addLayer(node: LayerNode<*>, index: Int) {
if (!styleNode.style.isLoaded) return

require(node.layer.id !in baseLayers) {
"Layer ID '${node.layer.id}' already exists in base style"
}
Expand All @@ -24,6 +26,8 @@ internal class LayerManager(private val styleNode: StyleNode) {
}

internal fun removeLayer(node: LayerNode<*>, oldIndex: Int) {
if (!styleNode.style.isLoaded) return

userLayers.removeAt(oldIndex)

// special handling for Replace anchors
Expand Down Expand Up @@ -52,6 +56,8 @@ internal class LayerManager(private val styleNode: StyleNode) {
}

internal fun applyChanges() {
if (!styleNode.style.isLoaded) return

val tailLayerIds = mutableMapOf<Anchor, String>()
val missedLayers = mutableMapOf<Anchor, MutableList<LayerNode<*>>>()

Expand Down Expand Up @@ -132,4 +138,7 @@ internal class LayerManager(private val styleNode: StyleNode) {
is Anchor.Replace -> layerId
else -> null
}

private fun getLayers() =
if (styleNode.style.isLoaded) styleNode.style.getLayers() else emptyList()
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import dev.sargunv.maplibrecompose.core.source.Source

internal class SourceManager(private val node: StyleNode) {

private val baseSources = node.style.getSources().associateBy { it.id }
private val baseSources = getSources().associateBy { it.id }
private val sourcesToAdd = mutableListOf<Source>()
private val counter = ReferenceCounter<Source>()

Expand All @@ -13,6 +13,8 @@ internal class SourceManager(private val node: StyleNode) {
}

internal fun addReference(source: Source) {
if (!node.style.isLoaded) return

require(source.id !in baseSources) { "Source ID '${source.id}' already exists in base style" }
counter.increment(source) {
node.logger?.i { "Queuing source ${source.id} for addition" }
Expand All @@ -21,6 +23,8 @@ internal class SourceManager(private val node: StyleNode) {
}

internal fun removeReference(source: Source) {
if (!node.style.isLoaded) return

require(source.id !in baseSources) {
"Source ID '${source.id}' is part of the base style and can't be removed here"
}
Expand All @@ -31,11 +35,15 @@ internal class SourceManager(private val node: StyleNode) {
}

internal fun applyChanges() {
if (!node.style.isLoaded) return

sourcesToAdd
.onEach {
node.logger?.i { "Adding source ${it.id}" }
node.style.addSource(it)
}
.clear()
}

private fun getSources() = if (node.style.isLoaded) node.style.getSources() else emptyList()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,53 @@ import dev.sargunv.maplibrecompose.core.layer.Layer
import dev.sargunv.maplibrecompose.core.source.Source

internal interface Style {
/**
* Returns true if the style is loaded. Returns false if a new style is underway of being loaded.
*/
var isLoaded: Boolean

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun addImage(id: String, image: ImageBitmap, sdf: Boolean)

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun removeImage(id: String)

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun getSource(id: String): Source?

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun getSources(): List<Source>

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun addSource(source: Source)

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun removeSource(source: Source)

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun getLayer(id: String): Layer?

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun getLayers(): List<Layer>

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun addLayer(layer: Layer)

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun addLayerAbove(id: String, layer: Layer)

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun addLayerBelow(id: String, layer: Layer)

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun addLayerAt(index: Int, layer: Layer)

/** @throws IllegalStateException on Android if [isLoaded] is false. */
fun removeLayer(layer: Layer)

object Null : Style {
override var isLoaded: Boolean = false

override fun addImage(id: String, image: ImageBitmap, sdf: Boolean) {}

override fun removeImage(id: String) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ internal class FakeStyle(
private val layerList = layers.toMutableList()
private val layerMap = layers.associateBy { it.id }.toMutableMap()

override var isLoaded: Boolean = true

override fun addImage(id: String, image: ImageBitmap, sdf: Boolean) {
if (id in imageMap) error("Image ID '${id}' already exists in style")
imageMap[id] = image
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import dev.sargunv.maplibrecompose.core.util.toUIImage
internal class IosStyle(style: MLNStyle, private val getScale: () -> Float) : Style {
private var impl: MLNStyle = style

override var isLoaded: Boolean = true

override fun addImage(id: String, image: ImageBitmap, sdf: Boolean) {
impl.setImage(image.toUIImage(getScale(), sdf), forName = id)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import dev.sargunv.maplibrejs.Map as MlJsMap

internal class JsStyle(internal val impl: MlJsMap) : Style {

override var isLoaded: Boolean = true

override fun addImage(id: String, image: ImageBitmap, sdf: Boolean) {}

override fun removeImage(id: String) {}
Expand Down