Skip to content

Commit

Permalink
Separated crypto and card payment flows
Browse files Browse the repository at this point in the history
  • Loading branch information
IrynaTsymbaliuk committed Apr 11, 2022
1 parent 8938d88 commit f45d859
Show file tree
Hide file tree
Showing 22 changed files with 622 additions and 105 deletions.
4 changes: 4 additions & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
android:name="updated.mysterium.vpn.ui.top.up.coingate.amount.TopUpAmountActivity"
android:screenOrientation="portrait" />

<activity
android:name="updated.mysterium.vpn.ui.top.up.card.price.TopUpPriceActivity"
android:screenOrientation="portrait" />

<activity
android:name="updated.mysterium.vpn.ui.top.up.coingate.crypto.TopUpCryptoActivity"
android:screenOrientation="portrait" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package updated.mysterium.vpn.model.payment

enum class Gateway(val gateway: String) {
COINGATE("coingate"),
CARDINITY("cardinity"),
PAYPAL("paypal");
PAYPAL("paypal"),
PLAY_BILLING("play_billing");

companion object {
fun from(gateway: String?): Gateway? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ data class GatewayCardItem(
R.color.payment_method_crypto_text_color,
R.color.payment_method_crypto_icon_color
)
Gateway.CARDINITY -> GatewayCardItem(
Gateway.PLAY_BILLING -> GatewayCardItem(
R.string.credit_card,
R.drawable.icon_top_up_now,
R.color.payment_method_card_background,
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package updated.mysterium.vpn.model.top.up

data class TopUpCardItem(
data class TopUpAmountCardItem(
val value: String,
var isSelected: Boolean = false
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package updated.mysterium.vpn.model.top.up

import android.os.Parcelable
import kotlinx.android.parcel.Parcelize

@Parcelize
data class TopUpPriceCardItem(
val sku: String,
val title: String,
val price: Double,
val mystAmount: Double,
var isSelected: Boolean = false
): Parcelable {

fun changeState() {
isSelected = !isSelected
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ class BalanceUseCase(
) {

private companion object {
const val CURRENCY = "USD"
const val USD = "USD"
const val CHF = "CHF"
}

fun initDeferredNode(deferredNode: DeferredNode) {
Expand All @@ -27,7 +28,9 @@ class BalanceUseCase(
callback: (Double) -> Unit
) = nodeRepository.registerBalanceChangeCallback(callback)

suspend fun getUsdEquivalent() = nodeRepository.getExchangeRate(CURRENCY)
suspend fun getUsdEquivalent() = nodeRepository.getExchangeRate(USD)

suspend fun getChfEquivalent() = nodeRepository.getExchangeRate(CHF)

suspend fun getWalletEquivalent(balance: Double) = nodeRepository.getWalletEquivalent(balance)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ import org.koin.android.ext.android.inject
import updated.mysterium.vpn.common.extensions.TAG
import updated.mysterium.vpn.common.localisation.LocaleHelper
import updated.mysterium.vpn.model.manual.connect.ConnectionState
import updated.mysterium.vpn.model.payment.Gateway
import updated.mysterium.vpn.model.pushy.PushyTopic
import updated.mysterium.vpn.notification.Notifications
import updated.mysterium.vpn.ui.connection.ConnectionActivity
import updated.mysterium.vpn.ui.custom.view.ConnectionToolbar
import updated.mysterium.vpn.ui.home.selection.HomeSelectionActivity
import updated.mysterium.vpn.ui.payment.method.PaymentMethodActivity
import updated.mysterium.vpn.ui.top.up.card.price.TopUpPriceActivity
import updated.mysterium.vpn.ui.top.up.coingate.amount.TopUpAmountActivity

abstract class BaseActivity : AppCompatActivity() {
Expand Down Expand Up @@ -266,13 +268,10 @@ abstract class BaseActivity : AppCompatActivity() {
baseViewModel.getGateways().observe(this) {
it.onSuccess { result ->
val gateways = result.filterNotNull()
val intent = if (gateways.size == 1) {
Intent(this, TopUpAmountActivity::class.java).apply {
putExtra(
TopUpAmountActivity.PAYMENT_METHOD_EXTRA_KEY,
gateways[0].gateway
)
}
val intent = if (gateways.size == 1 && gateways[0] == Gateway.PLAY_BILLING) {
Intent(this, TopUpPriceActivity::class.java)
} else if (gateways.size == 1 && gateways[0] == Gateway.COINGATE) {
Intent(this, TopUpAmountActivity::class.java)
} else {
val gatewayValues = gateways.map { it.gateway }
PaymentMethodActivity.newIntent(this, gatewayValues)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class BaseViewModel(useCaseProvider: UseCaseProvider) : ViewModel() {
.map { Gateway.from(it.name) }
.toMutableList()
.apply {
add(Gateway.CARDINITY) // for testing purpose only
add(Gateway.PLAY_BILLING) // for testing purpose only
remove(Gateway.PAYPAL)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.os.Bundle
import network.mysterium.vpn.databinding.ActivityPaymentMethodBinding
import updated.mysterium.vpn.model.payment.Gateway
import updated.mysterium.vpn.ui.base.BaseActivity
import updated.mysterium.vpn.ui.top.up.card.price.TopUpPriceActivity
import updated.mysterium.vpn.ui.top.up.coingate.amount.TopUpAmountActivity

class PaymentMethodActivity : BaseActivity() {
Expand Down Expand Up @@ -54,8 +55,10 @@ class PaymentMethodActivity : BaseActivity() {
}

private fun navigateToTopUp(gateway: Gateway) {
val intent = Intent(this, TopUpAmountActivity::class.java).apply {
putExtra(TopUpAmountActivity.PAYMENT_METHOD_EXTRA_KEY, gateway.gateway)
val intent = if (gateway == Gateway.PLAY_BILLING) {
Intent(this, TopUpPriceActivity::class.java)
} else {
Intent(this, TopUpAmountActivity::class.java)
}
startActivity(intent)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package updated.mysterium.vpn.ui.top.up
import androidx.lifecycle.ViewModel
import updated.mysterium.vpn.common.extensions.liveDataResult
import updated.mysterium.vpn.model.payment.Gateway
import updated.mysterium.vpn.model.top.up.TopUpCardItem
import updated.mysterium.vpn.model.top.up.TopUpAmountCardItem
import updated.mysterium.vpn.network.provider.usecase.UseCaseProvider

class TopUpViewModel(useCaseProvider: UseCaseProvider) : ViewModel() {
Expand All @@ -14,15 +14,16 @@ class TopUpViewModel(useCaseProvider: UseCaseProvider) : ViewModel() {
fun accountFlowShown() {
loginUseCase.accountFlowShown()
}
fun getUsdPrices(gateway: Gateway) = liveDataResult {

fun getAmounts() = liveDataResult {
paymentUseCase.getGateways()
.find {
it.name == gateway.gateway
it.name == Gateway.COINGATE.gateway
}
?.orderOptions
?.amountsSuggestion
?.mapIndexed { index, value ->
TopUpCardItem(value.toString(), index == 0)
TopUpAmountCardItem(value.toString(), index == 0)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package updated.mysterium.vpn.ui.top.up.card.price

import android.content.Intent
import android.os.Bundle
import android.util.Log
import network.mysterium.vpn.R
import network.mysterium.vpn.databinding.ActivityTopUpPriceBinding
import org.koin.android.ext.android.inject
import updated.mysterium.vpn.common.data.WalletEstimatesUtil
import updated.mysterium.vpn.common.extensions.TAG
import updated.mysterium.vpn.model.top.up.TopUpPriceCardItem
import updated.mysterium.vpn.ui.base.BaseActivity
import updated.mysterium.vpn.ui.top.up.TopUpViewModel
import updated.mysterium.vpn.ui.top.up.card.summary.CardSummaryActivity
import updated.mysterium.vpn.ui.top.up.coingate.amount.TopUpAmountViewModel
import updated.mysterium.vpn.ui.top.up.coingate.payment.TopUpPaymentViewModel
import updated.mysterium.vpn.ui.wallet.ExchangeRateViewModel
import java.util.*

class TopUpPriceActivity : BaseActivity() {

private lateinit var binding: ActivityTopUpPriceBinding
private val viewModel: TopUpViewModel by inject()
private val walletViewModel: TopUpAmountViewModel by inject()
private val exchangeRateViewModel: ExchangeRateViewModel by inject()
private val paymentViewModel: TopUpPaymentViewModel by inject()
private val topUpAdapter = TopUpPriceAdapter()
private var selectedItem: TopUpPriceCardItem? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityTopUpPriceBinding.inflate(layoutInflater)
setContentView(binding.root)
configure()
bindsAction()
getSkuList()
}

private fun configure() {
binding.priceRecycler.adapter = topUpAdapter
topUpAdapter.onItemSelected = {
onItemSelected(it)
}
}

private fun bindsAction() {
binding.backButton.setOnClickListener {
finish()
}
binding.confirmButton.setOnClickListener {
navigateToCardPaymentFlow()
}
binding.freeTrialButtonButton.setOnClickListener {
viewModel.accountFlowShown()
navigateToConnectionOrHome(isBackTransition = false)
}
}

private fun getSkuList() {
paymentViewModel.getSkuDetailList().observe(this) {
it.onSuccess { skuDetailList ->
skuDetailList?.let {
topUpAdapter.addAll(it)
}
}
it.onFailure { throwable ->
Log.e(TAG, throwable.localizedMessage ?: throwable.toString())
}
}
topUpAdapter.getSelectedItem()?.let {
onItemSelected(it)
}
}

private fun updateEquivalent(mystAmount: Double) {
binding.mystEquivalentTextView.text = getString(
R.string.top_up_usd_equivalent, mystAmount
)
}

private fun updateWalletEstimates(mystAmount: Double) {
walletViewModel.getWalletEquivalent(mystAmount).observe(this) { result ->
result.onSuccess { estimates ->
binding.videoTopUpItem.setData(WalletEstimatesUtil.convertVideoData(estimates))
binding.videoTopUpItem.setType(
WalletEstimatesUtil.convertVideoType(estimates).toUpperCase(Locale.ROOT)
)
binding.pagesTopUpItem.setData(WalletEstimatesUtil.convertWebData(estimates))
binding.pagesTopUpItem.setType(
WalletEstimatesUtil.convertWebType(estimates).toUpperCase(Locale.ROOT)
)
binding.trafficTopUpItem.setData(
WalletEstimatesUtil.convertDownloadData(estimates).toString()
)
binding.trafficTopUpItem.setType(
WalletEstimatesUtil.convertDownloadType(
estimates
)
)
binding.musicTopUpItem.setData(
WalletEstimatesUtil.convertMusicTimeData(
estimates
)
)
binding.musicTopUpItem.setType(
WalletEstimatesUtil.convertMusicTimeType(estimates).toUpperCase(Locale.ROOT)
)
}
}
}

private fun onItemSelected(selectedItem: TopUpPriceCardItem) {
this.selectedItem = selectedItem
val mystAmount = exchangeRateViewModel.getMystEquivalent(selectedItem.price)
updateEquivalent(mystAmount)
updateWalletEstimates(mystAmount)
}

private fun navigateToCardPaymentFlow() {
val intent = Intent(this, CardSummaryActivity::class.java).apply {
putExtra(CardSummaryActivity.SKU_EXTRA_KEY, selectedItem)
}
startActivity(intent)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package updated.mysterium.vpn.ui.top.up.card.price

import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import network.mysterium.vpn.R
import network.mysterium.vpn.databinding.ItemCardElementBinding
import updated.mysterium.vpn.common.adapters.ContentListAdapter
import updated.mysterium.vpn.common.extensions.dpToPx
import updated.mysterium.vpn.model.top.up.TopUpPriceCardItem

class TopUpPriceAdapter :
ContentListAdapter<TopUpPriceCardItem, TopUpPriceAdapter.TopUpPriceViewHolder>() {

private companion object {
const val MARGIN_DP = 24f
}

private var selectedCardItem: TopUpPriceCardItem? = null
var onItemSelected: ((TopUpPriceCardItem) -> Unit)? = null

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = TopUpPriceViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.item_card_element, parent, false)
)

override fun onBindViewHolder(holder: TopUpPriceViewHolder, position: Int) {
if (position == items.lastIndex) {
val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
params.rightMargin = holder.itemView.context.dpToPx(MARGIN_DP)
holder.itemView.layoutParams = params
} else if (position == 0) {
val params = holder.itemView.layoutParams as RecyclerView.LayoutParams
params.leftMargin = holder.itemView.context.dpToPx(MARGIN_DP)
holder.itemView.layoutParams = params
}
holder.bind(items[position])
}

fun getSelectedItem() = selectedCardItem

inner class TopUpPriceViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

val binding = ItemCardElementBinding.bind(itemView)

fun bind(cardItem: TopUpPriceCardItem) {
binding.cardItemValue.text = cardItem.title
if (cardItem.isSelected) {
selectedCardItem = cardItem
selectedState()
} else {
unselectedState()
}
binding.cardItemFrame.setOnClickListener {
if (cardItem != selectedCardItem) {
onItemSelected?.invoke(cardItem)
selectedCardItem?.changeState()
cardItem.changeState()
selectedCardItem = cardItem
notifyDataSetChanged()
}
}
}

private fun selectedState() {
binding.cardItemValue.setTextColor(Color.WHITE)
binding.cardItemFrame.background = ContextCompat.getDrawable(
itemView.context, R.drawable.shape_card_element_selected
)
binding.shadow.visibility = View.VISIBLE
}

private fun unselectedState() {
binding.cardItemValue.setTextColor(
itemView.context.getColor(R.color.onboarding_title_dark_blue)
)
binding.cardItemFrame.background = ContextCompat.getDrawable(
itemView.context, R.drawable.shape_card_element_unselected
)
binding.shadow.visibility = View.INVISIBLE
}
}
}
Loading

0 comments on commit f45d859

Please sign in to comment.