Updated on 2026-08-14
This commit is contained in:
parent
4a89075d5a
commit
e17ff1b4c2
19 changed files with 391 additions and 177 deletions
|
|
@ -175,6 +175,7 @@
|
||||||
<string name="onboarding_twin_exit_warning">Процесс связывания карт частично завершен. Вы не можете выйти из него сейчас.</string>
|
<string name="onboarding_twin_exit_warning">Процесс связывания карт частично завершен. Вы не можете выйти из него сейчас.</string>
|
||||||
<string name="wallet_balance_blockchain_unreachable_try_later">Блокчейн недоступен. Попробуй позже.</string>
|
<string name="wallet_balance_blockchain_unreachable_try_later">Блокчейн недоступен. Попробуй позже.</string>
|
||||||
<string name="warning_button_ok">Хорошо, понял!</string>
|
<string name="warning_button_ok">Хорошо, понял!</string>
|
||||||
|
<string name="onboarding_success">Успешно!</string>
|
||||||
<string name="onboarding_getting_started">Начнем</string>
|
<string name="onboarding_getting_started">Начнем</string>
|
||||||
<string name="onboarding_button_backup_now">Выполнить резервное копирование</string>
|
<string name="onboarding_button_backup_now">Выполнить резервное копирование</string>
|
||||||
<string name="onboarding_button_skip_backup">Оставить на потом</string>
|
<string name="onboarding_button_skip_backup">Оставить на потом</string>
|
||||||
|
|
|
||||||
|
|
@ -153,6 +153,7 @@
|
||||||
|
|
||||||
<string name="warning_button_ok" translatable="false">Ok, Got it!</string>
|
<string name="warning_button_ok" translatable="false">Ok, Got it!</string>
|
||||||
|
|
||||||
|
<string name="onboarding_success" translatable="false">Success!</string>
|
||||||
<string name="onboarding_getting_started" translatable="false">Getting started</string>
|
<string name="onboarding_getting_started" translatable="false">Getting started</string>
|
||||||
|
|
||||||
<string name="onboarding_button_backup_now" translatable="false">Backup now</string>
|
<string name="onboarding_button_backup_now" translatable="false">Backup now</string>
|
||||||
|
|
@ -222,7 +223,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<string name="wallet_connect_bnb_sign_message" translatable="false">Dapp %s, requesting to\n
|
<string name="wallet_connect_bnb_sign_message" translatable="false">Dapp %s, requesting to\n
|
||||||
sign BNB transaction
|
sign BNB transaction
|
||||||
\n
|
\n
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.tangem.core.ui.components.appbar
|
package com.tangem.core.ui.components.appbar
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
|
@ -18,22 +19,6 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||||
import com.tangem.core.ui.R
|
import com.tangem.core.ui.R
|
||||||
import com.tangem.core.ui.res.TangemTheme
|
import com.tangem.core.ui.res.TangemTheme
|
||||||
|
|
||||||
@Preview(widthDp = 360, heightDp = 56, showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun PreviewAppBarWithBackButtonInLightTheme() {
|
|
||||||
TangemTheme(isDark = false) {
|
|
||||||
AppBarWithBackButton(text = "Title", onBackClick = {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(widthDp = 360, heightDp = 56, showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun PreviewAppBarWithBackButtonInDarkTheme() {
|
|
||||||
TangemTheme(isDark = true) {
|
|
||||||
AppBarWithBackButton(text = "Title", onBackClick = {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* App bar with back button and optional title
|
* App bar with back button and optional title
|
||||||
*
|
*
|
||||||
|
|
@ -47,8 +32,9 @@ fun PreviewAppBarWithBackButtonInDarkTheme() {
|
||||||
fun AppBarWithBackButton(text: String? = null, onBackClick: () -> Unit) {
|
fun AppBarWithBackButton(text: String? = null, onBackClick: () -> Unit) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(all = dimensionResource(R.dimen.spacing16))
|
.background(MaterialTheme.colors.primary)
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth()
|
||||||
|
.padding(all = dimensionResource(R.dimen.spacing16)),
|
||||||
horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.spacing16)),
|
horizontalArrangement = Arrangement.spacedBy(dimensionResource(R.dimen.spacing16)),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
|
|
@ -69,4 +55,20 @@ fun AppBarWithBackButton(text: String? = null, onBackClick: () -> Unit) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(widthDp = 360, heightDp = 56, showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun PreviewAppBarWithBackButtonInLightTheme() {
|
||||||
|
TangemTheme(isDark = false) {
|
||||||
|
AppBarWithBackButton(text = "Title", onBackClick = {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(widthDp = 360, heightDp = 56, showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun PreviewAppBarWithBackButtonInDarkTheme() {
|
||||||
|
TangemTheme(isDark = true) {
|
||||||
|
AppBarWithBackButton(text = "Title", onBackClick = {})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,4 +2,5 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="common_share">Поделиться</string>
|
<string name="common_share">Поделиться</string>
|
||||||
<string name="common_copy">Копировать</string>
|
<string name="common_copy">Копировать</string>
|
||||||
|
<string name="common_terms_and_conditions">условия участия</string>
|
||||||
</resources>
|
</resources>
|
||||||
4
core/ui/src/main/res/values-ru/strings.xml
Normal file
4
core/ui/src/main/res/values-ru/strings.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="warning_button_ok">Хорошо, понял!</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -13,7 +13,9 @@
|
||||||
<!-- endregion Elevation -->
|
<!-- endregion Elevation -->
|
||||||
|
|
||||||
<!-- region Radius -->
|
<!-- region Radius -->
|
||||||
|
<dimen name="radius2">2dp</dimen>
|
||||||
<dimen name="radius6">6dp</dimen>
|
<dimen name="radius6">6dp</dimen>
|
||||||
|
<dimen name="radius8">8dp</dimen>
|
||||||
<dimen name="radius12">12dp</dimen>
|
<dimen name="radius12">12dp</dimen>
|
||||||
<dimen name="radius16">16dp</dimen>
|
<dimen name="radius16">16dp</dimen>
|
||||||
<!-- endregion Radius -->
|
<!-- endregion Radius -->
|
||||||
|
|
@ -43,12 +45,14 @@
|
||||||
<dimen name="spacing8">8dp</dimen>
|
<dimen name="spacing8">8dp</dimen>
|
||||||
<dimen name="spacing10">10dp</dimen>
|
<dimen name="spacing10">10dp</dimen>
|
||||||
<dimen name="spacing12">12dp</dimen>
|
<dimen name="spacing12">12dp</dimen>
|
||||||
|
<dimen name="spacing14">14dp</dimen>
|
||||||
<dimen name="spacing16">16dp</dimen>
|
<dimen name="spacing16">16dp</dimen>
|
||||||
<dimen name="spacing24">24dp</dimen>
|
<dimen name="spacing24">24dp</dimen>
|
||||||
<dimen name="spacing32">32dp</dimen>
|
<dimen name="spacing32">32dp</dimen>
|
||||||
<dimen name="spacing44">44dp</dimen>
|
<dimen name="spacing44">44dp</dimen>
|
||||||
<dimen name="spacing50">50dp</dimen>
|
<dimen name="spacing50">50dp</dimen>
|
||||||
<dimen name="spacing54">54dp</dimen>
|
<dimen name="spacing54">54dp</dimen>
|
||||||
<dimen name="radius2">2dp</dimen>
|
<dimen name="spacing56">56dp</dimen>
|
||||||
|
<dimen name="spacing92">92dp</dimen>
|
||||||
<!-- endregion Spacing -->
|
<!-- endregion Spacing -->
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -2,4 +2,5 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="common_share" translatable="false">Share</string>
|
<string name="common_share" translatable="false">Share</string>
|
||||||
<string name="common_copy" translatable="false">Copy</string>
|
<string name="common_copy" translatable="false">Copy</string>
|
||||||
|
<string name="common_terms_and_conditions">terms and conditions</string>
|
||||||
</resources>
|
</resources>
|
||||||
4
core/ui/src/main/res/values/strings.xml
Normal file
4
core/ui/src/main/res/values/strings.xml
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="warning_button_ok">Ok, Got it!</string>
|
||||||
|
</resources>
|
||||||
|
|
@ -5,19 +5,22 @@ import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
|
import com.tangem.feature.referral.router.ReferralRouter
|
||||||
import com.tangem.feature.referral.ui.ReferralScreen
|
import com.tangem.feature.referral.ui.ReferralScreen
|
||||||
import com.tangem.feature.referral.viewmodels.ReferralViewModel
|
import com.tangem.feature.referral.viewmodels.ReferralViewModel
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class ReferralFragment : Fragment() {
|
class ReferralFragment : Fragment() {
|
||||||
private val viewModel by viewModels<ReferralViewModel>().apply {
|
private val viewModel by viewModels<ReferralViewModel>()
|
||||||
// TODO("[REDACTED_JIRA]") this.value.setOnBackClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
activity?.window?.let { WindowCompat.setDecorFitsSystemWindows(it, true) }
|
||||||
|
viewModel.setRouter(ReferralRouter(fragmentManager = WeakReference(parentFragmentManager)))
|
||||||
return ComposeView(inflater.context).apply {
|
return ComposeView(inflater.context).apply {
|
||||||
setContent {
|
setContent {
|
||||||
ReferralScreen(stateHolder = viewModel.uiState)
|
ReferralScreen(stateHolder = viewModel.uiState)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
package com.tangem.feature.referral.models
|
package com.tangem.feature.referral.models
|
||||||
|
|
||||||
data class ReferralStateHolder(
|
internal data class ReferralStateHolder(
|
||||||
val headerState: HeaderState,
|
val headerState: HeaderState,
|
||||||
val referralInfoState: ReferralInfoState,
|
val referralInfoState: ReferralInfoState,
|
||||||
val errorToast: ErrorToast,
|
val errorSnackbar: ErrorSnackbar? = null,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
data class HeaderState(val onBackClicked: () -> Unit)
|
data class HeaderState(val onBackClicked: () -> Unit)
|
||||||
|
|
||||||
sealed interface ReferralInfoContentState {
|
sealed interface ReferralInfoContentState {
|
||||||
val award: String
|
val award: String
|
||||||
|
val networkName: String
|
||||||
val discount: String
|
val discount: String
|
||||||
val url: String
|
val url: String
|
||||||
}
|
}
|
||||||
|
|
@ -17,15 +18,18 @@ data class ReferralStateHolder(
|
||||||
sealed interface ReferralInfoState {
|
sealed interface ReferralInfoState {
|
||||||
data class ParticipantContent(
|
data class ParticipantContent(
|
||||||
override val award: String,
|
override val award: String,
|
||||||
|
override val networkName: String,
|
||||||
val address: String,
|
val address: String,
|
||||||
override val discount: String,
|
override val discount: String,
|
||||||
val purchasedWalletCount: Int,
|
val purchasedWalletCount: Int,
|
||||||
val code: String,
|
val code: String,
|
||||||
|
val shareLink: String,
|
||||||
override val url: String,
|
override val url: String,
|
||||||
) : ReferralInfoState, ReferralInfoContentState
|
) : ReferralInfoState, ReferralInfoContentState
|
||||||
|
|
||||||
data class NonParticipantContent(
|
data class NonParticipantContent(
|
||||||
override val award: String,
|
override val award: String,
|
||||||
|
override val networkName: String,
|
||||||
override val discount: String,
|
override val discount: String,
|
||||||
override val url: String,
|
override val url: String,
|
||||||
val onParticipateClicked: () -> Unit,
|
val onParticipateClicked: () -> Unit,
|
||||||
|
|
@ -34,8 +38,8 @@ data class ReferralStateHolder(
|
||||||
object Loading : ReferralInfoState
|
object Loading : ReferralInfoState
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ErrorToast(
|
data class ErrorSnackbar(
|
||||||
val visibility: Boolean,
|
val throwable: Throwable,
|
||||||
val changeVisibility: () -> Unit
|
val onOkClicked: () -> Unit,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.tangem.feature.referral.router
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
internal class ReferralRouter(private val fragmentManager: WeakReference<FragmentManager>) {
|
||||||
|
|
||||||
|
fun back() {
|
||||||
|
fragmentManager.get()?.popBackStack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -29,7 +29,7 @@ import com.tangem.feature.referral.presentation.R
|
||||||
* @param url link to the html page
|
* @param url link to the html page
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun AgreementBottomSheetContent(url: String) {
|
internal fun AgreementBottomSheetContent(url: String) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(color = MaterialTheme.colors.secondary)
|
.background(color = MaterialTheme.colors.secondary)
|
||||||
|
|
|
||||||
|
|
@ -22,28 +22,8 @@ import com.tangem.core.ui.res.TextColorType
|
||||||
import com.tangem.core.ui.res.textColor
|
import com.tangem.core.ui.res.textColor
|
||||||
import com.tangem.feature.referral.presentation.R
|
import com.tangem.feature.referral.presentation.R
|
||||||
|
|
||||||
@Preview(widthDp = 360, showBackground = true)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Preview_AgreementText_InLightTheme() {
|
internal fun AgreementText(@StringRes firstPartResId: Int, onClicked: () -> Unit) {
|
||||||
TangemTheme(isDark = false) {
|
|
||||||
Box(modifier = Modifier.background(MaterialTheme.colors.primary)) {
|
|
||||||
AgreementText(firstPartResId = R.string.referral_tos_not_enroled_prefix, onClicked = {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(widthDp = 360, showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun Preview_AgreementText_InDarkTheme() {
|
|
||||||
TangemTheme(isDark = true) {
|
|
||||||
Box(modifier = Modifier.background(MaterialTheme.colors.primary)) {
|
|
||||||
AgreementText(firstPartResId = R.string.referral_tos_not_enroled_prefix, onClicked = {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun AgreementText(@StringRes firstPartResId: Int, onClicked: () -> Unit) {
|
|
||||||
val agreementText = annotatedAgreementString(firstPart = stringResource(firstPartResId))
|
val agreementText = annotatedAgreementString(firstPart = stringResource(firstPartResId))
|
||||||
ClickableText(
|
ClickableText(
|
||||||
text = agreementText,
|
text = agreementText,
|
||||||
|
|
@ -74,4 +54,24 @@ private fun annotatedAgreementString(firstPart: String): AnnotatedString {
|
||||||
append(" ${stringResource(id = R.string.referral_tos_suffix)}")
|
append(" ${stringResource(id = R.string.referral_tos_suffix)}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(widthDp = 360, showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun Preview_AgreementText_InLightTheme() {
|
||||||
|
TangemTheme(isDark = false) {
|
||||||
|
Box(modifier = Modifier.background(MaterialTheme.colors.primary)) {
|
||||||
|
AgreementText(firstPartResId = R.string.referral_tos_not_enroled_prefix, onClicked = {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(widthDp = 360, showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun Preview_AgreementText_InDarkTheme() {
|
||||||
|
TangemTheme(isDark = true) {
|
||||||
|
Box(modifier = Modifier.background(MaterialTheme.colors.primary)) {
|
||||||
|
AgreementText(firstPartResId = R.string.referral_tos_not_enroled_prefix, onClicked = {})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ import com.tangem.core.ui.res.TangemTheme
|
||||||
import com.tangem.feature.referral.presentation.R
|
import com.tangem.feature.referral.presentation.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun NonParticipateBottomBlock(onAgreementClicked: () -> Unit, onParticipateClicked: () -> Unit) {
|
internal fun NonParticipateBottomBlock(onAgreementClicked: () -> Unit, onParticipateClicked: () -> Unit) {
|
||||||
Column {
|
Column {
|
||||||
AgreementText(
|
AgreementText(
|
||||||
firstPartResId = R.string.referral_tos_not_enroled_prefix,
|
firstPartResId = R.string.referral_tos_not_enroled_prefix,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package com.tangem.feature.referral.ui
|
package com.tangem.feature.referral.ui
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
|
@ -14,8 +15,10 @@ import androidx.compose.runtime.Composable
|
||||||
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.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
|
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
|
||||||
import androidx.compose.ui.platform.LocalClipboardManager
|
import androidx.compose.ui.platform.LocalClipboardManager
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalHapticFeedback
|
||||||
import androidx.compose.ui.res.dimensionResource
|
import androidx.compose.ui.res.dimensionResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
|
|
@ -29,10 +32,12 @@ import com.tangem.core.ui.res.textColor
|
||||||
import com.tangem.feature.referral.presentation.R
|
import com.tangem.feature.referral.presentation.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ParticipateBottomBlock(
|
internal fun ParticipateBottomBlock(
|
||||||
purchasedWalletCount: Int,
|
purchasedWalletCount: Int,
|
||||||
code: String,
|
code: String,
|
||||||
|
shareLink: String,
|
||||||
onAgreementClicked: () -> Unit,
|
onAgreementClicked: () -> Unit,
|
||||||
|
showCopySnackbar: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
@ -51,7 +56,7 @@ fun ParticipateBottomBlock(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
PersonalCodeCard(code = code)
|
PersonalCodeCard(code = code)
|
||||||
AdditionalButtons(code = code)
|
AdditionalButtons(shareLink = shareLink, showCopySnackbar = showCopySnackbar)
|
||||||
AgreementText(firstPartResId = R.string.referral_tos_enroled_prefix, onClicked = onAgreementClicked)
|
AgreementText(firstPartResId = R.string.referral_tos_enroled_prefix, onClicked = onAgreementClicked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -89,9 +94,9 @@ private fun PersonalCodeCard(code: String) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AdditionalButtons(code: String) {
|
private fun AdditionalButtons(shareLink: String, showCopySnackbar: () -> Unit) {
|
||||||
val clipboardManager = LocalClipboardManager.current
|
val clipboardManager = LocalClipboardManager.current
|
||||||
val context = LocalContext.current
|
val hapticFeedback = LocalHapticFeedback.current
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
|
@ -101,25 +106,36 @@ private fun AdditionalButtons(code: String) {
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
text = stringResource(id = R.string.common_copy),
|
text = stringResource(id = R.string.common_copy),
|
||||||
iconResId = R.drawable.ic_copy,
|
iconResId = R.drawable.ic_copy,
|
||||||
onClicked = { clipboardManager.setText(AnnotatedString(code)) },
|
onClicked = {
|
||||||
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
|
clipboardManager.setText(AnnotatedString(shareLink))
|
||||||
|
showCopySnackbar()
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val context = LocalContext.current
|
||||||
PrimaryStartIconButton(
|
PrimaryStartIconButton(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
text = stringResource(id = R.string.common_share),
|
text = stringResource(id = R.string.common_share),
|
||||||
iconResId = R.drawable.ic_share,
|
iconResId = R.drawable.ic_share,
|
||||||
onClicked = {
|
onClicked = {
|
||||||
val sendIntent: Intent = Intent().apply {
|
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
|
||||||
action = Intent.ACTION_SEND
|
context.shareText(shareLink)
|
||||||
putExtra(Intent.EXTRA_TEXT, code)
|
|
||||||
type = "text/plain"
|
|
||||||
}
|
|
||||||
val shareIntent = Intent.createChooser(sendIntent, null)
|
|
||||||
startActivity(context, shareIntent, null)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Context.shareText(text: String) {
|
||||||
|
val sendIntent: Intent = Intent().apply {
|
||||||
|
action = Intent.ACTION_SEND
|
||||||
|
putExtra(Intent.EXTRA_TEXT, text)
|
||||||
|
type = "text/plain"
|
||||||
|
}
|
||||||
|
val shareIntent = Intent.createChooser(sendIntent, null)
|
||||||
|
startActivity(this, shareIntent, null)
|
||||||
|
}
|
||||||
|
|
||||||
@Preview(widthDp = 360, showBackground = true)
|
@Preview(widthDp = 360, showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun Preview_ParticipateBottomBlock_InLightTheme() {
|
fun Preview_ParticipateBottomBlock_InLightTheme() {
|
||||||
|
|
@ -128,7 +144,9 @@ fun Preview_ParticipateBottomBlock_InLightTheme() {
|
||||||
ParticipateBottomBlock(
|
ParticipateBottomBlock(
|
||||||
purchasedWalletCount = 3,
|
purchasedWalletCount = 3,
|
||||||
code = "x4JdK",
|
code = "x4JdK",
|
||||||
|
shareLink = "",
|
||||||
onAgreementClicked = {},
|
onAgreementClicked = {},
|
||||||
|
showCopySnackbar = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +160,9 @@ fun Preview_ParticipateBottomBlock_InDarkTheme() {
|
||||||
ParticipateBottomBlock(
|
ParticipateBottomBlock(
|
||||||
purchasedWalletCount = 3,
|
purchasedWalletCount = 3,
|
||||||
code = "x4JdK",
|
code = "x4JdK",
|
||||||
|
shareLink = "",
|
||||||
onAgreementClicked = {},
|
onAgreementClicked = {},
|
||||||
|
showCopySnackbar = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,50 @@
|
||||||
package com.tangem.feature.referral.ui
|
package com.tangem.feature.referral.ui
|
||||||
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.LocalOverscrollConfiguration
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ColumnScope
|
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
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.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
|
||||||
import androidx.compose.material.BottomSheetScaffold
|
import androidx.compose.material.BottomSheetScaffold
|
||||||
import androidx.compose.material.BottomSheetState
|
import androidx.compose.material.BottomSheetState
|
||||||
import androidx.compose.material.BottomSheetValue
|
import androidx.compose.material.BottomSheetValue
|
||||||
import androidx.compose.material.ExperimentalMaterialApi
|
import androidx.compose.material.ExperimentalMaterialApi
|
||||||
import androidx.compose.material.Icon
|
import androidx.compose.material.Icon
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Snackbar
|
||||||
|
import androidx.compose.material.SnackbarDuration
|
||||||
|
import androidx.compose.material.SnackbarHost
|
||||||
|
import androidx.compose.material.SnackbarHostState
|
||||||
|
import androidx.compose.material.SnackbarResult
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.material.rememberBottomSheetScaffoldState
|
import androidx.compose.material.rememberBottomSheetScaffoldState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.SideEffect
|
import androidx.compose.runtime.SideEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
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.draw.clip
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.draw.shadow
|
||||||
|
import androidx.compose.ui.layout.onSizeChanged
|
||||||
|
import androidx.compose.ui.platform.LocalConfiguration
|
||||||
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.res.dimensionResource
|
import androidx.compose.ui.res.dimensionResource
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -41,8 +53,10 @@ import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.withStyle
|
import androidx.compose.ui.text.withStyle
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.tangem.core.ui.components.VerticalSpacer
|
import com.tangem.core.ui.components.VerticalSpacer
|
||||||
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
|
||||||
|
import com.tangem.core.ui.res.Black
|
||||||
import com.tangem.core.ui.res.ButtonColorType
|
import com.tangem.core.ui.res.ButtonColorType
|
||||||
import com.tangem.core.ui.res.IconColorType
|
import com.tangem.core.ui.res.IconColorType
|
||||||
import com.tangem.core.ui.res.TangemColorPalette
|
import com.tangem.core.ui.res.TangemColorPalette
|
||||||
|
|
@ -52,6 +66,7 @@ import com.tangem.core.ui.res.buttonColor
|
||||||
import com.tangem.core.ui.res.iconColor
|
import com.tangem.core.ui.res.iconColor
|
||||||
import com.tangem.core.ui.res.textColor
|
import com.tangem.core.ui.res.textColor
|
||||||
import com.tangem.feature.referral.models.ReferralStateHolder
|
import com.tangem.feature.referral.models.ReferralStateHolder
|
||||||
|
import com.tangem.feature.referral.models.ReferralStateHolder.ErrorSnackbar
|
||||||
import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoContentState
|
import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoContentState
|
||||||
import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState
|
import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState
|
||||||
import com.tangem.feature.referral.presentation.R
|
import com.tangem.feature.referral.presentation.R
|
||||||
|
|
@ -65,7 +80,7 @@ import kotlinx.coroutines.launch
|
||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalMaterialApi::class)
|
@OptIn(ExperimentalMaterialApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
internal fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
|
val bottomSheetScaffoldState = rememberBottomSheetScaffoldState(
|
||||||
bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed),
|
bottomSheetState = BottomSheetState(BottomSheetValue.Collapsed),
|
||||||
|
|
@ -75,7 +90,11 @@ fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
||||||
BottomSheetScaffold(
|
BottomSheetScaffold(
|
||||||
sheetContent = {
|
sheetContent = {
|
||||||
AgreementBottomSheetContent(
|
AgreementBottomSheetContent(
|
||||||
url = (stateHolder.referralInfoState as? ReferralInfoContentState)?.url ?: "",
|
url = when (val state = stateHolder.referralInfoState) {
|
||||||
|
is ReferralInfoState.NonParticipantContent -> state.url
|
||||||
|
is ReferralInfoState.ParticipantContent -> state.url
|
||||||
|
is ReferralInfoState.Loading -> ""
|
||||||
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
scaffoldState = bottomSheetScaffoldState,
|
scaffoldState = bottomSheetScaffoldState,
|
||||||
|
|
@ -100,66 +119,92 @@ fun ReferralScreen(stateHolder: ReferralStateHolder) {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val context = LocalContext.current
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
SideEffect {
|
@Composable
|
||||||
if (stateHolder.errorToast.visibility) {
|
private fun ReferralContent(stateHolder: ReferralStateHolder, onAgreementClicked: () -> Unit) {
|
||||||
//TODO("[REDACTED_JIRA]")
|
val isCopyButtonPressed = remember { mutableStateOf(false) }
|
||||||
Toast.makeText(context, "", Toast.LENGTH_LONG).show()
|
|
||||||
stateHolder.errorToast.changeVisibility()
|
Box {
|
||||||
|
CompositionLocalProvider(LocalOverscrollConfiguration provides null) {
|
||||||
|
LazyColumn(
|
||||||
|
modifier = Modifier
|
||||||
|
.background(color = MaterialTheme.colors.primary)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
stickyHeader {
|
||||||
|
AppBarWithBackButton(
|
||||||
|
text = stringResource(R.string.details_referral_title),
|
||||||
|
onBackClick = stateHolder.headerState.onBackClicked,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
item { Header() }
|
||||||
|
item {
|
||||||
|
ReferralInfo(
|
||||||
|
stateHolder = stateHolder,
|
||||||
|
onAgreementClicked = onAgreementClicked,
|
||||||
|
showCopySnackbar = { isCopyButtonPressed.value = true },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorSnackbarHost(errorSnackbar = stateHolder.errorSnackbar)
|
||||||
|
CopySnackbarHost(isCopyButtonPressed = isCopyButtonPressed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReferralContent(stateHolder: ReferralStateHolder, onAgreementClicked: () -> Unit) {
|
private fun Header() {
|
||||||
Column(
|
Column {
|
||||||
modifier = Modifier
|
Image(
|
||||||
.background(color = MaterialTheme.colors.primary)
|
painter = painterResource(R.drawable.ill_businessman_3d),
|
||||||
.fillMaxSize()
|
contentDescription = null,
|
||||||
.verticalScroll(rememberScrollState()),
|
modifier = Modifier
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
.padding(horizontal = dimensionResource(id = R.dimen.spacing32))
|
||||||
) {
|
.fillMaxWidth()
|
||||||
Header(stateHolder = stateHolder)
|
.height(dimensionResource(R.dimen.size200)),
|
||||||
|
)
|
||||||
|
VerticalSpacer(spaceResId = R.dimen.spacing24)
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.referral_title),
|
||||||
|
modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.spacing50)),
|
||||||
|
color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY1),
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
maxLines = 2,
|
||||||
|
style = MaterialTheme.typography.h2,
|
||||||
|
)
|
||||||
VerticalSpacer(spaceResId = R.dimen.spacing16)
|
VerticalSpacer(spaceResId = R.dimen.spacing16)
|
||||||
ReferralInfo(stateHolder = stateHolder, onAgreementClicked = onAgreementClicked)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ColumnScope.Header(stateHolder: ReferralStateHolder) {
|
private fun ReferralInfo(
|
||||||
AppBar(stateHolder = stateHolder)
|
stateHolder: ReferralStateHolder,
|
||||||
Image(
|
onAgreementClicked: () -> Unit,
|
||||||
painter = painterResource(R.drawable.ill_businessman_3d),
|
showCopySnackbar: () -> Unit,
|
||||||
contentDescription = null,
|
) {
|
||||||
modifier = Modifier
|
|
||||||
.padding(horizontal = dimensionResource(id = R.dimen.spacing32))
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(dimensionResource(R.dimen.size200)),
|
|
||||||
)
|
|
||||||
VerticalSpacer(spaceResId = R.dimen.spacing24)
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.referral_title),
|
|
||||||
modifier = Modifier.padding(horizontal = dimensionResource(R.dimen.spacing50)),
|
|
||||||
color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY1),
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
maxLines = 2,
|
|
||||||
style = MaterialTheme.typography.h2,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun ReferralInfo(stateHolder: ReferralStateHolder, onAgreementClicked: () -> Unit) {
|
|
||||||
when (val state = stateHolder.referralInfoState) {
|
when (val state = stateHolder.referralInfoState) {
|
||||||
is ReferralInfoState.ParticipantContent -> {
|
is ReferralInfoState.ParticipantContent -> {
|
||||||
Conditions(state = state)
|
Conditions(state = state)
|
||||||
ParticipantBottomBlock(state = state, onAgreementClicked = onAgreementClicked)
|
ParticipateBottomBlock(
|
||||||
|
purchasedWalletCount = state.purchasedWalletCount,
|
||||||
|
code = state.code,
|
||||||
|
shareLink = state.shareLink,
|
||||||
|
onAgreementClicked = onAgreementClicked,
|
||||||
|
showCopySnackbar = showCopySnackbar,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is ReferralInfoState.NonParticipantContent -> {
|
is ReferralInfoState.NonParticipantContent -> {
|
||||||
Conditions(state = state)
|
Conditions(state = state)
|
||||||
VerticalSpacer(spaceResId = R.dimen.spacing44)
|
VerticalSpacer(spaceResId = R.dimen.spacing44)
|
||||||
NonParticipantBottomBlock(state = state, onAgreementClicked = onAgreementClicked)
|
NonParticipateBottomBlock(
|
||||||
|
onAgreementClicked = onAgreementClicked,
|
||||||
|
onParticipateClicked = state.onParticipateClicked,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is ReferralInfoState.Loading -> {
|
is ReferralInfoState.Loading -> {
|
||||||
LoadingCondition(iconResId = R.drawable.ic_tether)
|
LoadingCondition(iconResId = R.drawable.ic_tether)
|
||||||
|
|
@ -169,38 +214,34 @@ fun ReferralInfo(stateHolder: ReferralStateHolder, onAgreementClicked: () -> Uni
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun AppBar(stateHolder: ReferralStateHolder) {
|
|
||||||
AppBarWithBackButton(
|
|
||||||
text = stringResource(R.string.details_referral_title),
|
|
||||||
onBackClick = stateHolder.headerState.onBackClicked,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun Conditions(state: ReferralInfoContentState) {
|
private fun Conditions(state: ReferralInfoContentState) {
|
||||||
ConditionForYou(state = state)
|
ConditionForYou(state = state)
|
||||||
VerticalSpacer(spaceResId = R.dimen.spacing32)
|
VerticalSpacer(spaceResId = R.dimen.spacing32)
|
||||||
ConditionForYourFriend(state = state)
|
ConditionForYourFriend(discount = state.discount)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ConditionForYou(state: ReferralInfoContentState) {
|
private fun ConditionForYou(state: ReferralInfoContentState) {
|
||||||
Condition(iconResId = R.drawable.ic_tether) {
|
Condition(iconResId = R.drawable.ic_tether) {
|
||||||
when (state) {
|
when (state) {
|
||||||
is ReferralInfoState.ParticipantContent -> InfoForYou(award = state.award, address = state.address)
|
is ReferralInfoState.ParticipantContent -> InfoForYou(
|
||||||
is ReferralInfoState.NonParticipantContent -> InfoForYou(award = state.award)
|
award = state.award,
|
||||||
|
networkName = state.networkName,
|
||||||
|
address = state.address,
|
||||||
|
)
|
||||||
|
is ReferralInfoState.NonParticipantContent -> InfoForYou(
|
||||||
|
award = state.award,
|
||||||
|
networkName = state.networkName,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ConditionForYourFriend(state: ReferralInfoContentState) {
|
private fun ConditionForYourFriend(discount: String) {
|
||||||
Condition(iconResId = R.drawable.ic_discount) {
|
Condition(iconResId = R.drawable.ic_discount) {
|
||||||
when (state) {
|
InfoForYourFriend(discount = discount)
|
||||||
is ReferralInfoState.ParticipantContent -> InfoForYourFriend(discount = state.discount)
|
|
||||||
is ReferralInfoState.NonParticipantContent -> InfoForYourFriend(discount = state.discount)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -239,7 +280,7 @@ private fun Condition(@DrawableRes iconResId: Int, infoBlock: @Composable () ->
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun InfoForYou(award: String, address: String? = null) {
|
private fun InfoForYou(award: String, networkName: String, address: String? = null) {
|
||||||
ConditionInfo(title = stringResource(id = R.string.referral_point_currencies_title)) {
|
ConditionInfo(title = stringResource(id = R.string.referral_point_currencies_title)) {
|
||||||
Text(
|
Text(
|
||||||
text = buildAnnotatedString {
|
text = buildAnnotatedString {
|
||||||
|
|
@ -250,7 +291,8 @@ private fun InfoForYou(award: String, address: String? = null) {
|
||||||
append(
|
append(
|
||||||
String.format(
|
String.format(
|
||||||
stringResource(id = R.string.referral_point_currencies_description_suffix),
|
stringResource(id = R.string.referral_point_currencies_description_suffix),
|
||||||
if (!address.isNullOrBlank()) address else "",
|
networkName,
|
||||||
|
if (!address.isNullOrBlank()) " $address" else "",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -319,21 +361,105 @@ private fun ShimmerInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO() Replace component with component from ds
|
||||||
@Composable
|
@Composable
|
||||||
private fun ParticipantBottomBlock(state: ReferralInfoState.ParticipantContent, onAgreementClicked: () -> Unit) {
|
private fun ErrorSnackbarHost(errorSnackbar: ErrorSnackbar?) {
|
||||||
ParticipateBottomBlock(
|
if (errorSnackbar != null) {
|
||||||
purchasedWalletCount = state.purchasedWalletCount,
|
val snackbarHostState by remember { mutableStateOf(SnackbarHostState()) }
|
||||||
code = state.code,
|
val coroutineScope = rememberCoroutineScope()
|
||||||
onAgreementClicked = onAgreementClicked,
|
|
||||||
)
|
SnackbarHost(
|
||||||
|
hostState = snackbarHostState,
|
||||||
|
modifier = Modifier.padding(top = dimensionResource(id = R.dimen.spacing56)),
|
||||||
|
snackbar = {
|
||||||
|
Snackbar(
|
||||||
|
snackbarData = it,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
actionOnNewLine = true,
|
||||||
|
shape = RoundedCornerShape(size = dimensionResource(id = R.dimen.radius8)),
|
||||||
|
backgroundColor = Black,
|
||||||
|
contentColor = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY2),
|
||||||
|
actionColor = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY2),
|
||||||
|
elevation = dimensionResource(id = R.dimen.elevation3),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val message = if (errorSnackbar.throwable.cause != null) {
|
||||||
|
String.format(
|
||||||
|
format = stringResource(id = R.string.referral_error_failed_to_load_info_with_reason),
|
||||||
|
errorSnackbar.throwable.cause,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
stringResource(id = R.string.referral_error_failed_to_load_info)
|
||||||
|
}
|
||||||
|
val actionLabel = stringResource(id = R.string.warning_button_ok)
|
||||||
|
|
||||||
|
SideEffect {
|
||||||
|
coroutineScope.launch {
|
||||||
|
val result = snackbarHostState.showSnackbar(
|
||||||
|
message = message,
|
||||||
|
actionLabel = actionLabel,
|
||||||
|
duration = SnackbarDuration.Indefinite,
|
||||||
|
)
|
||||||
|
if (result == SnackbarResult.ActionPerformed) {
|
||||||
|
errorSnackbar.onOkClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO() Replace component with component from ds
|
||||||
@Composable
|
@Composable
|
||||||
private fun NonParticipantBottomBlock(state: ReferralInfoState.NonParticipantContent, onAgreementClicked: () -> Unit) {
|
private fun CopySnackbarHost(isCopyButtonPressed: MutableState<Boolean>) {
|
||||||
NonParticipateBottomBlock(
|
if (isCopyButtonPressed.value) {
|
||||||
onAgreementClicked = onAgreementClicked,
|
val snackbarHostState by remember { mutableStateOf(SnackbarHostState()) }
|
||||||
onParticipateClicked = state.onParticipateClicked,
|
val coroutineScope = rememberCoroutineScope()
|
||||||
)
|
|
||||||
|
var snackbarSize by remember { mutableStateOf(0) }
|
||||||
|
val width = LocalConfiguration.current.screenWidthDp.dp
|
||||||
|
val snackbarWidth = with(LocalDensity.current) { snackbarSize.toDp() }
|
||||||
|
|
||||||
|
SnackbarHost(
|
||||||
|
hostState = snackbarHostState,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = dimensionResource(id = R.dimen.spacing56), start = (width - snackbarWidth).div(2))
|
||||||
|
.fillMaxWidth(),
|
||||||
|
snackbar = {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.onSizeChanged { snackbarSize = it.width }
|
||||||
|
.background(Black, RoundedCornerShape(size = dimensionResource(id = R.dimen.radius8)))
|
||||||
|
.shadow(
|
||||||
|
dimensionResource(id = R.dimen.elevation3),
|
||||||
|
RoundedCornerShape(size = dimensionResource(id = R.dimen.radius8)),
|
||||||
|
)
|
||||||
|
.padding(
|
||||||
|
horizontal = dimensionResource(id = R.dimen.spacing16),
|
||||||
|
vertical = dimensionResource(id = R.dimen.spacing14),
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = it.message,
|
||||||
|
color = MaterialTheme.colors.textColor(type = TextColorType.PRIMARY2),
|
||||||
|
style = MaterialTheme.typography.body2,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
val message = stringResource(id = R.string.referral_promo_code_copied)
|
||||||
|
SideEffect {
|
||||||
|
coroutineScope.launch {
|
||||||
|
snackbarHostState.showSnackbar(
|
||||||
|
message = message,
|
||||||
|
duration = SnackbarDuration.Short,
|
||||||
|
)
|
||||||
|
isCopyButtonPressed.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(widthDp = 360, showBackground = true)
|
@Preview(widthDp = 360, showBackground = true)
|
||||||
|
|
@ -345,13 +471,15 @@ fun Preview_ReferralScreen_Participant_InLightTheme() {
|
||||||
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
||||||
referralInfoState = ReferralInfoState.ParticipantContent(
|
referralInfoState = ReferralInfoState.ParticipantContent(
|
||||||
award = "10 USDT",
|
award = "10 USDT",
|
||||||
|
networkName = "Tron",
|
||||||
address = "ma80...zk8q2",
|
address = "ma80...zk8q2",
|
||||||
discount = "10%",
|
discount = "10%",
|
||||||
purchasedWalletCount = 3,
|
purchasedWalletCount = 3,
|
||||||
code = "x4JdK",
|
code = "x4JdK",
|
||||||
|
shareLink = "",
|
||||||
url = "",
|
url = "",
|
||||||
),
|
),
|
||||||
errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}),
|
errorSnackbar = null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -366,13 +494,15 @@ fun Preview_ReferralScreen_Participant_InDarkTheme() {
|
||||||
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
||||||
referralInfoState = ReferralInfoState.ParticipantContent(
|
referralInfoState = ReferralInfoState.ParticipantContent(
|
||||||
award = "10 USDT",
|
award = "10 USDT",
|
||||||
|
networkName = "Tron",
|
||||||
address = "ma80...zk8q2",
|
address = "ma80...zk8q2",
|
||||||
discount = "10%",
|
discount = "10%",
|
||||||
purchasedWalletCount = 3,
|
purchasedWalletCount = 3,
|
||||||
code = "x4JdK",
|
code = "x4JdK",
|
||||||
|
shareLink = "",
|
||||||
url = "",
|
url = "",
|
||||||
),
|
),
|
||||||
errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}),
|
errorSnackbar = null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -387,11 +517,12 @@ fun Preview_ReferralScreen_NonParticipant_InLightTheme() {
|
||||||
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
||||||
referralInfoState = ReferralInfoState.NonParticipantContent(
|
referralInfoState = ReferralInfoState.NonParticipantContent(
|
||||||
award = "10 USDT",
|
award = "10 USDT",
|
||||||
|
networkName = "Tron",
|
||||||
discount = "10%",
|
discount = "10%",
|
||||||
url = "",
|
url = "",
|
||||||
onParticipateClicked = {},
|
onParticipateClicked = {},
|
||||||
),
|
),
|
||||||
errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}),
|
errorSnackbar = null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -406,11 +537,12 @@ fun Preview_ReferralScreen_NonParticipant_InDarkTheme() {
|
||||||
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
||||||
referralInfoState = ReferralInfoState.NonParticipantContent(
|
referralInfoState = ReferralInfoState.NonParticipantContent(
|
||||||
award = "10 USDT",
|
award = "10 USDT",
|
||||||
|
networkName = "Tron",
|
||||||
discount = "10%",
|
discount = "10%",
|
||||||
url = "",
|
url = "",
|
||||||
onParticipateClicked = {},
|
onParticipateClicked = {},
|
||||||
),
|
),
|
||||||
errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}),
|
errorSnackbar = null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -424,7 +556,7 @@ fun Preview_ReferralScreen_Loading_InLightTheme() {
|
||||||
stateHolder = ReferralStateHolder(
|
stateHolder = ReferralStateHolder(
|
||||||
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
||||||
referralInfoState = ReferralInfoState.Loading,
|
referralInfoState = ReferralInfoState.Loading,
|
||||||
errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}),
|
errorSnackbar = null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -438,7 +570,7 @@ fun Preview_ReferralScreen_Loading_InDarkTheme() {
|
||||||
stateHolder = ReferralStateHolder(
|
stateHolder = ReferralStateHolder(
|
||||||
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
headerState = ReferralStateHolder.HeaderState(onBackClicked = {}),
|
||||||
referralInfoState = ReferralInfoState.Loading,
|
referralInfoState = ReferralInfoState.Loading,
|
||||||
errorToast = ReferralStateHolder.ErrorToast(visibility = false, changeVisibility = {}),
|
errorSnackbar = null,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,16 +8,20 @@ import androidx.lifecycle.viewModelScope
|
||||||
import com.tangem.feature.referral.domain.ReferralInteractor
|
import com.tangem.feature.referral.domain.ReferralInteractor
|
||||||
import com.tangem.feature.referral.domain.models.DiscountType
|
import com.tangem.feature.referral.domain.models.DiscountType
|
||||||
import com.tangem.feature.referral.domain.models.ReferralData
|
import com.tangem.feature.referral.domain.models.ReferralData
|
||||||
|
import com.tangem.feature.referral.domain.models.ReferralInfo
|
||||||
import com.tangem.feature.referral.models.ReferralStateHolder
|
import com.tangem.feature.referral.models.ReferralStateHolder
|
||||||
|
import com.tangem.feature.referral.models.ReferralStateHolder.ErrorSnackbar
|
||||||
import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState
|
import com.tangem.feature.referral.models.ReferralStateHolder.ReferralInfoState
|
||||||
|
import com.tangem.feature.referral.router.ReferralRouter
|
||||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||||
import com.tangem.utils.coroutines.runCatching
|
import com.tangem.utils.coroutines.runCatching
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class ReferralViewModel @Inject constructor(
|
internal class ReferralViewModel @Inject constructor(
|
||||||
private val referralInteractor: ReferralInteractor,
|
private val referralInteractor: ReferralInteractor,
|
||||||
private val dispatchers: CoroutineDispatcherProvider,
|
private val dispatchers: CoroutineDispatcherProvider,
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
@ -25,57 +29,80 @@ class ReferralViewModel @Inject constructor(
|
||||||
var uiState: ReferralStateHolder by mutableStateOf(createInitiallyUiState())
|
var uiState: ReferralStateHolder by mutableStateOf(createInitiallyUiState())
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
private var referralRouter: ReferralRouter by Delegates.notNull()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
loadReferralData()
|
loadReferralData()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setOnBackClicked(onBackClicked: () -> Unit) {
|
fun setRouter(router: ReferralRouter) {
|
||||||
uiState = uiState.copy(headerState = ReferralStateHolder.HeaderState(onBackClicked = onBackClicked))
|
referralRouter = router
|
||||||
|
uiState = uiState.copy(headerState = ReferralStateHolder.HeaderState(onBackClicked = router::back))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createInitiallyUiState() = ReferralStateHolder(
|
private fun createInitiallyUiState() = ReferralStateHolder(
|
||||||
headerState = ReferralStateHolder.HeaderState(onBackClicked = { }),
|
headerState = ReferralStateHolder.HeaderState(onBackClicked = { }),
|
||||||
referralInfoState = ReferralInfoState.Loading,
|
referralInfoState = ReferralInfoState.Loading,
|
||||||
errorToast = ReferralStateHolder.ErrorToast(
|
errorSnackbar = null,
|
||||||
visibility = false,
|
|
||||||
changeVisibility = {
|
|
||||||
uiState = uiState.copy(
|
|
||||||
referralInfoState = uiState.referralInfoState,
|
|
||||||
errorToast = uiState.errorToast.copy(visibility = false),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun loadReferralData() {
|
private fun loadReferralData() {
|
||||||
val lastUiState = uiState
|
|
||||||
uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading)
|
uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading)
|
||||||
viewModelScope.launch(dispatchers.main) {
|
viewModelScope.launch(dispatchers.main) {
|
||||||
runCatching(dispatchers.io) { referralInteractor.getReferralStatus() }
|
runCatching(dispatchers.io) { referralInteractor.getReferralStatus() }
|
||||||
.onSuccess { uiState = uiState.copy(referralInfoState = it.convertToReferralInfoState()) }
|
.onSuccess(::showContent)
|
||||||
.onFailure { uiState = lastUiState.copy(errorToast = lastUiState.errorToast.copy(visibility = true)) }
|
.onFailure(::showErrorSnackbar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun participate() {
|
||||||
|
uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading)
|
||||||
|
viewModelScope.launch(dispatchers.main) {
|
||||||
|
runCatching(dispatchers.io) { referralInteractor.startReferral() }
|
||||||
|
.onSuccess(::showContent)
|
||||||
|
.onFailure(::showErrorSnackbar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showContent(referralData: ReferralData) {
|
||||||
|
uiState = uiState.copy(referralInfoState = referralData.convertToReferralInfoState())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showErrorSnackbar(throwable: Throwable) {
|
||||||
|
uiState = uiState.copy(
|
||||||
|
errorSnackbar = ErrorSnackbar(throwable = throwable, onOkClicked = referralRouter::back),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun ReferralData.convertToReferralInfoState(): ReferralInfoState = when (this) {
|
private fun ReferralData.convertToReferralInfoState(): ReferralInfoState = when (this) {
|
||||||
is ReferralData.ParticipantData -> ReferralInfoState.ParticipantContent(
|
is ReferralData.ParticipantData -> ReferralInfoState.ParticipantContent(
|
||||||
award = getAwardValue(),
|
award = getAwardValue(),
|
||||||
address = referral.address,
|
networkName = getNetworkName(),
|
||||||
|
address = referral.getAddressValue(),
|
||||||
discount = getDiscountValue(),
|
discount = getDiscountValue(),
|
||||||
purchasedWalletCount = referral.walletsPurchased,
|
purchasedWalletCount = referral.walletsPurchased,
|
||||||
code = referral.promocode,
|
code = referral.promocode,
|
||||||
|
shareLink = referral.shareLink,
|
||||||
url = tosLink,
|
url = tosLink,
|
||||||
)
|
)
|
||||||
is ReferralData.NonParticipantData -> ReferralInfoState.NonParticipantContent(
|
is ReferralData.NonParticipantData -> ReferralInfoState.NonParticipantContent(
|
||||||
award = getAwardValue(),
|
award = getAwardValue(),
|
||||||
|
networkName = getNetworkName(),
|
||||||
discount = getDiscountValue(),
|
discount = getDiscountValue(),
|
||||||
url = tosLink,
|
url = tosLink,
|
||||||
onParticipateClicked = ::onParticipateClicked,
|
onParticipateClicked = ::participate,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ReferralData.getAwardValue(): String =
|
private fun ReferralData.getAwardValue(): String = "$award ${getToken().symbol}"
|
||||||
"$award ${requireNotNull(tokens.firstOrNull()?.symbol) { "Token list is empty" }}"
|
|
||||||
|
private fun ReferralData.getNetworkName(): String = getToken().networkId.replaceFirstChar(Char::uppercase)
|
||||||
|
|
||||||
|
private fun ReferralInfo.getAddressValue(): String {
|
||||||
|
check(address.length > 5) { "Invalid address" }
|
||||||
|
return address.substring(startIndex = 0, endIndex = 4) + "..." +
|
||||||
|
address.substring(startIndex = address.length - 5, endIndex = address.length)
|
||||||
|
}
|
||||||
|
|
||||||
private fun ReferralData.getDiscountValue(): String {
|
private fun ReferralData.getDiscountValue(): String {
|
||||||
val discountSymbol = when (discountType) {
|
val discountSymbol = when (discountType) {
|
||||||
|
|
@ -85,13 +112,5 @@ class ReferralViewModel @Inject constructor(
|
||||||
return "$discount $discountSymbol"
|
return "$discount $discountSymbol"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onParticipateClicked() {
|
private fun ReferralData.getToken() = requireNotNull(tokens.firstOrNull()) { "Token list is empty" }
|
||||||
val lastUiState = uiState
|
|
||||||
uiState = uiState.copy(referralInfoState = ReferralInfoState.Loading)
|
|
||||||
viewModelScope.launch(dispatchers.main) {
|
|
||||||
runCatching(dispatchers.io) { referralInteractor.startReferral() }
|
|
||||||
.onSuccess { uiState = uiState.copy(referralInfoState = it.convertToReferralInfoState()) }
|
|
||||||
.onFailure { uiState = lastUiState.copy(errorToast = lastUiState.errorToast.copy(visibility = true)) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<string name="referral_title">Приведи друга в Tangem</string>
|
<string name="referral_title">Приведи друга в Tangem</string>
|
||||||
<string name="referral_point_currencies_title">Вы</string>
|
<string name="referral_point_currencies_title">Вы</string>
|
||||||
<string name="referral_point_currencies_description_prefix">Получите</string>
|
<string name="referral_point_currencies_description_prefix">Получите</string>
|
||||||
<string name="referral_point_currencies_description_suffix">за каждый кошелек, который купит ваш друг на ваш адрес в сети Tron %s</string>
|
<string name="referral_point_currencies_description_suffix">на ваш адрес в сети %s%s за каждый кошелек, который купит ваш друг</string>
|
||||||
<string name="referral_point_discount_title">Ваш друг</string>
|
<string name="referral_point_discount_title">Ваш друг</string>
|
||||||
<string name="referral_point_discount_description_prefix">Получит</string>
|
<string name="referral_point_discount_description_prefix">Получит</string>
|
||||||
<string name="referral_point_discount_description_value">%s скидку</string>
|
<string name="referral_point_discount_description_value">%s скидку</string>
|
||||||
|
|
@ -17,4 +17,8 @@
|
||||||
<string name="referral_promo_code_title">Ваш персональный код</string>
|
<string name="referral_promo_code_title">Ваш персональный код</string>
|
||||||
<string name="referral_wallets_purchased_count">%d кошельков</string>
|
<string name="referral_wallets_purchased_count">%d кошельков</string>
|
||||||
<string name="referral_friends_bought_title">Ваши друзья купили</string>
|
<string name="referral_friends_bought_title">Ваши друзья купили</string>
|
||||||
|
<string name="referral_error_failed_to_load_info">Не удалось загрузить информацию по реферальной программе. Пожалуйста, попробуйте позже.</string>
|
||||||
|
<string name="referral_error_failed_to_load_info_with_reason">Не удалось загрузить информацию по реферальной программе. Причина: %s. Пожалуйста, попробуйте позже.</string>
|
||||||
|
<string name="referral_error_failed_to_participate">Не удалось обработать вашу заявку на участие. Причина: %s. Пожалуйста, попробуйте позже. Если проблема сохранится, вы можете обратиться в техподдержку.</string>
|
||||||
|
<string name="referral_promo_code_copied">Персональный код скопирован!</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<string name="referral_title">Refer your friends to Tangem</string>
|
<string name="referral_title">Refer your friends to Tangem</string>
|
||||||
<string name="referral_point_currencies_title">You</string>
|
<string name="referral_point_currencies_title">You</string>
|
||||||
<string name="referral_point_currencies_description_prefix">Will get</string>
|
<string name="referral_point_currencies_description_prefix">Will get</string>
|
||||||
<string name="referral_point_currencies_description_suffix">for each wallet bought by your friend on your Tron network address %s</string>
|
<string name="referral_point_currencies_description_suffix">for each wallet bought by your friend on your %s network address%s</string>
|
||||||
<string name="referral_point_discount_title">Your friend</string>
|
<string name="referral_point_discount_title">Your friend</string>
|
||||||
<string name="referral_point_discount_description_prefix">Will get a</string>
|
<string name="referral_point_discount_description_prefix">Will get a</string>
|
||||||
<string name="referral_point_discount_description_value">%s discount</string>
|
<string name="referral_point_discount_description_value">%s discount</string>
|
||||||
|
|
@ -17,4 +17,8 @@
|
||||||
<string name="referral_promo_code_title">Your personal code</string>
|
<string name="referral_promo_code_title">Your personal code</string>
|
||||||
<string name="referral_wallets_purchased_count">%d wallets</string>
|
<string name="referral_wallets_purchased_count">%d wallets</string>
|
||||||
<string name="referral_friends_bought_title">Your friends bought</string>
|
<string name="referral_friends_bought_title">Your friends bought</string>
|
||||||
|
<string name="referral_error_failed_to_load_info">Failed to load the information about the referral program. Please try again later.</string>
|
||||||
|
<string name="referral_error_failed_to_load_info_with_reason">Failed to load the information about the referral program. Reason: %s. Please try again later.</string>
|
||||||
|
<string name="referral_error_failed_to_participate">Your participation request could not be processed. Reason: %s. Please try again later. If the problem persists — feel free to contact our support.</string>
|
||||||
|
<string name="referral_promo_code_copied">Personal code copied!</string>
|
||||||
</resources>
|
</resources>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue