mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2274 Payment | Welcome screen (#1000)
This commit is contained in:
parent
7d65104c34
commit
d123867aaf
12 changed files with 536 additions and 201 deletions
|
@ -19,6 +19,7 @@ import com.anytypeio.anytype.core_utils.ui.BaseBottomSheetComposeFragment
|
|||
import com.anytypeio.anytype.di.common.componentManager
|
||||
import com.anytypeio.anytype.screens.CodeScreen
|
||||
import com.anytypeio.anytype.screens.MainPaymentsScreen
|
||||
import com.anytypeio.anytype.screens.PaymentWelcomeScreen
|
||||
import com.anytypeio.anytype.screens.TierScreen
|
||||
import com.anytypeio.anytype.ui.settings.typography
|
||||
import com.anytypeio.anytype.viewmodel.PaymentsNavigation
|
||||
|
@ -62,6 +63,10 @@ class PaymentsFragment : BaseBottomSheetComposeFragment() {
|
|||
when (command) {
|
||||
PaymentsNavigation.Tier -> navController.navigate(PaymentsNavigation.Tier.route)
|
||||
PaymentsNavigation.Code -> navController.navigate(PaymentsNavigation.Code.route)
|
||||
PaymentsNavigation.Welcome -> {
|
||||
navController.popBackStack(PaymentsNavigation.Main.route, false)
|
||||
navController.navigate(PaymentsNavigation.Welcome.route)
|
||||
}
|
||||
PaymentsNavigation.Dismiss -> navController.popBackStack()
|
||||
else -> {}
|
||||
}
|
||||
|
@ -84,19 +89,24 @@ class PaymentsFragment : BaseBottomSheetComposeFragment() {
|
|||
private fun NavigationGraph(navController: NavHostController) {
|
||||
NavHost(navController = navController, startDestination = PaymentsNavigation.Main.route) {
|
||||
composable(PaymentsNavigation.Main.route) {
|
||||
MainPaymentsScreen()
|
||||
InitMainPaymentsScreen()
|
||||
}
|
||||
bottomSheet(PaymentsNavigation.Tier.route) {
|
||||
TierScreen()
|
||||
InitTierScreen()
|
||||
}
|
||||
bottomSheet(PaymentsNavigation.Code.route) {
|
||||
CodeScreen()
|
||||
InitCodeScreen()
|
||||
}
|
||||
bottomSheet(PaymentsNavigation.Welcome.route) {
|
||||
InitWelcomeScreen()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MainPaymentsScreen() {
|
||||
private fun InitMainPaymentsScreen() {
|
||||
skipCollapsed()
|
||||
expand()
|
||||
MainPaymentsScreen(
|
||||
state = vm.viewState.collectAsStateWithLifecycle().value,
|
||||
tierClicked = vm::onTierClicked
|
||||
|
@ -104,24 +114,32 @@ class PaymentsFragment : BaseBottomSheetComposeFragment() {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun TierScreen() {
|
||||
private fun InitTierScreen() {
|
||||
TierScreen(
|
||||
tier = vm.selectedTier.collectAsStateWithLifecycle().value,
|
||||
state = vm.tierState.collectAsStateWithLifecycle().value,
|
||||
onDismiss = vm::onDismissTier,
|
||||
actionPay = vm::onPayButtonClicked
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun CodeScreen() {
|
||||
private fun InitCodeScreen() {
|
||||
CodeScreen(
|
||||
state = vm.codeViewState.collectAsStateWithLifecycle().value,
|
||||
state = vm.codeState.collectAsStateWithLifecycle().value,
|
||||
actionResend = { },
|
||||
actionCode = vm::onActionCode,
|
||||
onDismiss = vm::onDismissCode
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InitWelcomeScreen() {
|
||||
PaymentWelcomeScreen(
|
||||
state = vm.welcomeState.collectAsStateWithLifecycle().value,
|
||||
onDismiss = vm::onDismissWelcome
|
||||
)
|
||||
}
|
||||
|
||||
override fun injectDependencies() {
|
||||
componentManager().paymentsComponent.get().inject(this)
|
||||
}
|
||||
|
|
|
@ -223,4 +223,6 @@
|
|||
<color name="widget_edit_view_stroke_color_active">@color/palette_system_amber_50</color>
|
||||
<color name="widget_edit_view_stroke_color_inactive">@color/shape_primary</color>
|
||||
|
||||
<color name="payments_tier_current_background">#F6F6F6</color>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1343,20 +1343,20 @@
|
|||
|
||||
<!--region PAYMENTS -->
|
||||
|
||||
<string name="payments_header">Let’s build\ntogether</string>
|
||||
<string name="payments_header">Membership</string>
|
||||
<string name="payments_subheader">Joining Anytype network means contributing to its story</string>
|
||||
|
||||
<string name="payments_card_text_1">Co-create with us</string>
|
||||
<string name="payments_card_description_1">Stay closely connected with our team and community. Join calls with the team, influence Anytype\'s evolution, and have your say on features.</string>
|
||||
<string name="payments_card_text_1">Co-create the Vision</string>
|
||||
<string name="payments_card_description_1">As a valued member your voice matters! Engage in exclusive events, shape strategic choices, and influence our roadmap.</string>
|
||||
|
||||
<string name="payments_card_text_2">Gain Benefits</string>
|
||||
<string name="payments_card_description_2">Our members have unique identity on Anytype Network, more storage, shared spaces and members per space for extensive collaboration.</string>
|
||||
<string name="payments_card_text_2">Unlock Member Benefits</string>
|
||||
<string name="payments_card_description_2">Members enjoy higher backup storage & sync limits, invitations for multiple guests to collaborate in shared spaces, and a unique identity on the Anytype Network.</string>
|
||||
|
||||
<string name="payments_card_text_3">Support the Vision</string>
|
||||
<string name="payments_card_description_3">Your contribution supports our independent team and endorses our vision︎ of a user-driven, secure, and collaborative digital environment.</string>
|
||||
<string name="payments_card_text_3">Support Digital Independence</string>
|
||||
<string name="payments_card_description_3">Your contribution supports our team and endorses our vision of a user-owned, secure, and collaborative digital network.</string>
|
||||
|
||||
<string name="payments_card_text_4">Invest in Connectivity</string>
|
||||
<string name="payments_card_description_4">Our software is free by design, but we thrive on the network that connects us all. Support us, and you\'re investing in the very infrastructure that keeps us united.</string>
|
||||
<string name="payments_card_description_4">Our network\'s value exceeds the sum of its parts. Your membership sustains the infrastructure for its growth which underpins this network.</string>
|
||||
|
||||
<string name="payments_tier_explorer">Explorer</string>
|
||||
<string name="payments_tier_explorer_description">Dive into the network and enjoy the thrill of one-on-one collaboration</string>
|
||||
|
@ -1375,24 +1375,25 @@
|
|||
<string name="payments_terms_link">Terms and conditions</string>
|
||||
<string name="payments_let_us_link_start">Would you like to use Anytype for business, education, etc.?</string>
|
||||
<string name="payments_let_us_link_end">Please let us know here.</string>
|
||||
<string name="payments_current_label">Current</string>
|
||||
|
||||
<!-- Membership Level Details -->
|
||||
<string name="payments_details_name_title">Pick your unique name</string>
|
||||
<string name="payments_details_name_subtitle">This is your unique name on the Anytype network, confirming your Membership. It acts as your personal domain and cannot be changed.</string>
|
||||
<string name="payments_details_name_hint">Myself</string>
|
||||
<string name="payments_details_name_domain">.any</string>
|
||||
<string name="payments_details_name_min">Min 7 characters</string>
|
||||
<string name="payments_details_name_error">This name is already taken!</string>
|
||||
<string name="payments_details_name_success">This name is up for grabs!</string>
|
||||
<!-- Tier details -->
|
||||
<string name="payments_tier_details_name_title">Pick your unique name</string>
|
||||
<string name="payments_tier_details_name_subtitle">This is your unique name on the Anytype network, confirming your Membership. It acts as your personal domain and cannot be changed.</string>
|
||||
<string name="payments_tier_details_name_hint">Myself</string>
|
||||
<string name="payments_tier_details_name_domain">.any</string>
|
||||
<string name="payments_tier_details_name_min">Min 7 characters</string>
|
||||
<string name="payments_tier_details_name_error">This name is already taken!</string>
|
||||
<string name="payments_tier_details_name_success">This name is up for grabs!</string>
|
||||
|
||||
<string name="payments_details_info_explorer">Dive into the network and enjoy the thrill of one-on-one collaboration</string>
|
||||
<string name="payments_tier_details_info_explorer">Dive into the network and enjoy the thrill of one-on-one collaboration</string>
|
||||
<string-array name="payments_benefits_explorer">
|
||||
<item>1 GB of network space</item>
|
||||
<item>10 one-to-one spaces</item>
|
||||
<item>Up to 10 shared spaces in read-only mode</item>
|
||||
</string-array>
|
||||
|
||||
<string name="payments_details_info_builder">Unlock the magic of multi-party collaboration and enjoy top-notch support</string>
|
||||
<string name="payments_tier_details_info_builder">Unlock the magic of multi-party collaboration and enjoy top-notch support</string>
|
||||
<string-array name="payments_benefits_builder">
|
||||
<item>Unique name (from 7 characters)</item>
|
||||
<item>128 GB of network space</item>
|
||||
|
@ -1400,7 +1401,7 @@
|
|||
<item>Priority support</item>
|
||||
</string-array>
|
||||
|
||||
<string name="payments_details_info_cocreator">Support our adventure and unlock exclusive access and perks</string>
|
||||
<string name="payments_tier_details_info_cocreator">Support our adventure and unlock exclusive access and perks</string>
|
||||
<string-array name="payments_benefits_cocreator">
|
||||
<item>Unique name (from 5 characters)</item>
|
||||
<item>256 GB of network space</item>
|
||||
|
@ -1417,10 +1418,20 @@
|
|||
<string name="payments_email_checkbox_text">I\'d like to get updates on products and enjoy free perks!</string>
|
||||
<string name="payments_email_hint">E-mail</string>
|
||||
|
||||
<string name="payments_tier_current_title">Your current status:</string>
|
||||
<string name="payments_tier_current_valid">Valid until</string>
|
||||
<string name="payments_tier_current_paid_by">Paid by Card</string>
|
||||
<string name="payments_tier_current_button">Manage payment</string>
|
||||
|
||||
<!-- Payments Code -->
|
||||
<string name="payments_code_title">Enter the code sent to your email</string>
|
||||
<string name="payments_code_resend">Resend</string>
|
||||
<string name="payments_code_resend_in">Resend in %1$n sec</string>
|
||||
|
||||
|
||||
<!-- Payments Welcome -->
|
||||
<string name="payments_welcome_title">Welcome to the network,\n%1$s</string>
|
||||
<string name="payments_welcome_subtitle">Big cheers for your curiosity!</string>
|
||||
<string name="payments_welcome_button">Continue</string>
|
||||
|
||||
</resources>
|
|
@ -1,31 +1,36 @@
|
|||
package com.anytypeio.anytype.models
|
||||
|
||||
import com.anytypeio.anytype.viewmodel.TierId
|
||||
|
||||
sealed class Tier {
|
||||
abstract val id: String
|
||||
abstract val id: TierId
|
||||
abstract val isCurrent: Boolean
|
||||
abstract val validUntil: String
|
||||
|
||||
data class Explorer(
|
||||
override val id: String,
|
||||
override val id: TierId,
|
||||
override val isCurrent: Boolean,
|
||||
override val validUntil: String,
|
||||
val price: String = "",
|
||||
val email: String = "",
|
||||
val isChecked: Boolean = true
|
||||
) : Tier()
|
||||
|
||||
data class Builder(
|
||||
override val id: String,
|
||||
override val id: TierId,
|
||||
override val isCurrent: Boolean,
|
||||
override val validUntil: String,
|
||||
val price: String = "",
|
||||
val interval: String = "",
|
||||
val name: String = "",
|
||||
val nameIsTaken: Boolean = false,
|
||||
val nameIsFree: Boolean = false
|
||||
|
||||
) : Tier()
|
||||
|
||||
data class CoCreator(
|
||||
override val id: String,
|
||||
override val id: TierId,
|
||||
override val isCurrent: Boolean,
|
||||
override val validUntil: String,
|
||||
val price: String = "",
|
||||
val interval: String = "",
|
||||
val name: String = "",
|
||||
|
@ -34,8 +39,9 @@ sealed class Tier {
|
|||
) : Tier()
|
||||
|
||||
data class Custom(
|
||||
override val id: String,
|
||||
override val id: TierId,
|
||||
override val isCurrent: Boolean,
|
||||
override val validUntil: String,
|
||||
val price: String = ""
|
||||
) : Tier()
|
||||
}
|
|
@ -52,38 +52,42 @@ import com.anytypeio.anytype.core_ui.views.HeadlineTitle
|
|||
import com.anytypeio.anytype.core_ui.views.PreviewTitle1Regular
|
||||
import com.anytypeio.anytype.peyments.R
|
||||
import com.anytypeio.anytype.viewmodel.PaymentsCodeState
|
||||
import com.anytypeio.anytype.viewmodel.TierId
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun CodeScreen(
|
||||
state: PaymentsCodeState,
|
||||
actionResend: () -> Unit,
|
||||
actionCode: (String) -> Unit,
|
||||
actionCode: (String, TierId) -> Unit,
|
||||
onDismiss: () -> Unit
|
||||
) {
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
ModalBottomSheet(
|
||||
sheetState = sheetState,
|
||||
onDismissRequest = onDismiss,
|
||||
containerColor = colorResource(id = R.color.background_primary),
|
||||
content = { ModalCodeContent(state = state, actionCode = actionCode) }
|
||||
)
|
||||
if (state is PaymentsCodeState.Visible) {
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
ModalBottomSheet(
|
||||
sheetState = sheetState,
|
||||
onDismissRequest = onDismiss,
|
||||
containerColor = colorResource(id = R.color.background_primary),
|
||||
content = { ModalCodeContent(state = state, actionCode = { code -> actionCode(code, state.tierId)}) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ModalCodeContent(state: PaymentsCodeState, actionCode: (String) -> Unit) {
|
||||
private fun ModalCodeContent(state: PaymentsCodeState.Visible, actionCode: (String) -> Unit) {
|
||||
val focusRequesters = remember { List(4) { FocusRequester() } }
|
||||
val enteredDigits = remember { mutableStateListOf<Char>() }
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
LaunchedEffect(key1 = enteredDigits.size) {
|
||||
if (enteredDigits.size == 4) {
|
||||
actionCode(enteredDigits.joinToString(""))
|
||||
val code = enteredDigits.joinToString("")
|
||||
actionCode(code)
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = state) {
|
||||
if (state is PaymentsCodeState.Loading) {
|
||||
if (state is PaymentsCodeState.Visible.Loading) {
|
||||
focusManager.clearFocus(true)
|
||||
}
|
||||
}
|
||||
|
@ -114,7 +118,7 @@ private fun ModalCodeContent(state: PaymentsCodeState, actionCode: (String) -> U
|
|||
) {
|
||||
focusRequesters.forEachIndexed { index, focusRequester ->
|
||||
CodeNumber(
|
||||
isEnabled = state !is PaymentsCodeState.Loading,
|
||||
isEnabled = state !is PaymentsCodeState.Visible.Loading,
|
||||
modifier = modifier,
|
||||
focusRequester = focusRequester,
|
||||
onDigitEntered = { digit ->
|
||||
|
@ -131,7 +135,7 @@ private fun ModalCodeContent(state: PaymentsCodeState, actionCode: (String) -> U
|
|||
if (index < 3) Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
}
|
||||
if (state is PaymentsCodeState.Error) {
|
||||
if (state is PaymentsCodeState.Visible.Error) {
|
||||
Text(
|
||||
text = state.message,
|
||||
color = colorResource(id = R.color.palette_system_red),
|
||||
|
@ -152,7 +156,7 @@ private fun ModalCodeContent(state: PaymentsCodeState, actionCode: (String) -> U
|
|||
}
|
||||
AnimatedVisibility(
|
||||
modifier = Modifier.align(Alignment.Center),
|
||||
visible = state is PaymentsCodeState.Loading,
|
||||
visible = state is PaymentsCodeState.Visible.Loading,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut()
|
||||
) {
|
||||
|
@ -227,7 +231,7 @@ private fun CodeNumber(
|
|||
@Composable
|
||||
fun EnterCodeModalPreview() {
|
||||
ModalCodeContent(
|
||||
state = PaymentsCodeState.Loading,
|
||||
actionCode = {}
|
||||
state = PaymentsCodeState.Visible.Loading(TierId("123")),
|
||||
actionCode = { _ -> }
|
||||
)
|
||||
}
|
|
@ -54,10 +54,11 @@ import com.anytypeio.anytype.core_ui.views.Caption1Regular
|
|||
import com.anytypeio.anytype.core_ui.views.Relations2
|
||||
import com.anytypeio.anytype.core_ui.views.fontRiccioneRegular
|
||||
import com.anytypeio.anytype.models.Tier
|
||||
import com.anytypeio.anytype.viewmodel.PaymentsState
|
||||
import com.anytypeio.anytype.viewmodel.PaymentsMainState
|
||||
import com.anytypeio.anytype.viewmodel.TierId
|
||||
|
||||
@Composable
|
||||
fun MainPaymentsScreen(state: PaymentsState, tierClicked: (Tier) -> Unit) {
|
||||
fun MainPaymentsScreen(state: PaymentsMainState, tierClicked: (TierId) -> Unit) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.nestedScroll(rememberNestedScrollInteropConnection())
|
||||
|
@ -74,10 +75,13 @@ fun MainPaymentsScreen(state: PaymentsState, tierClicked: (Tier) -> Unit) {
|
|||
.padding(bottom = 20.dp)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
if (state is PaymentsState.Default) {
|
||||
Header()
|
||||
if (state is PaymentsMainState.Default) {
|
||||
Title()
|
||||
Spacer(modifier = Modifier.height(7.dp))
|
||||
Subtitle()
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
InfoCards()
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
TiersList(tiers = state.tiers, tierClicked = tierClicked)
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
LinkButton(text = stringResource(id = R.string.payments_member_link), action = {})
|
||||
|
@ -88,9 +92,9 @@ fun MainPaymentsScreen(state: PaymentsState, tierClicked: (Tier) -> Unit) {
|
|||
Spacer(modifier = Modifier.height(32.dp))
|
||||
BottomText()
|
||||
}
|
||||
if (state is PaymentsState.PaymentSuccess) {
|
||||
Header()
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
if (state is PaymentsMainState.PaymentSuccess) {
|
||||
Title()
|
||||
Spacer(modifier = Modifier.height(39.dp))
|
||||
TiersList(tiers = state.tiers, tierClicked = tierClicked)
|
||||
Spacer(modifier = Modifier.height(32.dp))
|
||||
LinkButton(text = stringResource(id = R.string.payments_member_link), action = {})
|
||||
|
@ -106,7 +110,7 @@ fun MainPaymentsScreen(state: PaymentsState, tierClicked: (Tier) -> Unit) {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun Header() {
|
||||
private fun Title() {
|
||||
|
||||
// Dragger at the top, centered
|
||||
Box(
|
||||
|
@ -133,7 +137,10 @@ private fun Header() {
|
|||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Subtitle() {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
@ -142,7 +149,7 @@ private fun Header() {
|
|||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 60.dp, end = 60.dp, top = 7.dp),
|
||||
.padding(start = 60.dp, end = 60.dp),
|
||||
text = stringResource(id = R.string.payments_subheader),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = Relations2,
|
||||
|
@ -153,13 +160,12 @@ private fun Header() {
|
|||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun TiersList(tiers: List<Tier>, tierClicked: (Tier) -> Unit) {
|
||||
fun TiersList(tiers: List<Tier>, tierClicked: (TierId) -> Unit) {
|
||||
val itemsScroll = rememberLazyListState(initialFirstVisibleItemIndex = 1)
|
||||
LazyRow(
|
||||
state = itemsScroll,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 32.dp),
|
||||
.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(20.dp),
|
||||
contentPadding = PaddingValues(start = 20.dp, end = 20.dp),
|
||||
flingBehavior = rememberSnapFlingBehavior(lazyListState = itemsScroll)
|
||||
|
@ -174,7 +180,8 @@ fun TiersList(tiers: List<Tier>, tierClicked: (Tier) -> Unit) {
|
|||
radialGradient = resources.radialGradient,
|
||||
icon = resources.smallIcon,
|
||||
buttonText = stringResource(id = R.string.payments_button_learn),
|
||||
onClick = { tierClicked.invoke(tier) }
|
||||
onClick = { tierClicked.invoke(tier.id) },
|
||||
isCurrent = tier.isCurrent
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -281,12 +288,12 @@ fun BottomText() {
|
|||
@Composable
|
||||
fun MainPaymentsScreenPreview() {
|
||||
val tiers = listOf(
|
||||
Tier.Explorer("999", isCurrent = true),
|
||||
Tier.Builder("999", isCurrent = false),
|
||||
Tier.CoCreator("999", isCurrent = false),
|
||||
Tier.Custom("999", isCurrent = false)
|
||||
Tier.Explorer(TierId("999"), isCurrent = true, validUntil = "2022-12-31"),
|
||||
Tier.Builder(TierId("999"), isCurrent = true, validUntil = "2022-12-31"),
|
||||
Tier.CoCreator(TierId("999"), isCurrent = false, validUntil = "2022-12-31"),
|
||||
Tier.Custom(TierId("999"), isCurrent = false, validUntil = "2022-12-31")
|
||||
)
|
||||
MainPaymentsScreen(PaymentsState.PaymentSuccess(tiers), {})
|
||||
MainPaymentsScreen(PaymentsMainState.PaymentSuccess(tiers), {})
|
||||
}
|
||||
|
||||
val headerTextStyle = TextStyle(
|
||||
|
|
|
@ -52,32 +52,37 @@ import com.anytypeio.anytype.core_ui.views.BodyBold
|
|||
import com.anytypeio.anytype.core_ui.views.BodyCallout
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonPrimary
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSecondary
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineTitle
|
||||
import com.anytypeio.anytype.core_ui.views.Relations1
|
||||
import com.anytypeio.anytype.core_ui.views.Relations2
|
||||
import com.anytypeio.anytype.models.Tier
|
||||
import com.anytypeio.anytype.peyments.R
|
||||
import com.anytypeio.anytype.viewmodel.PaymentsTierState
|
||||
import com.anytypeio.anytype.viewmodel.TierId
|
||||
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun TierScreen(tier: Tier?, onDismiss: () -> Unit, actionPay: () -> Unit) {
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier.padding(top = 30.dp),
|
||||
sheetState = sheetState,
|
||||
containerColor = Color.Transparent,
|
||||
dragHandle = null,
|
||||
onDismissRequest = { onDismiss() },
|
||||
content = {
|
||||
MembershipLevels(tier = tier, actionPay = actionPay)
|
||||
}
|
||||
)
|
||||
fun TierScreen(state: PaymentsTierState, onDismiss: () -> Unit, actionPay: (TierId) -> Unit) {
|
||||
if (state is PaymentsTierState.Visible) {
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier.padding(top = 30.dp),
|
||||
sheetState = sheetState,
|
||||
containerColor = Color.Transparent,
|
||||
dragHandle = null,
|
||||
onDismissRequest = { onDismiss() },
|
||||
content = {
|
||||
MembershipLevels(tier = state.tier, actionPay = { actionPay(state.tier.id) })
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MembershipLevels(tier: Tier?, actionPay: () -> Unit) {
|
||||
fun MembershipLevels(tier: Tier, actionPay: () -> Unit) {
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -153,29 +158,32 @@ fun MembershipLevels(tier: Tier?, actionPay: () -> Unit) {
|
|||
})
|
||||
}
|
||||
if (tier is Tier.Builder) {
|
||||
NamePickerAndButton(
|
||||
name = tier.name,
|
||||
nameIsTaken = tier.nameIsTaken,
|
||||
nameIsFree = tier.nameIsFree,
|
||||
price = tier.price,
|
||||
interval = tier.interval,
|
||||
actionPay = actionPay
|
||||
)
|
||||
if (tier.isCurrent) {
|
||||
StatusSubscribed(tier, {})
|
||||
} else {
|
||||
NamePickerAndButton(
|
||||
name = tier.name,
|
||||
nameIsTaken = tier.nameIsTaken,
|
||||
nameIsFree = tier.nameIsFree,
|
||||
price = tier.price,
|
||||
interval = tier.interval,
|
||||
actionPay = actionPay
|
||||
)
|
||||
}
|
||||
}
|
||||
if (tier is Tier.CoCreator) {
|
||||
NamePickerAndButton(
|
||||
name = tier.name,
|
||||
nameIsTaken = tier.nameIsTaken,
|
||||
nameIsFree = tier.nameIsFree,
|
||||
price = tier.price,
|
||||
interval = tier.interval,
|
||||
actionPay = actionPay
|
||||
)
|
||||
Price(tier.price, tier.interval)
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
ButtonPay(enabled = true, actionPay = {
|
||||
|
||||
})
|
||||
if (tier.isCurrent) {
|
||||
StatusSubscribed(tier, {})
|
||||
} else {
|
||||
NamePickerAndButton(
|
||||
name = tier.name,
|
||||
nameIsTaken = tier.nameIsTaken,
|
||||
nameIsFree = tier.nameIsFree,
|
||||
price = tier.price,
|
||||
interval = tier.interval,
|
||||
actionPay = actionPay
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,7 +219,7 @@ fun NamePickerAndButton(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 26.dp),
|
||||
text = stringResource(id = R.string.payments_details_name_title),
|
||||
text = stringResource(id = R.string.payments_tier_details_name_title),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = BodyBold,
|
||||
textAlign = TextAlign.Start
|
||||
|
@ -220,7 +228,7 @@ fun NamePickerAndButton(
|
|||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 6.dp),
|
||||
text = stringResource(id = R.string.payments_details_name_subtitle),
|
||||
text = stringResource(id = R.string.payments_tier_details_name_subtitle),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = BodyCallout,
|
||||
textAlign = TextAlign.Start
|
||||
|
@ -256,7 +264,7 @@ fun NamePickerAndButton(
|
|||
decorationBox = { innerTextField ->
|
||||
if (innerValue.isEmpty()) {
|
||||
Text(
|
||||
text = stringResource(id = com.anytypeio.anytype.localization.R.string.payments_details_name_hint),
|
||||
text = stringResource(id = com.anytypeio.anytype.localization.R.string.payments_tier_details_name_hint),
|
||||
style = BodyRegular,
|
||||
color = colorResource(id = com.anytypeio.anytype.core_ui.R.color.text_tertiary),
|
||||
modifier = Modifier
|
||||
|
@ -268,7 +276,7 @@ fun NamePickerAndButton(
|
|||
}
|
||||
)
|
||||
Text(
|
||||
text = stringResource(id = R.string.payments_details_name_domain),
|
||||
text = stringResource(id = R.string.payments_tier_details_name_domain),
|
||||
style = BodyRegular,
|
||||
color = colorResource(id = R.color.text_primary)
|
||||
)
|
||||
|
@ -277,13 +285,13 @@ fun NamePickerAndButton(
|
|||
Divider(paddingStart = 0.dp, paddingEnd = 0.dp)
|
||||
val (messageTextColor, messageText) = when {
|
||||
nameIsTaken ->
|
||||
colorResource(id = R.color.palette_system_red) to stringResource(id = R.string.payments_details_name_error)
|
||||
colorResource(id = R.color.palette_system_red) to stringResource(id = R.string.payments_tier_details_name_error)
|
||||
|
||||
nameIsFree ->
|
||||
colorResource(id = R.color.palette_dark_lime) to stringResource(id = R.string.payments_details_name_success)
|
||||
colorResource(id = R.color.palette_dark_lime) to stringResource(id = R.string.payments_tier_details_name_success)
|
||||
|
||||
else ->
|
||||
colorResource(id = R.color.text_secondary) to stringResource(id = R.string.payments_details_name_min)
|
||||
colorResource(id = R.color.text_secondary) to stringResource(id = R.string.payments_tier_details_name_min)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Text(
|
||||
|
@ -303,6 +311,80 @@ fun NamePickerAndButton(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun StatusSubscribed(tier: Tier, actionManage: () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.background(
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
color = colorResource(id = R.color.background_primary)
|
||||
)
|
||||
.padding(start = 20.dp, end = 20.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 26.dp),
|
||||
text = stringResource(id = R.string.payments_tier_current_title),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = BodyBold,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight()
|
||||
.background(
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
color = colorResource(id = R.color.payments_tier_current_background)
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 34.dp),
|
||||
text = stringResource(id = R.string.payments_tier_current_valid),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = Relations2,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 4.dp),
|
||||
text = tier.validUntil,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = HeadlineTitle,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 23.dp, bottom = 15.dp),
|
||||
text = stringResource(id = R.string.payments_tier_current_paid_by),
|
||||
color = colorResource(id = R.color.text_secondary),
|
||||
style = Relations2,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
ButtonSecondary(
|
||||
enabled = true,
|
||||
text = stringResource(id = R.string.payments_tier_current_button),
|
||||
onClick = { actionManage() },
|
||||
size = ButtonSize.LargeSecondary,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Price(price: String, interval: String) {
|
||||
Row() {
|
||||
|
@ -485,10 +567,11 @@ private fun ButtonPay(enabled: Boolean, actionPay: () -> Unit) {
|
|||
fun MyLevel() {
|
||||
MembershipLevels(
|
||||
tier = Tier.Builder(
|
||||
id = "121",
|
||||
id = TierId("121"),
|
||||
isCurrent = true,
|
||||
price = "$99",
|
||||
interval = "per year"
|
||||
interval = "per year",
|
||||
validUntil = "12/12/2025",
|
||||
),
|
||||
actionPay = {}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
package com.anytypeio.anytype.screens
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
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.wrapContentHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.rememberModalBottomSheetState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.anytypeio.anytype.core_ui.views.BodyRegular
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSecondary
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.HeadlineHeading
|
||||
import com.anytypeio.anytype.models.Tier
|
||||
import com.anytypeio.anytype.peyments.R
|
||||
import com.anytypeio.anytype.viewmodel.PaymentsWelcomeState
|
||||
import com.anytypeio.anytype.viewmodel.TierId
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun PaymentWelcomeScreen(state: PaymentsWelcomeState, onDismiss: () -> Unit) {
|
||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||
if (state is PaymentsWelcomeState.Initial) {
|
||||
ModalBottomSheet(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp)
|
||||
.fillMaxWidth()
|
||||
.wrapContentHeight(),
|
||||
sheetState = sheetState,
|
||||
onDismissRequest = onDismiss,
|
||||
containerColor = colorResource(id = R.color.background_secondary),
|
||||
content = {
|
||||
val tierResources = mapTierToResources(state.tier)
|
||||
if (tierResources != null) WelcomeContent(tierResources, onDismiss)
|
||||
},
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
dragHandle = null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WelcomeContent(tierResources: TierResources, onDismiss: () -> Unit) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(36.dp))
|
||||
Icon(
|
||||
modifier = Modifier.wrapContentSize(),
|
||||
painter = painterResource(id = tierResources.mediumIcon!!),
|
||||
contentDescription = "logo",
|
||||
tint = tierResources.radialGradient
|
||||
)
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp),
|
||||
text = stringResource(id = R.string.payments_welcome_title, tierResources.title),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = HeadlineHeading,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(7.dp))
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp),
|
||||
text = stringResource(id = R.string.payments_welcome_subtitle),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = BodyRegular,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
Spacer(modifier = Modifier.height(30.dp))
|
||||
ButtonSecondary(
|
||||
text = stringResource(id = R.string.payments_welcome_button),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 20.dp),
|
||||
onClick = { onDismiss() },
|
||||
size = ButtonSize.LargeSecondary
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PaymentWelcomeScreenPreview() {
|
||||
PaymentWelcomeScreen(
|
||||
PaymentsWelcomeState.Initial(Tier.Explorer(TierId("Free"), true, "01-01-2025")), {})
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.anytypeio.anytype.screens
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
|
@ -9,10 +10,12 @@ import androidx.compose.foundation.layout.height
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.wrapContentHeight
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
@ -32,6 +35,7 @@ import com.anytypeio.anytype.core_ui.foundation.noRippleThrottledClickable
|
|||
import com.anytypeio.anytype.core_ui.views.ButtonPrimary
|
||||
import com.anytypeio.anytype.core_ui.views.ButtonSize
|
||||
import com.anytypeio.anytype.core_ui.views.Caption1Regular
|
||||
import com.anytypeio.anytype.core_ui.views.Relations3
|
||||
import com.anytypeio.anytype.core_ui.views.fontInterSemibold
|
||||
import com.anytypeio.anytype.models.Tier
|
||||
|
||||
|
@ -43,7 +47,8 @@ fun TierView(
|
|||
radialGradient: Color,
|
||||
icon: Int,
|
||||
buttonText: String,
|
||||
onClick: () -> Unit
|
||||
onClick: () -> Unit,
|
||||
isCurrent: Boolean
|
||||
) {
|
||||
val brush = Brush.verticalGradient(
|
||||
listOf(
|
||||
|
@ -52,60 +57,81 @@ fun TierView(
|
|||
)
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(192.dp)
|
||||
.wrapContentHeight()
|
||||
.background(
|
||||
color = colorResource(id = R.color.shape_tertiary),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.noRippleThrottledClickable { onClick() }
|
||||
) {
|
||||
Box(
|
||||
Box(modifier = Modifier.wrapContentSize()) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(80.dp)
|
||||
.background(brush = brush, shape = RoundedCornerShape(16.dp)),
|
||||
contentAlignment = androidx.compose.ui.Alignment.BottomStart
|
||||
.width(192.dp)
|
||||
.wrapContentHeight()
|
||||
.background(
|
||||
color = colorResource(id = R.color.shape_tertiary),
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.noRippleThrottledClickable { onClick() }
|
||||
) {
|
||||
Icon(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp),
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = "logo",
|
||||
tint = radialGradient
|
||||
.fillMaxWidth()
|
||||
.height(80.dp)
|
||||
.background(brush = brush, shape = RoundedCornerShape(16.dp)),
|
||||
contentAlignment = Alignment.BottomStart
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp),
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = "logo",
|
||||
tint = radialGradient
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 17.dp, top = 10.dp),
|
||||
text = title,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = titleTextStyle,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(96.dp)
|
||||
.padding(start = 16.dp, end = 16.dp, top = 5.dp),
|
||||
text = subTitle,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = Caption1Regular,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
PriceOrOption()
|
||||
ButtonPrimary(
|
||||
text = buttonText,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
onClick = { onClick() },
|
||||
size = ButtonSize.Small
|
||||
)
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
|
||||
if (isCurrent) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.wrapContentSize()
|
||||
.padding(end = 15.5.dp, top = 18.dp)
|
||||
.border(
|
||||
shape = RoundedCornerShape(11.dp),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
width = 1.dp
|
||||
)
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(top = 2.dp, bottom = 3.dp, start = 8.dp, end = 8.dp),
|
||||
text = stringResource(id = R.string.payments_current_label),
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = Relations3,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 17.dp, top = 10.dp),
|
||||
text = title,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = titleTextStyle,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(96.dp)
|
||||
.padding(start = 16.dp, end = 16.dp, top = 5.dp),
|
||||
text = subTitle,
|
||||
color = colorResource(id = R.color.text_primary),
|
||||
style = Caption1Regular,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
PriceOrOption()
|
||||
ButtonPrimary(
|
||||
text = buttonText,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
onClick = { /*TODO*/ },
|
||||
size = ButtonSize.Small
|
||||
)
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,7 +201,8 @@ fun TierPreview() {
|
|||
onClick = {},
|
||||
icon = R.drawable.logo_co_creator_64,
|
||||
colorGradient = Color(0xFFCFF6CF),
|
||||
radialGradient = Color(0xFF24BFD4)
|
||||
radialGradient = Color(0xFF24BFD4),
|
||||
isCurrent = true
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package com.anytypeio.anytype.viewmodel
|
||||
|
||||
import com.anytypeio.anytype.models.Tier
|
||||
|
||||
sealed class PaymentsMainState {
|
||||
object Loading : PaymentsMainState()
|
||||
data class Default(val tiers: List<Tier>) : PaymentsMainState()
|
||||
data class PaymentSuccess(val tiers: List<Tier>) : PaymentsMainState()
|
||||
}
|
||||
|
||||
sealed class PaymentsTierState {
|
||||
object Hidden : PaymentsTierState()
|
||||
|
||||
sealed class Visible : PaymentsTierState() {
|
||||
abstract val tier: Tier
|
||||
|
||||
data class Initial(override val tier: Tier) : Visible()
|
||||
data class Subscribed(override val tier: Tier) : Visible()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class PaymentsCodeState {
|
||||
object Hidden : PaymentsCodeState()
|
||||
|
||||
sealed class Visible : PaymentsCodeState() {
|
||||
abstract val tierId: TierId
|
||||
|
||||
data class Initial(override val tierId: TierId) : Visible()
|
||||
data class Loading(override val tierId: TierId) : Visible()
|
||||
data class Success(override val tierId: TierId) : Visible()
|
||||
data class Error(override val tierId: TierId, val message: String) : Visible()
|
||||
}
|
||||
}
|
||||
|
||||
sealed class PaymentsWelcomeState {
|
||||
object Hidden : PaymentsWelcomeState()
|
||||
data class Initial(val tier: Tier) : PaymentsWelcomeState()
|
||||
}
|
||||
|
||||
sealed class PaymentsNavigation(val route: String) {
|
||||
object Main : PaymentsNavigation("main")
|
||||
object Tier : PaymentsNavigation("tier")
|
||||
object Code : PaymentsNavigation("code")
|
||||
object Welcome : PaymentsNavigation("welcome")
|
||||
object Dismiss : PaymentsNavigation("")
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class TierId(val value: String)
|
|
@ -1,23 +0,0 @@
|
|||
package com.anytypeio.anytype.viewmodel
|
||||
|
||||
import com.anytypeio.anytype.models.Tier
|
||||
|
||||
sealed class PaymentsState {
|
||||
object Loading : PaymentsState()
|
||||
data class Default(val tiers: List<Tier>) : PaymentsState()
|
||||
data class PaymentSuccess(val tiers: List<Tier>) : PaymentsState()
|
||||
}
|
||||
|
||||
sealed class PaymentsCodeState {
|
||||
object Empty : PaymentsCodeState()
|
||||
object Loading : PaymentsCodeState()
|
||||
object Success : PaymentsCodeState()
|
||||
data class Error(val message: String) : PaymentsCodeState()
|
||||
}
|
||||
|
||||
sealed class PaymentsNavigation(val route: String) {
|
||||
object Main : PaymentsNavigation("main")
|
||||
object Tier : PaymentsNavigation("tier")
|
||||
object Code : PaymentsNavigation("code")
|
||||
object Dismiss : PaymentsNavigation("")
|
||||
}
|
|
@ -1,51 +1,93 @@
|
|||
package com.anytypeio.anytype.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.anytypeio.anytype.analytics.base.Analytics
|
||||
import com.anytypeio.anytype.models.Tier
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
|
||||
class PaymentsViewModel(
|
||||
private val analytics: Analytics,
|
||||
) : ViewModel() {
|
||||
|
||||
val viewState = MutableStateFlow<PaymentsState>(PaymentsState.Loading)
|
||||
val codeViewState = MutableStateFlow<PaymentsCodeState>(PaymentsCodeState.Empty)
|
||||
val viewState = MutableStateFlow<PaymentsMainState>(PaymentsMainState.Loading)
|
||||
val codeState = MutableStateFlow<PaymentsCodeState>(PaymentsCodeState.Hidden)
|
||||
val tierState = MutableStateFlow<PaymentsTierState>(PaymentsTierState.Hidden)
|
||||
val welcomeState = MutableStateFlow<PaymentsWelcomeState>(PaymentsWelcomeState.Hidden)
|
||||
|
||||
val command = MutableStateFlow<PaymentsNavigation?>(null)
|
||||
|
||||
val selectedTier = MutableStateFlow<Tier?>(null)
|
||||
private val _tiers = mutableListOf<Tier>()
|
||||
|
||||
init {
|
||||
Timber.d("PaymentsViewModel created")
|
||||
viewState.value = PaymentsState.Default(
|
||||
listOf(
|
||||
Tier.Explorer("Free", true),
|
||||
Tier.Builder("$9.99/mo", false),
|
||||
Tier.CoCreator("$19.99/mo", false),
|
||||
Tier.Custom("$29.99/mo", false)
|
||||
)
|
||||
)
|
||||
Timber.d("PaymentsViewModel init")
|
||||
|
||||
_tiers.addAll(gertTiers())
|
||||
viewState.value = PaymentsMainState.Default(_tiers)
|
||||
}
|
||||
|
||||
fun onTierClicked(tier: Tier) {
|
||||
selectedTier.value = tier
|
||||
fun onTierClicked(tierId: TierId) {
|
||||
Timber.d("onTierClicked: tierId:$tierId")
|
||||
tierState.value = PaymentsTierState.Visible.Initial(tier = _tiers.first { it.id == tierId })
|
||||
command.value = PaymentsNavigation.Tier
|
||||
}
|
||||
|
||||
fun onActionCode(code: String) {
|
||||
Timber.d("onActionCode: $code")
|
||||
fun onActionCode(code: String, tierId: TierId) {
|
||||
Timber.d("onActionCode: tierId:$tierId, code:$code, _tiers:${_tiers}")
|
||||
viewModelScope.launch {
|
||||
codeState.value = PaymentsCodeState.Visible.Loading(tierId = tierId)
|
||||
delay(2000)
|
||||
welcomeState.value =
|
||||
PaymentsWelcomeState.Initial(tier = _tiers.first { it.id == tierId })
|
||||
val updatedTiers = _tiers.map {
|
||||
if (it.id == tierId) {
|
||||
when (it) {
|
||||
is Tier.Builder -> it.copy(isCurrent = true)
|
||||
is Tier.CoCreator -> it.copy(isCurrent = true)
|
||||
is Tier.Custom -> it.copy(isCurrent = true)
|
||||
is Tier.Explorer -> it.copy(isCurrent = true)
|
||||
}
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
_tiers.clear()
|
||||
_tiers.addAll(updatedTiers)
|
||||
viewState.value = PaymentsMainState.PaymentSuccess(_tiers)
|
||||
command.value = PaymentsNavigation.Welcome
|
||||
}
|
||||
}
|
||||
|
||||
fun onPayButtonClicked() {
|
||||
fun onPayButtonClicked(tierId: TierId) {
|
||||
Timber.d("onPayButtonClicked: tierId:$tierId")
|
||||
codeState.value = PaymentsCodeState.Visible.Initial(tierId = tierId)
|
||||
command.value = PaymentsNavigation.Code
|
||||
}
|
||||
|
||||
fun onDismissTier() {
|
||||
Timber.d("onDismissTier")
|
||||
command.value = PaymentsNavigation.Dismiss
|
||||
}
|
||||
|
||||
fun onDismissCode() {
|
||||
Timber.d("onDismissCode")
|
||||
command.value = PaymentsNavigation.Dismiss
|
||||
}
|
||||
|
||||
fun onDismissWelcome() {
|
||||
Timber.d("onDismissWelcome")
|
||||
command.value = PaymentsNavigation.Dismiss
|
||||
}
|
||||
|
||||
private fun gertTiers(): List<Tier> {
|
||||
return listOf(
|
||||
Tier.Explorer(id = TierId("idExplorer"), isCurrent = false, validUntil = "2022-12-31"),
|
||||
Tier.Builder(id = TierId("idBuilder"), isCurrent = false, validUntil = "2022-12-31"),
|
||||
Tier.CoCreator(id = TierId("idCoCreator"), isCurrent = false, validUntil = "2022-12-31"),
|
||||
Tier.Custom(id = TierId("idCustom"), isCurrent = false, validUntil = "2022-12-31")
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue