diff --git a/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/dataSetSection/DataSetSectionFragment.kt b/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/dataSetSection/DataSetSectionFragment.kt
index 75d74aa135..84f22b818c 100644
--- a/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/dataSetSection/DataSetSectionFragment.kt
+++ b/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/dataSetSection/DataSetSectionFragment.kt
@@ -209,6 +209,7 @@ class DataSetSectionFragment : FragmentGlobalAbstract(), DataValueContract.View
onCellClick = presenterFragment::onCellClick,
onEdition = presenter::editingCellValue,
onSaveValue = presenterFragment::onSaveValueChange,
+ emptyTablesText = getString(R.string.section_misconfigured),
)
}
}
diff --git a/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/dataSetSection/DataValuePresenter.kt b/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/dataSetSection/DataValuePresenter.kt
index 434b519908..36310c14dd 100644
--- a/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/dataSetSection/DataValuePresenter.kt
+++ b/app/src/main/java/org/dhis2/usescases/datasets/dataSetTable/dataSetSection/DataValuePresenter.kt
@@ -15,6 +15,7 @@ import org.dhis2.commons.schedulers.SchedulerProvider
import org.dhis2.commons.viewmodel.DispatcherProvider
import org.dhis2.composetable.TableConfigurationState
import org.dhis2.composetable.TableScreenState
+import org.dhis2.composetable.TableState
import org.dhis2.composetable.actions.Validator
import org.dhis2.composetable.model.TableCell
import org.dhis2.composetable.model.TableModel
@@ -79,7 +80,7 @@ class DataValuePresenter(
.subscribe(
{
screenState.update { currentScreenState ->
- currentScreenState.copy(tables = it.tables)
+ currentScreenState.copy(tables = it.tables, state = TableState.SUCCESS)
}
},
{ Timber.e(it) },
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index c0bce83893..40fb2d39e9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -978,4 +978,5 @@
Show fields
Hide fields
Import successful
+ This section is misconfigured.\nContact your administrator.
diff --git a/compose-table/src/androidTest/java/org/dhis2/composetable/TableRobot.kt b/compose-table/src/androidTest/java/org/dhis2/composetable/TableRobot.kt
index 43e8955d4c..06424d9d2e 100644
--- a/compose-table/src/androidTest/java/org/dhis2/composetable/TableRobot.kt
+++ b/compose-table/src/androidTest/java/org/dhis2/composetable/TableRobot.kt
@@ -17,6 +17,7 @@ import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertTextEquals
import androidx.compose.ui.test.hasParent
import androidx.compose.ui.test.hasTestTag
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
@@ -40,6 +41,7 @@ import org.dhis2.composetable.model.TextInputModel
import org.dhis2.composetable.ui.DataSetTableScreen
import org.dhis2.composetable.ui.DataTable
import org.dhis2.composetable.ui.DrawableId
+import org.dhis2.composetable.ui.EMPTY_TABLE_TEXT_TAG
import org.dhis2.composetable.ui.INPUT_ERROR_MESSAGE_TEST_TAG
import org.dhis2.composetable.ui.INPUT_HELPER_TEXT_TEST_TAG
import org.dhis2.composetable.ui.INPUT_ICON_TEST_TAG
@@ -176,6 +178,33 @@ class TableRobot(
return fakeModel
}
+ fun initEmptyTableAppScreen(
+ emptyTablesText: String,
+ ): List {
+ val fakeModel: List = emptyList()
+ composeTestRule.setContent {
+ val screenState = TableScreenState(fakeModel, state = TableState.SUCCESS)
+
+ val model by remember { mutableStateOf(screenState) }
+ TableTheme(
+ tableColors = TableColors().copy(primary = MaterialTheme.colors.primary),
+ tableConfiguration = TableConfiguration(),
+ tableResizeActions = object : TableResizeActions {}
+ ) {
+ DataSetTableScreen(
+ tableScreenState = model,
+ onCellClick = { _, _, _ ->
+ null
+ },
+ emptyTablesText = emptyTablesText,
+ onEdition = {},
+ onSaveValue = {}
+ )
+ }
+ }
+ return fakeModel
+ }
+
private fun updateValue(fakeModel: List, tableCell: TableCell): List {
return fakeModel.map { tableModel ->
val hasRowWithDataElement = tableModel.tableRows.find {
@@ -456,4 +485,12 @@ class TableRobot(
fun hideKeyboard() {
keyboardHelper.hideKeyboard()
}
+
+ fun assertInfoBarIsVisible(emptyString: String) {
+ composeTestRule.onNode(
+ hasParent(hasTestTag(EMPTY_TABLE_TEXT_TAG))
+ and
+ hasText(emptyString)
+ ).assertIsDisplayed()
+ }
}
\ No newline at end of file
diff --git a/compose-table/src/androidTest/java/org/dhis2/composetable/ui/DataSetTableUiTest.kt b/compose-table/src/androidTest/java/org/dhis2/composetable/ui/DataSetTableUiTest.kt
index 75b8fcd759..2685ac04bc 100644
--- a/compose-table/src/androidTest/java/org/dhis2/composetable/ui/DataSetTableUiTest.kt
+++ b/compose-table/src/androidTest/java/org/dhis2/composetable/ui/DataSetTableUiTest.kt
@@ -1,8 +1,13 @@
package org.dhis2.composetable.ui
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasTestTag
+import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import org.dhis2.composetable.model.FakeTableModels
+import org.dhis2.composetable.tableRobot
import org.junit.Rule
import org.junit.Test
@@ -20,4 +25,15 @@ class DataSetTableUiTest {
)
}
}
-}
\ No newline at end of file
+
+ @Test
+ fun shouldRenderInfoBarIfTableListIsEmpty() {
+ tableRobot(composeTestRule) {
+ initEmptyTableAppScreen(
+ emptyTablesText = "Section is misconfigured"
+ )
+
+ assertInfoBarIsVisible("Section is misconfigured")
+ }
+ }
+}
diff --git a/compose-table/src/main/java/org/dhis2/composetable/TableScreenState.kt b/compose-table/src/main/java/org/dhis2/composetable/TableScreenState.kt
index 3b40f2d161..a558287e25 100644
--- a/compose-table/src/main/java/org/dhis2/composetable/TableScreenState.kt
+++ b/compose-table/src/main/java/org/dhis2/composetable/TableScreenState.kt
@@ -6,6 +6,7 @@ import java.util.UUID
data class TableScreenState(
val tables: List,
val id: UUID = UUID.randomUUID(),
+ val state: TableState = TableState.LOADING,
)
data class TableConfigurationState(
@@ -17,3 +18,8 @@ data class TableConfigurationState(
!overwrittenRowHeaderWidth.isNullOrEmpty() or
!overwrittenColumnWidth.isNullOrEmpty()
}
+
+enum class TableState {
+ LOADING,
+ SUCCESS,
+}
diff --git a/compose-table/src/main/java/org/dhis2/composetable/ui/DataSetTableScreen.kt b/compose-table/src/main/java/org/dhis2/composetable/ui/DataSetTableScreen.kt
index ae0f763239..315b7e7b50 100644
--- a/compose-table/src/main/java/org/dhis2/composetable/ui/DataSetTableScreen.kt
+++ b/compose-table/src/main/java/org/dhis2/composetable/ui/DataSetTableScreen.kt
@@ -6,13 +6,18 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.BottomSheetScaffold
import androidx.compose.material.BottomSheetValue
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.Icon
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.ErrorOutline
import androidx.compose.material.rememberBottomSheetScaffoldState
import androidx.compose.material.rememberBottomSheetState
import androidx.compose.runtime.Composable
@@ -29,9 +34,11 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
+import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.launch
import org.dhis2.composetable.TableScreenState
+import org.dhis2.composetable.TableState
import org.dhis2.composetable.actions.TableInteractions
import org.dhis2.composetable.actions.TextInputInteractions
import org.dhis2.composetable.model.TableCell
@@ -43,6 +50,9 @@ import org.dhis2.composetable.ui.compositions.LocalInteraction
import org.dhis2.composetable.ui.compositions.LocalUpdatingCell
import org.dhis2.composetable.ui.extensions.collapseIfExpanded
import org.dhis2.composetable.ui.extensions.expandIfCollapsed
+import org.hisp.dhis.mobile.ui.designsystem.component.AdditionalInfoItemColor
+import org.hisp.dhis.mobile.ui.designsystem.component.InfoBar
+import org.hisp.dhis.mobile.ui.designsystem.component.InfoBarData
@OptIn(ExperimentalMaterialApi::class)
@Composable
@@ -53,6 +63,7 @@ fun DataSetTableScreen(
TableCell,
updateCellValue: (TableCell) -> Unit,
) -> TextInputModel?,
+ emptyTablesText: String? = null,
onEdition: (editing: Boolean) -> Unit,
onSaveValue: (TableCell) -> Unit,
bottomContent: @Composable (() -> Unit)? = null,
@@ -257,7 +268,7 @@ fun DataSetTableScreen(
),
) {
AnimatedVisibility(
- visible = tableScreenState.tables.isEmpty(),
+ visible = tableScreenState.state == TableState.LOADING,
enter = fadeIn(),
exit = fadeOut(),
) {
@@ -277,10 +288,36 @@ fun DataSetTableScreen(
LocalUpdatingCell provides updatingCell,
LocalInteraction provides iter,
) {
- DataTable(
- tableList = tableScreenState.tables,
- bottomContent = bottomContent,
- )
+ if (tableScreenState.state == TableState.SUCCESS && tableScreenState.tables.isEmpty()) {
+ Column(
+ modifier = Modifier.fillMaxWidth()
+ .padding(16.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ InfoBar(
+ infoBarData = InfoBarData(
+ text = emptyTablesText ?: "",
+ icon = {
+ Icon(
+ imageVector = Icons.Outlined.ErrorOutline,
+ contentDescription = "warning",
+ tint = AdditionalInfoItemColor.WARNING.color,
+ )
+ },
+ color = AdditionalInfoItemColor.WARNING.color,
+ backgroundColor = AdditionalInfoItemColor.WARNING.color.copy(alpha = 0.1f),
+ actionText = null,
+ onClick = {},
+ ),
+ Modifier.testTag(EMPTY_TABLE_TEXT_TAG),
+ )
+ }
+ } else {
+ DataTable(
+ tableList = tableScreenState.tables,
+ bottomContent = bottomContent,
+ )
+ }
}
displayDescription?.let {
TableDialog(
@@ -295,3 +332,5 @@ fun DataSetTableScreen(
}
}
}
+
+const val EMPTY_TABLE_TEXT_TAG = "EMPTY_TABLE_TEXT_TAG"
diff --git a/stock-usecase/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockViewModel.kt b/stock-usecase/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockViewModel.kt
index 08866d35c1..d7b70a3461 100644
--- a/stock-usecase/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockViewModel.kt
+++ b/stock-usecase/src/main/java/org/dhis2/android/rtsm/ui/managestock/ManageStockViewModel.kt
@@ -43,6 +43,7 @@ import org.dhis2.commons.resources.ResourceManager
import org.dhis2.commons.viewmodel.DispatcherProvider
import org.dhis2.composetable.TableConfigurationState
import org.dhis2.composetable.TableScreenState
+import org.dhis2.composetable.TableState
import org.dhis2.composetable.actions.Validator
import org.dhis2.composetable.model.KeyboardInputType
import org.dhis2.composetable.model.TableCell
@@ -265,6 +266,7 @@ class ManageStockViewModel @Inject constructor(
_screenState.postValue(
TableScreenState(
tables = tables,
+ state = TableState.SUCCESS,
),
)