feat: Add stats for the current day, update typography
The arrow button can be used to get a detailed analysis of the focus durations
This commit is contained in:
@@ -1,3 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Nishant Mishra
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.nsh07.pomodoro.ui.settingsScreen
|
package org.nsh07.pomodoro.ui.settingsScreen
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
@@ -52,7 +59,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import org.nsh07.pomodoro.R
|
import org.nsh07.pomodoro.R
|
||||||
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel
|
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel
|
||||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTitle
|
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
||||||
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@@ -106,7 +113,7 @@ private fun SettingsScreen(
|
|||||||
Text(
|
Text(
|
||||||
"Settings",
|
"Settings",
|
||||||
style = LocalTextStyle.current.copy(
|
style = LocalTextStyle.current.copy(
|
||||||
fontFamily = robotoFlexTitle,
|
fontFamily = robotoFlexTopBar,
|
||||||
fontSize = 32.sp,
|
fontSize = 32.sp,
|
||||||
lineHeight = 32.sp
|
lineHeight = 32.sp
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,18 +7,41 @@
|
|||||||
|
|
||||||
package org.nsh07.pomodoro.ui.statsScreen
|
package org.nsh07.pomodoro.ui.statsScreen
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
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
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
|
import androidx.compose.material3.FilledTonalIconToggleButton
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButtonDefaults
|
||||||
import androidx.compose.material3.LocalTextStyle
|
import androidx.compose.material3.LocalTextStyle
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||||
|
import androidx.compose.material3.MaterialTheme.motionScheme
|
||||||
import androidx.compose.material3.MaterialTheme.typography
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.rotate
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.tooling.preview.Devices
|
import androidx.compose.ui.tooling.preview.Devices
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -27,17 +50,23 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
|||||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||||
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.nsh07.pomodoro.R
|
||||||
|
import org.nsh07.pomodoro.data.Stat
|
||||||
import org.nsh07.pomodoro.ui.statsScreen.viewModel.StatsViewModel
|
import org.nsh07.pomodoro.ui.statsScreen.viewModel.StatsViewModel
|
||||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTitle
|
import org.nsh07.pomodoro.ui.theme.AppFonts.openRundeClock
|
||||||
|
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
||||||
|
import org.nsh07.pomodoro.utils.millisecondsToHoursMinutes
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun StatsScreenRoot(
|
fun StatsScreenRoot(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: StatsViewModel = viewModel(factory = StatsViewModel.Factory)
|
viewModel: StatsViewModel = viewModel(factory = StatsViewModel.Factory)
|
||||||
) {
|
) {
|
||||||
val allStatsSummaryModelProducer = viewModel.allStatsSummaryModelProducer
|
val todayStat by viewModel.todayStat.collectAsState(null)
|
||||||
StatsScreen(
|
StatsScreen(
|
||||||
allStatsSummaryModelProducer = allStatsSummaryModelProducer,
|
allStatsSummaryModelProducer = viewModel.allStatsSummaryModelProducer,
|
||||||
|
todayStatModelProducer = viewModel.todayStatModelProducer,
|
||||||
|
todayStat = todayStat,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -46,25 +75,150 @@ fun StatsScreenRoot(
|
|||||||
@Composable
|
@Composable
|
||||||
fun StatsScreen(
|
fun StatsScreen(
|
||||||
allStatsSummaryModelProducer: CartesianChartModelProducer,
|
allStatsSummaryModelProducer: CartesianChartModelProducer,
|
||||||
|
todayStatModelProducer: CartesianChartModelProducer,
|
||||||
|
todayStat: Stat?,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
Column(modifier) {
|
var todayStatExpanded by rememberSaveable { mutableStateOf(false) }
|
||||||
TopAppBar(
|
|
||||||
title = {
|
LazyColumn(
|
||||||
Text(
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
"Stats",
|
modifier = modifier
|
||||||
style = LocalTextStyle.current.copy(
|
) {
|
||||||
fontFamily = robotoFlexTitle,
|
item {
|
||||||
fontSize = 32.sp,
|
TopAppBar(
|
||||||
lineHeight = 32.sp
|
title = {
|
||||||
|
Text(
|
||||||
|
"Stats",
|
||||||
|
style = LocalTextStyle.current.copy(
|
||||||
|
fontFamily = robotoFlexTopBar,
|
||||||
|
fontSize = 32.sp,
|
||||||
|
lineHeight = 32.sp
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
},
|
||||||
},
|
subtitle = {},
|
||||||
subtitle = {},
|
titleHorizontalAlignment = Alignment.CenterHorizontally
|
||||||
titleHorizontalAlignment = Alignment.CenterHorizontally
|
)
|
||||||
)
|
}
|
||||||
Text("This week", style = typography.headlineSmall, modifier = Modifier.padding(16.dp))
|
item {
|
||||||
TimeColumnChart(allStatsSummaryModelProducer, modifier = Modifier.padding(start = 16.dp))
|
Text(
|
||||||
|
"Today",
|
||||||
|
style = typography.headlineSmall,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
Row(modifier = Modifier.padding(horizontal = 16.dp)) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
colorScheme.primaryContainer,
|
||||||
|
MaterialTheme.shapes.largeIncreased
|
||||||
|
)
|
||||||
|
.weight(1f)
|
||||||
|
) {
|
||||||
|
Column(Modifier.padding(16.dp)) {
|
||||||
|
Text(
|
||||||
|
"Focus",
|
||||||
|
style = typography.titleMedium,
|
||||||
|
color = colorScheme.onPrimaryContainer
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
if (todayStat != null) remember(todayStat) {
|
||||||
|
millisecondsToHoursMinutes(
|
||||||
|
todayStat.focusTimeQ1 +
|
||||||
|
todayStat.focusTimeQ2 +
|
||||||
|
todayStat.focusTimeQ3 +
|
||||||
|
todayStat.focusTimeQ4
|
||||||
|
)
|
||||||
|
} else "0h 0m",
|
||||||
|
style = typography.displaySmall,
|
||||||
|
fontFamily = openRundeClock,
|
||||||
|
color = colorScheme.onPrimaryContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(
|
||||||
|
colorScheme.tertiaryContainer,
|
||||||
|
MaterialTheme.shapes.largeIncreased
|
||||||
|
)
|
||||||
|
.weight(1f)
|
||||||
|
) {
|
||||||
|
Column(Modifier.padding(16.dp)) {
|
||||||
|
Text(
|
||||||
|
"Break",
|
||||||
|
style = typography.titleMedium,
|
||||||
|
color = colorScheme.onTertiaryContainer
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
if (todayStat != null) remember(todayStat) {
|
||||||
|
millisecondsToHoursMinutes(todayStat.breakTime)
|
||||||
|
} else "0h 0m",
|
||||||
|
style = typography.displaySmall,
|
||||||
|
fontFamily = openRundeClock,
|
||||||
|
color = colorScheme.onTertiaryContainer
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
val iconRotation by animateFloatAsState(
|
||||||
|
if (todayStatExpanded) 180f else 0f,
|
||||||
|
animationSpec = motionScheme.defaultSpatialSpec()
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
FilledTonalIconToggleButton(
|
||||||
|
checked = todayStatExpanded,
|
||||||
|
onCheckedChange = { todayStatExpanded = it },
|
||||||
|
shapes = IconButtonDefaults.toggleableShapes(),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.width(52.dp)
|
||||||
|
.align(Alignment.End)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.arrow_down),
|
||||||
|
"More info",
|
||||||
|
modifier = Modifier.rotate(iconRotation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AnimatedVisibility(todayStatExpanded) {
|
||||||
|
TimeColumnChart(
|
||||||
|
todayStatModelProducer,
|
||||||
|
timeConverter = ::millisecondsToHoursMinutes,
|
||||||
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
Text(
|
||||||
|
"This week",
|
||||||
|
style = typography.headlineSmall,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
|
}
|
||||||
|
item {
|
||||||
|
TimeColumnChart(
|
||||||
|
allStatsSummaryModelProducer,
|
||||||
|
modifier = Modifier.padding(start = 16.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,11 +232,15 @@ fun StatsScreenPreview() {
|
|||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
modelProducer.runTransaction {
|
modelProducer.runTransaction {
|
||||||
columnSeries { series(5, 6) }
|
columnSeries {
|
||||||
|
series(5, 6, 5, 2, 11, 8, 5, 2, 15, 11, 8, 13, 12, 10, 2, 7)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StatsScreen(
|
StatsScreen(
|
||||||
allStatsSummaryModelProducer = modelProducer
|
modelProducer,
|
||||||
|
modelProducer,
|
||||||
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ package org.nsh07.pomodoro.ui.statsScreen
|
|||||||
import android.graphics.Path
|
import android.graphics.Path
|
||||||
import android.graphics.RectF
|
import android.graphics.RectF
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.MaterialTheme.motionScheme
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
|
import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost
|
||||||
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottom
|
import com.patrykandpatrick.vico.compose.cartesian.axis.rememberBottom
|
||||||
@@ -40,9 +40,11 @@ import org.nsh07.pomodoro.utils.millisecondsToHours
|
|||||||
internal fun TimeColumnChart(
|
internal fun TimeColumnChart(
|
||||||
modelProducer: CartesianChartModelProducer,
|
modelProducer: CartesianChartModelProducer,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
thickness: Dp = 40.dp,
|
||||||
|
timeConverter: (Long) -> String = ::millisecondsToHours
|
||||||
) {
|
) {
|
||||||
val radius = with(LocalDensity.current) {
|
val radius = with(LocalDensity.current) {
|
||||||
(48.dp / 2).toPx()
|
(thickness / 2).toPx()
|
||||||
}
|
}
|
||||||
ProvideVicoTheme(rememberM3VicoTheme()) {
|
ProvideVicoTheme(rememberM3VicoTheme()) {
|
||||||
CartesianChartHost(
|
CartesianChartHost(
|
||||||
@@ -53,7 +55,7 @@ internal fun TimeColumnChart(
|
|||||||
vicoTheme.columnCartesianLayerColors.map { color ->
|
vicoTheme.columnCartesianLayerColors.map { color ->
|
||||||
rememberLineComponent(
|
rememberLineComponent(
|
||||||
fill = fill(color),
|
fill = fill(color),
|
||||||
thickness = 48.dp,
|
thickness = thickness,
|
||||||
shape = { _, path, left, top, right, bottom ->
|
shape = { _, path, left, top, right, bottom ->
|
||||||
if (top + radius <= bottom - radius) {
|
if (top + radius <= bottom - radius) {
|
||||||
path.arcTo(
|
path.arcTo(
|
||||||
@@ -87,21 +89,21 @@ internal fun TimeColumnChart(
|
|||||||
tick = rememberLineComponent(Fill.Transparent),
|
tick = rememberLineComponent(Fill.Transparent),
|
||||||
guideline = rememberLineComponent(Fill.Transparent),
|
guideline = rememberLineComponent(Fill.Transparent),
|
||||||
valueFormatter = CartesianValueFormatter { measuringContext, value, _ ->
|
valueFormatter = CartesianValueFormatter { measuringContext, value, _ ->
|
||||||
millisecondsToHours(value.toLong())
|
timeConverter(value.toLong())
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
bottomAxis = HorizontalAxis.rememberBottom(
|
bottomAxis = HorizontalAxis.rememberBottom(
|
||||||
rememberLineComponent(Fill.Transparent),
|
rememberLineComponent(Fill.Transparent),
|
||||||
tick = rememberLineComponent(Fill.Transparent),
|
tick = rememberLineComponent(Fill.Transparent),
|
||||||
guideline = rememberLineComponent(Fill.Transparent)
|
guideline = rememberLineComponent(Fill.Transparent)
|
||||||
),
|
)
|
||||||
),
|
),
|
||||||
modelProducer = modelProducer,
|
modelProducer = modelProducer,
|
||||||
zoomState = rememberVicoZoomState(
|
zoomState = rememberVicoZoomState(
|
||||||
|
zoomEnabled = false,
|
||||||
initialZoom = Zoom.fixed(),
|
initialZoom = Zoom.fixed(),
|
||||||
minZoom = Zoom.min(Zoom.fixed(), Zoom.Content)
|
minZoom = Zoom.min(Zoom.Content, Zoom.fixed())
|
||||||
),
|
),
|
||||||
animationSpec = motionScheme.defaultSpatialSpec(),
|
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import androidx.lifecycle.viewmodel.viewModelFactory
|
|||||||
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer
|
||||||
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.nsh07.pomodoro.TomatoApplication
|
import org.nsh07.pomodoro.TomatoApplication
|
||||||
import org.nsh07.pomodoro.data.StatRepository
|
import org.nsh07.pomodoro.data.StatRepository
|
||||||
@@ -23,11 +24,12 @@ import org.nsh07.pomodoro.data.StatRepository
|
|||||||
class StatsViewModel(
|
class StatsViewModel(
|
||||||
statRepository: StatRepository
|
statRepository: StatRepository
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
private val todayStat = statRepository.getTodayStat()
|
val todayStat = statRepository.getTodayStat().distinctUntilChanged()
|
||||||
private val allStatsSummary = statRepository.getLastWeekStatsSummary()
|
private val allStatsSummary = statRepository.getLastWeekStatsSummary()
|
||||||
private val averageFocusTimes = statRepository.getAverageFocusTimes()
|
private val averageFocusTimes = statRepository.getAverageFocusTimes()
|
||||||
|
|
||||||
val allStatsSummaryModelProducer = CartesianChartModelProducer()
|
val allStatsSummaryModelProducer = CartesianChartModelProducer()
|
||||||
|
val todayStatModelProducer = CartesianChartModelProducer()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
@@ -38,6 +40,21 @@ class StatsViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
todayStat
|
||||||
|
.collect {
|
||||||
|
todayStatModelProducer.runTransaction {
|
||||||
|
columnSeries {
|
||||||
|
series(
|
||||||
|
it?.focusTimeQ1 ?: 0,
|
||||||
|
it?.focusTimeQ2 ?: 0,
|
||||||
|
it?.focusTimeQ3 ?: 0,
|
||||||
|
it?.focusTimeQ4 ?: 0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2025 Nishant Mishra
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
package org.nsh07.pomodoro.ui.theme
|
package org.nsh07.pomodoro.ui.theme
|
||||||
|
|
||||||
import androidx.compose.material3.Typography
|
import androidx.compose.material3.Typography
|
||||||
@@ -9,6 +16,8 @@ import androidx.compose.ui.text.font.FontVariation
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import org.nsh07.pomodoro.R
|
import org.nsh07.pomodoro.R
|
||||||
|
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexHeadline
|
||||||
|
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTitle
|
||||||
|
|
||||||
// Set of Material typography styles to start with
|
// Set of Material typography styles to start with
|
||||||
val Typography = Typography(
|
val Typography = Typography(
|
||||||
@@ -18,6 +27,18 @@ val Typography = Typography(
|
|||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
lineHeight = 24.sp,
|
lineHeight = 24.sp,
|
||||||
letterSpacing = 0.5.sp
|
letterSpacing = 0.5.sp
|
||||||
|
),
|
||||||
|
headlineSmall = TextStyle(
|
||||||
|
fontFamily = robotoFlexHeadline,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
lineHeight = 32.sp,
|
||||||
|
letterSpacing = 0.sp,
|
||||||
|
),
|
||||||
|
titleMedium = TextStyle(
|
||||||
|
fontFamily = robotoFlexTitle,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
lineHeight = 24.sp,
|
||||||
|
letterSpacing = 0.15.sp,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,7 +48,7 @@ object AppFonts {
|
|||||||
)
|
)
|
||||||
|
|
||||||
@OptIn(ExperimentalTextApi::class)
|
@OptIn(ExperimentalTextApi::class)
|
||||||
val robotoFlexTitle = FontFamily(
|
val robotoFlexTopBar = FontFamily(
|
||||||
Font(
|
Font(
|
||||||
R.font.roboto_flex_variable,
|
R.font.roboto_flex_variable,
|
||||||
variationSettings = FontVariation.Settings(
|
variationSettings = FontVariation.Settings(
|
||||||
@@ -45,4 +66,28 @@ object AppFonts {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTextApi::class)
|
||||||
|
val robotoFlexHeadline = FontFamily(
|
||||||
|
Font(
|
||||||
|
R.font.roboto_flex_variable,
|
||||||
|
variationSettings = FontVariation.Settings(
|
||||||
|
FontVariation.width(130f),
|
||||||
|
FontVariation.weight(600),
|
||||||
|
FontVariation.grade(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalTextApi::class)
|
||||||
|
val robotoFlexTitle = FontFamily(
|
||||||
|
Font(
|
||||||
|
R.font.roboto_flex_variable,
|
||||||
|
variationSettings = FontVariation.Settings(
|
||||||
|
FontVariation.width(130f),
|
||||||
|
FontVariation.weight(700),
|
||||||
|
FontVariation.grade(0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
@@ -58,7 +58,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import org.nsh07.pomodoro.R
|
import org.nsh07.pomodoro.R
|
||||||
import org.nsh07.pomodoro.ui.theme.AppFonts.openRundeClock
|
import org.nsh07.pomodoro.ui.theme.AppFonts.openRundeClock
|
||||||
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTitle
|
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
||||||
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
import org.nsh07.pomodoro.ui.theme.TomatoTheme
|
||||||
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerAction
|
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerAction
|
||||||
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerMode
|
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerMode
|
||||||
@@ -112,7 +112,7 @@ fun TimerScreen(
|
|||||||
Text(
|
Text(
|
||||||
"Tomato",
|
"Tomato",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontFamily = robotoFlexTitle,
|
fontFamily = robotoFlexTopBar,
|
||||||
fontSize = 32.sp,
|
fontSize = 32.sp,
|
||||||
lineHeight = 32.sp,
|
lineHeight = 32.sp,
|
||||||
color = colorScheme.onErrorContainer
|
color = colorScheme.onErrorContainer
|
||||||
@@ -125,7 +125,7 @@ fun TimerScreen(
|
|||||||
Text(
|
Text(
|
||||||
"Focus",
|
"Focus",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontFamily = robotoFlexTitle,
|
fontFamily = robotoFlexTopBar,
|
||||||
fontSize = 32.sp,
|
fontSize = 32.sp,
|
||||||
lineHeight = 32.sp,
|
lineHeight = 32.sp,
|
||||||
color = colorScheme.onPrimaryContainer
|
color = colorScheme.onPrimaryContainer
|
||||||
@@ -137,7 +137,7 @@ fun TimerScreen(
|
|||||||
TimerMode.SHORT_BREAK -> Text(
|
TimerMode.SHORT_BREAK -> Text(
|
||||||
"Short Break",
|
"Short Break",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontFamily = robotoFlexTitle,
|
fontFamily = robotoFlexTopBar,
|
||||||
fontSize = 32.sp,
|
fontSize = 32.sp,
|
||||||
lineHeight = 32.sp,
|
lineHeight = 32.sp,
|
||||||
color = colorScheme.onTertiaryContainer
|
color = colorScheme.onTertiaryContainer
|
||||||
@@ -149,7 +149,7 @@ fun TimerScreen(
|
|||||||
TimerMode.LONG_BREAK -> Text(
|
TimerMode.LONG_BREAK -> Text(
|
||||||
"Long Break",
|
"Long Break",
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontFamily = robotoFlexTitle,
|
fontFamily = robotoFlexTopBar,
|
||||||
fontSize = 32.sp,
|
fontSize = 32.sp,
|
||||||
lineHeight = 32.sp,
|
lineHeight = 32.sp,
|
||||||
color = colorScheme.onTertiaryContainer
|
color = colorScheme.onTertiaryContainer
|
||||||
|
|||||||
@@ -23,4 +23,11 @@ fun millisecondsToHours(t: Long): String =
|
|||||||
Locale.getDefault(),
|
Locale.getDefault(),
|
||||||
"%dh",
|
"%dh",
|
||||||
TimeUnit.MILLISECONDS.toHours(t)
|
TimeUnit.MILLISECONDS.toHours(t)
|
||||||
|
)
|
||||||
|
|
||||||
|
fun millisecondsToHoursMinutes(t: Long): String =
|
||||||
|
String.format(
|
||||||
|
Locale.getDefault(),
|
||||||
|
"%dh %dm", TimeUnit.MILLISECONDS.toHours(t),
|
||||||
|
TimeUnit.MILLISECONDS.toMinutes(t) % TimeUnit.HOURS.toMinutes(1)
|
||||||
)
|
)
|
||||||
10
app/src/main/res/drawable/arrow_down.xml
Normal file
10
app/src/main/res/drawable/arrow_down.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="#000000"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M480,599q-8,0 -15,-2.5t-13,-8.5L268,404q-11,-11 -11,-28t11,-28q11,-11 28,-11t28,11l156,156 156,-156q11,-11 28,-11t28,11q11,11 11,28t-11,28L508,588q-6,6 -13,8.5t-15,2.5Z" />
|
||||||
|
</vector>
|
||||||
Binary file not shown.
Reference in New Issue
Block a user