Skip to content

Commit

Permalink
feat: [ANDROAPP-6689] Create DataSetInstanceScreen
Browse files Browse the repository at this point in the history
  • Loading branch information
Balcan committed Dec 20, 2024
1 parent 7d86c12 commit 856179c
Show file tree
Hide file tree
Showing 29 changed files with 795 additions and 31 deletions.
1 change: 1 addition & 0 deletions aggregates/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
20 changes: 16 additions & 4 deletions aggregates/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ plugins {
alias(libs.plugins.kotlin.compose.compiler)
}

repositories{
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
mavenCentral()
google()
}

kotlin {
androidTarget {
compilations.all {
Expand All @@ -14,7 +20,8 @@ kotlin {
}
}

jvm("desktop")
jvm("desktop").


/*listOf(
iosX64(),
Expand All @@ -34,15 +41,16 @@ kotlin {
implementation(compose.ui)
implementation(compose.material3)
api(compose.materialIconsExtended)
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
implementation(libs.dhis2.mobile.designsystem)
implementation(libs.compose.material3.window)
}
commonTest.dependencies {
implementation(kotlin("test"))
}

androidMain.dependencies { }
androidMain.dependencies {
implementation(libs.androidx.compose.preview)
}

androidUnitTest.dependencies { }

Expand All @@ -65,3 +73,7 @@ android {
targetCompatibility = JavaVersion.VERSION_1_8
}
}
dependencies {
debugImplementation(libs.androidx.compose.preview)
debugImplementation(libs.androidx.ui.tooling)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.dhis2.mobile.aggregates.ui

import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import org.dhis2.mobile.aggregates.model.previewDataSetScreenState
import org.hisp.dhis.mobile.ui.designsystem.theme.DHIS2Theme

@Preview(device = "id:pixel_8a")
@Composable
fun DataSetTableScreenPreview() {
DHIS2Theme {
DataSetInstanceScreen(previewDataSetScreenState(false, 3)) {}
}
}

@Preview(device = "id:pixel_c")
@Composable
fun DataSetTableTabletScreenPreview() {
DHIS2Theme {
DataSetInstanceScreen(previewDataSetScreenState(true, 10)) {}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.dhis2.mobile.aggregates.ui

import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@Composable
actual fun getScreenWidth(): Dp = LocalConfiguration.current.screenWidthDp.dp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.dhis2.mobile.aggregates.model

data class DataSetDetails(
val titleLabel: String,
val dateLabel: String,
val orgUnitLabel: String,
val catOptionComboLabel: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.dhis2.mobile.aggregates.model

data class DataSetScreenState(
val dataSetDetails: DataSetDetails,
val dataSetSections: List<DataSetSection>,
val useTwoPane: Boolean,
)

inline fun previewDataSetScreenState(
useTwoPane: Boolean,
numberOfTabs: Int,
) = DataSetScreenState(
dataSetDetails = DataSetDetails(
titleLabel = "Data set title",
dateLabel = "Jan. 2024",
orgUnitLabel = "Org. Unit",
catOptionComboLabel = "Cat. Option Combo",
),
dataSetSections = buildList {
repeat(numberOfTabs) {
add(
DataSetSection("uid$it", "Section $it"),
)
}
},
useTwoPane = useTwoPane,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.dhis2.mobile.aggregates.model

data class DataSetSection(
val uid: String,
val title: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package org.dhis2.mobile.aggregates.ui

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ScrollableTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.TabRowDefaults
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp
import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing

/**
* Adaptive Tab Row
* Displays a scrollable tab row if the total width of the tabs exceeds the screen width.
* @param modifier Modifier for styling
* @param tabLabels List of tab labels to display
* @param onTabClicked Callback function to be invoked when a tab is clicked
* **/
@Composable
fun AdaptiveTabRow(
modifier: Modifier = Modifier,
tabLabels: List<String>,
onTabClicked: (index: Int) -> Unit,
) {
var selectedTab by remember { mutableStateOf(0) }
val tabWidths = remember { mutableStateListOf<Int>() }
var scrollable by remember { mutableStateOf(false) }

// Calculate total width of tabs
val totalTabWidth = tabWidths.sum()
val screenWidth = with(LocalDensity.current) {
getScreenWidth().roundToPx()
}

LaunchedEffect(key1 = totalTabWidth, key2 = screenWidth) {
// Determine if tabs should be scrollable
scrollable = totalTabWidth > screenWidth
}

// TabRow with conditional behavior
if (false) {
ScrollableTabRow(
modifier = modifier
.height(48.dp)
.fillMaxWidth(),
selectedTabIndex = selectedTab,
containerColor = MaterialTheme.colorScheme.primary,
edgePadding = Spacing.Spacing16,
indicator = { tabPositions ->
TabRowDefaults.PrimaryIndicator(
width = 56.dp,
modifier = Modifier.tabIndicatorOffset(tabPositions[selectedTab]),
color = MaterialTheme.colorScheme.onPrimary,
)
},
divider = {},
) {
tabLabels.forEachIndexed { index, tabLabel ->
Tab(
modifier = Modifier
.height(48.dp)
.onGloballyPositioned { coordinates ->
tabWidths.add(index, coordinates.size.width)
},
selected = selectedTab == index,
onClick = {
selectedTab = index
onTabClicked(index)
},
) {
Text(
text = tabLabel,
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.titleSmall,
)
}
}
}
} else {
TabRow(
modifier = modifier
.height(48.dp)
.fillMaxWidth(),
selectedTabIndex = selectedTab,
containerColor = MaterialTheme.colorScheme.primary,
indicator = { tabPositions ->
TabRowDefaults.PrimaryIndicator(
width = 56.dp,
modifier = Modifier.tabIndicatorOffset(tabPositions[selectedTab]),
color = MaterialTheme.colorScheme.onPrimary,
)
},
divider = {},
) {
tabLabels.forEachIndexed { index, tabLabel ->
Tab(
modifier = Modifier
.height(48.dp)
.onGloballyPositioned { coordinates ->
tabWidths.add(index, coordinates.size.width)
},
selected = selectedTab == index,
onClick = {
selectedTab = index
onTabClicked(index)
},
) {
Text(
text = tabLabel,
color = MaterialTheme.colorScheme.onPrimary,
style = MaterialTheme.typography.titleSmall,
)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.dhis2.mobile.aggregates.ui

import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountTree
import androidx.compose.material.icons.filled.CalendarMonth
import androidx.compose.material.icons.filled.Category
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import org.dhis2.mobile.aggregates.model.DataSetDetails
import org.hisp.dhis.mobile.ui.designsystem.component.AssistChip
import org.hisp.dhis.mobile.ui.designsystem.component.Tag
import org.hisp.dhis.mobile.ui.designsystem.component.TagType
import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing

@Composable
internal fun DataSetDetails(
modifier: Modifier = Modifier,
editable: Boolean = false,
dataSetDetails: DataSetDetails,
) {
LazyRow(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = spacedBy(Spacing.Spacing8),
) {
item {
if (editable) {
AssistChip(
label = dataSetDetails.dateLabel,
icon = {
Icon(
imageVector = Icons.Filled.CalendarMonth,
contentDescription = "",
)
},
onClick = {
/*not yet supported*/
},
)
} else {
Tag(
label = dataSetDetails.dateLabel,
type = TagType.DEFAULT,
)
}
}

item {
if (editable) {
AssistChip(
label = dataSetDetails.orgUnitLabel,
icon = {
Icon(
imageVector = Icons.Filled.AccountTree,
contentDescription = "",
)
},
onClick = {
/*not yet supported*/
},
)
} else {
Tag(
label = dataSetDetails.orgUnitLabel,
type = TagType.DEFAULT,
)
}
}

item {
if (editable) {
AssistChip(
label = dataSetDetails.catOptionComboLabel,
icon = {
Icon(
imageVector = Icons.Filled.Category,
contentDescription = "",
)
},
onClick = {
/*not yet supported*/
},
)
} else {
Tag(
label = dataSetDetails.catOptionComboLabel,
type = TagType.DEFAULT,
)
}
}
}
}
Loading

0 comments on commit 856179c

Please sign in to comment.