Merge branch 'dev'
@@ -33,8 +33,8 @@ android {
|
||||
applicationId = "org.nsh07.pomodoro"
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
versionCode = 12
|
||||
versionName = "1.5.0-alpha01"
|
||||
versionCode = 13
|
||||
versionName = "1.5.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
@@ -62,6 +62,7 @@ android {
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
buildConfig = true
|
||||
}
|
||||
dependenciesInfo {
|
||||
includeInApk = false
|
||||
|
||||
@@ -102,8 +102,10 @@ class TimerService : Service() {
|
||||
|
||||
Actions.RESET.toString() -> {
|
||||
if (timerState.value.timerRunning) toggleTimer()
|
||||
resetTimer()
|
||||
stopForegroundService()
|
||||
skipScope.launch {
|
||||
resetTimer()
|
||||
stopForegroundService()
|
||||
}
|
||||
}
|
||||
|
||||
Actions.SKIP.toString() -> skipTimer(true)
|
||||
@@ -278,27 +280,25 @@ class TimerService : Service() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetTimer() {
|
||||
private suspend fun resetTimer() {
|
||||
updateProgressSegments()
|
||||
skipScope.launch {
|
||||
saveTimeToDb()
|
||||
time = timerRepository.focusTime
|
||||
cycles = 0
|
||||
startTime = 0L
|
||||
pauseTime = 0L
|
||||
pauseDuration = 0L
|
||||
saveTimeToDb()
|
||||
time = timerRepository.focusTime
|
||||
cycles = 0
|
||||
startTime = 0L
|
||||
pauseTime = 0L
|
||||
pauseDuration = 0L
|
||||
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(
|
||||
timerMode = TimerMode.FOCUS,
|
||||
timeStr = millisecondsToStr(time),
|
||||
totalTime = time,
|
||||
nextTimerMode = if (timerRepository.sessionLength > 1) TimerMode.SHORT_BREAK else TimerMode.LONG_BREAK,
|
||||
nextTimeStr = millisecondsToStr(if (timerRepository.sessionLength > 1) timerRepository.shortBreakTime else timerRepository.longBreakTime),
|
||||
currentFocusCount = 1,
|
||||
totalFocusCount = timerRepository.sessionLength
|
||||
)
|
||||
}
|
||||
_timerState.update { currentState ->
|
||||
currentState.copy(
|
||||
timerMode = TimerMode.FOCUS,
|
||||
timeStr = millisecondsToStr(time),
|
||||
totalTime = time,
|
||||
nextTimerMode = if (timerRepository.sessionLength > 1) TimerMode.SHORT_BREAK else TimerMode.LONG_BREAK,
|
||||
nextTimeStr = millisecondsToStr(if (timerRepository.sessionLength > 1) timerRepository.shortBreakTime else timerRepository.longBreakTime),
|
||||
currentFocusCount = 1,
|
||||
totalFocusCount = timerRepository.sessionLength
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
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.foundation.text.TextAutoSize
|
||||
@@ -26,6 +27,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.FilledTonalIconToggleButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.LocalTextStyle
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -59,6 +61,7 @@ import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.columnSeries
|
||||
import com.patrykandpatrick.vico.core.cartesian.data.lineSeries
|
||||
import com.patrykandpatrick.vico.core.common.data.ExtraStore
|
||||
import org.nsh07.pomodoro.BuildConfig
|
||||
import org.nsh07.pomodoro.R
|
||||
import org.nsh07.pomodoro.data.Stat
|
||||
import org.nsh07.pomodoro.ui.statsScreen.viewModel.StatsViewModel
|
||||
@@ -93,6 +96,7 @@ fun StatsScreenRoot(
|
||||
lastWeekAverageFocusTimes = lastWeekAnalysisValues,
|
||||
lastMonthAverageFocusTimes = lastMonthAnalysisValues,
|
||||
lastYearAverageFocusTimes = lastYearAnalysisValues,
|
||||
generateSampleData = viewModel::generateSampleData,
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
||||
@@ -108,6 +112,7 @@ fun StatsScreen(
|
||||
lastWeekAverageFocusTimes: List<Int>,
|
||||
lastMonthAverageFocusTimes: List<Int>,
|
||||
lastYearAverageFocusTimes: List<Int>,
|
||||
generateSampleData: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior()
|
||||
@@ -152,6 +157,17 @@ fun StatsScreen(
|
||||
.padding(vertical = 14.dp)
|
||||
)
|
||||
},
|
||||
actions = if (BuildConfig.DEBUG) {
|
||||
{
|
||||
IconButton(
|
||||
onClick = generateSampleData
|
||||
) {
|
||||
Spacer(Modifier.size(24.dp))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
{}
|
||||
},
|
||||
subtitle = {},
|
||||
titleHorizontalAlignment = Alignment.CenterHorizontally,
|
||||
scrollBehavior = scrollBehavior,
|
||||
@@ -458,7 +474,8 @@ fun StatsScreenPreview() {
|
||||
null,
|
||||
listOf(0, 0, 0, 0),
|
||||
listOf(0, 0, 0, 0),
|
||||
listOf(0, 0, 0, 0)
|
||||
listOf(0, 0, 0, 0),
|
||||
{}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,18 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.nsh07.pomodoro.BuildConfig
|
||||
import org.nsh07.pomodoro.TomatoApplication
|
||||
import org.nsh07.pomodoro.data.Stat
|
||||
import org.nsh07.pomodoro.data.StatRepository
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.TextStyle
|
||||
import java.util.Locale
|
||||
|
||||
class StatsViewModel(
|
||||
statRepository: StatRepository
|
||||
private val statRepository: StatRepository
|
||||
) : ViewModel() {
|
||||
|
||||
val todayStat = statRepository.getTodayStat().distinctUntilChanged()
|
||||
@@ -151,6 +155,31 @@ class StatsViewModel(
|
||||
initialValue = listOf(0, 0, 0, 0)
|
||||
)
|
||||
|
||||
fun generateSampleData() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
viewModelScope.launch {
|
||||
val today = LocalDate.now().plusDays(1)
|
||||
var it = today.minusDays(40)
|
||||
|
||||
while (it.isBefore(today)) {
|
||||
statRepository.insertStat(
|
||||
Stat(
|
||||
it,
|
||||
(0..30 * 60 * 1000L).random(),
|
||||
(1 * 60 * 60 * 1000L..3 * 60 * 60 * 1000L).random(),
|
||||
(0..3 * 60 * 60 * 1000L).random(),
|
||||
(0..1 * 60 * 60 * 1000L).random(),
|
||||
0
|
||||
)
|
||||
)
|
||||
it = it.plusDays(1)
|
||||
}
|
||||
|
||||
statRepository.addBreakTime((0..30 * 60 * 60 * 1000L).random())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
|
||||
@@ -138,7 +138,9 @@ fun TimerScreen(
|
||||
targetOffsetY = { (it * 1.25).toInt() }
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
when (it) {
|
||||
TimerMode.BRAND ->
|
||||
@@ -150,8 +152,7 @@ fun TimerScreen(
|
||||
lineHeight = 32.sp,
|
||||
color = colorScheme.error
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.width(210.dp)
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
TimerMode.FOCUS ->
|
||||
@@ -163,8 +164,7 @@ fun TimerScreen(
|
||||
lineHeight = 32.sp,
|
||||
color = colorScheme.primary
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.width(210.dp)
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
TimerMode.SHORT_BREAK -> Text(
|
||||
@@ -175,8 +175,7 @@ fun TimerScreen(
|
||||
lineHeight = 32.sp,
|
||||
color = colorScheme.tertiary
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.width(210.dp)
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
TimerMode.LONG_BREAK -> Text(
|
||||
@@ -187,8 +186,7 @@ fun TimerScreen(
|
||||
lineHeight = 32.sp,
|
||||
color = colorScheme.tertiary
|
||||
),
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier.width(210.dp)
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
||||
<string name="start">تشغيل</string>
|
||||
<string name="stop">إيقاف</string>
|
||||
<string name="focus">تركيز</string>
|
||||
<string name="short_break">استراحة قصيرة</string>
|
||||
<string name="long_break">استراحة طويلة</string>
|
||||
<string name="exit">خروج</string>
|
||||
<string name="skip">تخطي</string>
|
||||
<string name="stop_alarm">إيقاف المنبه</string>
|
||||
<string name="min_remaining_notification">%1$s دقيقة متبقية</string>
|
||||
<string name="paused">متوقف</string>
|
||||
<string name="completed">انتهي</string>
|
||||
<string name="up_next_notification">القادم: %1$s (%2$s)</string>
|
||||
<string name="start_next">ابدأ التالي</string>
|
||||
<string name="choose_color_scheme">اختر مجموعة الالوان</string>
|
||||
<string name="ok">حسناً</string>
|
||||
<string name="color_scheme">مجموعة الالوان</string>
|
||||
<string name="dynamic">ديناميكي</string>
|
||||
<string name="color">لون</string>
|
||||
<string name="system_default">النظام (الافتراضي)</string>
|
||||
<string name="alarm">منبه</string>
|
||||
<string name="light">فاتح</string>
|
||||
<string name="dark">داكن</string>
|
||||
<string name="choose_theme">اختر سمة</string>
|
||||
<string name="productivity_analysis">تحليل الإنتاجية</string>
|
||||
<string name="productivity_analysis_desc">مدة التركيز في أوقات مختلفة في اليوم</string>
|
||||
<string name="alarm_sound">صوت المنبه</string>
|
||||
<string name="black_theme">الوضع الاسود</string>
|
||||
<string name="black_theme_desc">استخدم سمة اسود نقي</string>
|
||||
<string name="alarm_desc">التنبيه عند انتهاء المؤقت</string>
|
||||
<string name="vibrate">اهتزاز</string>
|
||||
<string name="vibrate_desc">الاهتزاز عندما ينتهي المؤقت</string>
|
||||
<string name="theme">سمة</string>
|
||||
<string name="settings">الاعدادات</string>
|
||||
<string name="session_length">طول الجلسة</string>
|
||||
<string name="session_length_desc">فترات التركيز في الجلسة الواحدة: %1$d</string>
|
||||
<string name="pomodoro_info">\"الجلسة\" هي تسلسل فترات بومودورو التي تحتوي علي فترات التركيز، فترة الاستراحة القصيرة و فترة الاستراحة الطويلة. آخر استراحة في الجلسة هي دائما استراحة كبيرة.</string>
|
||||
<string name="stats">الإحصائيات</string>
|
||||
<string name="today">اليوم</string>
|
||||
<string name="break_">استراحة</string>
|
||||
<string name="last_week">الاسبوع الماضي</string>
|
||||
<string name="focus_per_day_avg">مدة التركيز في اليوم (المتوسط)</string>
|
||||
<string name="more_info">معلومات أكثر</string>
|
||||
<string name="weekly_productivity_analysis">تحليل الإنتاجية الاسبوعي</string>
|
||||
<string name="last_month">الشهر الماضي</string>
|
||||
<string name="monthly_productivity_analysis">تحليل الإنتاجية الشهري</string>
|
||||
<string name="stop_alarm_question">إيقاف المنبه؟</string>
|
||||
<string name="stop_alarm_dialog_text">مؤقت الجلسة الحالية انتهي. اضغط في أي مكان لإيقاف المنبه.</string>
|
||||
<string name="timer_session_count">%1$d من %2$d</string>
|
||||
<string name="more">أكثر</string>
|
||||
<string name="pause">إيقاف</string>
|
||||
<string name="play">أبدا</string>
|
||||
<string name="restart">إعادة التعيين</string>
|
||||
<string name="skip_to_next">تخطي الي التالي</string>
|
||||
<string name="up_next">القادم</string>
|
||||
<string name="timer">المؤقت</string>
|
||||
<string name="timer_progress">تقدم المؤقت</string>
|
||||
<string name="last_year">السنة الماضية</string>
|
||||
</resources>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<resources>
|
||||
<string name="start">Почати</string>
|
||||
<string name="stop">Стоп</string>
|
||||
<string name="focus">Концентрація</string>
|
||||
<string name="focus">Фокус</string>
|
||||
<string name="short_break">Коротка перерва</string>
|
||||
<string name="long_break">Довга перерва</string>
|
||||
<string name="exit">Вийти</string>
|
||||
<string name="exit">Завершити</string>
|
||||
<string name="skip">Пропустити</string>
|
||||
<string name="color_scheme">Колірна схема</string>
|
||||
<string name="productivity_analysis">Аналіз продуктивності</string>
|
||||
@@ -35,7 +35,7 @@
|
||||
<string name="ok">ОК</string>
|
||||
<string name="dynamic">Динамічна</string>
|
||||
<string name="color">Колір</string>
|
||||
<string name="system_default">За замовчуванням (система)</string>
|
||||
<string name="system_default">Налаштування системи</string>
|
||||
<string name="alarm">Сигнал</string>
|
||||
<string name="light">Світла</string>
|
||||
<string name="dark">Темна</string>
|
||||
@@ -43,17 +43,18 @@
|
||||
<string name="productivity_analysis_desc">Тривалість концентрації в різні години дня</string>
|
||||
<string name="alarm_sound">Звук сигналу</string>
|
||||
<string name="black_theme_desc">Використовувати чисту чорну тему</string>
|
||||
<string name="alarm_desc">Звуковий сигнал по завершенні таймера</string>
|
||||
<string name="alarm_desc">Звуковий сигнал після завершення таймера</string>
|
||||
<string name="vibrate_desc">Увімкнути вібрацію після завершення таймера</string>
|
||||
<string name="session_length_desc">Інтервали концентрації уваги в одній сесії: %1$d</string>
|
||||
<string name="pomodoro_info">«Сесія» - це послідовність інтервалів Pomodoro, що містить інтервали концентрації, короткі перерви та довгу перерву. Остання перерва сесії є завжди довгою.</string>
|
||||
<string name="pomodoro_info">«Сесія» - це послідовність інтервалів Pomodoro, що містить інтервали концентрації, короткі перерви та довгу перерву. Остання перерва сесії завжди є довгою.</string>
|
||||
<string name="break_">Перерва</string>
|
||||
<string name="last_week">Минулого тижня</string>
|
||||
<string name="focus_per_day_avg">концентрацій на день (середнє значення)</string>
|
||||
<string name="focus_per_day_avg">концентрації на день (сер.)</string>
|
||||
<string name="stop_alarm_question">Зупинити сигнал?</string>
|
||||
<string name="stop_alarm_dialog_text">Поточна сесія таймера завершена. Натисніть будь-де, щоб зупинити сигнал.</string>
|
||||
<string name="timer_session_count">%1$d з %2$d</string>
|
||||
<string name="more">Більше</string>
|
||||
<string name="pause">Пауза</string>
|
||||
<string name="play">Грати</string>
|
||||
<string name="last_year">Минулого року</string>
|
||||
</resources>
|
||||
|
||||
3
app/src/main/res/values-vi/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
||||
60
app/src/main/res/values-zh-rTW/strings.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="start">開始</string>
|
||||
<string name="stop">停止</string>
|
||||
<string name="focus">專注</string>
|
||||
<string name="short_break">短休息</string>
|
||||
<string name="long_break">長休息</string>
|
||||
<string name="exit">退出</string>
|
||||
<string name="skip">跳過</string>
|
||||
<string name="stop_alarm">停止鬧鐘</string>
|
||||
<string name="min_remaining_notification">剩餘%1$s</string>
|
||||
<string name="paused">已暫停</string>
|
||||
<string name="completed">已完成</string>
|
||||
<string name="up_next_notification">下一個: %1$s (%2$s)</string>
|
||||
<string name="start_next">開始下一個</string>
|
||||
<string name="choose_color_scheme">選擇配色方案</string>
|
||||
<string name="ok">好的</string>
|
||||
<string name="color_scheme">配色方案</string>
|
||||
<string name="dynamic">動態</string>
|
||||
<string name="color">顏色</string>
|
||||
<string name="system_default">系統默認</string>
|
||||
<string name="alarm">鬧鐘</string>
|
||||
<string name="light">亮色</string>
|
||||
<string name="dark">暗色</string>
|
||||
<string name="choose_theme">選擇主題</string>
|
||||
<string name="productivity_analysis">生產力分析</string>
|
||||
<string name="productivity_analysis_desc">一天中不同時間的專注持續時間</string>
|
||||
<string name="alarm_sound">鬧鐘鈴聲</string>
|
||||
<string name="black_theme">純黑主題</string>
|
||||
<string name="black_theme_desc">使用純黑色主題</string>
|
||||
<string name="alarm_desc">計時器完成時響起鬧鈴</string>
|
||||
<string name="vibrate">振動</string>
|
||||
<string name="vibrate_desc">當計時器完成時震動</string>
|
||||
<string name="theme">主题</string>
|
||||
<string name="settings">设置</string>
|
||||
<string name="session_length">会话时长</string>
|
||||
<string name="session_length_desc">单次专注时间间隔: %1$d</string>
|
||||
<string name="pomodoro_info">一个“会话”是由多个番茄钟组成的序列,其中包含专注时间段、短休息和长休息。一个会话中的最后一次休息必然是长休息。</string>
|
||||
<string name="stats">统计</string>
|
||||
<string name="today">今天</string>
|
||||
<string name="break_">休息</string>
|
||||
<string name="last_week">上周</string>
|
||||
<string name="focus_per_day_avg">每天平均專注時間</string>
|
||||
<string name="more_info">更多資訊</string>
|
||||
<string name="weekly_productivity_analysis">每週生產力分析</string>
|
||||
<string name="last_month">上月</string>
|
||||
<string name="monthly_productivity_analysis">每月生产力分析</string>
|
||||
<string name="stop_alarm_question">停止鬧鐘?</string>
|
||||
<string name="stop_alarm_dialog_text">當前計時器會話已經完成。 點擊任意位置停止鬧鐘。</string>
|
||||
<string name="timer_session_count">%1$d of %2$d</string>
|
||||
<string name="more">更多</string>
|
||||
<string name="pause">暂停</string>
|
||||
<string name="play">开始</string>
|
||||
<string name="restart">重置</string>
|
||||
<string name="skip_to_next">跳至下一个</string>
|
||||
<string name="up_next">接下来</string>
|
||||
<string name="timer">计时</string>
|
||||
<string name="timer_progress">计时进度</string>
|
||||
<string name="last_year">上年</string>
|
||||
</resources>
|
||||
1
fastlane/metadata/android/ar/full_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
<p><i>Tomato</i> هو مؤقت بومودورو بسيط (Pomodoro timer) لنظام أندرويد يعتمد على تصميم Material 3 Expressive.</p><p><br><b>الميزات:</b></p><ul><li>واجهة مستخدم بسيطة تعتمد على أحدث إرشادات Material 3 Expressive</li><li>إحصائيات مفصلة لأوقات العمل/الدراسة بطريقة سهلة الفهم<ul><li>إحصائيات اليوم الحالي مرئية بلمحة سريعة</li><li>إحصائيات الأسبوع الماضي والشهر الماضي معروضة في رسم بياني نظيف وسهل القراءة</li><li>إحصائيات إضافية للأسبوع والشهر الماضيين توضح في أي وقت من اليوم تكون أكثر إنتاجية</li></ul></li><li>إعدادات المؤقت قابلة للتخصيص</li></ul>
|
||||
1
fastlane/metadata/android/ar/short_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
مؤقت بومودورو بسيط
|
||||
1
fastlane/metadata/android/cs-CZ/short_description.txt
Normal file
@@ -0,0 +1 @@
|
||||
Minimalistický Pomodoro časovač
|
||||
14
fastlane/metadata/android/en-US/changelogs/13.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
Bug fixes and translation expansion over 1.5.0-alpha01
|
||||
|
||||
Full changelog for 1.5.0:
|
||||
New features:
|
||||
- The Stats screen now contains the data for the past year
|
||||
- Charts now have fading edges to indicate scrollable content
|
||||
|
||||
Fixes:
|
||||
- Improved Stats screen performance
|
||||
- Notification now does not pop up on your screen
|
||||
- Fixed low contrast on the Timer screen heading
|
||||
- Improve app usability on smaller screens
|
||||
|
||||
Expanded translations
|
||||
@@ -1 +1,12 @@
|
||||
<p><i>Tomato</i> is a minimalist Pomodoro timer for Android based on Material 3 Expressive.</p><p><br><b>Features:</b></p><ul><li>Simple, minimalist UI based on the latest Material 3 Expressive guidelines</li><li>Detailed statistics of work/study times in an easy to understand manner<ul><li>Stats for the current day visible at a glance</li><li>Stats for the last week and last month shown in an easy to read, clean graph</li><li>Additional stats for last week and month showing at what time of the day you're the most productive</li></ul></li><li>Customizable timer parameters</li></ul>
|
||||
<i>Tomato</i> is a minimalist Pomodoro timer for Android based on Material 3 Expressive.
|
||||
|
||||
Tomato is fully free and open-source, forever. You can find the source code and report bugs or suggest features at https://github.com/nsh07/Tomato
|
||||
|
||||
<b>Features:</b>
|
||||
- Simple, minimalist UI based on the latest Material 3 Expressive guidelines
|
||||
- Detailed statistics of work/study times in an easy to understand manner
|
||||
- Stats for the current day visible at a glance
|
||||
- Stats for the last week and last month shown in an easy to read, clean graph
|
||||
- Additional stats for last week and month showing at what time of the day you're the most productive
|
||||
- Customizable timer parameters
|
||||
- Support for Android 16 Live Updates
|
||||
|
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 239 KiB |
|
Before Width: | Height: | Size: 324 KiB After Width: | Height: | Size: 148 KiB |
|
Before Width: | Height: | Size: 323 KiB After Width: | Height: | Size: 157 KiB |
|
Before Width: | Height: | Size: 330 KiB After Width: | Height: | Size: 183 KiB |
|
Before Width: | Height: | Size: 353 KiB After Width: | Height: | Size: 214 KiB |
|
Before Width: | Height: | Size: 385 KiB After Width: | Height: | Size: 196 KiB |
|
Before Width: | Height: | Size: 386 KiB After Width: | Height: | Size: 737 KiB |