Add 'More options' experiment

The 'More options' button gets missed by a lot of users
pull/2068/head
Alex Baker 3 years ago
parent d82e594043
commit ff48aa18c2

@ -7,7 +7,7 @@ import at.bitfire.ical4android.Task
import com.todoroo.astrid.helper.UUIDHelper import com.todoroo.astrid.helper.UUIDHelper
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import org.dmfs.tasks.contract.TaskContract import org.dmfs.tasks.contract.TaskContract
import org.tasks.TestUtilities import org.tasks.caldav.iCalendar
import org.tasks.data.CaldavCalendar import org.tasks.data.CaldavCalendar
import org.tasks.data.CaldavDao import org.tasks.data.CaldavDao
import org.tasks.data.MyAndroidTask import org.tasks.data.MyAndroidTask
@ -46,7 +46,7 @@ class TestOpenTaskDao @Inject constructor(
fun insertTask(listId: Long, vtodo: String) { fun insertTask(listId: Long, vtodo: String) {
val ops = ArrayList<BatchOperation.CpoBuilder>() val ops = ArrayList<BatchOperation.CpoBuilder>()
val task = MyAndroidTask(TestUtilities.fromString(vtodo)) val task = MyAndroidTask(iCalendar.fromVtodo(vtodo)!!)
ops.add(task.toBuilder(tasks).withValue(TaskContract.TaskColumns.LIST_ID, listId)) ops.add(task.toBuilder(tasks).withValue(TaskContract.TaskColumns.LIST_ID, listId))
task.enqueueProperties(properties, ops, 0) task.enqueueProperties(properties, ops, 0)
applyOperation(*ops.toTypedArray()) applyOperation(*ops.toTypedArray())

@ -14,4 +14,6 @@ class Firebase @Inject constructor() {
fun addTask(source: String) {} fun addTask(source: String) {}
val subscribeCooldown = false val subscribeCooldown = false
val moreOptionsBadge = false
val moreOptionsSolid = false
} }

@ -73,6 +73,12 @@ class Firebase @Inject constructor(
get() = installCooldown get() = installCooldown
|| preferences.lastSubscribeRequest + days("subscribe_cooldown", 30L) > now() || 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 = private fun days(key: String, default: Long): Long =
TimeUnit.DAYS.toMillis(remoteConfig?.getLong(key) ?: default) TimeUnit.DAYS.toMillis(remoteConfig?.getLong(key) ?: default)

@ -12,7 +12,8 @@ import com.google.android.material.composethemeadapter.MdcTheme
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.tasks.LocalBroadcastManager 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.compose.PurchaseText.PurchaseText
import org.tasks.extensions.Context.toast import org.tasks.extensions.Context.toast
import org.tasks.injection.InjectingAppCompatActivity import org.tasks.injection.InjectingAppCompatActivity
@ -27,6 +28,7 @@ class PurchaseActivity : InjectingAppCompatActivity(), OnPurchasesUpdated {
@Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var localBroadcastManager: LocalBroadcastManager
@Inject lateinit var inventory: Inventory @Inject lateinit var inventory: Inventory
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
@Inject lateinit var firebase: Firebase
private var currentSubscription: Purchase? = null private var currentSubscription: Purchase? = null
private val purchaseReceiver: BroadcastReceiver = object : BroadcastReceiver() { private val purchaseReceiver: BroadcastReceiver = object : BroadcastReceiver() {
@ -53,11 +55,14 @@ class PurchaseActivity : InjectingAppCompatActivity(), OnPurchasesUpdated {
MdcTheme { MdcTheme {
Dialog(onDismissRequest = { finish() }) { Dialog(onDismissRequest = { finish() }) {
PurchaseText( PurchaseText(
nameYourPrice, nameYourPrice = nameYourPrice,
sliderPosition, sliderPosition = sliderPosition,
github, github = github,
IS_GENERIC, solidButton = firebase.moreOptionsSolid,
this::purchase) badge = firebase.moreOptionsBadge,
onDisplayed = { firebase.logEvent(R.string.event_showed_purchase_dialog) },
subscribe = this::purchase,
)
} }
} }
} }

@ -1,31 +1,13 @@
package org.tasks.compose package org.tasks.compose
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.*
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.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.ButtonDefaults import androidx.compose.material.*
import androidx.compose.material.Divider import androidx.compose.runtime.*
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.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color 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.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.google.android.material.composethemeadapter.MdcTheme
import org.tasks.R import org.tasks.R
import org.tasks.Tasks.Companion.IS_GENERIC
import org.tasks.compose.Constants.HALF_KEYLINE import org.tasks.compose.Constants.HALF_KEYLINE
import org.tasks.compose.Constants.KEYLINE_FIRST import org.tasks.compose.Constants.KEYLINE_FIRST
import org.tasks.compose.PurchaseText.PurchaseText import org.tasks.compose.PurchaseText.PurchaseText
import org.tasks.extensions.Context.openUri 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 { object PurchaseText {
private const val POPPER = "\uD83C\uDF89" private const val POPPER = "\uD83C\uDF89"
@ -133,7 +103,9 @@ object PurchaseText {
nameYourPrice: MutableState<Boolean> = mutableStateOf(false), nameYourPrice: MutableState<Boolean> = mutableStateOf(false),
sliderPosition: MutableState<Float> = mutableStateOf(0f), sliderPosition: MutableState<Float> = mutableStateOf(0f),
github: Boolean = false, github: Boolean = false,
fdroid: Boolean = IS_GENERIC, solidButton: Boolean = false,
badge: Boolean = false,
onDisplayed: () -> Unit = {},
subscribe: (Int, Boolean) -> Unit subscribe: (Int, Boolean) -> Unit
) { ) {
Column( Column(
@ -149,15 +121,30 @@ object PurchaseText {
val pagerState = remember { val pagerState = remember {
PagerState(maxPage = (featureList.size - 1).coerceAtLeast(0)) 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) PagerItem(featureList[page], nameYourPrice.value && page == 0)
} }
if (github) { if (github) {
SponsorButton() SponsorButton()
} else { } else {
GooglePlayButtons(nameYourPrice, sliderPosition, pagerState, subscribe) GooglePlayButtons(
nameYourPrice = nameYourPrice,
sliderPosition = sliderPosition,
pagerState = pagerState,
subscribe = subscribe,
solidButton = solidButton,
badge = badge,
)
} }
} }
LaunchedEffect(key1 = Unit) {
onDisplayed()
}
} }
@Composable @Composable
@ -202,6 +189,8 @@ object PurchaseText {
sliderPosition: MutableState<Float>, sliderPosition: MutableState<Float>,
pagerState: PagerState, pagerState: PagerState,
subscribe: (Int, Boolean) -> Unit, subscribe: (Int, Boolean) -> Unit,
solidButton: Boolean,
badge: Boolean,
) { ) {
Column( Column(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@ -221,19 +210,31 @@ object PurchaseText {
pagerState.currentPage = 0 pagerState.currentPage = 0
}, },
colors = ButtonDefaults.textButtonColors( colors = ButtonDefaults.textButtonColors(
backgroundColor = Color.Transparent backgroundColor = if (solidButton)
MaterialTheme.colors.secondary
else
Color.Transparent
) )
) { ) {
Text( BadgedBox(badge = {
text = stringResource( if (!nameYourPrice.value && badge) {
if (nameYourPrice.value) Badge()
R.string.back }
}) {
Text(
text = stringResource(
if (nameYourPrice.value)
R.string.back
else
R.string.more_options
),
color = if (solidButton)
MaterialTheme.colors.onSecondary
else else
R.string.more_options MaterialTheme.colors.secondary,
), style = MaterialTheme.typography.body1
color = MaterialTheme.colors.secondary, )
style = MaterialTheme.typography.body1 }
)
} }
Text( Text(
text = stringResource(R.string.pro_free_trial), text = stringResource(R.string.pro_free_trial),
@ -339,7 +340,7 @@ object PurchaseText {
onClick: (Int, Boolean) -> Unit onClick: (Int, Boolean) -> Unit
) { ) {
Column(horizontalAlignment = Alignment.CenterHorizontally) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
OutlinedButton( Button(
onClick = { onClick(price, monthly) }, onClick = { onClick(price, monthly) },
colors = ButtonDefaults.textButtonColors( colors = ButtonDefaults.textButtonColors(
backgroundColor = MaterialTheme.colors.secondary 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) { _, _ -> }
}
}

@ -423,6 +423,7 @@
<string name="p_install_date">install_date</string> <string name="p_install_date">install_date</string>
<string name="p_default_location">default_location</string> <string name="p_default_location">default_location</string>
<string name="event_showed_purchase_dialog">showed_purchase_dialog</string>
<string name="event_purchase_result">billing_flow_result</string> <string name="event_purchase_result">billing_flow_result</string>
<string name="param_sku">sku</string> <string name="param_sku">sku</string>
<string name="param_result">result</string> <string name="param_result">result</string>

Loading…
Cancel
Save