refactor UI components to utilize MaterialTheme for consistent theming

This commit is contained in:
2026-01-20 17:01:28 +01:00
parent 00cf71e65e
commit bcf66fd393
9 changed files with 73 additions and 76 deletions

View File

@@ -176,10 +176,10 @@ fun HomeDrawerFooter (
HomeAvatar( HomeAvatar(
size = 32.dp, size = 32.dp,
borderWidth = 1.dp, borderWidth = 1.dp,
borderColor = Color.White.copy(alpha = 0.1f), borderColor = colors.divider,
backgroundColor = colors.avatarBackground, backgroundColor = colors.avatarBackground,
icon = Icons.Outlined.Person, icon = Icons.Outlined.Person,
iconTint = Color.White iconTint = colors.textPrimary
) )
Column(modifier = Modifier.padding(start = 12.dp) Column(modifier = Modifier.padding(start = 12.dp)
.clickable {viewModel.logout()}) { .clickable {viewModel.logout()}) {

View File

@@ -29,7 +29,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
@@ -112,14 +111,14 @@ fun ContinueWatchingCard(
Box( Box(
modifier = Modifier modifier = Modifier
.matchParentSize() .matchParentSize()
.background(Color.Black.copy(alpha = 0.2f)) .background(colors.textPrimary.copy(alpha = 0.2f))
) )
Box( Box(
modifier = Modifier modifier = Modifier
.align(Alignment.BottomStart) .align(Alignment.BottomStart)
.fillMaxWidth() .fillMaxWidth()
.height(4.dp) .height(4.dp)
.background(Color.White.copy(alpha = 0.2f)) .background(colors.textPrimary.copy(alpha = 0.2f))
) { ) {
Box( Box(
modifier = Modifier modifier = Modifier

View File

@@ -19,7 +19,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@@ -41,7 +40,7 @@ fun HomeTopBar(
borderColor = colors.avatarBorder, borderColor = colors.avatarBorder,
backgroundColor = colors.avatarBackground, backgroundColor = colors.avatarBackground,
icon = Icons.Outlined.Person, icon = Icons.Outlined.Person,
iconTint = Color.White iconTint = colors.onPrimary
) )
} }
) { ) {

View File

@@ -6,11 +6,11 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.app.home.ui.PosterItem import hu.bbara.purefin.app.home.ui.PosterItem
@@ -44,7 +44,7 @@ fun LibraryPosterGrid(
contentPadding = PaddingValues(16.dp), contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp), horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = modifier.background(Color.Black) modifier = modifier.background(MaterialTheme.colorScheme.background)
) { ) {
items(libraryItems) { item -> items(libraryItems) { item ->
PosterCard( PosterCard(
@@ -53,4 +53,4 @@ fun LibraryPosterGrid(
) )
} }
} }
} }

View File

@@ -7,6 +7,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
@@ -30,15 +31,12 @@ fun PurefinComplexTextField(
trailingIcon: ImageVector? = null, trailingIcon: ImageVector? = null,
visualTransformation: VisualTransformation = VisualTransformation.None visualTransformation: VisualTransformation = VisualTransformation.None
) { ) {
val JellyfinOrange = Color(0xFFBD542E) val scheme = MaterialTheme.colorScheme
val JellyfinBg = Color(0xFF141517)
val JellyfinSurface = Color(0xFF1E2124)
val TextSecondary = Color(0xFF9EA3A8)
Column(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.fillMaxWidth()) {
Text( Text(
text = label, text = label,
color = Color.White, color = scheme.onBackground,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 14.sp, fontSize = 14.sp,
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier.padding(bottom = 8.dp)
@@ -49,22 +47,22 @@ fun PurefinComplexTextField(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(12.dp)), .clip(RoundedCornerShape(12.dp)),
placeholder = { Text(placeholder, color = TextSecondary) }, placeholder = { Text(placeholder, color = scheme.onSurfaceVariant) },
leadingIcon = if (leadingIcon != null) { leadingIcon = if (leadingIcon != null) {
{ Icon(leadingIcon, contentDescription = null, tint = TextSecondary) } { Icon(leadingIcon, contentDescription = null, tint = scheme.onSurfaceVariant) }
} else null, } else null,
trailingIcon = if (trailingIcon != null) { trailingIcon = if (trailingIcon != null) {
{ Icon(Icons.Default.Visibility, contentDescription = null, tint = TextSecondary) } { Icon(Icons.Default.Visibility, contentDescription = null, tint = scheme.onSurfaceVariant) }
} else null, } else null,
visualTransformation = visualTransformation, visualTransformation = visualTransformation,
colors = TextFieldDefaults.colors( colors = TextFieldDefaults.colors(
focusedContainerColor = JellyfinSurface, focusedContainerColor = scheme.surfaceVariant,
unfocusedContainerColor = JellyfinSurface, unfocusedContainerColor = scheme.surfaceVariant,
focusedIndicatorColor = Color.Transparent, focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent,
cursorColor = JellyfinOrange, cursorColor = scheme.primary,
focusedTextColor = Color.White, focusedTextColor = scheme.onSurface,
unfocusedTextColor = Color.White unfocusedTextColor = scheme.onSurface
)) ))
} }
} }

