fix(billing): adapt UI according to plus status
This commit is contained in:
@@ -17,11 +17,68 @@
|
|||||||
|
|
||||||
package org.nsh07.pomodoro.billing
|
package org.nsh07.pomodoro.billing
|
||||||
|
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
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.material3.Button
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||||
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalUriHandler
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import org.nsh07.pomodoro.R
|
||||||
|
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TomatoPlusPaywallDialog(
|
fun TomatoPlusPaywallDialog(
|
||||||
isPlus: Boolean,
|
isPlus: Boolean,
|
||||||
onDismiss: () -> Unit
|
onDismiss: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
val uriHandler = LocalUriHandler.current
|
||||||
|
|
||||||
|
BackHandler(enabled = true, onDismiss)
|
||||||
|
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(colorScheme.surface)
|
||||||
|
) {
|
||||||
|
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.bmc),
|
||||||
|
null,
|
||||||
|
tint = colorScheme.onSurface
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
|
Text(
|
||||||
|
"Tomato FOSS",
|
||||||
|
style = typography.headlineSmall,
|
||||||
|
fontFamily = robotoFlexTopBar,
|
||||||
|
color = colorScheme.onSurface
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
Text(
|
||||||
|
"All features are unlocked in this version. If my app made a difference in your life, please consider supporting me by donating on ${"BuyMeACoffee"}.",
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
color = colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(horizontal = 24.dp)
|
||||||
|
)
|
||||||
|
Spacer(Modifier.height(16.dp))
|
||||||
|
Button(onClick = { uriHandler.openUri("https://coff.ee/nsh07") }) {
|
||||||
|
Text("Buy Me A Coffee")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -164,6 +164,7 @@ fun AppScreen(
|
|||||||
entry<Screen.Timer> {
|
entry<Screen.Timer> {
|
||||||
TimerScreen(
|
TimerScreen(
|
||||||
timerState = uiState,
|
timerState = uiState,
|
||||||
|
isPlus = isPlus,
|
||||||
progress = { progress },
|
progress = { progress },
|
||||||
onAction = { action ->
|
onAction = { action ->
|
||||||
when (action) {
|
when (action) {
|
||||||
|
|||||||
@@ -26,26 +26,19 @@ import androidx.compose.animation.slideInHorizontally
|
|||||||
import androidx.compose.animation.slideOutHorizontally
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
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.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
|
||||||
import androidx.compose.foundation.text.input.TextFieldState
|
import androidx.compose.foundation.text.input.TextFieldState
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.LocalTextStyle
|
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.SliderState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
@@ -58,7 +51,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
|||||||
import androidx.compose.runtime.snapshots.SnapshotStateList
|
import androidx.compose.runtime.snapshots.SnapshotStateList
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -76,6 +68,7 @@ import org.nsh07.pomodoro.service.TimerService
|
|||||||
import org.nsh07.pomodoro.ui.Screen
|
import org.nsh07.pomodoro.ui.Screen
|
||||||
import org.nsh07.pomodoro.ui.settingsScreen.components.AboutCard
|
import org.nsh07.pomodoro.ui.settingsScreen.components.AboutCard
|
||||||
import org.nsh07.pomodoro.ui.settingsScreen.components.ClickableListItem
|
import org.nsh07.pomodoro.ui.settingsScreen.components.ClickableListItem
|
||||||
|
import org.nsh07.pomodoro.ui.settingsScreen.components.PlusPromo
|
||||||
import org.nsh07.pomodoro.ui.settingsScreen.screens.AlarmSettings
|
import org.nsh07.pomodoro.ui.settingsScreen.screens.AlarmSettings
|
||||||
import org.nsh07.pomodoro.ui.settingsScreen.screens.AppearanceSettings
|
import org.nsh07.pomodoro.ui.settingsScreen.screens.AppearanceSettings
|
||||||
import org.nsh07.pomodoro.ui.settingsScreen.screens.TimerSettings
|
import org.nsh07.pomodoro.ui.settingsScreen.screens.TimerSettings
|
||||||
@@ -233,44 +226,20 @@ private fun SettingsScreen(
|
|||||||
) {
|
) {
|
||||||
item { Spacer(Modifier.height(12.dp)) }
|
item { Spacer(Modifier.height(12.dp)) }
|
||||||
|
|
||||||
item {
|
if (!isPlus) item {
|
||||||
Row(
|
PlusPromo(isPlus, setShowPaywall)
|
||||||
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(
|
|
||||||
if (!isPlus) stringResource(R.string.get_plus)
|
|
||||||
else stringResource(R.string.app_name_plus),
|
|
||||||
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))
|
Spacer(Modifier.height(14.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
item { AboutCard() }
|
item { AboutCard(isPlus) }
|
||||||
|
|
||||||
item { Spacer(Modifier.height(12.dp)) }
|
item { Spacer(Modifier.height(12.dp)) }
|
||||||
|
|
||||||
|
if (isPlus) item {
|
||||||
|
PlusPromo(isPlus, setShowPaywall)
|
||||||
|
Spacer(Modifier.height(14.dp))
|
||||||
|
}
|
||||||
|
|
||||||
itemsIndexed(settingsScreens) { index, item ->
|
itemsIndexed(settingsScreens) { index, item ->
|
||||||
ClickableListItem(
|
ClickableListItem(
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
|
|||||||
@@ -51,7 +51,10 @@ import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
|||||||
|
|
||||||
// Taken from https://github.com/shub39/Grit/blob/master/app/src/main/java/com/shub39/grit/core/presentation/settings/ui/component/AboutApp.kt
|
// Taken from https://github.com/shub39/Grit/blob/master/app/src/main/java/com/shub39/grit/core/presentation/settings/ui/component/AboutApp.kt
|
||||||
@Composable
|
@Composable
|
||||||
fun AboutCard(modifier: Modifier = Modifier) {
|
fun AboutCard(
|
||||||
|
isPlus: Boolean,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
val uriHandler = LocalUriHandler.current
|
val uriHandler = LocalUriHandler.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
@@ -77,7 +80,8 @@ fun AboutCard(modifier: Modifier = Modifier) {
|
|||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.app_name),
|
if (!isPlus) stringResource(R.string.app_name)
|
||||||
|
else stringResource(R.string.app_name_plus),
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
fontFamily = robotoFlexTopBar
|
fontFamily = robotoFlexTopBar
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.nsh07.pomodoro.ui.settingsScreen.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.MaterialTheme.colorScheme
|
||||||
|
import androidx.compose.material3.MaterialTheme.typography
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import org.nsh07.pomodoro.R
|
||||||
|
import org.nsh07.pomodoro.ui.theme.AppFonts.robotoFlexTopBar
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PlusPromo(
|
||||||
|
isPlus: Boolean,
|
||||||
|
setShowPaywall: (Boolean) -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
val container = if (isPlus) colorScheme.surfaceBright else colorScheme.primary
|
||||||
|
val onContainer = if (isPlus) colorScheme.onSurface else colorScheme.onPrimary
|
||||||
|
val onContainerVariant = if (isPlus) colorScheme.onSurfaceVariant else colorScheme.onPrimary
|
||||||
|
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
modifier = modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(container)
|
||||||
|
.padding(16.dp)
|
||||||
|
.clickable { setShowPaywall(true) }
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.tomato_logo_notification),
|
||||||
|
null,
|
||||||
|
tint = onContainerVariant,
|
||||||
|
modifier = Modifier
|
||||||
|
.size(24.dp)
|
||||||
|
)
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
if (!isPlus) stringResource(R.string.get_plus)
|
||||||
|
else stringResource(R.string.app_name_plus),
|
||||||
|
style = typography.titleLarge,
|
||||||
|
fontFamily = robotoFlexTopBar,
|
||||||
|
color = onContainer
|
||||||
|
)
|
||||||
|
Spacer(Modifier.weight(1f))
|
||||||
|
Icon(
|
||||||
|
painterResource(R.drawable.arrow_forward_big),
|
||||||
|
null,
|
||||||
|
tint = onContainerVariant
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,6 +107,7 @@ import org.nsh07.pomodoro.ui.timerScreen.viewModel.TimerState
|
|||||||
@Composable
|
@Composable
|
||||||
fun SharedTransitionScope.TimerScreen(
|
fun SharedTransitionScope.TimerScreen(
|
||||||
timerState: TimerState,
|
timerState: TimerState,
|
||||||
|
isPlus: Boolean,
|
||||||
progress: () -> Float,
|
progress: () -> Float,
|
||||||
onAction: (TimerAction) -> Unit,
|
onAction: (TimerAction) -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
@@ -159,7 +160,8 @@ fun SharedTransitionScope.TimerScreen(
|
|||||||
when (it) {
|
when (it) {
|
||||||
TimerMode.BRAND ->
|
TimerMode.BRAND ->
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.app_name),
|
if (!isPlus) stringResource(R.string.app_name)
|
||||||
|
else stringResource(R.string.app_name_plus),
|
||||||
style = TextStyle(
|
style = TextStyle(
|
||||||
fontFamily = robotoFlexTopBar,
|
fontFamily = robotoFlexTopBar,
|
||||||
fontSize = 32.sp,
|
fontSize = 32.sp,
|
||||||
@@ -552,6 +554,7 @@ fun TimerScreenPreview() {
|
|||||||
SharedTransitionLayout {
|
SharedTransitionLayout {
|
||||||
TimerScreen(
|
TimerScreen(
|
||||||
timerState,
|
timerState,
|
||||||
|
isPlus = true,
|
||||||
{ 0.3f },
|
{ 0.3f },
|
||||||
{}
|
{}
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user