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 @@ -14,6 +14,7 @@ import com.velord.core.ui.compose.component.DesktopBackDispatcher
import com.velord.core.ui.compose.component.LocalDesktopBackDispatcher
import com.velord.core.ui.compose.component.ToastHost
import com.velord.core.ui.theme.AppThemeHost
import com.velord.core.ui.theme.LocalizationHost
import com.velord.core.ui.util.ObserveSharedFlow
import com.velord.infrastructure.di.createCommonAppModuleRoster
import com.velord.infrastructure.navigation.NavigationHost
Expand Down Expand Up @@ -58,15 +59,17 @@ fun main() = application {
}

CompositionLocalProvider(LocalDesktopBackDispatcher provides dispatcher) {
AppThemeHost {
SplashScreen(viewModel = splashVM) {
ToastHost(
toastEventFlow = mainVM.toastConfigFlow,
modifier = Modifier.fillMaxSize(),
content = {
NavigationHost(navigationLib = mainVM.navigationLib)
},
)
LocalizationHost {
AppThemeHost {
SplashScreen(viewModel = splashVM) {
ToastHost(
toastEventFlow = mainVM.toastConfigFlow,
modifier = Modifier.fillMaxSize(),
content = {
NavigationHost(navigationLib = mainVM.navigationLib)
},
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"use_system_dynamic_theme": "Use System Dynamic Theme",
"not_available_on_android_11": "Not available on Android 11 and below",
"disable_os_theme_switcher_first": "Disable Os theme switcher first",
"disable_dynamic_theme_first": "Disable system dynamic theme first",
"error": "Error",
"loading": "Loading",
"count": "Count: %1$d",
Expand Down Expand Up @@ -94,7 +95,15 @@
"show_one_button_dialog": "Show one button dialog",
"language": "Language",
"language_default": "Default",
"language_name": "English"
"language_name": "English",
"theme_light": "Light",
"theme_dark": "Dark",
"theme_negative_light": "Negative Light",
"theme_ocean": "Ocean",
"shape_rounded": "Rounded",
"shape_cut": "Cut",
"shape_square": "Square",
"shape_style_title": "Component Shapes"
},
"es": {
"app_name": "ComposeScreenExample",
Expand Down Expand Up @@ -129,6 +138,7 @@
"use_system_dynamic_theme": "Usar tema dinámico del sistema",
"not_available_on_android_11": "No disponible en Android 11 y versiones anteriores",
"disable_os_theme_switcher_first": "Desactiva primero el selector de tema del SO",
"disable_dynamic_theme_first": "Desactiva primero el tema dinámico del sistema",
"error": "Error",
"loading": "Cargando",
"count": "Cantidad: %1$d",
Expand Down Expand Up @@ -188,7 +198,15 @@
"show_one_button_dialog": "Mostrar diálogo con un botón",
"language": "Idioma",
"language_default": "Predeterminado",
"language_name": "Español"
"language_name": "Español",
"theme_light": "Claro",
"theme_dark": "Oscuro",
"theme_negative_light": "Luz Negativa",
"theme_ocean": "Océano",
"shape_rounded": "Redondeado",
"shape_cut": "Cortado",
"shape_square": "Cuadrado",
"shape_style_title": "Formas de los componentes"
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment
import androidx.lifecycle.LifecycleOwner
import com.velord.core.ui.compose.component.ToastHost
import com.velord.core.ui.theme.AppThemeHost
import com.velord.core.ui.theme.LocalizationHost
import com.velord.model.ToastConfig
import kotlinx.coroutines.flow.Flow

Expand Down Expand Up @@ -42,8 +43,10 @@ private fun ComposeView.setThemedContent(
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)

setContent {
AppThemeHost {
this@setThemedContent.content()
LocalizationHost {
AppThemeHost {
this@setThemedContent.content()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,30 @@
package com.velord.core.ui.compose.shape

import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Shapes
import androidx.compose.ui.unit.dp

val MainShapes = Shapes(
val RoundedShapes = Shapes(
extraSmall = RoundedCornerShape(4.dp),
small = RoundedCornerShape(8.dp),
medium = RoundedCornerShape(12.dp),
large = RoundedCornerShape(16.dp),
extraLarge = RoundedCornerShape(24.dp)
)

val CutShapes = Shapes(
extraSmall = CutCornerShape(4.dp),
small = CutCornerShape(8.dp),
medium = CutCornerShape(12.dp),
large = CutCornerShape(16.dp),
extraLarge = CutCornerShape(24.dp)
)

val SquareShapes = Shapes(
extraSmall = RoundedCornerShape(0.dp),
small = RoundedCornerShape(0.dp),
medium = RoundedCornerShape(0.dp),
large = RoundedCornerShape(0.dp),
extraLarge = RoundedCornerShape(0.dp)
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,36 @@ package com.velord.core.ui.compose.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Shapes
import androidx.compose.runtime.Composable
import com.velord.core.ui.compose.shape.MainShapes
import com.velord.core.ui.compose.shape.CutShapes
import com.velord.core.ui.compose.shape.RoundedShapes
import com.velord.core.ui.compose.shape.SquareShapes
import com.velord.core.ui.compose.theme.color.DarkColorScheme
import com.velord.core.ui.compose.theme.color.LightColorScheme
import com.velord.core.ui.compose.theme.color.NegativeLightColorScheme
import com.velord.core.ui.compose.theme.color.OceanColorScheme
import com.velord.model.setting.AppShapeStyle
import com.velord.model.setting.AppThemeConfig
import com.velord.model.setting.SpecialTheme

private fun SpecialTheme.toColorScheme(): ColorScheme = when (this) {
SpecialTheme.DARK -> DarkColorScheme
SpecialTheme.LIGHT -> LightColorScheme
SpecialTheme.NEGATIVE_LIGHT -> NegativeLightColorScheme
SpecialTheme.OCEAN -> OceanColorScheme
}

private fun getDefaultDarkScheme() = SpecialTheme.DEFAULT_DARK_SCHEME.toColorScheme()
private fun getDefaultLightScheme() = SpecialTheme.DEFAULT_LIGHT_SCHEME.toColorScheme()
private fun defineDefaultColorScheme(
useDarkTheme: Boolean
): ColorScheme = if (useDarkTheme) getDefaultDarkScheme() else getDefaultLightScheme()

private fun AppShapeStyle.toShapes(): Shapes = when(this) {
AppShapeStyle.ROUNDED -> RoundedShapes
AppShapeStyle.CUT -> CutShapes
AppShapeStyle.SQUARE -> SquareShapes
}

@Composable
Expand All @@ -21,17 +41,20 @@ fun MainTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = true,
specialTheme: SpecialTheme,
shapeStyle: AppShapeStyle = AppShapeStyle.ROUNDED,
content: @Composable () -> Unit,
) {
val isDark = specialTheme.mode.isDark(useDarkTheme)

val dynamicColorScheme = platformDynamicColorScheme(
useDarkTheme = useDarkTheme,
useDarkTheme = isDark,
dynamicColor = dynamicColor,
apiAvailable = AppThemeConfig.DEFAULT.isSystemDynamicColorAvailable,
)

val colorScheme: ColorScheme = when {
abideToOsTheme.not() && dynamicColorScheme != null -> dynamicColorScheme
abideToOsTheme -> if (useDarkTheme) DarkColorScheme else LightColorScheme
abideToOsTheme -> defineDefaultColorScheme(isDark)
else -> specialTheme.toColorScheme()
}

Expand All @@ -43,7 +66,7 @@ fun MainTheme(

MaterialTheme(
colorScheme = colorScheme,
shapes = MainShapes,
shapes = shapeStyle.toShapes(),
typography = MainTypography,
content = content,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.velord.core.ui.compose.theme.color

import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.ui.graphics.Color
import com.velord.core.ui.util.color.inverseColor

val DarkColorScheme = darkColorScheme(
primary = ColorDarkTokens.Primary,
Expand Down Expand Up @@ -80,3 +82,82 @@ val LightColorScheme = lightColorScheme(
surfaceContainerLowest = ColorLightTokens.SurfaceContainerLowest,
surfaceDim = ColorLightTokens.SurfaceDim,
)

val NegativeLightColorScheme = darkColorScheme(
primary = ColorLightTokens.Primary.inverseColor(),
onPrimary = ColorLightTokens.OnPrimary.inverseColor(),
primaryContainer = ColorLightTokens.PrimaryContainer.inverseColor(),
onPrimaryContainer = ColorLightTokens.OnPrimaryContainer.inverseColor(),
inversePrimary = ColorLightTokens.InversePrimary.inverseColor(),
secondary = ColorLightTokens.Secondary.inverseColor(),
onSecondary = ColorLightTokens.OnSecondary.inverseColor(),
secondaryContainer = ColorLightTokens.SecondaryContainer.inverseColor(),
onSecondaryContainer = ColorLightTokens.OnSecondaryContainer.inverseColor(),
tertiary = ColorLightTokens.Tertiary.inverseColor(),
onTertiary = ColorLightTokens.OnTertiary.inverseColor(),
tertiaryContainer = ColorLightTokens.TertiaryContainer.inverseColor(),
onTertiaryContainer = ColorLightTokens.OnTertiaryContainer.inverseColor(),
background = ColorLightTokens.Background.inverseColor(),
onBackground = ColorLightTokens.OnBackground.inverseColor(),
surface = ColorLightTokens.Surface.inverseColor(),
onSurface = ColorLightTokens.OnSurface.inverseColor(),
surfaceVariant = ColorLightTokens.SurfaceVariant.inverseColor(),
onSurfaceVariant = ColorLightTokens.OnSurfaceVariant.inverseColor(),
surfaceTint = ColorLightTokens.SurfaceTint.inverseColor(),
inverseSurface = ColorLightTokens.InverseSurface.inverseColor(),
inverseOnSurface = ColorLightTokens.InverseOnSurface.inverseColor(),
error = ColorLightTokens.Error.inverseColor(),
onError = ColorLightTokens.OnError.inverseColor(),
errorContainer = ColorLightTokens.ErrorContainer.inverseColor(),
onErrorContainer = ColorLightTokens.OnErrorContainer.inverseColor(),
outline = ColorLightTokens.Outline.inverseColor(),
outlineVariant = ColorLightTokens.OutlineVariant.inverseColor(),
scrim = ColorLightTokens.Scrim.inverseColor(),
surfaceBright = ColorLightTokens.SurfaceBright.inverseColor(),
surfaceContainer = ColorLightTokens.SurfaceContainer.inverseColor(),
surfaceContainerHigh = ColorLightTokens.SurfaceContainerHigh.inverseColor(),
surfaceContainerHighest = ColorLightTokens.SurfaceContainerHighest.inverseColor(),
surfaceContainerLow = ColorLightTokens.SurfaceContainerLow.inverseColor(),
surfaceContainerLowest = ColorLightTokens.SurfaceContainerLowest.inverseColor(),
surfaceDim = ColorLightTokens.SurfaceDim.inverseColor(),
)

val OceanColorScheme = darkColorScheme(
primary = Color(0xFF4DD0E1),
onPrimary = Color(0xFF00363A),
primaryContainer = Color(0xFF004D40),
onPrimaryContainer = Color(0xFF80CBC4),
inversePrimary = Color(0xFF00838F),
secondary = Color(0xFF81C784),
onSecondary = Color(0xFF1B5E20),
secondaryContainer = Color(0xFF2E7D32),
onSecondaryContainer = Color(0xFFA5D6A7),
tertiary = Color(0xFF64B5F6),
onTertiary = Color(0xFF0D47A1),
tertiaryContainer = Color(0xFF1565C0),
onTertiaryContainer = Color(0xFFE3F2FD),
background = Color(0xFF001F24),
onBackground = Color(0xFFE0F7FA),
surface = Color(0xFF001F24),
onSurface = Color(0xFFE0F7FA),
surfaceVariant = Color(0xFF00363A),
onSurfaceVariant = Color(0xFF80CBC4),
surfaceTint = Color(0xFF4DD0E1),
inverseSurface = Color(0xFFE0F7FA),
inverseOnSurface = Color(0xFF001F24),
error = Color(0xFFE57373),
onError = Color(0xFFB71C1C),
errorContainer = Color(0xFFD32F2F),
onErrorContainer = Color(0xFFFFEBEE),
outline = Color(0xFF4DD0E1),
outlineVariant = Color(0xFF006064),
scrim = Color(0xFF000000),
surfaceBright = Color(0xFF00363A),
surfaceContainer = Color(0xFF001518),
surfaceContainerHigh = Color(0xFF001A1E),
surfaceContainerHighest = Color(0xFF001F24),
surfaceContainerLow = Color(0xFF000B0D),
surfaceContainerLowest = Color(0xFF000507),
surfaceDim = Color(0xFF001518)
)

Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,22 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.State
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.velord.core.resource.LocalLocalizationState
import com.velord.core.ui.compose.theme.MainTheme
import com.velord.core.ui.util.LocalTheme
import com.velord.model.setting.AppThemeConfig
import com.velord.ui.sharedviewmodel.LanguageVM
import com.velord.ui.sharedviewmodel.ThemeUiState
import com.velord.ui.sharedviewmodel.ThemeVM
import org.koin.compose.viewmodel.koinViewModel

@Composable
fun AppThemeHost(
themeVM: ThemeVM = koinViewModel(),
languageVM: LanguageVM = koinViewModel(),
content: @Composable () -> Unit,
) {
val themeState: State<ThemeUiState?> = themeVM.uiStateFlow.collectAsStateWithLifecycle()
val theme = themeState.value?.appThemeConfig ?: AppThemeConfig.DEFAULT
val localizationState = languageVM.uiStateFlow
.collectAsStateWithLifecycle()
.value
.localization

CompositionLocalProvider(
LocalTheme provides theme,
LocalLocalizationState provides localizationState,
) {
CompositionLocalProvider(LocalTheme provides theme) {
val localThemeConfig = LocalTheme.current

val isDark = if (localThemeConfig.config.abideToOs) {
Expand All @@ -44,6 +34,7 @@ fun AppThemeHost(
useDarkTheme = isDark,
dynamicColor = localThemeConfig.config.useDynamicColor,
specialTheme = localThemeConfig.config.current,
shapeStyle = localThemeConfig.config.shapeStyle,
content = content,
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.velord.core.ui.theme

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.velord.core.resource.LocalLocalizationState
import com.velord.ui.sharedviewmodel.LanguageVM
import org.koin.compose.viewmodel.koinViewModel

@Composable
fun LocalizationHost(
languageVM: LanguageVM = koinViewModel(),
content: @Composable () -> Unit,
) {
val localizationState = languageVM.uiStateFlow
.collectAsStateWithLifecycle()
.value
.localization

CompositionLocalProvider(LocalLocalizationState provides localizationState) {
content()
}
}
Loading
Loading