diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml
index 9430665b..81de5467 100644
--- a/i18n/src/main/res/values/strings.xml
+++ b/i18n/src/main/res/values/strings.xml
@@ -411,6 +411,8 @@
Generate from primary color
Light color scheme
Dark color scheme
+ Font
+ System default
About
Version
Links
diff --git a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt
index a46272cf..7ddad708 100644
--- a/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt
+++ b/preferences/src/main/java/de/mm20/launcher2/preferences/Defaults.kt
@@ -17,6 +17,7 @@ fun createFactorySettings(context: Context): Settings {
.setLightScheme(DefaultLightCustomColorScheme)
.setDarkScheme(DefaultDarkCustomColorScheme)
)
+ .setFont(Settings.AppearanceSettings.Font.Poppins)
.build()
)
.setWeather(
diff --git a/preferences/src/main/proto/settings.proto b/preferences/src/main/proto/settings.proto
index b7a28933..359729fc 100644
--- a/preferences/src/main/proto/settings.proto
+++ b/preferences/src/main/proto/settings.proto
@@ -70,6 +70,12 @@ message Settings {
Pager = 1;
}
Layout layout = 9;
+
+ enum Font {
+ Poppins = 0;
+ SystemDefault = 1;
+ }
+ Font font = 10;
}
AppearanceSettings appearance = 2;
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/ListPreference.kt b/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/ListPreference.kt
index 9d7ccdf2..a3edfcae 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/ListPreference.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/component/preferences/ListPreference.kt
@@ -1,10 +1,7 @@
package de.mm20.launcher2.ui.component.preferences
import androidx.compose.foundation.clickable
-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.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -25,7 +22,12 @@ fun ListPreference(
value: T,
summary: String? = items.firstOrNull { value == it.value }?.label,
onValueChanged: (T) -> Unit,
- enabled: Boolean = true
+ enabled: Boolean = true,
+ itemLabel: @Composable RowScope.(item: ListPreferenceItem) -> Unit = {
+ Text(
+ text = it.label,
+ )
+ }
) {
var showDialog by remember { mutableStateOf(false) }
Preference(
@@ -71,16 +73,24 @@ fun ListPreference(
onValueChanged(it.value)
showDialog = false
}
- .padding(start = 16.dp, top = 4.dp, bottom = 4.dp, end = 24.dp)
+ .padding(
+ start = 16.dp,
+ top = 16.dp,
+ bottom = 16.dp,
+ end = 24.dp
+ )
) {
- RadioButton(selected = it.value == value, onClick = {
- onValueChanged(it.value)
- showDialog = false
- })
- Text(
- text = it.label,
- modifier = Modifier.padding(start = 16.dp)
+ RadioButton(
+ selected = it.value == value,
+ onClick = null,
+ modifier = Modifier
+ .padding(end = 16.dp)
)
+ CompositionLocalProvider(
+ LocalTextStyle provides MaterialTheme.typography.titleMedium
+ ) {
+ itemLabel(it)
+ }
}
}
}
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt
index 20c66b18..1f03c47e 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreen.kt
@@ -41,6 +41,7 @@ import de.mm20.launcher2.ui.component.preferences.*
import de.mm20.launcher2.ui.launcher.search.SearchBar
import de.mm20.launcher2.ui.launcher.search.SearchBarLevel
import de.mm20.launcher2.ui.locals.LocalNavController
+import de.mm20.launcher2.ui.theme.getTypography
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
@@ -86,6 +87,25 @@ fun AppearanceSettingsScreen() {
navController?.navigate("settings/appearance/colorscheme")
}
)
+ val font by viewModel.font.observeAsState()
+ ListPreference(
+ title = stringResource(R.string.preference_font),
+ items = listOf(
+ "Poppins" to AppearanceSettings.Font.Poppins,
+ stringResource(R.string.preference_font_system) to AppearanceSettings.Font.SystemDefault,
+ ),
+ value = font,
+ onValueChanged = {
+ if (it != null) viewModel.setFont(it)
+ },
+ itemLabel = {
+ val typography = remember(it.value) {
+ getTypography(context, it.value)
+ }
+ Text(it.first, style = typography.titleMedium)
+ }
+ )
+
Preference(
title = stringResource(R.string.preference_cards),
summary = stringResource(R.string.preference_cards_summary),
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt
index 27b0fd8e..b110cea8 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/appearance/AppearanceSettingsScreenVM.kt
@@ -7,8 +7,7 @@ import de.mm20.launcher2.icons.IconPack
import de.mm20.launcher2.icons.IconRepository
import de.mm20.launcher2.preferences.LauncherDataStore
import de.mm20.launcher2.preferences.Settings
-import de.mm20.launcher2.preferences.Settings.AppearanceSettings.ColorScheme
-import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
+import de.mm20.launcher2.preferences.Settings.AppearanceSettings.*
import de.mm20.launcher2.preferences.Settings.SearchBarSettings
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
@@ -42,6 +41,17 @@ class AppearanceSettingsScreenVM : ViewModel(), KoinComponent {
}
}
+ val font = dataStore.data.map { it.appearance.font }.asLiveData()
+ fun setFont(font: Font) {
+ viewModelScope.launch {
+ dataStore.updateData {
+ it.toBuilder()
+ .setAppearance(it.appearance.toBuilder().setFont(font))
+ .build()
+ }
+ }
+ }
+
val columnCount = dataStore.data.map { it.grid.columnCount }.asLiveData()
fun setColumnCount(columnCount: Int) {
viewModelScope.launch {
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/theme/LauncherTheme.kt b/ui/src/main/java/de/mm20/launcher2/ui/theme/LauncherTheme.kt
index abfca97b..1a250162 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/theme/LauncherTheme.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/theme/LauncherTheme.kt
@@ -1,5 +1,6 @@
package de.mm20.launcher2.ui.theme
+import android.content.Context
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.shape.CornerSize
@@ -16,6 +17,7 @@ import de.mm20.launcher2.preferences.Settings.AppearanceSettings.Theme
import de.mm20.launcher2.ui.locals.LocalDarkTheme
import de.mm20.launcher2.ui.theme.colorscheme.*
import de.mm20.launcher2.ui.theme.typography.DefaultTypography
+import de.mm20.launcher2.ui.theme.typography.getDeviceDefaultTypography
import kotlinx.coroutines.flow.map
import org.koin.androidx.compose.inject
@@ -25,6 +27,7 @@ fun LauncherTheme(
content: @Composable () -> Unit
) {
+ val context = LocalContext.current
val dataStore: LauncherDataStore by inject()
val colorSchemePreference by remember {
@@ -48,7 +51,7 @@ fun LauncherTheme(
val baseShape by remember {
dataStore.data.map {
- when(it.cards.shape) {
+ when (it.cards.shape) {
Settings.CardSettings.Shape.Cut -> CutCornerShape(0f)
else -> RoundedCornerShape(0f)
}
@@ -57,12 +60,20 @@ fun LauncherTheme(
val colorScheme by colorSchemeAsState(colorSchemePreference, darkTheme)
+ val font by remember { dataStore.data.map { it.appearance.font } }.collectAsState(
+ AppearanceSettings.Font.Poppins
+ )
+
+ val typography = remember(font) {
+ getTypography(context, font)
+ }
+
CompositionLocalProvider(
LocalDarkTheme provides darkTheme
) {
MaterialTheme(
colorScheme = colorScheme,
- typography = DefaultTypography,
+ typography = typography,
shapes = Shapes(
extraSmall = baseShape.copy(CornerSize(cornerRadius / 3f)),
small = baseShape.copy(CornerSize(cornerRadius / 3f * 2f)),
@@ -76,7 +87,10 @@ fun LauncherTheme(
}
@Composable
-fun colorSchemeAsState(colorScheme: AppearanceSettings.ColorScheme, darkTheme: Boolean): MutableState {
+fun colorSchemeAsState(
+ colorScheme: AppearanceSettings.ColorScheme,
+ darkTheme: Boolean
+): MutableState {
val context = LocalContext.current
val dataStore: LauncherDataStore by inject()
@@ -134,3 +148,10 @@ fun colorSchemeAsState(colorScheme: AppearanceSettings.ColorScheme, darkTheme: B
}
}
+
+fun getTypography(context: Context, font: AppearanceSettings.Font?): Typography {
+ return when (font) {
+ AppearanceSettings.Font.SystemDefault -> getDeviceDefaultTypography(context)
+ else -> DefaultTypography
+ }
+}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/Default.kt b/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/Default.kt
index ceed1b73..9cce7953 100644
--- a/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/Default.kt
+++ b/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/Default.kt
@@ -2,4 +2,4 @@ package de.mm20.launcher2.ui.theme.typography
import de.mm20.launcher2.ui.theme.typography.fontfamily.Poppins
-val DefaultTypography = makeTypography(headlineFamily = Poppins)
+val DefaultTypography = makeTypography(headlineFamily = Poppins)
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/SystemDefault.kt b/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/SystemDefault.kt
new file mode 100644
index 00000000..2df017cb
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/SystemDefault.kt
@@ -0,0 +1,10 @@
+package de.mm20.launcher2.ui.theme.typography
+
+import android.content.Context
+import androidx.compose.material3.Typography
+import androidx.compose.ui.text.font.*
+import de.mm20.launcher2.ui.theme.typography.fontfamily.getDeviceHeadlineFontFamily
+
+fun getDeviceDefaultTypography(context: Context): Typography {
+ return makeTypography(headlineFamily = getDeviceHeadlineFontFamily(context))
+}
\ No newline at end of file
diff --git a/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/fontfamily/DeviceDefault.kt b/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/fontfamily/DeviceDefault.kt
new file mode 100644
index 00000000..8cbb348a
--- /dev/null
+++ b/ui/src/main/java/de/mm20/launcher2/ui/theme/typography/fontfamily/DeviceDefault.kt
@@ -0,0 +1,38 @@
+package de.mm20.launcher2.ui.theme.typography.fontfamily
+
+import android.content.Context
+import androidx.compose.ui.text.ExperimentalTextApi
+import androidx.compose.ui.text.font.*
+
+@OptIn(ExperimentalTextApi::class)
+fun getDeviceHeadlineFontFamily(context: Context): FontFamily {
+ val configResId = context.resources
+ .getIdentifier("config_headlineFontFamily", "string", "android")
+
+ if (configResId != 0) {
+ val fontFamily = context.resources.getString(configResId)
+ return FontFamily(
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Thin, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.ExtraLight, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Light, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Normal, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Medium, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.SemiBold, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Bold, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.ExtraBold, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Black, style = FontStyle.Normal),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Thin, style = FontStyle.Italic),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.ExtraLight, style = FontStyle.Italic),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Light, style = FontStyle.Italic),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Normal, style = FontStyle.Italic),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Medium, style = FontStyle.Italic),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.SemiBold, style = FontStyle.Italic),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Bold, style = FontStyle.Italic),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.ExtraBold, style = FontStyle.Italic),
+ Font(DeviceFontFamilyName(fontFamily), weight = FontWeight.Black, style = FontStyle.Italic),
+ )
+ }
+
+ return FontFamily.SansSerif
+
+}
\ No newline at end of file