diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 31e1df6..a396eba 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -116,7 +116,8 @@ dependencies {
implementation(libs.androidx.room.ktx)
ksp(libs.androidx.room.compiler)
- "playImplementation"(libs.purchases)
+ "playImplementation"(libs.revenuecat.purchases)
+ "playImplementation"(libs.revenuecat.purchases.ui)
testImplementation(libs.junit)
diff --git a/app/src/foss/java/org/nsh07/pomodoro/billing/FossBillingManager.kt b/app/src/foss/java/org/nsh07/pomodoro/billing/FossBillingManager.kt
new file mode 100644
index 0000000..4a155a3
--- /dev/null
+++ b/app/src/foss/java/org/nsh07/pomodoro/billing/FossBillingManager.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * This file is part of Tomato - a minimalist pomodoro timer for Android.
+ *
+ * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tomato.
+ * If not, see .
+ */
+
+package org.nsh07.pomodoro.billing
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/**
+ * Google Play implementation of BillingManager
+ */
+class FossBillingManager : BillingManager {
+ override val isPlus = MutableStateFlow(true).asStateFlow()
+}
+
+object BillingManagerProvider {
+ val manager: BillingManager = FossBillingManager()
+}
\ No newline at end of file
diff --git a/app/src/foss/java/org/nsh07/pomodoro/billing/TomatoPlusPaywallDialog.kt b/app/src/foss/java/org/nsh07/pomodoro/billing/TomatoPlusPaywallDialog.kt
new file mode 100644
index 0000000..973041c
--- /dev/null
+++ b/app/src/foss/java/org/nsh07/pomodoro/billing/TomatoPlusPaywallDialog.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * This file is part of Tomato - a minimalist pomodoro timer for Android.
+ *
+ * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tomato.
+ * If not, see .
+ */
+
+package org.nsh07.pomodoro.billing
+
+import androidx.compose.runtime.Composable
+
+@Composable
+fun TomatoPlusPaywallDialog(
+ isPlus: Boolean,
+ onDismiss: () -> Unit
+) {
+}
\ No newline at end of file
diff --git a/app/src/foss/java/org/nsh07/pomodoro/billing/initializePurchases.kt b/app/src/foss/java/org/nsh07/pomodoro/billing/initializePurchases.kt
new file mode 100644
index 0000000..7a44002
--- /dev/null
+++ b/app/src/foss/java/org/nsh07/pomodoro/billing/initializePurchases.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * This file is part of Tomato - a minimalist pomodoro timer for Android.
+ *
+ * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tomato.
+ * If not, see .
+ */
+
+package org.nsh07.pomodoro.billing
+
+import android.content.Context
+
+fun initializePurchases(context: Context) {}
\ No newline at end of file
diff --git a/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt b/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt
index a129af6..4f34773 100644
--- a/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/MainActivity.kt
@@ -30,12 +30,10 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.nsh07.pomodoro.ui.AppScreen
import org.nsh07.pomodoro.ui.settingsScreen.viewModel.SettingsViewModel
import org.nsh07.pomodoro.ui.theme.TomatoTheme
-import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel
import org.nsh07.pomodoro.utils.toColor
class MainActivity : ComponentActivity() {
- private val timerViewModel: TimerViewModel by viewModels(factoryProducer = { TimerViewModel.Factory })
private val settingsViewModel: SettingsViewModel by viewModels(factoryProducer = { SettingsViewModel.Factory })
private val appContainer by lazy {
@@ -62,6 +60,8 @@ class MainActivity : ComponentActivity() {
val seed = preferencesState.colorScheme.toColor()
+ val isPlus by settingsViewModel.isPlus.collectAsStateWithLifecycle()
+
TomatoTheme(
darkTheme = darkTheme,
seedColor = seed,
@@ -73,7 +73,7 @@ class MainActivity : ComponentActivity() {
}
AppScreen(
- timerViewModel = timerViewModel,
+ isPlus = isPlus,
isAODEnabled = preferencesState.aodEnabled,
setTimerFrequency = {
appContainer.appTimerRepository.timerFrequency = it
diff --git a/app/src/main/java/org/nsh07/pomodoro/TomatoApplication.kt b/app/src/main/java/org/nsh07/pomodoro/TomatoApplication.kt
index 87be588..47de7fe 100644
--- a/app/src/main/java/org/nsh07/pomodoro/TomatoApplication.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/TomatoApplication.kt
@@ -1,8 +1,26 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * This file is part of Tomato - a minimalist pomodoro timer for Android.
+ *
+ * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tomato.
+ * If not, see .
+ */
+
package org.nsh07.pomodoro
import android.app.Application
import android.app.NotificationChannel
import android.app.NotificationManager
+import org.nsh07.pomodoro.billing.initializePurchases
import org.nsh07.pomodoro.data.AppContainer
import org.nsh07.pomodoro.data.DefaultAppContainer
@@ -12,6 +30,8 @@ class TomatoApplication : Application() {
super.onCreate()
container = DefaultAppContainer(this)
+ initializePurchases(this)
+
val notificationChannel = NotificationChannel(
"timer",
getString(R.string.timer_progress),
diff --git a/app/src/main/java/org/nsh07/pomodoro/billing/BillingManager.kt b/app/src/main/java/org/nsh07/pomodoro/billing/BillingManager.kt
new file mode 100644
index 0000000..66b1659
--- /dev/null
+++ b/app/src/main/java/org/nsh07/pomodoro/billing/BillingManager.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * This file is part of Tomato - a minimalist pomodoro timer for Android.
+ *
+ * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tomato.
+ * If not, see .
+ */
+
+package org.nsh07.pomodoro.billing
+
+import kotlinx.coroutines.flow.StateFlow
+
+interface BillingManager {
+ val isPlus: StateFlow
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt b/app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt
index 4ca23c9..bf445c8 100644
--- a/app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt
@@ -26,6 +26,8 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import kotlinx.coroutines.flow.MutableStateFlow
import org.nsh07.pomodoro.R
+import org.nsh07.pomodoro.billing.BillingManager
+import org.nsh07.pomodoro.billing.BillingManagerProvider
import org.nsh07.pomodoro.service.addTimerActions
import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState
import org.nsh07.pomodoro.utils.millisecondsToStr
@@ -34,6 +36,7 @@ interface AppContainer {
val appPreferenceRepository: AppPreferenceRepository
val appStatRepository: AppStatRepository
val appTimerRepository: AppTimerRepository
+ val billingManager: BillingManager
val notificationManager: NotificationManagerCompat
val notificationManagerService: NotificationManager
val notificationBuilder: NotificationCompat.Builder
@@ -54,6 +57,8 @@ class DefaultAppContainer(context: Context) : AppContainer {
override val appTimerRepository: AppTimerRepository by lazy { AppTimerRepository() }
+ override val billingManager: BillingManager by lazy { BillingManagerProvider.manager }
+
override val notificationManager: NotificationManagerCompat by lazy {
NotificationManagerCompat.from(context)
}
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt
index 905e377..5455ad9 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt
@@ -41,8 +41,10 @@ import androidx.compose.material3.Text
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfo
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberUpdatedState
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLayoutDirection
@@ -54,6 +56,7 @@ import androidx.navigation3.runtime.entryProvider
import androidx.navigation3.runtime.rememberNavBackStack
import androidx.navigation3.ui.NavDisplay
import androidx.window.core.layout.WindowSizeClass
+import org.nsh07.pomodoro.billing.TomatoPlusPaywallDialog
import org.nsh07.pomodoro.service.TimerService
import org.nsh07.pomodoro.ui.settingsScreen.SettingsScreenRoot
import org.nsh07.pomodoro.ui.statsScreen.StatsScreenRoot
@@ -65,10 +68,11 @@ import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerViewModel
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun AppScreen(
- modifier: Modifier = Modifier,
- timerViewModel: TimerViewModel = viewModel(factory = TimerViewModel.Factory),
isAODEnabled: Boolean,
- setTimerFrequency: (Float) -> Unit
+ isPlus: Boolean,
+ setTimerFrequency: (Float) -> Unit,
+ modifier: Modifier = Modifier,
+ timerViewModel: TimerViewModel = viewModel(factory = TimerViewModel.Factory)
) {
val context = LocalContext.current
@@ -91,6 +95,7 @@ fun AppScreen(
}
}
+ var showPaywall by remember { mutableStateOf(false) }
Scaffold(
bottomBar = {
@@ -218,6 +223,7 @@ fun AppScreen(
entry {
SettingsScreenRoot(
+ setShowPaywall = { showPaywall = it },
modifier = modifier.padding(
start = contentPadding.calculateStartPadding(layoutDirection),
end = contentPadding.calculateEndPadding(layoutDirection),
@@ -240,4 +246,5 @@ fun AppScreen(
)
}
}
+ if (showPaywall) TomatoPlusPaywallDialog(isPlus = isPlus) { showPaywall = false }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt
index a22b1f5..356c922 100644
--- a/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt
+++ b/app/src/main/java/org/nsh07/pomodoro/ui/settingsScreen/SettingsScreen.kt
@@ -17,6 +17,7 @@
package org.nsh07.pomodoro.ui.settingsScreen
+import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import androidx.compose.animation.fadeIn
@@ -25,19 +26,26 @@ import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
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.lazy.itemsIndexed
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.input.TextFieldState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalTextStyle
+import androidx.compose.material3.MaterialTheme.colorScheme
+import androidx.compose.material3.MaterialTheme.typography
import androidx.compose.material3.SliderState
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
@@ -50,6 +58,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.snapshots.SnapshotStateList
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
@@ -80,6 +89,7 @@ import org.nsh07.pomodoro.ui.theme.CustomColors.topBarColors
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SettingsScreenRoot(
+ setShowPaywall: (Boolean) -> Unit,
modifier: Modifier = Modifier,
viewModel: SettingsViewModel = viewModel(factory = SettingsViewModel.Factory)
) {
@@ -102,6 +112,7 @@ fun SettingsScreenRoot(
viewModel.longBreakTimeTextFieldState
}
+ val isPlus by viewModel.isPlus.collectAsStateWithLifecycle()
val alarmEnabled by viewModel.alarmEnabled.collectAsStateWithLifecycle(true)
val vibrateEnabled by viewModel.vibrateEnabled.collectAsStateWithLifecycle(true)
val dndEnabled by viewModel.dndEnabled.collectAsStateWithLifecycle(false)
@@ -119,6 +130,7 @@ fun SettingsScreenRoot(
}
SettingsScreen(
+ isPlus = isPlus,
preferencesState = preferencesState,
backStack = backStack,
focusTimeInputFieldState = focusTimeInputFieldState,
@@ -143,13 +155,16 @@ fun SettingsScreenRoot(
},
onThemeChange = viewModel::saveTheme,
onColorSchemeChange = viewModel::saveColorScheme,
+ setShowPaywall = setShowPaywall,
modifier = modifier
)
}
+@SuppressLint("LocalContextGetResourceValueCall")
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
private fun SettingsScreen(
+ isPlus: Boolean,
preferencesState: PreferencesState,
backStack: SnapshotStateList,
focusTimeInputFieldState: TextFieldState,
@@ -168,6 +183,7 @@ private fun SettingsScreen(
onAlarmSoundChanged: (Uri?) -> Unit,
onThemeChange: (String) -> Unit,
onColorSchemeChange: (Color) -> Unit,
+ setShowPaywall: (Boolean) -> Unit,
modifier: Modifier = Modifier
) {
val context = LocalContext.current
@@ -217,6 +233,39 @@ private fun SettingsScreen(
) {
item { Spacer(Modifier.height(12.dp)) }
+ if (!isPlus) item {
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ modifier = Modifier
+ .clip(CircleShape)
+ .background(colorScheme.primary)
+ .padding(16.dp)
+ .clickable { setShowPaywall(true) }
+ ) {
+ Icon(
+ painterResource(R.drawable.tomato_logo_notification),
+ null,
+ tint = colorScheme.onPrimary,
+ modifier = Modifier
+ .size(24.dp)
+ )
+ Spacer(Modifier.width(8.dp))
+ Text(
+ "Get Tomato+",
+ style = typography.titleLarge,
+ fontFamily = robotoFlexTopBar,
+ color = colorScheme.onPrimary
+ )
+ Spacer(Modifier.weight(1f))
+ Icon(
+ painterResource(R.drawable.arrow_forward_big),
+ null,
+ tint = colorScheme.onPrimary
+ )
+ }
+ Spacer(Modifier.height(14.dp))
+ }
+
item { AboutCard() }
item { Spacer(Modifier.height(12.dp)) }
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 0a3262f..6f9041d 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
@@ -40,17 +40,21 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.nsh07.pomodoro.TomatoApplication
+import org.nsh07.pomodoro.billing.BillingManager
import org.nsh07.pomodoro.data.AppPreferenceRepository
import org.nsh07.pomodoro.data.TimerRepository
import org.nsh07.pomodoro.ui.Screen
@OptIn(FlowPreview::class, ExperimentalMaterial3Api::class)
class SettingsViewModel(
+ private val billingManager: BillingManager,
private val preferenceRepository: AppPreferenceRepository,
private val timerRepository: TimerRepository,
) : ViewModel() {
val backStack = mutableStateListOf(Screen.Settings.Main)
+ val isPlus = billingManager.isPlus
+
private val _preferencesState = MutableStateFlow(PreferencesState())
val preferencesState = _preferencesState.asStateFlow()
@@ -237,8 +241,10 @@ class SettingsViewModel(
val application = (this[APPLICATION_KEY] as TomatoApplication)
val appPreferenceRepository = application.container.appPreferenceRepository
val appTimerRepository = application.container.appTimerRepository
+ val appBillingManager = application.container.billingManager
SettingsViewModel(
+ billingManager = appBillingManager,
preferenceRepository = appPreferenceRepository,
timerRepository = appTimerRepository,
)
diff --git a/app/src/play/java/org/nsh07/pomodoro/billing/PlayBillingManager.kt b/app/src/play/java/org/nsh07/pomodoro/billing/PlayBillingManager.kt
new file mode 100644
index 0000000..94bfcb2
--- /dev/null
+++ b/app/src/play/java/org/nsh07/pomodoro/billing/PlayBillingManager.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * This file is part of Tomato - a minimalist pomodoro timer for Android.
+ *
+ * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tomato.
+ * If not, see .
+ */
+
+package org.nsh07.pomodoro.billing
+
+import android.util.Log
+import com.revenuecat.purchases.Purchases
+import com.revenuecat.purchases.getCustomerInfoWith
+import com.revenuecat.purchases.interfaces.UpdatedCustomerInfoListener
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+private const val ENTITLEMENT_ID = "plus"
+
+/**
+ * Google Play implementation of BillingManager
+ */
+class PlayBillingManager : BillingManager {
+ private val _isPlus = MutableStateFlow(false)
+ override val isPlus = _isPlus.asStateFlow()
+
+ private val purchases by lazy { Purchases.sharedInstance }
+
+ init {
+ purchases.updatedCustomerInfoListener =
+ UpdatedCustomerInfoListener { customerInfo ->
+ _isPlus.value = customerInfo.entitlements[ENTITLEMENT_ID]?.isActive == true
+ }
+
+ // Fetch initial customer info
+ purchases.getCustomerInfoWith(
+ onSuccess = { customerInfo ->
+ _isPlus.value = customerInfo.entitlements[ENTITLEMENT_ID]?.isActive == true
+ },
+ onError = { error ->
+ Log.e("GooglePlayPaywallManager", "Error fetching customer info: $error")
+ }
+ )
+ }
+}
+
+object BillingManagerProvider {
+ val manager: BillingManager = PlayBillingManager()
+}
\ No newline at end of file
diff --git a/app/src/play/java/org/nsh07/pomodoro/billing/TomatoPlusPaywallDialog.kt b/app/src/play/java/org/nsh07/pomodoro/billing/TomatoPlusPaywallDialog.kt
new file mode 100644
index 0000000..1ecda02
--- /dev/null
+++ b/app/src/play/java/org/nsh07/pomodoro/billing/TomatoPlusPaywallDialog.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * This file is part of Tomato - a minimalist pomodoro timer for Android.
+ *
+ * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tomato.
+ * If not, see .
+ */
+
+package org.nsh07.pomodoro.billing
+
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.FilledTonalIconButton
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import com.revenuecat.purchases.ui.revenuecatui.Paywall
+import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions
+import com.revenuecat.purchases.ui.revenuecatui.customercenter.CustomerCenter
+import org.nsh07.pomodoro.R
+
+@Composable
+fun TomatoPlusPaywallDialog(
+ isPlus: Boolean,
+ onDismiss: () -> Unit
+) {
+ val paywallOptions = remember {
+ PaywallOptions.Builder(dismissRequest = onDismiss)
+ .build()
+ }
+
+ Scaffold { innerPadding ->
+ if (!isPlus) {
+ Paywall(paywallOptions)
+
+ FilledTonalIconButton(
+ onClick = onDismiss,
+ modifier = Modifier
+ .padding(innerPadding)
+ .padding(16.dp)
+ ) {
+ Icon(
+ painterResource(R.drawable.arrow_back),
+ null
+ )
+ }
+ } else {
+ CustomerCenter(onDismiss = onDismiss)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/play/java/org/nsh07/pomodoro/billing/initializePurchases.kt b/app/src/play/java/org/nsh07/pomodoro/billing/initializePurchases.kt
new file mode 100644
index 0000000..00e2437
--- /dev/null
+++ b/app/src/play/java/org/nsh07/pomodoro/billing/initializePurchases.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2025 Nishant Mishra
+ *
+ * This file is part of Tomato - a minimalist pomodoro timer for Android.
+ *
+ * Tomato is free software: you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * Tomato is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+ * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with Tomato.
+ * If not, see .
+ */
+
+package org.nsh07.pomodoro.billing
+
+import android.content.Context
+import com.revenuecat.purchases.Purchases
+import com.revenuecat.purchases.PurchasesConfiguration
+
+fun initializePurchases(context: Context) {
+ Purchases.configure(
+ PurchasesConfiguration
+ .Builder(context, "goog_jBpRIBjTYvhKYluCqkPXSHbuFbX")
+ .build()
+ )
+}
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 9356ceb..85f21bf 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -12,7 +12,7 @@ ksp = "2.2.20-2.0.4"
lifecycleRuntimeKtx = "2.9.4"
materialKolor = "3.0.1"
navigation3 = "1.0.0-beta01"
-purchases = "9.12.0"
+revenuecat = "9.12.0"
room = "2.8.3"
vico = "2.2.1"
@@ -40,7 +40,8 @@ androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
material-kolor = { module = "com.materialkolor:material-kolor", version.ref = "materialKolor" }
-purchases = { module = "com.revenuecat.purchases:purchases", version.ref = "purchases" }
+revenuecat-purchases = { module = "com.revenuecat.purchases:purchases", version.ref = "revenuecat" }
+revenuecat-purchases-ui = { module = "com.revenuecat.purchases:purchases-ui", version.ref = "revenuecat" }
vico-compose-m3 = { group = "com.patrykandpatrick.vico", name = "compose-m3", version.ref = "vico" }
[plugins]