refactor: add dynamic font scaling support and integrate ProvideDynamicTypeFontScale across modules
This commit is contained in:
1 parent
df38936893
commit
abeb484258
12 files changed
+143
-1
No files matched your search
@@ -1,9 +1,18 @@
|
||||
plugins {
|
||||
id("gwenedeg.kmp.library")
|
||||
id("gwenedeg.compose")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
androidLibrary {
|
||||
namespace = "bzh.ajaury.chombev.core.accessibility"
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
// UI - Compose
|
||||
implementation(libs.compose.runtime)
|
||||
implementation(libs.compose.ui)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package bzh.ajaury.chombev.core.accessibility.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
/** No-op: the font scale already follows the system setting. */
|
||||
@Composable
|
||||
actual fun ProvideDynamicTypeFontScale(content: @Composable () -> Unit) = content()
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package bzh.ajaury.chombev.core.accessibility.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
/**
|
||||
* Applies the system text size to [content] as soon as the user changes it.
|
||||
*
|
||||
* Only needed on iOS, see its implementation. Every Compose scene must be wrapped: the root one
|
||||
* and each dialog or bottom sheet, which iOS renders in a scene of its own that does not inherit
|
||||
* the font scale provided by the root one.
|
||||
*/
|
||||
@Composable
|
||||
expect fun ProvideDynamicTypeFontScale(content: @Composable () -> Unit)
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package bzh.ajaury.chombev.core.accessibility.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.Density
|
||||
import platform.Foundation.NSNotificationCenter
|
||||
import platform.Foundation.NSOperationQueue
|
||||
import platform.UIKit.UIApplication
|
||||
import platform.UIKit.UIContentSizeCategoryAccessibilityExtraExtraExtraLarge
|
||||
import platform.UIKit.UIContentSizeCategoryAccessibilityExtraExtraLarge
|
||||
import platform.UIKit.UIContentSizeCategoryAccessibilityExtraLarge
|
||||
import platform.UIKit.UIContentSizeCategoryAccessibilityLarge
|
||||
import platform.UIKit.UIContentSizeCategoryAccessibilityMedium
|
||||
import platform.UIKit.UIContentSizeCategoryDidChangeNotification
|
||||
import platform.UIKit.UIContentSizeCategoryExtraExtraExtraLarge
|
||||
import platform.UIKit.UIContentSizeCategoryExtraExtraLarge
|
||||
import platform.UIKit.UIContentSizeCategoryExtraLarge
|
||||
import platform.UIKit.UIContentSizeCategoryExtraSmall
|
||||
import platform.UIKit.UIContentSizeCategoryLarge
|
||||
import platform.UIKit.UIContentSizeCategoryMedium
|
||||
import platform.UIKit.UIContentSizeCategorySmall
|
||||
|
||||
/**
|
||||
* Applies the system text size (Dynamic Type) to [content] as soon as the user changes it.
|
||||
*
|
||||
* Compose Multiplatform reads the font scale once, when the Compose scene is created, so a change
|
||||
* made in the iOS settings only shows once the scene is created again: after the app restarts for
|
||||
* the root scene, or when it is opened again for a dialog or bottom sheet. Workaround for CMP-10365
|
||||
* (https://youtrack.jetbrains.com/issue/CMP-10365), fixed in Compose Multiplatform 1.13.0: remove
|
||||
* it once the project is upgraded.
|
||||
*/
|
||||
@Composable
|
||||
actual fun ProvideDynamicTypeFontScale(content: @Composable () -> Unit) {
|
||||
var contentSizeCategory by remember {
|
||||
mutableStateOf(UIApplication.sharedApplication.preferredContentSizeCategory)
|
||||
}
|
||||
|
||||
DisposableEffect(Unit) {
|
||||
val notificationCenter = NSNotificationCenter.defaultCenter
|
||||
val observer = notificationCenter.addObserverForName(
|
||||
name = UIContentSizeCategoryDidChangeNotification,
|
||||
`object` = null,
|
||||
queue = NSOperationQueue.mainQueue,
|
||||
) { _ ->
|
||||
contentSizeCategory = UIApplication.sharedApplication.preferredContentSizeCategory
|
||||
}
|
||||
onDispose { notificationCenter.removeObserver(observer) }
|
||||
}
|
||||
|
||||
val density = LocalDensity.current
|
||||
// Only the font scale is overridden: the pixel density stays the one Compose computed.
|
||||
val fontScale = contentSizeCategoryToFontScale[contentSizeCategory] ?: density.fontScale
|
||||
CompositionLocalProvider(
|
||||
LocalDensity provides Density(density = density.density, fontScale = fontScale),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
|
||||
// Same mapping as Compose Multiplatform (`uiContentSizeCategoryToFontScaleMap`, which is private),
|
||||
// so that the font scale matches the one Compose computes when the scene is created.
|
||||
private val contentSizeCategoryToFontScale = mapOf(
|
||||
UIContentSizeCategoryExtraSmall to 0.8f,
|
||||
UIContentSizeCategorySmall to 0.85f,
|
||||
UIContentSizeCategoryMedium to 0.9f,
|
||||
UIContentSizeCategoryLarge to 1f,
|
||||
UIContentSizeCategoryExtraLarge to 1.1f,
|
||||
UIContentSizeCategoryExtraExtraLarge to 1.2f,
|
||||
UIContentSizeCategoryExtraExtraExtraLarge to 1.3f,
|
||||
UIContentSizeCategoryAccessibilityMedium to 1.4f,
|
||||
UIContentSizeCategoryAccessibilityLarge to 1.5f,
|
||||
UIContentSizeCategoryAccessibilityExtraLarge to 1.6f,
|
||||
UIContentSizeCategoryAccessibilityExtraExtraLarge to 1.7f,
|
||||
UIContentSizeCategoryAccessibilityExtraExtraExtraLarge to 1.8f,
|
||||
)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package bzh.ajaury.chombev.core.accessibility.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
/** No-op: the font scale already follows the system setting. */
|
||||
@Composable
|
||||
actual fun ProvideDynamicTypeFontScale(content: @Composable () -> Unit) = content()
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package bzh.ajaury.chombev.core.accessibility.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
/** No-op: the font scale already follows the system setting. */
|
||||
@Composable
|
||||
actual fun ProvideDynamicTypeFontScale(content: @Composable () -> Unit) = content()
|
||||
@@ -13,6 +13,9 @@ kotlin {
|
||||
implementation(libs.compose.uiToolingPreview)
|
||||
}
|
||||
commonMain.dependencies {
|
||||
// Core modules
|
||||
implementation(projects.core.accessibility)
|
||||
|
||||
// Data modules
|
||||
implementation(projects.data.preferences)
|
||||
implementation(projects.data.resources)
|
||||
|
||||
+3
@@ -33,6 +33,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import bzh.ajaury.chombev.core.accessibility.ui.ProvideDynamicTypeFontScale
|
||||
import bzh.ajaury.chombev.onboarding.model.OnboardingLevel
|
||||
import bzh.ajaury.chombev.onboarding.ui.components.OnboardingInfoPage
|
||||
import bzh.ajaury.chombev.onboarding.ui.components.OnboardingLevelPage
|
||||
@@ -90,6 +91,7 @@ fun OnboardingScreen(
|
||||
// The content sizes itself against the window rather than the platform default width.
|
||||
properties = DialogProperties(usePlatformDefaultWidth = false),
|
||||
) {
|
||||
ProvideDynamicTypeFontScale {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.sizeIn(maxWidth = DIALOG_MAX_WIDTH, maxHeight = DIALOG_MAX_HEIGHT)
|
||||
@@ -105,6 +107,7 @@ fun OnboardingScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Scaffold { innerPadding ->
|
||||
OnboardingContent(
|
||||
|
||||
+3
@@ -14,6 +14,7 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import bzh.ajaury.chombev.core.accessibility.ui.ProvideDynamicTypeFontScale
|
||||
import bzh.ajaury.chombev.player.ui.components.LabeledSlider
|
||||
import bzh.ajaury.chombev.preferences.model.PlaybackPreferences
|
||||
import bzh.ajaury.chombev.preferences.ui.PreferenceToggle
|
||||
@@ -50,6 +51,7 @@ fun PlaybackSpeedBottomSheet(
|
||||
onDismissRequest = onDismiss,
|
||||
sheetState = sheetState,
|
||||
) {
|
||||
ProvideDynamicTypeFontScale {
|
||||
PlaybackSpeedContent(
|
||||
speed = speed,
|
||||
breakSeconds = breakSeconds,
|
||||
@@ -60,6 +62,7 @@ fun PlaybackSpeedBottomSheet(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PlaybackSpeedContent(
|
||||
|
||||
+3
@@ -32,6 +32,7 @@ import androidx.compose.ui.semantics.setProgress
|
||||
import androidx.compose.ui.semantics.stateDescription
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import bzh.ajaury.chombev.core.accessibility.ui.ProvideDynamicTypeFontScale
|
||||
import bzh.ajaury.chombev.preferences.model.SubtitlePreferences
|
||||
import bzh.ajaury.chombev.resources.generated.resources.Res
|
||||
import bzh.ajaury.chombev.resources.generated.resources.subtitle_marked_letters_description
|
||||
@@ -68,6 +69,7 @@ fun SubtitlePreferencesBottomSheet(
|
||||
onDismissRequest = onDismiss,
|
||||
sheetState = sheetState,
|
||||
) {
|
||||
ProvideDynamicTypeFontScale {
|
||||
SubtitlePreferencesContent(
|
||||
subtitlePreferences = subtitlePreferences,
|
||||
onShowTranscriptionChange = onShowTranscriptionChange,
|
||||
@@ -78,6 +80,7 @@ fun SubtitlePreferencesBottomSheet(
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SubtitlePreferencesContent(
|
||||
|
||||
@@ -35,6 +35,7 @@ kotlin {
|
||||
}
|
||||
commonMain.dependencies {
|
||||
// Core modules
|
||||
implementation(projects.core.accessibility)
|
||||
implementation(projects.core.coroutines)
|
||||
implementation(projects.core.logging)
|
||||
implementation(projects.core.model)
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
package bzh.ajaury.chombev
|
||||
|
||||
import androidx.compose.ui.window.ComposeUIViewController
|
||||
import bzh.ajaury.chombev.core.accessibility.ui.ProvideDynamicTypeFontScale
|
||||
|
||||
@Suppress("ktlint:standard:function-naming")
|
||||
fun MainViewController() = ComposeUIViewController { App() }
|
||||
fun MainViewController() =
|
||||
ComposeUIViewController {
|
||||
ProvideDynamicTypeFontScale {
|
||||
App()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user