diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c67e8a19..5d915bee 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -3,6 +3,7 @@ plugins { alias(libs.plugins.kotlin.android) alias(libs.plugins.ksp) alias(libs.plugins.hilt.android) + alias(libs.plugins.compose.compiler) } android { @@ -96,6 +97,7 @@ android { buildFeatures { buildConfig = true + compose = true } ndkVersion = "28.0.13004108" @@ -127,12 +129,21 @@ dependencies { implementation(libs.hilt.android) ksp(libs.hilt.android.compiler) + // Compose + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.bundles.compose) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.ui.test.manifest) + add("androidTestScreenshotImplementation", libs.junit) add("androidTestScreenshotImplementation", libs.fastlane.screengrab) add("androidTestScreenshotImplementation", libs.androidx.test.rules) add("androidTestScreenshotImplementation", libs.androidx.test.ext.junit) add("androidTestScreenshotImplementation", libs.androidx.test.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test.junit4) + testImplementation(libs.junit) testImplementation(libs.google.truth) } diff --git a/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Color.kt b/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Color.kt new file mode 100644 index 00000000..127691b8 --- /dev/null +++ b/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Color.kt @@ -0,0 +1,43 @@ +package de.rwth_aachen.phyphox.ui.theme + +import androidx.compose.ui.graphics.Color + +val PhyphoxPrimary = Color(0xFFFF7E22) +val PhyphoxPrimaryWeak = Color(0xFFFFA500) +val PhyphoxRwthPrimary = Color(0xFF00549F) + +val PhyphoxWhite100 = Color(0xFFFFFFFF) +val PhyphoxWhite90 = Color(0xFFF0F0F0) +val PhyphoxWhite80 = Color(0xFFE0E0E0) +val PhyphoxWhite70 = Color(0xFFD0D0D0) +val PhyphoxWhite60 = Color(0xFFC4C4C4) +val PhyphoxWhite50Black50 = Color(0xFF808080) +val PhyphoxBlack40 = Color(0xFF404040) +val PhyphoxBlack50 = Color(0xFF303030) +val PhyphoxBlack60 = Color(0xFF202020) +val PhyphoxBlack80 = Color(0xFF101010) +val PhyphoxBlack100 = Color(0xFF000000) + +val PhyphoxBlue100 = Color(0xFF2260A5) +val PhyphoxBlue60 = Color(0xFF39A2FF) +val PhyphoxBlue40 = Color(0xFF9DD1FF) +val PhyphoxBlueStrong = Color(0xFF0169C5) + +val PhyphoxRed = Color(0xFFFE005D) +val PhyphoxRedWeak = Color(0xFFFF7CAC) + +val PhyphoxMagenta = Color(0xFFEB46F4) +val PhyphoxMagentaWeak = Color(0xFFF6AAFA) + +val PhyphoxGreen = Color(0xFF2BFB4C) +val PhyphoxGreenWeak = Color(0xFFA1FDAF) +val PhyphoxGreenStrong = Color(0xFF00D425) + +val PhyphoxYellowWeak = Color(0xFFE7E09B) +val PhyphoxYellow = Color(0xFFEDF668) +val PhyphoxYellowStrong = Color(0xFF8D9709) + +// Helper aliases to match old definitions if any +val PhyphoxBlack = PhyphoxBlack100 +val PhyphoxWhite = PhyphoxWhite100 +val PhyphoxBlue = PhyphoxBlue100 diff --git a/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Theme.kt b/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Theme.kt new file mode 100644 index 00000000..30ec94c0 --- /dev/null +++ b/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Theme.kt @@ -0,0 +1,126 @@ +package de.rwth_aachen.phyphox.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.ReadOnlyComposable +import androidx.compose.runtime.SideEffect +import androidx.compose.runtime.staticCompositionLocalOf +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.toArgb +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalView +import androidx.core.view.WindowCompat + +@Immutable +data class PhyphoxColors( + val primary: Color = PhyphoxPrimary, + val primaryWeak: Color = PhyphoxPrimaryWeak, + val rwthPrimary: Color = PhyphoxRwthPrimary, + val white100: Color = PhyphoxWhite100, + val white90: Color = PhyphoxWhite90, + val white80: Color = PhyphoxWhite80, + val white70: Color = PhyphoxWhite70, + val white60: Color = PhyphoxWhite60, + val white50Black50: Color = PhyphoxWhite50Black50, + val black40: Color = PhyphoxBlack40, + val black50: Color = PhyphoxBlack50, + val black60: Color = PhyphoxBlack60, + val black80: Color = PhyphoxBlack80, + val black100: Color = PhyphoxBlack100, + val blue100: Color = PhyphoxBlue100, + val blue60: Color = PhyphoxBlue60, + val blue40: Color = PhyphoxBlue40, + val blueStrong: Color = PhyphoxBlueStrong, + val red: Color = PhyphoxRed, + val redWeak: Color = PhyphoxRedWeak, + val magenta: Color = PhyphoxMagenta, + val magentaWeak: Color = PhyphoxMagentaWeak, + val green: Color = PhyphoxGreen, + val greenWeak: Color = PhyphoxGreenWeak, + val greenStrong: Color = PhyphoxGreenStrong, + val yellowWeak: Color = PhyphoxYellowWeak, + val yellow: Color = PhyphoxYellow, + val yellowStrong: Color = PhyphoxYellowStrong, +) + +val LocalPhyphoxColors = staticCompositionLocalOf { PhyphoxColors() } + +val MaterialTheme.customColors: PhyphoxColors + @Composable + @ReadOnlyComposable + get() = LocalPhyphoxColors.current + +private val DarkColorScheme = darkColorScheme( + primary = PhyphoxPrimary, + secondary = PhyphoxPrimaryWeak, + tertiary = PhyphoxBlue, + background = PhyphoxBlack60, + surface = PhyphoxBlack50, + onPrimary = PhyphoxWhite100, + onSecondary = PhyphoxBlack100, + onTertiary = PhyphoxWhite100, + onBackground = PhyphoxWhite100, + onSurface = PhyphoxWhite100, + surfaceVariant = PhyphoxBlack80, + onSurfaceVariant = PhyphoxWhite80 +) + +private val LightColorScheme = lightColorScheme( + primary = PhyphoxPrimary, + secondary = PhyphoxPrimaryWeak, + tertiary = PhyphoxBlue, + background = PhyphoxWhite100, + surface = PhyphoxWhite100, + onPrimary = PhyphoxWhite100, + onSecondary = PhyphoxBlack100, + onTertiary = PhyphoxWhite100, + onBackground = PhyphoxBlack60, + onSurface = PhyphoxBlack60, + surfaceVariant = PhyphoxWhite90, + onSurfaceVariant = PhyphoxBlack60 +) + +@Composable +fun PhyphoxTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + val view = LocalView.current + if (!view.isInEditMode) { + SideEffect { + val window = (view.context as Activity).window + window.statusBarColor = colorScheme.primary.toArgb() + WindowCompat.getInsetsController(window, view).isAppearanceLightStatusBars = !darkTheme + } + } + + CompositionLocalProvider( + LocalPhyphoxColors provides PhyphoxColors() + ) { + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) + } +} diff --git a/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Type.kt b/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Type.kt new file mode 100644 index 00000000..7b9c825a --- /dev/null +++ b/app/src/main/java/de/rwth_aachen/phyphox/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package de.rwth_aachen.phyphox.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2a8fbd68..3d90af06 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,6 +34,9 @@ truth = "1.0.1" pahoMqtt = "4.4" camerax = "1.4.2" hilt-android = "2.57.2" +composeBom = "2025.02.00" +activityCompose = "1.10.0" +lifecycleRuntimeCompose = "2.8.7" [libraries] androidx-multidex = { group = "androidx.multidex", name = "multidex", version.ref = "multidex" } @@ -67,15 +70,29 @@ androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "camerax" } androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "camerax" } -#hilt-android +# Hilt hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt-android" } hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt-android" } +# Compose +androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" } +androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } +androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } +androidx-lifecycle-runtime-compose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycleRuntimeCompose" } +androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } +androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } +androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } + [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt-android" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } +compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } [bundles] camerax = ["androidx-camera-core", "androidx-camera-camera2", "androidx-camera-lifecycle", "androidx-camera-view"] +compose = ["androidx-compose-ui", "androidx-compose-ui-graphics", "androidx-compose-ui-tooling-preview", "androidx-compose-material3", "androidx-activity-compose", "androidx-lifecycle-runtime-compose"]