Skip to content

Commit 261ca27

Browse files
authored
Merge pull request #14459 from woocommerce/woomob-1023-woo-possettings-2-pane-layout-based-on-the-wireframes
[WOOMOB-1023][Woo POS][Settings] Implement 2-pane layout with Android-style UI design
2 parents 2317d23 + 60c66f9 commit 261ca27

File tree

12 files changed

+644
-34
lines changed

12 files changed

+644
-34
lines changed

WooCommerce/src/main/kotlin/com/woocommerce/android/ui/woopos/common/composeui/component/WooPosToolbar.kt

Lines changed: 42 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.woocommerce.android.ui.woopos.common.composeui.component
22

3+
import androidx.compose.animation.AnimatedVisibility
4+
import androidx.compose.animation.fadeIn
5+
import androidx.compose.animation.fadeOut
6+
import androidx.compose.animation.scaleIn
7+
import androidx.compose.animation.scaleOut
38
import androidx.compose.foundation.layout.Column
49
import androidx.compose.foundation.layout.Spacer
510
import androidx.compose.foundation.layout.fillMaxWidth
@@ -27,46 +32,60 @@ import com.woocommerce.android.ui.woopos.common.composeui.designsystem.toAdaptiv
2732

2833
@Composable
2934
fun WooPosToolbar(
35+
modifier: Modifier = Modifier,
3036
titleText: String,
31-
onBackClicked: () -> Unit
37+
onBackClicked: (() -> Unit)? = null,
38+
titleStyle: WooPosTypography = WooPosTypography.Heading,
39+
titleFontWeight: FontWeight = FontWeight.Bold
3240
) {
3341
ConstraintLayout(
34-
modifier = Modifier
42+
modifier = modifier
3543
.fillMaxWidth()
3644
.statusBarsPadding()
3745
.height(56.dp),
3846
) {
3947
val (backButton, title) = createRefs()
40-
IconButton(
41-
onClick = { onBackClicked() },
42-
modifier = Modifier
43-
.constrainAs(backButton) {
44-
start.linkTo(parent.start)
45-
bottom.linkTo(parent.bottom)
46-
top.linkTo(parent.top)
47-
}
48-
.size(48.dp)
49-
.padding(start = WooPosSpacing.Small.value.toAdaptivePadding())
48+
49+
AnimatedVisibility(
50+
visible = onBackClicked != null,
51+
enter = scaleIn() + fadeIn(),
52+
exit = scaleOut() + fadeOut(),
53+
modifier = Modifier.constrainAs(backButton) {
54+
start.linkTo(parent.start)
55+
bottom.linkTo(parent.bottom)
56+
top.linkTo(parent.top)
57+
}
5058
) {
51-
Icon(
52-
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
53-
contentDescription = stringResource(R.string.woopos_toolbar_icon_content_description),
54-
tint = MaterialTheme.colorScheme.onSurface,
59+
IconButton(
60+
onClick = { onBackClicked?.invoke() },
5561
modifier = Modifier
56-
.size(28.dp)
57-
)
62+
.size(48.dp)
63+
.padding(start = WooPosSpacing.Small.value.toAdaptivePadding())
64+
) {
65+
Icon(
66+
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
67+
contentDescription = stringResource(R.string.woopos_toolbar_icon_content_description),
68+
tint = MaterialTheme.colorScheme.onSurface,
69+
modifier = Modifier
70+
.size(28.dp)
71+
)
72+
}
5873
}
5974

60-
val iconTitlePadding = WooPosSpacing.Small.value.toAdaptivePadding()
75+
val startPadding = WooPosSpacing.Small.value.toAdaptivePadding()
6176
WooPosText(
6277
text = titleText,
63-
style = WooPosTypography.Heading,
64-
color = MaterialTheme.colorScheme.onBackground,
65-
fontWeight = FontWeight.Bold,
78+
style = titleStyle,
79+
color = MaterialTheme.colorScheme.onSurface,
80+
fontWeight = titleFontWeight,
6681
maxLines = 1,
6782
modifier = Modifier
6883
.constrainAs(title) {
69-
start.linkTo(backButton.end, margin = iconTitlePadding)
84+
if (onBackClicked != null) {
85+
start.linkTo(backButton.end, margin = startPadding)
86+
} else {
87+
start.linkTo(parent.start, margin = startPadding)
88+
}
7089
bottom.linkTo(parent.bottom)
7190
top.linkTo(parent.top)
7291
}
Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,95 @@
11
package com.woocommerce.android.ui.woopos.settings
22

3-
import androidx.compose.foundation.layout.Box
3+
import androidx.activity.compose.BackHandler
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Row
47
import androidx.compose.foundation.layout.fillMaxSize
8+
import androidx.compose.foundation.layout.fillMaxWidth
9+
import androidx.compose.foundation.layout.padding
10+
import androidx.compose.foundation.layout.statusBarsPadding
11+
import androidx.compose.material3.MaterialTheme
512
import androidx.compose.runtime.Composable
6-
import androidx.compose.ui.Alignment
13+
import androidx.compose.runtime.collectAsState
14+
import androidx.compose.runtime.getValue
715
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.res.stringResource
17+
import androidx.compose.ui.text.font.FontWeight
818
import androidx.hilt.navigation.compose.hiltViewModel
19+
import com.woocommerce.android.R
20+
import com.woocommerce.android.ui.woopos.common.composeui.WooPosPreview
921
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosText
22+
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosSpacing
23+
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTheme
1024
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography
1125
import com.woocommerce.android.ui.woopos.root.navigation.WooPosNavigationEvent
26+
import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategoriesPaneScreen
27+
import com.woocommerce.android.ui.woopos.settings.details.WooPosSettingsDetailPaneScreen
1228

1329
@Composable
14-
@Suppress("UnusedParameter")
1530
fun WooPosSettingsScreen(
1631
onNavigationEvent: (WooPosNavigationEvent) -> Unit,
17-
viewModel: WooPosSettingsViewModel = hiltViewModel()
1832
) {
19-
Box(
20-
modifier = Modifier.fillMaxSize(),
21-
contentAlignment = Alignment.Center
33+
val containerViewModel: WooPosSettingsViewModel = hiltViewModel()
34+
val navigationState by containerViewModel.navigationState.collectAsState()
35+
36+
BackHandler { onNavigationEvent(WooPosNavigationEvent.GoBack) }
37+
38+
Row(
39+
modifier = Modifier.fillMaxSize()
2240
) {
23-
WooPosText(
24-
text = "Settings Screen",
25-
style = WooPosTypography.Heading,
41+
Column(
42+
modifier = Modifier
43+
.weight(0.3f)
44+
.background(MaterialTheme.colorScheme.surface)
45+
) {
46+
SettingsCategoriesToolbar(
47+
titleText = stringResource(R.string.woopos_settings_title)
48+
)
49+
50+
WooPosSettingsCategoriesPaneScreen(
51+
selectedCategory = navigationState.selectedCategory,
52+
onCategorySelected = containerViewModel::onCategorySelected,
53+
modifier = Modifier.fillMaxSize()
54+
)
55+
}
56+
57+
WooPosSettingsDetailPaneScreen(
58+
state = navigationState,
59+
onNavigate = containerViewModel::navigateToDetail,
60+
onBack = containerViewModel::navigateBack,
61+
modifier = Modifier
62+
.weight(0.7f)
63+
.background(MaterialTheme.colorScheme.surfaceContainerLow)
64+
)
65+
}
66+
}
67+
68+
@Composable
69+
private fun SettingsCategoriesToolbar(
70+
titleText: String
71+
) {
72+
WooPosText(
73+
text = titleText,
74+
style = WooPosTypography.Heading,
75+
fontWeight = FontWeight.Bold,
76+
maxLines = 1,
77+
modifier = Modifier
78+
.fillMaxWidth()
79+
.statusBarsPadding()
80+
.padding(
81+
horizontal = WooPosSpacing.Medium.value,
82+
vertical = WooPosSpacing.Medium.value
83+
)
84+
)
85+
}
86+
87+
@WooPosPreview
88+
@Composable
89+
fun WooPosSettingsScreenPreview() {
90+
WooPosTheme {
91+
WooPosSettingsScreen(
92+
onNavigationEvent = {}
2693
)
2794
}
2895
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.woocommerce.android.ui.woopos.settings
2+
3+
import androidx.annotation.StringRes
4+
import com.woocommerce.android.R
5+
import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategory
6+
7+
data class WooPosSettingsState(
8+
val selectedCategory: WooPosSettingsCategory = WooPosSettingsCategory.HARDWARE,
9+
val currentDestination: WooPosSettingsDetailDestination = selectedCategory.rootDestination
10+
) {
11+
val canGoBack: Boolean
12+
get() = currentDestination.parentDestination != null
13+
}
14+
15+
sealed class WooPosSettingsDetailDestination {
16+
@get:StringRes
17+
abstract val titleRes: Int
18+
abstract val parentDestination: WooPosSettingsDetailDestination?
19+
abstract val childDestinations: List<WooPosSettingsDetailDestination>
20+
21+
sealed class Hardware : WooPosSettingsDetailDestination() {
22+
data object Overview : Hardware() {
23+
override val titleRes: Int = R.string.woopos_settings_hardware_category
24+
override val parentDestination: WooPosSettingsDetailDestination? = null
25+
override val childDestinations: List<Hardware> = listOf(BarcodeScanners, CardReaders)
26+
}
27+
28+
data object BarcodeScanners : Hardware() {
29+
override val titleRes: Int = R.string.woopos_settings_hardware_barcode_scanners
30+
override val parentDestination: Hardware = Overview
31+
override val childDestinations: List<WooPosSettingsDetailDestination> = emptyList()
32+
}
33+
34+
data object CardReaders : Hardware() {
35+
override val titleRes: Int = R.string.woopos_settings_hardware_card_readers
36+
override val parentDestination: Hardware = Overview
37+
override val childDestinations: List<WooPosSettingsDetailDestination> = emptyList()
38+
}
39+
}
40+
41+
sealed class Store : WooPosSettingsDetailDestination() {
42+
data object Overview : Store() {
43+
override val titleRes: Int = R.string.woopos_settings_store_category
44+
override val parentDestination: WooPosSettingsDetailDestination? = null
45+
override val childDestinations: List<WooPosSettingsDetailDestination> = emptyList()
46+
}
47+
}
48+
}
Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,42 @@
11
package com.woocommerce.android.ui.woopos.settings
22

33
import androidx.lifecycle.ViewModel
4+
import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCategory
45
import dagger.hilt.android.lifecycle.HiltViewModel
6+
import kotlinx.coroutines.flow.MutableStateFlow
7+
import kotlinx.coroutines.flow.StateFlow
8+
import kotlinx.coroutines.flow.asStateFlow
9+
import kotlinx.coroutines.flow.update
510
import javax.inject.Inject
611

712
@HiltViewModel
8-
class WooPosSettingsViewModel @Inject constructor() : ViewModel()
13+
class WooPosSettingsViewModel @Inject constructor() : ViewModel() {
14+
private val _navigationState = MutableStateFlow(WooPosSettingsState())
15+
val navigationState: StateFlow<WooPosSettingsState> = _navigationState.asStateFlow()
16+
17+
fun onCategorySelected(category: WooPosSettingsCategory) {
18+
_navigationState.update { currentState ->
19+
currentState.copy(
20+
selectedCategory = category,
21+
currentDestination = category.rootDestination
22+
)
23+
}
24+
}
25+
26+
fun navigateToDetail(destination: WooPosSettingsDetailDestination) {
27+
_navigationState.update { currentState ->
28+
currentState.copy(currentDestination = destination)
29+
}
30+
}
31+
32+
fun navigateBack() {
33+
_navigationState.update { currentState ->
34+
val parentDestination = currentState.currentDestination.parentDestination
35+
if (parentDestination != null) {
36+
currentState.copy(currentDestination = parentDestination)
37+
} else {
38+
currentState
39+
}
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)