Skip to content

Instantly share code, notes, and snippets.

@tasyamalia
Last active January 5, 2026 16:38
Show Gist options
  • Select an option

  • Save tasyamalia/dda450ad2abea27e5be76f7049348b50 to your computer and use it in GitHub Desktop.

Select an option

Save tasyamalia/dda450ad2abea27e5be76f7049348b50 to your computer and use it in GitHub Desktop.
Lumen - a lamp inspired brightness UI built with Jetpack Compose. Focus on glow, animation, and responsive layout behavior.
/*
* Lumen UI
* Jetpack Compose UI experiment
*
* Created by Tasya Amalia Salsabila, 2026
*/
import android.app.Activity
import android.view.WindowManager
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.blur
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Devices
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.min
@Composable
fun LumenScreen(
modifier: Modifier = Modifier,
isLandscape: Boolean,
isPreview: Boolean = false
) {
val context = LocalContext.current
val activity = context as? Activity
var brightness by rememberSaveable { mutableFloatStateOf(0.4f) }
var temperature by rememberSaveable { mutableFloatStateOf(0.3f) }
if (!isPreview && activity != null) {
DisposableEffect(brightness) {
val params = activity.window.attributes
params.screenBrightness = brightness.coerceIn(0.05f, 1f)
activity.window.attributes = params
onDispose {
val restore = activity.window.attributes
restore.screenBrightness =
WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE
activity.window.attributes = restore
}
}
}
val flicker by rememberInfiniteTransition(label = "flicker")
.animateFloat(
initialValue = 0.97f,
targetValue = 1.03f,
animationSpec = infiniteRepeatable(
tween(1400, easing = LinearEasing),
RepeatMode.Reverse
),
label = "flickerAnim"
)
val animatedBrightness by animateFloatAsState(
targetValue = brightness,
animationSpec = tween(400, easing = FastOutSlowInEasing),
label = "brightnessAnim"
)
val lampColor = lerpColor(
start = Color(0xFFFFE6A7), // warm
end = Color(0xFFD6ECFF), // cool
fraction = temperature
)
Box(
modifier = modifier
.fillMaxSize()
.background(
Brush.verticalGradient(
listOf(Color(0xFF050505), Color(0xFF111111))
)
)
.padding(WindowInsets.systemBars.asPaddingValues())
) {
BoxWithConstraints(
modifier = Modifier.fillMaxSize()
) {
val lampSize = min(maxWidth, maxHeight) * 0.55f
val glowSize = lampSize * (1.2f + animatedBrightness * flicker)
if (isLandscape) {
Row(
modifier = Modifier.fillMaxSize(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceEvenly
) {
LampVisual(
lampSize = lampSize,
glowSize = glowSize,
lampColor = lampColor,
brightness = animatedBrightness,
flicker = flicker
)
Controls(
brightness = brightness,
onBrightnessChange = { brightness = it },
temperature = temperature,
onTemperatureChange = { temperature = it },
lampColor = lampColor
)
}
} else {
Column(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 32.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween
) {
Spacer(Modifier.height(32.dp))
LampVisual(
lampSize = lampSize,
glowSize = glowSize,
lampColor = lampColor,
brightness = animatedBrightness,
flicker = flicker
)
Controls(
brightness = brightness,
onBrightnessChange = { brightness = it },
temperature = temperature,
onTemperatureChange = { temperature = it },
lampColor = lampColor
)
}
}
}
}
}
@Composable
private fun LampVisual(
lampSize: Dp,
glowSize: Dp,
lampColor: Color,
brightness: Float,
flicker: Float
) {
Box(
modifier = Modifier.size(lampSize),
contentAlignment = Alignment.Center
) {
Box(
modifier = Modifier
.size(glowSize)
.blur(70.dp)
.background(
Brush.radialGradient(
listOf(
lampColor.copy(alpha = brightness * flicker),
Color.Transparent
)
),
CircleShape
)
)
Box(
modifier = Modifier
.fillMaxSize(0.45f)
.background(
lampColor.copy(alpha = 0.45f + brightness * flicker),
CircleShape
)
)
}
}
@Composable
private fun Controls(
brightness: Float,
onBrightnessChange: (Float) -> Unit,
temperature: Float,
onTemperatureChange: (Float) -> Unit,
lampColor: Color
) {
Column(
modifier = Modifier
.fillMaxWidth(0.9f)
.background(
Color.White.copy(alpha = 0.08f),
RoundedCornerShape(28.dp)
)
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Lumen",
style = MaterialTheme.typography.titleMedium,
color = Color.White
)
Spacer(Modifier.height(20.dp))
Text("Brightness", color = Color.White.copy(alpha = 0.7f))
Slider(
value = brightness,
onValueChange = { onBrightnessChange(it.coerceIn(0.05f, 1f)) },
colors = SliderDefaults.colors(
thumbColor = lampColor,
activeTrackColor = lampColor,
inactiveTrackColor = Color.White.copy(alpha = 0.2f)
)
)
Spacer(Modifier.height(12.dp))
Text("Temperature", color = Color.White.copy(alpha = 0.7f))
Slider(
value = temperature,
onValueChange = { onTemperatureChange(it.coerceIn(0f, 1f)) },
colors = SliderDefaults.colors(
thumbColor = lampColor,
activeTrackColor = lampColor,
inactiveTrackColor = Color.White.copy(alpha = 0.2f)
)
)
}
}
private fun lerpColor(
start: Color,
end: Color,
fraction: Float
): Color =
Color(
red = start.red + (end.red - start.red) * fraction,
green = start.green + (end.green - start.green) * fraction,
blue = start.blue + (end.blue - start.blue) * fraction,
alpha = 1f
)
@Preview(
name = "Lamp - Medium Brightness",
showBackground = true,
backgroundColor = 0xFF050505
)
@Composable
private fun LampVisualPreview() {
LampVisual(
lampSize = 220.dp,
glowSize = 320.dp,
lampColor = Color(0xFFFFE6A7),
brightness = 0.6f,
flicker = 1f
)
}
@Preview(
name = "Controls",
showBackground = true,
backgroundColor = 0xFF050505
)
@Composable
private fun ControlsPreview() {
Controls(
brightness = 0.5f,
onBrightnessChange = {},
temperature = 0.3f,
onTemperatureChange = {},
lampColor = Color(0xFFFFE6A7)
)
}
@Preview(
name = "LumenScreen - Portrait",
showBackground = true,
device = Devices.PIXEL_6
)
@Composable
private fun LumenScreenPortraitPreview() {
MaterialTheme {
LumenScreen(isLandscape = false, isPreview = true)
}
}
@Preview(
name = "LumenScreen - Landscape",
showBackground = true,
widthDp = 840,
heightDp = 360,
)
@Composable
private fun LumenScreenLandscapePreview() {
MaterialTheme {
LumenScreen(isLandscape = true, isPreview = true)
}
}
@tasyamalia

Copy link
Copy Markdown
Author

Screen_recording_20260105_151057
Screen_recording_20260105_151151

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment