diff --git a/JetLagged/app/src/main/java/com/example/jetlagged/JetLaggedScreen.kt b/JetLagged/app/src/main/java/com/example/jetlagged/JetLaggedScreen.kt index ae7ac23aec..8495fa7eb6 100644 --- a/JetLagged/app/src/main/java/com/example/jetlagged/JetLaggedScreen.kt +++ b/JetLagged/app/src/main/java/com/example/jetlagged/JetLaggedScreen.kt @@ -40,7 +40,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.viewmodel.compose.viewModel -import com.example.jetlagged.backgrounds.yellowBackground +import com.example.jetlagged.backgrounds.movingStripesBackground import com.example.jetlagged.data.JetLaggedHomeScreenViewModel import com.example.jetlagged.heartrate.HeartRateCard import com.example.jetlagged.sleep.JetLaggedHeader @@ -63,7 +63,7 @@ fun JetLaggedScreen( .verticalScroll(rememberScrollState()) .background(Color.White) ) { - Column(modifier = Modifier.yellowBackground()) { + Column(modifier = Modifier.movingStripesBackground()) { JetLaggedHeader( modifier = Modifier.fillMaxWidth(), onDrawerClicked = onDrawerClicked diff --git a/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/SimpleGradientBackground.kt b/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/SimpleGradientBackground.kt new file mode 100644 index 0000000000..57352fae3f --- /dev/null +++ b/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/SimpleGradientBackground.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.jetlagged.backgrounds + +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.graphics.Brush +import com.example.jetlagged.ui.theme.White +import com.example.jetlagged.ui.theme.Yellow +import com.example.jetlagged.ui.theme.YellowVariant + +fun Modifier.simpleGradient(): Modifier = + drawWithCache { + val gradientBrush = Brush.verticalGradient(listOf(Yellow, YellowVariant, White)) + onDrawBehind { + drawRect(gradientBrush, alpha = 1f) + } + } diff --git a/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/SolarFlareShaderBackground.kt b/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/SolarFlareShaderBackground.kt new file mode 100644 index 0000000000..6000dba7dc --- /dev/null +++ b/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/SolarFlareShaderBackground.kt @@ -0,0 +1,128 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.jetlagged.backgrounds + +import android.graphics.RuntimeShader +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.animation.core.withInfiniteAnimationFrameMillis +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ShaderBrush +import androidx.compose.ui.graphics.drawscope.ContentDrawScope +import androidx.compose.ui.node.DrawModifierNode +import androidx.compose.ui.node.ModifierNodeElement +import com.example.jetlagged.ui.theme.Yellow +import kotlinx.coroutines.launch +import org.intellij.lang.annotations.Language + +/** + * Background modifier that displays a custom shader for Android T and above and a linear gradient + * for older versions of Android + */ +fun Modifier.solarFlareShaderBackground(): Modifier = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.then(SolarFlareShaderBackgroundElement) + } else { + this.then(Modifier.simpleGradient()) + } + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +private data object SolarFlareShaderBackgroundElement : + ModifierNodeElement() { + override fun create() = SolarFlairShaderBackgroundNode() + override fun update(node: SolarFlairShaderBackgroundNode) { + } +} + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +private class SolarFlairShaderBackgroundNode : DrawModifierNode, Modifier.Node() { + private val shader = RuntimeShader(SHADER) + private val shaderBrush = ShaderBrush(shader) + private val time = mutableFloatStateOf(0f) + + init { + shader.setColorUniform( + "baseColor", + android.graphics.Color.valueOf(Yellow.red, Yellow.green, Yellow.blue, Yellow.alpha) + ) + } + + override fun ContentDrawScope.draw() { + shader.setFloatUniform("resolution", size.width, size.height) + shader.setFloatUniform("time", time.floatValue) + + drawRect(shaderBrush) + drawContent() + } + + override fun onAttach() { + coroutineScope.launch { + while (isAttached) { + withInfiniteAnimationFrameMillis { + time.floatValue = it / 1000f + } + } + } + } +} + +@Language("AGSL") +private val SHADER = """ + uniform float2 resolution; + uniform float time; + layout(color) uniform half4 baseColor; + + const int ITERATIONS = 2; + const float INTENSITY = 100.0; + const float TIME_MULTIPLIER = 0.25; + + float4 main(in float2 fragCoord) { + // Slow down the animation to be more soothing + float calculatedTime = time * TIME_MULTIPLIER; + + // Coords + float2 uv = fragCoord / resolution.xy; + float2 uvCalc = (uv * 5.0) - (INTENSITY * 2.0); + + // Values to adjust per iteration + float2 iterationChange = float2(uvCalc); + float colorPart = 1.0; + + for (int i = 0; i < ITERATIONS; i++) { + iterationChange = uvCalc + float2( + cos(calculatedTime + iterationChange.x) + + sin(calculatedTime - iterationChange.y), + cos(calculatedTime - iterationChange.x) + + sin(calculatedTime + iterationChange.y) + ); + colorPart += 0.8 / length( + float2(uvCalc.x / (cos(iterationChange.x + calculatedTime) * INTENSITY), + uvCalc.y / (sin(iterationChange.y + calculatedTime) * INTENSITY) + ) + ); + } + colorPart = 1.6 - (colorPart / float(ITERATIONS)); + + // Fade out the bottom on a curve + float alpha = 1.0 - (uv.y * uv.y); + // Mix calculated color with the incoming base color + float4 color = float4(colorPart * baseColor.r, colorPart * baseColor.g, colorPart * baseColor.b, alpha); + // Keep all channels within valid bounds of 0.0 and 1.0 + return clamp(color, 0.0, 1.0); + } +""".trimIndent() diff --git a/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/ShaderBackground.kt b/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/StripesShaderBackground.kt similarity index 78% rename from JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/ShaderBackground.kt rename to JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/StripesShaderBackground.kt index 4add69d96f..94e93e61a0 100644 --- a/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/ShaderBackground.kt +++ b/JetLagged/app/src/main/java/com/example/jetlagged/backgrounds/StripesShaderBackground.kt @@ -23,27 +23,24 @@ import androidx.annotation.RequiresApi import androidx.compose.animation.core.withInfiniteAnimationFrameMillis import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithCache -import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.ShaderBrush import androidx.compose.ui.graphics.drawscope.ContentDrawScope import androidx.compose.ui.node.DrawModifierNode import androidx.compose.ui.node.ModifierNodeElement -import com.example.jetlagged.ui.theme.White import com.example.jetlagged.ui.theme.Yellow -import com.example.jetlagged.ui.theme.YellowVariant import kotlinx.coroutines.launch import org.intellij.lang.annotations.Language -private data object YellowBackgroundElement : ModifierNodeElement() { +private data object MovingStripesBackgroundElement : + ModifierNodeElement() { @RequiresApi(Build.VERSION_CODES.TIRAMISU) - override fun create() = YellowBackgroundNode() - override fun update(node: YellowBackgroundNode) { + override fun create() = MovingStripesBackgroundNode() + override fun update(node: MovingStripesBackgroundNode) { } } @RequiresApi(Build.VERSION_CODES.TIRAMISU) -private class YellowBackgroundNode : DrawModifierNode, Modifier.Node() { +private class MovingStripesBackgroundNode : DrawModifierNode, Modifier.Node() { private val shader = RuntimeShader(SHADER) private val shaderBrush = ShaderBrush(shader) @@ -59,7 +56,6 @@ private class YellowBackgroundNode : DrawModifierNode, Modifier.Node() { override fun ContentDrawScope.draw() { shader.setFloatUniform("resolution", size.width, size.height) shader.setFloatUniform("time", time.floatValue) - shader.setFloatUniform("waves", 7f) drawRect(shaderBrush) @@ -77,23 +73,17 @@ private class YellowBackgroundNode : DrawModifierNode, Modifier.Node() { } } -fun Modifier.yellowBackground(): Modifier = +fun Modifier.movingStripesBackground(): Modifier = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - this.then(YellowBackgroundElement) + this.then(MovingStripesBackgroundElement) } else { - drawWithCache { - val gradientBrush = Brush.verticalGradient(listOf(Yellow, YellowVariant, White)) - onDrawBehind { - drawRect(gradientBrush, alpha = 1f) - } - } + this.then(Modifier.simpleGradient()) } @Language("AGSL") -val SHADER = """ +private val SHADER = """ uniform float2 resolution; uniform float time; - uniform float waves; layout(color) uniform half4 color; float calculateColorMultiplier(float yCoord, float factor) { @@ -104,7 +94,7 @@ val SHADER = """ // Config values const float speedMultiplier = 1.5; const float waveDensity = 1.0; - //const float loops = iWaves; + const float waves = 7.0; const float energy = 0.6; // Calculated values @@ -114,8 +104,7 @@ val SHADER = """ float hAdjustment = uv.x * 4.3; float3 loopColor = vec3(1.0 - rgbColor.r, 1.0 - rgbColor.g, 1.0 - rgbColor.b) / waves; - for (float i = 1.0; i <= 100; i += 1.0) { - if (i > waves) break; + for (float i = 1.0; i <= waves; i += 1.0) { float loopFactor = i * 0.1; float sinInput = (timeOffset + hAdjustment) * energy; float curve = sin(sinInput) * (1.0 - loopFactor) * 0.05;