diff --git a/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlur.kt b/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlur.kt deleted file mode 100644 index 34fd199..0000000 --- a/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlur.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Infomaniak Authenticator - Android - * Copyright (C) 2026 Infomaniak Network SA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.infomaniak.auth.ui.images.illus.blueBlur - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.size -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import com.infomaniak.auth.ui.images.AppImages -import com.infomaniak.auth.ui.images.AppImages.AppIllus -import com.infomaniak.auth.ui.theme.AuthenticatorTheme -import com.infomaniak.core.ui.compose.preview.PreviewLightAndDark -import com.infomaniak.core.ui.compose.theme.ThemedImage - -@Suppress("UnusedReceiverParameter") -val AppIllus.BlueBlur: ThemedImage - get() = _blueBlur ?: object : ThemedImage { - override val light = AppIllus.BlueBlurLight - override val dark = AppIllus.BlueBlurDark - }.also { _blueBlur = it } - -private var _blueBlur: ThemedImage? = null - -@PreviewLightAndDark -@Composable -private fun Preview() { - AuthenticatorTheme { - Box { - Image( - imageVector = AppIllus.BlueBlur.image(), - contentDescription = null, - modifier = Modifier.size(AppImages.previewSize), - ) - } - } -} diff --git a/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlurDark.kt b/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlurDark.kt deleted file mode 100644 index 1f03e8a..0000000 --- a/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlurDark.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Infomaniak Authenticator - Android - * Copyright (C) 2026 Infomaniak Network SA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.infomaniak.auth.ui.images.illus.blueBlur - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.size -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathFillType.Companion.NonZero -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap.Companion.Butt -import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.ImageVector.Builder -import androidx.compose.ui.graphics.vector.group -import androidx.compose.ui.graphics.vector.path -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.infomaniak.auth.ui.images.AppImages -import com.infomaniak.auth.ui.images.AppImages.AppIllus - -@Suppress("UnusedReceiverParameter") -val AppIllus.BlueBlurDark: ImageVector - get() { - if (_blueBlurDark != null) { - return _blueBlurDark!! - } - _blueBlurDark = Builder( - name = "BlueBlurDark", - defaultWidth = 460.0.dp, - defaultHeight = 460.0.dp, - viewportWidth = 460.0f, - viewportHeight = 460.0f, - ).apply { - group { - path( - fill = SolidColor(Color(0xFF5869D9)), - stroke = null, - fillAlpha = 0.256f, - strokeAlpha = 0.32f, - strokeLineWidth = 0.0f, - strokeLineCap = Butt, - strokeLineJoin = Miter, - strokeLineMiter = 4.0f, - pathFillType = NonZero, - ) { - moveTo(364.18f, 230.0f) - curveTo(364.18f, 304.11f, 304.11f, 364.18f, 230.0f, 364.18f) - curveTo(155.89f, 364.18f, 95.82f, 304.11f, 95.82f, 230.0f) - curveTo(95.82f, 155.89f, 155.89f, 95.82f, 230.0f, 95.82f) - curveTo(304.11f, 95.82f, 364.18f, 155.89f, 364.18f, 230.0f) - close() - } - } - }.build() - return _blueBlurDark!! - } - -private var _blueBlurDark: ImageVector? = null - -@Preview -@Composable -private fun Preview() { - Box { - Image( - imageVector = AppIllus.BlueBlurDark, - contentDescription = null, - modifier = Modifier.size(AppImages.previewSize), - ) - } -} diff --git a/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlurLight.kt b/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlurLight.kt deleted file mode 100644 index 7dfc140..0000000 --- a/app/src/main/kotlin/com/infomaniak/auth/ui/images/illus/blueBlur/BlueBlurLight.kt +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Infomaniak Authenticator - Android - * Copyright (C) 2026 Infomaniak Network SA - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.infomaniak.auth.ui.images.illus.blueBlur - -import androidx.compose.foundation.Image -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.size -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.PathFillType.Companion.NonZero -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.StrokeCap.Companion.Butt -import androidx.compose.ui.graphics.StrokeJoin.Companion.Miter -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.graphics.vector.ImageVector.Builder -import androidx.compose.ui.graphics.vector.group -import androidx.compose.ui.graphics.vector.path -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.infomaniak.auth.ui.images.AppImages -import com.infomaniak.auth.ui.images.AppImages.AppIllus - -@Suppress("UnusedReceiverParameter") -val AppIllus.BlueBlurLight: ImageVector - get() { - if (_blurLight != null) { - return _blurLight!! - } - _blurLight = Builder( - name = "BlurLight", - defaultWidth = 460.0.dp, - defaultHeight = 460.0.dp, - viewportWidth = 460.0f, - viewportHeight = 460.0f, - ).apply { - group { - path( - fill = SolidColor(Color(0xFF2F40AB)), - stroke = null, - fillAlpha = 0.096f, - strokeAlpha = 0.32f, - strokeLineWidth = 0.0f, - strokeLineCap = Butt, - strokeLineJoin = Miter, - strokeLineMiter = 4.0f, - pathFillType = NonZero, - ) { - moveTo(364.18f, 230.0f) - curveTo(364.18f, 304.11f, 304.11f, 364.18f, 230.0f, 364.18f) - curveTo(155.89f, 364.18f, 95.82f, 304.11f, 95.82f, 230.0f) - curveTo(95.82f, 155.89f, 155.89f, 95.82f, 230.0f, 95.82f) - curveTo(304.11f, 95.82f, 364.18f, 155.89f, 364.18f, 230.0f) - close() - } - } - }.build() - return _blurLight!! - } - -private var _blurLight: ImageVector? = null - -@Preview -@Composable -private fun Preview() { - Box { - Image( - imageVector = AppIllus.BlueBlurLight, - contentDescription = null, - modifier = Modifier.size(AppImages.previewSize), - ) - } -} diff --git a/app/src/main/kotlin/com/infomaniak/auth/ui/screen/onboarding/OnboardingPage.kt b/app/src/main/kotlin/com/infomaniak/auth/ui/screen/onboarding/OnboardingPage.kt index 9f9a34b..3cac74f 100644 --- a/app/src/main/kotlin/com/infomaniak/auth/ui/screen/onboarding/OnboardingPage.kt +++ b/app/src/main/kotlin/com/infomaniak/auth/ui/screen/onboarding/OnboardingPage.kt @@ -20,33 +20,40 @@ package com.infomaniak.auth.ui.screen.onboarding import androidx.annotation.RawRes import androidx.annotation.StringRes import androidx.compose.foundation.Image +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.size import androidx.compose.foundation.pager.PagerState +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Brush +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.infomaniak.auth.R import com.infomaniak.auth.ui.images.AppImages.AppIllus -import com.infomaniak.auth.ui.images.illus.blueBlur.BlueBlur import com.infomaniak.auth.ui.images.illus.shieldPerson.ShieldPerson +import com.infomaniak.auth.ui.theme.AuthenticatorTheme import com.infomaniak.core.onboarding.OnboardingPage +import com.infomaniak.core.onboarding.OnboardingScaffold import com.infomaniak.core.onboarding.components.OnboardingComponents.DefaultTitleAndDescription import com.infomaniak.core.onboarding.components.OnboardingComponents.ThemedDotLottie import com.infomaniak.core.onboarding.models.OnboardingLottieSource +import com.infomaniak.core.ui.compose.preview.PreviewSmallWindow import com.infomaniak.core.ui.compose.theme.LocalIsThemeDarkMode import com.infomaniak.core.ui.compose.theme.ThemedImage internal enum class Page( - val background: IllustrationResource, val illustration: IllustrationResource, @StringRes val titleRes: Int, @StringRes val descriptionRes: Int, ) { Login( - background = IllustrationResource.Vector(AppIllus.BlueBlur), illustration = IllustrationResource.Vector(AppIllus.ShieldPerson), titleRes = R.string.onBoardingLoginTitle, descriptionRes = R.string.onBoardingLoginDescription @@ -71,7 +78,6 @@ internal fun Page.toOnboardingPage(pagerState: PagerState, index: Int) = Onboard private fun Page.OnboardingPageIllustration(pagerState: PagerState, index: Int) { Box { val isCurrentPageVisible = { pagerState.currentPage == index } - RenderIllustration(background, isCurrentPageVisible) RenderIllustration(illustration, isCurrentPageVisible) } } @@ -81,7 +87,13 @@ private fun RenderIllustration(resource: IllustrationResource, isCurrentPageVisi when (resource) { is IllustrationResource.Vector -> { Image( - modifier = Modifier.size(350.dp), + modifier = Modifier + .size(350.dp) + .background( + Brush.radialGradient( + colors = listOf(AuthenticatorTheme.colors.illustrationBackgroundGradient, Color.Transparent), + ) + ), imageVector = resource.themedImage.image(), contentDescription = null, ) @@ -104,3 +116,27 @@ internal sealed class IllustrationResource { val themeIdDark: String? = null, ) : IllustrationResource() } + +@PreviewSmallWindow +@Composable +private fun OnboardingPagePreview() { + val pagerState = rememberPagerState(pageCount = { 1 }) + val page = Page.Login.toOnboardingPage(pagerState = pagerState, index = 0) + + AuthenticatorTheme { + OnboardingScaffold( + pagerState = pagerState, + onboardingPages = listOf(page), + bottomContent = { + Box( + modifier = Modifier + .height(100.dp) + .fillMaxWidth() + .background(Color.LightGray) + ) { + Text("Bottom content") + } + }, + ) + } +} diff --git a/app/src/main/kotlin/com/infomaniak/auth/ui/theme/Color.kt b/app/src/main/kotlin/com/infomaniak/auth/ui/theme/Color.kt index 4fc6d18..f2c2587 100644 --- a/app/src/main/kotlin/com/infomaniak/auth/ui/theme/Color.kt +++ b/app/src/main/kotlin/com/infomaniak/auth/ui/theme/Color.kt @@ -2,7 +2,7 @@ package com.infomaniak.auth.ui.theme import androidx.compose.ui.graphics.Color -val primaryLight = Color(0xFF525A92) +val primaryLight = Color(0xFF2B39A8) val onPrimaryLight = Color(0xFFFFFFFF) val primaryContainerLight = Color(0xFFDFE0FF) val onPrimaryContainerLight = Color(0xFF3A4279) @@ -38,7 +38,7 @@ val surfaceContainerLight = Color(0xFFEFEDF4) val surfaceContainerHighLight = Color(0xFFE9E7EF) val surfaceContainerHighestLight = Color(0xFFE4E1E9) -val primaryDark = Color(0xFFBBC3FF) +val primaryDark = Color(0xFFBCC2FF) val onPrimaryDark = Color(0xFF232C61) val primaryContainerDark = Color(0xFF3A4279) val onPrimaryContainerDark = Color(0xFFDFE0FF) @@ -73,3 +73,6 @@ val surfaceContainerLowDark = Color(0xFF1B1B21) val surfaceContainerDark = Color(0xFF1F1F25) val surfaceContainerHighDark = Color(0xFF29292F) val surfaceContainerHighestDark = Color(0xFF34343A) + +// Custom primitives +val productSecurity = Color(0xFF5869D9) diff --git a/app/src/main/kotlin/com/infomaniak/auth/ui/theme/CustomColor.kt b/app/src/main/kotlin/com/infomaniak/auth/ui/theme/CustomColor.kt new file mode 100644 index 0000000..35908b2 --- /dev/null +++ b/app/src/main/kotlin/com/infomaniak/auth/ui/theme/CustomColor.kt @@ -0,0 +1,37 @@ +/* + * Infomaniak Authenticator - Android + * Copyright (C) 2026 Infomaniak Network SA + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.infomaniak.auth.ui.theme + +import androidx.compose.runtime.Immutable +import androidx.compose.ui.graphics.Color + +@Immutable +data class CustomColorScheme( + val illustrationBackgroundGradient: Color = Color.Unspecified +) + +private val illustrationBackgroundGradientLight = lightScheme.primary.copy(alpha = 0.28f) +private val illustrationBackgroundGradientDark = productSecurity.copy(alpha = 0.6f) + +val lightCustomScheme = CustomColorScheme( + illustrationBackgroundGradient = illustrationBackgroundGradientLight +) + +val darkCustomScheme = CustomColorScheme( + illustrationBackgroundGradient = illustrationBackgroundGradientDark +) diff --git a/app/src/main/kotlin/com/infomaniak/auth/ui/theme/Theme.kt b/app/src/main/kotlin/com/infomaniak/auth/ui/theme/Theme.kt index b02ddd3..23ea6af 100644 --- a/app/src/main/kotlin/com/infomaniak/auth/ui/theme/Theme.kt +++ b/app/src/main/kotlin/com/infomaniak/auth/ui/theme/Theme.kt @@ -3,6 +3,7 @@ package com.infomaniak.auth.ui.theme import android.app.Activity import android.os.Build.VERSION.SDK_INT import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.ColorScheme import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.dynamicDarkColorScheme @@ -10,13 +11,16 @@ import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.ProvidableCompositionLocal import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.core.view.WindowCompat import com.infomaniak.core.ui.compose.theme.LocalIsThemeDarkMode -private val lightScheme = lightColorScheme( +// Never access it directly outside of the theme setup +val lightScheme = lightColorScheme( primary = primaryLight, onPrimary = onPrimaryLight, primaryContainer = primaryContainerLight, @@ -92,6 +96,8 @@ private val darkScheme = darkColorScheme( surfaceContainerHighest = surfaceContainerHighestDark, ) +val LocalCustomColorScheme: ProvidableCompositionLocal = staticCompositionLocalOf { CustomColorScheme() } + @Composable fun AuthenticatorTheme( isDarkTheme: Boolean = isSystemInDarkTheme(), @@ -119,7 +125,10 @@ fun AuthenticatorTheme( } } + val customColors = if (isDarkTheme) darkCustomScheme else lightCustomScheme + CompositionLocalProvider( + LocalCustomColorScheme provides customColors, LocalIsThemeDarkMode provides isDarkTheme ) { MaterialTheme( @@ -129,3 +138,11 @@ fun AuthenticatorTheme( } } +object AuthenticatorTheme { + val colors: CustomColorScheme + @Composable + get() = LocalCustomColorScheme.current + val materialColors: ColorScheme + @Composable + get() = MaterialTheme.colorScheme +}