diff --git a/app/src/main/java/io/simplelogin/android/MainActivity.kt b/app/src/main/java/io/simplelogin/android/MainActivity.kt index 605f7a9b..227d8661 100644 --- a/app/src/main/java/io/simplelogin/android/MainActivity.kt +++ b/app/src/main/java/io/simplelogin/android/MainActivity.kt @@ -45,7 +45,6 @@ import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Text -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.material3.rememberDrawerState import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect @@ -72,7 +71,6 @@ import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.lifecycle.HiltViewModel import io.simplelogin.android.root.AppRoot import io.simplelogin.android.root.AppRootViewModel -import io.simplelogin.android.root.supportsMultiplePanes import io.simplelogin.core.common.ProtonLinkManager import io.simplelogin.core.common.ProtonLoginManager import io.simplelogin.core.common.di.LoadingState @@ -128,8 +126,6 @@ class MainActivity : AppCompatActivity() { } val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) val scope = rememberCoroutineScope() - val windowAdaptiveInfo = currentWindowAdaptiveInfo() - val asDialog = windowAdaptiveInfo.supportsMultiplePanes() val appRooState by appRootViewModel.stateFlow.collectAsState() val userInfo by viewModel.userInfoStateFlow.collectAsState() @@ -155,9 +151,7 @@ class MainActivity : AppCompatActivity() { } fun openAccountSettings() { - closeDrawerAndExecute { - appRootViewModel.showAccountSettingsScreen(asDialog) - } + closeDrawerAndExecute(appRootViewModel::showAccountSettingsScreen) } SimpleLoginTheme(darkTheme = darkTheme, dynamicColor = devicePreferences.dynamicColor) { @@ -173,22 +167,16 @@ class MainActivity : AppCompatActivity() { openAccountSettings() }, onMailboxesClick = { - closeDrawerAndExecute { - appRootViewModel.showMailboxesScreen(asDialog) - } + closeDrawerAndExecute(appRootViewModel::showMailboxesScreen) }, onCustomDomainsClick = { - closeDrawerAndExecute { - appRootViewModel.showCustomDomainsScreen(asDialog) - } + closeDrawerAndExecute(appRootViewModel::showCustomDomainsScreen) }, onAccountSettingsClick = { openAccountSettings() }, onDeviceSettingsClick = { - closeDrawerAndExecute { - appRootViewModel.showDeviceSettingsScreen(asDialog) - } + closeDrawerAndExecute(appRootViewModel::showDeviceSettingsScreen) }, onContactUsClick = { closeDrawerAndExecute(::openContactUsPage) diff --git a/app/src/main/java/io/simplelogin/android/home/HomeScreen.kt b/app/src/main/java/io/simplelogin/android/home/HomeScreen.kt index 04ace6fd..6eae297e 100644 --- a/app/src/main/java/io/simplelogin/android/home/HomeScreen.kt +++ b/app/src/main/java/io/simplelogin/android/home/HomeScreen.kt @@ -24,7 +24,6 @@ import androidx.compose.material3.Icon import androidx.compose.material3.Scaffold import androidx.compose.material3.Surface import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState @@ -41,26 +40,20 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel import io.simplelogin.android.R import io.simplelogin.android.home.topbar.NormalTopAppBar import io.simplelogin.android.home.topbar.SearchTopAppBar -import io.simplelogin.android.root.supportsMultiplePanes import io.simplelogin.core.designsystem.TitledFAB import io.simplelogin.core.designsystem.clickableRippleDisabled import io.simplelogin.core.designsystem.noAliasesMessage import io.simplelogin.core.designsystem.theme.SlColor import io.simplelogin.core.model.api.Alias -import io.simplelogin.core.model.api.ApiKey import io.simplelogin.core.model.api.RandomMode import io.simplelogin.core.model.ui.AliasAction -import io.simplelogin.core.model.ui.DialogPayload import io.simplelogin.core.ui.EditTextDialog import io.simplelogin.feature.aliasdetail.FullScreenDialog import io.simplelogin.feature.aliaslist.AliasList -import io.simplelogin.feature.createalias.CreateAliasScreen import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.debounce @@ -82,12 +75,10 @@ fun HomeScreen( } var isSearching by rememberSaveable { mutableStateOf(false) } - var createAliasDialogPayload by rememberSaveable { mutableStateOf(null) } var fullScreenAlias by rememberSaveable { mutableStateOf(null) } val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher var fabExpanded by rememberSaveable { mutableStateOf(false) } - val windowAdaptiveInfo = currentWindowAdaptiveInfo() LaunchedEffect(Unit) { createdAliasFlow.collect { alias -> @@ -121,13 +112,7 @@ fun HomeScreen( onViewDetails = onViewDetails, onViewContacts = onViewContacts, onEnterFullScreen = { fullScreenAlias = it }, - onCustomAliasClick = { - if (windowAdaptiveInfo.supportsMultiplePanes()) { - createAliasDialogPayload = DialogPayload(ApiKey(viewModel.apiKeyValue)) - } else { - onCreateAlias() - } - } + onCustomAliasClick = onCreateAlias ) } @@ -137,22 +122,6 @@ fun HomeScreen( onDismiss = { fullScreenAlias = null } ) } - - createAliasDialogPayload?.let { payload -> - Dialog( - onDismissRequest = { createAliasDialogPayload = null }, - properties = DialogProperties(usePlatformDefaultWidth = windowAdaptiveInfo.supportsMultiplePanes()) - ) { - CreateAliasScreen( - apiKeyValue = payload.apiKey.value, - onAliasCreated = { - createAliasDialogPayload = null - viewModel.handleCreatedAlias(it) - }, - onDismiss = { createAliasDialogPayload = null } - ) - } - } } @Suppress("CyclomaticComplexMethod") diff --git a/app/src/main/java/io/simplelogin/android/root/AppRoot.kt b/app/src/main/java/io/simplelogin/android/root/AppRoot.kt index 7577fa75..5699d3f8 100644 --- a/app/src/main/java/io/simplelogin/android/root/AppRoot.kt +++ b/app/src/main/java/io/simplelogin/android/root/AppRoot.kt @@ -9,20 +9,21 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi import androidx.compose.material3.adaptive.WindowAdaptiveInfo -import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo +import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2 import androidx.compose.material3.adaptive.layout.calculatePaneScaffoldDirective import androidx.compose.material3.adaptive.navigation3.ListDetailSceneStrategy import androidx.compose.material3.adaptive.navigation3.rememberListDetailSceneStrategy import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.entryProvider +import androidx.navigation3.scene.DialogSceneStrategy import androidx.navigation3.ui.NavDisplay import androidx.window.core.layout.WindowSizeClass.Companion.WIDTH_DP_MEDIUM_LOWER_BOUND import io.simplelogin.android.R @@ -94,8 +95,7 @@ fun AppRoot( onOpenDrawer: () -> Unit ) = with(viewModel) { val backStack by navBackStack.collectAsState() - val dialogStack by dialogStack.collectAsState() - val activeDialog = dialogStack.lastOrNull() + val showLogOutDialog by showLogOutDialog.collectAsState() val configuration = LocalConfiguration.current val screenWidth = configuration.screenWidthDp.dp @@ -104,19 +104,22 @@ fun AppRoot( } else { screenWidth * 0.5f } - val windowAdaptiveInfo = currentWindowAdaptiveInfo() + val windowAdaptiveInfo = currentWindowAdaptiveInfoV2() + val numberOfPanes = if (windowAdaptiveInfo.supportsMultiplePanes()) 2 else 1 val listDetailSceneStrategy = rememberListDetailSceneStrategy( directive = calculatePaneScaffoldDirective(windowAdaptiveInfo).copy( defaultPanePreferredWidth = listPaneWidth, - maxHorizontalPartitions = if (windowAdaptiveInfo.supportsMultiplePanes()) 2 else 1, + maxHorizontalPartitions = numberOfPanes, horizontalPartitionSpacerSize = 0.dp ) ) + val dialogStrategy = remember { DialogSceneStrategy() } + val dialogMetadata = if (numberOfPanes > 1) DialogSceneStrategy.dialog() else emptyMap() NavDisplay( modifier = modifier, backStack = backStack, - sceneStrategies = listOf(listDetailSceneStrategy), + sceneStrategies = listOf(listDetailSceneStrategy, dialogStrategy), entryProvider = entryProvider { entry {} @@ -139,7 +142,7 @@ fun AppRoot( ) } - entry { key -> + entry(metadata = dialogMetadata) { key -> CreateAliasScreen( apiKeyValue = key.apiKey, onAliasCreated = viewModel::handleCreatedAlias, @@ -182,52 +185,46 @@ fun AppRoot( ) } - entry { + entry(metadata = dialogMetadata) { DeviceSettingsScreen(onDismiss = viewModel::goBack) } - entry { key -> + entry(metadata = dialogMetadata) { key -> AccountSettingsScreen( apiKeyValue = key.apiKey, onDismiss = viewModel::goBack ) } - entry { key -> + entry(metadata = dialogMetadata) { key -> MailboxesScreen( apiKeyValue = key.apiKey, onDismiss = viewModel::goBack ) } - entry { key -> + entry(metadata = dialogMetadata) { key -> CustomDomainsScreen( apiKeyValue = key.apiKey, onViewDetails = { - viewModel.showCustomDomainDetails( - domain = it, - asDialog = false - ) + viewModel.showCustomDomainDetails(domain = it) }, onDismiss = viewModel::goBack ) } - entry { key -> + entry(metadata = dialogMetadata) { key -> CustomDomainDetailsScreen( domain = key.domain, apiKeyValue = key.apiKey, onDismiss = viewModel::goBack, onViewDeletedAliases = { - viewModel.showCustomDomainDeletedAliases( - domain = key.domain, - asDialog = false - ) + viewModel.showCustomDomainDeletedAliases(domain = key.domain) } ) } - entry { key -> + entry(metadata = dialogMetadata) { key -> CustomDomainDeletedAliasesScreen( domain = key.domain, apiKeyValue = key.apiKey, @@ -237,8 +234,8 @@ fun AppRoot( } ) - when (activeDialog) { - AppRootDialog.LogOut -> AlertDialog( + if (showLogOutDialog) { + AlertDialog( onDismissRequest = ::dismissActiveDialog, title = { Text(stringResource(R.string.sign_out)) }, text = { Text(stringResource(R.string.sign_out_message)) }, @@ -253,58 +250,8 @@ fun AppRoot( } } ) - - AppRootDialog.DeviceSettings -> Dialog(onDismissRequest = ::dismissActiveDialog) { - DeviceSettingsScreen(onDismiss = ::dismissActiveDialog) - } - - is AppRootDialog.AccountSettings -> Dialog(onDismissRequest = ::dismissActiveDialog) { - AccountSettingsScreen( - apiKeyValue = activeDialog.apiKey.value, - onDismiss = ::dismissActiveDialog - ) - } - - is AppRootDialog.Mailboxes -> Dialog(onDismissRequest = ::dismissActiveDialog) { - MailboxesScreen( - apiKeyValue = activeDialog.apiKey.value, - onDismiss = ::dismissActiveDialog - ) - } - - is AppRootDialog.CustomDomains -> Dialog(onDismissRequest = ::dismissActiveDialog) { - CustomDomainsScreen( - apiKeyValue = activeDialog.apiKey.value, - onViewDetails = { showCustomDomainDetails(domain = it, asDialog = true) }, - onDismiss = ::dismissActiveDialog - ) - } - - is AppRootDialog.CustomDomainDetails -> Dialog(onDismissRequest = ::dismissActiveDialog) { - CustomDomainDetailsScreen( - domain = activeDialog.domain, - apiKeyValue = activeDialog.apiKey.value, - onDismiss = ::dismissActiveDialog, - onViewDeletedAliases = { - viewModel.showCustomDomainDeletedAliases( - domain = activeDialog.domain, - asDialog = true - ) - } - ) - } - - is AppRootDialog.CustomDomainDeletedAliases -> Dialog(onDismissRequest = ::dismissActiveDialog) { - CustomDomainDeletedAliasesScreen( - domain = activeDialog.domain, - apiKeyValue = activeDialog.apiKey.value, - onDismiss = ::dismissActiveDialog - ) - } - - null -> Unit } } -fun WindowAdaptiveInfo.supportsMultiplePanes(): Boolean = +private fun WindowAdaptiveInfo.supportsMultiplePanes(): Boolean = windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_MEDIUM_LOWER_BOUND) diff --git a/app/src/main/java/io/simplelogin/android/root/AppRootDialog.kt b/app/src/main/java/io/simplelogin/android/root/AppRootDialog.kt deleted file mode 100644 index 844323a0..00000000 --- a/app/src/main/java/io/simplelogin/android/root/AppRootDialog.kt +++ /dev/null @@ -1,15 +0,0 @@ -package io.simplelogin.android.root - -import io.simplelogin.core.model.api.ApiKey -import io.simplelogin.core.model.api.CustomDomain - -sealed interface AppRootDialog { - data object LogOut : AppRootDialog - data object DeviceSettings : AppRootDialog - data class AccountSettings(val apiKey: ApiKey) : AppRootDialog - data class Mailboxes(val apiKey: ApiKey) : AppRootDialog - data class CustomDomains(val apiKey: ApiKey) : AppRootDialog - data class CustomDomainDetails(val apiKey: ApiKey, val domain: CustomDomain) : AppRootDialog - data class CustomDomainDeletedAliases(val apiKey: ApiKey, val domain: CustomDomain) : - AppRootDialog -} diff --git a/app/src/main/java/io/simplelogin/android/root/AppRootViewModel.kt b/app/src/main/java/io/simplelogin/android/root/AppRootViewModel.kt index 7e1e5272..9ebd7ac3 100644 --- a/app/src/main/java/io/simplelogin/android/root/AppRootViewModel.kt +++ b/app/src/main/java/io/simplelogin/android/root/AppRootViewModel.kt @@ -21,6 +21,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.stateIn @@ -43,39 +44,33 @@ class AppRootViewModel @Inject constructor( private val _createdAlias = Channel(Channel.BUFFERED) val createdAlias = _createdAlias.receiveAsFlow() - private val _dialogStack = MutableStateFlow>(emptyList()) - val dialogStack = _dialogStack.asStateFlow() + private val _showLogOutDialog = MutableStateFlow(false) + val showLogOutDialog = _showLogOutDialog - val stateFlow: StateFlow = observeSessionSettings() - .map { - AppRootState( - isReady = true, - apiKey = it.apiKey - ) - } - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = AppRootState.Default - ) + val stateFlow: StateFlow = observeSessionSettings().map { + AppRootState(isReady = true, apiKey = it.apiKey) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = AppRootState.Default + ) //region Setup init { viewModelScope.launch { - stateFlow - .collect { - _navBackStack.value.apply { - clear() - if (!it.isReady) { - add(InitializationDestination) - return@collect - } - - it.apiKey?.let { apiKey -> - add(HomeDestination(apiKey.value)) - } ?: add(LogInDestination) + stateFlow.collect { + _navBackStack.value.apply { + clear() + if (!it.isReady) { + add(InitializationDestination) + return@collect } + + it.apiKey?.let { apiKey -> + add(HomeDestination(apiKey.value)) + } ?: add(LogInDestination) } + } } } //endregion @@ -86,108 +81,61 @@ class AppRootViewModel @Inject constructor( //region Drawer fun showLogOutDialog() { - _dialogStack.value = listOf(AppRootDialog.LogOut) + _showLogOutDialog.value = true } fun dismissActiveDialog() { - _dialogStack.value = _dialogStack.value.dropLast(1) + _showLogOutDialog.value = false } fun logOut() { - _dialogStack.value = emptyList() + _showLogOutDialog.value = false viewModelScope.launch { logOutUseCase() } } - fun showDeviceSettingsScreen(asDialog: Boolean) { - if (asDialog) { - _dialogStack.value = listOf(AppRootDialog.DeviceSettings) - } else { - _navBackStack.value.apply { - add(DeviceSettingsDestination) - } + fun showDeviceSettingsScreen() { + _navBackStack.value.apply { + add(DeviceSettingsDestination) } } - fun showAccountSettingsScreen(asDialog: Boolean) { - withApiKey { apiKey -> - if (asDialog) { - _dialogStack.value = listOf(AppRootDialog.AccountSettings(apiKey)) - } else { - _navBackStack.value.apply { - add(AccountSettingsDestination(apiKey.value)) - } - } + fun showAccountSettingsScreen() { + addToBackStackWithApiKey { apiKey -> + AccountSettingsDestination(apiKey.value) } } - fun showMailboxesScreen(asDialog: Boolean) { - withApiKey { apiKey -> - if (asDialog) { - _dialogStack.value = listOf(AppRootDialog.Mailboxes(apiKey)) - } else { - _navBackStack.value.apply { - add(MailboxesDestination(apiKey.value)) - } - } + fun showMailboxesScreen() { + addToBackStackWithApiKey { apiKey -> + MailboxesDestination(apiKey.value) } } - fun showCustomDomainsScreen(asDialog: Boolean) { - withApiKey { apiKey -> - if (asDialog) { - _dialogStack.value = listOf(AppRootDialog.CustomDomains(apiKey)) - } else { - _navBackStack.value.apply { - add(CustomDomainsDestination(apiKey.value)) - } - } + fun showCustomDomainsScreen() { + addToBackStackWithApiKey { apiKey -> + CustomDomainsDestination(apiKey.value) } } - fun showCustomDomainDetails(domain: CustomDomain, asDialog: Boolean) { - withApiKey { apiKey -> - if (asDialog) { - _dialogStack.value += AppRootDialog.CustomDomainDetails( - apiKey = apiKey, - domain = domain - ) - } else { - _navBackStack.value.apply { - add(CustomDomainDetailsDestination(domain = domain, apiKey = apiKey.value)) - } - } + fun showCustomDomainDetails(domain: CustomDomain) { + addToBackStackWithApiKey { apiKey -> + CustomDomainDetailsDestination(domain = domain, apiKey = apiKey.value) } } - fun showCustomDomainDeletedAliases(domain: CustomDomain, asDialog: Boolean) { - withApiKey { apiKey -> - if (asDialog) { - _dialogStack.value += AppRootDialog.CustomDomainDeletedAliases( - apiKey = apiKey, - domain = domain - ) - } else { - _navBackStack.value.apply { - add( - CustomDomainDeletedAliasesDestination( - domain = domain, - apiKey = apiKey.value - ) - ) - } - } + fun showCustomDomainDeletedAliases(domain: CustomDomain) { + addToBackStackWithApiKey { apiKey -> + CustomDomainDeletedAliasesDestination(domain = domain, apiKey = apiKey.value) } } //endregion //region Home fun showCreateAliasScreen() { - withApiKey { apiKey -> - _navBackStack.value.apply { - add(CreateAliasDestination(apiKey.value)) - } + addToBackStackWithApiKey { apiKey -> + CreateAliasDestination(apiKey.value) } } @@ -235,18 +183,24 @@ class AppRootViewModel @Inject constructor( } } + private fun addToBackStackWithApiKey(block: (ApiKey) -> NavKey) { + withApiKey { + val destination = block(it) + _navBackStack.value.apply { + add(destination) + } + } + } + private fun withApiKey( scope: CoroutineScope = viewModelScope, block: (ApiKey) -> Unit ) { scope.launch { - observeSessionSettings().collect { settings -> - settings.apiKey?.let { - block(it) - } ?: scope.launch { - showSnackbarFailure(context.getString(R.string.missing_api_key)) - } - } + val settings = observeSessionSettings().first() + settings.apiKey?.let { + block(it) + } ?: showSnackbarFailure(context.getString(R.string.missing_api_key)) } } } diff --git a/core/model/src/main/java/io/simplelogin/core/model/ui/DialogPayload.kt b/core/model/src/main/java/io/simplelogin/core/model/ui/DialogPayload.kt deleted file mode 100644 index 5452bc53..00000000 --- a/core/model/src/main/java/io/simplelogin/core/model/ui/DialogPayload.kt +++ /dev/null @@ -1,5 +0,0 @@ -package io.simplelogin.core.model.ui - -import io.simplelogin.core.model.api.ApiKey - -data class DialogPayload(val apiKey: ApiKey) diff --git a/feature/auth/src/main/java/io/simplelogin/feature/auth/ui/dialog/ForgotPasswordDialog.kt b/feature/auth/src/main/java/io/simplelogin/feature/auth/ui/dialog/ForgotPasswordDialog.kt index 18c6e93e..0f8b87e2 100644 --- a/feature/auth/src/main/java/io/simplelogin/feature/auth/ui/dialog/ForgotPasswordDialog.kt +++ b/feature/auth/src/main/java/io/simplelogin/feature/auth/ui/dialog/ForgotPasswordDialog.kt @@ -1,6 +1,7 @@ package io.simplelogin.feature.auth.ui.dialog import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.AlertDialog import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -37,7 +38,9 @@ internal fun ForgotPasswordDialog( Column { Text(stringResource(R.string.forgot_password_instruction)) EmailTextField( - modifier = Modifier.focusRequester(focusRequester), + modifier = Modifier + .focusRequester(focusRequester) + .fillMaxWidth(), value = emailAddress, onValueChange = { emailAddress = it } ) diff --git a/feature/auth/src/main/java/io/simplelogin/feature/auth/ui/dialog/SetApiKeyDialog.kt b/feature/auth/src/main/java/io/simplelogin/feature/auth/ui/dialog/SetApiKeyDialog.kt index 9291d6ea..4bd171a5 100644 --- a/feature/auth/src/main/java/io/simplelogin/feature/auth/ui/dialog/SetApiKeyDialog.kt +++ b/feature/auth/src/main/java/io/simplelogin/feature/auth/ui/dialog/SetApiKeyDialog.kt @@ -2,6 +2,7 @@ package io.simplelogin.feature.auth.ui.dialog import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material3.AlertDialog import androidx.compose.material3.Text import androidx.compose.material3.TextButton @@ -46,7 +47,9 @@ internal fun SetApiKeyDialog( focusRequester.requestFocus() } TextField( - modifier = Modifier.focusRequester(focusRequester), + modifier = Modifier + .focusRequester(focusRequester) + .fillMaxWidth(), value = apiKey, placeholder = { Text(stringResource(R.string.api_key)) }, onValueChange = { apiKey = it } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f153c4cc..cb6c6395 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ junitVersion = "1.3.0" espressoCore = "3.7.0" lifecycleRuntimeKtx = "2.10.0" activityCompose = "1.13.0" -composeBom = "2026.05.00" +composeBom = "2026.05.01" retrofit = "3.0.0" okhttpLoggingInterceptor = "5.3.2" hilt = "2.59.2" @@ -17,20 +17,20 @@ ksp = "2.3.7" datastorePreferences = "1.2.1" kotlinSerializationJson = "1.11.0" kotlinxCoroutines = "1.11.0" -nav3Core = "1.1.1" +nav3Core = "1.1.2" nav3Lifecycle = "2.10.0" coreSplashScreen = "1.2.0" composeMaterialIconsExtended = "1.7.8" adaptiveAndroid = "1.2.0" adaptiveNavigation3 = "1.0.0-alpha03" zxingCore = "3.5.4" -adaptiveNavigation3Version = "1.3.0-beta01" +adaptiveNavigation3Version = "1.3.0-beta02" coil = "2.7.0" -ui = "1.11.1" +ui = "1.11.2" biometric = "1.1.0" appcompat = "1.7.1" browser = "1.10.0" -material = "1.13.0" +material = "1.14.0" detekt = "1.23.8" [libraries]