Respect incognito keyboard setting in Compose UIs.

This commit is contained in:
jeffrey-signal
2025-11-17 14:44:57 -05:00
committed by Cody Henthorne
parent d5150d44e3
commit 9f0f8b7cbc
71 changed files with 248 additions and 204 deletions

View File

@@ -16,7 +16,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.signal.core.ui.compose.theme.SignalTheme
object BottomSheets {
/**
@@ -37,7 +36,7 @@ object BottomSheets {
@Preview
@Composable
private fun HandlePreview() {
SignalTheme(isDarkMode = false) {
Previews.Preview {
BottomSheets.Handle()
}
}

View File

@@ -231,7 +231,10 @@ private fun SampleBox(
darkMode: Boolean,
content: @Composable BoxScope.() -> Unit
) {
SignalTheme(isDarkMode = darkMode) {
SignalTheme(
isDarkMode = darkMode,
incognitoKeyboardEnabled = false
) {
Surface {
Box(modifier = Modifier.padding(8.dp)) {
content()

View File

@@ -18,7 +18,6 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import org.signal.core.ui.compose.theme.SignalTheme
/**
* Thin divider lines for separating content.
@@ -55,7 +54,7 @@ object Dividers {
@DayNightPreviews
@Composable
private fun DefaultPreview() {
SignalTheme {
Previews.Preview {
Dividers.Default()
}
}
@@ -63,7 +62,7 @@ private fun DefaultPreview() {
@DayNightPreviews
@Composable
private fun VerticalPreview() {
SignalTheme {
Previews.Preview {
Dividers.Vertical(modifier = Modifier.height(20.dp))
}
}

View File

@@ -24,7 +24,9 @@ object Previews {
val dir = if (forceRtl) LayoutDirection.Rtl else LocalLayoutDirection.current
CompositionLocalProvider(LocalLayoutDirection provides dir) {
SignalTheme {
SignalTheme(
incognitoKeyboardEnabled = false
) {
Surface {
content()
}
@@ -40,7 +42,7 @@ object Previews {
val dir = if (forceRtl) LayoutDirection.Rtl else LocalLayoutDirection.current
CompositionLocalProvider(LocalLayoutDirection provides dir) {
SignalTheme {
SignalTheme(incognitoKeyboardEnabled = false) {
Surface {
Box(modifier = Modifier.background(color = SignalTheme.colors.colorSurface1)) {
content()

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.signal.core.ui.compose
import android.os.Build
import android.view.inputmethod.EditorInfo
import androidx.compose.runtime.Composable
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.platform.InterceptPlatformTextInput
import androidx.compose.ui.platform.PlatformTextInputMethodRequest
/**
* When [enabled]=true, this function sets the [EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING] flag for all text fields within its content to enable the
* incognito keyboard.
*
* This workaround is needed until it's possible to configure granular IME options for a [androidx.compose.material3.TextField].
* https://issuetracker.google.com/issues/359257538
*/
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun ProvideIncognitoKeyboard(
enabled: Boolean,
content: @Composable () -> Unit
) {
if (enabled) {
InterceptPlatformTextInput(
interceptor = { request, nextHandler ->
val modifiedRequest = PlatformTextInputMethodRequest { outAttributes ->
request.createInputConnection(outAttributes).also {
if (Build.VERSION.SDK_INT >= 26) {
outAttributes.imeOptions = outAttributes.imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
}
}
}
nextHandler.startInputMethod(modifiedRequest)
}
) {
content()
}
} else {
content()
}
}

View File

@@ -113,7 +113,7 @@ object Scaffolds {
@DayNightPreviews
@Composable
private fun SettingsScaffoldPreview() {
SignalTheme {
Previews.Preview {
val vector = remember {
ImageVector.Builder(
defaultWidth = 24.dp,
@@ -148,7 +148,7 @@ private fun SettingsScaffoldPreview() {
@DayNightPreviews
@Composable
private fun SettingsScaffoldNoNavIconPreview() {
SignalTheme {
Previews.Preview {
Scaffolds.Settings(
"Settings Scaffold",
onNavigationClick = {},

View File

@@ -14,7 +14,6 @@ import androidx.compose.material3.SnackbarVisuals
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import org.signal.core.ui.compose.theme.LocalSnackbarColors
import org.signal.core.ui.compose.theme.SignalTheme
/**
* Properly themed Snackbars. Since these use internal color state, we need to
@@ -46,7 +45,7 @@ object Snackbars {
@DayNightPreviews
@Composable
private fun SnackbarPreview() {
SignalTheme {
Previews.Preview {
Snackbars.Default(snackbarData = SampleSnackbarData)
}
}

View File

@@ -22,7 +22,6 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.text.getSpans
import org.signal.core.ui.R
import org.signal.core.ui.compose.theme.SignalTheme
object Texts {
/**
@@ -85,7 +84,7 @@ object Texts {
@Preview
@Composable
private fun SectionHeaderPreview() {
SignalTheme(isDarkMode = false) {
Previews.Preview {
Texts.SectionHeader("Header")
}
}

View File

@@ -1,6 +1,7 @@
package org.signal.core.ui.compose.theme
import android.content.res.Configuration
import androidx.annotation.Discouraged
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -15,6 +16,7 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import org.signal.core.ui.compose.ProvideIncognitoKeyboard
private val typography = Typography().run {
copy(
@@ -184,27 +186,34 @@ private val darkSnackbarColors = SnackbarColors(
dismissActionContentColor = darkColorScheme.onSurfaceVariant
)
@Discouraged("Use org.thoughtcrime.securesms.compose.SignalTheme instead.")
@Composable
fun SignalTheme(
isDarkMode: Boolean = LocalConfiguration.current.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES,
incognitoKeyboardEnabled: Boolean,
content: @Composable () -> Unit
) {
val extendedColors = if (isDarkMode) darkExtendedColors else lightExtendedColors
val snackbarColors = if (isDarkMode) darkSnackbarColors else lightSnackbarColors
CompositionLocalProvider(LocalExtendedColors provides extendedColors, LocalSnackbarColors provides snackbarColors) {
MaterialTheme(
colorScheme = if (isDarkMode) darkColorScheme else lightColorScheme,
typography = typography,
content = content
)
ProvideIncognitoKeyboard(enabled = incognitoKeyboardEnabled) {
CompositionLocalProvider(LocalExtendedColors provides extendedColors, LocalSnackbarColors provides snackbarColors) {
MaterialTheme(
colorScheme = if (isDarkMode) darkColorScheme else lightColorScheme,
typography = typography,
content = content
)
}
}
}
@Preview(showBackground = true)
@Composable
private fun TypographyPreview() {
SignalTheme(isDarkMode = false) {
SignalTheme(
isDarkMode = false,
incognitoKeyboardEnabled = false
) {
Column {
Text(
text = "Headline Small",
@@ -258,6 +267,7 @@ private fun TypographyPreview() {
}
}
@Discouraged("Use org.thoughtcrime.securesms.compose.SignalTheme instead.")
object SignalTheme {
val colors: ExtendedColors
@Composable