fix(stats): fix crash when opening last week screen with empty stats table
This commit is contained in:
@@ -21,6 +21,7 @@ import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||
@@ -33,6 +34,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -41,13 +43,19 @@ import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/**
|
||||
* A custom implementation of the 1-Dimensional heatmap plot that varies the width of the cells
|
||||
* instead of the colors. The colors are varied according to the `maxIndex` value passed but they do
|
||||
* NOT correspond to the actual values represented by the cells, and exist for aesthetic reasons
|
||||
* only.
|
||||
* A "Horizontal stacked bar" component, which can be considered as a horizontal stacked bar chart
|
||||
* with a single bar. This component can be stacked in a column to create a "100% stacked bar chart"
|
||||
* where each bar is the same length to easily visualize proportions of each type of value
|
||||
* represented
|
||||
*
|
||||
* @param values Values to be represented by the bar
|
||||
* @param rankList A list of the rank of each element if the list was sorted in a non-increasing
|
||||
* order
|
||||
* @param height Height of the bar
|
||||
* @param gap Gap between each part of the bar
|
||||
*/
|
||||
@Composable
|
||||
fun VariableWidth1DHeatmap(
|
||||
fun HorizontalStackedBar(
|
||||
values: List<Long>,
|
||||
modifier: Modifier = Modifier,
|
||||
rankList: List<Int> = remember(values) {
|
||||
@@ -112,60 +120,70 @@ fun FocusBreakRatioVisualization(
|
||||
height: Dp = 40.dp,
|
||||
gap: Dp = 2.dp
|
||||
) {
|
||||
val focusPercentage = ((focusDuration / (focusDuration.toFloat() + breakDuration)) * 100)
|
||||
val breakPercentage = ((breakDuration / (focusDuration.toFloat() + breakDuration)) * 100)
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(gap),
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(
|
||||
text = focusPercentage.roundToInt().toString() + '%',
|
||||
style = typography.bodyLarge,
|
||||
color = colorScheme.primary,
|
||||
modifier = Modifier.padding(end = 6.dp)
|
||||
)
|
||||
Spacer(
|
||||
Modifier
|
||||
.weight(focusPercentage)
|
||||
.height(height)
|
||||
.background(
|
||||
colorScheme.primary,
|
||||
shapes.large.copy(
|
||||
topEnd = shapes.extraSmall.topEnd,
|
||||
bottomEnd = shapes.extraSmall.bottomEnd
|
||||
if (focusDuration + breakDuration > 0) {
|
||||
val focusPercentage = ((focusDuration / (focusDuration.toFloat() + breakDuration)) * 100)
|
||||
val breakPercentage = 100 - focusPercentage
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(gap),
|
||||
modifier = modifier
|
||||
) {
|
||||
Text(
|
||||
text = focusPercentage.roundToInt().toString() + '%',
|
||||
style = typography.bodyLarge,
|
||||
color = colorScheme.primary,
|
||||
modifier = Modifier.padding(end = 6.dp)
|
||||
)
|
||||
if (focusDuration > 0) Spacer(
|
||||
Modifier
|
||||
.weight(focusPercentage)
|
||||
.height(height)
|
||||
.background(
|
||||
colorScheme.primary,
|
||||
if (breakDuration > 0) shapes.large.copy(
|
||||
topEnd = shapes.extraSmall.topEnd,
|
||||
bottomEnd = shapes.extraSmall.bottomEnd
|
||||
) else shapes.large
|
||||
)
|
||||
)
|
||||
)
|
||||
Spacer(
|
||||
Modifier
|
||||
.weight(breakPercentage)
|
||||
.height(height)
|
||||
.background(
|
||||
colorScheme.tertiary,
|
||||
shapes.large.copy(
|
||||
topStart = shapes.extraSmall.topStart,
|
||||
bottomStart = shapes.extraSmall.bottomStart
|
||||
)
|
||||
if (breakDuration > 0) Spacer(
|
||||
Modifier
|
||||
.weight(breakPercentage)
|
||||
.height(height)
|
||||
.background(
|
||||
colorScheme.tertiary,
|
||||
if (focusDuration > 0) shapes.large.copy(
|
||||
topStart = shapes.extraSmall.topStart,
|
||||
bottomStart = shapes.extraSmall.bottomStart
|
||||
) else shapes.large
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
Text(
|
||||
text = breakPercentage.roundToInt().toString() + '%',
|
||||
style = typography.bodyLarge,
|
||||
color = colorScheme.tertiary,
|
||||
modifier = Modifier.padding(start = 6.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Text(
|
||||
text = breakPercentage.roundToInt().toString() + '%',
|
||||
text = "Not enough data",
|
||||
style = typography.bodyLarge,
|
||||
color = colorScheme.tertiary,
|
||||
modifier = Modifier.padding(start = 6.dp)
|
||||
color = colorScheme.outline,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun VariableWidth1DHeatmapPreview() {
|
||||
fun HorizontalStackedBarPreview() {
|
||||
val values = listOf(38L, 190L, 114L, 14L)
|
||||
val rankList = listOf(2, 0, 1, 3)
|
||||
TomatoTheme(dynamicColor = false) {
|
||||
Surface {
|
||||
VariableWidth1DHeatmap(
|
||||
HorizontalStackedBar(
|
||||
values = values,
|
||||
rankList = rankList,
|
||||
modifier = Modifier.padding(16.dp),
|
||||
|
||||
@@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
@@ -57,8 +58,8 @@ import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
||||
import org.nsh07.pomodoro.R
|
||||
import org.nsh07.pomodoro.ui.mergePaddingValues
|
||||
import org.nsh07.pomodoro.ui.statsScreen.components.FocusBreakRatioVisualization
|
||||
import org.nsh07.pomodoro.ui.statsScreen.components.HorizontalStackedBar
|
||||
import org.nsh07.pomodoro.ui.statsScreen.components.TimeColumnChart
|
||||
import org.nsh07.pomodoro.ui.statsScreen.components.VariableWidth1DHeatmap
|
||||
import org.nsh07.pomodoro.ui.statsScreen.components.sharedBoundsReveal
|
||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
||||
import org.nsh07.pomodoro.ui.theme.TomatoShapeDefaults.topListItemShape
|
||||
@@ -213,7 +214,7 @@ fun SharedTransitionScope.LastWeekScreen(
|
||||
color = colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
item { VariableWidth1DHeatmap(lastWeekAnalysisValues.first, rankList = rankList) }
|
||||
item { HorizontalStackedBar(lastWeekAnalysisValues.first, rankList = rankList) }
|
||||
item {
|
||||
Row {
|
||||
lastWeekAnalysisValues.first.fastForEach {
|
||||
@@ -260,6 +261,16 @@ fun SharedTransitionScope.LastWeekScreen(
|
||||
}
|
||||
item {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||
Row {
|
||||
Spacer(Modifier.width(18.dp))
|
||||
(0..8 step 2).forEach {
|
||||
Text(
|
||||
(it * 10).toString() + '%',
|
||||
style = typography.labelSmall,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
lastWeekSummaryValues.fastForEach {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(
|
||||
@@ -267,7 +278,7 @@ fun SharedTransitionScope.LastWeekScreen(
|
||||
style = typography.labelSmall,
|
||||
modifier = Modifier.size(18.dp)
|
||||
)
|
||||
VariableWidth1DHeatmap(it.second, rankList = rankList)
|
||||
HorizontalStackedBar(it.second, rankList = rankList)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user