From 7af9aa726f0a8fdce62282673e810ef7a82b7be2 Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Tue, 30 Sep 2025 23:10:57 +0530 Subject: [PATCH 01/16] fix: Fix incorrect average being calculated --- .../java/org/nsh07/pomodoro/data/StatDao.kt | 14 ++++++--- .../ui/statsScreen/TimeColumnChart.kt | 31 ++----------------- 2 files changed, 11 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt b/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt index f1767f5..b7c1c76 100644 --- a/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt +++ b/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt @@ -42,11 +42,15 @@ interface StatDao { @Query( "SELECT " + - "AVG(NULLIF(focusTimeQ1,0)) AS focusTimeQ1, " + - "AVG(NULLIF(focusTimeQ2,0)) AS focusTimeQ2, " + - "AVG(NULLIF(focusTimeQ3,0)) AS focusTimeQ3, " + - "AVG(NULLIF(focusTimeQ4,0)) AS focusTimeQ4 " + - "FROM (SELECT focusTimeQ1, focusTimeQ2, focusTimeQ3, focusTimeQ4 FROM stat ORDER BY date DESC LIMIT :n)" + "AVG(focusTimeQ1) AS focusTimeQ1, " + + "AVG(focusTimeQ2) AS focusTimeQ2, " + + "AVG(focusTimeQ3) AS focusTimeQ3, " + + "AVG(focusTimeQ4) AS focusTimeQ4 " + + "FROM (" + + "SELECT focusTimeQ1, focusTimeQ2, focusTimeQ3, focusTimeQ4 FROM stat " + + "WHERE focusTimeQ1 != 0 OR focusTimeQ2 != 0 OR focusTimeQ3 != 0 OR focusTimeQ4 != 0 " + + "ORDER BY date DESC LIMIT :n" + + ")" ) fun getLastNDaysAvgFocusTimes(n: Int): Flow diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt index a085850..3edf72f 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt @@ -7,14 +7,11 @@ package org.nsh07.pomodoro.ui.statsScreen -import android.graphics.Path -import android.graphics.RectF import androidx.compose.animation.core.AnimationSpec import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.MaterialTheme.motionScheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.patrykandpatrick.vico.compose.cartesian.CartesianChartHost @@ -35,6 +32,7 @@ import com.patrykandpatrick.vico.core.cartesian.data.CartesianChartModelProducer import com.patrykandpatrick.vico.core.cartesian.data.CartesianValueFormatter import com.patrykandpatrick.vico.core.cartesian.layer.ColumnCartesianLayer import com.patrykandpatrick.vico.core.common.Fill +import com.patrykandpatrick.vico.core.common.shape.CorneredShape import org.nsh07.pomodoro.utils.millisecondsToHours @OptIn(ExperimentalMaterial3ExpressiveApi::class) @@ -50,9 +48,6 @@ internal fun TimeColumnChart( }, animationSpec: AnimationSpec? = motionScheme.slowEffectsSpec() ) { - val radius = with(LocalDensity.current) { - (thickness / 2).toPx() - } ProvideVicoTheme(rememberM3VicoTheme()) { CartesianChartHost( chart = @@ -63,29 +58,7 @@ internal fun TimeColumnChart( rememberLineComponent( fill = fill(color), thickness = thickness, - shape = { _, path, left, top, right, bottom -> - if (top + radius <= bottom - radius) { - path.arcTo( - RectF(left, top, right, top + 2 * radius), - 180f, - 180f - ) - path.lineTo(right, bottom - radius) - path.arcTo( - RectF(left, bottom - 2 * radius, right, bottom), - 0f, - 180f - ) - path.close() - } else { - path.addCircle( - left + radius, - bottom - radius, - radius, - Path.Direction.CW - ) - } - } + shape = CorneredShape.Pill ) } ), From 47abcb86df7a0e434714e30b022f29b300a60dc4 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 1 Oct 2025 03:51:49 +0200 Subject: [PATCH 02/16] Added translation using Weblate (Persian) Co-authored-by: Yamin Siahmargooei --- app/src/main/res/values-fa/strings.xml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/src/main/res/values-fa/strings.xml diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml new file mode 100644 index 0000000..55344e5 --- /dev/null +++ b/app/src/main/res/values-fa/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file From ef4a2eaeec54f8d8be1914bfc295312676237f6c Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 1 Oct 2025 14:15:35 +0200 Subject: [PATCH 03/16] Added translation using Weblate (Ukrainian) Co-authored-by: vintagezero --- app/src/main/res/values-uk/strings.xml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/src/main/res/values-uk/strings.xml diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml new file mode 100644 index 0000000..55344e5 --- /dev/null +++ b/app/src/main/res/values-uk/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file From 31823ce9caa8c4f679373fcbdf8dafdfd1739cf8 Mon Sep 17 00:00:00 2001 From: qamarelsafadi Date: Wed, 1 Oct 2025 23:33:29 +0300 Subject: [PATCH 04/16] fix: observe the current focus count into settings screen slider --- .../viewModel/SettingsViewModel.kt | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt index 276f3de..cc05034 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt @@ -31,11 +31,13 @@ import kotlinx.coroutines.launch import org.nsh07.pomodoro.TomatoApplication import org.nsh07.pomodoro.data.AppPreferenceRepository import org.nsh07.pomodoro.data.TimerRepository +import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState @OptIn(FlowPreview::class, ExperimentalMaterial3Api::class) class SettingsViewModel( private val preferenceRepository: AppPreferenceRepository, - private val timerRepository: TimerRepository + private val timerRepository: TimerRepository, + private val _timerState: MutableStateFlow, ) : ViewModel() { private val _preferencesState = MutableStateFlow(PreferencesState()) val preferencesState = _preferencesState.asStateFlow() @@ -79,6 +81,11 @@ class SettingsViewModel( val blackTheme = preferenceRepository.getBooleanPreference("black_theme") ?: preferenceRepository.saveBooleanPreference("black_theme", false) + // Load session length from preferences and update slider + val sessionLength = preferenceRepository.getIntPreference("session_length") + ?: timerRepository.sessionLength + sessionsSliderState.value = sessionLength.toFloat() + _preferencesState.update { currentState -> currentState.copy( theme = theme, @@ -87,6 +94,7 @@ class SettingsViewModel( ) } } + observeCurrentFocusCount() } private fun updateSessionLength() { @@ -194,18 +202,28 @@ class SettingsViewModel( } } + private fun observeCurrentFocusCount() { + viewModelScope.launch { + _timerState.collect { + sessionsSliderState.value = it.currentFocusCount.toFloat() + } + } + } + companion object { val Factory: ViewModelProvider.Factory = viewModelFactory { initializer { val application = (this[APPLICATION_KEY] as TomatoApplication) val appPreferenceRepository = application.container.appPreferenceRepository val appTimerRepository = application.container.appTimerRepository + val timerState = application.container.timerState SettingsViewModel( preferenceRepository = appPreferenceRepository, - timerRepository = appTimerRepository + timerRepository = appTimerRepository, + _timerState = timerState ) } } } -} \ No newline at end of file +} From bfec4ec0d62e4ac2982287f2ef2a0fc48c176d5f Mon Sep 17 00:00:00 2001 From: qamarelsafadi Date: Wed, 1 Oct 2025 23:55:09 +0300 Subject: [PATCH 05/16] Revert "Create CODE_OF_CONDUCT.md" This reverts commit a014c49463e46c1eb44cfbbec5cfdd10a7848efc. --- CODE_OF_CONDUCT.md | 128 --------------------------------------------- 1 file changed, 128 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 7626f2c..0000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,128 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or - advances of any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email - address, without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -nishant.28@outlook.com. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.0, available at -https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. - -Community Impact Guidelines were inspired by [Mozilla's code of conduct -enforcement ladder](https://github.com/mozilla/diversity). - -[homepage]: https://www.contributor-covenant.org - -For answers to common questions about this code of conduct, see the FAQ at -https://www.contributor-covenant.org/faq. Translations are available at -https://www.contributor-covenant.org/translations. From 21408f429d1aded3e07875178cb5162e2baae3ac Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 2 Oct 2025 15:02:12 +0200 Subject: [PATCH 06/16] Translated using Weblate (Ukrainian) Currently translated at 100.0% (57 of 57 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (10 of 10 strings) Translated using Weblate (Hindi) Currently translated at 90.0% (9 of 10 strings) Translated using Weblate (Hindi) Currently translated at 7.0% (4 of 57 strings) Co-authored-by: Hosted Weblate Co-authored-by: Nishant Mishra <66912344+nsh07@users.noreply.github.com> Co-authored-by: vintagezero Translate-URL: https://hosted.weblate.org/projects/tomato/store-descriptions/hi/ Translate-URL: https://hosted.weblate.org/projects/tomato/store-descriptions/uk/ Translate-URL: https://hosted.weblate.org/projects/tomato/strings/hi/ Translate-URL: https://hosted.weblate.org/projects/tomato/strings/uk/ Translation: Tomato/Store descriptions Translation: Tomato/Strings --- app/src/main/res/values-hi/strings.xml | 5 +- app/src/main/res/values-uk/strings.xml | 58 ++++++++++++++++++- .../android/hi-IN/short_description.txt | 1 + .../metadata/android/uk/full_description.txt | 1 + .../metadata/android/uk/short_description.txt | 1 + fastlane/metadata/android/uk/title.txt | 1 + 6 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/hi-IN/short_description.txt create mode 100644 fastlane/metadata/android/uk/full_description.txt create mode 100644 fastlane/metadata/android/uk/short_description.txt create mode 100644 fastlane/metadata/android/uk/title.txt diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 55344e5..2f3ad16 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -1,3 +1,6 @@ - \ No newline at end of file + प्रारंभ करें + विराम करें + ध्यान + diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 55344e5..b25d003 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1,3 +1,59 @@ - \ No newline at end of file + Почати + Стоп + Концентрація + Коротка перерва + Довга перерва + Вийти + Пропустити + Колірна схема + Аналіз продуктивності + Чорна тема + Вібрація + Тема + Налаштування + Тривалість сесії + Статистика + Сьогодні + Більше інформації + Щотижневий аналіз продуктивності + Минулого місяця + Щомісячний аналіз продуктивності + Перезапустити + Перейти до наступного + Далі + Таймер + Прогрес таймера + Зупинити + %1$s хв залишилося + Призупинено + Завершено + Далі: %1$s (%2$s) + Почати наступне + Обрати колірну схему + ОК + Динамічна + Колір + За замовчуванням (система) + Сигнал + Світла + Темна + Обрати тему + Тривалість концентрації в різні години дня + Звук сигналу + Використовувати чисту чорну тему + Звуковий сигнал по завершенні таймера + Увімкнути вібрацію після завершення таймера + Інтервали концентрації уваги в одній сесії: %1$d + «Сесія» - це послідовність інтервалів Pomodoro, що містить інтервали концентрації, короткі перерви та довгу перерву. Остання перерва сесії є завжди довгою. + Перерва + Минулого тижня + концентрацій на день (середнє значення) + Зупинити сигнал? + Поточна сесія таймера завершена. Натисніть будь-де, щоб зупинити сигнал. + %1$d з %2$d + Більше + Пауза + Грати + diff --git a/fastlane/metadata/android/hi-IN/short_description.txt b/fastlane/metadata/android/hi-IN/short_description.txt new file mode 100644 index 0000000..1e9457d --- /dev/null +++ b/fastlane/metadata/android/hi-IN/short_description.txt @@ -0,0 +1 @@ +सरल पोमोडोरो टाइमर diff --git a/fastlane/metadata/android/uk/full_description.txt b/fastlane/metadata/android/uk/full_description.txt new file mode 100644 index 0000000..5c73fb5 --- /dev/null +++ b/fastlane/metadata/android/uk/full_description.txt @@ -0,0 +1 @@ +

Tomato - мінімалістичний Pomodoro таймер для Android на базі Material 3 Expressive.


Особливості:

  • Простий, мінімалістичний інтерфейс на основі останніх рекомендацій Material 3 Expressive
  • Детальна статистика робочого/навчального часу в зрозумілій формі
    • Статистика за поточний день, доступна з одного погляду
    • Статистика за останній тиждень і останній місяць, представлена у вигляді зручного для сприйняття чіткого графіку
    • Додаткова статистика за останній тиждень і місяць, що показує, в який час дня ви були найбільш продуктивні
  • Настроювані параметри таймера
diff --git a/fastlane/metadata/android/uk/short_description.txt b/fastlane/metadata/android/uk/short_description.txt new file mode 100644 index 0000000..16e4d1c --- /dev/null +++ b/fastlane/metadata/android/uk/short_description.txt @@ -0,0 +1 @@ +Мінімалістичний Pomodoro таймер diff --git a/fastlane/metadata/android/uk/title.txt b/fastlane/metadata/android/uk/title.txt new file mode 100644 index 0000000..ee64617 --- /dev/null +++ b/fastlane/metadata/android/uk/title.txt @@ -0,0 +1 @@ +Tomato From 91cab4a0620c0a5dc0537c89abb6d46ae299d63b Mon Sep 17 00:00:00 2001 From: qamarelsafadi Date: Thu, 2 Oct 2025 22:38:02 +0300 Subject: [PATCH 07/16] fix: update the fix to take the sessionLength when sessionsSliderState being called. --- .../viewModel/SettingsViewModel.kt | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt index cc05034..9a6034a 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt @@ -52,12 +52,14 @@ class SettingsViewModel( TextFieldState((timerRepository.longBreakTime / 60000).toString()) } - val sessionsSliderState = SliderState( - value = timerRepository.sessionLength.toFloat(), - steps = 4, - valueRange = 1f..6f, - onValueChangeFinished = ::updateSessionLength - ) + val sessionsSliderState by lazy { + SliderState( + value = timerRepository.sessionLength.toFloat(), + steps = 4, + valueRange = 1f..6f, + onValueChangeFinished = ::updateSessionLength + ) + } val currentAlarmSound = timerRepository.alarmSoundUri.toString() @@ -81,11 +83,6 @@ class SettingsViewModel( val blackTheme = preferenceRepository.getBooleanPreference("black_theme") ?: preferenceRepository.saveBooleanPreference("black_theme", false) - // Load session length from preferences and update slider - val sessionLength = preferenceRepository.getIntPreference("session_length") - ?: timerRepository.sessionLength - sessionsSliderState.value = sessionLength.toFloat() - _preferencesState.update { currentState -> currentState.copy( theme = theme, @@ -94,7 +91,6 @@ class SettingsViewModel( ) } } - observeCurrentFocusCount() } private fun updateSessionLength() { @@ -202,14 +198,6 @@ class SettingsViewModel( } } - private fun observeCurrentFocusCount() { - viewModelScope.launch { - _timerState.collect { - sessionsSliderState.value = it.currentFocusCount.toFloat() - } - } - } - companion object { val Factory: ViewModelProvider.Factory = viewModelFactory { initializer { From 6e61074335be8aa4c809e48688e7e76fd08541ed Mon Sep 17 00:00:00 2001 From: qamarelsafadi Date: Thu, 2 Oct 2025 22:43:04 +0300 Subject: [PATCH 08/16] housekeeping --- .../pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt index 9a6034a..faed267 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt @@ -37,7 +37,6 @@ import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState class SettingsViewModel( private val preferenceRepository: AppPreferenceRepository, private val timerRepository: TimerRepository, - private val _timerState: MutableStateFlow, ) : ViewModel() { private val _preferencesState = MutableStateFlow(PreferencesState()) val preferencesState = _preferencesState.asStateFlow() @@ -204,12 +203,10 @@ class SettingsViewModel( val application = (this[APPLICATION_KEY] as TomatoApplication) val appPreferenceRepository = application.container.appPreferenceRepository val appTimerRepository = application.container.appTimerRepository - val timerState = application.container.timerState SettingsViewModel( preferenceRepository = appPreferenceRepository, timerRepository = appTimerRepository, - _timerState = timerState ) } } From 51f29ce1fa772e04419f39e1d3f987c81f2f7c05 Mon Sep 17 00:00:00 2001 From: qamarelsafadi Date: Thu, 2 Oct 2025 22:43:44 +0300 Subject: [PATCH 09/16] housekeeping --- .../pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt index faed267..5f604c1 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/viewModel/SettingsViewModel.kt @@ -31,7 +31,6 @@ import kotlinx.coroutines.launch import org.nsh07.pomodoro.TomatoApplication import org.nsh07.pomodoro.data.AppPreferenceRepository import org.nsh07.pomodoro.data.TimerRepository -import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState @OptIn(FlowPreview::class, ExperimentalMaterial3Api::class) class SettingsViewModel( From c1d927b2b1c2011d45ae071314522d5e7c5ee45f Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 4 Oct 2025 04:26:36 +0200 Subject: [PATCH 10/16] Added translation using Weblate (Hebrew) Co-authored-by: Arthur Khamkov --- app/src/main/res/values-iw/strings.xml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/src/main/res/values-iw/strings.xml diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml new file mode 100644 index 0000000..55344e5 --- /dev/null +++ b/app/src/main/res/values-iw/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file From bab70e6de126d42ae0981e61b89fd10dea910470 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 8 Oct 2025 09:26:33 +0200 Subject: [PATCH 11/16] Added translation using Weblate (Chinese (Simplified Han script)) Co-authored-by: Raven-1027 --- app/src/main/res/values-zh-rCN/strings.xml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/src/main/res/values-zh-rCN/strings.xml diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000..55344e5 --- /dev/null +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file From 84daa547d8322f8b630036f0232c6e56a904b6af Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Wed, 8 Oct 2025 21:22:36 +0530 Subject: [PATCH 12/16] fix: use alarm audio stream for alarm sound Closes: #63 --- .../nsh07/pomodoro/service/TimerService.kt | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/service/TimerService.kt b/app/src/main/java/org/nsh07/pomodoro/service/TimerService.kt index 595efae..07de4c2 100644 --- a/app/src/main/java/org/nsh07/pomodoro/service/TimerService.kt +++ b/app/src/main/java/org/nsh07/pomodoro/service/TimerService.kt @@ -3,6 +3,7 @@ package org.nsh07.pomodoro.service import android.annotation.SuppressLint import android.app.Service import android.content.Intent +import android.media.AudioAttributes import android.media.MediaPlayer import android.os.Build import android.os.IBinder @@ -78,7 +79,7 @@ class TimerService : Service() { override fun onCreate() { super.onCreate() timerRepository.serviceRunning = true - alarm = MediaPlayer.create(this, timerRepository.alarmSoundUri) + alarm = initializeMediaPlayer() } override fun onDestroy() { @@ -387,9 +388,29 @@ class TimerService : Service() { ) } + private fun initializeMediaPlayer(): MediaPlayer? { + return try { + MediaPlayer().apply { + setAudioAttributes( + AudioAttributes.Builder() + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .setUsage(AudioAttributes.USAGE_ALARM) + .build() + ) + timerRepository.alarmSoundUri?.let { + setDataSource(applicationContext, it) + prepare() + } + } + } catch (e: Exception) { + e.printStackTrace() + null + } + } + fun updateAlarmTone() { alarm?.release() - alarm = MediaPlayer.create(this, timerRepository.alarmSoundUri) + alarm = initializeMediaPlayer() } suspend fun saveTimeToDb() { @@ -417,4 +438,4 @@ class TimerService : Service() { enum class Actions { TOGGLE, SKIP, RESET, STOP_ALARM, UPDATE_ALARM_TONE } -} \ No newline at end of file +} From 54ee995f63217d1fc2633e5e9d2c4cd9b6786cb4 Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Thu, 9 Oct 2025 08:38:19 +0530 Subject: [PATCH 13/16] fix: fix average calculation (again) --- app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt b/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt index b7c1c76..a58aff0 100644 --- a/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt +++ b/app/src/main/java/org/nsh07/pomodoro/data/StatDao.kt @@ -47,9 +47,10 @@ interface StatDao { "AVG(focusTimeQ3) AS focusTimeQ3, " + "AVG(focusTimeQ4) AS focusTimeQ4 " + "FROM (" + - "SELECT focusTimeQ1, focusTimeQ2, focusTimeQ3, focusTimeQ4 FROM stat " + + "SELECT * FROM (" + + "SELECT focusTimeQ1, focusTimeQ2, focusTimeQ3, focusTimeQ4 FROM stat ORDER BY date DESC LIMIT :n" + + ") " + "WHERE focusTimeQ1 != 0 OR focusTimeQ2 != 0 OR focusTimeQ3 != 0 OR focusTimeQ4 != 0 " + - "ORDER BY date DESC LIMIT :n" + ")" ) fun getLastNDaysAvgFocusTimes(n: Int): Flow From a4b4ce612349291877de90f7e35bba6e0fef3652 Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Thu, 9 Oct 2025 08:39:44 +0530 Subject: [PATCH 14/16] fix: show minutes when hour count is 0 on graph vertical axis Closes: #62 --- .../org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt | 9 +++++++-- app/src/main/java/org/nsh07/pomodoro/utils/Utils.kt | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt index 3edf72f..497e553 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/statsScreen/TimeColumnChart.kt @@ -34,6 +34,7 @@ import com.patrykandpatrick.vico.core.cartesian.layer.ColumnCartesianLayer import com.patrykandpatrick.vico.core.common.Fill import com.patrykandpatrick.vico.core.common.shape.CorneredShape import org.nsh07.pomodoro.utils.millisecondsToHours +import org.nsh07.pomodoro.utils.millisecondsToMinutes @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable @@ -43,8 +44,12 @@ internal fun TimeColumnChart( thickness: Dp = 40.dp, columnCollectionSpacing: Dp = 4.dp, xValueFormatter: CartesianValueFormatter = CartesianValueFormatter.Default, - yValueFormatter: CartesianValueFormatter = CartesianValueFormatter { measuringContext, value, _ -> - millisecondsToHours(value.toLong()) + yValueFormatter: CartesianValueFormatter = CartesianValueFormatter { _, value, _ -> + if (value >= 60 * 60 * 1000) { + millisecondsToHours(value.toLong()) + } else { + millisecondsToMinutes(value.toLong()) + } }, animationSpec: AnimationSpec? = motionScheme.slowEffectsSpec() ) { diff --git a/app/src/main/java/org/nsh07/pomodoro/utils/Utils.kt b/app/src/main/java/org/nsh07/pomodoro/utils/Utils.kt index 6406065..4bbaabf 100644 --- a/app/src/main/java/org/nsh07/pomodoro/utils/Utils.kt +++ b/app/src/main/java/org/nsh07/pomodoro/utils/Utils.kt @@ -30,6 +30,15 @@ fun millisecondsToHours(t: Long): String { ) } +fun millisecondsToMinutes(t: Long): String { + require(t >= 0L) + return String.format( + Locale.getDefault(), + "%dm", + TimeUnit.MILLISECONDS.toMinutes(t) + ) +} + fun millisecondsToHoursMinutes(t: Long): String { require(t >= 0L) return String.format( From 9fec4d871a7c8adf55ee180f1361b074f5c03f5d Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 9 Oct 2025 05:15:49 +0200 Subject: [PATCH 15/16] Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 98.2% (56 of 57 strings) Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 100.0% (10 of 10 strings) Co-authored-by: Hosted Weblate Co-authored-by: Raven-1027 Translate-URL: https://hosted.weblate.org/projects/tomato/store-descriptions/zh_Hans/ Translate-URL: https://hosted.weblate.org/projects/tomato/strings/zh_Hans/ Translation: Tomato/Store descriptions Translation: Tomato/Strings --- app/src/main/res/values-zh-rCN/strings.xml | 58 ++++++++++++++++++- .../android/zh-CN/full_description.txt | 1 + .../android/zh-CN/short_description.txt | 1 + 3 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 fastlane/metadata/android/zh-CN/full_description.txt create mode 100644 fastlane/metadata/android/zh-CN/short_description.txt diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 55344e5..fcc8a7d 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,3 +1,59 @@ - \ No newline at end of file + 开始 + 停止 + 专注 + 短休息 + 长休息 + 退出 + 跳过 + 停止响铃 + 还剩 %1$s 分钟 + 已暂停 + 已完成 + 下一步: %1$s (%2$s) + 开始下一个 + 选择配色方案 + 好的 + 配色方案 + 动态 + 颜色 + 系统默认 + 响铃 + 亮色 + 暗色 + 选择主题 + 工作效率分析 + 每日不同时间的专注时长 + 铃声 + 黑色主题 + 使用纯黑主题 + 计时结束时响铃 + 振动 + 计时结束时振动 + 主题 + 设置 + 小节长度 + 一小节内的专注时段: %1$d + 一个“小节”是一系列包含专注时段、短休息时段和长休息时段的番茄钟时段。一个小节的最后一个休息时段始终是长休息时段。 + 统计 + 今日 + 休息 + 上周 + 每日专注时长 (平均) + 更多信息 + 周生产力分析 + 上月 + 月生产力分析 + 要停止响铃吗? + 当前计时小节已完成. 轻触任何位置来停止响铃. + 更多 + 暂停 + 开始 + 重新开始 + 跳过到下一个 + 接下来是 + 计时 + 计时器进度 + %1$d 的 %2$d + diff --git a/fastlane/metadata/android/zh-CN/full_description.txt b/fastlane/metadata/android/zh-CN/full_description.txt new file mode 100644 index 0000000..08a5f6c --- /dev/null +++ b/fastlane/metadata/android/zh-CN/full_description.txt @@ -0,0 +1 @@ +

Tomato 是一个基于Material 3 Expressive的安卓极简主义番茄钟.


功能:

  • 基于最新Material 3 Expressive指南的简洁用户界面
  • 以便于理解的方式提供工作/学习的详细统计数据
    • 当日统计数据一目了然
    • 清楚易读的上周和上月统计图表
    • 上周和上月的额外统计数据帮您找到一天中最高效的时间段
  • 可自定义的计时器参数
diff --git a/fastlane/metadata/android/zh-CN/short_description.txt b/fastlane/metadata/android/zh-CN/short_description.txt new file mode 100644 index 0000000..7cbbd96 --- /dev/null +++ b/fastlane/metadata/android/zh-CN/short_description.txt @@ -0,0 +1 @@ +极简主义番茄钟 From 25e93cdd3f134417c8d2cb9d296c006197f7f4ab Mon Sep 17 00:00:00 2001 From: Nishant Mishra Date: Thu, 9 Oct 2025 08:49:47 +0530 Subject: [PATCH 16/16] chore: Bump version string, update changelog --- app/build.gradle.kts | 4 ++-- fastlane/metadata/android/en-US/changelogs/11.txt | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/11.txt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9e46fb8..77e1df8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -33,8 +33,8 @@ android { applicationId = "org.nsh07.pomodoro" minSdk = 26 targetSdk = 36 - versionCode = 10 - versionName = "1.4.2" + versionCode = 11 + versionName = "1.4.3" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/fastlane/metadata/android/en-US/changelogs/11.txt b/fastlane/metadata/android/en-US/changelogs/11.txt new file mode 100644 index 0000000..1c37825 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/11.txt @@ -0,0 +1,8 @@ +New features: +- The app is now translated into 6 languages (Chinese (Simplified), English, Hebrew, Hindi, Persian, Ukrainian). You can help translate by going to the app's Weblate page! +- Alarms now use your phone's alarm volume instead of the media volume + +Bug fixes: +- Fixed incorrect calculation of average durations +- Fixed a bug that caused the set session length to not show in the settings slider +- Fixed a bug that caused the focus time on graphs show 0 when it was less than an hour \ No newline at end of file