From 12f268984a9e8f3dc6b5c8047e3adfc234158126 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 10:35:09 +0200 Subject: [PATCH 01/15] Add toolbar with back navigation to WooPosSettingsScreen --- .../woopos/settings/WooPosSettingsScreen.kt | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt index 4e0fdede74d0..f1d863069dd8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt @@ -1,28 +1,55 @@ package com.woocommerce.android.ui.woopos.settings +import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel +import com.woocommerce.android.R +import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosToolbar +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTheme import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography import com.woocommerce.android.ui.woopos.root.navigation.WooPosNavigationEvent @Composable -@Suppress("UnusedParameter") fun WooPosSettingsScreen( onNavigationEvent: (WooPosNavigationEvent) -> Unit, - viewModel: WooPosSettingsViewModel = hiltViewModel() ) { - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center + val viewModel: WooPosSettingsViewModel = hiltViewModel() + BackHandler { onNavigationEvent(WooPosNavigationEvent.GoBack) } + + Column( + modifier = Modifier.fillMaxSize() ) { - WooPosText( - text = "Settings Screen", - style = WooPosTypography.Heading, + WooPosToolbar( + titleText = stringResource(R.string.woopos_settings_title), + onBackClicked = { onNavigationEvent(WooPosNavigationEvent.GoBack) } + ) + + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + WooPosText( + text = "Settings Screen", + style = WooPosTypography.Heading, + ) + } + } +} + +@WooPosPreview +@Composable +fun WooPosSettingsScreenPreview() { + WooPosTheme { + WooPosSettingsScreen( + onNavigationEvent = {} ) } } From 622534bae2813568923b7ab60662f55d1442af68 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 11:00:58 +0200 Subject: [PATCH 02/15] Implement 2-pane settings architecture with string resources --- .../woopos/settings/WooPosSettingsScreen.kt | 46 +++++-- .../ui/woopos/settings/WooPosSettingsState.kt | 19 +++ .../settings/WooPosSettingsViewModel.kt | 8 -- .../WooPosSettingsCategoriesPane.kt | 78 +++++++++++ .../WooPosSettingsCategoriesState.kt | 19 +++ .../WooPosSettingsCategoriesViewModel.kt | 24 ++++ .../WooPosSettingsContainerViewModel.kt | 51 ++++++++ .../details/WooPosSettingsDetailPane.kt | 123 ++++++++++++++++++ .../hardware/WooPosHardwareSettingsScreen.kt | 92 +++++++++++++ .../hardware/WooPosHardwareSettingsState.kt | 26 ++++ .../WooPosHardwareSettingsViewModel.kt | 19 +++ WooCommerce/src/main/res/values/strings.xml | 8 ++ 12 files changed, 494 insertions(+), 19 deletions(-) create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt delete mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesViewModel.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/container/WooPosSettingsContainerViewModel.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt create mode 100644 WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsViewModel.kt diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt index f1d863069dd8..6ef61ac60987 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt @@ -1,27 +1,35 @@ package com.woocommerce.android.ui.woopos.settings import androidx.activity.compose.BackHandler -import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview -import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosToolbar import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTheme -import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography import com.woocommerce.android.ui.woopos.root.navigation.WooPosNavigationEvent +import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategoriesPane +import com.woocommerce.android.ui.woopos.settings.container.WooPosSettingsContainerViewModel +import com.woocommerce.android.ui.woopos.settings.details.WooPosSettingsDetailPane @Composable fun WooPosSettingsScreen( onNavigationEvent: (WooPosNavigationEvent) -> Unit, ) { - val viewModel: WooPosSettingsViewModel = hiltViewModel() + val containerViewModel: WooPosSettingsContainerViewModel = hiltViewModel() + val navigationState by containerViewModel.navigationState.collectAsState() + BackHandler { onNavigationEvent(WooPosNavigationEvent.GoBack) } Column( @@ -32,13 +40,29 @@ fun WooPosSettingsScreen( onBackClicked = { onNavigationEvent(WooPosNavigationEvent.GoBack) } ) - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center + HorizontalDivider( + modifier = Modifier.fillMaxWidth(), + color = MaterialTheme.colorScheme.outlineVariant + ) + + Row( + modifier = Modifier.fillMaxSize() ) { - WooPosText( - text = "Settings Screen", - style = WooPosTypography.Heading, + WooPosSettingsCategoriesPane( + selectedCategory = navigationState.selectedCategory, + onCategorySelected = containerViewModel::onCategorySelected, + modifier = Modifier.weight(0.3f) + ) + + VerticalDivider( + color = MaterialTheme.colorScheme.outlineVariant + ) + + WooPosSettingsDetailPane( + state = navigationState, + onNavigate = containerViewModel::navigateToDetail, + onBack = containerViewModel::popDetailBackStack, + modifier = Modifier.weight(0.7f) ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt new file mode 100644 index 000000000000..e8bf9dbb76e7 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt @@ -0,0 +1,19 @@ +package com.woocommerce.android.ui.woopos.settings + +import androidx.annotation.StringRes +import com.woocommerce.android.R + +data class WooPosSettingsState( + val selectedCategory: SettingsCategory = SettingsCategory.HARDWARE, + val detailBackStack: List = listOf(SettingsDetailDestination.HardwareOverview) +) + +enum class SettingsCategory(@StringRes val titleRes: Int) { + HARDWARE(R.string.woopos_settings_hardware_category) +} + +sealed class SettingsDetailDestination { + data object HardwareOverview : SettingsDetailDestination() + data object BarcodeScanners : SettingsDetailDestination() + data object CardReaders : SettingsDetailDestination() +} \ No newline at end of file diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt deleted file mode 100644 index 65da50621ec9..000000000000 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.woocommerce.android.ui.woopos.settings - -import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject - -@HiltViewModel -class WooPosSettingsViewModel @Inject constructor() : ViewModel() diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt new file mode 100644 index 000000000000..1d1ad79c7e81 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt @@ -0,0 +1,78 @@ +package com.woocommerce.android.ui.woopos.settings.categories + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.hilt.navigation.compose.hiltViewModel +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography +import com.woocommerce.android.ui.woopos.settings.SettingsCategory + +@Composable +fun WooPosSettingsCategoriesPane( + selectedCategory: SettingsCategory, + onCategorySelected: (SettingsCategory) -> Unit, + modifier: Modifier = Modifier, + viewModel: WooPosSettingsCategoriesViewModel = hiltViewModel() +) { + val state by viewModel.state.collectAsState() + + Column( + modifier = modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.surface) + .padding(WooPosSpacing.Medium.value) + ) { + state.categories.forEach { item -> + CategoryItem( + item = item, + isSelected = item.category == selectedCategory, + onClick = { + if (item.isEnabled) { + onCategorySelected(item.category) + } + } + ) + } + } +} + +@Composable +private fun CategoryItem( + item: SettingsCategoryItem, + isSelected: Boolean, + onClick: () -> Unit +) { + val backgroundColor = if (isSelected) { + MaterialTheme.colorScheme.primaryContainer + } else { + MaterialTheme.colorScheme.surface + } + + val textColor = when { + !item.isEnabled -> MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f) + isSelected -> MaterialTheme.colorScheme.onPrimaryContainer + else -> MaterialTheme.colorScheme.onSurface + } + + WooPosText( + text = stringResource(item.titleRes), + style = WooPosTypography.BodyLarge, + color = textColor, + modifier = Modifier + .fillMaxWidth() + .background(backgroundColor) + .clickable(enabled = item.isEnabled) { onClick() } + .padding(WooPosSpacing.Medium.value) + ) +} \ No newline at end of file diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt new file mode 100644 index 000000000000..0b9ff05d60a2 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt @@ -0,0 +1,19 @@ +package com.woocommerce.android.ui.woopos.settings.categories + +import androidx.annotation.StringRes +import com.woocommerce.android.ui.woopos.settings.SettingsCategory + +data class SettingsCategoryItem( + val category: SettingsCategory, + @StringRes val titleRes: Int, + val isEnabled: Boolean = true +) + +data class WooPosSettingsCategoriesState( + val categories: List = listOf( + SettingsCategoryItem( + category = SettingsCategory.HARDWARE, + titleRes = SettingsCategory.HARDWARE.titleRes + ) + ) +) \ No newline at end of file diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesViewModel.kt new file mode 100644 index 000000000000..195a9b5d835d --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesViewModel.kt @@ -0,0 +1,24 @@ +package com.woocommerce.android.ui.woopos.settings.categories + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +@HiltViewModel +class WooPosSettingsCategoriesViewModel @Inject constructor() : ViewModel() { + + private val _state = MutableStateFlow(WooPosSettingsCategoriesState()) + val state: StateFlow = _state.asStateFlow() + + init { + loadCategories() + } + + private fun loadCategories() { + // In the future, this could load categories based on feature flags, + // user permissions, or other business logic + } +} \ No newline at end of file diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/container/WooPosSettingsContainerViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/container/WooPosSettingsContainerViewModel.kt new file mode 100644 index 000000000000..decf05fd0463 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/container/WooPosSettingsContainerViewModel.kt @@ -0,0 +1,51 @@ +package com.woocommerce.android.ui.woopos.settings.container + +import androidx.lifecycle.ViewModel +import com.woocommerce.android.ui.woopos.settings.WooPosSettingsState +import com.woocommerce.android.ui.woopos.settings.SettingsCategory +import com.woocommerce.android.ui.woopos.settings.SettingsDetailDestination +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update +import javax.inject.Inject + +@HiltViewModel +class WooPosSettingsContainerViewModel @Inject constructor() : ViewModel() { + + private val _navigationState = MutableStateFlow(WooPosSettingsState()) + val navigationState: StateFlow = _navigationState.asStateFlow() + + fun onCategorySelected(category: SettingsCategory) { + _navigationState.update { currentState -> + val newDetailDestination = when (category) { + SettingsCategory.HARDWARE -> SettingsDetailDestination.HardwareOverview + } + currentState.copy( + selectedCategory = category, + detailBackStack = listOf(newDetailDestination) + ) + } + } + + fun navigateToDetail(destination: SettingsDetailDestination) { + _navigationState.update { currentState -> + currentState.copy( + detailBackStack = currentState.detailBackStack + destination + ) + } + } + + fun popDetailBackStack() { + _navigationState.update { currentState -> + if (currentState.detailBackStack.size > 1) { + currentState.copy( + detailBackStack = currentState.detailBackStack.dropLast(1) + ) + } else { + currentState + } + } + } +} \ No newline at end of file diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt new file mode 100644 index 000000000000..d56fddfb401e --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt @@ -0,0 +1,123 @@ +package com.woocommerce.android.ui.woopos.settings.details + +import androidx.activity.compose.BackHandler +import androidx.compose.animation.AnimatedContent +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.woocommerce.android.R +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography +import com.woocommerce.android.ui.woopos.settings.WooPosSettingsState +import com.woocommerce.android.ui.woopos.settings.SettingsDetailDestination +import com.woocommerce.android.ui.woopos.settings.details.hardware.WooPosHardwareSettingsScreen + +@Composable +fun WooPosSettingsDetailPane( + state: WooPosSettingsState, + onNavigate: (SettingsDetailDestination) -> Unit, + onBack: () -> Unit, + modifier: Modifier = Modifier +) { + val currentDestination = state.detailBackStack.lastOrNull() + val canGoBack = state.detailBackStack.size > 1 + + BackHandler(enabled = canGoBack) { + onBack() + } + + Column( + modifier = modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background) + ) { + if (canGoBack) { + DetailPaneToolbar(onBack = onBack) + } + + AnimatedContent( + targetState = currentDestination, + label = "settings_detail_animation" + ) { destination -> + when (destination) { + is SettingsDetailDestination.HardwareOverview -> { + WooPosHardwareSettingsScreen(onNavigate = onNavigate) + } + is SettingsDetailDestination.BarcodeScanners -> { + BarcodeScannerDetailScreen() + } + is SettingsDetailDestination.CardReaders -> { + CardReadersDetailScreen() + } + null -> { + Box(modifier = Modifier.fillMaxSize()) + } + } + } + } +} + +@Composable +private fun DetailPaneToolbar(onBack: () -> Unit) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(WooPosSpacing.Small.value), + verticalAlignment = Alignment.CenterVertically + ) { + IconButton(onClick = onBack) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.woopos_settings_back_content_description), + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(24.dp) + ) + } + } +} + +@Composable +private fun BarcodeScannerDetailScreen() { + Box( + modifier = Modifier + .fillMaxSize() + .padding(WooPosSpacing.Medium.value), + contentAlignment = Alignment.Center + ) { + WooPosText( + text = stringResource(R.string.woopos_settings_barcode_scanner_detail_title), + style = WooPosTypography.Heading + ) + } +} + +@Composable +private fun CardReadersDetailScreen() { + Box( + modifier = Modifier + .fillMaxSize() + .padding(WooPosSpacing.Medium.value), + contentAlignment = Alignment.Center + ) { + WooPosText( + text = stringResource(R.string.woopos_settings_card_reader_detail_title), + style = WooPosTypography.Heading + ) + } +} \ No newline at end of file diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt new file mode 100644 index 000000000000..b43f7315276c --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -0,0 +1,92 @@ +package com.woocommerce.android.ui.woopos.settings.details.hardware + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.hilt.navigation.compose.hiltViewModel +import com.woocommerce.android.R +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography +import com.woocommerce.android.ui.woopos.settings.SettingsDetailDestination + +@Composable +fun WooPosHardwareSettingsScreen( + onNavigate: (SettingsDetailDestination) -> Unit, + viewModel: WooPosHardwareSettingsViewModel = hiltViewModel() +) { + val state by viewModel.state.collectAsState() + + Column( + modifier = Modifier + .fillMaxSize() + .padding(WooPosSpacing.Medium.value) + ) { + WooPosText( + text = stringResource(R.string.woopos_settings_hardware_category), + style = WooPosTypography.Heading, + modifier = Modifier.padding(bottom = WooPosSpacing.Medium.value) + ) + + state.items.forEach { item -> + HardwareSettingsMenuItem( + item = item, + onClick = { + viewModel.onItemClicked(item.id) + when (item.id) { + "barcode_scanners" -> onNavigate(SettingsDetailDestination.BarcodeScanners) + "card_readers" -> onNavigate(SettingsDetailDestination.CardReaders) + } + } + ) + } + } +} + +@Composable +private fun HardwareSettingsMenuItem( + item: HardwareSettingsItem, + onClick: () -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { onClick() } + .padding(vertical = WooPosSpacing.Medium.value), + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + WooPosText( + text = stringResource(item.titleRes), + style = WooPosTypography.BodyLarge, + color = MaterialTheme.colorScheme.onSurface + ) + item.subtitleRes?.let { subtitleRes -> + WooPosText( + text = stringResource(subtitleRes), + style = WooPosTypography.BodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(top = WooPosSpacing.XSmall.value) + ) + } + } + Icon( + imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant + ) + } +} \ No newline at end of file diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt new file mode 100644 index 000000000000..f57b29f5aad1 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt @@ -0,0 +1,26 @@ +package com.woocommerce.android.ui.woopos.settings.details.hardware + +import androidx.annotation.StringRes +import com.woocommerce.android.R + +data class HardwareSettingsItem( + val id: String, + @StringRes val titleRes: Int, + @StringRes val subtitleRes: Int? = null +) + +data class WooPosHardwareSettingsState( + val items: List = listOf( + HardwareSettingsItem( + id = "barcode_scanners", + titleRes = R.string.woopos_settings_hardware_barcode_scanners, + subtitleRes = R.string.woopos_settings_hardware_barcode_scanners_subtitle + ), + HardwareSettingsItem( + id = "card_readers", + titleRes = R.string.woopos_settings_hardware_card_readers, + subtitleRes = R.string.woopos_settings_hardware_card_readers_subtitle + ) + ), + val isLoading: Boolean = false +) \ No newline at end of file diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsViewModel.kt new file mode 100644 index 000000000000..d2a0dfd44db7 --- /dev/null +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsViewModel.kt @@ -0,0 +1,19 @@ +package com.woocommerce.android.ui.woopos.settings.details.hardware + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +@HiltViewModel +class WooPosHardwareSettingsViewModel @Inject constructor() : ViewModel() { + private val _state = MutableStateFlow(WooPosHardwareSettingsState()) + val state: StateFlow = _state.asStateFlow() + + fun onItemClicked(itemId: String) { + // Handle item clicks - in real implementation this would trigger navigation + // For now, navigation is handled by the container + } +} diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index 795884312822..d4b8c61d6b20 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -4339,6 +4339,14 @@ Settings + Hardware + Barcode scanners + Configure barcode scanner settings + Card Readers + Manage card reader connections + Barcode Scanner Settings + Card Reader Settings + Back Exit POS Get Support Initial barcode scanner setup From 7117802e2d762258cc92cccc04eb7eca908a1ac3 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 11:01:45 +0200 Subject: [PATCH 03/15] Refactor WooPosSettingsScreen to use WooPosSettingsViewModel and add new ViewModel for settings navigation state management --- .../ui/woopos/settings/WooPosSettingsScreen.kt | 3 +-- ...rViewModel.kt => WooPosSettingsViewModel.kt} | 17 +++++++---------- 2 files changed, 8 insertions(+), 12 deletions(-) rename WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/{container/WooPosSettingsContainerViewModel.kt => WooPosSettingsViewModel.kt} (80%) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt index 6ef61ac60987..83f3ed68826c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt @@ -20,14 +20,13 @@ import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosToolba import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTheme import com.woocommerce.android.ui.woopos.root.navigation.WooPosNavigationEvent import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategoriesPane -import com.woocommerce.android.ui.woopos.settings.container.WooPosSettingsContainerViewModel import com.woocommerce.android.ui.woopos.settings.details.WooPosSettingsDetailPane @Composable fun WooPosSettingsScreen( onNavigationEvent: (WooPosNavigationEvent) -> Unit, ) { - val containerViewModel: WooPosSettingsContainerViewModel = hiltViewModel() + val containerViewModel: WooPosSettingsViewModel = hiltViewModel() val navigationState by containerViewModel.navigationState.collectAsState() BackHandler { onNavigationEvent(WooPosNavigationEvent.GoBack) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/container/WooPosSettingsContainerViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt similarity index 80% rename from WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/container/WooPosSettingsContainerViewModel.kt rename to WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt index decf05fd0463..62a3bf062186 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/container/WooPosSettingsContainerViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt @@ -1,9 +1,6 @@ -package com.woocommerce.android.ui.woopos.settings.container +package com.woocommerce.android.ui.woopos.settings import androidx.lifecycle.ViewModel -import com.woocommerce.android.ui.woopos.settings.WooPosSettingsState -import com.woocommerce.android.ui.woopos.settings.SettingsCategory -import com.woocommerce.android.ui.woopos.settings.SettingsDetailDestination import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -12,11 +9,11 @@ import kotlinx.coroutines.flow.update import javax.inject.Inject @HiltViewModel -class WooPosSettingsContainerViewModel @Inject constructor() : ViewModel() { - +class WooPosSettingsViewModel @Inject constructor() : ViewModel() { + private val _navigationState = MutableStateFlow(WooPosSettingsState()) val navigationState: StateFlow = _navigationState.asStateFlow() - + fun onCategorySelected(category: SettingsCategory) { _navigationState.update { currentState -> val newDetailDestination = when (category) { @@ -28,7 +25,7 @@ class WooPosSettingsContainerViewModel @Inject constructor() : ViewModel() { ) } } - + fun navigateToDetail(destination: SettingsDetailDestination) { _navigationState.update { currentState -> currentState.copy( @@ -36,7 +33,7 @@ class WooPosSettingsContainerViewModel @Inject constructor() : ViewModel() { ) } } - + fun popDetailBackStack() { _navigationState.update { currentState -> if (currentState.detailBackStack.size > 1) { @@ -48,4 +45,4 @@ class WooPosSettingsContainerViewModel @Inject constructor() : ViewModel() { } } } -} \ No newline at end of file +} From 232f9c8bd9fd857873dd912b25af0d715f433290 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 11:13:13 +0200 Subject: [PATCH 04/15] Some simplifications --- .../ui/woopos/settings/WooPosSettingsState.kt | 16 +++++------ .../settings/WooPosSettingsViewModel.kt | 6 ++--- .../WooPosSettingsCategoriesPane.kt | 27 +++++++++---------- .../WooPosSettingsCategoriesState.kt | 18 +++---------- .../WooPosSettingsCategoriesViewModel.kt | 12 +-------- .../details/WooPosSettingsDetailPane.kt | 18 ++++++------- .../hardware/WooPosHardwareSettingsScreen.kt | 20 +++++++------- .../hardware/WooPosHardwareSettingsState.kt | 8 ++---- .../WooPosHardwareSettingsViewModel.kt | 5 ---- 9 files changed, 49 insertions(+), 81 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt index e8bf9dbb76e7..579e4e804b21 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt @@ -4,16 +4,16 @@ import androidx.annotation.StringRes import com.woocommerce.android.R data class WooPosSettingsState( - val selectedCategory: SettingsCategory = SettingsCategory.HARDWARE, - val detailBackStack: List = listOf(SettingsDetailDestination.HardwareOverview) + val selectedCategory: WooPosSettingsCategory = WooPosSettingsCategory.HARDWARE, + val detailBackStack: List = listOf(WooPosSettingsDetailDestination.HardwareOverview) ) -enum class SettingsCategory(@StringRes val titleRes: Int) { +enum class WooPosSettingsCategory(@StringRes val titleRes: Int) { HARDWARE(R.string.woopos_settings_hardware_category) } -sealed class SettingsDetailDestination { - data object HardwareOverview : SettingsDetailDestination() - data object BarcodeScanners : SettingsDetailDestination() - data object CardReaders : SettingsDetailDestination() -} \ No newline at end of file +sealed class WooPosSettingsDetailDestination { + data object HardwareOverview : WooPosSettingsDetailDestination() + data object BarcodeScanners : WooPosSettingsDetailDestination() + data object CardReaders : WooPosSettingsDetailDestination() +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt index 62a3bf062186..98e715664ab3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt @@ -14,10 +14,10 @@ class WooPosSettingsViewModel @Inject constructor() : ViewModel() { private val _navigationState = MutableStateFlow(WooPosSettingsState()) val navigationState: StateFlow = _navigationState.asStateFlow() - fun onCategorySelected(category: SettingsCategory) { + fun onCategorySelected(category: WooPosSettingsCategory) { _navigationState.update { currentState -> val newDetailDestination = when (category) { - SettingsCategory.HARDWARE -> SettingsDetailDestination.HardwareOverview + WooPosSettingsCategory.HARDWARE -> WooPosSettingsDetailDestination.HardwareOverview } currentState.copy( selectedCategory = category, @@ -26,7 +26,7 @@ class WooPosSettingsViewModel @Inject constructor() : ViewModel() { } } - fun navigateToDetail(destination: SettingsDetailDestination) { + fun navigateToDetail(destination: WooPosSettingsDetailDestination) { _navigationState.update { currentState -> currentState.copy( detailBackStack = currentState.detailBackStack + destination diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt index 1d1ad79c7e81..5054706aee2b 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt @@ -16,17 +16,17 @@ import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography -import com.woocommerce.android.ui.woopos.settings.SettingsCategory +import com.woocommerce.android.ui.woopos.settings.WooPosSettingsCategory @Composable fun WooPosSettingsCategoriesPane( - selectedCategory: SettingsCategory, - onCategorySelected: (SettingsCategory) -> Unit, + selectedCategory: WooPosSettingsCategory, + onCategorySelected: (WooPosSettingsCategory) -> Unit, modifier: Modifier = Modifier, viewModel: WooPosSettingsCategoriesViewModel = hiltViewModel() ) { val state by viewModel.state.collectAsState() - + Column( modifier = modifier .fillMaxSize() @@ -36,11 +36,9 @@ fun WooPosSettingsCategoriesPane( state.categories.forEach { item -> CategoryItem( item = item, - isSelected = item.category == selectedCategory, - onClick = { - if (item.isEnabled) { - onCategorySelected(item.category) - } + isSelected = item == selectedCategory, + onClick = { + onCategorySelected(item) } ) } @@ -49,7 +47,7 @@ fun WooPosSettingsCategoriesPane( @Composable private fun CategoryItem( - item: SettingsCategoryItem, + item: WooPosSettingsCategory, isSelected: Boolean, onClick: () -> Unit ) { @@ -58,13 +56,12 @@ private fun CategoryItem( } else { MaterialTheme.colorScheme.surface } - + val textColor = when { - !item.isEnabled -> MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f) isSelected -> MaterialTheme.colorScheme.onPrimaryContainer else -> MaterialTheme.colorScheme.onSurface } - + WooPosText( text = stringResource(item.titleRes), style = WooPosTypography.BodyLarge, @@ -72,7 +69,7 @@ private fun CategoryItem( modifier = Modifier .fillMaxWidth() .background(backgroundColor) - .clickable(enabled = item.isEnabled) { onClick() } + .clickable { onClick() } .padding(WooPosSpacing.Medium.value) ) -} \ No newline at end of file +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt index 0b9ff05d60a2..97a7c5cddf5e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt @@ -1,19 +1,7 @@ package com.woocommerce.android.ui.woopos.settings.categories -import androidx.annotation.StringRes -import com.woocommerce.android.ui.woopos.settings.SettingsCategory - -data class SettingsCategoryItem( - val category: SettingsCategory, - @StringRes val titleRes: Int, - val isEnabled: Boolean = true -) +import com.woocommerce.android.ui.woopos.settings.WooPosSettingsCategory data class WooPosSettingsCategoriesState( - val categories: List = listOf( - SettingsCategoryItem( - category = SettingsCategory.HARDWARE, - titleRes = SettingsCategory.HARDWARE.titleRes - ) - ) -) \ No newline at end of file + val categories: List = WooPosSettingsCategory.entries +) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesViewModel.kt index 195a9b5d835d..8f82c4203a83 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesViewModel.kt @@ -9,16 +9,6 @@ import javax.inject.Inject @HiltViewModel class WooPosSettingsCategoriesViewModel @Inject constructor() : ViewModel() { - private val _state = MutableStateFlow(WooPosSettingsCategoriesState()) val state: StateFlow = _state.asStateFlow() - - init { - loadCategories() - } - - private fun loadCategories() { - // In the future, this could load categories based on feature flags, - // user permissions, or other business logic - } -} \ No newline at end of file +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt index d56fddfb401e..df61c99dceea 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt @@ -24,24 +24,24 @@ import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography +import com.woocommerce.android.ui.woopos.settings.WooPosSettingsDetailDestination import com.woocommerce.android.ui.woopos.settings.WooPosSettingsState -import com.woocommerce.android.ui.woopos.settings.SettingsDetailDestination import com.woocommerce.android.ui.woopos.settings.details.hardware.WooPosHardwareSettingsScreen @Composable fun WooPosSettingsDetailPane( state: WooPosSettingsState, - onNavigate: (SettingsDetailDestination) -> Unit, + onNavigate: (WooPosSettingsDetailDestination) -> Unit, onBack: () -> Unit, modifier: Modifier = Modifier ) { val currentDestination = state.detailBackStack.lastOrNull() val canGoBack = state.detailBackStack.size > 1 - + BackHandler(enabled = canGoBack) { onBack() } - + Column( modifier = modifier .fillMaxSize() @@ -50,19 +50,19 @@ fun WooPosSettingsDetailPane( if (canGoBack) { DetailPaneToolbar(onBack = onBack) } - + AnimatedContent( targetState = currentDestination, label = "settings_detail_animation" ) { destination -> when (destination) { - is SettingsDetailDestination.HardwareOverview -> { + is WooPosSettingsDetailDestination.HardwareOverview -> { WooPosHardwareSettingsScreen(onNavigate = onNavigate) } - is SettingsDetailDestination.BarcodeScanners -> { + is WooPosSettingsDetailDestination.BarcodeScanners -> { BarcodeScannerDetailScreen() } - is SettingsDetailDestination.CardReaders -> { + is WooPosSettingsDetailDestination.CardReaders -> { CardReadersDetailScreen() } null -> { @@ -120,4 +120,4 @@ private fun CardReadersDetailScreen() { style = WooPosTypography.Heading ) } -} \ No newline at end of file +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt index b43f7315276c..e337b9e0023d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -21,15 +21,15 @@ import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography -import com.woocommerce.android.ui.woopos.settings.SettingsDetailDestination +import com.woocommerce.android.ui.woopos.settings.WooPosSettingsDetailDestination @Composable fun WooPosHardwareSettingsScreen( - onNavigate: (SettingsDetailDestination) -> Unit, + onNavigate: (WooPosSettingsDetailDestination) -> Unit, viewModel: WooPosHardwareSettingsViewModel = hiltViewModel() ) { val state by viewModel.state.collectAsState() - + Column( modifier = Modifier .fillMaxSize() @@ -40,15 +40,17 @@ fun WooPosHardwareSettingsScreen( style = WooPosTypography.Heading, modifier = Modifier.padding(bottom = WooPosSpacing.Medium.value) ) - + state.items.forEach { item -> HardwareSettingsMenuItem( item = item, onClick = { - viewModel.onItemClicked(item.id) - when (item.id) { - "barcode_scanners" -> onNavigate(SettingsDetailDestination.BarcodeScanners) - "card_readers" -> onNavigate(SettingsDetailDestination.CardReaders) + when (item.titleRes) { + R.string.woopos_settings_hardware_barcode_scanners -> + onNavigate(WooPosSettingsDetailDestination.BarcodeScanners) + + R.string.woopos_settings_hardware_card_readers -> + onNavigate(WooPosSettingsDetailDestination.CardReaders) } } ) @@ -89,4 +91,4 @@ private fun HardwareSettingsMenuItem( tint = MaterialTheme.colorScheme.onSurfaceVariant ) } -} \ No newline at end of file +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt index f57b29f5aad1..9194c9bb2a9c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt @@ -4,23 +4,19 @@ import androidx.annotation.StringRes import com.woocommerce.android.R data class HardwareSettingsItem( - val id: String, @StringRes val titleRes: Int, - @StringRes val subtitleRes: Int? = null + @StringRes val subtitleRes: Int, ) data class WooPosHardwareSettingsState( val items: List = listOf( HardwareSettingsItem( - id = "barcode_scanners", titleRes = R.string.woopos_settings_hardware_barcode_scanners, subtitleRes = R.string.woopos_settings_hardware_barcode_scanners_subtitle ), HardwareSettingsItem( - id = "card_readers", titleRes = R.string.woopos_settings_hardware_card_readers, subtitleRes = R.string.woopos_settings_hardware_card_readers_subtitle ) ), - val isLoading: Boolean = false -) \ No newline at end of file +) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsViewModel.kt index d2a0dfd44db7..12747c683890 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsViewModel.kt @@ -11,9 +11,4 @@ import javax.inject.Inject class WooPosHardwareSettingsViewModel @Inject constructor() : ViewModel() { private val _state = MutableStateFlow(WooPosHardwareSettingsState()) val state: StateFlow = _state.asStateFlow() - - fun onItemClicked(itemId: String) { - // Handle item clicks - in real implementation this would trigger navigation - // For now, navigation is handled by the container - } } From ecd382b95e7314cba543ddfaacdf83d37b7f9a26 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 11:48:09 +0200 Subject: [PATCH 05/15] Make category-destination relationship compile-time safe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move root destination directly into WooPosSettingsCategory enum to eliminate potential mismatches between categories and their destinations. Remove companion object function that created loose coupling. 🤖 Generated with [Claude Code](https://claude.ai/code) --- .../ui/woopos/settings/WooPosSettingsState.kt | 35 +++++++++++++------ .../settings/WooPosSettingsViewModel.kt | 20 ++++------- ... => WooPosSettingsCategoriesPaneScreen.kt} | 1 - .../WooPosSettingsCategoriesState.kt | 14 +++++++- ...e.kt => WooPosSettingsDetailPaneScreen.kt} | 0 5 files changed, 45 insertions(+), 25 deletions(-) rename WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/{WooPosSettingsCategoriesPane.kt => WooPosSettingsCategoriesPaneScreen.kt} (97%) rename WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/{WooPosSettingsDetailPane.kt => WooPosSettingsDetailPaneScreen.kt} (100%) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt index 579e4e804b21..ed5691be0e84 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt @@ -1,19 +1,34 @@ package com.woocommerce.android.ui.woopos.settings -import androidx.annotation.StringRes -import com.woocommerce.android.R +import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategory data class WooPosSettingsState( val selectedCategory: WooPosSettingsCategory = WooPosSettingsCategory.HARDWARE, - val detailBackStack: List = listOf(WooPosSettingsDetailDestination.HardwareOverview) -) - -enum class WooPosSettingsCategory(@StringRes val titleRes: Int) { - HARDWARE(R.string.woopos_settings_hardware_category) + val currentDestination: WooPosSettingsDetailDestination = selectedCategory.rootDestination +) { + val canGoBack: Boolean + get() = currentDestination.parentDestination != null } sealed class WooPosSettingsDetailDestination { - data object HardwareOverview : WooPosSettingsDetailDestination() - data object BarcodeScanners : WooPosSettingsDetailDestination() - data object CardReaders : WooPosSettingsDetailDestination() + abstract val parentDestination: WooPosSettingsDetailDestination? + abstract val childDestinations: List + + sealed class Hardware : WooPosSettingsDetailDestination() { + + data object Overview : Hardware() { + override val parentDestination: WooPosSettingsDetailDestination? = null + override val childDestinations: List = listOf(BarcodeScanners, CardReaders) + } + + data object BarcodeScanners : Hardware() { + override val parentDestination: Hardware = Overview + override val childDestinations: List = emptyList() + } + + data object CardReaders : Hardware() { + override val parentDestination: Hardware = Overview + override val childDestinations: List = emptyList() + } + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt index 98e715664ab3..26949562f253 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsViewModel.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.ui.woopos.settings import androidx.lifecycle.ViewModel +import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategory import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -10,36 +11,29 @@ import javax.inject.Inject @HiltViewModel class WooPosSettingsViewModel @Inject constructor() : ViewModel() { - private val _navigationState = MutableStateFlow(WooPosSettingsState()) val navigationState: StateFlow = _navigationState.asStateFlow() fun onCategorySelected(category: WooPosSettingsCategory) { _navigationState.update { currentState -> - val newDetailDestination = when (category) { - WooPosSettingsCategory.HARDWARE -> WooPosSettingsDetailDestination.HardwareOverview - } currentState.copy( selectedCategory = category, - detailBackStack = listOf(newDetailDestination) + currentDestination = category.rootDestination ) } } fun navigateToDetail(destination: WooPosSettingsDetailDestination) { _navigationState.update { currentState -> - currentState.copy( - detailBackStack = currentState.detailBackStack + destination - ) + currentState.copy(currentDestination = destination) } } - fun popDetailBackStack() { + fun navigateBack() { _navigationState.update { currentState -> - if (currentState.detailBackStack.size > 1) { - currentState.copy( - detailBackStack = currentState.detailBackStack.dropLast(1) - ) + val parentDestination = currentState.currentDestination.parentDestination + if (parentDestination != null) { + currentState.copy(currentDestination = parentDestination) } else { currentState } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt similarity index 97% rename from WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt rename to WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt index 5054706aee2b..87d5ac961fed 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPane.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt @@ -16,7 +16,6 @@ import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography -import com.woocommerce.android.ui.woopos.settings.WooPosSettingsCategory @Composable fun WooPosSettingsCategoriesPane( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt index 97a7c5cddf5e..ae8eacdab21e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt @@ -1,6 +1,18 @@ package com.woocommerce.android.ui.woopos.settings.categories -import com.woocommerce.android.ui.woopos.settings.WooPosSettingsCategory +import androidx.annotation.StringRes +import com.woocommerce.android.R +import com.woocommerce.android.ui.woopos.settings.WooPosSettingsDetailDestination + +enum class WooPosSettingsCategory( + @StringRes val titleRes: Int, + val rootDestination: WooPosSettingsDetailDestination +) { + HARDWARE( + R.string.woopos_settings_hardware_category, + WooPosSettingsDetailDestination.Hardware.Overview + ) +} data class WooPosSettingsCategoriesState( val categories: List = WooPosSettingsCategory.entries diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt similarity index 100% rename from WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPane.kt rename to WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt From c6fc1fc146a0823107330d29807b23765308addf Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 11:49:09 +0200 Subject: [PATCH 06/15] Rename settings pane functions for consistency and update navigation destinations --- .../ui/woopos/settings/WooPosSettingsScreen.kt | 10 +++++----- .../WooPosSettingsCategoriesPaneScreen.kt | 2 +- .../details/WooPosSettingsDetailPaneScreen.kt | 18 +++++++----------- .../hardware/WooPosHardwareSettingsScreen.kt | 4 ++-- 4 files changed, 15 insertions(+), 19 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt index 83f3ed68826c..fd15ba492c91 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt @@ -19,8 +19,8 @@ import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosToolbar import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTheme import com.woocommerce.android.ui.woopos.root.navigation.WooPosNavigationEvent -import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategoriesPane -import com.woocommerce.android.ui.woopos.settings.details.WooPosSettingsDetailPane +import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategoriesPaneScreen +import com.woocommerce.android.ui.woopos.settings.details.WooPosSettingsDetailPaneScreen @Composable fun WooPosSettingsScreen( @@ -47,7 +47,7 @@ fun WooPosSettingsScreen( Row( modifier = Modifier.fillMaxSize() ) { - WooPosSettingsCategoriesPane( + WooPosSettingsCategoriesPaneScreen( selectedCategory = navigationState.selectedCategory, onCategorySelected = containerViewModel::onCategorySelected, modifier = Modifier.weight(0.3f) @@ -57,10 +57,10 @@ fun WooPosSettingsScreen( color = MaterialTheme.colorScheme.outlineVariant ) - WooPosSettingsDetailPane( + WooPosSettingsDetailPaneScreen( state = navigationState, onNavigate = containerViewModel::navigateToDetail, - onBack = containerViewModel::popDetailBackStack, + onBack = containerViewModel::navigateBack, modifier = Modifier.weight(0.7f) ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt index 87d5ac961fed..0ca95918deea 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt @@ -18,7 +18,7 @@ import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpa import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography @Composable -fun WooPosSettingsCategoriesPane( +fun WooPosSettingsCategoriesPaneScreen( selectedCategory: WooPosSettingsCategory, onCategorySelected: (WooPosSettingsCategory) -> Unit, modifier: Modifier = Modifier, diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt index df61c99dceea..ddf08c75fac8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt @@ -29,16 +29,15 @@ import com.woocommerce.android.ui.woopos.settings.WooPosSettingsState import com.woocommerce.android.ui.woopos.settings.details.hardware.WooPosHardwareSettingsScreen @Composable -fun WooPosSettingsDetailPane( +fun WooPosSettingsDetailPaneScreen( state: WooPosSettingsState, onNavigate: (WooPosSettingsDetailDestination) -> Unit, onBack: () -> Unit, modifier: Modifier = Modifier ) { - val currentDestination = state.detailBackStack.lastOrNull() - val canGoBack = state.detailBackStack.size > 1 + val currentDestination = state.currentDestination - BackHandler(enabled = canGoBack) { + BackHandler(enabled = state.canGoBack) { onBack() } @@ -47,7 +46,7 @@ fun WooPosSettingsDetailPane( .fillMaxSize() .background(MaterialTheme.colorScheme.background) ) { - if (canGoBack) { + if (state.canGoBack) { DetailPaneToolbar(onBack = onBack) } @@ -56,18 +55,15 @@ fun WooPosSettingsDetailPane( label = "settings_detail_animation" ) { destination -> when (destination) { - is WooPosSettingsDetailDestination.HardwareOverview -> { + is WooPosSettingsDetailDestination.Hardware.Overview -> { WooPosHardwareSettingsScreen(onNavigate = onNavigate) } - is WooPosSettingsDetailDestination.BarcodeScanners -> { + is WooPosSettingsDetailDestination.Hardware.BarcodeScanners -> { BarcodeScannerDetailScreen() } - is WooPosSettingsDetailDestination.CardReaders -> { + is WooPosSettingsDetailDestination.Hardware.CardReaders -> { CardReadersDetailScreen() } - null -> { - Box(modifier = Modifier.fillMaxSize()) - } } } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt index e337b9e0023d..7fc0acd9fbbe 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -47,10 +47,10 @@ fun WooPosHardwareSettingsScreen( onClick = { when (item.titleRes) { R.string.woopos_settings_hardware_barcode_scanners -> - onNavigate(WooPosSettingsDetailDestination.BarcodeScanners) + onNavigate(WooPosSettingsDetailDestination.Hardware.BarcodeScanners) R.string.woopos_settings_hardware_card_readers -> - onNavigate(WooPosSettingsDetailDestination.CardReaders) + onNavigate(WooPosSettingsDetailDestination.Hardware.CardReaders) } } ) From c7f4cd63fa0429ccd58688efbc8e0738a777f41f Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 12:48:32 +0200 Subject: [PATCH 07/15] Update POS settings UI to match Android settings design with icons, subtitles, and proper alignment --- .../woopos/settings/WooPosSettingsScreen.kt | 72 +++++++++++-------- .../ui/woopos/settings/WooPosSettingsState.kt | 8 ++- .../WooPosSettingsCategoriesPaneScreen.kt | 63 +++++++++------- .../WooPosSettingsCategoriesState.kt | 7 ++ .../details/WooPosSettingsDetailPaneScreen.kt | 52 +++++++++----- .../hardware/WooPosHardwareSettingsScreen.kt | 55 +++++++------- .../hardware/WooPosHardwareSettingsState.kt | 11 ++- WooCommerce/src/main/res/values/strings.xml | 1 + 8 files changed, 171 insertions(+), 98 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt index fd15ba492c91..18fa5b31fee9 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt @@ -1,23 +1,27 @@ package com.woocommerce.android.ui.woopos.settings import androidx.activity.compose.BackHandler +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.material3.HorizontalDivider +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.VerticalDivider import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview -import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosToolbar +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTheme +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography import com.woocommerce.android.ui.woopos.root.navigation.WooPosNavigationEvent import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategoriesPaneScreen import com.woocommerce.android.ui.woopos.settings.details.WooPosSettingsDetailPaneScreen @@ -31,40 +35,52 @@ fun WooPosSettingsScreen( BackHandler { onNavigationEvent(WooPosNavigationEvent.GoBack) } - Column( + Row( modifier = Modifier.fillMaxSize() ) { - WooPosToolbar( - titleText = stringResource(R.string.woopos_settings_title), - onBackClicked = { onNavigationEvent(WooPosNavigationEvent.GoBack) } - ) - - HorizontalDivider( - modifier = Modifier.fillMaxWidth(), - color = MaterialTheme.colorScheme.outlineVariant - ) - - Row( - modifier = Modifier.fillMaxSize() + Column( + modifier = Modifier + .weight(0.3f) + .background(MaterialTheme.colorScheme.surface) ) { + SettingsCategoriesToolbar( + titleText = stringResource(R.string.woopos_settings_title) + ) + WooPosSettingsCategoriesPaneScreen( - selectedCategory = navigationState.selectedCategory, onCategorySelected = containerViewModel::onCategorySelected, - modifier = Modifier.weight(0.3f) + modifier = Modifier.fillMaxSize() ) + } - VerticalDivider( - color = MaterialTheme.colorScheme.outlineVariant - ) + WooPosSettingsDetailPaneScreen( + state = navigationState, + onNavigate = containerViewModel::navigateToDetail, + onBack = containerViewModel::navigateBack, + modifier = Modifier + .weight(0.7f) + .background(MaterialTheme.colorScheme.surfaceContainerLow) + ) + } +} - WooPosSettingsDetailPaneScreen( - state = navigationState, - onNavigate = containerViewModel::navigateToDetail, - onBack = containerViewModel::navigateBack, - modifier = Modifier.weight(0.7f) +@Composable +private fun SettingsCategoriesToolbar( + titleText: String +) { + WooPosText( + text = titleText, + style = WooPosTypography.Heading, + fontWeight = FontWeight.Bold, + maxLines = 1, + modifier = Modifier + .fillMaxWidth() + .statusBarsPadding() + .padding( + horizontal = WooPosSpacing.Medium.value, + vertical = WooPosSpacing.Medium.value ) - } - } + ) } @WooPosPreview diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt index ed5691be0e84..2d3ce4753664 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt @@ -1,5 +1,7 @@ package com.woocommerce.android.ui.woopos.settings +import androidx.annotation.StringRes +import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategory data class WooPosSettingsState( @@ -11,22 +13,26 @@ data class WooPosSettingsState( } sealed class WooPosSettingsDetailDestination { + @get:StringRes + abstract val titleRes: Int abstract val parentDestination: WooPosSettingsDetailDestination? abstract val childDestinations: List sealed class Hardware : WooPosSettingsDetailDestination() { - data object Overview : Hardware() { + override val titleRes: Int = R.string.woopos_settings_hardware_category override val parentDestination: WooPosSettingsDetailDestination? = null override val childDestinations: List = listOf(BarcodeScanners, CardReaders) } data object BarcodeScanners : Hardware() { + override val titleRes: Int = R.string.woopos_settings_hardware_barcode_scanners override val parentDestination: Hardware = Overview override val childDestinations: List = emptyList() } data object CardReaders : Hardware() { + override val titleRes: Int = R.string.woopos_settings_hardware_card_readers override val parentDestination: Hardware = Overview override val childDestinations: List = emptyList() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt index 0ca95918deea..039619106850 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt @@ -1,17 +1,22 @@ package com.woocommerce.android.ui.woopos.settings.categories -import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing @@ -19,7 +24,6 @@ import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTyp @Composable fun WooPosSettingsCategoriesPaneScreen( - selectedCategory: WooPosSettingsCategory, onCategorySelected: (WooPosSettingsCategory) -> Unit, modifier: Modifier = Modifier, viewModel: WooPosSettingsCategoriesViewModel = hiltViewModel() @@ -29,13 +33,10 @@ fun WooPosSettingsCategoriesPaneScreen( Column( modifier = modifier .fillMaxSize() - .background(MaterialTheme.colorScheme.surface) - .padding(WooPosSpacing.Medium.value) ) { state.categories.forEach { item -> CategoryItem( item = item, - isSelected = item == selectedCategory, onClick = { onCategorySelected(item) } @@ -47,28 +48,42 @@ fun WooPosSettingsCategoriesPaneScreen( @Composable private fun CategoryItem( item: WooPosSettingsCategory, - isSelected: Boolean, onClick: () -> Unit ) { - val backgroundColor = if (isSelected) { - MaterialTheme.colorScheme.primaryContainer - } else { - MaterialTheme.colorScheme.surface - } - - val textColor = when { - isSelected -> MaterialTheme.colorScheme.onPrimaryContainer - else -> MaterialTheme.colorScheme.onSurface - } - - WooPosText( - text = stringResource(item.titleRes), - style = WooPosTypography.BodyLarge, - color = textColor, + val textColor = MaterialTheme.colorScheme.onSurface + val iconTint = MaterialTheme.colorScheme.onSurfaceVariant + Row( modifier = Modifier .fillMaxWidth() - .background(backgroundColor) .clickable { onClick() } - .padding(WooPosSpacing.Medium.value) - ) + .padding( + horizontal = WooPosSpacing.Medium.value, + vertical = WooPosSpacing.Small.value + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Start + ) { + Icon( + imageVector = item.icon, + contentDescription = null, + tint = iconTint, + modifier = Modifier.size(24.dp) + ) + + Column( + modifier = Modifier.padding(start = WooPosSpacing.Medium.value) + ) { + WooPosText( + text = stringResource(item.titleRes), + style = WooPosTypography.BodyLarge, + color = textColor + ) + WooPosText( + text = stringResource(item.subtitleRes), + style = WooPosTypography.BodySmall, + color = MaterialTheme.colorScheme.outline, + modifier = Modifier.padding(top = WooPosSpacing.XSmall.value) + ) + } + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt index ae8eacdab21e..524c45501da3 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt @@ -1,15 +1,22 @@ package com.woocommerce.android.ui.woopos.settings.categories import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Build +import androidx.compose.ui.graphics.vector.ImageVector import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.settings.WooPosSettingsDetailDestination enum class WooPosSettingsCategory( @StringRes val titleRes: Int, + @StringRes val subtitleRes: Int, + val icon: ImageVector, val rootDestination: WooPosSettingsDetailDestination ) { HARDWARE( R.string.woopos_settings_hardware_category, + R.string.woopos_settings_hardware_category_subtitle, + Icons.Default.Build, WooPosSettingsDetailDestination.Hardware.Overview ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt index ddf08c75fac8..c9b7d10aef1e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt @@ -2,7 +2,6 @@ package com.woocommerce.android.ui.woopos.settings.details import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent -import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -10,6 +9,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Icon @@ -42,13 +42,15 @@ fun WooPosSettingsDetailPaneScreen( } Column( - modifier = modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.background) + modifier = modifier.fillMaxSize() + .padding(WooPosSpacing.Medium.value) + .statusBarsPadding() ) { - if (state.canGoBack) { - DetailPaneToolbar(onBack = onBack) - } + DetailPaneToolbar( + canGoBack = state.canGoBack, + title = state.currentDestination.titleRes, + onBack = onBack + ) AnimatedContent( targetState = currentDestination, @@ -70,21 +72,39 @@ fun WooPosSettingsDetailPaneScreen( } @Composable -private fun DetailPaneToolbar(onBack: () -> Unit) { +private fun DetailPaneToolbar( + canGoBack: Boolean, + @androidx.annotation.StringRes title: Int, + onBack: () -> Unit +) { Row( modifier = Modifier .fillMaxWidth() - .padding(WooPosSpacing.Small.value), + .padding( + top = WooPosSpacing.Small.value, + bottom = WooPosSpacing.Medium.value + ), verticalAlignment = Alignment.CenterVertically ) { - IconButton(onClick = onBack) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.woopos_settings_back_content_description), - tint = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.size(24.dp) - ) + if (canGoBack) { + IconButton(onClick = onBack) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.woopos_settings_back_content_description), + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(24.dp) + ) + } } + + WooPosText( + text = stringResource(title), + style = WooPosTypography.BodyLarge, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.padding( + start = if (canGoBack) WooPosSpacing.XSmall.value else WooPosSpacing.Medium.value + ) + ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt index 7fc0acd9fbbe..19eba3a3cc1c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -1,13 +1,13 @@ package com.woocommerce.android.ui.woopos.settings.details.hardware import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight +import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -16,6 +16,7 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText @@ -31,16 +32,8 @@ fun WooPosHardwareSettingsScreen( val state by viewModel.state.collectAsState() Column( - modifier = Modifier - .fillMaxSize() - .padding(WooPosSpacing.Medium.value) + modifier = Modifier.fillMaxSize() ) { - WooPosText( - text = stringResource(R.string.woopos_settings_hardware_category), - style = WooPosTypography.Heading, - modifier = Modifier.padding(bottom = WooPosSpacing.Medium.value) - ) - state.items.forEach { item -> HardwareSettingsMenuItem( item = item, @@ -67,28 +60,36 @@ private fun HardwareSettingsMenuItem( modifier = Modifier .fillMaxWidth() .clickable { onClick() } - .padding(vertical = WooPosSpacing.Medium.value), - verticalAlignment = Alignment.CenterVertically + .padding( + horizontal = WooPosSpacing.Medium.value, + vertical = WooPosSpacing.Medium.value + ), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Start ) { - Column(modifier = Modifier.weight(1f)) { + Icon( + imageVector = item.icon, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.size(24.dp) + ) + + Column( + modifier = Modifier + .weight(1f) + .padding(start = WooPosSpacing.Medium.value) + ) { WooPosText( text = stringResource(item.titleRes), style = WooPosTypography.BodyLarge, color = MaterialTheme.colorScheme.onSurface ) - item.subtitleRes?.let { subtitleRes -> - WooPosText( - text = stringResource(subtitleRes), - style = WooPosTypography.BodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.padding(top = WooPosSpacing.XSmall.value) - ) - } + WooPosText( + text = stringResource(item.subtitleRes), + style = WooPosTypography.BodySmall, + color = MaterialTheme.colorScheme.outline, + modifier = Modifier.padding(top = WooPosSpacing.XSmall.value) + ) } - Icon( - imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight, - contentDescription = null, - tint = MaterialTheme.colorScheme.onSurfaceVariant - ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt index 9194c9bb2a9c..967ff3fab9c2 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsState.kt @@ -1,22 +1,29 @@ package com.woocommerce.android.ui.woopos.settings.details.hardware import androidx.annotation.StringRes +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CreditCard +import androidx.compose.material.icons.filled.QrCodeScanner +import androidx.compose.ui.graphics.vector.ImageVector import com.woocommerce.android.R data class HardwareSettingsItem( @StringRes val titleRes: Int, @StringRes val subtitleRes: Int, + val icon: ImageVector, ) data class WooPosHardwareSettingsState( val items: List = listOf( HardwareSettingsItem( titleRes = R.string.woopos_settings_hardware_barcode_scanners, - subtitleRes = R.string.woopos_settings_hardware_barcode_scanners_subtitle + subtitleRes = R.string.woopos_settings_hardware_barcode_scanners_subtitle, + icon = Icons.Default.QrCodeScanner ), HardwareSettingsItem( titleRes = R.string.woopos_settings_hardware_card_readers, - subtitleRes = R.string.woopos_settings_hardware_card_readers_subtitle + subtitleRes = R.string.woopos_settings_hardware_card_readers_subtitle, + icon = Icons.Default.CreditCard ) ), ) diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index d4b8c61d6b20..b344883f1d38 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -4340,6 +4340,7 @@ Settings Hardware + Manage hardware connections Barcode scanners Configure barcode scanner settings Card Readers From 18d41716c14015c35b15defa526c73bc90990c92 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 12:53:26 +0200 Subject: [PATCH 08/15] Add scrolling, fix toolbar jumping, and improve detail animations in POS settings --- .../WooPosSettingsCategoriesPaneScreen.kt | 3 ++ .../details/WooPosSettingsDetailPaneScreen.kt | 40 ++++++++++++++----- .../hardware/WooPosHardwareSettingsScreen.kt | 6 ++- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt index 039619106850..743fb61219dd 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt @@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -33,6 +35,7 @@ fun WooPosSettingsCategoriesPaneScreen( Column( modifier = modifier .fillMaxSize() + .verticalScroll(rememberScrollState()) ) { state.categories.forEach { item -> CategoryItem( diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt index c9b7d10aef1e..fe9fe94637b7 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt @@ -2,6 +2,11 @@ package com.woocommerce.android.ui.woopos.settings.details import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -54,6 +59,16 @@ fun WooPosSettingsDetailPaneScreen( AnimatedContent( targetState = currentDestination, + transitionSpec = { + val isNavigatingForward = targetState.parentDestination == initialState + if (isNavigatingForward) { + (slideInHorizontally(initialOffsetX = { it }) + fadeIn()) togetherWith + (slideOutHorizontally(targetOffsetX = { -it }) + fadeOut()) + } else { + (slideInHorizontally(initialOffsetX = { -it }) + fadeIn()) togetherWith + (slideOutHorizontally(targetOffsetX = { it }) + fadeOut()) + } + }, label = "settings_detail_animation" ) { destination -> when (destination) { @@ -86,14 +101,19 @@ private fun DetailPaneToolbar( ), verticalAlignment = Alignment.CenterVertically ) { - if (canGoBack) { - IconButton(onClick = onBack) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.woopos_settings_back_content_description), - tint = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.size(24.dp) - ) + Box( + modifier = Modifier.size(48.dp), + contentAlignment = Alignment.Center + ) { + if (canGoBack) { + IconButton(onClick = onBack) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.woopos_settings_back_content_description), + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(24.dp) + ) + } } } @@ -101,9 +121,7 @@ private fun DetailPaneToolbar( text = stringResource(title), style = WooPosTypography.BodyLarge, color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.padding( - start = if (canGoBack) WooPosSpacing.XSmall.value else WooPosSpacing.Medium.value - ) + modifier = Modifier.padding(start = WooPosSpacing.XSmall.value) ) } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt index 19eba3a3cc1c..ab102cc28a11 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable @@ -32,7 +34,9 @@ fun WooPosHardwareSettingsScreen( val state by viewModel.state.collectAsState() Column( - modifier = Modifier.fillMaxSize() + modifier = Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) ) { state.items.forEach { item -> HardwareSettingsMenuItem( From e836c249d8ee997f664483ebfcfcf6a59c121cd4 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 13:16:15 +0200 Subject: [PATCH 09/15] Improve detail toolbar animations and fix vertical jumping --- .../WooPosSettingsCategoriesState.kt | 4 +- .../details/WooPosSettingsDetailPaneScreen.kt | 73 +++++++++++++------ 2 files changed, 52 insertions(+), 25 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt index 524c45501da3..785f3656cd57 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt @@ -2,7 +2,7 @@ package com.woocommerce.android.ui.woopos.settings.categories import androidx.annotation.StringRes import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Build +import androidx.compose.material.icons.filled.Hardware import androidx.compose.ui.graphics.vector.ImageVector import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.settings.WooPosSettingsDetailDestination @@ -16,7 +16,7 @@ enum class WooPosSettingsCategory( HARDWARE( R.string.woopos_settings_hardware_category, R.string.woopos_settings_hardware_category_subtitle, - Icons.Default.Build, + Icons.Default.Hardware, WooPosSettingsDetailDestination.Hardware.Overview ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt index fe9fe94637b7..07423db49c4e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt @@ -1,17 +1,21 @@ package com.woocommerce.android.ui.woopos.settings.details import androidx.activity.compose.BackHandler +import androidx.annotation.StringRes import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding @@ -25,6 +29,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.constraintlayout.compose.ConstraintLayout +import androidx.constraintlayout.compose.Dimension import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing @@ -89,40 +95,61 @@ fun WooPosSettingsDetailPaneScreen( @Composable private fun DetailPaneToolbar( canGoBack: Boolean, - @androidx.annotation.StringRes title: Int, + @StringRes title: Int, onBack: () -> Unit ) { - Row( + ConstraintLayout( modifier = Modifier .fillMaxWidth() + .height(56.dp) .padding( top = WooPosSpacing.Small.value, bottom = WooPosSpacing.Medium.value - ), - verticalAlignment = Alignment.CenterVertically + ) ) { - Box( - modifier = Modifier.size(48.dp), - contentAlignment = Alignment.Center + val (backButton, titleText) = createRefs() + + AnimatedVisibility( + visible = canGoBack, + enter = scaleIn() + fadeIn(), + exit = scaleOut() + fadeOut(), + modifier = Modifier.constrainAs(backButton) { + start.linkTo(parent.start) + centerVerticallyTo(parent) + } ) { - if (canGoBack) { - IconButton(onClick = onBack) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.woopos_settings_back_content_description), - tint = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.size(24.dp) - ) - } + IconButton(onClick = onBack) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.woopos_toolbar_icon_content_description), + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(28.dp) + ) } } - WooPosText( - text = stringResource(title), - style = WooPosTypography.BodyLarge, - color = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.padding(start = WooPosSpacing.XSmall.value) - ) + AnimatedContent( + targetState = title, + transitionSpec = { + fadeIn() togetherWith fadeOut() + }, + label = "title_text_animation", + modifier = Modifier.constrainAs(titleText) { + start.linkTo( + if (canGoBack) backButton.end else parent.start, + margin = if (canGoBack) WooPosSpacing.XSmall.value else 0.dp + ) + end.linkTo(parent.end) + centerVerticallyTo(parent) + width = Dimension.fillToConstraints + } + ) { currentTitle -> + WooPosText( + text = stringResource(currentTitle), + style = WooPosTypography.BodyLarge, + color = MaterialTheme.colorScheme.onSurface + ) + } } } From a73b68ed8ee8d5607ed6d6e2c65d9f438b7bbfaa Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 14:17:03 +0200 Subject: [PATCH 10/15] Update settings UI with Android-style selection --- .../woopos/settings/WooPosSettingsScreen.kt | 1 + .../ui/woopos/settings/WooPosSettingsState.kt | 8 +++++ .../WooPosSettingsCategoriesPaneScreen.kt | 35 +++++++++++++------ .../WooPosSettingsCategoriesState.kt | 7 ++++ .../details/WooPosSettingsDetailPaneScreen.kt | 24 ++++++++++++- .../hardware/WooPosHardwareSettingsScreen.kt | 4 +-- WooCommerce/src/main/res/values/strings.xml | 3 +- 7 files changed, 68 insertions(+), 14 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt index 18fa5b31fee9..87a1f6808c86 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsScreen.kt @@ -48,6 +48,7 @@ fun WooPosSettingsScreen( ) WooPosSettingsCategoriesPaneScreen( + selectedCategory = navigationState.selectedCategory, onCategorySelected = containerViewModel::onCategorySelected, modifier = Modifier.fillMaxSize() ) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt index 2d3ce4753664..b93fc0c62dc4 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/WooPosSettingsState.kt @@ -37,4 +37,12 @@ sealed class WooPosSettingsDetailDestination { override val childDestinations: List = emptyList() } } + + sealed class Store : WooPosSettingsDetailDestination() { + data object Overview : Store() { + override val titleRes: Int = R.string.woopos_settings_store_category + override val parentDestination: WooPosSettingsDetailDestination? = null + override val childDestinations: List = emptyList() + } + } } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt index 743fb61219dd..3ee0238b209e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesPaneScreen.kt @@ -1,5 +1,6 @@ package com.woocommerce.android.ui.woopos.settings.categories +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -9,6 +10,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme @@ -17,15 +19,18 @@ import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText +import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosCornerRadius import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography @Composable fun WooPosSettingsCategoriesPaneScreen( + selectedCategory: WooPosSettingsCategory, onCategorySelected: (WooPosSettingsCategory) -> Unit, modifier: Modifier = Modifier, viewModel: WooPosSettingsCategoriesViewModel = hiltViewModel() @@ -40,9 +45,11 @@ fun WooPosSettingsCategoriesPaneScreen( state.categories.forEach { item -> CategoryItem( item = item, + isSelected = item == selectedCategory, onClick = { onCategorySelected(item) - } + }, + modifier = Modifier.padding(horizontal = WooPosSpacing.Medium.value) ) } } @@ -51,17 +58,25 @@ fun WooPosSettingsCategoriesPaneScreen( @Composable private fun CategoryItem( item: WooPosSettingsCategory, - onClick: () -> Unit + isSelected: Boolean, + onClick: () -> Unit, + modifier: Modifier = Modifier ) { - val textColor = MaterialTheme.colorScheme.onSurface - val iconTint = MaterialTheme.colorScheme.onSurfaceVariant Row( - modifier = Modifier + modifier = modifier .fillMaxWidth() + .clip(RoundedCornerShape(WooPosCornerRadius.Large.value)) + .background( + if (isSelected) { + MaterialTheme.colorScheme.secondary.copy(alpha = 0.5f) + } else { + MaterialTheme.colorScheme.surface + } + ) .clickable { onClick() } .padding( horizontal = WooPosSpacing.Medium.value, - vertical = WooPosSpacing.Small.value + vertical = WooPosSpacing.Medium.value ), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Start @@ -69,8 +84,8 @@ private fun CategoryItem( Icon( imageVector = item.icon, contentDescription = null, - tint = iconTint, - modifier = Modifier.size(24.dp) + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(28.dp) ) Column( @@ -79,12 +94,12 @@ private fun CategoryItem( WooPosText( text = stringResource(item.titleRes), style = WooPosTypography.BodyLarge, - color = textColor + color = MaterialTheme.colorScheme.onSurface ) WooPosText( text = stringResource(item.subtitleRes), style = WooPosTypography.BodySmall, - color = MaterialTheme.colorScheme.outline, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = WooPosSpacing.XSmall.value) ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt index 785f3656cd57..6cfc4951d621 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/categories/WooPosSettingsCategoriesState.kt @@ -3,6 +3,7 @@ package com.woocommerce.android.ui.woopos.settings.categories import androidx.annotation.StringRes import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Hardware +import androidx.compose.material.icons.filled.Store import androidx.compose.ui.graphics.vector.ImageVector import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.settings.WooPosSettingsDetailDestination @@ -18,6 +19,12 @@ enum class WooPosSettingsCategory( R.string.woopos_settings_hardware_category_subtitle, Icons.Default.Hardware, WooPosSettingsDetailDestination.Hardware.Overview + ), + STORE( + R.string.woopos_settings_store_category, + R.string.woopos_settings_store_category_subtitle, + Icons.Default.Store, + WooPosSettingsDetailDestination.Store.Overview ) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt index 07423db49c4e..0c3634d6efe6 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt @@ -67,7 +67,11 @@ fun WooPosSettingsDetailPaneScreen( targetState = currentDestination, transitionSpec = { val isNavigatingForward = targetState.parentDestination == initialState - if (isNavigatingForward) { + val isCategorySwitch = initialState.parentDestination == null && targetState.parentDestination == null + + if (isCategorySwitch) { + fadeIn() togetherWith fadeOut() + } else if (isNavigatingForward) { (slideInHorizontally(initialOffsetX = { it }) + fadeIn()) togetherWith (slideOutHorizontally(targetOffsetX = { -it }) + fadeOut()) } else { @@ -87,6 +91,9 @@ fun WooPosSettingsDetailPaneScreen( is WooPosSettingsDetailDestination.Hardware.CardReaders -> { CardReadersDetailScreen() } + is WooPosSettingsDetailDestination.Store.Overview -> { + StoreDetailScreen() + } } } } @@ -182,3 +189,18 @@ private fun CardReadersDetailScreen() { ) } } + +@Composable +private fun StoreDetailScreen() { + Box( + modifier = Modifier + .fillMaxSize() + .padding(WooPosSpacing.Medium.value), + contentAlignment = Alignment.Center + ) { + WooPosText( + text = stringResource(R.string.woopos_settings_store_category), + style = WooPosTypography.Heading + ) + } +} diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt index ab102cc28a11..a53abe115a89 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -74,8 +74,8 @@ private fun HardwareSettingsMenuItem( Icon( imageVector = item.icon, contentDescription = null, - tint = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier.size(24.dp) + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.size(28.dp) ) Column( diff --git a/WooCommerce/src/main/res/values/strings.xml b/WooCommerce/src/main/res/values/strings.xml index b344883f1d38..01245f6bd6ec 100644 --- a/WooCommerce/src/main/res/values/strings.xml +++ b/WooCommerce/src/main/res/values/strings.xml @@ -4341,13 +4341,14 @@ Settings Hardware Manage hardware connections + Store + Store configuration and settings Barcode scanners Configure barcode scanner settings Card Readers Manage card reader connections Barcode Scanner Settings Card Reader Settings - Back Exit POS Get Support Initial barcode scanner setup From 4099fd0d2c96abdfdf1d5c28bb9f3b95df93fb71 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 14:18:50 +0200 Subject: [PATCH 11/15] Fix settings detail pane toolbar layout --- .../details/WooPosSettingsDetailPaneScreen.kt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt index 0c3634d6efe6..4243df0d7e95 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt @@ -135,12 +135,7 @@ private fun DetailPaneToolbar( } } - AnimatedContent( - targetState = title, - transitionSpec = { - fadeIn() togetherWith fadeOut() - }, - label = "title_text_animation", + Box( modifier = Modifier.constrainAs(titleText) { start.linkTo( if (canGoBack) backButton.end else parent.start, @@ -150,9 +145,9 @@ private fun DetailPaneToolbar( centerVerticallyTo(parent) width = Dimension.fillToConstraints } - ) { currentTitle -> + ) { WooPosText( - text = stringResource(currentTitle), + text = stringResource(title), style = WooPosTypography.BodyLarge, color = MaterialTheme.colorScheme.onSurface ) From e157201729f87b7fe1cbad703c9534c9043bf792 Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 12 Aug 2025 14:28:49 +0200 Subject: [PATCH 12/15] Add ripple effect to hardware menu items --- .../details/hardware/WooPosHardwareSettingsScreen.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt index a53abe115a89..4e2c2ebf0b96 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -1,6 +1,7 @@ package com.woocommerce.android.ui.woopos.settings.details.hardware import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -12,9 +13,11 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ripple import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -63,7 +66,10 @@ private fun HardwareSettingsMenuItem( Row( modifier = Modifier .fillMaxWidth() - .clickable { onClick() } + .clickable( + interactionSource = remember { MutableInteractionSource() }, + indication = ripple() + ) { onClick() } .padding( horizontal = WooPosSpacing.Medium.value, vertical = WooPosSpacing.Medium.value From 6550edd5ae8b3eb24592337d5c2d9721879e4efa Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 13 Aug 2025 14:55:31 +0200 Subject: [PATCH 13/15] Use WooPosToolbar instead of the custom solution --- .../composeui/component/WooPosToolbar.kt | 62 +++++++++----- .../details/WooPosSettingsDetailPaneScreen.kt | 82 ++----------------- 2 files changed, 47 insertions(+), 97 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt index b33d311aa052..7162a63ff3a8 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt @@ -1,5 +1,10 @@ package com.woocommerce.android.ui.woopos.common.composeui.component +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.scaleIn +import androidx.compose.animation.scaleOut import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -28,7 +33,9 @@ import com.woocommerce.android.ui.woopos.common.composeui.designsystem.toAdaptiv @Composable fun WooPosToolbar( titleText: String, - onBackClicked: () -> Unit + onBackClicked: (() -> Unit)? = null, + titleStyle: WooPosTypography = WooPosTypography.Heading, + titleFontWeight: FontWeight = FontWeight.Bold ) { ConstraintLayout( modifier = Modifier @@ -37,36 +44,47 @@ fun WooPosToolbar( .height(56.dp), ) { val (backButton, title) = createRefs() - IconButton( - onClick = { onBackClicked() }, - modifier = Modifier - .constrainAs(backButton) { - start.linkTo(parent.start) - bottom.linkTo(parent.bottom) - top.linkTo(parent.top) - } - .size(48.dp) - .padding(start = WooPosSpacing.Small.value.toAdaptivePadding()) + + AnimatedVisibility( + visible = onBackClicked != null, + enter = scaleIn() + fadeIn(), + exit = scaleOut() + fadeOut(), + modifier = Modifier.constrainAs(backButton) { + start.linkTo(parent.start) + bottom.linkTo(parent.bottom) + top.linkTo(parent.top) + } ) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.woopos_toolbar_icon_content_description), - tint = MaterialTheme.colorScheme.onSurface, + IconButton( + onClick = { onBackClicked?.invoke() }, modifier = Modifier - .size(28.dp) - ) + .size(48.dp) + .padding(start = WooPosSpacing.Small.value.toAdaptivePadding()) + ) { + Icon( + imageVector = Icons.AutoMirrored.Filled.ArrowBack, + contentDescription = stringResource(R.string.woopos_toolbar_icon_content_description), + tint = MaterialTheme.colorScheme.onSurface, + modifier = Modifier + .size(28.dp) + ) + } } - val iconTitlePadding = WooPosSpacing.Small.value.toAdaptivePadding() + val startPadding = WooPosSpacing.Small.value.toAdaptivePadding() WooPosText( text = titleText, - style = WooPosTypography.Heading, - color = MaterialTheme.colorScheme.onBackground, - fontWeight = FontWeight.Bold, + style = titleStyle, + color = MaterialTheme.colorScheme.onSurface, + fontWeight = titleFontWeight, maxLines = 1, modifier = Modifier .constrainAs(title) { - start.linkTo(backButton.end, margin = iconTitlePadding) + if (onBackClicked != null) { + start.linkTo(backButton.end, margin = startPadding) + } else { + start.linkTo(parent.start, margin = startPadding) + } bottom.linkTo(parent.bottom) top.linkTo(parent.top) } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt index 4243df0d7e95..fe5facadb97e 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt @@ -1,38 +1,25 @@ package com.woocommerce.android.ui.woopos.settings.details import androidx.activity.compose.BackHandler -import androidx.annotation.StringRes import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.animation.scaleIn -import androidx.compose.animation.scaleOut import androidx.compose.animation.slideInHorizontally import androidx.compose.animation.slideOutHorizontally import androidx.compose.animation.togetherWith import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.ArrowBack -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.constraintlayout.compose.ConstraintLayout -import androidx.constraintlayout.compose.Dimension +import androidx.compose.ui.text.font.FontWeight import com.woocommerce.android.R import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText +import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosToolbar import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography import com.woocommerce.android.ui.woopos.settings.WooPosSettingsDetailDestination @@ -57,10 +44,11 @@ fun WooPosSettingsDetailPaneScreen( .padding(WooPosSpacing.Medium.value) .statusBarsPadding() ) { - DetailPaneToolbar( - canGoBack = state.canGoBack, - title = state.currentDestination.titleRes, - onBack = onBack + WooPosToolbar( + titleText = stringResource(state.currentDestination.titleRes), + onBackClicked = if (state.canGoBack) onBack else null, + titleStyle = WooPosTypography.BodyLarge, + titleFontWeight = FontWeight.Normal ) AnimatedContent( @@ -99,62 +87,6 @@ fun WooPosSettingsDetailPaneScreen( } } -@Composable -private fun DetailPaneToolbar( - canGoBack: Boolean, - @StringRes title: Int, - onBack: () -> Unit -) { - ConstraintLayout( - modifier = Modifier - .fillMaxWidth() - .height(56.dp) - .padding( - top = WooPosSpacing.Small.value, - bottom = WooPosSpacing.Medium.value - ) - ) { - val (backButton, titleText) = createRefs() - - AnimatedVisibility( - visible = canGoBack, - enter = scaleIn() + fadeIn(), - exit = scaleOut() + fadeOut(), - modifier = Modifier.constrainAs(backButton) { - start.linkTo(parent.start) - centerVerticallyTo(parent) - } - ) { - IconButton(onClick = onBack) { - Icon( - imageVector = Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.woopos_toolbar_icon_content_description), - tint = MaterialTheme.colorScheme.onSurface, - modifier = Modifier.size(28.dp) - ) - } - } - - Box( - modifier = Modifier.constrainAs(titleText) { - start.linkTo( - if (canGoBack) backButton.end else parent.start, - margin = if (canGoBack) WooPosSpacing.XSmall.value else 0.dp - ) - end.linkTo(parent.end) - centerVerticallyTo(parent) - width = Dimension.fillToConstraints - } - ) { - WooPosText( - text = stringResource(title), - style = WooPosTypography.BodyLarge, - color = MaterialTheme.colorScheme.onSurface - ) - } - } -} - @Composable private fun BarcodeScannerDetailScreen() { Box( From 8bd41fbe17246becce02bf0a0e9478b001af9cd3 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 13 Aug 2025 15:10:49 +0200 Subject: [PATCH 14/15] Removed redundat riple declaration. Better looking clicking area --- .../common/composeui/component/WooPosToolbar.kt | 3 ++- .../details/WooPosSettingsDetailPaneScreen.kt | 12 +++++++++--- .../details/hardware/WooPosHardwareSettingsScreen.kt | 5 +---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt index 7162a63ff3a8..e138ad25e042 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt @@ -32,13 +32,14 @@ import com.woocommerce.android.ui.woopos.common.composeui.designsystem.toAdaptiv @Composable fun WooPosToolbar( + modifier: Modifier = Modifier, titleText: String, onBackClicked: (() -> Unit)? = null, titleStyle: WooPosTypography = WooPosTypography.Heading, titleFontWeight: FontWeight = FontWeight.Bold ) { ConstraintLayout( - modifier = Modifier + modifier = modifier .fillMaxWidth() .statusBarsPadding() .height(56.dp), diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt index fe5facadb97e..9e9e579fb07a 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/WooPosSettingsDetailPaneScreen.kt @@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -41,10 +40,14 @@ fun WooPosSettingsDetailPaneScreen( Column( modifier = modifier.fillMaxSize() - .padding(WooPosSpacing.Medium.value) - .statusBarsPadding() ) { WooPosToolbar( + modifier = Modifier + .padding( + top = WooPosSpacing.Medium.value, + start = WooPosSpacing.Medium.value, + end = WooPosSpacing.Medium.value, + ), titleText = stringResource(state.currentDestination.titleRes), onBackClicked = if (state.canGoBack) onBack else null, titleStyle = WooPosTypography.BodyLarge, @@ -73,12 +76,15 @@ fun WooPosSettingsDetailPaneScreen( is WooPosSettingsDetailDestination.Hardware.Overview -> { WooPosHardwareSettingsScreen(onNavigate = onNavigate) } + is WooPosSettingsDetailDestination.Hardware.BarcodeScanners -> { BarcodeScannerDetailScreen() } + is WooPosSettingsDetailDestination.Hardware.CardReaders -> { CardReadersDetailScreen() } + is WooPosSettingsDetailDestination.Store.Overview -> { StoreDetailScreen() } diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt index 4e2c2ebf0b96..a465e954f92c 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -70,10 +70,7 @@ private fun HardwareSettingsMenuItem( interactionSource = remember { MutableInteractionSource() }, indication = ripple() ) { onClick() } - .padding( - horizontal = WooPosSpacing.Medium.value, - vertical = WooPosSpacing.Medium.value - ), + .padding(WooPosSpacing.Medium.value), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Start ) { From 60c66f9da307d0d74364733322fcda2e46d91b57 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 13 Aug 2025 15:49:41 +0200 Subject: [PATCH 15/15] Simplify clickable modifier by removing unnecessary interaction source and ripple indication --- .../details/hardware/WooPosHardwareSettingsScreen.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt index a465e954f92c..3b356550680d 100644 --- a/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt +++ b/WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/settings/details/hardware/WooPosHardwareSettingsScreen.kt @@ -1,7 +1,6 @@ package com.woocommerce.android.ui.woopos.settings.details.hardware import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -13,11 +12,9 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ripple import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource @@ -66,10 +63,7 @@ private fun HardwareSettingsMenuItem( Row( modifier = Modifier .fillMaxWidth() - .clickable( - interactionSource = remember { MutableInteractionSource() }, - indication = ripple() - ) { onClick() } + .clickable(onClick = onClick) .padding(WooPosSpacing.Medium.value), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Start