Skip to content

Commit b9c1b86

Browse files
committed
Merge branch 'dev'
2 parents fec38de + 7051c36 commit b9c1b86

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1424
-250
lines changed

.github/repo_photos/banner.png

-163 KB
Binary file not shown.

.github/repo_photos/googleplay.png

20 KB
Loading

.github/workflows/android.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ jobs:
1919
run: chmod +x gradlew
2020

2121
- name: Build debug APK with Gradle
22-
run: ./gradlew assembleDebug
22+
run: ./gradlew assembleFossDebug
2323

2424
- name: Run tests
25-
run: ./gradlew testDebugUnitTest
25+
run: ./gradlew testFossDebugUnitTest
2626

2727
- name: Upload debug APK artifact
28-
uses: actions/upload-artifact@v4
28+
uses: actions/upload-artifact@v5
2929
with:
3030
name: tomato-debug
3131
path: ./app/build/outputs/apk/debug/app-debug.apk

README.md

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,6 @@ Tomato is a minimalist Pomodoro timer for Android based on Material 3 Expressive
77

88
</div>
99

10-
> [!NOTE]
11-
> Tomato is available on Google Play in closed testing. Please [use this link to join the testers Google Group](https://groups.google.com/g/nsh07-app-testers) and then install [Tomato from the Play Store with this link](https://play.google.com/store/apps/details?id=org.nsh07.pomodoro). Tomato needs 12 testers for at least 14 days for the app to be available on Google Play publicly.
12-
1310
<div align="center">
1411

1512
<a href="https://hosted.weblate.org/engage/tomato/?utm_source=widget">
@@ -24,15 +21,18 @@ Tomato is a minimalist Pomodoro timer for Android based on Material 3 Expressive
2421
<a href="https://github.com/nsh07/tomato/blob/main/LICENSE">
2522
<img src="https://img.shields.io/github/license/nsh07/tomato?logo=gnu&color=blue&labelColor=1a1a1a">
2623
</a>
27-
<img src="https://img.shields.io/badge/API-26+-blue?logo=android&labelColor=1a1a1a">
24+
<img src="https://img.shields.io/badge/API-27+-blue?logo=android&labelColor=1a1a1a">
2825

2926
<p>
30-
<a href="https://apt.izzysoft.de/fdroid/index/apk/org.nsh07.pomodoro">
31-
<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" width="200">
27+
<a href="https://play.google.com/store/apps/details?id=org.nsh07.pomodoro">
28+
<img src=".github/repo_photos/googleplay.png" width="200">
3229
</a>
3330
<a href="https://f-droid.org/packages/org.nsh07.pomodoro">
3431
<img src="https://f-droid.org/badge/get-it-on.png" width="200">
3532
</a>
33+
<a href="https://apt.izzysoft.de/fdroid/index/apk/org.nsh07.pomodoro">
34+
<img src="https://gitlab.com/IzzyOnDroid/repo/-/raw/master/assets/IzzyOnDroid.png" width="200">
35+
</a>
3636
</p>
3737
<p>
3838
<a href="https://hosted.weblate.org/engage/tomato/">
@@ -48,9 +48,11 @@ Tomato is a minimalist Pomodoro timer for Android based on Material 3 Expressive
4848

4949
<br/>
5050

51-
> *"... an app to support this habit helps me stay focused and get things done. Currently, that app is Tomato."*
51+
> *"... an app to support this habit helps me stay focused and get things done. Currently, that app
52+
is Tomato."*
5253

53-
\- [*Android Authority*](https://www.androidauthority.com/best-new-android-apps-october-2025-3602966/)
54+
\- [*Android
55+
Authority*](https://www.androidauthority.com/best-new-android-apps-october-2025-3602966/)
5456

5557
<br/>
5658

@@ -92,23 +94,20 @@ translating this project into languages you know.
9294

9395
## Download
9496

95-
- **Google Play Store** (recommended): Tomato is available for closed testing on Google Play. Use
96-
[this link to join the testers Google Group](https://groups.google.com/g/nsh07-app-testers), then
97-
[install Tomato from the Play Store with this link](https://play.google.com/store/apps/details?id=org.nsh07.pomodoro) and help Tomato to get an official Play Store release.
97+
- **Google Play Store** (recommended): Tomato will soon be available (currently in closed testing)
98+
on the Google Play Store.
99+
[You can find it through this link](https://play.google.com/store/apps/details?id=org.nsh07.pomodoro).
98100
- **F-Droid** (recommended): Tomato is available on the official F-Droid repository. Simply open
99-
your preferred F-Droid app and search for Tomato.
100-
Updates on F-Droid are generally a week late. To get faster updates, you can install it through
101+
your preferred F-Droid app and search for Tomato. Updates on F-Droid are generally a week late. To
102+
get faster updates, you can install it through
101103
the [IzzyOnDroid repository](https://apt.izzysoft.de/fdroid/).
102-
- **Obtainium** (recommended): You can add this GitHub repository
103-
on [Obtainium](https://obtainium.imranr.dev/) to get updates directly from GitHub releases. This
104-
is the fastest way to install and update Tomato.
105104
- **GitHub releases**: Alternatively, you can manually download and install APKs from
106-
the [Releases](https://github.com/nsh07/Tomato/releases/latest) section of this repo (This
107-
method is not recommended, use Obtainium instead).
105+
the [Releases](https://github.com/nsh07/Tomato/releases/latest) section of this repo (This method
106+
is not recommended, use Google Play/F-Droid instead).
108107

109108
> [!TIP]
110109
> To [verify](https://developer.android.com/studio/command-line/apksigner#usage-verify) the APK
111-
> downloaded from Obtainium/GitHub, use the following signing certificate fingerprints:
110+
> downloaded from GitHub, use the following signing certificate fingerprints:
112111
> ```
113112
> SHA1: B1:4E:17:93:11:E8:DB:D5:35:EF:8D:E9:FB:8F:FF:08:F8:EC:65:08
114113
> SHA256: 07:BE:F3:05:81:BA:EE:8F:45:EC:93:E4:7E:E6:8E:F2:08:74:E5:0E:F5:70:9C:78:B2:EE:67:AC:86:BE:4C:3D

app/build.gradle.kts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ android {
4343
applicationId = "org.nsh07.pomodoro"
4444
minSdk = 27
4545
targetSdk = 36
46-
versionCode = 15
47-
versionName = "1.6.0"
46+
versionCode = 17
47+
versionName = "1.6.2"
4848

4949
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
5050
}
@@ -58,6 +58,19 @@ android {
5858
)
5959
}
6060
}
61+
62+
flavorDimensions += "version"
63+
productFlavors {
64+
create("foss") {
65+
dimension = "version"
66+
isDefault = true
67+
}
68+
create("play") {
69+
dimension = "version"
70+
versionNameSuffix = "-play"
71+
}
72+
}
73+
6174
compileOptions {
6275
sourceCompatibility = JavaVersion.VERSION_17
6376
targetCompatibility = JavaVersion.VERSION_17
@@ -103,6 +116,9 @@ dependencies {
103116
implementation(libs.androidx.room.ktx)
104117
ksp(libs.androidx.room.compiler)
105118

119+
"playImplementation"(libs.revenuecat.purchases)
120+
"playImplementation"(libs.revenuecat.purchases.ui)
121+
106122
testImplementation(libs.junit)
107123

108124
androidTestImplementation(libs.androidx.junit)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (c) 2025 Nishant Mishra
3+
*
4+
* This file is part of Tomato - a minimalist pomodoro timer for Android.
5+
*
6+
* Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
7+
* General Public License as published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
11+
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12+
* Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License along with Tomato.
15+
* If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package org.nsh07.pomodoro.billing
19+
20+
import kotlinx.coroutines.flow.MutableStateFlow
21+
import kotlinx.coroutines.flow.asStateFlow
22+
23+
/**
24+
* Google Play implementation of BillingManager
25+
*/
26+
class FossBillingManager : BillingManager {
27+
override val isPlus = MutableStateFlow(true).asStateFlow()
28+
override val isLoaded = MutableStateFlow(true).asStateFlow()
29+
}
30+
31+
object BillingManagerProvider {
32+
val manager: BillingManager = FossBillingManager()
33+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2025 Nishant Mishra
3+
*
4+
* This file is part of Tomato - a minimalist pomodoro timer for Android.
5+
*
6+
* Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
7+
* General Public License as published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
11+
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12+
* Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License along with Tomato.
15+
* If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package org.nsh07.pomodoro.billing
19+
20+
import androidx.activity.compose.BackHandler
21+
import androidx.compose.foundation.background
22+
import androidx.compose.foundation.layout.Box
23+
import androidx.compose.foundation.layout.Column
24+
import androidx.compose.foundation.layout.Spacer
25+
import androidx.compose.foundation.layout.fillMaxSize
26+
import androidx.compose.foundation.layout.height
27+
import androidx.compose.foundation.layout.padding
28+
import androidx.compose.material3.Button
29+
import androidx.compose.material3.Icon
30+
import androidx.compose.material3.MaterialTheme.colorScheme
31+
import androidx.compose.material3.MaterialTheme.typography
32+
import androidx.compose.material3.Text
33+
import androidx.compose.runtime.Composable
34+
import androidx.compose.ui.Alignment
35+
import androidx.compose.ui.Modifier
36+
import androidx.compose.ui.platform.LocalUriHandler
37+
import androidx.compose.ui.res.painterResource
38+
import androidx.compose.ui.res.stringResource
39+
import androidx.compose.ui.text.style.TextAlign
40+
import androidx.compose.ui.unit.dp
41+
import org.nsh07.pomodoro.R
42+
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
43+
44+
@Composable
45+
fun TomatoPlusPaywallDialog(
46+
isPlus: Boolean,
47+
onDismiss: () -> Unit
48+
) {
49+
val uriHandler = LocalUriHandler.current
50+
51+
BackHandler(enabled = true, onDismiss)
52+
53+
Box(
54+
contentAlignment = Alignment.Center,
55+
modifier = Modifier
56+
.fillMaxSize()
57+
.background(colorScheme.surface)
58+
) {
59+
Column(horizontalAlignment = Alignment.CenterHorizontally) {
60+
Icon(
61+
painterResource(R.drawable.bmc),
62+
null,
63+
tint = colorScheme.onSurface
64+
)
65+
Spacer(Modifier.height(16.dp))
66+
Text(
67+
stringResource(R.string.tomato_foss),
68+
style = typography.headlineSmall,
69+
fontFamily = robotoFlexTopBar,
70+
color = colorScheme.onSurface
71+
)
72+
Spacer(Modifier.height(8.dp))
73+
Text(
74+
stringResource(R.string.tomato_foss_desc, "BuyMeACoffee"),
75+
textAlign = TextAlign.Center,
76+
color = colorScheme.onSurfaceVariant,
77+
modifier = Modifier.padding(horizontal = 24.dp)
78+
)
79+
Spacer(Modifier.height(16.dp))
80+
Button(onClick = { uriHandler.openUri("https://coff.ee/nsh07") }) {
81+
Text("Buy Me A Coffee")
82+
}
83+
}
84+
}
85+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright (c) 2025 Nishant Mishra
3+
*
4+
* This file is part of Tomato - a minimalist pomodoro timer for Android.
5+
*
6+
* Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
7+
* General Public License as published by the Free Software Foundation, either version 3 of the
8+
* License, or (at your option) any later version.
9+
*
10+
* Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
11+
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
12+
* Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License along with Tomato.
15+
* If not, see <https://www.gnu.org/licenses/>.
16+
*/
17+
18+
package org.nsh07.pomodoro.billing
19+
20+
import android.content.Context
21+
22+
fun initializePurchases(context: Context) {}

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
1919
xmlns:tools="http://schemas.android.com/tools">
2020

21+
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
2122
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
2223
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
2324
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

app/src/main/java/org/nsh07/pomodoro/MainActivity.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
3030
import org.nsh07.pomodoro.ui.AppScreen
3131
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel
3232
import org.nsh07.pomodoro.ui.theme.TomatoTheme
33-
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel
3433
import org.nsh07.pomodoro.utils.toColor
3534

3635
class MainActivity : ComponentActivity() {
3736

38-
private val timerViewModel: TimerViewModel by viewModels(factoryProducer = { TimerViewModel.Factory })
3937
private val settingsViewModel: SettingsViewModel by viewModels(factoryProducer = { SettingsViewModel.Factory })
4038

4139
private val appContainer by lazy {
@@ -62,6 +60,20 @@ class MainActivity : ComponentActivity() {
6260

6361
val seed = preferencesState.colorScheme.toColor()
6462

63+
val isPlus by settingsViewModel.isPlus.collectAsStateWithLifecycle()
64+
val isPurchaseStateLoaded by settingsViewModel.isPurchaseStateLoaded.collectAsStateWithLifecycle()
65+
val isSettingsLoaded by settingsViewModel.isSettingsLoaded.collectAsStateWithLifecycle()
66+
67+
LaunchedEffect(isPurchaseStateLoaded, isPlus, isSettingsLoaded) {
68+
if (isPurchaseStateLoaded && isSettingsLoaded) {
69+
if (!isPlus) {
70+
settingsViewModel.resetPaywalledSettings()
71+
} else {
72+
settingsViewModel.reloadSettings()
73+
}
74+
}
75+
}
76+
6577
TomatoTheme(
6678
darkTheme = darkTheme,
6779
seedColor = seed,
@@ -73,7 +85,7 @@ class MainActivity : ComponentActivity() {
7385
}
7486

7587
AppScreen(
76-
timerViewModel = timerViewModel,
88+
isPlus = isPlus,
7789
isAODEnabled = preferencesState.aodEnabled,
7890
setTimerFrequency = {
7991
appContainer.appTimerRepository.timerFrequency = it

0 commit comments

Comments
 (0)