Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ sealed class WooPosSettingsDetailDestination {
}
}

sealed class LocalCatalog : WooPosSettingsDetailDestination() {
data object Overview : LocalCatalog() {
override val titleRes: Int = R.string.woopos_settings_local_catalog_category
override val parentDestination: WooPosSettingsDetailDestination? = null
override val childDestinations: List<WooPosSettingsDetailDestination> = emptyList()
}
}

sealed class Help : WooPosSettingsDetailDestination() {
data object Overview : Help() {
override val titleRes: Int = R.string.woopos_settings_help_category
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.woocommerce.android.ui.woopos.settings.categories.WooPosSettingsCateg
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent.Event.HardwareTapped
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent.Event.HelpTapped
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent.Event.LocalCatalogTapped
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent.Event.SettingsClosed
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent.Event.SettingsOpened
import com.woocommerce.android.ui.woopos.util.analytics.WooPosAnalyticsEvent.Event.StoreDetailsTapped
Expand Down Expand Up @@ -38,6 +39,7 @@ class WooPosSettingsViewModel @Inject constructor(
private fun trackCategorySelection(category: WooPosSettingsCategory) {
val event = when (category) {
WooPosSettingsCategory.STORE -> StoreDetailsTapped
WooPosSettingsCategory.LOCAL_CATALOG -> LocalCatalogTapped
WooPosSettingsCategory.HARDWARE -> HardwareTapped
WooPosSettingsCategory.HELP -> HelpTapped
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Help
import androidx.compose.material.icons.filled.Hardware
import androidx.compose.material.icons.filled.Inventory
import androidx.compose.material.icons.filled.Store
import androidx.compose.ui.graphics.vector.ImageVector
import com.woocommerce.android.R
Expand All @@ -22,6 +23,12 @@ enum class WooPosSettingsCategory(
Icons.Default.Store,
WooPosSettingsDetailDestination.Store.Overview
),
LOCAL_CATALOG(
R.string.woopos_settings_local_catalog_category,
R.string.woopos_settings_local_catalog_category_subtitle,
Icons.Default.Inventory,
WooPosSettingsDetailDestination.LocalCatalog.Overview
),
HARDWARE(
R.string.woopos_settings_hardware_category,
R.string.woopos_settings_hardware_category_subtitle,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
package com.woocommerce.android.ui.woopos.settings.categories

import android.content.Context
import androidx.lifecycle.ViewModel
import com.woocommerce.android.util.FeatureFlag
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
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())
class WooPosSettingsCategoriesViewModel @Inject constructor(
@ApplicationContext private val context: Context
) : ViewModel() {
private val _state = MutableStateFlow(createInitialState())
val state: StateFlow<WooPosSettingsCategoriesState> = _state.asStateFlow()
private fun createInitialState(): WooPosSettingsCategoriesState {
val allCategories = WooPosSettingsCategory.entries
val visibleCategories = if (FeatureFlag.WOO_POS_LOCAL_CATALOG_M1.isEnabled(context)) {
allCategories
} else {
allCategories.filter { it != WooPosSettingsCategory.LOCAL_CATALOG }
}
return WooPosSettingsCategoriesState(categories = visibleCategories)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import com.woocommerce.android.ui.woopos.settings.details.hardware.WooPosHardwar
import com.woocommerce.android.ui.woopos.settings.details.hardware.barcodescanner.WooPosSettingsHardwareBarcodeScannerScreen
import com.woocommerce.android.ui.woopos.settings.details.hardware.cardreader.WooPosSettingsHardwareCardReaderScreen
import com.woocommerce.android.ui.woopos.settings.details.help.WooPosHelpDetailScreen
import com.woocommerce.android.ui.woopos.settings.details.localcatalog.WooPosSettingsLocalCatalogScreen
import com.woocommerce.android.ui.woopos.settings.details.store.WooPosSettingsStoreScreen

@Composable
Expand Down Expand Up @@ -93,6 +94,10 @@ fun WooPosSettingsDetailPaneScreen(
WooPosSettingsStoreScreen()
}

is WooPosSettingsDetailDestination.LocalCatalog.Overview -> {
WooPosSettingsLocalCatalogScreen()
}

is WooPosSettingsDetailDestination.Help.Overview -> {
WooPosHelpDetailScreen(onShowProductInfoDialog = onShowProductInfoDialog)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
package com.woocommerce.android.ui.woopos.settings.details.localcatalog

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
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.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Switch
import androidx.compose.material3.SwitchDefaults
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.draw.clip
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.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.WooPosButton
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosButtonState
import com.woocommerce.android.ui.woopos.common.composeui.component.WooPosShimmerBox
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.WooPosTheme
import com.woocommerce.android.ui.woopos.common.composeui.designsystem.WooPosTypography

@Composable
fun WooPosSettingsLocalCatalogScreen(
modifier: Modifier = Modifier,
viewModel: WooPosSettingsLocalCatalogViewModel = hiltViewModel()
) {
val state by viewModel.state.collectAsState()

WooPosSettingsLocalCatalogScreen(
state = state,
onToggleCellularData = viewModel::toggleCellularDataUpdate,
onRefreshCatalog = viewModel::runFullCatalogSync,
modifier = modifier
)
}

@Composable
private fun WooPosSettingsLocalCatalogScreen(
state: WooPosSettingsLocalCatalogState,
onToggleCellularData: () -> Unit,
onRefreshCatalog: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
modifier = modifier
.fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(WooPosSpacing.Medium.value)
) {
CatalogStatusSection(
catalogStatus = state.catalogStatus,
isLoading = state.isLoading
)

Spacer(modifier = Modifier.height(WooPosSpacing.Large.value))

SettingsSection(
allowCellularDataUpdate = state.allowCellularDataUpdate,
onToggleCellularData = onToggleCellularData,
isLoading = state.isLoading
)

Spacer(modifier = Modifier.height(WooPosSpacing.Large.value))

RefreshSection(
onRefreshCatalog = onRefreshCatalog,
isRefreshing = state.isRefreshing
)
}
}

@Composable
private fun CatalogStatusSection(
catalogStatus: CatalogStatus?,
isLoading: Boolean
) {
Column(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(WooPosCornerRadius.Large.value))
.background(MaterialTheme.colorScheme.surfaceContainerHigh)
.padding(WooPosSpacing.Medium.value)
) {
SectionTitle(stringResource(R.string.woopos_settings_local_catalog_status))

Spacer(modifier = Modifier.height(WooPosSpacing.Medium.value))

if (isLoading || catalogStatus == null) {
StatusRow(
label = stringResource(R.string.woopos_settings_local_catalog_size),
value = null,
isLoading = true
)
StatusRow(
label = stringResource(R.string.woopos_settings_local_catalog_last_update),
value = null,
isLoading = true
)
StatusRow(
label = stringResource(R.string.woopos_settings_local_catalog_last_full_update),
value = null,
isLoading = true
)
} else {
StatusRow(
label = stringResource(R.string.woopos_settings_local_catalog_size),
value = catalogStatus.catalogSize,
isLoading = false
)
StatusRow(
label = stringResource(R.string.woopos_settings_local_catalog_last_update),
value = catalogStatus.lastUpdate,
isLoading = false
)
StatusRow(
label = stringResource(R.string.woopos_settings_local_catalog_last_full_update),
value = catalogStatus.lastFullUpdate,
isLoading = false
)
}
}
}

@Composable
private fun SettingsSection(
allowCellularDataUpdate: Boolean,
onToggleCellularData: () -> Unit,
isLoading: Boolean
) {
Column(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(WooPosCornerRadius.Large.value))
.background(MaterialTheme.colorScheme.surfaceContainerHigh)
.padding(WooPosSpacing.Medium.value)
) {
SectionTitle(stringResource(R.string.woopos_settings_local_catalog_settings))

Spacer(modifier = Modifier.height(WooPosSpacing.Medium.value))

Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier.weight(1f)
) {
WooPosText(
text = stringResource(R.string.woopos_settings_local_catalog_cellular_data),
style = WooPosTypography.BodyLarge,
color = MaterialTheme.colorScheme.onSurface
)
WooPosText(
text = stringResource(R.string.woopos_settings_local_catalog_cellular_data_subtitle),
style = WooPosTypography.BodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(top = WooPosSpacing.XSmall.value)
)
}

Switch(
checked = allowCellularDataUpdate,
onCheckedChange = { onToggleCellularData() },
enabled = !isLoading,
colors = SwitchDefaults.colors(
checkedThumbColor = MaterialTheme.colorScheme.primary,
checkedTrackColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.5f)
)
)
}
}
}

@Composable
private fun RefreshSection(
onRefreshCatalog: () -> Unit,
isRefreshing: Boolean
) {
Column(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(WooPosCornerRadius.Large.value))
.background(MaterialTheme.colorScheme.surfaceContainerHigh)
.padding(WooPosSpacing.Medium.value)
) {
SectionTitle(stringResource(R.string.woopos_settings_local_catalog_actions))

Spacer(modifier = Modifier.height(WooPosSpacing.Medium.value))

WooPosText(
text = stringResource(R.string.woopos_settings_local_catalog_refresh_description),
style = WooPosTypography.BodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(bottom = WooPosSpacing.Medium.value)
)

WooPosButton(
modifier = Modifier.fillMaxWidth(),
onClick = onRefreshCatalog,
state = if (isRefreshing) WooPosButtonState.LOADING else WooPosButtonState.ENABLED,
text = stringResource(R.string.woopos_settings_local_catalog_refresh_button)
)
}
}

@Composable
private fun StatusRow(
label: String,
value: String?,
isLoading: Boolean
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = WooPosSpacing.Small.value),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
WooPosText(
text = label,
style = WooPosTypography.BodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)

if (isLoading) {
WooPosShimmerBox(
modifier = Modifier
.width(100.dp)
.height(20.dp),
)
} else {
WooPosText(
text = value ?: "-",
style = WooPosTypography.BodyMedium,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurface
)
}
}
}

@Composable
private fun SectionTitle(title: String) {
WooPosText(
text = title,
style = WooPosTypography.BodyXLarge,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.onSurface
)
}

@WooPosPreview
@Composable
fun WooPosSettingsLocalCatalogScreenPreview() {
WooPosTheme {
WooPosSettingsLocalCatalogScreen(
state = WooPosSettingsLocalCatalogState(
catalogStatus = CatalogStatus(
catalogSize = "12.5 MB",
lastUpdate = "2 hours ago",
lastFullUpdate = "Yesterday at 3:45 PM"
),
allowCellularDataUpdate = true,
isLoading = false,
isRefreshing = false
),
onToggleCellularData = {},
onRefreshCatalog = {}
)
}
}
Loading