diff --git a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/components/ComposeExtensions.kt b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/components/ComposeExtensions.kt index a5cd5c5..91a635d 100644 --- a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/components/ComposeExtensions.kt +++ b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/components/ComposeExtensions.kt @@ -1,12 +1,14 @@ package net.dzikoysk.presenceofmind.components import androidx.compose.runtime.Composable +import androidx.compose.runtime.ProvidableCompositionLocal +import androidx.compose.runtime.compositionLocalOf import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.sp +val LocalFontScale: ProvidableCompositionLocal = compositionLocalOf { 1f } + @Composable fun Int.scaledSp(): TextUnit = - with(LocalDensity.current) { - (this@scaledSp / this.fontScale).sp - } + (this@scaledSp / LocalDensity.current.fontScale * LocalFontScale.current).sp diff --git a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/model/presence/PresenceRepository.kt b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/model/presence/PresenceRepository.kt index f04cec3..eacc0ec 100644 --- a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/model/presence/PresenceRepository.kt +++ b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/model/presence/PresenceRepository.kt @@ -5,6 +5,7 @@ import androidx.core.content.edit import net.dzikoysk.presenceofmind.BuildConfig private const val DEFAULT_AVATAR = "https://avatars.githubusercontent.com/u/75123628?s=200&v=4" +private const val DEFAULT_FONT_SCALE = 1f sealed interface PresenceRepository { @@ -17,6 +18,8 @@ sealed interface PresenceRepository { fun setAvatarUrl(url: String) fun getAvatarUrl(): String + fun setFontScale(size: Float) + fun getFontScale(): Float } class SharedPreferencesPresenceRepository( @@ -27,6 +30,7 @@ class SharedPreferencesPresenceRepository( private val lightModeId = "light-mode-$version" private val latestVersionCodeId = "latest-version-code-$version" private val avatarUrlId = "avatar-url-$version" + private val fontScaleId = "font-scale-$version" private fun setProperty(modifier: SharedPreferences.Editor.() -> Unit): Unit = sharedPreferences.edit(commit = true) { modifier(this) } @@ -40,6 +44,8 @@ class SharedPreferencesPresenceRepository( override fun setAvatarUrl(url: String) = setProperty { putString(avatarUrlId, url) } override fun getAvatarUrl(): String = sharedPreferences.getString(avatarUrlId, DEFAULT_AVATAR).takeUnless { it.isNullOrEmpty() }?: DEFAULT_AVATAR + override fun setFontScale(size: Float) = setProperty { putFloat(fontScaleId, size) } + override fun getFontScale(): Float = sharedPreferences.getFloat(fontScaleId, DEFAULT_FONT_SCALE) } class InMemoryPresenceRepository : PresenceRepository { @@ -47,6 +53,7 @@ class InMemoryPresenceRepository : PresenceRepository { private var lightMode = true private var latestVersionCode = BuildConfig.VERSION_CODE private var avatarUrl = DEFAULT_AVATAR + private var fontSize: Float = DEFAULT_FONT_SCALE override fun setColorMode(isLightMode: Boolean) { this.lightMode = isLightMode } override fun isLightMode(): Boolean = lightMode @@ -57,5 +64,7 @@ class InMemoryPresenceRepository : PresenceRepository { override fun setAvatarUrl(url: String) { this.avatarUrl = url } override fun getAvatarUrl(): String = avatarUrl + override fun setFontScale(size: Float) { this.fontSize = size } + override fun getFontScale(): Float = this.fontSize } diff --git a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/Router.kt b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/Router.kt index 2d1a1ca..9ba33ef 100644 --- a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/Router.kt +++ b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/Router.kt @@ -1,9 +1,11 @@ package net.dzikoysk.presenceofmind.pages import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.tooling.preview.Preview +import net.dzikoysk.presenceofmind.components.LocalFontScale import net.dzikoysk.presenceofmind.createDefaultTasks import net.dzikoysk.presenceofmind.model.presence.InMemoryPresenceRepository import net.dzikoysk.presenceofmind.model.presence.PresenceOfMindTheme @@ -38,21 +40,25 @@ fun Router( page: Page ) { PresenceOfMindTheme(lightTheme = presenceRepository.isLightMode()) { - val currentPage = remember { mutableStateOf(page) } + CompositionLocalProvider(LocalFontScale provides presenceRepository.getFontScale()) { + val currentPage = remember { mutableStateOf(page) } - when (currentPage.value) { - Page.DASHBOARD -> - Dashboard( - presenceRepository = presenceRepository, - taskService = taskService, - restartActivity = restartActivity, - changePage = { currentPage.value = it } - ) - Page.SETTINGS -> - Settings( - presenceRepository = presenceRepository, - changePage = { currentPage.value = it } - ) + when (currentPage.value) { + Page.DASHBOARD -> + Dashboard( + presenceRepository = presenceRepository, + taskService = taskService, + restartActivity = restartActivity, + changePage = { currentPage.value = it } + ) + + Page.SETTINGS -> + Settings( + presenceRepository = presenceRepository, + restartActivity = restartActivity, + changePage = { currentPage.value = it }, + ) + } } } } \ No newline at end of file diff --git a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/Dashboard.kt b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/Dashboard.kt index 0b155ad..c6dd118 100644 --- a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/Dashboard.kt +++ b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/Dashboard.kt @@ -68,10 +68,11 @@ fun Dashboard( openMenu = { openMenu.value = true } ) TodayLabel( - modifier = Modifier.padding(start = 16.dp) + modifier = Modifier + .padding(start = 16.dp) + .weight(1f, fill = false) ) Row( - modifier = Modifier.weight(2f), horizontalArrangement = Arrangement.End ) { ChangeThemeButton( diff --git a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/TodayLabel.kt b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/TodayLabel.kt index 83c6bcb..cf3f270 100644 --- a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/TodayLabel.kt +++ b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/TodayLabel.kt @@ -7,8 +7,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.text.withStyle +import androidx.compose.ui.tooling.preview.Preview import net.dzikoysk.presenceofmind.components.scaledSp import java.time.Instant import java.time.ZoneId @@ -16,6 +21,7 @@ import java.time.format.DateTimeFormatter import java.util.Locale @Composable +@Preview(showBackground = true) fun TodayLabel(modifier: Modifier = Modifier) { val todayFormatter = remember { DateTimeFormatter.ofPattern("E dd.MM") @@ -23,30 +29,29 @@ fun TodayLabel(modifier: Modifier = Modifier) { .withZone(ZoneId.systemDefault()) } - val fontSize = 13.scaledSp() + val style = SpanStyle( + fontWeight = FontWeight.Bold, + fontSize = 13.scaledSp() + ) Column(modifier) { + Text( + buildAnnotatedString { + withStyle(style.copy(color = Color(0xFF777777))) { + append("Today is ") + } + withStyle(style.copy(textDecoration = TextDecoration.Underline)) { + append(todayFormatter.format(Instant.now())) + } + } + ) Row { Text( - text = "Today is ", - fontWeight = FontWeight.Bold, - color = Color(0xFF777777), - fontSize = fontSize - ) - Text( - text = todayFormatter.format(Instant.now()), - fontWeight = FontWeight.Bold, - textDecoration = TextDecoration.Underline, - fontSize = fontSize - ) - } - Row { - Text( - text = "Suggested activities for you:", - fontWeight = FontWeight.Bold, - color = Color(0xFF777777), - fontSize = fontSize + AnnotatedString( + "Suggested activities for you:", + style.copy(color = Color(0xFF777777)) + ) ) } } -} \ No newline at end of file +} diff --git a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/list/attributes/ChecklistAttributeRenderer.kt b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/list/attributes/ChecklistAttributeRenderer.kt index aca0ed6..9b5dc56 100644 --- a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/list/attributes/ChecklistAttributeRenderer.kt +++ b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/dashboard/list/attributes/ChecklistAttributeRenderer.kt @@ -1,11 +1,11 @@ package net.dzikoysk.presenceofmind.pages.dashboard.list.attributes -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.padding import androidx.compose.material.Checkbox import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.unit.TextUnit @@ -40,22 +40,17 @@ fun ChecklistAttributeRenderer( ) } - Box(modifier = Modifier.padding(start = 3.dp)) { + Column(modifier = Modifier.padding(start = 3.dp)) { checklistAttribute.list .sortedBy { it.done } - .forEachIndexed { idx, subtask -> - Row( - modifier = Modifier.padding(top = (30 * idx).dp), - horizontalArrangement = Arrangement.SpaceBetween, - ) { - ChecklistEntryRenderer( - task = task, - checklistAttribute = checklistAttribute, - entry = subtask, - fontSize = fontSize, - updateTask = updateTask - ) - } + .forEach { subtask -> + ChecklistEntryRenderer( + task = task, + checklistAttribute = checklistAttribute, + entry = subtask, + fontSize = fontSize, + updateTask = updateTask + ) } } } @@ -68,7 +63,7 @@ fun ChecklistEntryRenderer( fontSize: TextUnit, updateTask: UpdateTask ) { - Row { + Row(verticalAlignment = Alignment.CenterVertically) { Checkbox( checked = entry.done, onCheckedChange = { @@ -84,8 +79,7 @@ fun ChecklistEntryRenderer( ) DescriptionMarkdown( description = entry.description, - fontSize = fontSize, - modifier = Modifier.padding(top = 15.dp) + fontSize = fontSize ) } } \ No newline at end of file diff --git a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/settings/Settings.kt b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/settings/Settings.kt index 4ca06e6..490a6f9 100644 --- a/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/settings/Settings.kt +++ b/pom-application/app/src/main/java/net/dzikoysk/presenceofmind/pages/settings/Settings.kt @@ -1,11 +1,20 @@ package net.dzikoysk.presenceofmind.pages.settings +import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.material.Icon +import androidx.compose.material.Slider import androidx.compose.material.Text import androidx.compose.material.TextField import androidx.compose.runtime.Composable @@ -13,15 +22,18 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import net.dzikoysk.presenceofmind.R +import net.dzikoysk.presenceofmind.components.NumberField import net.dzikoysk.presenceofmind.components.scaledSp import net.dzikoysk.presenceofmind.model.presence.InMemoryPresenceRepository import net.dzikoysk.presenceofmind.model.presence.PresenceRepository import net.dzikoysk.presenceofmind.pages.Page +import kotlin.math.roundToInt @Preview(showBackground = false) @Composable @@ -32,14 +44,17 @@ fun SettingsPreview() { @Composable fun Settings( presenceRepository: PresenceRepository = InMemoryPresenceRepository(), + restartActivity: () -> Unit = {}, changePage: (Page) -> Unit = {} ) { val avatarUrl = remember { mutableStateOf(presenceRepository.getAvatarUrl()) } + val fontSize = remember { mutableStateOf(presenceRepository.getFontScale()) } Column( modifier = Modifier .fillMaxSize() - .padding(horizontal = 16.dp) + .padding(horizontal = 16.dp), + verticalArrangement = Arrangement.spacedBy(16.dp, Alignment.Top) ) { Row( verticalAlignment = Alignment.CenterVertically, @@ -47,7 +62,9 @@ fun Settings( .padding(vertical = 24.dp) .clickable { presenceRepository.setAvatarUrl(avatarUrl.value) + presenceRepository.setFontScale(fontSize.value) changePage(Page.DASHBOARD) + restartActivity() } ) { Icon( @@ -72,9 +89,32 @@ fun Settings( TextField( value = avatarUrl.value, - onValueChange = { avatarUrl.value = it } + onValueChange = { avatarUrl.value = it } + ) + } + } + + Row { + Column { + Text( + fontSize = 15.scaledSp(), + text = "Font scale", + modifier = Modifier.padding(bottom = 5.dp) + ) + + Slider( + value = fontSize.value, + onValueChange = { fontSize.value = it.roundFontSize() }, + valueRange = 1f..2f, + steps = 10 + ) + + Text( + text = fontSize.value.toString() ) } } } -} \ No newline at end of file +} +private fun Float.roundFontSize(): Float = + (this * 10).roundToInt() / 10f