Merge branch 'dev'

This commit is contained in:
Nishant Mishra
2025-10-18 17:09:24 +05:30
21 changed files with 236 additions and 42 deletions

View File

@@ -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

View File

@@ -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
)
}
}

View File

@@ -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),
{}
)
}
}

View File

@@ -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 {

View File

@@ -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
)
}
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>

View 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>

View 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>

View File

@@ -0,0 +1 @@
مؤقت بومودورو بسيط

View File

@@ -0,0 +1 @@
Minimalistický Pomodoro časovač

View 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

View File

@@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 179 KiB

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 324 KiB

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 323 KiB

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

After

Width:  |  Height:  |  Size: 183 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 353 KiB

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 385 KiB

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 KiB

After

Width:  |  Height:  |  Size: 737 KiB