Files
Zern-BlackOut/app/src/main/java/com/wdtt/client/Theme.kt
T
2026-05-23 22:18:08 +03:00

282 lines
11 KiB
Kotlin

package com.wdtt.client
import android.os.Build
import android.app.Activity
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Typography
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.SideEffect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.lerp
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import androidx.core.view.WindowCompat
// ═══ Inter Font Family ═══
val InterFontFamily = FontFamily(
Font(R.font.inter_regular, FontWeight.Normal),
Font(R.font.inter_medium, FontWeight.Medium),
Font(R.font.inter_semibold, FontWeight.SemiBold),
Font(R.font.inter_bold, FontWeight.Bold),
)
// ═══ Типография на Inter ═══
val WDTTTypography = Typography(
displayLarge = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Bold, fontSize = 57.sp, lineHeight = 64.sp),
displayMedium = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Bold, fontSize = 45.sp, lineHeight = 52.sp),
displaySmall = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Bold, fontSize = 36.sp, lineHeight = 44.sp),
headlineLarge = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.SemiBold, fontSize = 32.sp, lineHeight = 40.sp),
headlineMedium = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.SemiBold, fontSize = 28.sp, lineHeight = 36.sp),
headlineSmall = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.SemiBold, fontSize = 24.sp, lineHeight = 32.sp),
titleLarge = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.SemiBold, fontSize = 22.sp, lineHeight = 28.sp),
titleMedium = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.SemiBold, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.15.sp),
titleSmall = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.1.sp),
bodyLarge = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 24.sp, letterSpacing = 0.5.sp),
bodyMedium = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.25.sp),
bodySmall = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Normal, fontSize = 12.sp, lineHeight = 16.sp, letterSpacing = 0.4.sp),
labelLarge = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.1.sp),
labelMedium = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Medium, fontSize = 12.sp, lineHeight = 16.sp, letterSpacing = 0.5.sp),
labelSmall = TextStyle(fontFamily = InterFontFamily, fontWeight = FontWeight.Medium, fontSize = 11.sp, lineHeight = 16.sp, letterSpacing = 0.5.sp),
)
// ═══ Светлая палитра — «Раф на кокосовом молоке» ═══
private val LightColorScheme = lightColorScheme(
primary = Color(0xFF6D4C41),
onPrimary = Color(0xFFFFFFFF),
primaryContainer = Color(0xFFD7CCC8),
onPrimaryContainer = Color(0xFF3E2723),
secondary = Color(0xFF8D6E63),
onSecondary = Color(0xFFFFFFFF),
secondaryContainer = Color(0xFFEFEBE9),
onSecondaryContainer = Color(0xFF4E342E),
tertiary = Color(0xFF795548),
onTertiary = Color(0xFFFFFFFF),
tertiaryContainer = Color(0xFFBCAAA4),
onTertiaryContainer = Color(0xFF3E2723),
background = Color(0xFFF2F0EC),
onBackground = Color(0xFF1C1B1A),
surface = Color(0xFFFAF8F4),
onSurface = Color(0xFF1C1B1A),
surfaceVariant = Color(0xFFEFEBE9),
onSurfaceVariant = Color(0xFF5D4037),
outline = Color(0xFFBCAAA4),
outlineVariant = Color(0xFFD7CCC8),
error = Color(0xFFBA1A1A),
onError = Color(0xFFFFFFFF),
errorContainer = Color(0xFFFFDAD6),
onErrorContainer = Color(0xFF410002),
inverseSurface = Color(0xFF322F2D),
inverseOnSurface = Color(0xFFF5F0EB),
inversePrimary = Color(0xFFD7CCC8),
surfaceTint = Color(0xFF6D4C41),
)
// ═══ Тёмная палитра — «Эспрессо» ═══
private val DarkColorScheme = darkColorScheme(
primary = Color(0xFFD7CCC8),
onPrimary = Color(0xFF3E2723),
primaryContainer = Color(0xFF5D4037),
onPrimaryContainer = Color(0xFFEFEBE9),
secondary = Color(0xFFBCAAA4),
onSecondary = Color(0xFF3E2723),
secondaryContainer = Color(0xFF4E342E),
onSecondaryContainer = Color(0xFFEFEBE9),
tertiary = Color(0xFFA1887F),
onTertiary = Color(0xFF3E2723),
tertiaryContainer = Color(0xFF5D4037),
onTertiaryContainer = Color(0xFFEFEBE9),
background = Color(0xFF1A1614),
onBackground = Color(0xFFEDE0D4),
surface = Color(0xFF211D1B),
onSurface = Color(0xFFEDE0D4),
surfaceVariant = Color(0xFF2C2624),
onSurfaceVariant = Color(0xFFD7CCC8),
outline = Color(0xFF8D6E63),
outlineVariant = Color(0xFF4E342E),
error = Color(0xFFFFB4AB),
onError = Color(0xFF690005),
errorContainer = Color(0xFF93000A),
onErrorContainer = Color(0xFFFFDAD6),
inverseSurface = Color(0xFFEDE0D4),
inverseOnSurface = Color(0xFF322F2D),
inversePrimary = Color(0xFF6D4C41),
surfaceTint = Color(0xFFD7CCC8),
)
private val IndigoLightColorScheme = lightColorScheme(
primary = Color(0xFF5B588D),
onPrimary = Color(0xFFFFFFFF),
primaryContainer = Color(0xFFE2DFFF),
onPrimaryContainer = Color(0xFF1A1744),
secondary = Color(0xFF5B588D),
onSecondary = Color(0xFFFFFFFF),
secondaryContainer = Color(0xFFE2DFFF),
onSecondaryContainer = Color(0xFF1A1744),
background = Color(0xFFFBF8FF),
onBackground = Color(0xFF1B1B1F),
surface = Color(0xFFF6F3FA),
onSurface = Color(0xFF1B1B1F),
surfaceVariant = Color(0xFFE4E1EC),
onSurfaceVariant = Color(0xFF47464F),
outline = Color(0xFF787680),
outlineVariant = Color(0xFFC8C5D0),
)
private val IndigoDarkColorScheme = darkColorScheme(
primary = Color(0xFFC4C0FF),
onPrimary = Color(0xFF2D2A5B),
primaryContainer = Color(0xFF434073),
onPrimaryContainer = Color(0xFFE2DFFF),
secondary = Color(0xFFC4C0FF),
onSecondary = Color(0xFF2D2A5B),
secondaryContainer = Color(0xFF434073),
onSecondaryContainer = Color(0xFFE2DFFF),
background = Color(0xFF131316),
onBackground = Color(0xFFE4E1E6),
surface = Color(0xFF1B1B1F),
onSurface = Color(0xFFC8C5D0),
surfaceVariant = Color(0xFF47464F),
onSurfaceVariant = Color(0xFFC8C5D0),
outline = Color(0xFF918F9A),
outlineVariant = Color(0xFF47464F),
)
private val ForestLightColorScheme = lightColorScheme(
primary = Color(0xFF5F5D68),
onPrimary = Color(0xFFFFFFFF),
primaryContainer = Color(0xFFE5E0F0),
onPrimaryContainer = Color(0xFF1C1A23),
secondary = Color(0xFF5F5D68),
onSecondary = Color(0xFFFFFFFF),
secondaryContainer = Color(0xFFE5E0F0),
onSecondaryContainer = Color(0xFF1C1A23),
background = Color(0xFFFCF8FF),
onBackground = Color(0xFF1D1B20),
surface = Color(0xFFF7F2FA),
onSurface = Color(0xFF1D1B20),
surfaceVariant = Color(0xFFE6E0E9),
onSurfaceVariant = Color(0xFF48454E),
outline = Color(0xFF79747E),
outlineVariant = Color(0xFFCAC4D0),
)
private val ForestDarkColorScheme = darkColorScheme(
primary = Color(0xFFC8C4D3),
onPrimary = Color(0xFF312F38),
primaryContainer = Color(0xFF474550),
onPrimaryContainer = Color(0xFFE5E0F0),
secondary = Color(0xFFC8C4D3),
onSecondary = Color(0xFF312F38),
secondaryContainer = Color(0xFF474550),
onSecondaryContainer = Color(0xFFE5E0F0),
background = Color(0xFF141318),
onBackground = Color(0xFFE6E1E5),
surface = Color(0xFF1D1B20),
onSurface = Color(0xFFCAC4D0),
surfaceVariant = Color(0xFF48454E),
onSurfaceVariant = Color(0xFFCAC4D0),
outline = Color(0xFF938F99),
outlineVariant = Color(0xFF48454E),
)
private fun getAppColorScheme(palette: String, isDark: Boolean): androidx.compose.material3.ColorScheme {
return when (palette) {
"espresso" -> if (isDark) DarkColorScheme else LightColorScheme
"forest" -> if (isDark) ForestDarkColorScheme else ForestLightColorScheme
else -> if (isDark) IndigoDarkColorScheme else IndigoLightColorScheme
}
}
// ═══ Расширенные цвета для кастомных элементов ═══
object WDTTColors {
// Статус: подключено
val connected = Color(0xFF4CAF50)
val connectedContainer = Color(0xFF4CAF50).copy(alpha = 0.12f)
val onConnected = Color(0xFF1B5E20)
val connectedDark = Color(0xFF81C784)
val connectedContainerDark = Color(0xFF81C784).copy(alpha = 0.15f)
val onConnectedDark = Color(0xFFC8E6C9)
// Статус: предупреждение
val warning = Color(0xFFFFA726)
val warningDark = Color(0xFFFFCC80)
// Терминал (логи)
val terminalBg = Color(0xFF1A1A2E)
val terminalBgDark = Color(0xFF0D0D1A)
val terminalText = Color(0xFFE0E0E0)
val terminalGreen = Color(0xFF4CAF50)
val terminalBlue = Color(0xFF42A5F5)
val terminalRed = Color(0xFFEF5350)
val terminalYellow = Color(0xFFFFC107)
val terminalCounter = Color(0xFF1E88E5)
// GitHub
val github = Color(0xFF24292E)
val githubDark = Color(0xFF333C47)
// Donate
val donate = Color(0xFF8B3FFD)
}
@Composable
fun WDTTTheme(
themeMode: String = "system",
dynamicColor: Boolean = false,
themePalette: String = "indigo",
content: @Composable () -> Unit
) {
val darkTheme = when (themeMode) {
"dark" -> true
"light" -> false
else -> isSystemInDarkTheme()
}
val colorScheme = when {
dynamicColor && !darkTheme && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
dynamicLightColorScheme(context)
}
else -> getAppColorScheme(themePalette, darkTheme)
}
val view = LocalView.current
if (!view.isInEditMode) {
SideEffect {
val window = (view.context as Activity).window
val navigationBarColor = if (darkTheme) {
Color.Transparent
} else {
lerp(colorScheme.background, colorScheme.surface, 0.55f)
}
window.statusBarColor = Color.Transparent.toArgb()
window.navigationBarColor = navigationBarColor.toArgb()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
window.isNavigationBarContrastEnforced = false
window.isStatusBarContrastEnforced = false
}
WindowCompat.getInsetsController(window, view).apply {
isAppearanceLightStatusBars = !darkTheme
isAppearanceLightNavigationBars = !darkTheme
}
}
}
MaterialTheme(
colorScheme = colorScheme,
typography = WDTTTypography,
content = content
)
}