diff --git a/app/src/main/java/com/dueattendant149/bookreader/reader/ui/theme/Shapes.kt b/app/src/main/java/com/dueattendant149/bookreader/reader/ui/theme/Shapes.kt new file mode 100644 index 0000000..a7e4dda --- /dev/null +++ b/app/src/main/java/com/dueattendant149/bookreader/reader/ui/theme/Shapes.kt @@ -0,0 +1,16 @@ +package org.dueattendant149.bookreader.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Shapes +import androidx.compose.ui.unit.dp + +/** + * Myne-style Material You 3 shape scheme: generous rounded corners. + */ +val AppShapes = Shapes( + extraSmall = RoundedCornerShape(8.dp), + small = RoundedCornerShape(12.dp), + medium = RoundedCornerShape(16.dp), + large = RoundedCornerShape(24.dp), + extraLarge = RoundedCornerShape(32.dp), +) \ No newline at end of file diff --git a/app/src/main/java/com/dueattendant149/bookreader/reader/ui/theme/Theme.kt b/app/src/main/java/com/dueattendant149/bookreader/reader/ui/theme/Theme.kt index 080c31c..daf31e4 100644 --- a/app/src/main/java/com/dueattendant149/bookreader/reader/ui/theme/Theme.kt +++ b/app/src/main/java/com/dueattendant149/bookreader/reader/ui/theme/Theme.kt @@ -178,6 +178,7 @@ fun AppTheme( MaterialTheme( colorScheme = finalColorScheme, typography = appFontFamily?.let { AppTypography.withAppFontFamily(it) } ?: AppTypography, + shapes = AppShapes, content = content ) } diff --git a/app/src/main/java/org/dueattendant149/bookreader/ServerSettingsScreen.kt b/app/src/main/java/org/dueattendant149/bookreader/ServerSettingsScreen.kt index 1f7120c..a668bc2 100644 --- a/app/src/main/java/org/dueattendant149/bookreader/ServerSettingsScreen.kt +++ b/app/src/main/java/org/dueattendant149/bookreader/ServerSettingsScreen.kt @@ -1,21 +1,26 @@ package org.dueattendant149.bookreader.bookshelf +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -23,7 +28,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.text.input.PasswordVisualTransformation -import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -34,13 +38,13 @@ fun ServerSettingsScreen( onBackClick: () -> Unit, ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() - var bookshelfUrl by remember(uiState.bookshelfUrl) { androidx.compose.runtime.mutableStateOf(uiState.bookshelfUrl) } - var absUrl by remember(uiState.absUrl) { androidx.compose.runtime.mutableStateOf(uiState.absUrl) } - var absToken by remember(uiState.absToken) { androidx.compose.runtime.mutableStateOf(uiState.absToken) } + var bookshelfUrl by remember(uiState.bookshelfUrl) { mutableStateOf(uiState.bookshelfUrl) } + var absUrl by remember(uiState.absUrl) { mutableStateOf(uiState.absUrl) } + var absToken by remember(uiState.absToken) { mutableStateOf(uiState.absToken) } Scaffold( topBar = { - TopAppBar( + androidx.compose.material3.CenterAlignedTopAppBar( title = { Text("Server settings") }, navigationIcon = { IconButton(onClick = onBackClick) { @@ -54,61 +58,87 @@ fun ServerSettingsScreen( modifier = Modifier .fillMaxSize() .padding(padding) - .padding(16.dp) + .padding(horizontal = 16.dp, vertical = 8.dp) + .verticalScroll(rememberScrollState()), + verticalArrangement = Arrangement.spacedBy(16.dp) ) { - Text("Bookshelf API") - Spacer(modifier = Modifier.height(8.dp)) - OutlinedTextField( - value = bookshelfUrl, - onValueChange = { - bookshelfUrl = it - viewModel.updateBookshelfUrl(it) - }, - label = { Text("https://books.dueattendant149.org/") }, - singleLine = true, - modifier = Modifier.fillMaxWidth() - ) + SettingsSectionCard(title = "Bookshelf API") { + OutlinedTextField( + value = bookshelfUrl, + onValueChange = { + bookshelfUrl = it + viewModel.updateBookshelfUrl(it) + }, + label = { Text("https://books.dueattendant149.org/") }, + singleLine = true, + modifier = Modifier.fillMaxWidth() + ) + } - Spacer(modifier = Modifier.height(24.dp)) - - Text("Audiobookshelf") - Spacer(modifier = Modifier.height(8.dp)) - OutlinedTextField( - value = absUrl, - onValueChange = { - absUrl = it - viewModel.updateAbsUrl(it) - }, - label = { Text("https://abs.dueattendant149.org/") }, - singleLine = true, - modifier = Modifier.fillMaxWidth() - ) - Spacer(modifier = Modifier.height(8.dp)) - OutlinedTextField( - value = absToken, - onValueChange = { - absToken = it - viewModel.updateAbsToken(it) - }, - label = { Text("Bearer token") }, - singleLine = true, - visualTransformation = PasswordVisualTransformation(), - modifier = Modifier.fillMaxWidth() - ) - - Spacer(modifier = Modifier.height(24.dp)) + SettingsSectionCard(title = "Audiobookshelf") { + OutlinedTextField( + value = absUrl, + onValueChange = { + absUrl = it + viewModel.updateAbsUrl(it) + }, + label = { Text("https://abs.dueattendant149.org/") }, + singleLine = true, + modifier = Modifier.fillMaxWidth() + ) + Spacer(modifier = Modifier.height(12.dp)) + OutlinedTextField( + value = absToken, + onValueChange = { + absToken = it + viewModel.updateAbsToken(it) + }, + label = { Text("Bearer token") }, + singleLine = true, + visualTransformation = PasswordVisualTransformation(), + modifier = Modifier.fillMaxWidth() + ) + } Button( onClick = viewModel::save, - modifier = Modifier.fillMaxWidth() + modifier = Modifier.fillMaxWidth(), + shape = MaterialTheme.shapes.large ) { Text("Save") } if (uiState.saved) { - Spacer(modifier = Modifier.height(8.dp)) - Text("Saved") + Text( + "Saved", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.primary + ) } } } +} + +@Composable +private fun SettingsSectionCard( + title: String, + content: @Composable () -> Unit, +) { + Card( + modifier = Modifier.fillMaxWidth(), + shape = MaterialTheme.shapes.large, + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceContainerLow + ) + ) { + Column(modifier = Modifier.padding(20.dp)) { + Text( + text = title, + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(bottom = 12.dp) + ) + content() + } + } } \ No newline at end of file diff --git a/app/src/main/java/org/dueattendant149/bookreader/bookshelf/BookshelfLibraryScreen.kt b/app/src/main/java/org/dueattendant149/bookreader/bookshelf/BookshelfLibraryScreen.kt index ae9aba7..aa8b896 100644 --- a/app/src/main/java/org/dueattendant149/bookreader/bookshelf/BookshelfLibraryScreen.kt +++ b/app/src/main/java/org/dueattendant149/bookreader/bookshelf/BookshelfLibraryScreen.kt @@ -19,7 +19,6 @@ import androidx.compose.material3.LinearProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -56,7 +55,7 @@ fun BookshelfLibraryScreen( Scaffold( topBar = { - TopAppBar( + androidx.compose.material3.CenterAlignedTopAppBar( title = { Text("Server Library") }, actions = { IconButton(onClick = onOpenSettings) { @@ -145,9 +144,13 @@ private fun LibraryCard( onClick = onClick, modifier = Modifier .fillMaxWidth() - .padding(vertical = 4.dp) + .padding(vertical = 6.dp), + shape = MaterialTheme.shapes.large, + colors = androidx.compose.material3.CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceContainerLow + ) ) { - Column(modifier = Modifier.padding(16.dp)) { + Column(modifier = Modifier.padding(20.dp)) { Text( text = library.name, style = MaterialTheme.typography.titleMedium, @@ -156,7 +159,9 @@ private fun LibraryCard( ) Text( text = "${library.itemCount} items ยท ${library.mediaType}", - style = MaterialTheme.typography.bodySmall + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 4.dp) ) } } @@ -172,9 +177,13 @@ private fun ItemCard( onClick = onClick, modifier = Modifier .fillMaxWidth() - .padding(vertical = 4.dp) + .padding(vertical = 6.dp), + shape = MaterialTheme.shapes.large, + colors = androidx.compose.material3.CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceContainerLow + ) ) { - Column(modifier = Modifier.padding(16.dp)) { + Column(modifier = Modifier.padding(20.dp)) { Text( text = item.title, style = MaterialTheme.typography.titleMedium, @@ -184,16 +193,29 @@ private fun ItemCard( if (item.author.isNotBlank()) { Text( text = item.author, - style = MaterialTheme.typography.bodyMedium + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 4.dp) ) } Text( text = item.type, - style = MaterialTheme.typography.bodySmall + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = 4.dp) ) if (isDownloading) { - LinearProgressIndicator(modifier = Modifier.fillMaxWidth().padding(top = 8.dp)) - Text("Downloading...", style = MaterialTheme.typography.bodySmall) + LinearProgressIndicator( + modifier = Modifier + .fillMaxWidth() + .padding(top = 12.dp), + ) + Text( + "Downloading...", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.primary, + modifier = Modifier.padding(top = 4.dp) + ) } } }