diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/component/AccentColorPicker.kt b/Android/app/src/main/java/com/droidspaces/app/ui/component/AccentColorPicker.kt index 62e90968..1868fbda 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/component/AccentColorPicker.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/component/AccentColorPicker.kt @@ -9,8 +9,10 @@ import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp +import com.droidspaces.app.R import com.droidspaces.app.ui.theme.ThemePalette /** @@ -37,7 +39,7 @@ fun AccentColorPicker( }, headlineContent = { Text( - text = "Accent Color", + text = stringResource(R.string.accent_color), style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold ) diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/component/ContainerCard.kt b/Android/app/src/main/java/com/droidspaces/app/ui/component/ContainerCard.kt index dab97359..a349363c 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/component/ContainerCard.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/component/ContainerCard.kt @@ -199,7 +199,7 @@ fun ContainerCard( .fillMaxWidth() .padding(horizontal = 4.dp), color = MaterialTheme.colorScheme.surfaceContainerHigh, // Depth for secondary actions - shape = RoundedCornerShape(12.dp), + shape = RoundedCornerShape(20.dp), border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.2f)) ) { Row(modifier = Modifier.fillMaxWidth().padding(4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp)) { diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/component/DsDropdown.kt b/Android/app/src/main/java/com/droidspaces/app/ui/component/DsDropdown.kt index 74adf9b6..bde05567 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/component/DsDropdown.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/component/DsDropdown.kt @@ -1,5 +1,7 @@ package com.droidspaces.app.ui.component +import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape @@ -8,6 +10,9 @@ import androidx.compose.material.icons.filled.Check import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.luminance import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.font.FontWeight @@ -30,9 +35,9 @@ fun DsDropdown( var expanded by remember { mutableStateOf(false) } val focusManager = LocalFocusManager.current - val fieldShape = RoundedCornerShape(16.dp) + val fieldShape = RoundedCornerShape(20.dp) val fieldColors = OutlinedTextFieldDefaults.colors( - unfocusedBorderColor = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f), + unfocusedBorderColor = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f), focusedBorderColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.8f), unfocusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow, focusedContainerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f) @@ -63,32 +68,52 @@ fun DsDropdown( .menuAnchor() .fillMaxWidth() ) - ExposedDropdownMenu( - expanded = expanded, - onDismissRequest = { - expanded = false - focusManager.clearFocus() - } + val isDark = MaterialTheme.colorScheme.background.luminance() < 0.5f + val dropdownColor = if (isDark) MaterialTheme.colorScheme.surfaceContainerHigh else MaterialTheme.colorScheme.surfaceContainer + + MaterialTheme( + colorScheme = MaterialTheme.colorScheme.copy( + surface = dropdownColor, + surfaceContainer = dropdownColor, + surfaceTint = Color.Transparent + ), + shapes = MaterialTheme.shapes.copy( + extraSmall = RoundedCornerShape(20.dp) + ) ) { - options.forEach { option -> - DropdownMenuItem( - text = { Text(displayName(option), fontWeight = FontWeight.Medium) }, - onClick = { - onSelect(option) - expanded = false - focusManager.clearFocus() - }, - leadingIcon = if (option == selected) { - { - Icon( - Icons.Default.Check, - contentDescription = null, - modifier = Modifier.size(18.dp), - tint = MaterialTheme.colorScheme.primary - ) - } - } else null - ) + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { + expanded = false + focusManager.clearFocus() + }, + modifier = Modifier + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f), + shape = RoundedCornerShape(20.dp) + ) + ) { + options.forEach { option -> + DropdownMenuItem( + text = { Text(displayName(option), fontWeight = FontWeight.Medium) }, + onClick = { + onSelect(option) + expanded = false + focusManager.clearFocus() + }, + leadingIcon = if (option == selected) { + { + Icon( + Icons.Default.Check, + contentDescription = null, + modifier = Modifier.size(18.dp), + tint = MaterialTheme.colorScheme.primary + ) + } + } else null + ) + } } } } diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/component/HelpCard.kt b/Android/app/src/main/java/com/droidspaces/app/ui/component/HelpCard.kt index ac53ca4f..ebcbb466 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/component/HelpCard.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/component/HelpCard.kt @@ -2,14 +2,10 @@ package com.droidspaces.app.ui.component import android.content.Intent import android.net.Uri -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.ripple.rememberRipple import androidx.compose.material3.* import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -26,20 +22,12 @@ fun HelpCard( val url = context.getString(R.string.help_card_url) val cardShape = RoundedCornerShape(20.dp) - val interactionSource = remember { MutableInteractionSource() } - Surface( - modifier = modifier - .fillMaxWidth() - .clip(cardShape) - .clickable( - interactionSource = interactionSource, - indication = rememberRipple(bounded = true), - onClick = { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - context.startActivity(intent) - } - ), + onClick = { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + context.startActivity(intent) + }, + modifier = modifier.fillMaxWidth(), shape = cardShape, color = MaterialTheme.colorScheme.surfaceContainer, border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/component/SettingsRowCard.kt b/Android/app/src/main/java/com/droidspaces/app/ui/component/SettingsRowCard.kt index 2eaaeb65..432ebc68 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/component/SettingsRowCard.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/component/SettingsRowCard.kt @@ -33,7 +33,7 @@ fun SettingsRowCard( enabled = enabled, shape = RoundedCornerShape(20.dp), color = MaterialTheme.colorScheme.surfaceContainerHigh, - border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)) + border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) ) { Row( modifier = Modifier diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/component/SwitchItem.kt b/Android/app/src/main/java/com/droidspaces/app/ui/component/SwitchItem.kt index b94134ff..f0948293 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/component/SwitchItem.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/component/SwitchItem.kt @@ -24,6 +24,7 @@ fun SwitchItem( val stateAlpha = Modifier.alpha(if (enabled) 1f else 0.5f) ListItem( + colors = ListItemDefaults.colors(containerColor = androidx.compose.ui.graphics.Color.Transparent), modifier = Modifier .toggleable( value = checked, @@ -52,7 +53,7 @@ fun SwitchItem( Switch( checked = checked, enabled = enabled, - onCheckedChange = onCheckedChange, + onCheckedChange = null, interactionSource = interactionSource, colors = SwitchDefaults.colors( checkedThumbColor = MaterialTheme.colorScheme.onPrimary, diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/component/ToggleCard.kt b/Android/app/src/main/java/com/droidspaces/app/ui/component/ToggleCard.kt index 8ba8a3c6..d18a11e6 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/component/ToggleCard.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/component/ToggleCard.kt @@ -34,7 +34,7 @@ fun ToggleCard( enabled = enabled, shape = RoundedCornerShape(20.dp), color = MaterialTheme.colorScheme.surfaceContainerHigh, - border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f)) + border = androidx.compose.foundation.BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) ) { Row( modifier = Modifier @@ -81,7 +81,7 @@ fun ToggleCard( } Switch( checked = checked, - onCheckedChange = onCheckedChange, + onCheckedChange = null, enabled = enabled, colors = SwitchDefaults.colors( checkedThumbColor = MaterialTheme.colorScheme.onPrimary, diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/OpenRCScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/OpenRCScreen.kt index aa856534..248eaacf 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/OpenRCScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/OpenRCScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.luminance import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily @@ -401,12 +402,34 @@ private fun OpenRCServiceCard( ) { Box(contentAlignment = Alignment.Center) { Icon(Icons.Default.MoreVert, null, tint = MaterialTheme.colorScheme.onSurfaceVariant) } } - DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) { - DropdownMenuItem( - text = { Text(context.getString(R.string.restart_service)) }, - leadingIcon = { Icon(Icons.Default.Refresh, null) }, - onClick = { showMenu = false; onAction(context.getString(R.string.restart_service)) { ContainerOpenRCManager.restartService(containerName, service.name) } } + val isDark = MaterialTheme.colorScheme.background.luminance() < 0.5f + val dropdownColor = if (isDark) MaterialTheme.colorScheme.surfaceContainerHigh else MaterialTheme.colorScheme.surfaceContainer + MaterialTheme( + colorScheme = MaterialTheme.colorScheme.copy( + surface = dropdownColor, + surfaceContainer = dropdownColor, + surfaceTint = Color.Transparent + ), + shapes = MaterialTheme.shapes.copy( + extraSmall = RoundedCornerShape(20.dp) ) + ) { + DropdownMenu( + expanded = showMenu, + onDismissRequest = { showMenu = false }, + modifier = Modifier + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f), + shape = RoundedCornerShape(20.dp) + ) + ) { + DropdownMenuItem( + text = { Text(context.getString(R.string.restart_service)) }, + leadingIcon = { Icon(Icons.Default.Refresh, null) }, + onClick = { showMenu = false; onAction(context.getString(R.string.restart_service)) { ContainerOpenRCManager.restartService(containerName, service.name) } } + ) + } } } } diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/ProcdScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/ProcdScreen.kt index 2d5be973..0c30b6d3 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/ProcdScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/ProcdScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.luminance import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily @@ -404,19 +405,41 @@ private fun ProcdServiceCard( ) { Box(contentAlignment = Alignment.Center) { Icon(Icons.Default.MoreVert, null, tint = MaterialTheme.colorScheme.onSurfaceVariant) } } - DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) { - DropdownMenuItem( - text = { Text(context.getString(R.string.restart_service)) }, - leadingIcon = { Icon(Icons.Default.Refresh, null) }, - onClick = { showMenu = false; onAction(context.getString(R.string.restart_service)) { ContainerProcdManager.restartService(containerName, service.name) } } - ) - DropdownMenuItem( - text = { Text(context.getString(R.string.reload_service)) }, - leadingIcon = { Icon(Icons.Default.Refresh, null) }, - onClick = { showMenu = false; onAction(context.getString(R.string.reload_service)) { ContainerProcdManager.reloadService(containerName, service.name) } } - ) + val isDark = MaterialTheme.colorScheme.background.luminance() < 0.5f + val dropdownColor = if (isDark) MaterialTheme.colorScheme.surfaceContainerHigh else MaterialTheme.colorScheme.surfaceContainer + MaterialTheme( + colorScheme = MaterialTheme.colorScheme.copy( + surface = dropdownColor, + surfaceContainer = dropdownColor, + surfaceTint = Color.Transparent + ), + shapes = MaterialTheme.shapes.copy( + extraSmall = RoundedCornerShape(20.dp) + ) + ) { + DropdownMenu( + expanded = showMenu, + onDismissRequest = { showMenu = false }, + modifier = Modifier + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f), + shape = RoundedCornerShape(20.dp) + ) + ) { + DropdownMenuItem( + text = { Text(context.getString(R.string.restart_service)) }, + leadingIcon = { Icon(Icons.Default.Refresh, null) }, + onClick = { showMenu = false; onAction(context.getString(R.string.restart_service)) { ContainerProcdManager.restartService(containerName, service.name) } } + ) + DropdownMenuItem( + text = { Text(context.getString(R.string.reload_service)) }, + leadingIcon = { Icon(Icons.Default.Refresh, null) }, + onClick = { showMenu = false; onAction(context.getString(R.string.reload_service)) { ContainerProcdManager.reloadService(containerName, service.name) } } + ) + } + } } - } } } } diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/SettingsScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/SettingsScreen.kt index fb78bce1..786c7e75 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/SettingsScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/SettingsScreen.kt @@ -163,13 +163,20 @@ fun SettingsScreen( // Backend Reinstallation Section Text( text = context.getString(R.string.backend_section), - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.SemiBold, - modifier = Modifier.padding(horizontal = 16.dp, vertical = 16.dp), + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(start = 24.dp, bottom = 8.dp, top = 8.dp), color = MaterialTheme.colorScheme.primary ) - ListItem( + Surface( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + shape = RoundedCornerShape(24.dp), + color = if (darkTheme) MaterialTheme.colorScheme.surfaceContainerHigh else MaterialTheme.colorScheme.surfaceContainer, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) + ) { + Column { + ListItem(colors = ListItemDefaults.colors(containerColor = Color.Transparent), leadingContent = { Icon( imageVector = Icons.Default.Build, @@ -215,6 +222,8 @@ fun SettingsScreen( ) ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) + // Daemon Mode Toggle SwitchItem( icon = Icons.Default.SettingsBackupRestore, @@ -227,6 +236,8 @@ fun SettingsScreen( } ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) + val isBackendAvailable = appStateViewModel.isBackendAvailable SwitchItem( icon = Icons.Default.Link, @@ -246,8 +257,10 @@ fun SettingsScreen( } ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) + // Auto Boot Priority - clickable to navigate to the boot-order screen - ListItem( + ListItem(colors = ListItemDefaults.colors(containerColor = Color.Transparent), leadingContent = { Icon( imageVector = Icons.Default.LowPriority, @@ -273,23 +286,34 @@ fun SettingsScreen( modifier = Modifier.clickable { onNavigateToAutoBootPriority() } ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) + // Requirements Card - clickable to navigate to requirements page RequirementsCard( onNavigateToRequirements = onNavigateToRequirements ) + } + } - HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) + Spacer(modifier = Modifier.height(8.dp)) // Theme Section Text( text = context.getString(R.string.appearance_section), - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.SemiBold, - modifier = Modifier.padding(horizontal = 16.dp, vertical = 16.dp), + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(start = 24.dp, bottom = 8.dp, top = 8.dp), color = MaterialTheme.colorScheme.primary ) - // Language Picker + Surface( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + shape = RoundedCornerShape(24.dp), + color = if (darkTheme) MaterialTheme.colorScheme.surfaceContainerHigh else MaterialTheme.colorScheme.surfaceContainer, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) + ) { + Column { + // Language Picker val currentLanguageDisplay = remember(currentAppLocale) { val currentLanguageCode = LocaleHelper.getCurrentLanguageCode() if (currentLanguageCode == "system") { @@ -302,7 +326,7 @@ fun SettingsScreen( } } - ListItem( + ListItem(colors = ListItemDefaults.colors(containerColor = Color.Transparent), leadingContent = { Icon( imageVector = Icons.Default.Translate, @@ -324,6 +348,8 @@ fun SettingsScreen( } ) + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) + // Follow System Theme SwitchItem( icon = Icons.Default.BrightnessAuto, @@ -337,6 +363,7 @@ fun SettingsScreen( // Dark Theme (only shown when not following system) if (!followSystemTheme) { + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) SwitchItem( icon = Icons.Default.DarkMode, title = context.getString(R.string.dark_theme), @@ -350,6 +377,7 @@ fun SettingsScreen( // AMOLED Mode (shown when followSystemTheme is true OR manual darkTheme is true) if (followSystemTheme || darkTheme) { + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) SwitchItem( icon = Icons.Default.RadioButtonUnchecked, title = context.getString(R.string.amoled_mode), @@ -365,6 +393,7 @@ fun SettingsScreen( // Use Dynamic Color (Monet theming) - Only show on Android 12+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) SwitchItem( icon = Icons.Default.ColorLens, title = context.getString(R.string.dynamic_color), @@ -380,6 +409,7 @@ fun SettingsScreen( // Accent Color Picker - show when dynamic color is off, // or always show on devices below Android 12 (no dynamic color support) if (!useDynamicColor || android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.S) { + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) AccentColorPicker( selectedPalette = themeState.themePalette, isDarkTheme = darkTheme, @@ -388,11 +418,28 @@ fun SettingsScreen( } ) } + } + } - HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) + Spacer(modifier = Modifier.height(8.dp)) - // Bug Report Section - ListItem( + // Debugging Section + Text( + text = context.getString(R.string.debugging_section), + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(start = 24.dp, bottom = 8.dp, top = 8.dp), + color = MaterialTheme.colorScheme.primary + ) + + Surface( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + + shape = RoundedCornerShape(24.dp), + color = if (darkTheme) MaterialTheme.colorScheme.surfaceContainerHigh else MaterialTheme.colorScheme.surfaceContainer, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) + ) { + ListItem(colors = ListItemDefaults.colors(containerColor = Color.Transparent), leadingContent = { Icon( imageVector = Icons.Default.BugReport, @@ -436,20 +483,27 @@ fun SettingsScreen( Modifier } ) - ) + ) + } - HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp)) + Spacer(modifier = Modifier.height(8.dp)) // About Section Text( text = context.getString(R.string.about_section), - style = MaterialTheme.typography.titleMedium, - fontWeight = FontWeight.SemiBold, - modifier = Modifier.padding(horizontal = 16.dp, vertical = 16.dp), + style = MaterialTheme.typography.titleSmall, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(start = 24.dp, bottom = 8.dp, top = 8.dp), color = MaterialTheme.colorScheme.primary ) - ListItem( + Surface( + modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp), + shape = RoundedCornerShape(24.dp), + color = if (darkTheme) MaterialTheme.colorScheme.surfaceContainerHigh else MaterialTheme.colorScheme.surfaceContainer, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) + ) { + ListItem(colors = ListItemDefaults.colors(containerColor = Color.Transparent), leadingContent = { Icon( imageVector = Icons.Default.Info, @@ -469,9 +523,10 @@ fun SettingsScreen( modifier = Modifier.clickable { showAboutDialog = true } - ) + ) + } - Spacer(modifier = Modifier.height(16.dp)) + Spacer(modifier = Modifier.height(24.dp)) } } @@ -523,7 +578,7 @@ private fun AboutDialog(onDismiss: () -> Unit) { Column( modifier = Modifier .fillMaxSize() - .padding(24.dp) + .padding(top = 24.dp, start = 24.dp, end = 24.dp, bottom = 8.dp) ) { // Title Text( @@ -545,120 +600,126 @@ private fun AboutDialog(onDismiss: () -> Unit) { style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant ) - Spacer(modifier = Modifier.height(8.dp)) - HorizontalDivider() - Spacer(modifier = Modifier.height(4.dp)) Text( text = context.getString(R.string.developers), style = MaterialTheme.typography.titleSmall, fontWeight = FontWeight.SemiBold, color = MaterialTheme.colorScheme.primary ) - // Developer 1 - Row( - modifier = Modifier - .fillMaxWidth() - .clickable { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/ravindu644")) - context.startActivity(intent) - }, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(8.dp) + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(24.dp), + color = MaterialTheme.colorScheme.surfaceContainerHigh, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) ) { - Icon( - imageVector = Icons.Default.Person, - contentDescription = null, - modifier = Modifier.size(20.dp), - tint = MaterialTheme.colorScheme.onSurfaceVariant - ) - Column(modifier = Modifier.weight(1f)) { - Text( - text = context.getString(R.string.developer_ravindu644), - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Medium - ) - Text( - text = context.getString(R.string.developer_ravindu644_role), - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) + Column { + // Developer 1 + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/ravindu644")) + context.startActivity(intent) + } + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Icon( + imageVector = Icons.Default.Person, + contentDescription = null, + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + Column(modifier = Modifier.weight(1f)) { + Text( + text = context.getString(R.string.developer_ravindu644), + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium + ) + Text( + text = context.getString(R.string.developer_ravindu644_role), + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant + ) + } + Icon( + imageVector = Icons.AutoMirrored.Filled.OpenInNew, + contentDescription = context.getString(R.string.github), + modifier = Modifier.size(18.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f) + ) + } + + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) + + // Telegram channel + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/Droidspaces")) + context.startActivity(intent) + } + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Icon( + painter = painterResource(id = R.drawable.ic_telegram), + contentDescription = null, + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colorScheme.primary + ) + Text( + text = context.getString(R.string.telegram_channel), + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium, + modifier = Modifier.weight(1f) + ) + Icon( + imageVector = Icons.AutoMirrored.Filled.OpenInNew, + contentDescription = context.getString(R.string.telegram_channel), + modifier = Modifier.size(18.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f) + ) + } + + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) + + // Source Code row + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/ravindu644/Droidspaces-OSS")) + context.startActivity(intent) + } + .padding(horizontal = 16.dp, vertical = 12.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp) + ) { + Icon( + imageVector = Icons.Default.Code, + contentDescription = null, + modifier = Modifier.size(24.dp), + tint = MaterialTheme.colorScheme.primary + ) + Text( + text = context.getString(R.string.source_code), + style = MaterialTheme.typography.bodyMedium, + fontWeight = FontWeight.Medium, + modifier = Modifier.weight(1f) + ) + Icon( + imageVector = Icons.AutoMirrored.Filled.OpenInNew, + contentDescription = context.getString(R.string.source_code), + modifier = Modifier.size(18.dp), + tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f) + ) + } } - Icon( - imageVector = Icons.AutoMirrored.Filled.OpenInNew, - contentDescription = context.getString(R.string.github), - modifier = Modifier.size(18.dp), - tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f) - ) - } - Spacer(modifier = Modifier.height(4.dp)) - HorizontalDivider() - Spacer(modifier = Modifier.height(4.dp)) - // Telegram channel - Row( - modifier = Modifier - .fillMaxWidth() - .clickable { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://t.me/Droidspaces")) - context.startActivity(intent) - }, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - Icon( - painter = painterResource(id = R.drawable.ic_telegram), - contentDescription = null, - modifier = Modifier.size(24.dp), - tint = MaterialTheme.colorScheme.primary - ) - Text( - text = context.getString(R.string.telegram_channel), - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Medium, - modifier = Modifier.weight(1f) - ) - Icon( - imageVector = Icons.AutoMirrored.Filled.OpenInNew, - contentDescription = context.getString(R.string.telegram_channel), - modifier = Modifier.size(18.dp), - tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f) - ) - } - Spacer(modifier = Modifier.height(4.dp)) - HorizontalDivider() - Spacer(modifier = Modifier.height(4.dp)) - // Source Code row - Row( - modifier = Modifier - .fillMaxWidth() - .clickable { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/ravindu644/Droidspaces-OSS")) - context.startActivity(intent) - }, - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(12.dp) - ) { - Icon( - imageVector = Icons.Default.Code, - contentDescription = null, - modifier = Modifier.size(24.dp), - tint = MaterialTheme.colorScheme.primary - ) - Text( - text = context.getString(R.string.source_code), - style = MaterialTheme.typography.bodyMedium, - fontWeight = FontWeight.Medium, - modifier = Modifier.weight(1f) - ) - Icon( - imageVector = Icons.AutoMirrored.Filled.OpenInNew, - contentDescription = context.getString(R.string.source_code), - modifier = Modifier.size(18.dp), - tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f) - ) } - Spacer(modifier = Modifier.height(4.dp)) - HorizontalDivider() - Spacer(modifier = Modifier.height(4.dp)) // Contributors Text( @@ -668,19 +729,30 @@ private fun AboutDialog(onDismiss: () -> Unit) { color = MaterialTheme.colorScheme.primary ) val contributors = remember { ContributorManager.load(context) } - contributors.forEach { contributor -> - ContributorItem( - contributor = contributor, - onClick = { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(contributor.githubUrl)) - context.startActivity(intent) + Surface( + modifier = Modifier.fillMaxWidth(), + shape = RoundedCornerShape(24.dp), + color = MaterialTheme.colorScheme.surfaceContainerHigh, + border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f)) + ) { + Column { + contributors.forEachIndexed { index, contributor -> + ContributorItem( + contributor = contributor, + onClick = { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(contributor.githubUrl)) + context.startActivity(intent) + } + ) + if (index < contributors.size - 1) { + HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.3f)) + } } - ) + } } } // OK Button - Spacer(modifier = Modifier.height(8.dp)) TextButton( onClick = onDismiss, modifier = Modifier.align(Alignment.End) @@ -702,7 +774,7 @@ private fun ContributorItem(contributor: Contributor, onClick: () -> Unit) { }.getOrNull() else null } Row( - modifier = Modifier.fillMaxWidth().clickable(onClick = onClick), + modifier = Modifier.fillMaxWidth().clickable(onClick = onClick).padding(horizontal = 16.dp, vertical = 12.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp) ) { @@ -756,7 +828,7 @@ private fun RequirementsCard( ) { val context = LocalContext.current - ListItem( + ListItem(colors = ListItemDefaults.colors(containerColor = Color.Transparent), leadingContent = { Icon( imageVector = Icons.Default.Code, diff --git a/Android/app/src/main/java/com/droidspaces/app/ui/screen/SystemdScreen.kt b/Android/app/src/main/java/com/droidspaces/app/ui/screen/SystemdScreen.kt index f37037f0..40a0ccbc 100644 --- a/Android/app/src/main/java/com/droidspaces/app/ui/screen/SystemdScreen.kt +++ b/Android/app/src/main/java/com/droidspaces/app/ui/screen/SystemdScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.luminance import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily @@ -377,9 +378,31 @@ private fun ServiceCard( } Box { Surface(onClick = { showMenu = true }, modifier = Modifier.size(48.dp), shape = RoundedCornerShape(16.dp), color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.05f), border = BorderStroke(1.dp, MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.2f))) { Box(contentAlignment = Alignment.Center) { Icon(Icons.Default.MoreVert, null, tint = MaterialTheme.colorScheme.onSurfaceVariant) } } - DropdownMenu(expanded = showMenu, onDismissRequest = { showMenu = false }) { - if (service.isRunning) { DropdownMenuItem(text = { Text(context.getString(R.string.restart_service)) }, leadingIcon = { Icon(Icons.Default.Refresh, null) }, onClick = { showMenu = false; onAction(context.getString(R.string.restart_service)) { ContainerSystemdManager.restartService(containerName, service.name) } }) } - DropdownMenuItem(text = { Text(context.getString(R.string.mask_service)) }, leadingIcon = { Icon(Icons.Default.Lock, null) }, onClick = { showMenu = false; onAction(context.getString(R.string.mask_service)) { ContainerSystemdManager.maskService(containerName, service.name) } }) + val isDark = MaterialTheme.colorScheme.background.luminance() < 0.5f + val dropdownColor = if (isDark) MaterialTheme.colorScheme.surfaceContainerHigh else MaterialTheme.colorScheme.surfaceContainer + MaterialTheme( + colorScheme = MaterialTheme.colorScheme.copy( + surface = dropdownColor, + surfaceContainer = dropdownColor, + surfaceTint = Color.Transparent + ), + shapes = MaterialTheme.shapes.copy( + extraSmall = RoundedCornerShape(20.dp) + ) + ) { + DropdownMenu( + expanded = showMenu, + onDismissRequest = { showMenu = false }, + modifier = Modifier + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.35f), + shape = RoundedCornerShape(20.dp) + ) + ) { + if (service.isRunning) { DropdownMenuItem(text = { Text(context.getString(R.string.restart_service)) }, leadingIcon = { Icon(Icons.Default.Refresh, null) }, onClick = { showMenu = false; onAction(context.getString(R.string.restart_service)) { ContainerSystemdManager.restartService(containerName, service.name) } }) } + DropdownMenuItem(text = { Text(context.getString(R.string.mask_service)) }, leadingIcon = { Icon(Icons.Default.Lock, null) }, onClick = { showMenu = false; onAction(context.getString(R.string.mask_service)) { ContainerSystemdManager.maskService(containerName, service.name) } }) + } } } } diff --git a/Android/app/src/main/res/values/strings.xml b/Android/app/src/main/res/values/strings.xml index bd68d63c..c9f28bc5 100644 --- a/Android/app/src/main/res/values/strings.xml +++ b/Android/app/src/main/res/values/strings.xml @@ -86,6 +86,7 @@ Pure black background for OLED displays Apply System\'s Default Color Palette Use Android 12+ Monet theming (Material You) + Accent Color Daemon Mode Run Droidspaces as a persistent system-level daemon to bypass seccomp blocks from Magisk/APatch, GrapheneOS, etc. This enables high-privilege operations by fetching and running commands from userspace (Reboot required). Integrate Droidspaces to the system path @@ -592,4 +593,5 @@ URL cannot be empty URL must start with https:// No custom repositories subscribed yet. + Debugging