feat: possibility to change UI font

This commit is contained in:
Diego Beraldin 2023-10-16 20:57:33 +02:00
parent 04b4f1edef
commit 5fe4b09de5
38 changed files with 388 additions and 181 deletions

View File

@ -6,7 +6,7 @@ import androidx.compose.material3.ColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.ui.graphics.Color
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.BlackColors
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ColorSchemeProvider
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.DarkColors
@ -22,11 +22,11 @@ internal class DefaultColorSchemeProvider(private val context: Context) : ColorS
}
override fun getColorScheme(
theme: ThemeState,
theme: UiTheme,
dynamic: Boolean,
customSeed: Color?,
): ColorScheme = when (theme) {
ThemeState.Dark -> {
UiTheme.Dark -> {
when {
dynamic -> {
dynamicDarkColorScheme(context)
@ -42,7 +42,7 @@ internal class DefaultColorSchemeProvider(private val context: Context) : ColorS
}
}
ThemeState.Black -> {
UiTheme.Black -> {
when {
dynamic -> {
dynamicDarkColorScheme(context).blackify()

View File

@ -1,40 +0,0 @@
package com.github.diegoberaldin.raccoonforlemmy.core.appearance.data
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.DarkMode
import androidx.compose.material.icons.filled.LightMode
import androidx.compose.material.icons.outlined.DarkMode
import androidx.compose.runtime.Composable
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.stringResource
sealed interface ThemeState {
data object Light : ThemeState
data object Dark : ThemeState
data object Black : ThemeState
}
fun Int.toThemeState() = when (this) {
2 -> ThemeState.Black
1 -> ThemeState.Dark
else -> ThemeState.Light
}
fun ThemeState.toInt() = when (this) {
ThemeState.Black -> 2
ThemeState.Dark -> 1
ThemeState.Light -> 0
}
@Composable
fun ThemeState.toReadableName() = when (this) {
ThemeState.Black -> stringResource(MR.strings.settings_theme_black)
ThemeState.Dark -> stringResource(MR.strings.settings_theme_dark)
ThemeState.Light -> stringResource(MR.strings.settings_theme_light)
}
fun ThemeState.toIcon() = when (this) {
ThemeState.Black -> Icons.Default.DarkMode
ThemeState.Dark -> Icons.Outlined.DarkMode
ThemeState.Light -> Icons.Default.LightMode
}

View File

@ -0,0 +1,28 @@
package com.github.diegoberaldin.raccoonforlemmy.core.appearance.data
import androidx.compose.runtime.Composable
sealed interface UiFontFamily {
data object TitilliumWeb : UiFontFamily
data object Roboto : UiFontFamily
data object EbGaramond : UiFontFamily
}
fun Int.toUiFontFamily() = when (this) {
2 -> UiFontFamily.EbGaramond
1 -> UiFontFamily.Roboto
else -> UiFontFamily.TitilliumWeb
}
fun UiFontFamily.toInt() = when (this) {
UiFontFamily.EbGaramond -> 2
UiFontFamily.Roboto -> 1
else -> 0
}
@Composable
fun UiFontFamily.toReadableName() = when (this) {
UiFontFamily.EbGaramond -> "EB Garamond"
UiFontFamily.Roboto -> "Roboto"
else -> "Titillium Web"
}

View File

@ -0,0 +1,40 @@
package com.github.diegoberaldin.raccoonforlemmy.core.appearance.data
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.DarkMode
import androidx.compose.material.icons.filled.LightMode
import androidx.compose.material.icons.outlined.DarkMode
import androidx.compose.runtime.Composable
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.stringResource
sealed interface UiTheme {
data object Light : UiTheme
data object Dark : UiTheme
data object Black : UiTheme
}
fun Int.toUiTheme() = when (this) {
2 -> UiTheme.Black
1 -> UiTheme.Dark
else -> UiTheme.Light
}
fun UiTheme.toInt() = when (this) {
UiTheme.Black -> 2
UiTheme.Dark -> 1
UiTheme.Light -> 0
}
@Composable
fun UiTheme.toReadableName() = when (this) {
UiTheme.Black -> stringResource(MR.strings.settings_theme_black)
UiTheme.Dark -> stringResource(MR.strings.settings_theme_dark)
UiTheme.Light -> stringResource(MR.strings.settings_theme_light)
}
fun UiTheme.toIcon() = when (this) {
UiTheme.Black -> Icons.Default.DarkMode
UiTheme.Dark -> Icons.Outlined.DarkMode
UiTheme.Light -> Icons.Default.LightMode
}

View File

@ -2,13 +2,15 @@ package com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository
import androidx.compose.ui.graphics.Color
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import kotlinx.coroutines.flow.MutableStateFlow
internal class DefaultThemeRepository : ThemeRepository {
override val state = MutableStateFlow<ThemeState>(ThemeState.Light)
override val uiTheme = MutableStateFlow<UiTheme>(UiTheme.Light)
override val uiFontFamily = MutableStateFlow<UiFontFamily>(UiFontFamily.TitilliumWeb)
override val uiFontScale = MutableStateFlow(1f)
override val contentFontScale = MutableStateFlow(1f)
override val navItemTitles = MutableStateFlow(false)
@ -16,8 +18,12 @@ internal class DefaultThemeRepository : ThemeRepository {
override val customSeedColor = MutableStateFlow<Color?>(null)
override val postLayout = MutableStateFlow<PostLayout>(PostLayout.Card)
override fun changeTheme(value: ThemeState) {
state.value = value
override fun changeUiTheme(value: UiTheme) {
uiTheme.value = value
}
override fun changeUiFontFamily(value: UiFontFamily) {
uiFontFamily.value = value
}
override fun changeUiFontScale(value: Float) {

View File

@ -2,12 +2,14 @@ package com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository
import androidx.compose.ui.graphics.Color
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import kotlinx.coroutines.flow.StateFlow
interface ThemeRepository {
val state: StateFlow<ThemeState>
val uiTheme: StateFlow<UiTheme>
val uiFontFamily: StateFlow<UiFontFamily>
val uiFontScale: StateFlow<Float>
val contentFontScale: StateFlow<Float>
val navItemTitles: StateFlow<Boolean>
@ -15,7 +17,9 @@ interface ThemeRepository {
val customSeedColor: StateFlow<Color?>
val postLayout: StateFlow<PostLayout>
fun changeTheme(value: ThemeState)
fun changeUiTheme(value: UiTheme)
fun changeUiFontFamily(value: UiFontFamily)
fun changeUiFontScale(value: Float)

View File

@ -5,25 +5,25 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getColorSchemeProvider
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
@Composable
fun AppTheme(
theme: ThemeState,
theme: UiTheme,
contentFontScale: Float,
useDynamicColors: Boolean,
content: @Composable () -> Unit,
) {
val repository = remember {
val res = getThemeRepository()
res.changeTheme(theme)
res.changeUiTheme(theme)
res.changeContentFontScale(contentFontScale)
res
}
val themeState by repository.state.collectAsState()
val themeState by repository.uiTheme.collectAsState()
val customSeedColor by repository.customSeedColor.collectAsState()
val colorSchemeProvider = remember { getColorSchemeProvider() }
@ -33,6 +33,9 @@ fun AppTheme(
customSeed = customSeedColor,
)
val fontFamily by repository.uiFontFamily.collectAsState()
val typography = getTypography(fontFamily)
MaterialTheme(
colorScheme = colorScheme,
typography = typography,

View File

@ -2,14 +2,14 @@ package com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme
import androidx.compose.material3.ColorScheme
import androidx.compose.ui.graphics.Color
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
interface ColorSchemeProvider {
val supportsDynamicColors: Boolean
fun getColorScheme(
theme: ThemeState,
theme: UiTheme,
dynamic: Boolean,
customSeed: Color? = null,
): ColorScheme

View File

@ -5,103 +5,110 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.fontFamilyResource
internal val typography: Typography
@Composable get() {
val fontFamily = fontFamilyResource(MR.fonts.TitilliumWeb.regular)
return Typography(
// h1
displayLarge = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Light,
fontSize = 96.sp,
letterSpacing = (-1.5).sp,
),
// h2
displayMedium = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Light,
fontSize = 60.sp,
letterSpacing = (-0.5).sp,
),
// h3
displaySmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 38.sp,
letterSpacing = 0.sp,
),
// h4
headlineMedium = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 34.sp,
letterSpacing = (0.25).sp,
),
// h5
headlineSmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 24.sp,
letterSpacing = 0.sp,
),
// h6
titleLarge = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Medium,
fontSize = 16.sp,
letterSpacing = (0.15).sp,
),
// subtitle1
titleMedium = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
letterSpacing = (0.15).sp,
),
// subtitle2
titleSmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
letterSpacing = (0.1).sp,
),
// body1
bodyLarge = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
letterSpacing = (0.5).sp,
),
// body2
bodyMedium = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 14.sp,
letterSpacing = (0.25).sp,
),
// button
labelLarge = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
letterSpacing = (0.15).sp, // original: 1.25
),
// caption
bodySmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 12.sp,
letterSpacing = (0.4).sp,
),
// overline
labelSmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 10.sp,
letterSpacing = (0.5).sp, // original: 1.5
),
)
@Composable
internal fun getTypography(
fontFamily: UiFontFamily = UiFontFamily.TitilliumWeb,
): Typography {
val fontFamily = when (fontFamily) {
UiFontFamily.EbGaramond -> fontFamilyResource(MR.fonts.EBGaramond.variableFont_wght)
UiFontFamily.Roboto -> fontFamilyResource(MR.fonts.Roboto.regular)
else -> fontFamilyResource(MR.fonts.TitilliumWeb.regular)
}
return Typography(
// h1
displayLarge = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Light,
fontSize = 96.sp,
letterSpacing = (-1.5).sp,
),
// h2
displayMedium = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Light,
fontSize = 60.sp,
letterSpacing = (-0.5).sp,
),
// h3
displaySmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 38.sp,
letterSpacing = 0.sp,
),
// h4
headlineMedium = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 34.sp,
letterSpacing = (0.25).sp,
),
// h5
headlineSmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 24.sp,
letterSpacing = 0.sp,
),
// h6
titleLarge = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Medium,
fontSize = 16.sp,
letterSpacing = (0.15).sp,
),
// subtitle1
titleMedium = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
letterSpacing = (0.15).sp,
),
// subtitle2
titleSmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
letterSpacing = (0.1).sp,
),
// body1
bodyLarge = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
letterSpacing = (0.5).sp,
),
// body2
bodyMedium = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 14.sp,
letterSpacing = (0.25).sp,
),
// button
labelLarge = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
letterSpacing = (0.15).sp, // original: 1.25
),
// caption
bodySmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 12.sp,
letterSpacing = (0.4).sp,
),
// overline
labelSmall = TextStyle(
fontFamily = fontFamily,
fontWeight = FontWeight.Normal,
fontSize = 10.sp,
letterSpacing = (0.5).sp, // original: 1.5
),
)
}

