diff --git a/app/src/androidTest/java/org/tasks/opentasks/TestOpenTaskDao.kt b/app/src/androidTest/java/org/tasks/opentasks/TestOpenTaskDao.kt index bbda58b02..0ddccef71 100644 --- a/app/src/androidTest/java/org/tasks/opentasks/TestOpenTaskDao.kt +++ b/app/src/androidTest/java/org/tasks/opentasks/TestOpenTaskDao.kt @@ -7,7 +7,7 @@ import at.bitfire.ical4android.Task import com.todoroo.astrid.helper.UUIDHelper import dagger.hilt.android.qualifiers.ApplicationContext import org.dmfs.tasks.contract.TaskContract -import org.tasks.TestUtilities +import org.tasks.caldav.iCalendar import org.tasks.data.CaldavCalendar import org.tasks.data.CaldavDao import org.tasks.data.MyAndroidTask @@ -46,7 +46,7 @@ class TestOpenTaskDao @Inject constructor( fun insertTask(listId: Long, vtodo: String) { val ops = ArrayList() - val task = MyAndroidTask(TestUtilities.fromString(vtodo)) + val task = MyAndroidTask(iCalendar.fromVtodo(vtodo)!!) ops.add(task.toBuilder(tasks).withValue(TaskContract.TaskColumns.LIST_ID, listId)) task.enqueueProperties(properties, ops, 0) applyOperation(*ops.toTypedArray()) diff --git a/app/src/generic/java/org/tasks/analytics/Firebase.kt b/app/src/generic/java/org/tasks/analytics/Firebase.kt index b32a9ef5e..2ff354efa 100644 --- a/app/src/generic/java/org/tasks/analytics/Firebase.kt +++ b/app/src/generic/java/org/tasks/analytics/Firebase.kt @@ -14,4 +14,6 @@ class Firebase @Inject constructor() { fun addTask(source: String) {} val subscribeCooldown = false + val moreOptionsBadge = false + val moreOptionsSolid = false } \ No newline at end of file diff --git a/app/src/googleplay/java/org/tasks/analytics/Firebase.kt b/app/src/googleplay/java/org/tasks/analytics/Firebase.kt index 229f40ec6..b371e8b1d 100644 --- a/app/src/googleplay/java/org/tasks/analytics/Firebase.kt +++ b/app/src/googleplay/java/org/tasks/analytics/Firebase.kt @@ -73,6 +73,12 @@ class Firebase @Inject constructor( get() = installCooldown || preferences.lastSubscribeRequest + days("subscribe_cooldown", 30L) > now() + val moreOptionsBadge: Boolean + get() = remoteConfig?.getBoolean("more_options_badge") ?: false + + val moreOptionsSolid: Boolean + get() = remoteConfig?.getBoolean("more_options_solid") ?: false + private fun days(key: String, default: Long): Long = TimeUnit.DAYS.toMillis(remoteConfig?.getLong(key) ?: default) diff --git a/app/src/main/java/org/tasks/billing/PurchaseActivity.kt b/app/src/main/java/org/tasks/billing/PurchaseActivity.kt index 715c749a5..1d9829299 100644 --- a/app/src/main/java/org/tasks/billing/PurchaseActivity.kt +++ b/app/src/main/java/org/tasks/billing/PurchaseActivity.kt @@ -12,7 +12,8 @@ import com.google.android.material.composethemeadapter.MdcTheme import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import org.tasks.LocalBroadcastManager -import org.tasks.Tasks.Companion.IS_GENERIC +import org.tasks.R +import org.tasks.analytics.Firebase import org.tasks.compose.PurchaseText.PurchaseText import org.tasks.extensions.Context.toast import org.tasks.injection.InjectingAppCompatActivity @@ -27,6 +28,7 @@ class PurchaseActivity : InjectingAppCompatActivity(), OnPurchasesUpdated { @Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var inventory: Inventory @Inject lateinit var preferences: Preferences + @Inject lateinit var firebase: Firebase private var currentSubscription: Purchase? = null private val purchaseReceiver: BroadcastReceiver = object : BroadcastReceiver() { @@ -53,11 +55,14 @@ class PurchaseActivity : InjectingAppCompatActivity(), OnPurchasesUpdated { MdcTheme { Dialog(onDismissRequest = { finish() }) { PurchaseText( - nameYourPrice, - sliderPosition, - github, - IS_GENERIC, - this::purchase) + nameYourPrice = nameYourPrice, + sliderPosition = sliderPosition, + github = github, + solidButton = firebase.moreOptionsSolid, + badge = firebase.moreOptionsBadge, + onDisplayed = { firebase.logEvent(R.string.event_showed_purchase_dialog) }, + subscribe = this::purchase, + ) } } } diff --git a/app/src/main/java/org/tasks/compose/Subscription.kt b/app/src/main/java/org/tasks/compose/Subscription.kt index 652da1640..e30975c04 100644 --- a/app/src/main/java/org/tasks/compose/Subscription.kt +++ b/app/src/main/java/org/tasks/compose/Subscription.kt @@ -1,31 +1,13 @@ package org.tasks.compose +import android.content.res.Configuration.UI_MODE_NIGHT_YES import androidx.compose.foundation.Image import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.requiredSize -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.* import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll -import androidx.compose.material.ButtonDefaults -import androidx.compose.material.Divider -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.OutlinedButton -import androidx.compose.material.Slider -import androidx.compose.material.SliderDefaults -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.material.* +import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -40,25 +22,13 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import com.google.android.material.composethemeadapter.MdcTheme import org.tasks.R -import org.tasks.Tasks.Companion.IS_GENERIC import org.tasks.compose.Constants.HALF_KEYLINE import org.tasks.compose.Constants.KEYLINE_FIRST import org.tasks.compose.PurchaseText.PurchaseText import org.tasks.extensions.Context.openUri -@Preview(showBackground = true, backgroundColor = 0xFFFFFF) -@Composable -private fun LightPreview() { - PurchaseText { _, _ -> } -} - -@Preview(showBackground = true, backgroundColor = 0x202124) -@Composable -private fun DarkPreview() { - PurchaseText { _, _ -> } -} - object PurchaseText { private const val POPPER = "\uD83C\uDF89" @@ -133,7 +103,9 @@ object PurchaseText { nameYourPrice: MutableState = mutableStateOf(false), sliderPosition: MutableState = mutableStateOf(0f), github: Boolean = false, - fdroid: Boolean = IS_GENERIC, + solidButton: Boolean = false, + badge: Boolean = false, + onDisplayed: () -> Unit = {}, subscribe: (Int, Boolean) -> Unit ) { Column( @@ -149,15 +121,30 @@ object PurchaseText { val pagerState = remember { PagerState(maxPage = (featureList.size - 1).coerceAtLeast(0)) } - Pager(state = pagerState, modifier = Modifier.fillMaxWidth().height(200.dp)) { + Pager( + state = pagerState, + modifier = Modifier + .fillMaxWidth() + .height(200.dp) + ) { PagerItem(featureList[page], nameYourPrice.value && page == 0) } if (github) { SponsorButton() } else { - GooglePlayButtons(nameYourPrice, sliderPosition, pagerState, subscribe) + GooglePlayButtons( + nameYourPrice = nameYourPrice, + sliderPosition = sliderPosition, + pagerState = pagerState, + subscribe = subscribe, + solidButton = solidButton, + badge = badge, + ) } } + LaunchedEffect(key1 = Unit) { + onDisplayed() + } } @Composable @@ -202,6 +189,8 @@ object PurchaseText { sliderPosition: MutableState, pagerState: PagerState, subscribe: (Int, Boolean) -> Unit, + solidButton: Boolean, + badge: Boolean, ) { Column( modifier = Modifier.fillMaxWidth(), @@ -221,19 +210,31 @@ object PurchaseText { pagerState.currentPage = 0 }, colors = ButtonDefaults.textButtonColors( - backgroundColor = Color.Transparent + backgroundColor = if (solidButton) + MaterialTheme.colors.secondary + else + Color.Transparent ) ) { - Text( - text = stringResource( - if (nameYourPrice.value) - R.string.back + BadgedBox(badge = { + if (!nameYourPrice.value && badge) { + Badge() + } + }) { + Text( + text = stringResource( + if (nameYourPrice.value) + R.string.back + else + R.string.more_options + ), + color = if (solidButton) + MaterialTheme.colors.onSecondary else - R.string.more_options - ), - color = MaterialTheme.colors.secondary, - style = MaterialTheme.typography.body1 - ) + MaterialTheme.colors.secondary, + style = MaterialTheme.typography.body1 + ) + } } Text( text = stringResource(R.string.pro_free_trial), @@ -339,7 +340,7 @@ object PurchaseText { onClick: (Int, Boolean) -> Unit ) { Column(horizontalAlignment = Alignment.CenterHorizontally) { - OutlinedButton( + Button( onClick = { onClick(price, monthly) }, colors = ButtonDefaults.textButtonColors( backgroundColor = MaterialTheme.colors.secondary @@ -409,3 +410,30 @@ object PurchaseText { } } } + +@Preview(showBackground = true) +@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun PurchaseDialogPreview() { + MdcTheme { + PurchaseText { _, _ -> } + } +} + +@Preview(showBackground = true) +@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun PurchaseDialogPreviewSolid() { + MdcTheme { + PurchaseText(solidButton = true) { _, _ -> } + } +} + +@Preview(showBackground = true) +@Preview(showBackground = true, uiMode = UI_MODE_NIGHT_YES) +@Composable +private fun PurchaseDialogPreviewBadge() { + MdcTheme { + PurchaseText(badge = true) { _, _ -> } + } +} diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml index 3ccaa39a1..2daaf4472 100644 --- a/app/src/main/res/values/keys.xml +++ b/app/src/main/res/values/keys.xml @@ -423,6 +423,7 @@ install_date default_location + showed_purchase_dialog billing_flow_result sku result