From 855918bbf4cfc893656eaf8a045519a0d1f52023 Mon Sep 17 00:00:00 2001 From: Mend Renovate Date: Sat, 12 Sep 2026 13:21:37 +0100 Subject: [PATCH] Update dependency androidx.compose:compose-bom-alpha to v2026.09.00 (#3752) Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../kanade/presentation/components/AppBar.kt | 85 ++++++++++++------- .../settings/screen/SettingsTrackingScreen.kt | 32 ++++--- .../reader/components/ChapterNavigator.kt | 24 ++++-- gradle/libs.versions.toml | 2 +- .../core/components/SettingsItems.kt | 1 + .../core/components/material/Slider.kt | 16 +++- 6 files changed, 100 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt index 17e01b67f..1de650944 100644 --- a/app/src/main/java/eu/kanade/presentation/components/AppBar.kt +++ b/app/src/main/java/eu/kanade/presentation/components/AppBar.kt @@ -6,8 +6,11 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.BasicTextField -import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.input.TextFieldLineLimits +import androidx.compose.foundation.text.input.clearText +import androidx.compose.foundation.text.input.rememberTextFieldState +import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Icon import androidx.compose.material3.IconButton @@ -25,12 +28,15 @@ import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.rememberTooltipState import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.key import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusDirection import androidx.compose.ui.focus.FocusRequester @@ -42,10 +48,10 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction -import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.coroutines.flow.drop import mihon.icons.materialsymbols.MaterialSymbols import mihon.icons.materialsymbols.automirroredrounded.ArrowBack import mihon.icons.materialsymbols.rounded.Close @@ -272,10 +278,26 @@ fun SearchToolbar( onClickCloseSearch: () -> Unit = { onChangeSearchQuery(null) }, actions: @Composable RowScope.() -> Unit = {}, scrollBehavior: TopAppBarScrollBehavior? = null, - visualTransformation: VisualTransformation = VisualTransformation.None, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, ) { val focusRequester = remember { FocusRequester() } + val searchFieldState = rememberTextFieldState(searchQuery.orEmpty()) + val currentOnChangeSearchQuery by rememberUpdatedState(onChangeSearchQuery) + val searchOpen by rememberUpdatedState(searchQuery != null) + + LaunchedEffect(searchFieldState) { + snapshotFlow { searchFieldState.text.toString() } + .drop(1) + .collect { if (searchOpen) currentOnChangeSearchQuery(it) } + } + LaunchedEffect(searchQuery) { + when { + searchQuery == null -> searchFieldState.clearText() + searchQuery != searchFieldState.text.toString() -> { + searchFieldState.setTextAndPlaceCursorAtEnd(searchQuery) + } + } + } AppBar( modifier = modifier, @@ -286,16 +308,16 @@ fun SearchToolbar( val focusManager = LocalFocusManager.current val searchAndClearFocus: () -> Unit = f@{ - if (searchQuery.isBlank()) return@f - onSearch(searchQuery) + val query = searchFieldState.text.toString() + if (query.isBlank()) return@f + onSearch(query) focusManager.clearFocus() keyboardController?.hide() focusManager.moveFocus(FocusDirection.Next) } BasicTextField( - value = searchQuery, - onValueChange = onChangeSearchQuery, + state = searchFieldState, modifier = Modifier .fillMaxWidth() .focusRequester(focusRequester) @@ -308,34 +330,30 @@ fun SearchToolbar( fontSize = 18.sp, ), keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search), - keyboardActions = KeyboardActions(onSearch = { searchAndClearFocus() }), - singleLine = true, + onKeyboardAction = { searchAndClearFocus() }, + lineLimits = TextFieldLineLimits.SingleLine, cursorBrush = SolidColor(MaterialTheme.colorScheme.onBackground), - visualTransformation = visualTransformation, interactionSource = interactionSource, - decorationBox = { innerTextField -> - TextFieldDefaults.DecorationBox( - value = searchQuery, - innerTextField = innerTextField, - enabled = true, - singleLine = true, - visualTransformation = visualTransformation, - interactionSource = interactionSource, - placeholder = { - Text( - modifier = Modifier.secondaryItemAlpha(), - text = (placeholderText ?: stringResource(MR.strings.action_search_hint)), - maxLines = 1, - overflow = TextOverflow.Ellipsis, - style = MaterialTheme.typography.titleMedium.copy( - fontSize = 18.sp, - fontWeight = FontWeight.Normal, - ), - ) - }, - container = {}, - ) - }, + decorator = TextFieldDefaults.decorator( + state = searchFieldState, + enabled = true, + lineLimits = TextFieldLineLimits.SingleLine, + outputTransformation = null, + interactionSource = interactionSource, + placeholder = { + Text( + modifier = Modifier.secondaryItemAlpha(), + text = (placeholderText ?: stringResource(MR.strings.action_search_hint)), + maxLines = 1, + overflow = TextOverflow.Ellipsis, + style = MaterialTheme.typography.titleMedium.copy( + fontSize = 18.sp, + fontWeight = FontWeight.Normal, + ), + ) + }, + container = {}, + ), ) }, navigateUp = if (searchQuery == null) navigateUp else onClickCloseSearch, @@ -378,6 +396,7 @@ fun SearchToolbar( ) { IconButton( onClick = { + searchFieldState.clearText() onClick() focusRequester.requestFocus() }, diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt index 69700bea4..3eea673ba 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsTrackingScreen.kt @@ -7,6 +7,9 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.input.TextFieldLineLimits +import androidx.compose.foundation.text.input.TextObfuscationMode +import androidx.compose.foundation.text.input.rememberTextFieldState import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults @@ -14,6 +17,7 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.OutlinedSecureTextField import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -33,9 +37,6 @@ import androidx.compose.ui.semantics.contentType import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.text.input.PasswordVisualTransformation -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import dev.icerock.moko.resources.StringResource @@ -204,8 +205,8 @@ object SettingsTrackingScreen : SearchableSettings { val context = LocalContext.current val scope = rememberCoroutineScope() - var username by remember { mutableStateOf(TextFieldValue(tracker.getUsername())) } - var password by remember { mutableStateOf(TextFieldValue(tracker.getPassword())) } + val username = rememberTextFieldState(tracker.getUsername()) + val password = rememberTextFieldState(tracker.getPassword()) var processing by remember { mutableStateOf(false) } var inputError by remember { mutableStateOf(false) } @@ -231,21 +232,19 @@ object SettingsTrackingScreen : SearchableSettings { modifier = Modifier .fillMaxWidth() .semantics { contentType = ContentType.Username + ContentType.EmailAddress }, - value = username, - onValueChange = { username = it }, + state = username, label = { Text(text = stringResource(uNameStringRes)) }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), - singleLine = true, + lineLimits = TextFieldLineLimits.SingleLine, isError = inputError && !processing, ) var hidePassword by remember { mutableStateOf(true) } - OutlinedTextField( + OutlinedSecureTextField( modifier = Modifier .fillMaxWidth() .semantics { contentType = ContentType.Password }, - value = password, - onValueChange = { password = it }, + state = password, label = { Text(text = stringResource(MR.strings.password)) }, trailingIcon = { IconButton(onClick = { hidePassword = !hidePassword }) { @@ -259,16 +258,15 @@ object SettingsTrackingScreen : SearchableSettings { ) } }, - visualTransformation = if (hidePassword) { - PasswordVisualTransformation() + textObfuscationMode = if (hidePassword) { + TextObfuscationMode.Hidden } else { - VisualTransformation.None + TextObfuscationMode.Visible }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Password, imeAction = ImeAction.Done, ), - singleLine = true, isError = inputError && !processing, ) } @@ -283,8 +281,8 @@ object SettingsTrackingScreen : SearchableSettings { val result = checkLogin( context = context, tracker = tracker, - username = username.text, - password = password.text, + username = username.text.toString(), + password = password.text.toString(), ) inputError = !result if (result) onDismissRequest() diff --git a/app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt b/app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt index 47426807b..8ba0d4a2d 100644 --- a/app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt +++ b/app/src/main/java/eu/kanade/presentation/reader/components/ChapterNavigator.kt @@ -21,11 +21,13 @@ import androidx.compose.material3.Slider import androidx.compose.material3.SliderState import androidx.compose.material3.Text import androidx.compose.material3.VerticalSlider +import androidx.compose.material3.rememberSliderState import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.key import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue @@ -75,16 +77,14 @@ fun ChapterNavigator( ) { val haptic = LocalHapticFeedback.current - val state = remember(totalPages) { - SliderState( + val state = key(totalPages) { + rememberSliderState( value = currentPage.toFloat(), steps = totalPages - 2, - valueRange = 1f..totalPages.toFloat(), + trackRange = 1f..totalPages.toFloat(), ) } state.value = currentPage.toFloat() - state.onValueChange = { onPageIndexChange(it.roundToInt() - 1) } - state.onValueChangeFinished = onPageIndexChangeFinished val interactionSource = remember { MutableInteractionSource() } val sliderDragged by interactionSource.collectIsDraggedAsState() @@ -106,6 +106,8 @@ fun ChapterNavigator( disabledContainerColor = backgroundColor, ) + val onPageChange: (Int) -> Unit = { onPageIndexChange(it - 1) } + if (type.isHorizontal()) { HorizontalChapterNavigator( isRtl = type == ChapterNavigatorType.HORIZONTAL_RTL, @@ -116,6 +118,8 @@ fun ChapterNavigator( enabledPrevious = enabledPrevious, currentPage = currentPage, totalPages = totalPages, + onPageChange = onPageChange, + onPageChangeFinished = onPageIndexChangeFinished, interactionSource = interactionSource, mainAxisPadding = mainAxisPadding, backgroundColor = backgroundColor, @@ -131,6 +135,8 @@ fun ChapterNavigator( enabledPrevious = enabledPrevious, currentPage = currentPage, totalPages = totalPages, + onPageChange = onPageChange, + onPageChangeFinished = onPageIndexChangeFinished, interactionSource = interactionSource, mainAxisPadding = mainAxisPadding, backgroundColor = backgroundColor, @@ -150,6 +156,8 @@ fun HorizontalChapterNavigator( enabledPrevious: Boolean, currentPage: Int, totalPages: Int, + onPageChange: (Int) -> Unit, + onPageChangeFinished: () -> Unit, interactionSource: MutableInteractionSource, mainAxisPadding: Dp, backgroundColor: Color, @@ -200,6 +208,8 @@ fun HorizontalChapterNavigator( modifier = Modifier .weight(1f) .padding(horizontal = 8.dp), + onValueChange = { onPageChange(it.roundToInt()) }, + onValueChangeFinished = onPageChangeFinished, interactionSource = interactionSource, ) @@ -235,6 +245,8 @@ fun VerticalChapterNavigator( enabledPrevious: Boolean, currentPage: Int, totalPages: Int, + onPageChange: (Int) -> Unit, + onPageChangeFinished: () -> Unit, interactionSource: MutableInteractionSource, mainAxisPadding: Dp, backgroundColor: Color, @@ -275,6 +287,8 @@ fun VerticalChapterNavigator( modifier = Modifier .weight(1f) .padding(vertical = 8.dp), + onValueChange = { onPageChange(it.roundToInt()) }, + onValueChangeFinished = onPageChangeFinished, interactionSource = interactionSource, ) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 47f4a7a48..0f03b1ed0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,7 +8,7 @@ androidx-appCompat = "1.8.0" androidx-baselineProfile = "1.5.0" androidx-benchmark = "1.5.0" androidx-biometric = "1.2.0-alpha05" -androidx-compose-bom = "2026.07.01" +androidx-compose-bom = "2026.09.00" androidx-constraintLayout = "2.2.2" androidx-core = "1.19.0" androidx-coreSplashScreen = "1.2.0" diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index 9cf64be9a..b60665626 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material3.Checkbox import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExposedDropdownMenu import androidx.compose.material3.ExposedDropdownMenuAnchorType import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Slider.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Slider.kt index 66f2124a2..d369227e2 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Slider.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/material/Slider.kt @@ -6,7 +6,9 @@ import androidx.compose.material3.Slider import androidx.compose.material3.SliderColors import androidx.compose.material3.SliderDefaults import androidx.compose.material3.SliderState +import androidx.compose.material3.rememberSliderState import androidx.compose.runtime.Composable +import androidx.compose.runtime.key import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import kotlin.math.roundToInt @@ -33,13 +35,19 @@ fun Slider( SliderDefaults.Track(colors = colors, enabled = enabled, sliderState = sliderState) }, ) { + val state = key(steps, valueRange) { + rememberSliderState( + value = value.toFloat(), + steps = steps, + trackRange = with(valueRange) { first.toFloat()..last.toFloat() }, + ) + } + state.value = value.toFloat() Slider( - value = value.toFloat(), - onValueChange = { onValueChange(it.roundToInt()) }, + state = state, modifier = modifier, enabled = enabled, - valueRange = with(valueRange) { first.toFloat()..last.toFloat() }, - steps = steps, + onValueChange = { onValueChange(it.roundToInt()) }, onValueChangeFinished = onValueChangeFinished, colors = colors, interactionSource = interactionSource,