View File

@@ -8,6 +8,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.Visibility
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
@@ -32,17 +33,14 @@ fun PurefinPasswordField(
placeholder: String, placeholder: String,
leadingIcon: ImageVector, leadingIcon: ImageVector,
) { ) {
val JellyfinOrange = Color(0xFFBD542E) val scheme = MaterialTheme.colorScheme
val JellyfinBg = Color(0xFF141517)
val JellyfinSurface = Color(0xFF1E2124)
val TextSecondary = Color(0xFF9EA3A8)
val showField = remember { mutableStateOf(false) } val showField = remember { mutableStateOf(false) }
Column(modifier = Modifier.fillMaxWidth()) { Column(modifier = Modifier.fillMaxWidth()) {
Text( Text(
text = label, text = label,
color = Color.White, color = scheme.onBackground,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
fontSize = 14.sp, fontSize = 14.sp,
modifier = Modifier.padding(bottom = 8.dp) modifier = Modifier.padding(bottom = 8.dp)
@@ -53,26 +51,26 @@ fun PurefinPasswordField(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.clip(RoundedCornerShape(12.dp)), .clip(RoundedCornerShape(12.dp)),
placeholder = { Text(placeholder, color = TextSecondary) }, placeholder = { Text(placeholder, color = scheme.onSurfaceVariant) },
leadingIcon = { Icon(leadingIcon, contentDescription = null, tint = TextSecondary) }, leadingIcon = { Icon(leadingIcon, contentDescription = null, tint = scheme.onSurfaceVariant) },
trailingIcon = trailingIcon =
{ {
IconButton( IconButton(
onClick = { showField.value = !showField.value }, onClick = { showField.value = !showField.value },
) { ) {
Icon(Icons.Default.Visibility, contentDescription = null, tint = TextSecondary) Icon(Icons.Default.Visibility, contentDescription = null, tint = scheme.onSurfaceVariant)
} }
}, },
visualTransformation = if (showField.value) VisualTransformation.None else PasswordVisualTransformation(), visualTransformation = if (showField.value) VisualTransformation.None else PasswordVisualTransformation(),
colors = TextFieldDefaults.colors( colors = TextFieldDefaults.colors(
focusedContainerColor = JellyfinSurface, focusedContainerColor = scheme.surfaceVariant,
unfocusedContainerColor = JellyfinSurface, unfocusedContainerColor = scheme.surfaceVariant,
focusedIndicatorColor = Color.Transparent, focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent, unfocusedIndicatorColor = Color.Transparent,
cursorColor = JellyfinOrange, cursorColor = scheme.primary,
focusedTextColor = Color.White, focusedTextColor = scheme.onSurface,
unfocusedTextColor = Color.White unfocusedTextColor = scheme.onSurface
) )
) )
} }
} }

View File

