feat: theme improvements

- Re-enable dynamic color by default
- Default to system dark/light mode
- Use only Roboto fonts
This commit is contained in:
rushiiMachine 2025-06-05 15:33:36 -07:00
parent c2e98ccf8a
commit 28841d128a
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
33 changed files with 119 additions and 58 deletions

View file

@ -10,7 +10,6 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.compose.animation.core.*
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.unit.IntOffset
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
@ -20,10 +19,9 @@ import cafe.adriel.voyager.navigator.*
import cafe.adriel.voyager.transitions.SlideTransition
import com.aliucord.manager.manager.OverlayManager
import com.aliucord.manager.manager.PreferencesManager
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.components.Theme
import com.aliucord.manager.ui.components.dialogs.StoragePermissionsDialog
import com.aliucord.manager.ui.screens.home.HomeScreen
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.widgets.updater.UpdaterDialog
import com.aliucord.manager.util.IS_CUSTOM_BUILD
import com.aliucord.manager.util.back
@ -42,8 +40,8 @@ class MainActivity : ComponentActivity() {
setContent {
ManagerTheme(
isDarkTheme = preferences.theme == Theme.DARK || preferences.theme == Theme.SYSTEM && isSystemInDarkTheme(),
isDynamicColor = preferences.dynamicColor
theme = preferences.theme,
dynamicColor = preferences.dynamicColor,
) {
StoragePermissionsDialog()

View file

@ -3,12 +3,12 @@ package com.aliucord.manager.manager
import android.content.SharedPreferences
import androidx.compose.runtime.Stable
import com.aliucord.manager.manager.base.BasePreferenceManager
import com.aliucord.manager.ui.components.Theme
import com.aliucord.manager.ui.theme.Theme
@Stable
class PreferencesManager(preferences: SharedPreferences) : BasePreferenceManager(preferences) {
var theme by enumPreference("theme", Theme.DARK)
var dynamicColor by booleanPreference("dynamic_color", false)
var theme by enumPreference("theme", Theme.System)
var dynamicColor by booleanPreference("dynamic_color", true)
var devMode by booleanPreference("dev_mode", false)
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PM)
var keepPatchedApks by booleanPreference("keep_patched_apks", false)

View file

@ -17,7 +17,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogProperties
import com.aliucord.manager.R
import com.aliucord.manager.ui.components.customColors
import com.aliucord.manager.ui.theme.customColors
@Composable
fun PlayProtectDialog(

View file

@ -9,9 +9,9 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.*
import com.aliucord.manager.R
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.components.customColors
import com.aliucord.manager.ui.screens.patching.components.TextBanner
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.theme.customColors
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.dialogs
import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.logs.components.dialogs.DeleteLogsDialog
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.dialogs
import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.components.dialogs.InstallerAbortDialog
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.dialogs
import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.components.dialogs.NetworkWarningDialog
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.dialogs
import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.components.dialogs.PlayProtectDialog
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -5,9 +5,9 @@ import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.components.dialogs.ExternalStorageDialog
import com.aliucord.manager.ui.components.dialogs.ManageStorageDialog
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@RequiresApi(Build.VERSION_CODES.R)

View file

@ -3,15 +3,15 @@ package com.aliucord.manager.ui.previews.dialogs
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.components.Theme
import com.aliucord.manager.ui.screens.settings.components.ThemeDialog
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.theme.Theme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
private fun ThemeDialogPreview() {
val (theme, setTheme) = remember { mutableStateOf(Theme.SYSTEM) }
val (theme, setTheme) = remember { mutableStateOf(Theme.System) }
ManagerTheme {
ThemeDialog(

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.dialogs
import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.plugins.components.dialogs.UninstallPluginDialog
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.dialogs
import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.components.dialogs.UnknownSourcesPermissionDialog
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -11,10 +11,10 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.*
import androidx.core.graphics.drawable.toBitmap
import com.aliucord.manager.R
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.iconopts.IconOptionsMode
import com.aliucord.manager.ui.screens.iconopts.IconOptionsScreenContent
import com.aliucord.manager.ui.screens.patchopts.PatchOptions.IconReplacement
import com.aliucord.manager.ui.theme.ManagerTheme
import dev.zt64.compose.pipette.HsvColor
import java.io.ByteArrayOutputStream

View file

@ -4,8 +4,8 @@ import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.*
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.patchopts.*
import com.aliucord.manager.ui.theme.ManagerTheme
// This preview has scrollable/interactable content that cannot be tested from an IDE preview

View file

@ -3,9 +3,9 @@ package com.aliucord.manager.ui.previews.screens.about
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.about.AboutScreenContent
import com.aliucord.manager.ui.screens.about.AboutScreenState
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -4,9 +4,9 @@ import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.*
import com.aliucord.manager.network.models.Contributor
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.about.AboutScreenContent
import com.aliucord.manager.ui.screens.about.AboutScreenState
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.util.emptyImmutableList
import com.aliucord.manager.util.serialization.ImmutableListSerializer
import kotlinx.collections.immutable.*

View file

@ -3,9 +3,9 @@ package com.aliucord.manager.ui.previews.screens.about
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.about.AboutScreenContent
import com.aliucord.manager.ui.screens.about.AboutScreenState
import com.aliucord.manager.ui.theme.ManagerTheme
// This preview cannot be properly viewed from an IDE

View file

@ -4,9 +4,9 @@ import android.content.res.Configuration
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.home.HomeScreenFailureContent
import com.aliucord.manager.ui.screens.home.components.HomeAppBar
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -7,9 +7,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.tooling.preview.*
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.home.*
import com.aliucord.manager.ui.screens.home.components.HomeAppBar
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.util.DiscordVersion
import io.ktor.util.decodeBase64Bytes
import kotlinx.collections.immutable.persistentListOf

View file

@ -4,9 +4,9 @@ import android.content.res.Configuration
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.home.HomeScreenLoadingContent
import com.aliucord.manager.ui.screens.home.components.HomeAppBar
import com.aliucord.manager.ui.theme.ManagerTheme
// This preview cannot be properly viewed from an IDE preview

View file

@ -4,9 +4,9 @@ import android.content.res.Configuration
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.home.HomeScreenNoneContent
import com.aliucord.manager.ui.screens.home.components.HomeAppBar
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -5,9 +5,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.logs.LogEntry
import com.aliucord.manager.ui.screens.logs.LogsScreenContent
import com.aliucord.manager.ui.theme.ManagerTheme
import kotlinx.collections.immutable.persistentListOf
import java.util.UUID

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.screens.logs
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.logs.LogsScreenContent
import com.aliucord.manager.ui.theme.ManagerTheme
@Composable
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.screens.plugins
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.plugins.PluginsScreenContent
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.util.emptyImmutableList
// This preview has interactable content that cannot be tested from an IDE preview

View file

@ -3,10 +3,10 @@ package com.aliucord.manager.ui.previews.screens.plugins
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.plugins.PluginsScreenContent
import com.aliucord.manager.ui.screens.plugins.model.PluginItem
import com.aliucord.manager.ui.screens.plugins.model.PluginManifest
import com.aliucord.manager.ui.theme.ManagerTheme
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import java.util.UUID

View file

@ -3,8 +3,8 @@ package com.aliucord.manager.ui.previews.screens.plugins
import android.content.res.Configuration
import androidx.compose.runtime.*
import androidx.compose.ui.tooling.preview.Preview
import com.aliucord.manager.ui.components.ManagerTheme
import com.aliucord.manager.ui.screens.plugins.PluginsScreenContent
import com.aliucord.manager.ui.theme.ManagerTheme
import com.aliucord.manager.ui.util.emptyImmutableList
// This preview has interactable content that cannot be tested from an IDE preview

View file

@ -30,11 +30,13 @@ import cafe.adriel.voyager.navigator.currentOrThrow
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.R
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.ui.components.*
import com.aliucord.manager.ui.components.MainActionButton
import com.aliucord.manager.ui.components.Wakelock
import com.aliucord.manager.ui.components.dialogs.InstallerAbortDialog
import com.aliucord.manager.ui.screens.log.LogScreen
import com.aliucord.manager.ui.screens.patching.components.*
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.aliucord.manager.ui.theme.customColors
import com.aliucord.manager.ui.util.paddings.*
import com.aliucord.manager.ui.util.spacedByLastAtBottom
import com.aliucord.manager.ui.util.thenIf

View file

@ -6,7 +6,7 @@ import cafe.adriel.voyager.core.model.ScreenModel
import cafe.adriel.voyager.core.model.screenModelScope
import com.aliucord.manager.R
import com.aliucord.manager.manager.PreferencesManager
import com.aliucord.manager.ui.components.Theme
import com.aliucord.manager.ui.theme.Theme
import com.aliucord.manager.util.launchBlock
import com.aliucord.manager.util.showToast
import kotlinx.coroutines.delay

View file

@ -14,7 +14,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.aliucord.manager.R
import com.aliucord.manager.ui.components.Theme
import com.aliucord.manager.ui.theme.Theme
@Composable
fun ThemeDialog(

View file

@ -3,7 +3,7 @@
* Licensed under the Open Software License version 3.0
*/
package com.aliucord.manager.ui.components
package com.aliucord.manager.ui.theme
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
@ -18,18 +18,23 @@ import com.google.accompanist.systemuicontroller.rememberSystemUiController
@Composable
fun ManagerTheme(
isDarkTheme: Boolean = isSystemInDarkTheme(),
isDynamicColor: Boolean = true,
theme: Theme = Theme.System,
dynamicColor: Boolean = true,
content: @Composable () -> Unit,
) {
val dynamicColor = isDynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val dynamicColor = dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
val darkTheme = when (theme) {
Theme.System -> isSystemInDarkTheme()
Theme.Dark -> true
Theme.Light -> false
}
val colorScheme = when {
dynamicColor && isDarkTheme -> dynamicDarkColorScheme(LocalContext.current)
dynamicColor && !isDarkTheme -> dynamicLightColorScheme(LocalContext.current)
isDarkTheme -> darkColorScheme()
dynamicColor && darkTheme -> dynamicDarkColorScheme(LocalContext.current)
dynamicColor && !darkTheme -> dynamicLightColorScheme(LocalContext.current)
darkTheme -> darkColorScheme()
else -> lightColorScheme()
}
val customColors = when (isDarkTheme) {
val customColors = when (darkTheme) {
true -> DarkCustomColors
false -> LightCustomColors
}
@ -42,7 +47,7 @@ fun ManagerTheme(
SideEffect {
systemUiController.setSystemBarsColor(
color = colorScheme.background,
darkIcons = !isDarkTheme
darkIcons = !darkTheme,
)
systemUiController.setNavigationBarColor(
color = Color.Transparent,
@ -52,27 +57,28 @@ fun ManagerTheme(
CompositionLocalProvider(LocalCustomColors provides customColors) {
MaterialTheme(
colorScheme = colorScheme,
content = content
typography = ThemeTypography,
content = content,
)
}
}
enum class Theme {
SYSTEM,
LIGHT,
DARK;
System,
Light,
Dark;
@Composable
fun toDisplayName() = when (this) {
SYSTEM -> stringResource(R.string.theme_system)
LIGHT -> stringResource(R.string.theme_light)
DARK -> stringResource(R.string.theme_dark)
System -> stringResource(R.string.theme_system)
Light -> stringResource(R.string.theme_light)
Dark -> stringResource(R.string.theme_dark)
}
@Composable
fun toPainter() = when (this) {
SYSTEM -> painterResource(R.drawable.ic_sync)
LIGHT -> painterResource(R.drawable.ic_light)
DARK -> painterResource(R.drawable.ic_night)
System -> painterResource(R.drawable.ic_sync)
Light -> painterResource(R.drawable.ic_light)
Dark -> painterResource(R.drawable.ic_night)
}
}

View file

@ -1,9 +1,10 @@
package com.aliucord.manager.ui.components
package com.aliucord.manager.ui.theme
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
@Suppress("UnusedReceiverParameter")
val MaterialTheme.customColors: CustomColors
@Composable
inline get() = LocalCustomColors.current

View file

@ -0,0 +1,54 @@
package com.aliucord.manager.ui.theme
import androidx.compose.material3.Typography
import androidx.compose.ui.text.ExperimentalTextApi
import androidx.compose.ui.text.font.*
import com.aliucord.manager.R
// This uses a variable font variant of Roboto.
// ref: https://medium.com/androiddevelopers/just-your-type-variable-fonts-in-compose-5bf63b357994
@OptIn(ExperimentalTextApi::class)
val ThemeTypography = run {
val baseline = Typography()
val weights = arrayOf(
FontWeight.Thin,
FontWeight.ExtraLight,
FontWeight.Light,
FontWeight.Normal,
FontWeight.Medium,
FontWeight.SemiBold,
FontWeight.ExtraBold,
FontWeight.Bold,
FontWeight.Black,
)
val fonts = weights.map { weight ->
Font(
resId = R.font.roboto_variable,
weight = weight,
variationSettings = FontVariation.Settings(
FontVariation.weight(weight.weight),
)
)
}
val fontFamily = FontFamily(fonts)
Typography(
displayLarge = baseline.displayLarge.copy(fontFamily = fontFamily),
displayMedium = baseline.displayMedium.copy(fontFamily = fontFamily),
displaySmall = baseline.displaySmall.copy(fontFamily = fontFamily),
headlineLarge = baseline.headlineLarge.copy(fontFamily = fontFamily),
headlineMedium = baseline.headlineMedium.copy(fontFamily = fontFamily),
headlineSmall = baseline.headlineSmall.copy(fontFamily = fontFamily),
titleLarge = baseline.titleLarge.copy(fontFamily = fontFamily),
titleMedium = baseline.titleMedium.copy(fontFamily = fontFamily),
titleSmall = baseline.titleSmall.copy(fontFamily = fontFamily),
bodyLarge = baseline.bodyLarge.copy(fontFamily = fontFamily),
bodyMedium = baseline.bodyMedium.copy(fontFamily = fontFamily),
bodySmall = baseline.bodySmall.copy(fontFamily = fontFamily),
labelLarge = baseline.labelLarge.copy(fontFamily = fontFamily),
labelMedium = baseline.labelMedium.copy(fontFamily = fontFamily),
labelSmall = baseline.labelSmall.copy(fontFamily = fontFamily),
)
}

Binary file not shown.