diff --git a/app/src/main/java/com/bnyro/translate/ext/HexToColor.kt b/app/src/main/java/com/bnyro/translate/ext/HexToColor.kt new file mode 100644 index 000000000..6ab1c14ba --- /dev/null +++ b/app/src/main/java/com/bnyro/translate/ext/HexToColor.kt @@ -0,0 +1,5 @@ +package com.bnyro.translate.ext + +import androidx.compose.ui.graphics.Color + +fun String.hexToColor() = Color(android.graphics.Color.parseColor("#$this")) diff --git a/app/src/main/java/com/bnyro/translate/ui/MainActivity.kt b/app/src/main/java/com/bnyro/translate/ui/MainActivity.kt index 203167768..c8902e020 100644 --- a/app/src/main/java/com/bnyro/translate/ui/MainActivity.kt +++ b/app/src/main/java/com/bnyro/translate/ui/MainActivity.kt @@ -13,6 +13,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModelProvider import androidx.navigation.compose.rememberNavController +import com.bnyro.translate.ext.hexToColor import com.bnyro.translate.ext.parcelable import com.bnyro.translate.ui.models.TranslationModel import com.bnyro.translate.ui.nav.NavigationHost @@ -27,6 +28,7 @@ class MainActivity : ComponentActivity() { var themeMode by mutableStateOf( Preferences.getThemeMode() ) + var accentColor by mutableStateOf(Preferences.getAccentColor()) override fun onCreate(savedInstanceState: Bundle?) { LocaleHelper.updateLanguage(this) @@ -36,7 +38,7 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { - TranslateYouTheme(themeMode) { + TranslateYouTheme(themeMode, accentColor?.hexToColor()) { val navController = rememberNavController() NavigationHost(navController, mainModel) } diff --git a/app/src/main/java/com/bnyro/translate/ui/components/BlockButton.kt b/app/src/main/java/com/bnyro/translate/ui/components/BlockButton.kt index 7e41f1df2..733f55ff9 100644 --- a/app/src/main/java/com/bnyro/translate/ui/components/BlockButton.kt +++ b/app/src/main/java/com/bnyro/translate/ui/components/BlockButton.kt @@ -23,7 +23,7 @@ fun BlockButton( text: String, selected: Boolean = false, containerColor: Color = MaterialTheme.colorScheme.surfaceVariant.copy(0.5f), - selectedContainerColor: Color = MaterialTheme.colorScheme.primaryContainer, + selectedContainerColor: Color = MaterialTheme.colorScheme.primary, contentColor: Color = MaterialTheme.colorScheme.inverseSurface, selectedContentColor: Color = MaterialTheme.colorScheme.onSurface, onClick: () -> Unit = {} diff --git a/app/src/main/java/com/bnyro/translate/ui/components/TopBarMenu.kt b/app/src/main/java/com/bnyro/translate/ui/components/TopBarMenu.kt index d07ac5a83..577040c93 100644 --- a/app/src/main/java/com/bnyro/translate/ui/components/TopBarMenu.kt +++ b/app/src/main/java/com/bnyro/translate/ui/components/TopBarMenu.kt @@ -1,7 +1,6 @@ package com.bnyro.translate.ui.components import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.material3.DropdownMenu @@ -10,8 +9,6 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp import com.bnyro.translate.obj.MenuItemData @Composable diff --git a/app/src/main/java/com/bnyro/translate/ui/components/prefs/AccentColorPref.kt b/app/src/main/java/com/bnyro/translate/ui/components/prefs/AccentColorPref.kt new file mode 100644 index 000000000..2696ded43 --- /dev/null +++ b/app/src/main/java/com/bnyro/translate/ui/components/prefs/AccentColorPref.kt @@ -0,0 +1,143 @@ +package com.bnyro.translate.ui.components.prefs + +import android.os.Build +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.core.content.edit +import com.bnyro.translate.R +import com.bnyro.translate.ext.hexToColor +import com.bnyro.translate.ui.MainActivity +import com.bnyro.translate.ui.components.DialogButton +import com.bnyro.translate.ui.theme.defaultAccentColor +import com.bnyro.translate.util.Preferences +import okhttp3.internal.toHexString + +@Composable +fun AccentColorPrefDialog( + onDismissRequest: () -> Unit +) { + val context = LocalContext.current + val supportsDynamicColors = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + + var color by remember { + mutableStateOf( + Preferences.getAccentColor() ?: run { + if (supportsDynamicColors) null else defaultAccentColor + } + ) + } + + AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + DialogButton(text = stringResource(R.string.okay)) { + Preferences.prefs.edit(true) { putString(Preferences.accentColorKey, color) } + (context as MainActivity).accentColor = color + onDismissRequest.invoke() + } + }, + dismissButton = { + DialogButton(text = stringResource(R.string.cancel)) { + onDismissRequest.invoke() + } + }, + title = { + Text(stringResource(R.string.accent_color)) + }, + text = { + Column( + modifier = Modifier.fillMaxWidth() + ) { + if (supportsDynamicColors) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + modifier = Modifier.weight(1f), + text = stringResource(R.string.dynamic_colors) + ) + Switch( + checked = color == null, + onCheckedChange = { newValue -> + color = defaultAccentColor.takeIf { !newValue } + } + ) + } + } + Row( + modifier = Modifier.height(250.dp) + ) { + AnimatedVisibility( + visible = color != null + ) { + Column( + horizontalAlignment = Alignment.CenterHorizontally + ) { + listOf("R", "G", "B").forEachIndexed { index, c -> + val startIndex = index * 2 + color?.let { + ColorSlider( + label = c, + value = it.substring(startIndex, startIndex + 2).toInt(16), + onChange = { colorInt -> + var newHex = colorInt.toHexString() + if (newHex.length == 1) newHex = "0$newHex" + color = StringBuilder(it).apply { + setCharAt(startIndex, newHex[0]) + setCharAt(startIndex + 1, newHex[1]) + }.toString() + } + ) + } + } + Spacer(modifier = Modifier.height(20.dp)) + color?.let { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + Modifier.size(50.dp).background( + MaterialTheme.colorScheme.primary, + CircleShape + ) + ) + Text(text = " => ", fontSize = 27.sp) + Box( + modifier = Modifier.size(50.dp).background( + it.hexToColor(), + CircleShape + ) + ) + } + } + } + } + } + } + } + ) +} diff --git a/app/src/main/java/com/bnyro/translate/ui/components/prefs/ColorSlider.kt b/app/src/main/java/com/bnyro/translate/ui/components/prefs/ColorSlider.kt new file mode 100644 index 000000000..ec741e7e3 --- /dev/null +++ b/app/src/main/java/com/bnyro/translate/ui/components/prefs/ColorSlider.kt @@ -0,0 +1,34 @@ +package com.bnyro.translate.ui.components.prefs + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Slider +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun ColorSlider( + label: String, + value: Int, + onChange: (Int) -> Unit +) { + Row( + modifier = Modifier.padding(horizontal = 10.dp, vertical = 5.dp), + verticalAlignment = Alignment.CenterVertically + ) { + Text(label) + Slider( + modifier = Modifier.padding(horizontal = 10.dp).weight(1f), + value = value.toFloat(), + valueRange = 0f..255f, + steps = 256, + onValueChange = { + onChange(it.toInt()) + } + ) + Text(value.toString()) + } +} diff --git a/app/src/main/java/com/bnyro/translate/ui/screens/SettingsScreen.kt b/app/src/main/java/com/bnyro/translate/ui/screens/SettingsScreen.kt index c84ce59fa..d65280381 100644 --- a/app/src/main/java/com/bnyro/translate/ui/screens/SettingsScreen.kt +++ b/app/src/main/java/com/bnyro/translate/ui/screens/SettingsScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.DarkMode +import androidx.compose.material.icons.filled.Palette import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.Text @@ -33,6 +34,7 @@ import com.bnyro.translate.R import com.bnyro.translate.ui.MainActivity import com.bnyro.translate.ui.components.StyledIconButton import com.bnyro.translate.ui.components.ThemeModeDialog +import com.bnyro.translate.ui.components.prefs.AccentColorPrefDialog import com.bnyro.translate.ui.components.prefs.ListPreference import com.bnyro.translate.ui.components.prefs.PreferenceItem import com.bnyro.translate.ui.components.prefs.SettingsCategory @@ -56,6 +58,10 @@ fun SettingsScreen( mutableStateOf(false) } + var showAccentColorDialog by remember { + mutableStateOf(false) + } + var enableSimultaneousTranslation by remember { mutableStateOf( Preferences.get(Preferences.simultaneousTranslationKey, false) @@ -88,6 +94,11 @@ fun SettingsScreen( } }, actions = { + StyledIconButton( + imageVector = Icons.Default.Palette + ) { + showAccentColorDialog = true + } StyledIconButton( imageVector = Icons.Default.DarkMode ) { @@ -268,4 +279,10 @@ fun SettingsScreen( showTessSettings = false } } + + if (showAccentColorDialog) { + AccentColorPrefDialog { + showAccentColorDialog = false + } + } } diff --git a/app/src/main/java/com/bnyro/translate/ui/theme/Color.kt b/app/src/main/java/com/bnyro/translate/ui/theme/Color.kt deleted file mode 100644 index 87a91f864..000000000 --- a/app/src/main/java/com/bnyro/translate/ui/theme/Color.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.bnyro.translate.ui.theme - -import androidx.compose.ui.graphics.Color - -val Purple80 = Color(0xFFD0BCFF) -val PurpleGrey80 = Color(0xFFCCC2DC) -val Pink80 = Color(0xFFEFB8C8) - -val Purple40 = Color(0xFF6650a4) -val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) diff --git a/app/src/main/java/com/bnyro/translate/ui/theme/Theme.kt b/app/src/main/java/com/bnyro/translate/ui/theme/Theme.kt index 3340ecd5e..c536dde7b 100644 --- a/app/src/main/java/com/bnyro/translate/ui/theme/Theme.kt +++ b/app/src/main/java/com/bnyro/translate/ui/theme/Theme.kt @@ -10,39 +10,21 @@ import androidx.compose.material3.dynamicLightColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.SideEffect +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.graphics.ColorUtils import androidx.core.view.WindowCompat import com.bnyro.translate.const.ThemeMode +import com.bnyro.translate.ext.hexToColor -private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 -) - -private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 - - /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - */ -) +const val defaultAccentColor = "d0bcff" @Composable fun TranslateYouTheme( themeMode: Int = ThemeMode.AUTO, - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, + accentColor: Color? = null, content: @Composable () -> Unit ) { val darkTheme = when (themeMode) { @@ -52,12 +34,20 @@ fun TranslateYouTheme( } val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + accentColor == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { val context = LocalContext.current if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) } - darkTheme -> DarkColorScheme - else -> LightColorScheme + else -> { + val accent = accentColor ?: defaultAccentColor.hexToColor() + val blendColor = if (darkTheme) android.graphics.Color.WHITE else android.graphics.Color.BLACK + val onPrimary = Color(ColorUtils.blendARGB(accent.toArgb(), blendColor, 0.3f)) + if (darkTheme) darkColorScheme(accent, onPrimary, secondary = onPrimary) else lightColorScheme( + accent, + onPrimary, + secondary = onPrimary + ) + } } val view = LocalView.current diff --git a/app/src/main/java/com/bnyro/translate/util/Preferences.kt b/app/src/main/java/com/bnyro/translate/util/Preferences.kt index 04c5ec61f..da28be03b 100644 --- a/app/src/main/java/com/bnyro/translate/util/Preferences.kt +++ b/app/src/main/java/com/bnyro/translate/util/Preferences.kt @@ -19,10 +19,11 @@ object Preferences { const val tessLanguageKey = "tessLanguage" const val themeModeKey = "themeMode" + const val accentColorKey = "accentColor" const val sourceLanguage = "sourceLanguage" const val targetLanguage = "targetLanguage" - private lateinit var prefs: SharedPreferences + lateinit var prefs: SharedPreferences fun initialize(context: Context) { prefs = context.getSharedPreferences( @@ -52,10 +53,7 @@ object Preferences { } } - fun getThemeMode(): Int { - return get( - themeModeKey, - ThemeMode.AUTO.toString() - ).toInt() - } + fun getThemeMode() = get(themeModeKey, ThemeMode.AUTO.toString()).toInt() + + fun getAccentColor() = prefs.getString(accentColorKey, null) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9732a5a78..ee6bd65eb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -55,6 +55,8 @@ System Light Dark + Accent color + Dynamic colors Clear history Open