@@ -22,6 +22,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Movie import androidx.compose.material.icons.outlined.Movie
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -39,11 +40,12 @@ import androidx.compose.ui.unit.sp
fun PurefinWaitingScreen( fun PurefinWaitingScreen(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val accentColor = Color(0xFFBD542E) val scheme = MaterialTheme.colorScheme
val backgroundColor = Color(0xFF141517) val accentColor = scheme.primary
val surfaceColor = Color(0xFF1E2124) val backgroundColor = scheme.background
val textPrimary = Color.White val surfaceColor = scheme.surface
val textSecondary = Color(0xFF9EA3A8) val textPrimary = scheme.onSurface
val textSecondary = scheme.onSurfaceVariant
val transition = rememberInfiniteTransition(label = "waiting-pulse") val transition = rememberInfiniteTransition(label = "waiting-pulse")
val pulseScale = transition.animateFloat( val pulseScale = transition.animateFloat(
@@ -112,7 +114,7 @@ fun PurefinWaitingScreen(
Icon( Icon(
imageVector = Icons.Outlined.Movie, imageVector = Icons.Outlined.Movie,
contentDescription = null, contentDescription = null,
tint = Color.White, tint = scheme.onPrimary,
modifier = Modifier.size(40.dp) modifier = Modifier.size(40.dp)
) )
} }
@@ -121,13 +123,13 @@ fun PurefinWaitingScreen(
Spacer(modifier = Modifier.height(20.dp)) Spacer(modifier = Modifier.height(20.dp))
Text( Text(
text = "Connecting", text = "Just a moment",
color = textPrimary, color = textPrimary,
fontSize = 20.sp, fontSize = 20.sp,
fontWeight = FontWeight.Bold fontWeight = FontWeight.Bold
) )
Text( Text(
text = "Summoning the media gnomes...", text = "I am doing all I can...",
color = textSecondary, color = textSecondary,
fontSize = 14.sp fontSize = 14.sp
) )

View File

@@ -21,6 +21,7 @@ import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Storage import androidx.compose.material.icons.filled.Storage
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -32,7 +33,6 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@@ -49,9 +49,7 @@ fun LoginScreen(
viewModel: LoginViewModel = hiltViewModel(), viewModel: LoginViewModel = hiltViewModel(),
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val JellyfinOrange = Color(0xFFBD542E) val scheme = MaterialTheme.colorScheme
val JellyfinBg = Color(0xFF141517)
val TextSecondary = Color(0xFF9EA3A8)
// Observe ViewModel state // Observe ViewModel state
val serverUrl by viewModel.url.collectAsState() val serverUrl by viewModel.url.collectAsState()
@@ -67,7 +65,7 @@ fun LoginScreen(
Column( Column(
modifier = modifier modifier = modifier
.fillMaxSize() .fillMaxSize()
.background(JellyfinBg) .background(scheme.background)
.padding(24.dp) .padding(24.dp)
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
@@ -78,27 +76,27 @@ fun LoginScreen(
Box( Box(
modifier = Modifier modifier = Modifier
.size(100.dp) .size(100.dp)
.background(JellyfinOrange, RoundedCornerShape(24.dp)), .background(scheme.primary, RoundedCornerShape(24.dp)),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Icon( Icon(
imageVector = Icons.Default.Movie, // Replace with actual logo resource imageVector = Icons.Default.Movie, // Replace with actual logo resource
contentDescription = "Logo", contentDescription = "Logo",
tint = Color.White, tint = scheme.onPrimary,
modifier = Modifier.size(60.dp) modifier = Modifier.size(60.dp)
) )
} }
Text( Text(
text = "Jellyfin", text = "Jellyfin",
color = Color.White, color = scheme.onBackground,
fontSize = 32.sp, fontSize = 32.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = Modifier.padding(top = 16.dp) modifier = Modifier.padding(top = 16.dp)
) )
Text( Text(
text = "PERSONAL MEDIA SYSTEM", text = "PERSONAL MEDIA SYSTEM",
color = TextSecondary, color = scheme.onSurfaceVariant,
fontSize = 12.sp, fontSize = 12.sp,
letterSpacing = 2.sp letterSpacing = 2.sp
) )
@@ -108,14 +106,14 @@ fun LoginScreen(
// Form Section // Form Section
Text( Text(
text = "Connect to Server", text = "Connect to Server",
color = Color.White, color = scheme.onBackground,
fontSize = 22.sp, fontSize = 22.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
modifier = Modifier.align(Alignment.Start) modifier = Modifier.align(Alignment.Start)
) )
Text( Text(
text = "Enter your details to access your library", text = "Enter your details to access your library",
color = TextSecondary, color = scheme.onSurfaceVariant,
fontSize = 14.sp, fontSize = 14.sp,
modifier = Modifier modifier = Modifier
.align(Alignment.Start) .align(Alignment.Start)
@@ -175,12 +173,12 @@ fun LoginScreen(
) { ) {
TextButton(onClick = {}) { TextButton(onClick = {}) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Default.Search, contentDescription = null, tint = TextSecondary, modifier = Modifier.size(18.dp)) Icon(Icons.Default.Search, contentDescription = null, tint = scheme.onSurfaceVariant, modifier = Modifier.size(18.dp))
Text(" Discover Servers", color = TextSecondary) Text(" Discover Servers", color = scheme.onSurfaceVariant)
} }
} }
TextButton(onClick = {}) { TextButton(onClick = {}) {
Text("Need Help?", color = TextSecondary) Text("Need Help?", color = scheme.onSurfaceVariant)
} }
} }

View File

@@ -8,14 +8,15 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.media3.ui.PlayerView import androidx.media3.ui.PlayerView
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import hu.bbara.purefin.player.viewmodel.PlayerViewModel import hu.bbara.purefin.player.viewmodel.PlayerViewModel
import hu.bbara.purefin.ui.theme.PurefinTheme
@AndroidEntryPoint @AndroidEntryPoint
class PlayerActivity : ComponentActivity() { class PlayerActivity : ComponentActivity() {
@@ -23,22 +24,24 @@ class PlayerActivity : ComponentActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContent { setContent {
val viewModel = hiltViewModel<PlayerViewModel>() PurefinTheme {
Box( val viewModel = hiltViewModel<PlayerViewModel>()
modifier = Modifier.fillMaxSize() Box(
.background(Color.Black) modifier = Modifier.fillMaxSize()
) { .background(MaterialTheme.colorScheme.background)
AndroidView( ) {
factory = { context -> AndroidView(
PlayerView(context).also { factory = { context ->
it.player = viewModel.player PlayerView(context).also {
} it.player = viewModel.player
}, }
modifier = Modifier.fillMaxHeight() },
.align(Alignment.Center) modifier = Modifier.fillMaxHeight()
.aspectRatio(16f / 9f) .align(Alignment.Center)
.aspectRatio(16f / 9f)
) )
}
} }
} }
} }