Add onboarding image carousel
Bundle the rotating onboarding illustrations (light/dark) and wire them into the Android onboarding info component, matching the iOS carousel. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@@ -0,0 +1,59 @@
|
||||
package app.voltplan.cable.ui.components
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.animation.AnimatedContent
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.animation.togetherWith
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
/**
|
||||
* Auto-advancing onboarding illustration carousel. Mirrors iOS `OnboardingCarouselView`:
|
||||
* cycles through the images every 8s with a horizontal slide. A single image stays static.
|
||||
*/
|
||||
@Composable
|
||||
fun OnboardingCarousel(
|
||||
@DrawableRes images: List<Int>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (images.isEmpty()) return
|
||||
var index by remember(images) { mutableIntStateOf(0) }
|
||||
|
||||
if (images.size > 1) {
|
||||
LaunchedEffect(images) {
|
||||
while (true) {
|
||||
delay(8_000)
|
||||
index = (index + 1) % images.size
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedContent(
|
||||
targetState = index,
|
||||
transitionSpec = {
|
||||
slideInHorizontally(tween(800)) { it } togetherWith
|
||||
slideOutHorizontally(tween(800)) { -it }
|
||||
},
|
||||
label = "onboarding-carousel",
|
||||
modifier = modifier,
|
||||
) { i ->
|
||||
Image(
|
||||
painter = painterResource(images[i]),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.Fit,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package app.voltplan.cable.ui.components
|
||||
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Button
|
||||
@@ -29,6 +31,7 @@ fun OnboardingInfo(
|
||||
onPrimary: () -> Unit,
|
||||
secondaryLabel: String? = null,
|
||||
onSecondary: (() -> Unit)? = null,
|
||||
@DrawableRes images: List<Int> = emptyList(),
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
@@ -36,7 +39,11 @@ fun OnboardingInfo(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(56.dp))
|
||||
if (images.isNotEmpty()) {
|
||||
OnboardingCarousel(images = images, modifier = Modifier.fillMaxWidth().height(200.dp))
|
||||
} else {
|
||||
Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary, modifier = Modifier.size(56.dp))
|
||||
}
|
||||
Spacer(Modifier.size(16.dp))
|
||||
Text(title, style = MaterialTheme.typography.titleLarge, textAlign = TextAlign.Center)
|
||||
Spacer(Modifier.size(8.dp))
|
||||
|
||||
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 28 KiB |
BIN
android/app/src/main/res/drawable-night-nodpi/onboarding_van.png
Normal file
|
After Width: | Height: | Size: 74 KiB |
BIN
android/app/src/main/res/drawable-nodpi/onboarding_battery.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
android/app/src/main/res/drawable-nodpi/onboarding_boat.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
android/app/src/main/res/drawable-nodpi/onboarding_cabin.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
android/app/src/main/res/drawable-nodpi/onboarding_charger.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
android/app/src/main/res/drawable-nodpi/onboarding_coffee.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
android/app/src/main/res/drawable-nodpi/onboarding_router.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
android/app/src/main/res/drawable-nodpi/onboarding_van.png
Normal file
|
After Width: | Height: | Size: 64 KiB |