Skip to content
Merged
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 @@ -44,6 +44,8 @@ import com.flipcash.app.bills.components.cards.LocalTipCardBackdrop
import com.flipcash.app.bills.components.cards.LocalTipCardBaseAlpha
import com.flipcash.app.bills.components.cards.LocalTipCardColor
import com.flipcash.app.bills.components.cards.TipCardOpaqueFallback
import com.flipcash.app.featureflags.FeatureFlag
import com.flipcash.app.featureflags.LocalFeatureFlags
import com.flipcash.app.core.android.extensions.launchAppSettings
import com.flipcash.app.core.bill.Scannable
import com.flipcash.app.core.tipping.LocalTipCoordinator
Expand Down Expand Up @@ -128,10 +130,15 @@ internal fun ScannableContainer(
// The frosted camera backdrop snapshots the feed (a GPU→CPU readback). Gate it to devices that
// can absorb that — API 31+ for the blur, and not low-RAM. Everywhere else the card falls back
// to an opaque approximation of the frosted tone.
val supportsFrostedTipCard = remember {
val deviceSupportsFrostedTipCard = remember {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
context.getSystemService(ActivityManager::class.java)?.isLowRamDevice != true
}
// Also gated behind a beta flag (off by default); the opaque fallback is used when it's disabled.
val frostedTipCardFlagEnabled by LocalFeatureFlags.current
.observe(FeatureFlag.FrostedTipCard)
.collectAsStateWithLifecycle()
val frostedTipCardEnabled = deviceSupportsFrostedTipCard && frostedTipCardFlagEnabled

OnLifecycleEvent { _, event ->
if (event == Lifecycle.Event.ON_STOP && !autoStart) {
Expand Down Expand Up @@ -292,18 +299,19 @@ internal fun ScannableContainer(
val isTipCard = updatedBillState.bill is Scannable.TipCard
val tipCardBackdrop = rememberCameraTipCardBackdrop(
previewView = previewView,
enabled = isTipCard && supportsFrostedTipCard,
enabled = isTipCard && frostedTipCardEnabled,
containerOriginInWindow = containerOriginInWindow,
)

// Where the frosted backdrop is unavailable, render the tip card as an opaque approximation
// of the frosted tone instead of a translucent panel over the (stutter-prone) live camera.
val useOpaqueFallback = isTipCard && !supportsFrostedTipCard
// Where the frosted backdrop is unavailable (incapable device or the beta flag is off),
// render the tip card as an opaque approximation of the frosted tone instead of a
// translucent panel over the (stutter-prone) live camera.
val useOpaqueFallback = isTipCard && !frostedTipCardEnabled

CompositionLocalProvider(
LocalTipCardBackdrop provides tipCardBackdrop,
LocalTipCardColor provides if (useOpaqueFallback) TipCardOpaqueFallback else Color.Unspecified,
LocalTipCardBaseAlpha provides if (useOpaqueFallback) 1f else LocalTipCardBaseAlpha.current,
LocalTipCardBaseAlpha provides if (useOpaqueFallback) 1f else 0.45f,
) {
AnimatedScannable(
modifier = Modifier.fillMaxSize(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ val LocalTipCardBackdrop = staticCompositionLocalOf<(@Composable BoxScope.() ->


/** Blur radius used for the card's backdrop, tuned to read like the design's 40px background blur. */
val TipCardBlurRadius: Dp = 24.dp
val TipCardBlurRadius: Dp = 16.dp

/**
* Base tint color for the card. Defaults to the theme's tip-card color; overridden on the opaque
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,16 @@ sealed interface FeatureFlag<T: Any> {
override val minTrack: FeatureTrack = FeatureTrack.Production
}

@FeatureFlagMarker
data object FrostedTipCard: FeatureFlag<Boolean> {
override val key: String = "frosted_tip_card_enabled"
override val default: Boolean = false
override val launched: Boolean = false
override val visible: Boolean = true
override val persistLogOut: Boolean = false
override val minTrack: FeatureTrack = FeatureTrack.Beta
}

companion object {
val entries: List<FeatureFlag<*>>
get() = FeatureFlagEntries.entries
Expand Down Expand Up @@ -305,6 +315,7 @@ val FeatureFlag<*>.title: String
FeatureFlag.AddMoneyUX -> "Add Money UX"
FeatureFlag.ShowNetworkState -> "Network Offline Indicator"
FeatureFlag.Tipping -> "Tipping"
FeatureFlag.FrostedTipCard -> "Frosted Tip Card"
}

val FeatureFlag<*>.message: String
Expand Down Expand Up @@ -334,6 +345,7 @@ val FeatureFlag<*>.message: String
FeatureFlag.AddMoneyUX -> "When enabled, the user experience for getting money into the app will be focused around 'Adding Money'"
FeatureFlag.ShowNetworkState -> "When enabled, you'll gain the ability to see the network state on the Scanner when offline"
FeatureFlag.Tipping -> "When enabled, you'll gain the ability to tip other users and set up your own tip card to receive tips"
FeatureFlag.FrostedTipCard -> "When enabled, the tip card in the scanner renders as frosted glass over a blurred snapshot of the camera instead of a solid card"
}


Expand Down
Loading