refactor(stats): make focus breakdown tooltip a separate fun

This commit is contained in:
Nishant Mishra
2025-12-18 22:48:39 +05:30
parent d3e9bb79fb
commit d9fb10388f
3 changed files with 107 additions and 118 deletions

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2025 Nishant Mishra
*
* This file is part of Tomato - a minimalist pomodoro timer for Android.
*
* Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Tomato.
* If not, see <https://www.gnu.org/licenses/>.
*/
package org.nsh07.pomodoro.ui.statsScreen.components
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.MaterialTheme.shapes
import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Popup
import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.data.Stat
import org.nsh07.pomodoro.utils.millisecondsToHoursMinutes
import java.time.format.DateTimeFormatter
import kotlin.math.roundToInt
@Composable
fun FocusBreakdownTooltip(
item: Stat,
rankList: List<Int>,
dateFormat: DateTimeFormatter,
onDismissRequest: (() -> Unit)
) {
val tooltipOffset = with(LocalDensity.current) {
(16 * 2 + // Vertical padding in the tooltip card
typography.titleSmall.lineHeight.value + 4 + // Heading
typography.bodyMedium.lineHeight.value + 8 + // Text
HORIZONTAL_STACKED_BAR_HEIGHT.value + // Obvious
8).dp.toPx().roundToInt()
}
val values = listOf(
item.focusTimeQ1,
item.focusTimeQ2,
item.focusTimeQ3,
item.focusTimeQ4
)
Popup(
alignment = Alignment.TopCenter,
offset = IntOffset(0, -tooltipOffset),
onDismissRequest = onDismissRequest
) {
Surface(
shape = shapes.large,
color = colorScheme.surfaceContainer,
contentColor = colorScheme.onSurfaceVariant,
shadowElevation = 3.dp,
tonalElevation = 3.dp,
modifier = Modifier.padding(horizontal = 16.dp)
) {
Column(Modifier.padding(16.dp)) {
Text(
text = item.date.format(dateFormat),
style = typography.titleSmall
)
Spacer(Modifier.height(4.dp))
Text(
text = millisecondsToHoursMinutes(
item.totalFocusTime(),
stringResource(R.string.hours_and_minutes_format)
),
style = typography.bodyMedium
)
Spacer(Modifier.height(8.dp))
HorizontalStackedBar(
values = values,
rankList = rankList
)
}
}
}
}

View File

@@ -24,7 +24,6 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
@@ -46,28 +45,21 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastForEachIndexed
import androidx.compose.ui.window.Popup
import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.data.Stat
import org.nsh07.pomodoro.ui.theme.TomatoTheme
import org.nsh07.pomodoro.utils.millisecondsToHoursMinutes
import java.time.DayOfWeek
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.time.format.TextStyle
import java.util.Locale
import kotlin.math.roundToInt
import kotlin.random.Random
val CALENDAR_CELL_SIZE = 40.dp
@@ -123,14 +115,6 @@ fun FocusHistoryCalendar(
DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(locale)
}
val tooltipOffset = with(LocalDensity.current) {
(16 * 2 + // Vertical padding in the tooltip card
typography.titleSmall.lineHeight.value + 4 + // Heading
typography.bodyMedium.lineHeight.value + 8 + // Text
HORIZONTAL_STACKED_BAR_HEIGHT.value + // Obvious
8).dp.toPx().roundToInt()
}
val groupedData = remember(data) {
data.chunked(7)
}
@@ -220,48 +204,11 @@ fun FocusHistoryCalendar(
)
if (isTooltipVisible) {
val values = remember(it) {
listOf(
it.focusTimeQ1,
it.focusTimeQ2,
it.focusTimeQ3,
it.focusTimeQ4
)
}
Popup(
alignment = Alignment.TopCenter,
offset = IntOffset(0, -tooltipOffset),
onDismissRequest = { selectedItemIndex = -1 }
) {
Surface(
shape = shapes.large,
color = colorScheme.surfaceContainer,
contentColor = colorScheme.onSurfaceVariant,
shadowElevation = 3.dp,
tonalElevation = 3.dp,
modifier = Modifier.padding(horizontal = 16.dp)
) {
Column(Modifier.padding(16.dp)) {
Text(
text = it.date.format(dateFormat),
style = typography.titleSmall
)
Spacer(Modifier.height(4.dp))
Text(
text = millisecondsToHoursMinutes(
sum,
stringResource(R.string.hours_and_minutes_format)
),
style = typography.bodyMedium
)
Spacer(Modifier.height(8.dp))
HorizontalStackedBar(
values = values,
rankList = averageRankList
)
}
}
}
FocusBreakdownTooltip(
it,
averageRankList,
dateFormat
) { selectedItemIndex = -1 }
}
}
}

View File

@@ -47,26 +47,19 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastMaxBy
import androidx.compose.ui.window.Popup
import org.nsh07.pomodoro.R
import org.nsh07.pomodoro.data.Stat
import org.nsh07.pomodoro.ui.theme.TomatoTheme
import org.nsh07.pomodoro.utils.millisecondsToHoursMinutes
import java.time.DayOfWeek
import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
import java.time.format.TextStyle
import java.util.Locale
import kotlin.math.roundToInt
val HEATMAP_CELL_SIZE = 28.dp
val HEATMAP_CELL_GAP = 2.dp
@@ -109,14 +102,6 @@ fun HeatmapWithWeekLabels(
}
} // Names of the 7 days of the week in the current locale
val tooltipOffset = with(LocalDensity.current) {
(16 * 2 + // Vertical padding in the tooltip card
typography.titleSmall.lineHeight.value + 4 + // Heading
typography.bodyMedium.lineHeight.value + 8 + // Text
HORIZONTAL_STACKED_BAR_HEIGHT.value + // Obvious
8).dp.toPx().roundToInt()
}
val dateFormat = remember(locale) {
DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).withLocale(locale)
}
@@ -186,51 +171,11 @@ fun HeatmapWithWeekLabels(
.clickable { activeTooltipIndex = index }
) {
if (isTooltipVisible) {
val values = remember(it) {
listOf(
it.focusTimeQ1,
it.focusTimeQ2,
it.focusTimeQ3,
it.focusTimeQ4
)
}
Popup(
alignment = Alignment.TopCenter,
offset = IntOffset(0, -tooltipOffset),
onDismissRequest = {
activeTooltipIndex = -1
}
) {
Surface(
shape = shapes.large,
color = colorScheme.surfaceContainer,
contentColor = colorScheme.onSurfaceVariant,
shadowElevation = 3.dp,
tonalElevation = 3.dp,
modifier = Modifier.padding(horizontal = 16.dp)
) {
Column(Modifier.padding(16.dp)) {
Text(
text = it.date.format(dateFormat),
style = typography.titleSmall
)
Spacer(Modifier.height(4.dp))
Text(
text = millisecondsToHoursMinutes(
sum,
stringResource(R.string.hours_and_minutes_format)
),
style = typography.bodyMedium
)
Spacer(Modifier.height(8.dp))
HorizontalStackedBar(
values = values,
rankList = averageRankList
)
}
}
}
FocusBreakdownTooltip(
it,
averageRankList,
dateFormat
) { activeTooltipIndex = -1 }
}
}
}