Skip to content

Commit

Permalink
WTA #71 initial setup for stats cards in project details page
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacob3075 committed Dec 4, 2024
1 parent 17aebcd commit 5feeb3b
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.BaselineShift
Expand All @@ -45,6 +46,7 @@ fun StatsChip(
onClick: () -> Unit,
roundedCornerPercent: Int,
modifier: Modifier = Modifier,
statValueTextStyle: TextStyle = MaterialTheme.typography.displayLarge,
) {
val gradientBrush = Brush.horizontalGradient(gradient.colorList)
val shape = RoundedCornerShape(roundedCornerPercent)
Expand All @@ -68,18 +70,17 @@ fun StatsChip(
.size(size = 50.dp)
.align(Alignment.BottomEnd),
)
// TODO: UPDATE TO USE SLOTS API
Column(
modifier = Modifier
.padding(
horizontal = MaterialTheme.spacing.medium,
vertical = MaterialTheme.spacing.small,
),
) {
val streakValueTextStyle = MaterialTheme.typography.displayLarge

Text(
text = buildAnnotatedString {
withStyle(style = streakValueTextStyle.toSpanStyle()) {
withStyle(style = statValueTextStyle.toSpanStyle()) {
append(statsValue)
}
withStyle(
Expand All @@ -91,7 +92,7 @@ fun StatsChip(
}
},
color = gradient.onStartColor,
modifier = Modifier.removeFontPadding(streakValueTextStyle),
modifier = Modifier.removeFontPadding(statValueTextStyle),
)
Text(
text = statsType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,8 @@ private fun DetailsPageLoaded(viewState: DetailsPageViewState.Loaded, today: Loc
state = pagerState,
beyondBoundsPageCount = 1,
) { page ->
viewState.statsForProject
when (pages[page]) {
Tabs.Time -> TimeTab(statsForProject = viewState.statsForProject, today)
Tabs.Time -> TimeTab(detailsPageData = viewState, today)
Tabs.Languages -> LanguagesTab()
Tabs.Editors -> EditorsTab()
Tabs.OperatingSystems -> OperatingSystemsTab()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import com.jacob.wakatimeapp.core.ui.theme.WakaTimeAppTheme
import com.jacob.wakatimeapp.core.ui.theme.cardHeader
import com.jacob.wakatimeapp.core.ui.theme.cardSubtitle
import com.jacob.wakatimeapp.core.ui.theme.spacing
import kotlinx.collections.immutable.ImmutableMap
import com.jacob.wakatimeapp.details.ui.DetailsPageViewState
import kotlinx.datetime.LocalDate
import kotlinx.datetime.format
import kotlinx.datetime.format.DayOfWeekNames
Expand All @@ -29,13 +29,13 @@ import java.util.Comparator.comparing
private const val BaseYear = 2000

internal fun LazyListScope.projectHistory(
statsForProject: ImmutableMap<LocalDate, Time>,
detailsPageData: DetailsPageViewState.Loaded,
) {
item {
Text(text = "Project History", modifier = Modifier.padding(vertical = MaterialTheme.spacing.extraSmall))
}
items(
items = statsForProject.filter { it.value != Time.ZERO }
items = detailsPageData.statsForProject.filter { it.value != Time.ZERO }
.toSortedMap(comparing { -it.toEpochDays() })
.toList(),
key = { it.first.toEpochDays() },
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package com.jacob.wakatimeapp.details.ui.components

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.width
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.jacob.wakatimeapp.core.models.Time
import com.jacob.wakatimeapp.core.ui.WtaPreviews
import com.jacob.wakatimeapp.core.ui.components.cards.StatsChip
import com.jacob.wakatimeapp.core.ui.theme.WakaTimeAppTheme
import com.jacob.wakatimeapp.core.ui.theme.assets
import com.jacob.wakatimeapp.core.ui.theme.gradients
import com.jacob.wakatimeapp.core.ui.theme.spacing
import com.jacob.wakatimeapp.details.ui.DetailsPageViewState
import kotlinx.collections.immutable.toImmutableMap
import kotlinx.datetime.LocalDate
import kotlinx.datetime.format
import kotlinx.datetime.format.DayOfWeekNames
import kotlinx.datetime.format.MonthNames
import kotlinx.datetime.format.char

@Composable
internal fun QuickStatsCards(detailsPageData: DetailsPageViewState.Loaded) {
val totalTime = remember(detailsPageData) { detailsPageData.statsForProject.values.fold(Time.ZERO, Time::plus) }
val averageTime =
remember(detailsPageData) { Time.fromDecimal(totalTime.decimal.div(detailsPageData.statsForProject.size)) }
val startDate = remember(detailsPageData) { detailsPageData.statsForProject.keys.minBy(LocalDate::toEpochDays) }
val numberOfDaysWorked =
remember(detailsPageData) { detailsPageData.statsForProject.values.filter { it != Time.ZERO }.size }

Column(
Modifier.fillMaxWidth(),
Arrangement.spacedBy(MaterialTheme.spacing.sMedium),
) {
StatsChip(
statsType = "Total Time on Project",
statsValue = totalTime.formattedPrint(),
statsValueSubText = "",
gradient = MaterialTheme.gradients.amin,
iconId = MaterialTheme.assets.icons.time,
onClick = {},
roundedCornerPercent = 15,
)
StatsChip(
statsType = "Average Time",
statsValue = averageTime.formattedPrint(),
statsValueSubText = "",
gradient = MaterialTheme.gradients.purpink,
iconId = MaterialTheme.assets.icons.time,
onClick = {},
roundedCornerPercent = 15,
)
Row(modifier = Modifier.fillMaxWidth()) {
val format = LocalDate.Format {
dayOfWeek(DayOfWeekNames.ENGLISH_ABBREVIATED)
chars(", ")
monthName(MonthNames.ENGLISH_ABBREVIATED)
char(' ')
dayOfMonth()
chars(", ")
yearTwoDigits(1960)
}
StatsChip(
statsType = "Start date",
statsValue = startDate.format(format),
statsValueSubText = "",
gradient = MaterialTheme.gradients.quepal,
iconId = MaterialTheme.assets.icons.time,
onClick = {},
roundedCornerPercent = 15,
statValueTextStyle = MaterialTheme.typography.titleMedium,
modifier = Modifier.weight(1f),
)
Spacer(modifier = Modifier.width(MaterialTheme.spacing.small))
StatsChip(
statsType = "No. of days worked",
statsValue = numberOfDaysWorked.toString(),
statsValueSubText = "",
gradient = MaterialTheme.gradients.tealLove,
iconId = MaterialTheme.assets.icons.time,
onClick = {},
roundedCornerPercent = 15,
statValueTextStyle = MaterialTheme.typography.titleMedium,
modifier = Modifier.weight(1f),
)
}
Row(modifier = Modifier.fillMaxWidth()) {
// expandable cards
// could replace tabs?
// when clicking on one of the cards will expand that card and shrink the other
// will expand in both X and Y, show pie chart after expanding
// before clicking/expanding
// 🟥 🟦
// 🟧 🟪
// after clicking/expanding
// 🟥🟥
// 🟥🟥
Text("Most used language")
Text("Most used editor")
Text("Most used os")
Text("Most used machine")
}
}
}

@WtaPreviews
@Composable
private fun ProjectHistoryListPreview() {
WakaTimeAppTheme {
Surface(modifier = Modifier.fillMaxSize()) {
QuickStatsCards(
DetailsPageViewState.Loaded(
"",
mapOf(
LocalDate.fromEpochDays(1) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(2) to Time.fromDecimal(1f),
LocalDate.fromEpochDays(3) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(4) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(5) to Time.fromDecimal(4f),
LocalDate.fromEpochDays(6) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(7) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(8) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(9) to Time.fromDecimal(4f),
LocalDate.fromEpochDays(10) to Time.fromDecimal(1f),
).toImmutableMap(),
),
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.jacob.wakatimeapp.core.models.Time
import com.jacob.wakatimeapp.core.ui.WtaComponentPreviews
import com.jacob.wakatimeapp.core.ui.WtaPreviews
import com.jacob.wakatimeapp.core.ui.components.VicoBarChart
import com.jacob.wakatimeapp.core.ui.components.VicoBarChartData
import com.jacob.wakatimeapp.core.ui.theme.WakaTimeAppTheme
import com.jacob.wakatimeapp.core.ui.theme.spacing
import kotlinx.collections.immutable.ImmutableMap
import com.jacob.wakatimeapp.details.ui.DetailsPageViewState
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toImmutableMap
import kotlinx.datetime.Clock
Expand All @@ -29,26 +28,21 @@ import kotlinx.datetime.toLocalDateTime
private const val DaysInChart = 30

@Composable
internal fun TimeTab(statsForProject: ImmutableMap<LocalDate, Time>, today: LocalDate, modifier: Modifier = Modifier) {
internal fun TimeTab(detailsPageData: DetailsPageViewState.Loaded, today: LocalDate, modifier: Modifier = Modifier) {
LazyColumn(
verticalArrangement = Arrangement.spacedBy(MaterialTheme.spacing.small),
modifier = modifier
.fillMaxSize()
.padding(horizontal = MaterialTheme.spacing.sMedium),
) {
item { RecentTimeSpentChart(statsForProject, today) }
item { QuickStatsCards() }
projectHistory(statsForProject)
item { RecentTimeSpentChart(detailsPageData, today) }
item { QuickStatsCards(detailsPageData) }
projectHistory(detailsPageData)
}
}

@Composable
private fun QuickStatsCards() {
Text(text = "Quick Stats Cards")
}

@Composable
private fun RecentTimeSpentChart(weeklyTimeSpent: ImmutableMap<LocalDate, Time>, today: LocalDate) = Surface(
private fun RecentTimeSpentChart(detailsPageData: DetailsPageViewState.Loaded, today: LocalDate) = Surface(
modifier = Modifier
.padding(horizontal = MaterialTheme.spacing.small)
.padding(top = MaterialTheme.spacing.sMedium)
Expand All @@ -58,32 +52,35 @@ private fun RecentTimeSpentChart(weeklyTimeSpent: ImmutableMap<LocalDate, Time>,
tonalElevation = 2.dp,
) {
VicoBarChart(
timeData = weeklyTimeSpent.values.toMutableList().takeLast(DaysInChart).toImmutableList(),
timeData = detailsPageData.statsForProject.values.toMutableList().takeLast(DaysInChart).toImmutableList(),
xAxisFormatter = VicoBarChartData.getDefaultXAxisFormatter(today, skipCount = 5),
modifier = Modifier.padding(MaterialTheme.spacing.small),
columnWidth = 30f,
showLabel = false,
)
}

@WtaComponentPreviews
@WtaPreviews
@Composable
private fun ProjectHistoryListPreview() {
WakaTimeAppTheme {
Surface {
TimeTab(
mapOf(
LocalDate.fromEpochDays(1) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(2) to Time.fromDecimal(1f),
LocalDate.fromEpochDays(3) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(4) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(5) to Time.fromDecimal(4f),
LocalDate.fromEpochDays(6) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(7) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(8) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(9) to Time.fromDecimal(4f),
LocalDate.fromEpochDays(10) to Time.fromDecimal(1f),
).toImmutableMap(),
DetailsPageViewState.Loaded(
"",
mapOf(
LocalDate.fromEpochDays(1) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(2) to Time.fromDecimal(1f),
LocalDate.fromEpochDays(3) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(4) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(5) to Time.fromDecimal(4f),
LocalDate.fromEpochDays(6) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(7) to Time.fromDecimal(2f),
LocalDate.fromEpochDays(8) to Time.fromDecimal(3f),
LocalDate.fromEpochDays(9) to Time.fromDecimal(4f),
LocalDate.fromEpochDays(10) to Time.fromDecimal(1f),
).toImmutableMap(),
),
today = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date,
)
}
Expand Down

0 comments on commit 5feeb3b

Please sign in to comment.