package com.swmansion.rnscreens.gamma.tabs.screen import android.content.Context import android.graphics.drawable.Drawable import com.swmansion.rnscreens.gamma.helpers.IconResolution import com.swmansion.rnscreens.gamma.helpers.NoTintDrawable import com.swmansion.rnscreens.gamma.helpers.PropIconResolver import kotlin.properties.Delegates /** * Single icon slot (normal or selected) of a tab bar item. Props stage here and may arrive * in any order within a single update batch; resolution runs once per transaction via * [resolveIfNeeded]. [onChanged] fires only when the resolved [drawable] actually changes. */ internal class TabsScreenIcon( private val context: Context, private val onChanged: () -> Unit, ) { var drawableResourceName: String? by Delegates.observable(null) { _, oldValue, newValue -> if (newValue != oldValue) isInvalidated = true } var tinting: TabsScreenIconTinting by Delegates.observable( TabsScreenIconTinting.DEFAULT, ) { _, oldValue, newValue -> if (newValue != oldValue) isInvalidated = true } var imageUri: String? by Delegates.observable(null) { _, oldValue, newValue -> if (newValue != oldValue) isInvalidated = true } // Resolved output; read by the appearance applicator. var drawable: Drawable? = null private set private var isInvalidated = false // Handles source precedence (drawable name wins over uri), dedup, and stale async image drops. private val resolver = PropIconResolver() // Kept unwrapped so a tint-only change re-wraps without reloading. private var rawDrawable: Drawable? = null private var appliedTinting = TabsScreenIconTinting.DEFAULT fun resolveIfNeeded() { if (!isInvalidated) { return } isInvalidated = false resolver.resolve(context, drawableResourceName, imageUri) { result -> when (result) { IconResolution.Unchanged -> if (tinting != appliedTinting) emit() is IconResolution.Resolved -> { rawDrawable = result.drawable emit() } } } } // Tint is read at emit time, so a toggle during an in-flight image load still applies. private fun emit() { appliedTinting = tinting val next = rawDrawable?.let { if (tinting == TabsScreenIconTinting.ORIGINAL) NoTintDrawable(it) else it } if (next !== drawable) { drawable = next onChanged() } } }