feat: add Material 3 theme and screen navigation
Made-with: Cursor
This commit is contained in:
@@ -55,6 +55,8 @@ dependencies {
|
||||
implementation(libs.datastore.preferences)
|
||||
implementation(libs.okhttp)
|
||||
implementation(libs.lifecycle.viewmodel.compose)
|
||||
implementation(libs.lifecycle.viewmodel.ktx)
|
||||
implementation(libs.material.icons.extended)
|
||||
implementation(libs.lifecycle.runtime.compose)
|
||||
implementation(libs.lifecycle.service)
|
||||
implementation(libs.coroutines.core)
|
||||
|
||||
@@ -2,27 +2,42 @@ package xyz.cottongin.radio247
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import xyz.cottongin.radio247.ui.navigation.Screen
|
||||
import xyz.cottongin.radio247.ui.screens.nowplaying.NowPlayingScreen
|
||||
import xyz.cottongin.radio247.ui.screens.settings.SettingsScreen
|
||||
import xyz.cottongin.radio247.ui.screens.stationlist.StationListScreen
|
||||
import xyz.cottongin.radio247.ui.theme.Radio247Theme
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContent {
|
||||
Radio247Placeholder()
|
||||
Radio247Theme {
|
||||
var currentScreen by remember { mutableStateOf<Screen>(Screen.StationList) }
|
||||
|
||||
BackHandler(enabled = currentScreen != Screen.StationList) {
|
||||
currentScreen = Screen.StationList
|
||||
}
|
||||
|
||||
when (currentScreen) {
|
||||
Screen.StationList -> StationListScreen(
|
||||
onNavigateToNowPlaying = { currentScreen = Screen.NowPlaying },
|
||||
onNavigateToSettings = { currentScreen = Screen.Settings }
|
||||
)
|
||||
Screen.NowPlaying -> NowPlayingScreen(
|
||||
onBack = { currentScreen = Screen.StationList }
|
||||
)
|
||||
Screen.Settings -> SettingsScreen(
|
||||
onBack = { currentScreen = Screen.StationList }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Radio247Placeholder() {
|
||||
Text("24/7 Radio")
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun Radio247PlaceholderPreview() {
|
||||
Radio247Placeholder()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package xyz.cottongin.radio247.ui.navigation
|
||||
|
||||
sealed class Screen {
|
||||
data object StationList : Screen()
|
||||
data object NowPlaying : Screen()
|
||||
data object Settings : Screen()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package xyz.cottongin.radio247.ui.screens.nowplaying
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun NowPlayingScreen(
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(modifier) {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
||||
}
|
||||
Text("Now Playing")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package xyz.cottongin.radio247.ui.screens.settings
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun SettingsScreen(
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(modifier) {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
||||
}
|
||||
Text("Settings")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package xyz.cottongin.radio247.ui.screens.stationlist
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@Composable
|
||||
fun StationListScreen(
|
||||
onNavigateToNowPlaying: () -> Unit,
|
||||
onNavigateToSettings: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
// Placeholder - full implementation in Task 10
|
||||
Column(modifier) {
|
||||
Text("Station List")
|
||||
Button(onClick = onNavigateToNowPlaying) { Text("Now Playing") }
|
||||
Button(onClick = onNavigateToSettings) { Text("Settings") }
|
||||
}
|
||||
}
|
||||
23
app/src/main/java/xyz/cottongin/radio247/ui/theme/Color.kt
Normal file
23
app/src/main/java/xyz/cottongin/radio247/ui/theme/Color.kt
Normal file
@@ -0,0 +1,23 @@
|
||||
package xyz.cottongin.radio247.ui.theme
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
||||
// Radio/broadcast themed palette - dark blues, amber accents
|
||||
// Light scheme
|
||||
val BlueGray900 = Color(0xFF0D1B2A)
|
||||
val BlueGray800 = Color(0xFF1B263B)
|
||||
val BlueGray700 = Color(0xFF415A77)
|
||||
val BlueGray600 = Color(0xFF778DA9)
|
||||
val BlueGray500 = Color(0xFFE0E1DD)
|
||||
val Amber500 = Color(0xFFFFB300)
|
||||
val Amber400 = Color(0xFFFFC107)
|
||||
val Amber300 = Color(0xFFFFD54F)
|
||||
|
||||
// Dark scheme
|
||||
val BlueGray100 = Color(0xFFE8EDF2)
|
||||
val BlueGray200 = Color(0xFFC5CBD3)
|
||||
val BlueGray300 = Color(0xFF778DA9)
|
||||
val BlueGray400 = Color(0xFF415A77)
|
||||
val BlueGray950 = Color(0xFF0A0F14)
|
||||
val Amber200 = Color(0xFFFFE082)
|
||||
val Amber100 = Color(0xFFFFECB3)
|
||||
70
app/src/main/java/xyz/cottongin/radio247/ui/theme/Theme.kt
Normal file
70
app/src/main/java/xyz/cottongin/radio247/ui/theme/Theme.kt
Normal file
@@ -0,0 +1,70 @@
|
||||
package xyz.cottongin.radio247.ui.theme
|
||||
|
||||
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.ui.platform.LocalContext
|
||||
|
||||
private val DarkColorScheme = darkColorScheme(
|
||||
primary = Amber400,
|
||||
onPrimary = BlueGray950,
|
||||
primaryContainer = BlueGray700,
|
||||
onPrimaryContainer = BlueGray100,
|
||||
secondary = BlueGray400,
|
||||
onSecondary = BlueGray100,
|
||||
secondaryContainer = BlueGray800,
|
||||
onSecondaryContainer = BlueGray200,
|
||||
tertiary = Amber300,
|
||||
onTertiary = BlueGray950,
|
||||
background = BlueGray950,
|
||||
onBackground = BlueGray100,
|
||||
surface = BlueGray900,
|
||||
onSurface = BlueGray100,
|
||||
surfaceVariant = BlueGray800,
|
||||
onSurfaceVariant = BlueGray300,
|
||||
outline = BlueGray600,
|
||||
outlineVariant = BlueGray700
|
||||
)
|
||||
|
||||
private val LightColorScheme = lightColorScheme(
|
||||
primary = Amber500,
|
||||
onPrimary = BlueGray900,
|
||||
primaryContainer = Amber300,
|
||||
onPrimaryContainer = BlueGray900,
|
||||
secondary = BlueGray600,
|
||||
onSecondary = BlueGray100,
|
||||
secondaryContainer = BlueGray200,
|
||||
onSecondaryContainer = BlueGray800,
|
||||
tertiary = Amber400,
|
||||
onTertiary = BlueGray900,
|
||||
background = BlueGray100,
|
||||
onBackground = BlueGray900,
|
||||
surface = BlueGray500,
|
||||
onSurface = BlueGray900,
|
||||
surfaceVariant = BlueGray200,
|
||||
onSurfaceVariant = BlueGray700,
|
||||
outline = BlueGray600,
|
||||
outlineVariant = BlueGray400
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun Radio247Theme(content: @Composable () -> Unit) {
|
||||
val dynamicColor = Build.VERSION.SDK_INT >= 31
|
||||
val darkTheme = isSystemInDarkTheme()
|
||||
val colorScheme = when {
|
||||
dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
|
||||
dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
|
||||
darkTheme -> DarkColorScheme
|
||||
else -> LightColorScheme
|
||||
}
|
||||
MaterialTheme(
|
||||
colorScheme = colorScheme,
|
||||
typography = Typography,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
100
app/src/main/java/xyz/cottongin/radio247/ui/theme/Type.kt
Normal file
100
app/src/main/java/xyz/cottongin/radio247/ui/theme/Type.kt
Normal file
@@ -0,0 +1,100 @@
|
||||
package xyz.cottongin.radio247.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
|
||||
|
||||
val Typography = Typography(
|
||||
displayLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 57.sp,
|
||||
lineHeight = 64.sp
|
||||
),
|
||||
displayMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 45.sp,
|
||||
lineHeight = 52.sp
|
||||
),
|
||||
displaySmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 36.sp,
|
||||
lineHeight = 44.sp
|
||||
),
|
||||
headlineLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 32.sp,
|
||||
lineHeight = 40.sp
|
||||
),
|
||||
headlineMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 28.sp,
|
||||
lineHeight = 36.sp
|
||||
),
|
||||
headlineSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 24.sp,
|
||||
lineHeight = 32.sp
|
||||
),
|
||||
titleLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 22.sp,
|
||||
lineHeight = 28.sp
|
||||
),
|
||||
titleMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp
|
||||
),
|
||||
titleSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp
|
||||
),
|
||||
bodyLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 16.sp,
|
||||
lineHeight = 24.sp
|
||||
),
|
||||
bodyMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp
|
||||
),
|
||||
bodySmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Normal,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp
|
||||
),
|
||||
labelLarge = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 14.sp,
|
||||
lineHeight = 20.sp
|
||||
),
|
||||
labelMedium = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 12.sp,
|
||||
lineHeight = 16.sp
|
||||
),
|
||||
labelSmall = TextStyle(
|
||||
fontFamily = FontFamily.Default,
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 11.sp,
|
||||
lineHeight = 16.sp
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user