From ea52015ea83b879bfb1f42e2111504cdb0614ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Miguel=20Rubio?= Date: Wed, 11 Jan 2023 11:45:16 +0100 Subject: [PATCH] Create UI states (#41) * SettingsUiState.kt * create ButtonUiState.kt * use reviewButtonUiState on ManageStockViewModel.kt * Remove toolbar title property * Remove local properties on BackdropComponent.kt * ktlintCheck * collect by viewmodels * ktlintCheck * Add transaction date to SettingsUiState.kt * collect settingsUiState in MainContent.kt * ktlintCheck * Mobe fromLabel and deliver label to SettingsUiState.kt * Move fromLabel and deliver label to SettingsUiState.kt * Remove hardcoded programUid * remove items from cache when cleared * remove activity_manage_stock.xml Co-authored-by: andresmr --- app/src/main/assets/paperwork.json | 2 +- .../android/rtsm/ui/home/HomeActivity.kt | 8 +- .../android/rtsm/ui/home/HomeViewModel.kt | 148 ++++---------- .../rtsm/ui/home/model/ButtonUiState.kt | 16 ++ .../rtsm/ui/home/model/SettingsUiState.kt | 47 +++++ .../rtsm/ui/home/screens/HomeScreen.kt | 84 +++----- .../screens/components/BackdropComponent.kt | 38 ++-- .../screens/components/DropdownComponent.kt | 39 ++-- .../screens/components/FilterComponents.kt | 21 +- .../ui/home/screens/components/MainContent.kt | 38 ++-- .../rtsm/ui/managestock/ManageStockAdapter.kt | 147 ------------- .../ui/managestock/ManageStockViewModel.kt | 43 +++- .../components/ManageStockTable.kt | 14 +- .../layout-w600dp/activity_manage_stock.xml | 193 ------------------ .../layout-w840dp/activity_manage_stock.xml | 193 ------------------ .../main/res/layout/activity_manage_stock.xml | 191 ----------------- .../rtsm/viewmodels/HomeViewModelUnitTest.kt | 104 ++-------- 17 files changed, 233 insertions(+), 1093 deletions(-) create mode 100644 stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/model/ButtonUiState.kt create mode 100644 stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/model/SettingsUiState.kt delete mode 100644 stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockAdapter.kt delete mode 100644 stock-managment/src/main/res/layout-w600dp/activity_manage_stock.xml delete mode 100644 stock-managment/src/main/res/layout-w840dp/activity_manage_stock.xml delete mode 100644 stock-managment/src/main/res/layout/activity_manage_stock.xml diff --git a/app/src/main/assets/paperwork.json b/app/src/main/assets/paperwork.json index 816885c2b5..69c253b66f 100644 --- a/app/src/main/assets/paperwork.json +++ b/app/src/main/assets/paperwork.json @@ -1 +1 @@ -{"buildTime":"2022-12-08 10:37","gitSha":"7a66f01fe"} \ No newline at end of file +{"buildTime":"2023-01-09 10:19","gitSha":"6885dc400"} \ No newline at end of file diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/HomeActivity.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/HomeActivity.kt index 4a4efb2a43..d2e2eeae3a 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/HomeActivity.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/HomeActivity.kt @@ -65,7 +65,8 @@ class HomeActivity : AppCompatActivity(), OnOrgUnitSelectionFinished { ?.let { manageStockViewModel.setConfig(it) } setContent { - updateTheme(viewModel.transactionType.collectAsState().value) + val settingsUiState by viewModel.settingsUiState.collectAsState() + updateTheme(settingsUiState.transactionType) MdcTheme { Surface( modifier = Modifier.fillMaxSize(), @@ -77,14 +78,13 @@ class HomeActivity : AppCompatActivity(), OnOrgUnitSelectionFinished { manageStockViewModel, Color(colorResource(themeColor).toArgb()), supportFragmentManager, - this@HomeActivity, barcodeLauncher, ::navigateToReviewStock ) { scope, scaffold -> synchronizeData( scope, scaffold, - viewModel.config.program + settingsUiState.programUid ) } } @@ -198,8 +198,6 @@ class HomeActivity : AppCompatActivity(), OnOrgUnitSelectionFinished { override fun onSelectionFinished(selectedOrgUnits: List) { viewModel.setFacility(selectedOrgUnits[0]) - viewModel.fromFacilitiesLabel(selectedOrgUnits[0].displayName().toString()) - viewModel.setSelectedText(selectedOrgUnits[0].displayName().toString()) setOrgUnitFilters(selectedOrgUnits) } diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/HomeViewModel.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/HomeViewModel.kt index a4bdfabeff..bc4c282a49 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/HomeViewModel.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/HomeViewModel.kt @@ -5,13 +5,11 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.SavedStateHandle import dagger.hilt.android.lifecycle.HiltViewModel import io.reactivex.disposables.CompositeDisposable -import java.time.Instant -import java.time.LocalDateTime -import java.time.ZoneId import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update import org.dhis2.android.rtsm.R import org.dhis2.android.rtsm.commons.Constants.INTENT_EXTRA_APP_CONFIG import org.dhis2.android.rtsm.data.AppConfig @@ -24,8 +22,8 @@ import org.dhis2.android.rtsm.services.MetadataManager import org.dhis2.android.rtsm.services.preferences.PreferenceProvider import org.dhis2.android.rtsm.services.scheduler.BaseSchedulerProvider import org.dhis2.android.rtsm.ui.base.BaseViewModel +import org.dhis2.android.rtsm.ui.home.model.SettingsUiState import org.dhis2.android.rtsm.utils.ParcelUtils -import org.dhis2.android.rtsm.utils.UIText import org.dhis2.android.rtsm.utils.humanReadableDate import org.hisp.dhis.android.core.option.Option import org.hisp.dhis.android.core.organisationunit.OrganisationUnit @@ -39,42 +37,13 @@ class HomeViewModel @Inject constructor( savedState: SavedStateHandle ) : BaseViewModel(preferenceProvider, schedulerProvider) { - val config: AppConfig = savedState.get(INTENT_EXTRA_APP_CONFIG) + private val config: AppConfig = savedState.get(INTENT_EXTRA_APP_CONFIG) ?: throw InitializationException("Some configuration parameters are missing") - private val _transactionType = MutableStateFlow(TransactionType.DISTRIBUTION) - val transactionType: StateFlow get() = _transactionType - - private val _isDistribution = MutableStateFlow(true) - val isDistribution: StateFlow - get() = _isDistribution - - private val _hasFacilitySelected = MutableStateFlow(false) - val hasFacilitySelected: StateFlow - get() = _hasFacilitySelected - - private val _hasDestinationSelected = MutableStateFlow(false) - val hasDestinationSelected: StateFlow - get() = _hasDestinationSelected - - private val _facility = MutableStateFlow(null) - val facility: StateFlow - get() = _facility - private val _scanText = MutableStateFlow("") val scanText = _scanText.asStateFlow() - private val _oldSelectedFacility = MutableStateFlow("") - val oldSelectedFacility = _oldSelectedFacility.asStateFlow() - - private val _transactionDate = MutableStateFlow(LocalDateTime.now()) - val transactionDate: StateFlow - get() = _transactionDate - - private val _destination = MutableStateFlow(null) - val destination: StateFlow - get() = _destination - + // TODO("IS this duplicated: facilities and org units list") private val _facilities = MutableStateFlow>>(OperationState.Loading) val facilities: StateFlow>> @@ -90,18 +59,8 @@ class HomeViewModel @Inject constructor( val destinationsList: StateFlow>> get() = _destinations - // Toolbar section variables - private val _toolbarTitle = MutableStateFlow(TransactionType.DISTRIBUTION) - val toolbarTitle: StateFlow get() = _toolbarTitle - - private val _fromFacility = MutableStateFlow(UIText.StringRes(R.string.from_facility)) - val fromFacility: StateFlow get() = _fromFacility - - private val _deliveryTo = MutableStateFlow(UIText.StringRes(R.string.to_facility)) - val deliveryTo: StateFlow get() = _deliveryTo - - private val _orgUnitName = MutableStateFlow("") - val orgUnitName: StateFlow get() = _orgUnitName + private val _settingsUiSate = MutableStateFlow(SettingsUiState(programUid = config.program)) + val settingsUiState: StateFlow = _settingsUiSate init { loadFacilities() @@ -135,7 +94,11 @@ class HomeViewModel @Inject constructor( _facilities.value = (OperationState.Success(it)) _orgUnitList.value = it - if (it.size == 1) _facility.value = (it[0]) + if (it.size == 1) { + _settingsUiSate.update { currentUiState -> + currentUiState.copy(facility = it[0]) + } + } }, { it.printStackTrace() @@ -146,40 +109,42 @@ class HomeViewModel @Inject constructor( } fun selectTransaction(type: TransactionType) { - _transactionType.value = type - _isDistribution.value = type == TransactionType.DISTRIBUTION + _settingsUiSate.update { currentUiState -> + currentUiState.copy(transactionType = type) + } // Distributed to cannot only be set for DISTRIBUTION, // so ensure you clear it for others if it has been set if (type != TransactionType.DISTRIBUTION) { - _destination.value = null - _deliveryTo.value = null - } else { - _deliveryTo.value = UIText.StringRes(R.string.to_facility) + _settingsUiSate.update { currentUiState -> + currentUiState.copy(destination = null) + } } } fun setFacility(facility: OrganisationUnit) { - _facility.value = facility + _settingsUiSate.update { currentUiState -> + currentUiState.copy(facility = facility) + } } fun setDestination(destination: Option?) { - if (!isDistribution.value) { + if (settingsUiState.value.transactionType != TransactionType.DISTRIBUTION) { throw UnsupportedOperationException( "Cannot set 'distributed to' for non-distribution transactions" ) } - _destination.value = destination + _settingsUiSate.update { currentUiState -> + currentUiState.copy(destination = destination) + } } fun checkForFieldErrors(): Int? { - return if (_facility.value == null) { + return if (settingsUiState.value.facility == null) { R.string.mandatory_facility_selection - } else if (_transactionDate.value == null) { - R.string.mandatory_transaction_date_selection - } else if (_transactionType.value == TransactionType.DISTRIBUTION && - _destination.value == null + } else if (settingsUiState.value.transactionType == TransactionType.DISTRIBUTION && + settingsUiState.value.destination == null ) { R.string.mandatory_distributed_to_selection } else { @@ -188,66 +153,25 @@ class HomeViewModel @Inject constructor( } fun getData(): Transaction { - if (facility.value == null) { + if (settingsUiState.value.facility == null) { throw UserIntentParcelCreationException( "Unable to create parcel with empty facility" ) } return Transaction( - transactionType.value, - ParcelUtils.facilityToIdentifiableModelParcel(facility.value!!), - transactionDate.value.humanReadableDate(), - destination.value?.let { ParcelUtils.distributedTo_ToIdentifiableModelParcel(it) } - ) - } - - fun setTransactionDate(epoch: Long) { - _transactionDate.value = Instant.ofEpochMilli(epoch) - .atZone(ZoneId.systemDefault()) - .toLocalDateTime() - } - - fun setToolbarTitle(transactionType: TransactionType) { - _toolbarTitle.value = transactionType - } - - fun fromFacilitiesLabel(from: String) { - when (transactionType.value) { - TransactionType.DISTRIBUTION -> { - _fromFacility.value = UIText.StringRes(R.string.subtitle, from) - } - TransactionType.DISCARD -> { - _fromFacility.value = UIText.StringRes(R.string.subtitle, from) - } - TransactionType.CORRECTION -> { - _fromFacility.value = UIText.StringRes(R.string.subtitle, from) + settingsUiState.value.transactionType, + ParcelUtils.facilityToIdentifiableModelParcel(settingsUiState.value.facility!!), + settingsUiState.value.transactionDate.humanReadableDate(), + settingsUiState.value.destination?.let { + ParcelUtils.distributedTo_ToIdentifiableModelParcel( + it + ) } - } - } - - fun deliveryToLabel(to: String) { - if (transactionType.value == TransactionType.DISTRIBUTION) { - _deliveryTo.value = UIText.StringRes(R.string.subtitle, to) - } - } - - fun setSelectedText(text: String) { - _orgUnitName.value = text + ) } fun setScannedText(text: String) { _scanText.value = text } - - fun setFacilitySelected(status: Boolean) { - _hasFacilitySelected.value = status - } - - fun setDestinationSelected(status: Boolean) { - _hasDestinationSelected.value = status - } - fun setOldSelectedFacility(text: String) { - _oldSelectedFacility.value = text - } } diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/model/ButtonUiState.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/model/ButtonUiState.kt new file mode 100644 index 0000000000..d1152cf913 --- /dev/null +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/model/ButtonUiState.kt @@ -0,0 +1,16 @@ +package org.dhis2.android.rtsm.ui.home.model + +import org.dhis2.android.rtsm.R +import org.dhis2.android.rtsm.ui.home.model.ButtonVisibilityState.HIDDEN + +data class ButtonUiState( + val text: Int = R.string.review, + val icon: Int = R.drawable.proceed_icon, + val visibility: ButtonVisibilityState = HIDDEN +) + +enum class ButtonVisibilityState { + HIDDEN, + DISABLED, + ENABLED +} diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/model/SettingsUiState.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/model/SettingsUiState.kt new file mode 100644 index 0000000000..850c638e8a --- /dev/null +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/model/SettingsUiState.kt @@ -0,0 +1,47 @@ +package org.dhis2.android.rtsm.ui.home.model + +import java.time.LocalDateTime +import org.dhis2.android.rtsm.R +import org.dhis2.android.rtsm.data.TransactionType +import org.dhis2.android.rtsm.data.TransactionType.CORRECTION +import org.dhis2.android.rtsm.data.TransactionType.DISCARD +import org.dhis2.android.rtsm.data.TransactionType.DISTRIBUTION +import org.dhis2.android.rtsm.utils.UIText +import org.hisp.dhis.android.core.option.Option +import org.hisp.dhis.android.core.organisationunit.OrganisationUnit + +data class SettingsUiState( + val programUid: String, + val transactionType: TransactionType = DISTRIBUTION, + val facility: OrganisationUnit? = null, + val destination: Option? = null, + val transactionDate: LocalDateTime = LocalDateTime.now() +) { + fun hasFacilitySelected() = facility != null + fun hasDestinationSelected() = destination != null + fun fromFacilitiesLabel(): UIText = facility?.let { + val orgUnitName = it.displayName().toString() + return when (transactionType) { + DISTRIBUTION -> { + UIText.StringRes(R.string.subtitle, orgUnitName) + } + DISCARD -> { + UIText.StringRes(R.string.subtitle, orgUnitName) + } + CORRECTION -> { + UIText.StringRes(R.string.subtitle, orgUnitName) + } + } + } ?: UIText.StringRes(R.string.from_facility) + + fun deliverToLabel(): UIText? = when (transactionType) { + DISTRIBUTION -> destination?.let { + UIText.StringRes(R.string.subtitle, it.displayName().toString()) + } ?: UIText.StringRes(R.string.to_facility) + else -> null + } + + fun facilityName() = facility?.let { + it.displayName().toString() + } ?: "" +} diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/HomeScreen.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/HomeScreen.kt index 2396a23562..100f3a0ea5 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/HomeScreen.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/HomeScreen.kt @@ -23,10 +23,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow import androidx.compose.ui.graphics.Color @@ -39,9 +36,8 @@ import androidx.lifecycle.viewmodel.compose.viewModel import com.journeyapps.barcodescanner.ScanOptions import kotlinx.coroutines.CoroutineScope import org.dhis2.android.rtsm.R -import org.dhis2.android.rtsm.data.TransactionType -import org.dhis2.android.rtsm.ui.home.HomeActivity import org.dhis2.android.rtsm.ui.home.HomeViewModel +import org.dhis2.android.rtsm.ui.home.model.ButtonVisibilityState import org.dhis2.android.rtsm.ui.home.screens.components.Backdrop import org.dhis2.android.rtsm.ui.managestock.ManageStockViewModel @@ -53,27 +49,29 @@ fun HomeScreen( manageStockViewModel: ManageStockViewModel = viewModel(), themeColor: Color, supportFragmentManager: FragmentManager, - homeContext: HomeActivity, barcodeLauncher: ActivityResultLauncher, proceedAction: (scope: CoroutineScope, scaffoldState: ScaffoldState) -> Unit = { _, _ -> }, syncAction: (scope: CoroutineScope, scaffoldState: ScaffoldState) -> Unit = { _, _ -> } ) { val scaffoldState = rememberScaffoldState() val scope = rememberCoroutineScope() - var enabled by remember { mutableStateOf(false) } + val buttonUiState by manageStockViewModel.reviewButtonUiState.collectAsState() Scaffold( scaffoldState = scaffoldState, floatingActionButton = { AnimatedVisibility( - visible = checkVisibility(viewModel = viewModel, manageStockViewModel), + visible = buttonUiState.visibility != ButtonVisibilityState.HIDDEN, enter = fadeIn(), exit = fadeOut() ) { CompositionLocalProvider( LocalRippleTheme provides - if (enabled) LocalRippleTheme.current - else NoRippleTheme + if (buttonUiState.visibility == ButtonVisibilityState.ENABLED) { + LocalRippleTheme.current + } else { + NoRippleTheme + } ) { ExtendedFloatingActionButton( modifier = Modifier @@ -88,29 +86,41 @@ fun HomeScreen( ), icon = { Icon( - painter = painterResource(R.drawable.proceed_icon), - contentDescription = stringResource(R.string.review), - tint = if (enabled) themeColor - else colorResource(id = R.color.proceed_text_color) + painter = painterResource(buttonUiState.icon), + contentDescription = stringResource(buttonUiState.text), + tint = if ( + buttonUiState.visibility == ButtonVisibilityState.ENABLED + ) { + themeColor + } else { + colorResource(id = R.color.proceed_text_color) + } ) }, text = { Text( - stringResource(R.string.review), - color = if (enabled) themeColor - else colorResource(id = R.color.proceed_text_color) + stringResource(buttonUiState.text), + color = if ( + buttonUiState.visibility == ButtonVisibilityState.ENABLED + ) { + themeColor + } else { + colorResource(id = R.color.proceed_text_color) + } ) }, onClick = { - if (enabled) { - enabled = !enabled + if (buttonUiState.visibility == ButtonVisibilityState.ENABLED) { proceedAction(scope, scaffoldState) - } else { - enabled = !enabled } }, - backgroundColor = if (enabled) Color.White - else colorResource(id = R.color.proceed_color), + backgroundColor = if ( + buttonUiState.visibility == ButtonVisibilityState.ENABLED + ) { + Color.White + } else { + colorResource(id = R.color.proceed_color) + }, shape = RoundedCornerShape(16.dp) ) } @@ -131,7 +141,6 @@ fun HomeScreen( manageStockViewModel, themeColor, supportFragmentManager, - homeContext, barcodeLauncher, scaffoldState ) { coroutineScope, scaffold -> @@ -139,32 +148,7 @@ fun HomeScreen( } } } -@Composable -fun checkVisibility(viewModel: HomeViewModel, manageStockViewModel: ManageStockViewModel): Boolean { - return if (( - viewModel.toolbarTitle.collectAsState().value.name == - TransactionType.DISCARD.name - ) - ) { - return viewModel.hasFacilitySelected.collectAsState().value && - manageStockViewModel.sizeTableData.collectAsState().value > 0 - } else if (( - viewModel.toolbarTitle.collectAsState().value.name == - TransactionType.CORRECTION.name - ) - ) { - return viewModel.hasFacilitySelected.collectAsState().value && - manageStockViewModel.sizeTableData.collectAsState().value > 0 - } else ( - ( - viewModel.toolbarTitle.collectAsState().value.name == - TransactionType.DISTRIBUTION.name - ) && - viewModel.hasFacilitySelected.collectAsState().value && - viewModel.hasDestinationSelected.collectAsState().value && - manageStockViewModel.sizeTableData.collectAsState().value > 0 - ) -} + private object NoRippleTheme : RippleTheme { @Composable override fun defaultColor() = Color.Unspecified diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/BackdropComponent.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/BackdropComponent.kt index b2b16235b0..50a7203c19 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/BackdropComponent.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/BackdropComponent.kt @@ -23,7 +23,6 @@ import com.journeyapps.barcodescanner.ScanOptions import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.dhis2.android.rtsm.data.TransactionType -import org.dhis2.android.rtsm.ui.home.HomeActivity import org.dhis2.android.rtsm.ui.home.HomeViewModel import org.dhis2.android.rtsm.ui.managestock.ManageStockViewModel @@ -36,27 +35,21 @@ fun Backdrop( manageStockViewModel: ManageStockViewModel, themeColor: Color, supportFragmentManager: FragmentManager, - homeContext: HomeActivity, barcodeLauncher: ActivityResultLauncher, scaffoldState: ScaffoldState, syncAction: (scope: CoroutineScope, scaffoldState: ScaffoldState) -> Unit = { _, _ -> } ) { val backdropState = rememberBackdropScaffoldState(BackdropValue.Concealed) - var isFrontLayerDisabled by remember { mutableStateOf(null) } - var hasFacilitySelected by remember { mutableStateOf(false) } - var hasDestinationSelected by remember { mutableStateOf(null) } - var toolbarTitle by remember { - mutableStateOf(TransactionType.DISTRIBUTION.name) - } val scope = rememberCoroutineScope() + val settingsUiState by viewModel.settingsUiState.collectAsState() BackdropScaffold( appBar = { Toolbar( - viewModel.toolbarTitle.collectAsState().value.name, - viewModel.fromFacility.collectAsState().value.asString(), - viewModel.deliveryTo.collectAsState().value?.asString(), + settingsUiState.transactionType.name, + settingsUiState.fromFacilitiesLabel().asString(), + settingsUiState.deliverToLabel()?.asString(), themeColor, navigationAction = { activity.finish() @@ -64,23 +57,16 @@ fun Backdrop( backdropState, scaffoldState, syncAction, - hasFacilitySelected, - hasDestinationSelected + settingsUiState.hasFacilitySelected(), + settingsUiState.hasDestinationSelected() ) - toolbarTitle = viewModel.toolbarTitle.collectAsState().value.name }, backLayerBackgroundColor = themeColor, backLayerContent = { val height = filterList( viewModel, themeColor, - supportFragmentManager, - homeContext, - { hasFacilitySelected = it }, - { - hasDestinationSelected = it - viewModel.setDestinationSelected(it) - } + supportFragmentManager ) if (height > 160.dp) { scope.launch { backdropState.reveal() } @@ -94,15 +80,15 @@ fun Backdrop( themeColor, viewModel, manageStockViewModel, - hasFacilitySelected, - hasDestinationSelected, barcodeLauncher ) }, scaffoldState = backdropState, gesturesEnabled = false, - frontLayerScrimColor = if (toolbarTitle == TransactionType.DISTRIBUTION.name) { - if (hasFacilitySelected && hasDestinationSelected == true) { + frontLayerScrimColor = if ( + settingsUiState.transactionType == TransactionType.DISTRIBUTION + ) { + if (settingsUiState.hasFacilitySelected() && settingsUiState.hasDestinationSelected()) { isFrontLayerDisabled = false Color.Unspecified } else { @@ -110,7 +96,7 @@ fun Backdrop( MaterialTheme.colors.surface.copy(alpha = 0.60f) } } else { - if (!hasFacilitySelected) { + if (!settingsUiState.hasFacilitySelected()) { isFrontLayerDisabled = true MaterialTheme.colors.surface.copy(alpha = 0.60f) } else { diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/DropdownComponent.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/DropdownComponent.kt index 207bdd6fbb..da50c05df7 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/DropdownComponent.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/DropdownComponent.kt @@ -48,8 +48,8 @@ import androidx.compose.ui.zIndex import androidx.fragment.app.FragmentManager import org.dhis2.android.rtsm.R import org.dhis2.android.rtsm.data.models.TransactionItem -import org.dhis2.android.rtsm.ui.home.HomeActivity import org.dhis2.android.rtsm.ui.home.HomeViewModel +import org.dhis2.android.rtsm.ui.home.model.SettingsUiState import org.dhis2.android.rtsm.utils.Utils.Companion.capitalizeText import org.dhis2.commons.orgunitdialog.CommonOrgUnitDialog import org.hisp.dhis.android.core.option.Option @@ -155,7 +155,6 @@ fun DropdownComponent( DropdownMenuItem( onClick = { viewModel.selectTransaction(item.transactionType) - viewModel.setToolbarTitle(item.transactionType) selectedIndex = index itemIcon = item.icon @@ -198,9 +197,7 @@ fun DropdownComponentFacilities( viewModel: HomeViewModel, themeColor: Color = colorResource(R.color.colorPrimary), supportFragmentManager: FragmentManager, - homeContext: HomeActivity, - data: List, - isFacilitySelected: (value: String) -> Unit = { } + data: List ) { var isExpanded by remember { mutableStateOf(false) } @@ -221,17 +218,16 @@ fun DropdownComponentFacilities( painterResource(id = R.drawable.ic_arrow_drop_down) } + val settingsUiState by viewModel.settingsUiState.collectAsState() + val interactionSource = remember { MutableInteractionSource() } if (interactionSource.collectIsPressedAsState().value) { - viewModel.setFacilitySelected(false) - openOrgUnitTreeSelector(supportFragmentManager, homeContext, data, viewModel) + openOrgUnitTreeSelector(supportFragmentManager, data, viewModel, settingsUiState) } - isFacilitySelected(viewModel.orgUnitName.collectAsState().value) - Column(Modifier.padding(horizontal = 16.dp)) { OutlinedTextField( - value = viewModel.orgUnitName.collectAsState().value, + value = settingsUiState.facilityName(), onValueChange = { selectedText = it }, modifier = Modifier .fillMaxWidth() @@ -261,12 +257,11 @@ fun DropdownComponentFacilities( trailingIcon = { IconButton( onClick = { - viewModel.setFacilitySelected(false) openOrgUnitTreeSelector( supportFragmentManager, - homeContext, data, - viewModel + viewModel, + settingsUiState ) } ) { @@ -301,7 +296,6 @@ fun DropdownComponentFacilities( selectedIndex = index viewModel.setFacility(item) - viewModel.fromFacilitiesLabel(selectedText) } ) { Row( @@ -433,7 +427,6 @@ fun DropdownComponentDistributedTo( selectedIndex = index viewModel.setDestination(item) - viewModel.deliveryToLabel(selectedText) } ) { Row( @@ -465,40 +458,32 @@ fun DropdownComponentDistributedTo( fun openOrgUnitTreeSelector( supportFragmentManager: FragmentManager, - homeContext: HomeActivity, data: List, - viewModel: HomeViewModel + viewModel: HomeViewModel, + settingsUiState: SettingsUiState ) { - val programUid = "F5ijs28K4s8" val orgUnitDialog = CommonOrgUnitDialog() orgUnitDialog .setTitle("Facilities") .setMultiSelection(false) .setOrgUnits(data) - .setProgram(programUid) + .setProgram(settingsUiState.programUid) .setPossitiveListener { if (orgUnitDialog.selectedOrgUnitModel != null) { viewModel.setFacility(orgUnitDialog.selectedOrgUnitModel) - viewModel.fromFacilitiesLabel(orgUnitDialog.selectedOrgUnitName) - viewModel.setSelectedText(orgUnitDialog.selectedOrgUnitName) - viewModel.setOldSelectedFacility(orgUnitDialog.selectedOrgUnitName) orgUnitData = orgUnitDialog.selectedOrgUnitModel - viewModel.setFacilitySelected(true) } orgUnitDialog.dismiss() } .setNegativeListener { - if (viewModel.oldSelectedFacility.value != "") { - viewModel.setFacilitySelected(true) - } orgUnitDialog.dismiss() } orgUnitData?.let { orgUnitDialog.setOrgUnit(orgUnitData) } - orgUnitName = viewModel.orgUnitName.value + orgUnitName = settingsUiState.facilityName() orgUnitDialog.setOrgUnitName(orgUnitName) if (!orgUnitDialog.isAdded) { diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/FilterComponents.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/FilterComponents.kt index a091101213..5e10931eb0 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/FilterComponents.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/FilterComponents.kt @@ -23,8 +23,8 @@ import androidx.fragment.app.FragmentManager import org.dhis2.android.rtsm.R import org.dhis2.android.rtsm.data.OperationState import org.dhis2.android.rtsm.data.TransactionType +import org.dhis2.android.rtsm.data.TransactionType.DISTRIBUTION import org.dhis2.android.rtsm.data.models.TransactionItem -import org.dhis2.android.rtsm.ui.home.HomeActivity import org.dhis2.android.rtsm.ui.home.HomeViewModel import org.hisp.dhis.android.core.option.Option import org.hisp.dhis.android.core.organisationunit.OrganisationUnit @@ -33,14 +33,12 @@ import org.hisp.dhis.android.core.organisationunit.OrganisationUnit fun filterList( viewModel: HomeViewModel, themeColor: Color, - supportFragmentManager: FragmentManager, - homeContext: HomeActivity, - isFacilitySelected: (value: Boolean) -> Unit = {}, - isDestinationSelected: (value: Boolean) -> Unit = {} + supportFragmentManager: FragmentManager ): Dp { val facilities = viewModel.facilities.collectAsState().value val destinations = viewModel.destinationsList.collectAsState().value - val showDestination = viewModel.isDistribution.collectAsState().value + val showDestination = + viewModel.settingsUiState.collectAsState().value.transactionType == DISTRIBUTION // get local density from composable val localDensity = LocalDensity.current @@ -78,11 +76,8 @@ fun filterList( viewModel, themeColor, supportFragmentManager, - homeContext, getFacilities(facilities) - ) { facility -> - isFacilitySelected(facility.isNotEmpty()) - } + ) } if (showDestination) { @@ -93,9 +88,7 @@ fun filterList( viewModel, themeColor, result - ) { destination -> - isDestinationSelected(destination.isNotEmpty()) - } + ) } } } @@ -105,7 +98,7 @@ fun filterList( private fun mapTransaction(): MutableList { return mutableListOf( - TransactionItem(R.drawable.ic_distribution, TransactionType.DISTRIBUTION), + TransactionItem(R.drawable.ic_distribution, DISTRIBUTION), TransactionItem(R.drawable.ic_discard, TransactionType.DISCARD), TransactionItem(R.drawable.ic_correction, TransactionType.CORRECTION) ) diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/MainContent.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/MainContent.kt index ef051b8fbf..65b2fe0fa7 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/MainContent.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/home/screens/components/MainContent.kt @@ -61,8 +61,6 @@ fun MainContent( themeColor: Color, viewModel: HomeViewModel, manageStockViewModel: ManageStockViewModel, - hasFacilitySelected: Boolean, - hasDestinationSelected: Boolean?, barcodeLauncher: ActivityResultLauncher ) { val scope = rememberCoroutineScope() @@ -75,7 +73,8 @@ fun MainContent( val weightValueArrow = if (backdropState.isRevealed) 0.10f else 0.05f val weightValueArrowStatus = backdropState.isRevealed val focusManager = LocalFocusManager.current - val search = viewModel.scanText.collectAsState().value + val search by viewModel.scanText.collectAsState() + val settingsUiState by viewModel.settingsUiState.collectAsState() Column( modifier = Modifier.fillMaxSize(), @@ -209,31 +208,25 @@ fun MainContent( horizontalAlignment = Alignment.CenterHorizontally, modifier = Modifier.padding(vertical = 0.dp) ) { - if (viewModel.toolbarTitle.collectAsState().value.name - == TransactionType.DISTRIBUTION.name - ) { - if (viewModel.hasFacilitySelected.collectAsState().value && - hasDestinationSelected == true + if (settingsUiState.transactionType == TransactionType.DISTRIBUTION) { + if (settingsUiState.hasFacilitySelected() && + settingsUiState.hasDestinationSelected() ) { - updateTableState(manageStockViewModel, viewModel) + manageStockViewModel.setup(viewModel.getData()) ManageStockTable(manageStockViewModel) { scope.launch { backdropState.conceal() } } } - } else if (viewModel.toolbarTitle.collectAsState().value.name - == TransactionType.CORRECTION.name - ) { - if (viewModel.hasFacilitySelected.collectAsState().value) { - updateTableState(manageStockViewModel, viewModel) + } else if (settingsUiState.transactionType == TransactionType.CORRECTION) { + if (settingsUiState.hasFacilitySelected()) { + manageStockViewModel.setup(viewModel.getData()) ManageStockTable(manageStockViewModel) { scope.launch { backdropState.conceal() } } } - } else if (viewModel.toolbarTitle.collectAsState().value.name - == TransactionType.DISCARD.name - ) { - if (viewModel.hasFacilitySelected.collectAsState().value) { - updateTableState(manageStockViewModel, viewModel) + } else if (settingsUiState.transactionType == TransactionType.DISCARD) { + if (settingsUiState.hasFacilitySelected()) { + manageStockViewModel.setup(viewModel.getData()) ManageStockTable(manageStockViewModel) { scope.launch { backdropState.conceal() } } @@ -243,13 +236,6 @@ fun MainContent( } } -private fun updateTableState( - manageStockViewModel: ManageStockViewModel, - viewModel: HomeViewModel -) { - manageStockViewModel.setup(viewModel.getData()) -} - private fun scanBarcode(launcher: ActivityResultLauncher) { val scanOptions = ScanOptions() .setBeepEnabled(true) diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockAdapter.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockAdapter.kt deleted file mode 100644 index c297468cfd..0000000000 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockAdapter.kt +++ /dev/null @@ -1,147 +0,0 @@ -package org.dhis2.android.rtsm.ui.managestock - -import android.annotation.SuppressLint -import android.content.res.Resources -import android.text.Editable -import android.text.TextWatcher -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.TextView -import androidx.paging.PagedListAdapter -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.textfield.TextInputLayout -import org.dhis2.android.rtsm.R -import org.dhis2.android.rtsm.commons.Constants.CLEAR_FIELD_DELAY -import org.dhis2.android.rtsm.data.AppConfig -import org.dhis2.android.rtsm.data.models.StockItem -import org.dhis2.android.rtsm.data.models.Transaction -import org.dhis2.android.rtsm.ui.base.ItemWatcher -import org.dhis2.android.rtsm.ui.base.SpeechController -import org.dhis2.android.rtsm.ui.base.TextInputDelegate -import org.dhis2.android.rtsm.utils.KeyboardUtils -import org.jetbrains.annotations.NotNull -import org.jetbrains.annotations.Nullable - -class ManageStockAdapter( - private val itemWatcher: @NotNull ItemWatcher, - private var speechController: @Nullable SpeechController?, - val appConfig: @NotNull AppConfig, - private val transaction: Transaction, - private var voiceInputEnabled: Boolean -) : PagedListAdapter< - StockItem, ManageStockAdapter.StockItemHolder>(DIFF_CALLBACK) { - lateinit var resources: Resources - private val textInputDelegate: TextInputDelegate = TextInputDelegate() - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StockItemHolder { - val itemView = LayoutInflater.from(parent.context) - .inflate(R.layout.manage_stock_item_entry, parent, false) - resources = parent.context.resources - - return StockItemHolder(itemView, itemWatcher) - } - - override fun onBindViewHolder(holder: StockItemHolder, position: Int) { - // Note that the item is a placeholder if it is null - getItem(position)?.let { item -> holder.bindTo(item) } - } - - companion object { - private val DIFF_CALLBACK = object : DiffUtil.ItemCallback() { - override fun areItemsTheSame( - oldItem: StockItem, - newItem: StockItem - ) = oldItem.id == newItem.id - - @SuppressLint("DiffUtilEquals") - override fun areContentsTheSame( - oldItem: StockItem, - newItem: StockItem - ) = oldItem == newItem - } - } - - inner class StockItemHolder( - itemView: View, - private val watcher: ItemWatcher - ) : - RecyclerView.ViewHolder(itemView) { - - private val tvItemName: TextView = itemView.findViewById(R.id.item_name_text_view) - private val tvStockOnHand: TextView = - itemView.findViewById(R.id.stock_on_hand_value_text_view) - private val etQty: TextInputLayout = itemView.findViewById(R.id.item_qty_text_field) - - init { - KeyboardUtils.configureInputTypeForTransaction(transaction, etQty.editText) - - addTextListener() - addFocusListener() - } - - private fun addFocusListener() { - etQty.editText?.setOnFocusChangeListener { _, hasFocus -> - textInputDelegate.focusChanged( - speechController, etQty, hasFocus, voiceInputEnabled, adapterPosition - ) - } - } - - private fun addTextListener() { - etQty.editText?.addTextChangedListener(object : TextWatcher { - override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { - if (adapterPosition == RecyclerView.NO_POSITION) return - - val qty = s?.toString() - getItem(adapterPosition)?.let { - textInputDelegate.textChanged(it, qty, adapterPosition, watcher) - } - } - - override fun beforeTextChanged( - s: CharSequence?, - start: Int, - count: Int, - after: Int - ) { - } - - override fun afterTextChanged(s: Editable?) {} - }) - } - - fun bindTo(item: StockItem) { - tvItemName.text = item.name - tvStockOnHand.text = watcher.getStockOnHand(item) ?: item.stockOnHand - etQty.editText?.setText(watcher.getQuantity(item)) - - var error: String? = null - if (watcher.hasError(item)) { - error = resources.getString(R.string.invalid_quantity) - - // Highlight the erroneous text for easy correction - etQty.editText?.selectAll() - - // Clear the erroneous field after some time to prepare for next entry, - // if input is via voice - if (voiceInputEnabled) { - textInputDelegate.clearFieldAfterDelay( - etQty.editText, CLEAR_FIELD_DELAY - ) - } - } else { - // set the cursor at the end - etQty.editText?.setSelection(etQty.editText!!.text.length) - } - etQty.error = error - } - } - - fun voiceInputStateChanged(enabled: Boolean) { - voiceInputEnabled = enabled - - textInputDelegate.voiceInputStateChanged(this) - } -} diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockViewModel.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockViewModel.kt index 68a10f6a1b..e572acb959 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockViewModel.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockViewModel.kt @@ -15,7 +15,7 @@ import java.util.concurrent.TimeUnit import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.dhis2.android.rtsm.R import org.dhis2.android.rtsm.commons.Constants.QUANTITY_ENTRY_DEBOUNCE @@ -35,6 +35,8 @@ import org.dhis2.android.rtsm.services.rules.RuleValidationHelper import org.dhis2.android.rtsm.services.scheduler.BaseSchedulerProvider import org.dhis2.android.rtsm.ui.base.ItemWatcher import org.dhis2.android.rtsm.ui.base.SpeechRecognitionAwareViewModel +import org.dhis2.android.rtsm.ui.home.model.ButtonUiState +import org.dhis2.android.rtsm.ui.home.model.ButtonVisibilityState import org.dhis2.android.rtsm.utils.Utils.Companion.isValidStockOnHand import org.dhis2.commons.resources.ResourceManager import org.dhis2.composetable.TableScreenState @@ -77,8 +79,8 @@ class ManageStockViewModel @Inject constructor( private val entryRelay = PublishRelay.create() private val itemsCache = linkedMapOf() - private val _sizeTableData = MutableStateFlow(0) - val sizeTableData = _sizeTableData.asStateFlow() + private val _hasData = MutableStateFlow(false) + val hasData = _hasData private val _networkState = MutableLiveData>>>() val operationState: LiveData>>> @@ -95,6 +97,9 @@ class ManageStockViewModel @Inject constructor( private val _stockItems: MutableLiveData> = MutableLiveData>() + private val _reviewButtonUiState = MutableStateFlow(ButtonUiState()) + val reviewButtonUiState: StateFlow = _reviewButtonUiState + fun setup(transaction: Transaction) { _transaction.value = transaction @@ -199,7 +204,7 @@ class ManageStockViewModel @Inject constructor( ) { val tableRowModels = mutableListOf() - _sizeTableData.value = stockItems!!.size + _hasData.value = stockItems!!.size > 0 stockItems?.forEachIndexed { index, item -> val tableRowModel = TableRowModel( @@ -282,9 +287,11 @@ class ManageStockViewModel @Inject constructor( } } ?: emptyList() + _allTableState.value = updatedData + _screenState.postValue( TableScreenState( - tables = updatedData, + tables = allTableState.value, selectNext = false ) ) @@ -417,7 +424,7 @@ class ManageStockViewModel @Inject constructor( fun addItem(item: StockItem, qty: String?, stockOnHand: String?, hasError: Boolean) { // Remove from cache any item whose quantity has been cleared - if (qty == null) { + if (qty.isNullOrEmpty()) { itemsCache.remove(item.id) return } @@ -429,11 +436,33 @@ class ManageStockViewModel @Inject constructor( fun hasError(item: StockItem) = itemsCache[item.id]?.hasError ?: false - fun canReview(): Boolean = itemsCache.size > 0 && itemsCache.none { it.value.hasError } + private fun canReview(): Boolean = itemsCache.size > 0 && itemsCache.none { it.value.hasError } private fun getPopulatedEntries() = Collections.synchronizedList(itemsCache.values.toList()) fun getData(): ReviewStockData = ReviewStockData(transaction.value!!, getPopulatedEntries()) fun getItemCount(): Int = itemsCache.size + fun onEditingCell(isEditing: Boolean, onEditionStart: () -> Unit) { + updateReviewButton(isEditing) + if (isEditing) { + onEditionStart.invoke() + } + } + + private fun updateReviewButton(isEditing: Boolean = false) { + val buttonState: ButtonVisibilityState = if (isEditing || !hasData.value) { + ButtonVisibilityState.HIDDEN + } else { + if (canReview()) { + ButtonVisibilityState.ENABLED + } else { + ButtonVisibilityState.DISABLED + } + } + + _reviewButtonUiState.update { currentUiState -> + currentUiState.copy(visibility = buttonState) + } + } } diff --git a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/components/ManageStockTable.kt b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/components/ManageStockTable.kt index bc41e807ab..2c22a0ed20 100644 --- a/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/components/ManageStockTable.kt +++ b/stock-managment/src/main/java/org/dhis2/android/rtsm/ui/managestock/components/ManageStockTable.kt @@ -22,7 +22,7 @@ fun ManageStockTable( val screenState by viewModel.screenState.observeAsState() MdcTheme { - if (viewModel.sizeTableData.collectAsState().value > 0) { + if (viewModel.hasData.collectAsState().value) { TableTheme( tableColors = null, tableDimensions = TableDimensions(defaultRowHeaderWidth = 200.dp) @@ -33,7 +33,7 @@ fun ManageStockTable( viewModel.onCellClick(cell) }, onEdition = { isEditing -> - editingCellValue(isEditing, concealBackdropState) + viewModel.onEditingCell(isEditing, concealBackdropState) }, onCellValueChange = viewModel::onCellValueChanged, onSaveValue = viewModel::onSaveValueChange @@ -44,13 +44,3 @@ fun ManageStockTable( } } } - -fun editingCellValue( - editing: Boolean, - onEditionStart: () -> Unit -) { - // TODO Hide review button - if (editing) { - onEditionStart.invoke() - } -} diff --git a/stock-managment/src/main/res/layout-w600dp/activity_manage_stock.xml b/stock-managment/src/main/res/layout-w600dp/activity_manage_stock.xml deleted file mode 100644 index 7946c25f3e..0000000000 --- a/stock-managment/src/main/res/layout-w600dp/activity_manage_stock.xml +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/stock-managment/src/main/res/layout-w840dp/activity_manage_stock.xml b/stock-managment/src/main/res/layout-w840dp/activity_manage_stock.xml deleted file mode 100644 index 7946c25f3e..0000000000 --- a/stock-managment/src/main/res/layout-w840dp/activity_manage_stock.xml +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/stock-managment/src/main/res/layout/activity_manage_stock.xml b/stock-managment/src/main/res/layout/activity_manage_stock.xml deleted file mode 100644 index e99852a7f5..0000000000 --- a/stock-managment/src/main/res/layout/activity_manage_stock.xml +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/stock-managment/src/test/java/org/dhis2/android/rtsm/viewmodels/HomeViewModelUnitTest.kt b/stock-managment/src/test/java/org/dhis2/android/rtsm/viewmodels/HomeViewModelUnitTest.kt index b7e764eb97..a8807dd00c 100644 --- a/stock-managment/src/test/java/org/dhis2/android/rtsm/viewmodels/HomeViewModelUnitTest.kt +++ b/stock-managment/src/test/java/org/dhis2/android/rtsm/viewmodels/HomeViewModelUnitTest.kt @@ -11,7 +11,6 @@ import io.reactivex.disposables.CompositeDisposable import io.reactivex.plugins.RxJavaPlugins import io.reactivex.schedulers.Schedulers import java.time.LocalDateTime -import java.time.ZoneId import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -40,6 +39,7 @@ import org.hisp.dhis.android.core.option.Option import org.hisp.dhis.android.core.organisationunit.OrganisationUnit import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Rule @@ -147,12 +147,6 @@ class HomeViewModelUnitTest { RxAndroidPlugins.reset() } - private fun getTime() = - LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - - private fun getTime(dateTime: LocalDateTime) = - dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() - @Test fun init_shouldLoadFacilities() { verify(metadataManager).facilities(appConfig.program) @@ -167,20 +161,6 @@ class HomeViewModelUnitTest { assertEquals(viewModel.destinationsList.value, OperationState.Success(destinations)) } - @Test - fun init_shouldSetDefaultTransaction() { - assertNotNull(viewModel.transactionType.value) - } - - @Test - fun init_shouldSetTransactionDateToCurrentDate() { - val today = LocalDateTime.now() - - assertEquals(viewModel.transactionDate.value.year, today.year) - assertEquals(viewModel.transactionDate.value.month, today.month) - assertEquals(viewModel.transactionDate.value.dayOfMonth, today.dayOfMonth) - } - @Test fun canSelectDifferentTransactionTypes() { val types = listOf( @@ -191,26 +171,32 @@ class HomeViewModelUnitTest { types.forEach { viewModel.selectTransaction(it) - assertEquals(viewModel.transactionType.value, it) + assertEquals(viewModel.settingsUiState.value.transactionType, it) } } @Test fun isDistributionIsPositive_whenDistributionIsSet() { viewModel.selectTransaction(TransactionType.DISTRIBUTION) - assertEquals(viewModel.isDistribution.value, true) + assertEquals(viewModel.settingsUiState.value.transactionType, TransactionType.DISTRIBUTION) } @Test fun isDistributionIsNegative_whenDiscardIsSet() { viewModel.selectTransaction(TransactionType.DISCARD) - assertEquals(viewModel.isDistribution.value, false) + assertNotEquals( + viewModel.settingsUiState.value.transactionType, + TransactionType.DISTRIBUTION + ) } @Test fun isDistributionIsNegative_whenCorrectionIsSet() { viewModel.selectTransaction(TransactionType.CORRECTION) - assertEquals(viewModel.isDistribution.value, false) + assertNotEquals( + viewModel.settingsUiState.value.transactionType, + TransactionType.DISTRIBUTION + ) } @Test @@ -229,9 +215,6 @@ class HomeViewModelUnitTest { @Test fun distributionTransaction_cannotManageStock_ifOnlyTransactionDateIsSet() { viewModel.selectTransaction(TransactionType.DISTRIBUTION) - viewModel.setTransactionDate( - LocalDateTime.now().atZone(ZoneId.systemDefault()).toEpochSecond() - ) assertEquals(viewModel.checkForFieldErrors(), R.string.mandatory_facility_selection) } @@ -246,7 +229,6 @@ class HomeViewModelUnitTest { fun distributionTransaction_cannotManageStock_ifOnlyFacilityAndTransactionDateIsSet() { viewModel.selectTransaction(TransactionType.DISTRIBUTION) viewModel.setFacility(facilities[0]) - viewModel.setTransactionDate(getTime()) assertEquals(viewModel.checkForFieldErrors(), R.string.mandatory_distributed_to_selection) } @@ -254,7 +236,6 @@ class HomeViewModelUnitTest { fun distributionTransaction_cannotManageStock_ifOnlyDestinedToAndTransactionDateIsSet() { viewModel.selectTransaction(TransactionType.DISTRIBUTION) viewModel.setDestination(destinations[0]) - viewModel.setTransactionDate(getTime()) assertEquals(viewModel.checkForFieldErrors(), R.string.mandatory_facility_selection) } @@ -271,7 +252,6 @@ class HomeViewModelUnitTest { viewModel.selectTransaction(TransactionType.DISTRIBUTION) viewModel.setFacility(facilities[0]) viewModel.setDestination(destinations[0]) - viewModel.setTransactionDate(getTime()) assertEquals(viewModel.checkForFieldErrors(), null) } @@ -291,7 +271,6 @@ class HomeViewModelUnitTest { @Test fun discardTransaction_cannotManageStock_ifOnlyTransactionDateIsSet() { viewModel.selectTransaction(TransactionType.DISCARD) - viewModel.setTransactionDate(getTime()) assertEquals(viewModel.checkForFieldErrors(), R.string.mandatory_facility_selection) } @@ -300,7 +279,6 @@ class HomeViewModelUnitTest { fun discardTransaction_canManageStock_ifAllFieldsAreSet() { viewModel.selectTransaction(TransactionType.DISCARD) viewModel.setFacility(facilities[0]) - viewModel.setTransactionDate(getTime()) assertEquals(viewModel.checkForFieldErrors(), null) } @@ -327,7 +305,6 @@ class HomeViewModelUnitTest { @Test fun correctionTransaction_cannotManageStock_ifOnlyTransactionDateIsSet() { viewModel.selectTransaction(TransactionType.CORRECTION) - viewModel.setTransactionDate(getTime()) assertEquals(viewModel.checkForFieldErrors(), R.string.mandatory_facility_selection) } @@ -336,7 +313,6 @@ class HomeViewModelUnitTest { fun correctionTransaction_canManageStock_ifAllFieldsAreSet() { viewModel.selectTransaction(TransactionType.CORRECTION) viewModel.setFacility(facilities[0]) - viewModel.setTransactionDate(getTime()) assertEquals(viewModel.checkForFieldErrors(), null) } @@ -350,7 +326,6 @@ class HomeViewModelUnitTest { @Test(expected = UserIntentParcelCreationException::class) fun distributionWithMissingFacility_cannotCreateUserIntent() { viewModel.selectTransaction(TransactionType.DISTRIBUTION) - viewModel.setTransactionDate(getTime()) viewModel.getData() } @@ -375,7 +350,6 @@ class HomeViewModelUnitTest { viewModel.selectTransaction(TransactionType.DISTRIBUTION) viewModel.setDestination(destination) viewModel.setFacility(facility) - viewModel.setTransactionDate(getTime(now)) val data = viewModel.getData() assertEquals(data.transactionType, TransactionType.DISTRIBUTION) @@ -398,7 +372,6 @@ class HomeViewModelUnitTest { viewModel.selectTransaction(TransactionType.DISCARD) viewModel.setFacility(facility) - viewModel.setTransactionDate(getTime(now)) val data = viewModel.getData() assertEquals(data.transactionType, TransactionType.DISCARD) @@ -416,7 +389,6 @@ class HomeViewModelUnitTest { viewModel.selectTransaction(TransactionType.CORRECTION) viewModel.setFacility(facility) - viewModel.setTransactionDate(getTime(now)) val data = viewModel.getData() assertEquals(data.transactionType, TransactionType.CORRECTION) @@ -427,82 +399,36 @@ class HomeViewModelUnitTest { assertEquals(data.transactionDate, now.humanReadableDate()) } - @Test - fun shouldChangeToolbarTitle_forDistribution() { - viewModel.setToolbarTitle(TransactionType.DISTRIBUTION) - - val title = viewModel.toolbarTitle.value.name - assertEquals(TransactionType.DISTRIBUTION.name, title) - } - - @Test - fun shouldChangeToolbarTitle_forDiscard() { - viewModel.setToolbarTitle(TransactionType.DISCARD) - - val title = viewModel.toolbarTitle.value.name - assertEquals(TransactionType.DISCARD.name, title) - } - - @Test - fun shouldChangeToolbarTitle_forCorrection() { - viewModel.setToolbarTitle(TransactionType.CORRECTION) - - val title = viewModel.toolbarTitle.value.name - assertEquals(TransactionType.CORRECTION.name, title) - } - @Test fun shouldChangeToolbarSubtitle_forDistribution() { val destination = destinations[2] val facility = facilities[1] - val now = LocalDateTime.now() viewModel.selectTransaction(TransactionType.DISTRIBUTION) viewModel.setDestination(destination) viewModel.setFacility(facility) - viewModel.setTransactionDate(getTime(now)) - - val facilityName = viewModel.getData().facility.name - val distributedTo = viewModel.getData().distributedTo?.name - if (distributedTo != null) { - viewModel.fromFacilitiesLabel(facilityName) - viewModel.deliveryToLabel(distributedTo) - } - - assertNotNull(viewModel.fromFacility.value) - assertNotNull(viewModel.deliveryTo.value) + assertNotNull(viewModel.settingsUiState.value.fromFacilitiesLabel()) + assertNotNull(viewModel.settingsUiState.value.deliverToLabel()) } @Test fun shouldChangeToolbarSubtitle_forDiscard() { val facility = facilities[1] - val now = LocalDateTime.now() viewModel.selectTransaction(TransactionType.DISCARD) viewModel.setFacility(facility) - viewModel.setTransactionDate(getTime(now)) - - val facilityName = viewModel.getData().facility.name - viewModel.fromFacilitiesLabel(facilityName) - - assertNotNull(viewModel.fromFacility.value) + assertNotNull(viewModel.settingsUiState.value.fromFacilitiesLabel()) } @Test fun shouldChangeToolbarSubtitle_forCorrection() { val facility = facilities[1] - val now = LocalDateTime.now() viewModel.selectTransaction(TransactionType.CORRECTION) viewModel.setFacility(facility) - viewModel.setTransactionDate(getTime(now)) - - val facilityName = viewModel.getData().facility.name - - viewModel.fromFacilitiesLabel(facilityName) - assertNotNull(viewModel.fromFacility.value) + assertNotNull(viewModel.settingsUiState.value.fromFacilitiesLabel()) } }