From ca8ed52cf0d9c0f0294eb60feb2f8f79452105d6 Mon Sep 17 00:00:00 2001 From: Justin Visser Date: Thu, 28 May 2026 12:49:55 +0200 Subject: [PATCH] Scale hardcoded fontSize sites by Text size level Adds a scaledSp(baseSp: Int) composable helper that returns a TextUnit scaled by the active text-size level. The lookup is a hand-mapped DisplaySizeLevel.scaledSp(Int) table for the known base sp values (integer outputs at every cell, no fractional sp). Unknown base sp values fall back to integer-rounded percent math instead of throwing, so the helper is safe to call from anywhere. scaledSp reads from LocalInterfaceCustomization.current.textSizeLevel so the same composition local that already carries the user's interface preferences also drives text scaling. 33 hardcoded fontSize = N.sp call sites across cards, components, playback overlay, nav, setup, and livetv go through scaledSp. This covers both plain text and FontAwesome icon-glyph sites: at the Default level the lookup returns the exact base sp, so today's rendered sizes are byte-identical. PlaybackController's file-level titleTextSize and subtitleTextSize constants are inlined as scaledSp(28) and scaledSp(18), keeping the rendering and PlaybackOverlay's height-offset math in lockstep at every level. The v1 scaledDensity helper in InterfaceHelpers.kt and its tests are deleted - they had no callers after MainContent's density override was removed. The InterfaceCustomization derived-getter doc comment is retuned to v2-valid percent values. --- .../wholphin/preferences/DisplaySizeLevels.kt | 67 +++++++++++++++++++ .../wholphin/ui/cards/BannerCard.kt | 4 +- .../wholphin/ui/cards/DiscoverItemCard.kt | 8 +-- .../wholphin/ui/cards/ItemCardImage.kt | 8 +-- .../wholphin/ui/cards/PersonCard.kt | 4 +- .../wholphin/ui/components/FilterByButton.kt | 4 +- .../wholphin/ui/components/PlayButtons.kt | 4 +- .../ui/components/SeriesComponents.kt | 4 +- .../wholphin/ui/components/TabRow.kt | 4 +- .../wholphin/ui/components/TimeDisplay.kt | 4 +- .../ui/components/VideoStreamDetails.kt | 4 +- .../ui/components/VoiceSearchButton.kt | 8 +-- .../wholphin/ui/detail/livetv/Components.kt | 12 ++-- .../ui/detail/music/NowPlayingButtons.kt | 8 +-- .../damontecres/wholphin/ui/nav/NavDrawer.kt | 4 +- .../ui/playback/overlay/PlaybackController.kt | 9 +-- .../ui/playback/overlay/PlaybackControls.kt | 4 +- .../playback/overlay/PlaybackDebugOverlay.kt | 4 +- .../ui/playback/overlay/PlaybackOverlay.kt | 11 +-- .../ui/playback/overlay/SkipIndicator.kt | 4 +- .../ui/preferences/NavDrawerPreference.kt | 4 +- .../wholphin/ui/setup/InstallUpdatePage.kt | 6 +- .../damontecres/wholphin/ui/setup/PinEntry.kt | 4 +- .../damontecres/wholphin/ui/setup/UserList.kt | 4 +- .../wholphin/ui/util/InterfaceHelpers.kt | 24 +++---- .../wholphin/ui/util/InterfaceHelpersTest.kt | 30 --------- 26 files changed, 138 insertions(+), 113 deletions(-) diff --git a/app/src/main/java/com/github/damontecres/wholphin/preferences/DisplaySizeLevels.kt b/app/src/main/java/com/github/damontecres/wholphin/preferences/DisplaySizeLevels.kt index 6d1fdc84..ae53c1f4 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/preferences/DisplaySizeLevels.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/preferences/DisplaySizeLevels.kt @@ -1,5 +1,8 @@ package com.github.damontecres.wholphin.preferences +import androidx.compose.ui.unit.TextUnit +import androidx.compose.ui.unit.sp + val displaySizeLevelDisplayOrder: List = listOf( DisplaySizeLevel.EXTRA_SMALL, @@ -8,6 +11,70 @@ val displaySizeLevelDisplayOrder: List = DisplaySizeLevel.LARGE, ) +fun DisplaySizeLevel.scaledSp(baseSp: Int): TextUnit { + if (this == DisplaySizeLevel.DEFAULT || this == DisplaySizeLevel.UNRECOGNIZED) { + return baseSp.sp + } + val mapped = + when (this) { + DisplaySizeLevel.EXTRA_SMALL -> { + when (baseSp) { + 10 -> 9 + 12 -> 11 + 13 -> 11 + 14 -> 12 + 16 -> 14 + 18 -> 16 + 20 -> 18 + 24 -> 21 + 28 -> 25 + 56 -> 49 + 64 -> 56 + else -> null + } + } + + DisplaySizeLevel.SMALL -> { + when (baseSp) { + 10 -> 9 + 12 -> 11 + 13 -> 12 + 14 -> 13 + 16 -> 15 + 18 -> 17 + 20 -> 19 + 24 -> 23 + 28 -> 26 + 56 -> 53 + 64 -> 60 + else -> null + } + } + + DisplaySizeLevel.LARGE -> { + when (baseSp) { + 10 -> 11 + 12 -> 13 + 13 -> 14 + 14 -> 15 + 16 -> 17 + 18 -> 19 + 20 -> 22 + 24 -> 26 + 28 -> 30 + 56 -> 60 + 64 -> 69 + else -> null + } + } + + else -> { + null + } + } + return mapped?.sp ?: ((baseSp * textPercent() + 50) / 100).sp +} + fun DisplaySizeLevel.textPercent(): Int = when (this) { DisplaySizeLevel.EXTRA_SMALL -> 88 diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/BannerCard.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/BannerCard.kt index 8d00edfd..bcc9044b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/BannerCard.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/BannerCard.kt @@ -34,7 +34,6 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.isSpecified -import androidx.compose.ui.unit.sp import androidx.tv.material3.Card import androidx.tv.material3.CardDefaults import androidx.tv.material3.MaterialTheme @@ -48,6 +47,7 @@ import com.github.damontecres.wholphin.ui.Cards import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.LocalImageUrlService import com.github.damontecres.wholphin.ui.enableMarquee +import com.github.damontecres.wholphin.ui.util.scaledSp import org.jellyfin.sdk.model.api.ImageType /** @@ -179,7 +179,7 @@ fun BannerCard( .padding(8.dp), color = colorResource(android.R.color.holo_red_light), text = stringResource(R.string.fa_heart), - fontSize = 16.sp, + fontSize = scaledSp(16), fontFamily = FontAwesome, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/DiscoverItemCard.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/DiscoverItemCard.kt index 3b5fabc2..2fbd1cd5 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/DiscoverItemCard.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/DiscoverItemCard.kt @@ -30,7 +30,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.Card import androidx.tv.material3.CardDefaults import androidx.tv.material3.MaterialTheme @@ -46,6 +45,7 @@ import com.github.damontecres.wholphin.ui.PreviewTvSpec import com.github.damontecres.wholphin.ui.enableMarquee import com.github.damontecres.wholphin.ui.theme.WholphinTheme import com.github.damontecres.wholphin.ui.util.LocalInterfaceCustomization +import com.github.damontecres.wholphin.ui.util.scaledSp import kotlinx.coroutines.delay @Composable @@ -157,7 +157,7 @@ fun DiscoverItemCard( Text( text = pluralStringResource(it, 1), style = MaterialTheme.typography.bodySmall, - fontSize = 10.sp, + fontSize = scaledSp(10), modifier = Modifier .align(Alignment.TopStart) @@ -224,7 +224,7 @@ fun PendingIndicator(modifier: Modifier = Modifier) { Text( text = stringResource(R.string.fa_bell), fontFamily = FontAwesome, - fontSize = 10.sp, + fontSize = scaledSp(10), color = AppColors.Discover.Yellow, modifier = Modifier.align(Alignment.Center), ) @@ -249,7 +249,7 @@ fun AvailableIndicator(modifier: Modifier = Modifier) { Text( text = stringResource(R.string.fa_check), fontFamily = FontAwesome, - fontSize = 10.sp, + fontSize = scaledSp(10), color = Color.White, modifier = Modifier.align(Alignment.Center), ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/ItemCardImage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/ItemCardImage.kt index 63f6bdd8..0436dcaa 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/ItemCardImage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/ItemCardImage.kt @@ -29,7 +29,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import coil3.compose.AsyncImage @@ -41,6 +40,7 @@ import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.LocalImageUrlService import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.logCoilError +import com.github.damontecres.wholphin.ui.util.scaledSp import org.jellyfin.sdk.model.api.ImageType /** @@ -166,7 +166,7 @@ fun BoxScope.ItemCardImageFallback( Text( text = name, color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 14.sp, + fontSize = scaledSp(14), modifier = Modifier .padding(8.dp) @@ -222,7 +222,6 @@ fun ItemCardImageOverlay( text = numberOfVersions.toString(), color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.bodyMedium, -// fontSize = 16.sp, modifier = Modifier.padding(4.dp), ) } @@ -255,7 +254,6 @@ fun ItemCardImageOverlay( text = unwatchedCount.toString(), color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.bodyMedium, -// fontSize = 16.sp, modifier = Modifier.padding(4.dp), ) } @@ -280,7 +278,7 @@ fun ItemCardImageOverlay( @Composable fun FavoriteIndicator( modifier: Modifier = Modifier, - fontSize: TextUnit = 20.sp, + fontSize: TextUnit = scaledSp(20), ) = Text( color = colorResource(android.R.color.holo_red_light), text = stringResource(R.string.fa_heart), diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/PersonCard.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/PersonCard.kt index 4e146134..a737f61f 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/cards/PersonCard.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/cards/PersonCard.kt @@ -32,7 +32,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.Border import androidx.tv.material3.Card import androidx.tv.material3.CardDefaults @@ -45,6 +44,7 @@ import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.PreviewTvSpec import com.github.damontecres.wholphin.ui.enableMarquee import com.github.damontecres.wholphin.ui.theme.WholphinTheme +import com.github.damontecres.wholphin.ui.util.scaledSp import kotlinx.coroutines.delay import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.api.PersonKind @@ -153,7 +153,7 @@ fun PersonCard( text = stringResource(R.string.fa_user), fontFamily = FontAwesome, color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 64.sp, + fontSize = scaledSp(64), textAlign = TextAlign.Center, modifier = Modifier diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/FilterByButton.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/FilterByButton.kt index e881bb98..da656735 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/FilterByButton.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/FilterByButton.kt @@ -31,7 +31,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.Icon import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text @@ -54,6 +53,7 @@ import com.github.damontecres.wholphin.ui.FontAwesome import com.github.damontecres.wholphin.ui.PreviewTvSpec import com.github.damontecres.wholphin.ui.theme.WholphinTheme import com.github.damontecres.wholphin.ui.tryRequestFocus +import com.github.damontecres.wholphin.ui.util.scaledSp import java.util.UUID /** @@ -399,7 +399,7 @@ fun ExpandableFilterButton( text = stringResource(R.string.fa_filter), style = MaterialTheme.typography.titleSmall, color = iconColor, - fontSize = 16.sp, + fontSize = scaledSp(16), fontFamily = FontAwesome, textAlign = TextAlign.Center, modifier = Modifier.align(Alignment.Center), diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/PlayButtons.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/PlayButtons.kt index ca4c11b8..6763148b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/PlayButtons.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/PlayButtons.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.Icon import androidx.tv.material3.LocalContentColor import androidx.tv.material3.MaterialTheme @@ -59,6 +58,7 @@ import com.github.damontecres.wholphin.ui.data.SortAndDirection import com.github.damontecres.wholphin.ui.ifElse import com.github.damontecres.wholphin.ui.theme.PreviewInteractionSource import com.github.damontecres.wholphin.ui.theme.WholphinTheme +import com.github.damontecres.wholphin.ui.util.scaledSp import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.SortOrder import kotlin.time.Duration @@ -329,7 +329,7 @@ fun ExpandableFaButton( text = stringResource(iconStringRes), style = MaterialTheme.typography.titleSmall, color = iconColor, - fontSize = 16.sp, + fontSize = scaledSp(16), fontFamily = FontAwesome, textAlign = TextAlign.Center, modifier = Modifier.align(Alignment.Center), diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/SeriesComponents.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/SeriesComponents.kt index 0ea3d74f..1d518734 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/SeriesComponents.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/SeriesComponents.kt @@ -4,9 +4,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.unit.sp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text +import com.github.damontecres.wholphin.ui.util.scaledSp import org.jellyfin.sdk.model.api.BaseItemDto @Composable @@ -34,7 +34,7 @@ fun EpisodeName( text = episodeName ?: "", color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.headlineSmall, - fontSize = 20.sp, + fontSize = scaledSp(20), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = modifier, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/TabRow.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/TabRow.kt index f54fda5b..e2283023 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/TabRow.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/TabRow.kt @@ -36,12 +36,12 @@ import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.ui.PreviewTvSpec import com.github.damontecres.wholphin.ui.theme.WholphinTheme import com.github.damontecres.wholphin.ui.tryRequestFocus +import com.github.damontecres.wholphin.ui.util.scaledSp import timber.log.Timber @Composable @@ -147,7 +147,7 @@ fun Tab( ) { Text( text = title, - fontSize = 16.sp, + fontSize = scaledSp(16), color = contentColor, modifier = Modifier.padding(horizontal = 16.dp), ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/TimeDisplay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/TimeDisplay.kt index f70a4f6a..0a603bcd 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/TimeDisplay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/TimeDisplay.kt @@ -7,10 +7,10 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.ui.util.LocalClock +import com.github.damontecres.wholphin.ui.util.scaledSp /** * Displays the [LocalClock] in the upper right corner of the parent [androidx.compose.foundation.layout.Box] @@ -20,7 +20,7 @@ fun BoxScope.TimeDisplay(modifier: Modifier = Modifier) { val timeString by LocalClock.current.timeString Text( text = timeString, - fontSize = 18.sp, + fontSize = scaledSp(18), color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.bodyLarge, modifier = diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/VideoStreamDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/VideoStreamDetails.kt index 083dded6..ae8e4881 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/VideoStreamDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/VideoStreamDetails.kt @@ -23,7 +23,6 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.ProvideTextStyle import androidx.tv.material3.Text @@ -41,6 +40,7 @@ import com.github.damontecres.wholphin.ui.util.StreamFormatting.formatAudioCodec import com.github.damontecres.wholphin.ui.util.StreamFormatting.formatSubtitleCodec import com.github.damontecres.wholphin.ui.util.StreamFormatting.formatVideoRange import com.github.damontecres.wholphin.ui.util.StreamFormatting.resolutionString +import com.github.damontecres.wholphin.ui.util.scaledSp import com.github.damontecres.wholphin.util.languageName import org.jellyfin.sdk.model.api.MediaSourceInfo import org.jellyfin.sdk.model.api.MediaStream @@ -185,7 +185,7 @@ fun StreamLabel( ProvideTextStyle( TextStyle( color = MaterialTheme.colorScheme.onSurface, - fontSize = 12.sp, + fontSize = scaledSp(12), fontWeight = FontWeight.SemiBold, ), ) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/VoiceSearchButton.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/VoiceSearchButton.kt index 3042ac06..56896a65 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/VoiceSearchButton.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/VoiceSearchButton.kt @@ -43,7 +43,6 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.tv.material3.ButtonDefaults @@ -54,13 +53,12 @@ import androidx.tv.material3.Text import androidx.tv.material3.surfaceColorAtElevation import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.ui.FontAwesome +import com.github.damontecres.wholphin.ui.util.scaledSp import kotlinx.coroutines.delay private const val ERROR_AUTO_DISMISS_DELAY_MS = 3000L private const val SOUND_LEVEL_SCALE_FACTOR = 0.15f private val BUBBLE_SIZE = 160.dp -private val MIC_ICON_FONT_SIZE = 56.sp -private val BUTTON_ICON_FONT_SIZE = 20.sp private val CONTENT_SPACING = 48.dp private val HORIZONTAL_PADDING = 64.dp private val DISMISS_HINT_BOTTOM_PADDING = 32.dp @@ -174,7 +172,7 @@ fun VoiceSearchButton( Text( text = stringResource(R.string.fa_microphone), fontFamily = FontAwesome, - fontSize = BUTTON_ICON_FONT_SIZE, + fontSize = scaledSp(20), textAlign = TextAlign.Center, modifier = Modifier.semantics { contentDescription = voiceSearchDesc }, ) @@ -347,7 +345,7 @@ private fun VoiceSearchOverlay( Text( text = stringResource(R.string.fa_microphone), fontFamily = FontAwesome, - fontSize = MIC_ICON_FONT_SIZE, + fontSize = scaledSp(56), color = onPrimaryColor, textAlign = TextAlign.Center, modifier = Modifier.semantics { contentDescription = voiceSearchDesc }, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/livetv/Components.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/livetv/Components.kt index 41d53fd5..b2668ff2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/livetv/Components.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/livetv/Components.kt @@ -19,7 +19,6 @@ import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.ClickableSurfaceDefaults import androidx.tv.material3.LocalContentColor import androidx.tv.material3.MaterialTheme @@ -29,6 +28,7 @@ import androidx.tv.material3.surfaceColorAtElevation import coil3.compose.AsyncImage import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.ui.FontAwesome +import com.github.damontecres.wholphin.ui.util.scaledSp import java.time.LocalDateTime @Composable @@ -87,7 +87,7 @@ fun Program( text = stringResource(R.string.fa_caret_left), fontFamily = FontAwesome, color = LocalContentColor.current, - fontSize = 16.sp, + fontSize = scaledSp(16), modifier = Modifier .align(Alignment.CenterVertically) @@ -104,7 +104,7 @@ fun Program( Text( text = title, color = LocalContentColor.current, - fontSize = 16.sp, + fontSize = scaledSp(16), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier, @@ -120,7 +120,7 @@ fun Program( Text( text = it, color = LocalContentColor.current, - fontSize = 14.sp, + fontSize = scaledSp(14), overflow = TextOverflow.Ellipsis, modifier = Modifier, ) @@ -197,7 +197,7 @@ fun Channel( Text( text = it, style = MaterialTheme.typography.bodySmall, - fontSize = if (showImage) 10.sp else 16.sp, + fontSize = if (showImage) scaledSp(10) else scaledSp(16), maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier, @@ -209,7 +209,7 @@ fun Channel( Text( color = colorResource(android.R.color.holo_red_light), text = stringResource(R.string.fa_heart), - fontSize = 16.sp, + fontSize = scaledSp(16), fontFamily = FontAwesome, modifier = Modifier diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingButtons.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingButtons.kt index db5bbf4c..7361d123 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingButtons.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/music/NowPlayingButtons.kt @@ -24,7 +24,6 @@ import androidx.compose.ui.focus.onFocusChanged import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi import androidx.media3.ui.compose.state.rememberNextButtonState @@ -48,6 +47,7 @@ import com.github.damontecres.wholphin.ui.playback.overlay.PlaybackFaButton import com.github.damontecres.wholphin.ui.playback.overlay.buttonSpacing import com.github.damontecres.wholphin.ui.theme.PreviewInteractionSource import com.github.damontecres.wholphin.ui.theme.WholphinTheme +import com.github.damontecres.wholphin.ui.util.scaledSp import kotlin.time.Duration.Companion.seconds @OptIn(UnstableApi::class) @@ -176,7 +176,7 @@ fun ShuffleButton( ) { Text( text = stringResource(R.string.fa_shuffle), - fontSize = 18.sp, + fontSize = scaledSp(18), fontFamily = FontAwesome, textAlign = TextAlign.Center, color = @@ -228,7 +228,7 @@ fun RepeatButton( ) { Text( text = stringResource(R.string.fa_repeat), - fontSize = 18.sp, + fontSize = scaledSp(18), fontFamily = FontAwesome, textAlign = TextAlign.Center, color = @@ -253,7 +253,7 @@ fun RepeatButton( if (repeatMode == Player.REPEAT_MODE_ONE) { Text( text = "1", - fontSize = 10.sp, + fontSize = scaledSp(10), color = MaterialTheme.colorScheme.surface, modifier = Modifier diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt index af4ec63f..48016405 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt @@ -53,7 +53,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.findViewTreeViewModelStoreOwner @@ -89,6 +88,7 @@ import com.github.damontecres.wholphin.ui.spacedByWithFooter import com.github.damontecres.wholphin.ui.theme.LocalTheme import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.ui.tryRequestFocus +import com.github.damontecres.wholphin.ui.util.scaledSp import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -717,7 +717,7 @@ fun NavigationDrawerScope.NavItem( Text( text = stringResource(icon), textAlign = TextAlign.Center, - fontSize = 16.sp, + fontSize = scaledSp(16), fontFamily = FontAwesome, color = color, modifier = Modifier, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackController.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackController.kt index 528b6546..3d73fd9b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackController.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackController.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.media3.common.Player import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text @@ -35,6 +34,7 @@ import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.ui.getTimeFormatter import com.github.damontecres.wholphin.ui.playback.ControllerViewState import com.github.damontecres.wholphin.ui.playback.PlaybackDialogType +import com.github.damontecres.wholphin.ui.util.scaledSp import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import org.jellyfin.sdk.model.api.MediaSegmentDto @@ -121,9 +121,6 @@ fun PlaybackController( } } -internal val titleTextSize = 28.sp -internal val subtitleTextSize = 18.sp - /** * A wrapper for the playback controls to show title and other information, plus the actual controls * @@ -175,7 +172,7 @@ fun Controller( Text( text = it, style = MaterialTheme.typography.titleLarge, - fontSize = titleTextSize, + fontSize = scaledSp(28), maxLines = 1, overflow = TextOverflow.MiddleEllipsis, modifier = Modifier.fillMaxWidth(.75f), @@ -192,7 +189,7 @@ fun Controller( Text( text = it, style = MaterialTheme.typography.titleMedium, - fontSize = subtitleTextSize, + fontSize = scaledSp(18), maxLines = 1, overflow = TextOverflow.MiddleEllipsis, modifier = Modifier.fillMaxWidth(.75f), diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackControls.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackControls.kt index 820e634f..9161fbe7 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackControls.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackControls.kt @@ -49,7 +49,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogWindowProvider @@ -79,6 +78,7 @@ import com.github.damontecres.wholphin.ui.skipStringRes import com.github.damontecres.wholphin.ui.theme.LocalTheme import com.github.damontecres.wholphin.ui.theme.WholphinTheme import com.github.damontecres.wholphin.ui.tryRequestFocus +import com.github.damontecres.wholphin.ui.util.scaledSp import com.github.damontecres.wholphin.util.ExceptionHandler import kotlinx.coroutines.delay import kotlinx.coroutines.isActive @@ -497,7 +497,7 @@ fun PlaybackFaButton( ) { Text( text = stringResource(iconRes), - fontSize = 18.sp, + fontSize = scaledSp(18), fontFamily = FontAwesome, textAlign = TextAlign.Center, color = diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackDebugOverlay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackDebugOverlay.kt index 1420ffb6..51ded17c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackDebugOverlay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackDebugOverlay.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.media3.common.Format import androidx.media3.common.util.UnstableApi import androidx.tv.material3.MaterialTheme @@ -33,6 +32,7 @@ import com.github.damontecres.wholphin.ui.letNotEmpty import com.github.damontecres.wholphin.ui.playback.AnalyticsState import com.github.damontecres.wholphin.ui.playback.CurrentPlayback import com.github.damontecres.wholphin.ui.theme.WholphinTheme +import com.github.damontecres.wholphin.ui.util.scaledSp import com.github.damontecres.wholphin.util.TrackSupport import com.github.damontecres.wholphin.util.TrackSupportReason import com.github.damontecres.wholphin.util.TrackType @@ -85,7 +85,7 @@ fun PlaybackDebugOverlay( } val textStyle = MaterialTheme.typography.bodySmall.copy( - fontSize = 10.sp, + fontSize = scaledSp(10), color = MaterialTheme.colorScheme.onSurface, ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackOverlay.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackOverlay.kt index 96adc4df..3927dbe5 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackOverlay.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/PlaybackOverlay.kt @@ -61,6 +61,7 @@ import com.github.damontecres.wholphin.ui.playback.AnalyticsState import com.github.damontecres.wholphin.ui.playback.ControllerViewState import com.github.damontecres.wholphin.ui.playback.CurrentPlayback import com.github.damontecres.wholphin.ui.playback.PlaybackDialogType +import com.github.damontecres.wholphin.ui.util.scaledSp import org.jellyfin.sdk.model.api.ImageType import org.jellyfin.sdk.model.api.MediaSegmentDto import org.jellyfin.sdk.model.api.TrickplayInfo @@ -105,13 +106,15 @@ fun PlaybackOverlay( val density = LocalDensity.current + val titleSp = scaledSp(28) + val subtitleSp = scaledSp(18) val titleHeight = - remember(item?.title) { - if (item?.title.isNotNullOrBlank()) with(density) { titleTextSize.toDp() } else 0.dp + remember(item?.title, titleSp) { + if (item?.title.isNotNullOrBlank()) with(density) { titleSp.toDp() } else 0.dp } val subtitleHeight = - remember(item?.subtitleLong) { - if (item?.subtitleLong.isNotNullOrBlank()) with(density) { subtitleTextSize.toDp() } else 0.dp + remember(item?.subtitleLong, subtitleSp) { + if (item?.subtitleLong.isNotNullOrBlank()) with(density) { subtitleSp.toDp() } else 0.dp } // This will be calculated after composition diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/SkipIndicator.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/SkipIndicator.kt index 3ac39bfa..b5d35de4 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/SkipIndicator.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/playback/overlay/SkipIndicator.kt @@ -18,11 +18,11 @@ import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.scale import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.ui.ifElse +import com.github.damontecres.wholphin.ui.util.scaledSp import kotlin.math.abs /** @@ -63,7 +63,7 @@ fun SkipIndicator( Text( modifier = Modifier.align(Alignment.Center), color = MaterialTheme.colorScheme.onBackground, - fontSize = 13.sp, + fontSize = scaledSp(13), style = MaterialTheme.typography.bodySmall, text = abs(durationMs / 1000).toString(), ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/NavDrawerPreference.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/NavDrawerPreference.kt index e8c768a4..0e2ab226 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/NavDrawerPreference.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/preferences/NavDrawerPreference.kt @@ -30,7 +30,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.datastore.core.DataStore import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.ViewModel @@ -59,6 +58,7 @@ import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.main.settings.MoveDirection import com.github.damontecres.wholphin.ui.nav.NavDrawerItem import com.github.damontecres.wholphin.ui.theme.WholphinTheme +import com.github.damontecres.wholphin.ui.util.scaledSp import com.github.damontecres.wholphin.util.ExceptionHandler import com.github.damontecres.wholphin.util.RememberTabManager import dagger.hilt.android.lifecycle.HiltViewModel @@ -275,7 +275,7 @@ fun MoveButton( ) { Text( text = stringResource(icon), - fontSize = 16.sp, + fontSize = scaledSp(16), fontFamily = FontAwesome, textAlign = TextAlign.Center, modifier = Modifier.fillMaxWidth(), diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/InstallUpdatePage.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/InstallUpdatePage.kt index a3bd52e4..533bfba2 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/InstallUpdatePage.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/InstallUpdatePage.kt @@ -36,7 +36,6 @@ import androidx.compose.ui.input.key.onKeyEvent import androidx.compose.ui.input.key.type import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -60,6 +59,7 @@ import com.github.damontecres.wholphin.ui.dimAndBlur import com.github.damontecres.wholphin.ui.formatBytes import com.github.damontecres.wholphin.ui.launchIO import com.github.damontecres.wholphin.ui.theme.WholphinTheme +import com.github.damontecres.wholphin.ui.util.scaledSp import com.github.damontecres.wholphin.util.ExceptionHandler import com.github.damontecres.wholphin.util.LoadingState import com.github.damontecres.wholphin.util.Version @@ -369,7 +369,7 @@ fun DownloadDialog( ) { Text( text = stringResource(R.string.downloading), - fontSize = 24.sp, + fontSize = scaledSp(24), color = MaterialTheme.colorScheme.onSurface, ) if (progress != null) { @@ -396,7 +396,7 @@ fun DownloadDialog( val size = formatBytes(contentLength) Text( text = "$bytes / $size", - fontSize = 18.sp, + fontSize = scaledSp(18), color = MaterialTheme.colorScheme.onSurface, ) } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/PinEntry.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/PinEntry.kt index f9f22591..b0847b31 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/PinEntry.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/PinEntry.kt @@ -27,7 +27,6 @@ import androidx.compose.ui.input.key.type import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text import com.github.damontecres.wholphin.R @@ -38,6 +37,7 @@ import com.github.damontecres.wholphin.ui.components.Button import com.github.damontecres.wholphin.ui.components.TextButton import com.github.damontecres.wholphin.ui.playback.isEnterKey import com.github.damontecres.wholphin.ui.theme.WholphinTheme +import com.github.damontecres.wholphin.ui.util.scaledSp @Composable fun PinEntry( @@ -101,7 +101,7 @@ fun PinEntry( ) Text( text = stringResource(R.string.will_remove_pin), - fontSize = 10.sp, + fontSize = scaledSp(10), ) } } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/UserList.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/UserList.kt index ddc171c9..2b44f1eb 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/UserList.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/UserList.kt @@ -39,7 +39,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp import androidx.compose.ui.window.DialogProperties import androidx.tv.material3.Border import androidx.tv.material3.Button @@ -60,6 +59,7 @@ import com.github.damontecres.wholphin.ui.isNotNullOrBlank import com.github.damontecres.wholphin.ui.theme.WholphinTheme import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.ui.tryRequestFocus +import com.github.damontecres.wholphin.ui.util.scaledSp import java.util.UUID /** @@ -333,7 +333,7 @@ fun UserIconCardImage( Text( text = firstLetter, style = MaterialTheme.typography.bodyLarge, - fontSize = 14.sp, + fontSize = scaledSp(14), fontWeight = FontWeight.Normal, color = MaterialTheme.colorScheme.onSurface, textAlign = TextAlign.Center, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/util/InterfaceHelpers.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/util/InterfaceHelpers.kt index 018b9b56..8c06c339 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/util/InterfaceHelpers.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/util/InterfaceHelpers.kt @@ -1,11 +1,13 @@ package com.github.damontecres.wholphin.ui.util import androidx.compose.runtime.Composable -import androidx.compose.ui.unit.Density +import androidx.compose.runtime.ReadOnlyComposable import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.preferences.AppSliderPreference +import com.github.damontecres.wholphin.preferences.scaledSp import com.github.damontecres.wholphin.ui.AspectRatio import com.github.damontecres.wholphin.ui.Cards @@ -26,8 +28,8 @@ internal fun naturalCardBaseDp(aspectRatio: AspectRatio): Int = AspectRatio.TALL, AspectRatio.SQUARE, AspectRatio.FOUR_THREE -> Cards.HEIGHT_2X3_DP } -// The global Card slider, the per-row multiplier, and any preset-set absolute heightDp -// all stack. Preset 148dp + global 150% + per-row 100% = 222dp. The base is the row's +// The global Card size, the per-row multiplier, and any preset-set absolute heightDp +// all stack. Preset 148dp + global 116% + per-row 110% = ~189dp. The base is the row's // preset if present, otherwise the natural height for its aspect. internal fun resolveCardHeight( heightDp: Int, @@ -40,19 +42,9 @@ internal fun resolveCardHeight( return base * globalCardSizePercent / 100 * cardSizeMultiplier / 100 } -// Scales density (and therefore both dp layouts and sp text) linearly by uiScalePercent. -// fontScale is left at the user's system value so Android's accessibility setting still -// applies on top - scaling both would render text at factor^2 instead of factor. -internal fun scaledDensity( - base: Density, - uiScalePercent: Int, -): Density { - val factor = uiScalePercent / 100f - return Density( - density = base.density * factor, - fontScale = base.fontScale, - ) -} +@Composable +@ReadOnlyComposable +internal fun scaledSp(baseSp: Int): TextUnit = LocalInterfaceCustomization.current.textSizeLevel.scaledSp(baseSp) internal fun Int.withinBoundsOrDefault(preference: AppSliderPreference<*>): Int { val min = preference.min.toInt() diff --git a/app/src/test/java/com/github/damontecres/wholphin/ui/util/InterfaceHelpersTest.kt b/app/src/test/java/com/github/damontecres/wholphin/ui/util/InterfaceHelpersTest.kt index 8951e0d9..c4624fd5 100644 --- a/app/src/test/java/com/github/damontecres/wholphin/ui/util/InterfaceHelpersTest.kt +++ b/app/src/test/java/com/github/damontecres/wholphin/ui/util/InterfaceHelpersTest.kt @@ -1,6 +1,5 @@ package com.github.damontecres.wholphin.ui.util -import androidx.compose.ui.unit.Density import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowViewOptions import com.github.damontecres.wholphin.preferences.AppPreference @@ -102,35 +101,6 @@ class InterfaceHelpersTest { assertEquals(Cards.HEIGHT_2X3_DP, naturalCardBaseDp(AspectRatio.FOUR_THREE)) } - @Test - fun `scaledDensity scales density linearly and leaves fontScale alone`() { - val base = Density(density = 2.0f, fontScale = 1.0f) - val scaled = scaledDensity(base, 150) - // density grows by 1.5 - so dp layouts scale 1.5x. - assertEquals(3.0f, scaled.density, 0.001f) - // fontScale stays put - sp text is (density * fontScale) so it also scales linearly. - // Scaling fontScale too would render text at 1.5^2 = 2.25x. - assertEquals(1.0f, scaled.fontScale, 0.001f) - } - - @Test - fun `scaledDensity at 100 percent returns identity`() { - val base = Density(density = 2.0f, fontScale = 1.2f) - val scaled = scaledDensity(base, 100) - assertEquals(base.density, scaled.density, 0.001f) - assertEquals(base.fontScale, scaled.fontScale, 0.001f) - } - - @Test - fun `scaledDensity preserves user accessibility fontScale across UI scale changes`() { - // A user with system fontScale 1.3x (accessibility setting) bumping UI scale to 75% - // should keep fontScale = 1.3 - the UI scale slider is independent of accessibility. - val base = Density(density = 2.0f, fontScale = 1.3f) - val scaled = scaledDensity(base, 75) - assertEquals(1.5f, scaled.density, 0.001f) - assertEquals(1.3f, scaled.fontScale, 0.001f) - } - @Test fun `InterfaceCustomization cardHeightDp at DEFAULT level matches natural base`() { val customization = InterfaceCustomization(prefs = AppPreferences.getDefaultInstance())