View File

@ -2,7 +2,7 @@ package com.github.diegoberaldin.raccoonforlemmy.core.appearance
import androidx.compose.material3.ColorScheme
import androidx.compose.ui.graphics.Color
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.BlackColors
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.ColorSchemeProvider
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.DarkColors
@ -15,11 +15,11 @@ internal class DefaultColorSchemeProvider : ColorSchemeProvider {
override val supportsDynamicColors = false
override fun getColorScheme(
theme: ThemeState,
theme: UiTheme,
dynamic: Boolean,
customSeed: Color?,
): ColorScheme = when (theme) {
ThemeState.Dark -> {
UiTheme.Dark -> {
if (customSeed != null) {
dynamicColorScheme(customSeed, true)
} else {
@ -27,7 +27,7 @@ internal class DefaultColorSchemeProvider : ColorSchemeProvider {
}
}
ThemeState.Black -> {
UiTheme.Black -> {
if (customSeed != null) {
dynamicColorScheme(customSeed, true).blackify()
} else {

View File

@ -0,0 +1,98 @@
package com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.BottomSheetHandle
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.NotificationCenterContractKeys
import com.github.diegoberaldin.raccoonforlemmy.core.notifications.di.getNotificationCenter
import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick
import com.github.diegoberaldin.raccoonforlemmy.resources.MR
import dev.icerock.moko.resources.compose.fontFamilyResource
import dev.icerock.moko.resources.compose.stringResource
class FontFamilyBottomSheet(
private val values: List<UiFontFamily> = listOf(
UiFontFamily.TitilliumWeb,
UiFontFamily.Roboto,
UiFontFamily.EbGaramond,
),
) : Screen {
@Composable
override fun Content() {
val bottomSheetNavigator = LocalBottomSheetNavigator.current
val notificationCenter = remember { getNotificationCenter() }
Column(
modifier = Modifier
.padding(
top = Spacing.s,
start = Spacing.s,
end = Spacing.s,
bottom = Spacing.m,
),
verticalArrangement = Arrangement.spacedBy(Spacing.s),
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
) {
BottomSheetHandle()
Text(
modifier = Modifier.padding(start = Spacing.s, top = Spacing.s),
text = stringResource(MR.strings.settings_ui_font_family),
style = MaterialTheme.typography.titleLarge,
color = MaterialTheme.colorScheme.onBackground,
)
Column(
modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(Spacing.xxxs),
) {
for (value in values) {
Row(
modifier = Modifier.padding(
horizontal = Spacing.s,
vertical = Spacing.m,
)
.fillMaxWidth()
.onClick {
notificationCenter.getObserver(NotificationCenterContractKeys.ChangeFontFamily)
?.also {
it.invoke(value)
}
bottomSheetNavigator.hide()
},
) {
val fontFamily = when (value) {
UiFontFamily.EbGaramond -> fontFamilyResource(MR.fonts.EBGaramond.variableFont_wght)
UiFontFamily.Roboto -> fontFamilyResource(MR.fonts.Roboto.regular)
else -> fontFamilyResource(MR.fonts.TitilliumWeb.regular)
}
Text(
text = value.toReadableName(),
style = MaterialTheme.typography.bodyLarge.copy(
fontFamily = fontFamily,
),
color = MaterialTheme.colorScheme.onBackground,
)
}
}
}
}
}
}
}

View File

@ -18,7 +18,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toIcon
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
@ -58,9 +58,9 @@ class ThemeBottomSheet : Screen {
)
}
val values = listOf(
ThemeState.Light,
ThemeState.Dark,
ThemeState.Black,
UiTheme.Light,
UiTheme.Dark,
UiTheme.Black,
)
Column(
modifier = Modifier.fillMaxWidth().verticalScroll(rememberScrollState()),

View File

@ -6,6 +6,7 @@ object NotificationCenterContractKeys {
const val ChangeInboxType = "changeInboxType"
const val ChangeTheme = "changeTheme"
const val ChangeFontSize = "changeFontSize"
const val ChangeFontFamily = "changeFontFamily"
const val ChangeLanguage = "changeLanguage"
const val ChangePostLayout = "changePostLayout"
const val Logout = "logout"

View File

@ -5,6 +5,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.utils.JavaSerializable
data class SettingsModel(
val id: Long? = null,
val theme: Int? = null,
val uiFontFamily: Int = 0,
val uiFontScale: Float = 1f,
val contentFontScale: Float = 1f,
val locale: String? = null,

View File

@ -11,6 +11,7 @@ import kotlinx.coroutines.withContext
private object KeyStoreKeys {
const val UiTheme = "uiTheme"
const val UiFontFamily = "uiFontFamily"
const val UiFontScale = "uiFontSize"
const val ContentFontScale = "contentFontSize"
const val Locale = "locale"
@ -43,6 +44,7 @@ internal class DefaultSettingsRepository(
db.settingsQueries.create(
theme = settings.theme?.toLong(),
uiFontScale = settings.uiFontScale.toDouble(),
uiFontFamily = settings.uiFontFamily.toLong(),
contentFontScale = settings.contentFontScale.toDouble(),
locale = settings.locale,
defaultListingType = settings.defaultListingType.toLong(),
@ -71,6 +73,7 @@ internal class DefaultSettingsRepository(
keyStore[KeyStoreKeys.UiTheme, 0]
} else null,
uiFontScale = keyStore[KeyStoreKeys.UiFontScale, 1f],
uiFontFamily = keyStore[KeyStoreKeys.UiFontFamily, 1],
contentFontScale = keyStore[KeyStoreKeys.ContentFontScale, 1f],
locale = keyStore[KeyStoreKeys.Locale, ""].takeIf { it.isNotEmpty() },
defaultListingType = keyStore[KeyStoreKeys.DefaultListingType, 0],
@ -102,6 +105,7 @@ internal class DefaultSettingsRepository(
keyStore.save(KeyStoreKeys.UiTheme, settings.theme)
}
keyStore.save(KeyStoreKeys.UiFontScale, settings.uiFontScale)
keyStore.save(KeyStoreKeys.UiFontFamily, settings.uiFontFamily)
keyStore.save(KeyStoreKeys.ContentFontScale, settings.contentFontScale)
if (!settings.locale.isNullOrEmpty()) {
keyStore.save(KeyStoreKeys.Locale, settings.locale)
@ -128,6 +132,7 @@ internal class DefaultSettingsRepository(
db.settingsQueries.update(
theme = settings.theme?.toLong(),
uiFontScale = settings.uiFontScale.toDouble(),
uiFontFamily = settings.uiFontFamily.toLong(),
contentFontScale = settings.contentFontScale.toDouble(),
locale = settings.locale,
defaultListingType = settings.defaultListingType.toLong(),
@ -157,6 +162,7 @@ private fun GetBy.toModel() = SettingsModel(
id = id,
theme = theme?.toInt(),
uiFontScale = uiFontScale.toFloat(),
uiFontFamily = uiFontFamily.toInt(),
contentFontScale = contentFontScale.toFloat(),
locale = locale,
defaultListingType = defaultListingType.toInt(),

View File

@ -2,6 +2,7 @@ CREATE TABLE SettingsEntity (
id INTEGER PRIMARY KEY AUTOINCREMENT,
theme INTEGER DEFAULT NULL,
uiFontScale REAL NOT NULL DEFAULT 1,
uiFontFamily INTEGER NOT NULL DEFAULT 1,
contentFontScale REAL NOT NULL DEFAULT 1,
locale TEXT DEFAULT NULL,
defaultListingType INTEGER NOT NULL DEFAULT 0,
@ -26,6 +27,7 @@ create:
INSERT OR IGNORE INTO SettingsEntity (
theme,
uiFontScale,
uiFontFamily,
contentFontScale,
locale,
defaultListingType,
@ -60,6 +62,7 @@ INSERT OR IGNORE INTO SettingsEntity (
?,
?,
?,
?,
?
);
@ -67,6 +70,7 @@ update:
UPDATE SettingsEntity
SET theme = ?,
uiFontScale = ?,
uiFontFamily = ?,
contentFontScale = ?,
locale = ?,
defaultListingType = ?,
@ -89,6 +93,7 @@ SELECT
id,
theme,
uiFontScale,
uiFontFamily,
contentFontScale,
locale,
defaultListingType,

View File

@ -0,0 +1,2 @@
ALTER TABLE SettingsEntity
ADD COLUMN uiFontFamily INTEGER NOT NULL DEFAULT 1;

View File

@ -3,7 +3,8 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.settings.main
import androidx.compose.ui.graphics.Color
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.FontScale
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.MviModel
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.ListingType
import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.SortType
@ -12,8 +13,9 @@ interface SettingsMviModel :
MviModel<SettingsMviModel.Intent, SettingsMviModel.UiState, SettingsMviModel.Effect> {
sealed interface Intent {
data class ChangeTheme(val value: ThemeState) : Intent
data class ChangeUiTheme(val value: UiTheme) : Intent
data class ChangeUiFontSize(val value: Float) : Intent
data class ChangeUiFontFamily(val value: UiFontFamily) : Intent
data class ChangeContentFontSize(val value: Float) : Intent
data class ChangeLanguage(val value: String) : Intent
data class ChangeDefaultListingType(val value: ListingType) : Intent
@ -34,7 +36,8 @@ interface SettingsMviModel :
data class UiState(
val isLogged: Boolean = false,
val currentTheme: ThemeState = ThemeState.Light,
val uiTheme: UiTheme = UiTheme.Light,
val uiFontFamily: UiFontFamily = UiFontFamily.TitilliumWeb,
val customSeedColor: Color? = null,
val uiFontScale: FontScale = FontScale.Normal,
val contentFontScale: FontScale = FontScale.Normal,

View File

@ -41,7 +41,8 @@ import cafe.adriel.voyager.core.screen.Screen
import cafe.adriel.voyager.navigator.bottomSheet.LocalBottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.FontScale
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toReadableName
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getColorSchemeProvider
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
@ -49,6 +50,7 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing
import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getDrawerCoordinator
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ColorBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.FontFamilyBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.FontScaleBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.LanguageBottomSheet
import com.github.diegoberaldin.raccoonforlemmy.core.commonui.modals.ListingTypeBottomSheet
@ -177,12 +179,12 @@ class SettingsScreen : Screen {
// theme
SettingsRow(
title = stringResource(MR.strings.settings_ui_theme),
value = uiState.currentTheme.toReadableName(),
value = uiState.uiTheme.toReadableName(),
onTap = {
val sheet = ThemeBottomSheet()
notificationCenter.addObserver({ result ->
(result as? ThemeState)?.also { value ->
model.reduce(SettingsMviModel.Intent.ChangeTheme(value))
(result as? UiTheme)?.also { value ->
model.reduce(SettingsMviModel.Intent.ChangeUiTheme(value))
}
}, key, NotificationCenterContractKeys.ChangeTheme)
bottomSheetNavigator.show(sheet)
@ -209,7 +211,7 @@ class SettingsScreen : Screen {
SettingsColorRow(
title = stringResource(MR.strings.settings_custom_seed_color),
value = uiState.customSeedColor ?: colorSchemeProvider.getColorScheme(
theme = uiState.currentTheme,
theme = uiState.uiTheme,
dynamic = uiState.dynamicColors,
).primary,
onTap = {
@ -225,6 +227,24 @@ class SettingsScreen : Screen {
},
)
// font family
SettingsRow(
title = stringResource(MR.strings.settings_ui_font_family),
value = uiState.uiFontFamily.toReadableName(),
onTap = {
val sheet = FontFamilyBottomSheet()
notificationCenter.addObserver({ result ->
(result as? UiFontFamily)?.also { value ->
model.reduce(
SettingsMviModel.Intent.ChangeUiFontFamily(
value
)
)
}
}, key, NotificationCenterContractKeys.ChangeFontFamily)
bottomSheetNavigator.show(sheet)
},
)
// font scale
SettingsRow(
title = stringResource(MR.strings.settings_ui_font_scale),

View File

@ -4,7 +4,8 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import cafe.adriel.voyager.core.model.ScreenModel
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.PostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toFontScale
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toInt
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.repository.ThemeRepository
@ -58,8 +59,11 @@ class SettingsViewModel(
override fun onStarted() {
mvi.onStarted()
mvi.scope?.launch(Dispatchers.Main) {
themeRepository.state.onEach { currentTheme ->
mvi.updateState { it.copy(currentTheme = currentTheme) }
themeRepository.uiTheme.onEach { currentTheme ->
mvi.updateState { it.copy(uiTheme = currentTheme) }
}.launchIn(this)
themeRepository.uiFontFamily.onEach { fontFamily ->
mvi.updateState { it.copy(uiFontFamily = fontFamily) }
}.launchIn(this)
themeRepository.contentFontScale.onEach { value ->
mvi.updateState { it.copy(contentFontScale = value.toFontScale()) }
@ -108,10 +112,14 @@ class SettingsViewModel(
override fun reduce(intent: SettingsMviModel.Intent) {
when (intent) {
is SettingsMviModel.Intent.ChangeTheme -> {
is SettingsMviModel.Intent.ChangeUiTheme -> {
changeTheme(intent.value)
}
is SettingsMviModel.Intent.ChangeUiFontFamily -> {
changeFontFamily(intent.value)
}
is SettingsMviModel.Intent.ChangeContentFontSize -> {
changeContentFontScale(intent.value)
}
@ -177,8 +185,8 @@ class SettingsViewModel(
}
}
private fun changeTheme(value: ThemeState) {
themeRepository.changeTheme(value)
private fun changeTheme(value: UiTheme) {
themeRepository.changeUiTheme(value)
mvi.scope?.launch {
val settings = settingsRepository.currentSettings.value.copy(
theme = value.toInt()
@ -187,6 +195,16 @@ class SettingsViewModel(
}
}
private fun changeFontFamily(value: UiFontFamily) {
themeRepository.changeUiFontFamily(value)
mvi.scope?.launch {
val settings = settingsRepository.currentSettings.value.copy(
uiFontFamily = value.toInt()
)
saveSettings(settings)
}
}
private fun changeUiFontScale(value: Float) {
themeRepository.changeUiFontScale(value)
mvi.scope?.launch {

View File

@ -96,6 +96,7 @@
<string name="settings_theme_black">Pure black</string>
<string name="settings_language">Language</string>
<string name="settings_ui_font_scale">UI text size</string>
<string name="settings_ui_font_family">UI font</string>
<string name="settings_content_font_scale">Content text size</string>
<string name="settings_content_font_largest">Double extra large</string>
<string name="settings_content_font_larger">Extra large</string>

View File

@ -92,6 +92,7 @@
<string name="settings_theme_black">Oscuro (AMOLED)</string>
<string name="settings_language">Idioma</string>
<string name="settings_ui_font_scale">Tamaño de texto interfaz</string>
<string name="settings_ui_font_family">Fuente interfaz</string>
<string name="settings_content_font_scale">Tamaño de texto de contenidos</string>
<string name="settings_content_font_largest">Máximo</string>
<string name="settings_content_font_larger">Más grande</string>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -93,6 +93,7 @@
<string name="settings_theme_black">Scuro (AMOLED)</string>
<string name="settings_language">Lingua</string>
<string name="settings_ui_font_scale">Dimensione testo UI</string>
<string name="settings_ui_font_family">Font UI</string>
<string name="settings_content_font_scale">Dimensione testo contenuti</string>
<string name="settings_content_font_largest">Grandissimo</string>
<string name="settings_content_font_larger">Più grande</string>

View File

@ -32,10 +32,11 @@ import cafe.adriel.voyager.navigator.CurrentScreen
import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.Navigator
import cafe.adriel.voyager.navigator.bottomSheet.BottomSheetNavigator
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.ThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.UiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toInt
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toPostLayout
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toThemeState
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toUiFontFamily
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.data.toUiTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.di.getThemeRepository
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.AppTheme
import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.CornerSize
@ -72,9 +73,9 @@ fun App() {
hasBeenInitialized = true
}
val defaultTheme = if (isSystemInDarkTheme()) {
ThemeState.Dark.toInt()
UiTheme.Dark.toInt()
} else {
ThemeState.Light.toInt()
UiTheme.Light.toInt()
}
val defaultLocale = stringResource(MR.strings.lang)
@ -100,16 +101,17 @@ fun App() {
val themeRepository = remember { getThemeRepository() }
LaunchedEffect(settings) {
with(themeRepository) {
changeTheme((settings.theme ?: defaultTheme).toThemeState())
changeUiTheme((settings.theme ?: defaultTheme).toUiTheme())
changeNavItemTitles(settings.navigationTitlesVisible)
changeDynamicColors(settings.dynamicColors)
changeCustomSeedColor(settings.customSeedColor?.let { Color(it) })
changePostLayout(settings.postLayout.toPostLayout())
changeContentFontScale(settings.contentFontScale)
changeUiFontScale(settings.uiFontScale)
changeUiFontFamily(settings.uiFontFamily.toUiFontFamily())
}
}
val currentTheme by themeRepository.state.collectAsState()
val currentTheme by themeRepository.uiTheme.collectAsState()
val useDynamicColors by themeRepository.dynamicColors.collectAsState()
val fontScale by themeRepository.contentFontScale.collectAsState()
val uiFontScale by themeRepository.uiFontScale.collectAsState()