Updated on 2026-08-14
|
|
@ -1,22 +1,22 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
compileSdkVersion 31
|
||||
defaultConfig {
|
||||
applicationId "com.tangem.wallet"
|
||||
versionCode project.hasProperty('versionCode') ? project.property('versionCode') as int : 1
|
||||
versionName project.hasProperty('versionName') ? project.property('versionName') : "1.0.0.-SNAPSHOT"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion 31
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
androidExtensions {
|
||||
experimental = true
|
||||
buildFeatures {
|
||||
compose true
|
||||
viewBinding true
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
|
@ -47,12 +47,14 @@ android {
|
|||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8.toString()
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
coreLibraryDesugaringEnabled false
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion '1.1.0'
|
||||
}
|
||||
packagingOptions {
|
||||
exclude 'lib/x86_64/darwin/libscrypt.dylib'
|
||||
exclude 'lib/x86_64/freebsd/libscrypt.so'
|
||||
|
|
@ -67,13 +69,13 @@ repositories {
|
|||
dependencies {
|
||||
implementation fileTree(include: ['*.aar'], dir: 'libs')
|
||||
|
||||
implementation 'androidx.core:core-ktx:1.6.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.3.6'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation "androidx.core:core-ktx:1.6.0"
|
||||
implementation 'com.google.android.play:core:1.10.2'
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.4.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation "androidx.core:core-ktx:1.7.0"
|
||||
implementation 'com.google.android.play:core:1.10.3'
|
||||
implementation 'com.google.android.play:core-ktx:1.8.1'
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
|
|
@ -138,6 +140,15 @@ dependencies {
|
|||
// Google Pay
|
||||
implementation 'com.google.android.gms:play-services-wallet:19.1.0'
|
||||
|
||||
//Compose
|
||||
implementation 'androidx.activity:activity-compose:1.4.0'
|
||||
implementation 'androidx.compose.material:material:1.1.0'
|
||||
implementation 'androidx.compose.animation:animation:1.1.0'
|
||||
implementation 'androidx.compose.ui:ui-tooling:1.1.0'
|
||||
implementation "com.google.accompanist:accompanist-appcompat-theme:0.23.0"
|
||||
|
||||
implementation 'com.github.kirich1409:viewbindingpropertydelegate-noreflection:1.5.6'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation "com.google.truth:truth:1.1.3"
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
android:value="true" />
|
||||
|
||||
<activity
|
||||
android:exported="true"
|
||||
android:name="com.tangem.tap.MainActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="portrait"
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import android.os.Bundle
|
|||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.tangem.TangemSdk
|
||||
import com.tangem.operations.backup.BackupService
|
||||
|
|
@ -25,7 +26,7 @@ import com.tangem.tap.domain.TangemSdkManager
|
|||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.features.shop.redux.ShopAction
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import com.tangem.wallet.databinding.ActivityMainBinding
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
|
@ -63,6 +64,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
private var snackbar: Snackbar? = null
|
||||
private val dialogManager = DialogManager()
|
||||
private val intentHandler = IntentHandler()
|
||||
private val binding: ActivityMainBinding by viewBinding(ActivityMainBinding::bind)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -102,7 +104,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
notificationsHandler = NotificationsHandler(fragment_container)
|
||||
notificationsHandler = NotificationsHandler(binding.fragmentContainer)
|
||||
|
||||
val backStackIsEmpty = supportFragmentManager.backStackEntryCount == 0
|
||||
val isScannedBefore = store.state.globalState.scanResponse != null
|
||||
|
|
@ -139,7 +141,7 @@ class MainActivity : AppCompatActivity(), SnackbarHandler {
|
|||
if (snackbar != null) return
|
||||
|
||||
snackbar = Snackbar.make(
|
||||
fragment_container, getString(text), Snackbar.LENGTH_INDEFINITE
|
||||
binding.fragmentContainer, getString(text), Snackbar.LENGTH_INDEFINITE
|
||||
)
|
||||
if (buttonTitle != null && action != null) {
|
||||
snackbar?.setAction(getString(buttonTitle), action)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ fun Context.getColorCompat(@ColorRes colorRes: Int): Int {
|
|||
return ContextCompat.getColor(this, colorRes)
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun View.getColor(@ColorRes colorRes: Int): Int {
|
||||
return ContextCompat.getColor(context, colorRes)
|
||||
}
|
||||
|
||||
fun View.getString(@StringRes id: Int): String {
|
||||
return context.getString(id)
|
||||
}
|
||||
|
|
@ -169,4 +174,8 @@ fun Context.safeStartActivity(
|
|||
} finally {
|
||||
finally?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
fun View.getString(resId: Int, vararg formatArgs: Any?): String {
|
||||
return context.getString(resId, formatArgs)
|
||||
}
|
||||
|
|
@ -5,15 +5,18 @@ import android.view.View
|
|||
import android.widget.FrameLayout
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidget
|
||||
import com.tangem.tangem_sdk_new.ui.widget.leapfrogWidget.LeapfrogWidgetState
|
||||
import com.tangem.tap.domain.twins.TwinsCardWidget
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.test_leapfrog_fragment.*
|
||||
import com.tangem.wallet.databinding.TestLeapfrogFragmentBinding
|
||||
|
||||
class TestLeapfrogFragment : Fragment(R.layout.test_leapfrog_fragment) {
|
||||
|
||||
private lateinit var twinsCardWidget: TwinsCardWidget
|
||||
private val binding: TestLeapfrogFragmentBinding by viewBinding(TestLeapfrogFragmentBinding::bind)
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -28,30 +31,29 @@ class TestLeapfrogFragment : Fragment(R.layout.test_leapfrog_fragment) {
|
|||
val leapfrog = LeapfrogWidget(leapfrogContainer)
|
||||
twinsCardWidget = TwinsCardWidget(leapfrog) { 200f }
|
||||
|
||||
btn_twin_welcome.setOnClickListener {
|
||||
binding.btnTwinWelcome.setOnClickListener {
|
||||
twinsCardWidget.toWelcome()
|
||||
}
|
||||
btn_twin_to_leapfrog.setOnClickListener {
|
||||
binding.btnTwinToLeapfrog.setOnClickListener {
|
||||
twinsCardWidget.toLeapfrog()
|
||||
}
|
||||
btn_twin_activate.setOnClickListener {
|
||||
binding.btnTwinActivate.setOnClickListener {
|
||||
twinsCardWidget.toActivate()
|
||||
}
|
||||
|
||||
|
||||
btn_lp_init.setOnClickListener {
|
||||
binding.btnLpInit.setOnClickListener {
|
||||
leapfrog.initViews()
|
||||
}
|
||||
btn_lp_unfold.setOnClickListener {
|
||||
binding.btnLpUnfold.setOnClickListener {
|
||||
leapfrog.unfold()
|
||||
}
|
||||
btn_lp_fold.setOnClickListener {
|
||||
binding.btnLpFold.setOnClickListener {
|
||||
leapfrog.fold()
|
||||
}
|
||||
btn_lp_leap.setOnClickListener {
|
||||
binding.btnLpLeap.setOnClickListener {
|
||||
leapfrog.leap()
|
||||
}
|
||||
btn_lp_leap_back.setOnClickListener {
|
||||
binding.btnLpLeapBack.setOnClickListener {
|
||||
leapfrog.leapBack()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.view.View
|
|||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.tap.common.extensions.getDrawable
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.details.redux.ConfirmScreenState
|
||||
|
|
@ -12,12 +13,14 @@ import com.tangem.tap.features.details.redux.DetailsAction
|
|||
import com.tangem.tap.features.details.redux.DetailsState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_details_confirm.*
|
||||
import com.tangem.wallet.databinding.FragmentDetailsConfirmBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class DetailsConfirmFragment : Fragment(R.layout.fragment_details_confirm),
|
||||
StoreSubscriber<DetailsState> {
|
||||
|
||||
private val binding: FragmentDetailsConfirmBinding by viewBinding(FragmentDetailsConfirmBinding::bind)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
|
|
@ -47,38 +50,39 @@ class DetailsConfirmFragment : Fragment(R.layout.fragment_details_confirm),
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun newState(state: DetailsState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
setState(state)
|
||||
}
|
||||
|
||||
private fun setState(state: DetailsState) = with(binding) {
|
||||
when (state.confirmScreenState) {
|
||||
ConfirmScreenState.EraseWallet -> {
|
||||
toolbar.title = getString(R.string.details_row_title_reset_factory_settings)
|
||||
tv_warning_description.text = getString(R.string.details_row_title_reset_factory_settings_warning)
|
||||
btn_confirm.text = getString(R.string.details_row_title_reset_factory_settings)
|
||||
btn_confirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
null, null, getDrawable(R.drawable.ic_send), null
|
||||
tvWarningDescription.text = getString(R.string.details_row_title_reset_factory_settings_warning)
|
||||
btnConfirm.text = getString(R.string.details_row_title_reset_factory_settings)
|
||||
btnConfirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
null, null, getDrawable(R.drawable.ic_send), null
|
||||
)
|
||||
btn_confirm.setOnClickListener { store.dispatch(DetailsAction.ResetToFactory.Confirm) }
|
||||
btnConfirm.setOnClickListener { store.dispatch(DetailsAction.ResetToFactory.Confirm) }
|
||||
}
|
||||
ConfirmScreenState.LongTap, ConfirmScreenState.AccessCode,
|
||||
ConfirmScreenState.PassCode -> {
|
||||
toolbar.title = getString(R.string.details_manage_security_title)
|
||||
tv_warning_description.text = getString(R.string.details_security_management_warning)
|
||||
btn_confirm.text = getString(R.string.common_save_changes)
|
||||
btn_confirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
null, null, getDrawable(R.drawable.ic_save), null
|
||||
tvWarningDescription.text = getString(R.string.details_security_management_warning)
|
||||
btnConfirm.text = getString(R.string.common_save_changes)
|
||||
btnConfirm.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||
null, null, getDrawable(R.drawable.ic_save), null
|
||||
)
|
||||
btn_confirm.setOnClickListener { store.dispatch(DetailsAction.ManageSecurity.SaveChanges) }
|
||||
btnConfirm.setOnClickListener { store.dispatch(DetailsAction.ManageSecurity.SaveChanges) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import android.view.View
|
|||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.common.redux.navigation.AppScreen
|
||||
|
|
@ -18,13 +19,13 @@ import com.tangem.tap.features.details.redux.SecurityOption
|
|||
import com.tangem.tap.features.feedback.FeedbackEmail
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_details.*
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.toolbar
|
||||
import com.tangem.wallet.databinding.FragmentDetailsBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<DetailsState> {
|
||||
|
||||
private var currencySelectionDialog = CurrencySelectionDialog()
|
||||
private val binding: FragmentDetailsBinding by viewBinding(FragmentDetailsBinding::bind)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -55,15 +56,18 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun newState(state: DetailsState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
setState(state)
|
||||
}
|
||||
|
||||
private fun setState(state: DetailsState) = with (binding){
|
||||
|
||||
if (state.cardInfo != null) {
|
||||
val cardId = if (state.isTangemTwins) {
|
||||
|
|
@ -71,61 +75,61 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
} else {
|
||||
state.cardInfo.cardId
|
||||
}
|
||||
tv_card_id.text = cardId
|
||||
tv_issuer.text = state.cardInfo.issuer
|
||||
tv_signed_hashes.text = getString(
|
||||
tvCardId.text = cardId
|
||||
tvIssuer.text = state.cardInfo.issuer
|
||||
tvSignedHashes.text = getString(
|
||||
R.string.details_row_subtitle_signed_hashes_format,
|
||||
state.cardInfo.signedHashes.toString()
|
||||
)
|
||||
}
|
||||
|
||||
tv_signed_hashes.show(!state.isTangemTwins)
|
||||
tv_signed_hashes_title.show(!state.isTangemTwins)
|
||||
tvSignedHashes.show(!state.isTangemTwins)
|
||||
tvSignedHashesTitle.show(!state.isTangemTwins)
|
||||
|
||||
tv_disclaimer.setOnClickListener { store.dispatch(DetailsAction.ShowDisclaimer) }
|
||||
tvDisclaimer.setOnClickListener { store.dispatch(DetailsAction.ShowDisclaimer) }
|
||||
|
||||
tv_card_tou.show(state.cardTermsOfUseUrl != null)
|
||||
tv_card_tou.setOnClickListener {
|
||||
tvCardTou.show(state.cardTermsOfUseUrl != null)
|
||||
tvCardTou.setOnClickListener {
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.data = state.cardTermsOfUseUrl
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
if (state.isTangemTwins) {
|
||||
tv_reset_to_factory.show()
|
||||
tv_reset_to_factory.text = getText(R.string.details_row_title_twins_recreate)
|
||||
tv_reset_to_factory.setOnClickListener {
|
||||
tvResetToFactory.show()
|
||||
tvResetToFactory.text = getText(R.string.details_row_title_twins_recreate)
|
||||
tvResetToFactory.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ReCreateTwinsWallet(state.twinCardsState.cardNumber!!))
|
||||
}
|
||||
} else {
|
||||
tv_reset_to_factory.show()
|
||||
tv_reset_to_factory.text = getText(R.string.details_row_title_reset_factory_settings)
|
||||
tv_reset_to_factory.setOnClickListener {
|
||||
tvResetToFactory.show()
|
||||
tvResetToFactory.text = getText(R.string.details_row_title_reset_factory_settings)
|
||||
tvResetToFactory.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ResetToFactory.Check)
|
||||
store.dispatch(DetailsAction.ResetToFactory.Proceed)
|
||||
}
|
||||
}
|
||||
|
||||
tv_create_backup.show(state.createBackupAllowed)
|
||||
tv_create_backup.setOnClickListener {
|
||||
tvCreateBackup.show(state.createBackupAllowed)
|
||||
tvCreateBackup.setOnClickListener {
|
||||
store.dispatch(DetailsAction.CreateBackup)
|
||||
}
|
||||
|
||||
tv_app_currency.text = state.appCurrencyState.fiatCurrencyName
|
||||
tvAppCurrency.text = state.appCurrencyState.fiatCurrencyName
|
||||
|
||||
tv_app_currency_title.setOnClickListener {
|
||||
tvAppCurrencyTitle.setOnClickListener {
|
||||
store.dispatch(DetailsAction.AppCurrencyAction.ChooseAppCurrency)
|
||||
}
|
||||
tv_send_feedback.setOnClickListener {
|
||||
tvSendFeedback.setOnClickListener {
|
||||
store.dispatch(GlobalAction.SendFeedback(FeedbackEmail()))
|
||||
}
|
||||
|
||||
tv_wallet_connect.show(state.scanResponse?.card?.isMultiwalletAllowed == true)
|
||||
tv_wallet_connect.setOnClickListener {
|
||||
tvWalletConnect.show(state.scanResponse?.card?.isMultiwalletAllowed == true)
|
||||
tvWalletConnect.setOnClickListener {
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.WalletConnectSessions))
|
||||
}
|
||||
|
||||
ll_manage_security.setOnClickListener {
|
||||
llManageSecurity.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ManageSecurity.CheckCurrentSecurityOption(state.scanResponse!!.card))
|
||||
}
|
||||
|
||||
|
|
@ -135,7 +139,7 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
SecurityOption.AccessCode -> R.string.details_manage_security_access_code
|
||||
null -> null
|
||||
}
|
||||
currentSecurity?.let { tv_security.text = getString(it) }
|
||||
currentSecurity?.let { tvSecurity.text = getString(it) }
|
||||
|
||||
if (state.appCurrencyState.showAppCurrencyDialog &&
|
||||
!state.appCurrencyState.fiatCurrencies.isNullOrEmpty()) {
|
||||
|
|
@ -147,7 +151,6 @@ class DetailsFragment : Fragment(R.layout.fragment_details), StoreSubscriber<Det
|
|||
} else {
|
||||
currencySelectionDialog.clear()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import android.view.View
|
|||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.common.card.Card
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
|
|
@ -13,14 +14,17 @@ import com.tangem.tap.features.details.redux.DetailsState
|
|||
import com.tangem.tap.features.details.redux.SecurityOption
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_details_confirm.toolbar
|
||||
import kotlinx.android.synthetic.main.fragment_details_security.*
|
||||
import com.tangem.wallet.databinding.FragmentDetailsSecurityBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
import java.util.*
|
||||
|
||||
class DetailsSecurityFragment : Fragment(R.layout.fragment_details_security),
|
||||
StoreSubscriber<DetailsState> {
|
||||
|
||||
private val binding: FragmentDetailsSecurityBinding by viewBinding(
|
||||
FragmentDetailsSecurityBinding::bind
|
||||
)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
|
|
@ -49,14 +53,14 @@ class DetailsSecurityFragment : Fragment(R.layout.fragment_details_security),
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
toolbar.setNavigationOnClickListener {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
setOnClickListeners()
|
||||
}
|
||||
|
||||
private fun setOnClickListeners() {
|
||||
btn_save_changes.setOnClickListener {
|
||||
binding.btnSaveChanges.setOnClickListener {
|
||||
store.state.detailsState.securityScreenState?.selectedOption?.let {
|
||||
store.dispatch(DetailsAction.ManageSecurity.ConfirmSelection(it))
|
||||
}
|
||||
|
|
@ -64,7 +68,8 @@ class DetailsSecurityFragment : Fragment(R.layout.fragment_details_security),
|
|||
}
|
||||
|
||||
override fun newState(state: DetailsState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
selectSecurityOption(state.securityScreenState?.selectedOption)
|
||||
for (option in SecurityOption.values()) {
|
||||
setupOption(
|
||||
|
|
@ -73,18 +78,18 @@ class DetailsSecurityFragment : Fragment(R.layout.fragment_details_security),
|
|||
?: EnumSet.noneOf(SecurityOption::class.java)
|
||||
)
|
||||
}
|
||||
tv_access_code_unavailable_disclaimer.show(
|
||||
binding.tvAccessCodeUnavailableDisclaimer.show(
|
||||
state.scanResponse?.card?.backupStatus == Card.BackupStatus.NoBackup
|
||||
)
|
||||
}
|
||||
|
||||
private fun selectSecurityOption(securityOption: SecurityOption?) {
|
||||
radiobutton_long_tap.isChecked =
|
||||
securityOption == SecurityOption.LongTap && radiobutton_long_tap.isEnabled
|
||||
radiobutton_passcode.isChecked =
|
||||
securityOption == SecurityOption.PassCode && radiobutton_passcode.isEnabled
|
||||
radiobutton_access_code.isChecked =
|
||||
securityOption == SecurityOption.AccessCode && radiobutton_access_code.isEnabled
|
||||
private fun selectSecurityOption(securityOption: SecurityOption?) = with(binding) {
|
||||
radiobuttonLongTap.isChecked =
|
||||
securityOption == SecurityOption.LongTap && radiobuttonLongTap.isEnabled
|
||||
radiobuttonPasscode.isChecked =
|
||||
securityOption == SecurityOption.PassCode && radiobuttonPasscode.isEnabled
|
||||
radiobuttonAccessCode.isChecked =
|
||||
securityOption == SecurityOption.AccessCode && radiobuttonAccessCode.isEnabled
|
||||
}
|
||||
|
||||
private fun setupOption(option: SecurityOption, allowedOptions: EnumSet<SecurityOption>) {
|
||||
|
|
@ -95,46 +100,46 @@ class DetailsSecurityFragment : Fragment(R.layout.fragment_details_security),
|
|||
}
|
||||
}
|
||||
|
||||
private fun enableLongTap(enable: Boolean) {
|
||||
group_long_tap.show(enable)
|
||||
private fun enableLongTap(enable: Boolean) = with(binding) {
|
||||
groupLongTap.show(enable)
|
||||
val alpha = if (enable) 1f else 0.5f
|
||||
tv_long_tap_description.alpha = alpha
|
||||
tv_long_tap_title.alpha = alpha
|
||||
radiobutton_long_tap.alpha = alpha
|
||||
radiobutton_long_tap.isEnabled = enable
|
||||
v_long_tap.isClickable = enable
|
||||
tvLongTapDescription.alpha = alpha
|
||||
tvLongTapTitle.alpha = alpha
|
||||
radiobuttonLongTap.alpha = alpha
|
||||
radiobuttonLongTap.isEnabled = enable
|
||||
vLongTap.isClickable = enable
|
||||
if (enable) {
|
||||
v_long_tap.setOnClickListener {
|
||||
vLongTap.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ManageSecurity.SelectOption(SecurityOption.LongTap))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun enablePasscode(enable: Boolean) {
|
||||
group_passcode.show(enable)
|
||||
private fun enablePasscode(enable: Boolean) = with(binding) {
|
||||
groupPasscode.show(enable)
|
||||
val alpha = if (enable) 1f else 0.5f
|
||||
tv_passcode_description.alpha = alpha
|
||||
tv_passcode_title.alpha = alpha
|
||||
radiobutton_passcode.alpha = alpha
|
||||
radiobutton_passcode.isEnabled = enable
|
||||
v_passcode.isClickable = enable
|
||||
tvPasscodeDescription.alpha = alpha
|
||||
tvPasscodeTitle.alpha = alpha
|
||||
radiobuttonPasscode.alpha = alpha
|
||||
radiobuttonPasscode.isEnabled = enable
|
||||
vPasscode.isClickable = enable
|
||||
if (enable) {
|
||||
v_passcode.setOnClickListener {
|
||||
vPasscode.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ManageSecurity.SelectOption(SecurityOption.PassCode))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun enableAccessCode(enable: Boolean) {
|
||||
group_access_code.show(enable)
|
||||
private fun enableAccessCode(enable: Boolean) = with(binding) {
|
||||
groupAccessCode.show(enable)
|
||||
val alpha = if (enable) 1f else 0.5f
|
||||
tv_access_code_description.alpha = alpha
|
||||
tv_access_code_title.alpha = alpha
|
||||
radiobutton_access_code.alpha = alpha
|
||||
radiobutton_access_code.isEnabled = enable
|
||||
v_access_code.isClickable = enable
|
||||
tvAccessCodeDescription.alpha = alpha
|
||||
tvAccessCodeTitle.alpha = alpha
|
||||
radiobuttonAccessCode.alpha = alpha
|
||||
radiobuttonAccessCode.isEnabled = enable
|
||||
vAccessCode.isClickable = enable
|
||||
if (enable) {
|
||||
v_access_code.setOnClickListener {
|
||||
vAccessCode.setOnClickListener {
|
||||
store.dispatch(DetailsAction.ManageSecurity.SelectOption(SecurityOption.AccessCode))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@ package com.tangem.tap.features.details.ui.walletconnect
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.item_wallet_connect_session.view.*
|
||||
|
||||
class WalletConnectSessionsAdapter
|
||||
: ListAdapter<WalletConnectSession, WalletConnectSessionsAdapter.SessionsViewHolder>(
|
||||
|
|
@ -41,15 +42,14 @@ class WalletConnectSessionsAdapter
|
|||
RecyclerView.ViewHolder(view) {
|
||||
|
||||
fun bind(session: WalletConnectSession) {
|
||||
view.tv_card_id.text = view.context.getString(
|
||||
view.findViewById<TextView>(R.id.tv_card_id).text = view.context.getString(
|
||||
R.string.wallet_connect_card_number, session.wallet.cardId
|
||||
)
|
||||
view.tv_d_app_name.text = session.peerMeta.name
|
||||
view.findViewById<TextView>(R.id.tv_d_app_name).text = session.peerMeta.name
|
||||
|
||||
view.btn_disconnect.setOnClickListener {
|
||||
view.findViewById<Chip>(R.id.btn_disconnect).setOnClickListener {
|
||||
store.dispatch(WalletConnectAction.DisconnectSession(session.session))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,20 @@
|
|||
package com.tangem.tap.features.details.ui.walletconnect
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectAction
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectSession
|
||||
import com.tangem.tap.features.details.redux.walletconnect.WalletConnectState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_connect_sessions.*
|
||||
import com.tangem.wallet.databinding.FragmentWalletConnectSessionsBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
|
||||
|
|
@ -21,7 +22,9 @@ class WalletConnectSessionsFragment : Fragment(R.layout.fragment_wallet_connect_
|
|||
StoreSubscriber<WalletConnectState> {
|
||||
|
||||
private lateinit var walletConnectSessionsAdapter: WalletConnectSessionsAdapter
|
||||
private var dialog: Dialog? = null
|
||||
private val binding: FragmentWalletConnectSessionsBinding by viewBinding(
|
||||
FragmentWalletConnectSessionsBinding::bind
|
||||
)
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -53,7 +56,7 @@ class WalletConnectSessionsFragment : Fragment(R.layout.fragment_wallet_connect_
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
toolbar.setNavigationOnClickListener {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
setOnClickListeners()
|
||||
|
|
@ -61,27 +64,31 @@ class WalletConnectSessionsFragment : Fragment(R.layout.fragment_wallet_connect_
|
|||
}
|
||||
|
||||
private fun setOnClickListeners() {
|
||||
fab_open_session.setOnClickListener {
|
||||
binding.fabOpenSession.setOnClickListener {
|
||||
store.dispatch(WalletConnectAction.StartWalletConnect(activity = requireActivity()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupTransactionsRecyclerView() {
|
||||
private fun setupTransactionsRecyclerView() = with(binding) {
|
||||
walletConnectSessionsAdapter = WalletConnectSessionsAdapter()
|
||||
rv_wallet_connect_sessions.layoutManager = LinearLayoutManager(requireContext())
|
||||
rv_wallet_connect_sessions.adapter = walletConnectSessionsAdapter
|
||||
rvWalletConnectSessions.layoutManager = LinearLayoutManager(requireContext())
|
||||
rvWalletConnectSessions.adapter = walletConnectSessionsAdapter
|
||||
walletConnectSessionsAdapter.submitList(store.state.walletConnectState.sessions)
|
||||
}
|
||||
|
||||
override fun newState(state: WalletConnectState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
fab_open_session.show(!state.loading)
|
||||
pb_wallet_connect.show(state.loading)
|
||||
binding.fabOpenSession.show(!state.loading)
|
||||
binding.pbWalletConnect.show(state.loading)
|
||||
|
||||
walletConnectSessionsAdapter.submitList(state.sessions)
|
||||
rv_wallet_connect_sessions.show(state.sessions.isNotEmpty())
|
||||
tv_no_sessions.show(state.sessions.isEmpty())
|
||||
tv_no_sessions_title.show(state.sessions.isEmpty())
|
||||
showUpdatedList(state.sessions)
|
||||
}
|
||||
|
||||
private fun showUpdatedList(sessions: List<WalletConnectSession>) = with(binding) {
|
||||
walletConnectSessionsAdapter.submitList(sessions)
|
||||
rvWalletConnectSessions.show(sessions.isNotEmpty())
|
||||
tvNoSessions.show(sessions.isEmpty())
|
||||
tvNoSessionsTitle.show(sessions.isEmpty())
|
||||
}
|
||||
}
|
||||
|
|
@ -5,18 +5,21 @@ import android.view.View
|
|||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerAction
|
||||
import com.tangem.tap.features.disclaimer.redux.DisclaimerState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_disclaimer.*
|
||||
import com.tangem.wallet.databinding.FragmentDisclaimerBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class DisclaimerFragment : Fragment(R.layout.fragment_disclaimer),
|
||||
StoreSubscriber<DisclaimerState> {
|
||||
|
||||
private val binding: FragmentDisclaimerBinding by viewBinding(FragmentDisclaimerBinding::bind)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
|
||||
|
|
@ -45,22 +48,22 @@ class DisclaimerFragment : Fragment(R.layout.fragment_disclaimer),
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
toolbar.setNavigationOnClickListener {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
store.dispatch(NavigationAction.PopBackTo())
|
||||
}
|
||||
setOnClickListeners()
|
||||
}
|
||||
|
||||
private fun setOnClickListeners() {
|
||||
btn_accept.setOnClickListener { store.dispatch(DisclaimerAction.AcceptDisclaimer) }
|
||||
binding.btnAccept.setOnClickListener { store.dispatch(DisclaimerAction.AcceptDisclaimer) }
|
||||
}
|
||||
|
||||
override fun newState(state: DisclaimerState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
if (state.accepted) {
|
||||
half_transparent_overlay.hide()
|
||||
btn_accept.hide()
|
||||
binding.halfTransparentOverlay.hide()
|
||||
binding.btnAccept.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,35 +2,25 @@ package com.tangem.tap.features.home
|
|||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.transition.TransitionInflater
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
|
||||
import com.tangem.tap.common.redux.navigation.ShareElement
|
||||
import com.tangem.tap.common.toggleWidget.IndeterminateProgressButtonWidget
|
||||
import com.tangem.tap.common.toggleWidget.ViewStateWidget
|
||||
import com.tangem.tap.common.transitions.FrontCardEnterTransition
|
||||
import com.tangem.tap.common.transitions.FrontCardExitTransition
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.accompanist.appcompattheme.AppCompatTheme
|
||||
import com.tangem.tap.features.home.compose.StoriesScreen
|
||||
import com.tangem.tap.features.home.redux.HomeAction
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
import com.tangem.tap.features.onboarding.products.BaseOnboardingFragment
|
||||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding_main.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_container_bottom.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_home_top.*
|
||||
import kotlinx.android.synthetic.main.view_bg_home.*
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class HomeFragment : BaseOnboardingFragment<HomeState>() {
|
||||
class HomeFragment : Fragment(R.layout.fragment_home), StoreSubscriber<HomeState> {
|
||||
|
||||
private lateinit var btnScanCard: ViewStateWidget
|
||||
|
||||
override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_home_top
|
||||
var homeState: MutableState<HomeState> = mutableStateOf(store.state.homeState)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val inflater = TransitionInflater.from(requireContext())
|
||||
exitTransition = inflater.inflateTransition(R.transition.fade)
|
||||
store.dispatch(HomeAction.Init)
|
||||
}
|
||||
|
||||
|
|
@ -39,50 +29,36 @@ class HomeFragment : BaseOnboardingFragment<HomeState>() {
|
|||
|
||||
store.dispatch(BackupAction.CheckForUnfinishedBackup)
|
||||
|
||||
toolbar.hide()
|
||||
val shareTransition = FragmentShareTransition(
|
||||
listOf(
|
||||
ShareElement(imv_front_card, ShareElement.imvFrontCard),
|
||||
ShareElement(imv_back_card, ShareElement.imvBackCard),
|
||||
ShareElement(bg_circle_large),
|
||||
ShareElement(bg_circle_medium),
|
||||
ShareElement(bg_circle_min),
|
||||
),
|
||||
FrontCardEnterTransition(),
|
||||
FrontCardExitTransition()
|
||||
)
|
||||
|
||||
store.dispatch(HomeAction.SetFragmentShareTransition(shareTransition))
|
||||
|
||||
tv_header.setText(R.string.home_welcome_header)
|
||||
tv_body.setText(R.string.home_welcome_body)
|
||||
|
||||
btn_main_action.setText(R.string.home_button_scan)
|
||||
btn_main_action.setOnClickListener { store.dispatch(HomeAction.ReadCard) }
|
||||
btn_alternative_action.setText(R.string.home_button_get_new_card)
|
||||
btn_alternative_action.setOnClickListener { store.dispatch(HomeAction.GoToShop) }
|
||||
|
||||
btnScanCard = IndeterminateProgressButtonWidget(btn_main_action, progress)
|
||||
getView()?.findViewById<ComposeView>(R.id.cv_stories)?.setContent {
|
||||
AppCompatTheme {
|
||||
StoriesScreen(
|
||||
homeState,
|
||||
onScanButtonClick = { store.dispatch(HomeAction.ReadCard) },
|
||||
onShopButtonClick = { store.dispatch(HomeAction.GoToShop) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
store.subscribe(this) { state ->
|
||||
state.skipRepeats { oldState, newState ->
|
||||
oldState.homeState == newState.homeState
|
||||
}.select { it.homeState }
|
||||
}
|
||||
storeSubscribersList.add(this)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
|
||||
override fun newState(state: HomeState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
btnScanCard.changeState(state.btnScanState.progressState)
|
||||
btnScanCard.mainView.isEnabled = state.btnScanState.enabled
|
||||
homeState.value = state
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
store.dispatch(HomeAction.SetFragmentShareTransition(null))
|
||||
super.onDestroyView()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
package com.tangem.tap.features.home.compose
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.scaleIn
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@OptIn(ExperimentalAnimationApi::class)
|
||||
@Composable
|
||||
fun FirstStoriesContent(
|
||||
paused: Boolean, duration: Int = 8_000,
|
||||
hideContent: (Boolean) -> Unit
|
||||
) {
|
||||
val screenState = remember { mutableStateOf(StartingScreenState.INIT) }
|
||||
val progress = remember { Animatable(0f) }
|
||||
|
||||
LaunchedEffect(paused) {
|
||||
if (paused) {
|
||||
progress.stop()
|
||||
} else {
|
||||
progress.animateTo(
|
||||
targetValue = 2f,
|
||||
animationSpec = tween(
|
||||
durationMillis = duration,
|
||||
easing = LinearEasing
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
when (progress.value) {
|
||||
in 0f..0.2f -> screenState.value = StartingScreenState.INIT
|
||||
in 0.2f..0.3f -> screenState.value = StartingScreenState.BUY
|
||||
in 0.3f..0.4f -> screenState.value = StartingScreenState.STORE
|
||||
in 0.4f..0.5f -> screenState.value = StartingScreenState.SEND
|
||||
in 0.5f..0.6f -> screenState.value = StartingScreenState.PAY
|
||||
in 0.6f..0.7f -> screenState.value = StartingScreenState.EXCHANGE
|
||||
in 0.7f..0.8f -> screenState.value = StartingScreenState.BORROW
|
||||
in 0.8f..1f -> screenState.value = StartingScreenState.LEND
|
||||
in 1f..1.2f -> screenState.value = StartingScreenState.SHOW_CARD
|
||||
in 1.2f..2f -> screenState.value = StartingScreenState.MEET_TANGEM
|
||||
}
|
||||
|
||||
if (screenState.value == StartingScreenState.INIT) hideContent(true)
|
||||
if (screenState.value == StartingScreenState.BUY) hideContent(false)
|
||||
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
|
||||
val text = when (screenState.value) {
|
||||
StartingScreenState.INIT -> null
|
||||
StartingScreenState.BUY -> R.string.story_meet_buy
|
||||
StartingScreenState.STORE -> R.string.story_meet_store
|
||||
StartingScreenState.SEND -> R.string.story_meet_send
|
||||
StartingScreenState.PAY -> R.string.story_meet_pay
|
||||
StartingScreenState.EXCHANGE -> R.string.story_meet_exchange
|
||||
StartingScreenState.BORROW -> R.string.story_meet_borrow
|
||||
StartingScreenState.LEND -> R.string.story_meet_lend
|
||||
StartingScreenState.SHOW_CARD -> R.string.story_meet_title
|
||||
StartingScreenState.MEET_TANGEM -> R.string.story_meet_title
|
||||
}
|
||||
|
||||
if (screenState.value != StartingScreenState.MEET_TANGEM) {
|
||||
Text(
|
||||
text = text?.let { stringResource(text) } ?: "",
|
||||
fontSize = 60.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
modifier = Modifier
|
||||
.padding(start = 40.dp, end = 40.dp)
|
||||
.alpha(if (screenState.value == StartingScreenState.SHOW_CARD) 0f else 1f),
|
||||
color = Color.White,
|
||||
textAlign = TextAlign.Center,
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = screenState.value == StartingScreenState.MEET_TANGEM,
|
||||
enter = slideInVertically() { it / 2 }
|
||||
) {
|
||||
Text(
|
||||
text = text?.let { stringResource(text) } ?: "",
|
||||
fontSize = 60.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
modifier = Modifier
|
||||
.padding(start = 40.dp, end = 40.dp),
|
||||
color = Color.White,
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(
|
||||
visible = screenState.value == StartingScreenState.SHOW_CARD ||
|
||||
screenState.value == StartingScreenState.MEET_TANGEM,
|
||||
enter = scaleIn(initialScale = 3f)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(
|
||||
id = R.drawable.meet_tangem
|
||||
),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class StartingScreenState {
|
||||
INIT, BUY, STORE, SEND, PAY, EXCHANGE, BORROW, LEND, SHOW_CARD, MEET_TANGEM
|
||||
}
|
||||
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun Stories1Preview() {
|
||||
FirstStoriesContent(false, 7_000) {}
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package com.tangem.tap.features.home.compose
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.wallet.R
|
||||
import androidx.compose.foundation.layout.fillMaxWidth as fillMaxWidth1
|
||||
|
||||
@Composable
|
||||
fun HomeButtons(
|
||||
isDarkBackground: Boolean, modifier: Modifier = Modifier,
|
||||
onScanButtonClick: () -> Unit,
|
||||
onShopButtonClick: () -> Unit
|
||||
) {
|
||||
val darkColorBackground = Color(0xFF26292E)
|
||||
val darkColorButton = Color(0xFF080C10)
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
modifier = modifier.fillMaxWidth1()
|
||||
) {
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(42.dp),
|
||||
onClick = onScanButtonClick,
|
||||
colors = ButtonDefaults.textButtonColors(
|
||||
backgroundColor = if (isDarkBackground) darkColorBackground else Color.White,
|
||||
contentColor = if (isDarkBackground) Color.White else darkColorButton
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.home_button_scan),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.size(8.dp))
|
||||
Button(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(42.dp),
|
||||
onClick = onShopButtonClick,
|
||||
colors = ButtonDefaults.textButtonColors(
|
||||
backgroundColor = if (isDarkBackground) Color.White else darkColorBackground,
|
||||
contentColor = if (isDarkBackground) darkColorButton else Color.White
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.home_button_order),
|
||||
fontWeight = FontWeight.Medium,
|
||||
fontSize = 16.sp
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
package com.tangem.tap.features.home.compose
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.tangem.tap.features.home.redux.HomeState
|
||||
import com.tangem.tap.features.wallet.redux.ProgressState
|
||||
import com.tangem.wallet.R
|
||||
import kotlin.math.max
|
||||
|
||||
@Composable
|
||||
fun StoriesScreen(
|
||||
homeState: MutableState<HomeState> = mutableStateOf(HomeState()),
|
||||
onScanButtonClick: () -> Unit,
|
||||
onShopButtonClick: () -> Unit
|
||||
) {
|
||||
val steps = 6
|
||||
val stepDuration = 8_000
|
||||
|
||||
val currentStep = remember { mutableStateOf(1) }
|
||||
|
||||
val isDarkBackground = currentStep.value !in 3..5
|
||||
|
||||
val goToPreviousScreen = {
|
||||
currentStep.value = max(1, currentStep.value - 1)
|
||||
}
|
||||
val goToNextScreen = {
|
||||
currentStep.value = if (currentStep.value < steps) currentStep.value + 1 else 1
|
||||
}
|
||||
|
||||
val isPressed = remember { mutableStateOf(false) }
|
||||
val needsToBePaused =
|
||||
remember(homeState) { mutableStateOf(homeState.value.btnScanState.progressState == ProgressState.Loading) }
|
||||
val pause = isPressed.value || needsToBePaused.value
|
||||
|
||||
val hideContent = remember { mutableStateOf(true) }
|
||||
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color(0xFF090E13))
|
||||
.pointerInput(Unit) {
|
||||
val maxWidth = this.size.width
|
||||
detectTapGestures(
|
||||
onPress = {
|
||||
val pressStartTime = System.currentTimeMillis()
|
||||
isPressed.value = true
|
||||
this.tryAwaitRelease()
|
||||
val pressEndTime = System.currentTimeMillis()
|
||||
val totalPressTime = pressEndTime - pressStartTime
|
||||
if (totalPressTime < 200) {
|
||||
val isTapOnRightTwoTiers = (it.x > (maxWidth / 2))
|
||||
if (isTapOnRightTwoTiers) {
|
||||
goToNextScreen()
|
||||
} else {
|
||||
goToPreviousScreen()
|
||||
}
|
||||
}
|
||||
isPressed.value = false
|
||||
},
|
||||
)
|
||||
}
|
||||
) {
|
||||
if (!isDarkBackground) {
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_overlay),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
contentScale = ContentScale.FillBounds
|
||||
)
|
||||
}
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
) {
|
||||
Spacer(modifier = Modifier.size(24.dp))
|
||||
StoriesProgressBar(
|
||||
steps = steps,
|
||||
currentStep = currentStep.value,
|
||||
// paused = isPressed.value,
|
||||
stepDuration = stepDuration,
|
||||
paused = pause,
|
||||
onStepFinished = goToNextScreen,
|
||||
)
|
||||
Image(
|
||||
painter = painterResource(id = R.drawable.ic_tangem_logo),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillHeight,
|
||||
modifier = Modifier
|
||||
.padding(start = 16.dp, top = 10.dp)
|
||||
.height(17.dp)
|
||||
.alpha(if (hideContent.value) 0f else 1f)
|
||||
.align(Alignment.Start),
|
||||
colorFilter = if (isDarkBackground) null else ColorFilter.tint(Color.Black)
|
||||
)
|
||||
}
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
when (currentStep.value) {
|
||||
1 -> FirstStoriesContent(pause, stepDuration) { hideContent.value = it }
|
||||
2 -> StoriesRevolutionaryWallet()
|
||||
3 -> StoriesUltraSecureBackup()
|
||||
4 -> StoriesThousandsOfCurrencies()
|
||||
5 -> StoriesWeb3()
|
||||
6 -> StoriesWalletForEveryone()
|
||||
}
|
||||
}
|
||||
HomeButtons(
|
||||
isDarkBackground = isDarkBackground,
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(37.dp),
|
||||
onScanButtonClick = onScanButtonClick,
|
||||
onShopButtonClick = onShopButtonClick
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun InstagramScreenPreview() {
|
||||
StoriesScreen(onScanButtonClick = {}, onShopButtonClick = {})
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package com.tangem.tap.features.home.compose
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.tangem.wallet.R
|
||||
|
||||
@Composable
|
||||
fun StoriesGeneralContent(
|
||||
titleText: String,
|
||||
subtitleText: String,
|
||||
imageSource: Int?,
|
||||
isDarkBackground: Boolean,
|
||||
imageComposable: (() -> Unit)? = null,
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center,
|
||||
modifier =
|
||||
Modifier
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight(),
|
||||
) {
|
||||
|
||||
Text(
|
||||
text = titleText,
|
||||
fontSize = 32.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
modifier = Modifier
|
||||
.padding(start = 40.dp, end = 40.dp),
|
||||
color = if (isDarkBackground) Color.White else Color(0xFF090E13),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(16.dp))
|
||||
|
||||
Text(
|
||||
text = subtitleText,
|
||||
fontSize = 20.sp,
|
||||
fontWeight = FontWeight.Normal,
|
||||
modifier = Modifier
|
||||
.padding(start = 40.dp, end = 40.dp),
|
||||
color = Color(0xFFA6AAAD),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.size(25.dp))
|
||||
|
||||
if (imageSource != null) {
|
||||
Image(
|
||||
painter = painterResource(id = imageSource),
|
||||
contentDescription = null,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
imageComposable?.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesRevolutionaryWallet() {
|
||||
StoriesGeneralContent(
|
||||
titleText = stringResource(id = R.string.story_awe_title),
|
||||
subtitleText = stringResource(id = R.string.story_awe_description),
|
||||
imageSource = R.drawable.revolutionary_wallet,
|
||||
isDarkBackground = true
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesUltraSecureBackup() {
|
||||
StoriesGeneralContent(
|
||||
titleText = stringResource(id = R.string.story_backup_title),
|
||||
subtitleText = stringResource(id = R.string.story_backup_description),
|
||||
imageSource = R.drawable.floating_cards,
|
||||
isDarkBackground = false
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesThousandsOfCurrencies() {
|
||||
StoriesGeneralContent(
|
||||
titleText = stringResource(id = R.string.story_currencies_title),
|
||||
subtitleText = stringResource(id = R.string.story_currencies_description),
|
||||
imageSource = R.drawable.thousands_of_currencies,
|
||||
isDarkBackground = false
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesWeb3() {
|
||||
StoriesGeneralContent(
|
||||
titleText = stringResource(id = R.string.story_web3_title),
|
||||
subtitleText = stringResource(id = R.string.story_web3_description),
|
||||
imageSource = R.drawable.web_3,
|
||||
isDarkBackground = false
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun StoriesWalletForEveryone() {
|
||||
StoriesGeneralContent(
|
||||
titleText = stringResource(id = R.string.story_finish_title),
|
||||
subtitleText = stringResource(id = R.string.story_finish_description),
|
||||
imageSource = R.drawable.wallet_for_everyone,
|
||||
isDarkBackground = true
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
package com.tangem.tap.features.home.compose
|
||||
|
||||
import androidx.compose.animation.core.Animatable
|
||||
import androidx.compose.animation.core.LinearEasing
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun StoriesProgressBar(
|
||||
steps: Int,
|
||||
currentStep: Int,
|
||||
paused: Boolean = false,
|
||||
stepDuration: Int = 8_000,
|
||||
onStepFinished: () -> Unit = {},
|
||||
) {
|
||||
val progress = remember(currentStep) { Animatable(0f) }
|
||||
|
||||
LaunchedEffect(paused, currentStep) {
|
||||
if (paused) {
|
||||
progress.stop()
|
||||
} else {
|
||||
progress.animateTo(
|
||||
targetValue = 1f,
|
||||
animationSpec = tween(
|
||||
durationMillis = (stepDuration * (1f - progress.value)).toInt(),
|
||||
easing = LinearEasing
|
||||
)
|
||||
)
|
||||
progress.snapTo(0f)
|
||||
onStepFinished()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
// .height()
|
||||
.padding(start = 9.dp, end = 9.dp, top = 16.dp),
|
||||
) {
|
||||
for (index in 1..steps) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.height(2.dp)
|
||||
.weight(1f)
|
||||
.background(Color.White.copy(alpha = 0.4f))
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(Color.White)
|
||||
.fillMaxHeight().let {
|
||||
when (index) {
|
||||
currentStep -> it.fillMaxWidth(progress.value)
|
||||
in 0..currentStep -> it.fillMaxWidth(1f)
|
||||
else -> it
|
||||
}
|
||||
},
|
||||
) {}
|
||||
}
|
||||
if (index != steps) {
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun StoriesProgressBarPreview() {
|
||||
StoriesProgressBar(steps = 3, currentStep = 2, paused = false) { }
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
|
||||
import org.rekotlin.Action
|
||||
|
||||
sealed class HomeAction : Action {
|
||||
|
|
@ -10,10 +9,9 @@ sealed class HomeAction : Action {
|
|||
object GoToShop : HomeAction()
|
||||
|
||||
// internal
|
||||
data class ShouldScanCardOnResume(val shouldScanCard: Boolean):HomeAction()
|
||||
data class ShouldScanCardOnResume(val shouldScanCard: Boolean) : HomeAction()
|
||||
object Init : HomeAction()
|
||||
|
||||
data class SetFragmentShareTransition(val shareTransition: FragmentShareTransition?) : HomeAction()
|
||||
data class SetTermsOfUseState(val isDisclaimerAccepted: Boolean) : HomeAction()
|
||||
data class ChangeScanCardButtonState(val state: IndeterminateProgressButton) : HomeAction()
|
||||
|
||||
|
|
|
|||
|
|
@ -73,14 +73,14 @@ private fun handleReadCard() {
|
|||
if (OnboardingHelper.isOnboardingCase(scanResponse)) {
|
||||
val navigateTo = OnboardingHelper.whereToNavigate(scanResponse)
|
||||
store.dispatch(GlobalAction.Onboarding.Start(scanResponse))
|
||||
navigateTo(navigateTo, store.state.homeState.shareTransition)
|
||||
navigateTo(navigateTo)
|
||||
} else {
|
||||
scope.launch {
|
||||
store.onCardScanned(scanResponse)
|
||||
withMainContext {
|
||||
if (scanResponse.twinsIsTwinned() && !preferencesStorage.wasTwinsOnboardingShown()) {
|
||||
store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.WelcomeOnly))
|
||||
navigateTo(AppScreen.OnboardingTwins, store.state.homeState.shareTransition)
|
||||
navigateTo(AppScreen.OnboardingTwins)
|
||||
} else {
|
||||
navigateTo(AppScreen.Wallet, null)
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ private fun changeButtonState(state: ButtonState) {
|
|||
store.dispatch(HomeAction.ChangeScanCardButtonState(btnState))
|
||||
}
|
||||
|
||||
private fun navigateTo(screen: AppScreen, transition: FragmentShareTransition?) {
|
||||
private fun navigateTo(screen: AppScreen, transition: FragmentShareTransition? = null) {
|
||||
post(DELAY_SDK_DIALOG_CLOSE) {
|
||||
changeButtonState(ButtonState.ENABLED)
|
||||
store.dispatch(NavigationAction.NavigateTo(screen, transition))
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@ private fun internalReduce(action: Action, state: AppState): HomeState {
|
|||
|
||||
var state = state.homeState
|
||||
when (action) {
|
||||
is HomeAction.SetFragmentShareTransition -> {
|
||||
state = state.copy(shareTransition = action.shareTransition)
|
||||
}
|
||||
is HomeAction.ShouldScanCardOnResume -> {
|
||||
state = state.copy(shouldScanCardOnResume = action.shouldScanCard)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
package com.tangem.tap.features.home.redux
|
||||
|
||||
import com.tangem.tap.common.entities.IndeterminateProgressButton
|
||||
import com.tangem.tap.common.redux.navigation.FragmentShareTransition
|
||||
import com.tangem.tap.features.send.redux.states.ButtonState
|
||||
import org.rekotlin.StateType
|
||||
|
||||
data class HomeState(
|
||||
val shouldScanCardOnResume: Boolean = false,
|
||||
val shareTransition: FragmentShareTransition? = null,
|
||||
val btnScanState: IndeterminateProgressButton = IndeterminateProgressButton(ButtonState.ENABLED),
|
||||
) : StateType
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.tap.features.onboarding
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tangem.tap.common.extensions.copyToClipboard
|
||||
|
|
@ -8,11 +10,11 @@ import com.tangem.tap.common.extensions.dispatchDialogHide
|
|||
import com.tangem.tap.common.extensions.dispatchShare
|
||||
import com.tangem.tap.common.extensions.dispatchToastNotification
|
||||
import com.tangem.tap.common.redux.AppDialog
|
||||
import com.tangem.tap.features.wallet.redux.AddressData
|
||||
import com.tangem.tap.features.wallet.redux.Currency
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.dialog_onboarding_address_info.*
|
||||
import kotlinx.android.synthetic.main.layout_pseudo_toolbar.*
|
||||
import com.tangem.wallet.databinding.DialogOnboardingAddressInfoBinding
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -22,30 +24,40 @@ class AddressInfoBottomSheetDialog(
|
|||
context: Context
|
||||
) : BottomSheetDialog(context) {
|
||||
|
||||
init {
|
||||
this.setContentView(R.layout.dialog_onboarding_address_info)
|
||||
var binding: DialogOnboardingAddressInfoBinding? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = DialogOnboardingAddressInfoBinding
|
||||
.inflate(LayoutInflater.from(context))
|
||||
setContentView(binding!!.root)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
setOnCancelListener { store.dispatchDialogHide() }
|
||||
setOnCancelListener {
|
||||
store.dispatchDialogHide()
|
||||
binding = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
super.show()
|
||||
val data = stateDialog.addressData
|
||||
showData(data = stateDialog.addressData)
|
||||
}
|
||||
|
||||
imv_close.setOnClickListener {
|
||||
private fun showData(data: AddressData) = with(binding!!) {
|
||||
pseudoToolbar.imvClose.setOnClickListener {
|
||||
dismissWithAnimation = true
|
||||
cancel()
|
||||
}
|
||||
imv_qr_code.setImageBitmap(data.qrCode)
|
||||
tv_address.text = data.address
|
||||
btn_fl_copy_address.setOnClickListener {
|
||||
imvQrCode.setImageBitmap(data.qrCode)
|
||||
tvAddress.text = data.address
|
||||
btnFlCopyAddress.setOnClickListener {
|
||||
context.copyToClipboard(data.address)
|
||||
store.dispatchToastNotification(R.string.copy_toast_msg)
|
||||
}
|
||||
btn_fl_share.setOnClickListener {
|
||||
btnFlShare.setOnClickListener {
|
||||
store.dispatchShare(data.shareUrl)
|
||||
}
|
||||
tv_receive_message.text = getQRReceiveMessage(tv_receive_message.context, stateDialog.currency)
|
||||
tvReceiveMessage.text = getQRReceiveMessage(tvReceiveMessage.context, stateDialog.currency)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
package com.tangem.tap.features.onboarding.products
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import com.tangem.tap.common.extensions.inflate
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.transitions.HomeToOnboardingTransition
|
||||
import com.tangem.tap.features.BaseStoreFragment
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding_main.*
|
||||
import kotlinx.android.synthetic.main.view_confetti.*
|
||||
import com.tangem.wallet.databinding.FragmentOnboardingMainBinding
|
||||
import com.tangem.wallet.databinding.ViewOnboardingProgressBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
/**
|
||||
|
|
@ -16,26 +14,22 @@ import org.rekotlin.StoreSubscriber
|
|||
*/
|
||||
abstract class BaseOnboardingFragment<T> : BaseStoreFragment(R.layout.fragment_onboarding_main), StoreSubscriber<T> {
|
||||
|
||||
protected val binding: FragmentOnboardingMainBinding by viewBinding(FragmentOnboardingMainBinding::bind)
|
||||
protected val pbBinding: ViewOnboardingProgressBinding by viewBinding(ViewOnboardingProgressBinding::bind)
|
||||
|
||||
override fun configureTransitions() {
|
||||
enterTransition = HomeToOnboardingTransition()
|
||||
exitTransition = HomeToOnboardingTransition()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
onboarding_top_container.inflate(getOnboardingTopContainerId(), true)
|
||||
}
|
||||
|
||||
abstract fun getOnboardingTopContainerId(): Int
|
||||
|
||||
protected fun showConfetti(show: Boolean) {
|
||||
lav_confetti.show(show)
|
||||
protected fun showConfetti(show: Boolean) = with(binding.vConfetti) {
|
||||
lavConfetti.show(show)
|
||||
|
||||
if (show) {
|
||||
lav_confetti.playAnimation()
|
||||
lavConfetti.playAnimation()
|
||||
} else {
|
||||
lav_confetti.cancelAnimation()
|
||||
lavConfetti.cancelAnimation()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,11 +26,6 @@ import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteStat
|
|||
import com.tangem.tap.features.onboarding.products.note.redux.OnboardingNoteStep
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding_main.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_container_bottom.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_container_top.*
|
||||
import kotlinx.android.synthetic.main.view_onboarding_progress.*
|
||||
import kotlinx.android.synthetic.main.view_onboarding_tv_balance.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
|
|
@ -41,8 +36,6 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
|
|||
|
||||
private lateinit var btnRefreshBalanceWidget: RefreshBalanceWidget
|
||||
|
||||
override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_container_top
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
postponeEnterTransition()
|
||||
|
|
@ -52,11 +45,11 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
addBackPressHandler(this)
|
||||
|
||||
imv_front_card.transitionName = ShareElement.imvFrontCard
|
||||
binding.onboardingTopContainer.imvFrontCard.transitionName = ShareElement.imvFrontCard
|
||||
startPostponedEnterTransition()
|
||||
|
||||
toolbar.setTitle(R.string.onboarding_title)
|
||||
btnRefreshBalanceWidget = RefreshBalanceWidget(onboarding_main_container)
|
||||
binding.toolbar.setTitle(R.string.onboarding_title)
|
||||
btnRefreshBalanceWidget = RefreshBalanceWidget(binding.onboardingTopContainer.onboardingMainContainer)
|
||||
|
||||
store.dispatch(OnboardingNoteAction.LoadCardArtwork)
|
||||
store.dispatch(OnboardingNoteAction.DetermineStepOfScreen)
|
||||
|
|
@ -72,19 +65,19 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
|
|||
}
|
||||
|
||||
override fun newState(state: OnboardingNoteState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
Picasso.get()
|
||||
.load(state.cardArtworkUrl)
|
||||
.error(R.drawable.card_placeholder_black)
|
||||
.placeholder(R.drawable.card_placeholder_black)
|
||||
?.into(imv_front_card)
|
||||
.load(state.cardArtworkUrl)
|
||||
.error(R.drawable.card_placeholder_black)
|
||||
.placeholder(R.drawable.card_placeholder_black)
|
||||
?.into(binding.onboardingTopContainer.imvFrontCard)
|
||||
|
||||
pb_state.max = state.steps.size - 1
|
||||
pb_state.progress = state.progress
|
||||
pbBinding.pbState.max = state.steps.size - 1
|
||||
pbBinding.pbState.progress = state.progress
|
||||
|
||||
when (state.currentStep) {
|
||||
OnboardingNoteStep.None -> setupNoneState(state)
|
||||
OnboardingNoteStep.None -> setupNoneState()
|
||||
OnboardingNoteStep.CreateWallet -> setupCreateWalletState(state)
|
||||
OnboardingNoteStep.TopUpWallet -> setupTopUpWalletState(state)
|
||||
OnboardingNoteStep.Done -> setupDoneState(state)
|
||||
|
|
@ -97,77 +90,82 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
|
|||
private fun setBalance(state: OnboardingNoteState) {
|
||||
if (state.walletBalance.currency.blockchain == Blockchain.Unknown) return
|
||||
|
||||
if (state.balanceCriticalError == null) {
|
||||
val balanceValue = state.walletBalance.value.stripZeroPlainString()
|
||||
tv_balance_value.text = balanceValue
|
||||
tv_balance_currency.text = state.walletBalance.currency.currencySymbol
|
||||
} else {
|
||||
tv_balance_value.text = "–"
|
||||
tv_balance_currency.text = ""
|
||||
with (binding.onboardingTopContainer.onboardingTvBalance) {
|
||||
if (state.balanceCriticalError == null) {
|
||||
val balanceValue = state.walletBalance.value.stripZeroPlainString()
|
||||
tvBalanceValue.text = balanceValue
|
||||
tvBalanceCurrency.text = state.walletBalance.currency.currencySymbol
|
||||
} else {
|
||||
tvBalanceValue.text = "–"
|
||||
tvBalanceCurrency.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupNoneState(state: OnboardingNoteState) {
|
||||
btn_main_action.isVisible = false
|
||||
btn_alternative_action.isVisible = false
|
||||
private fun setupNoneState() = with(binding.onboardingActionContainer) {
|
||||
btnMainAction.isVisible = false
|
||||
btnAlternativeAction.isVisible = false
|
||||
btnRefreshBalanceWidget.show(false)
|
||||
tv_header.isVisible = false
|
||||
tv_body.isVisible = false
|
||||
tvHeader.isVisible = false
|
||||
tvBody.isVisible = false
|
||||
|
||||
btn_main_action.text = ""
|
||||
btn_alternative_action.text = ""
|
||||
tv_header.text = ""
|
||||
tv_body.text = ""
|
||||
btnMainAction.text = ""
|
||||
btnAlternativeAction.text = ""
|
||||
tvHeader.text = ""
|
||||
tvBody.text = ""
|
||||
}
|
||||
|
||||
private fun setupCreateWalletState(state: OnboardingNoteState) {
|
||||
btn_main_action.setText(R.string.onboarding_create_wallet_button_create_wallet)
|
||||
btn_main_action.setOnClickListener { store.dispatch(OnboardingNoteAction.CreateWallet) }
|
||||
btn_alternative_action.setText(R.string.onboarding_button_what_does_it_mean)
|
||||
btn_alternative_action.setOnClickListener { }
|
||||
private fun setupCreateWalletState(state: OnboardingNoteState) =
|
||||
with(binding.onboardingActionContainer) {
|
||||
btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet)
|
||||
btnMainAction.setOnClickListener { store.dispatch(OnboardingNoteAction.CreateWallet) }
|
||||
btnAlternativeAction.setText(R.string.onboarding_button_what_does_it_mean)
|
||||
btnAlternativeAction.setOnClickListener { }
|
||||
|
||||
btnRefreshBalanceWidget.mainView.setOnClickListener(null)
|
||||
btnRefreshBalanceWidget.mainView.setOnClickListener(null)
|
||||
|
||||
tv_header.setText(R.string.onboarding_create_wallet_header)
|
||||
tv_body.setText(R.string.onboarding_create_wallet_body)
|
||||
tvHeader.setText(R.string.onboarding_create_wallet_header)
|
||||
tvBody.setText(R.string.onboarding_create_wallet_body)
|
||||
|
||||
imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_circle))
|
||||
updateConstraints(state.currentStep, R.layout.lp_onboarding_create_wallet)
|
||||
binding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable(
|
||||
requireContext().getDrawableCompat(R.drawable.shape_circle)
|
||||
)
|
||||
updateConstraints(state.currentStep, R.layout.lp_onboarding_create_wallet)
|
||||
|
||||
btn_alternative_action.isVisible = false // temporary
|
||||
}
|
||||
btnAlternativeAction.isVisible = false // temporary
|
||||
}
|
||||
|
||||
private fun setupTopUpWalletState(state: OnboardingNoteState) {
|
||||
private fun setupTopUpWalletState(state: OnboardingNoteState) = with(binding.onboardingActionContainer) {
|
||||
if (state.isBuyAllowed) {
|
||||
btn_main_action.setText(R.string.onboarding_top_up_button_but_crypto)
|
||||
btn_main_action.setOnClickListener {
|
||||
btnMainAction.setText(R.string.onboarding_top_up_button_but_crypto)
|
||||
btnMainAction.setOnClickListener {
|
||||
store.dispatch(OnboardingNoteAction.TopUp)
|
||||
}
|
||||
|
||||
btn_alternative_action.isVisible = true
|
||||
btn_alternative_action.setText(R.string.onboarding_top_up_button_show_wallet_address)
|
||||
btn_alternative_action.setOnClickListener {
|
||||
btnAlternativeAction.isVisible = true
|
||||
btnAlternativeAction.setText(R.string.onboarding_top_up_button_show_wallet_address)
|
||||
btnAlternativeAction.setOnClickListener {
|
||||
store.dispatch(OnboardingNoteAction.ShowAddressInfoDialog)
|
||||
}
|
||||
} else {
|
||||
btn_main_action.setText(R.string.onboarding_button_receive_crypto)
|
||||
btn_main_action.setOnClickListener {
|
||||
btnMainAction.setText(R.string.onboarding_button_receive_crypto)
|
||||
btnMainAction.setOnClickListener {
|
||||
store.dispatch(OnboardingNoteAction.ShowAddressInfoDialog)
|
||||
}
|
||||
|
||||
btn_alternative_action.isVisible = false
|
||||
btnAlternativeAction.isVisible = false
|
||||
}
|
||||
|
||||
tv_header.setText(R.string.onboarding_top_up_header)
|
||||
tvHeader.setText(R.string.onboarding_top_up_header)
|
||||
if (state.balanceNonCriticalError == null) {
|
||||
tv_body.setText(R.string.onboarding_top_up_body)
|
||||
tvBody.setText(R.string.onboarding_top_up_body)
|
||||
} else {
|
||||
state.walletBalance.amountToCreateAccount?.let { amount ->
|
||||
val tvBodyMessage = getString(
|
||||
R.string.onboarding_top_up_body_no_account_error,
|
||||
amount, state.walletBalance.currency.currencySymbol
|
||||
)
|
||||
tv_body.text = tvBodyMessage
|
||||
tvBody.text = tvBodyMessage
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -177,38 +175,43 @@ class OnboardingNoteFragment : BaseOnboardingFragment<OnboardingNoteState>() {
|
|||
store.dispatch(OnboardingNoteAction.Balance.Update)
|
||||
}
|
||||
}
|
||||
imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8))
|
||||
binding.onboardingTopContainer.imvCardBackground
|
||||
.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8))
|
||||
updateConstraints(state.currentStep, R.layout.lp_onboarding_topup_wallet)
|
||||
}
|
||||
|
||||
private fun setupDoneState(state: OnboardingNoteState) {
|
||||
btn_main_action.setText(R.string.onboarding_done_button_continue)
|
||||
btn_main_action.setOnClickListener {
|
||||
private fun setupDoneState(state: OnboardingNoteState) = with(binding.onboardingActionContainer) {
|
||||
btnMainAction.setText(R.string.onboarding_done_button_continue)
|
||||
btnMainAction.setOnClickListener {
|
||||
showConfetti(false)
|
||||
store.dispatch(OnboardingNoteAction.Done)
|
||||
}
|
||||
|
||||
btn_alternative_action.isVisible = false
|
||||
btn_alternative_action.setText("")
|
||||
btn_alternative_action.setOnClickListener { }
|
||||
btnAlternativeAction.isVisible = false
|
||||
btnAlternativeAction.setText("")
|
||||
btnAlternativeAction.setOnClickListener { }
|
||||
btnRefreshBalanceWidget.mainView.setOnClickListener(null)
|
||||
|
||||
tv_header.setText(R.string.onboarding_done_header)
|
||||
tv_body.setText(R.string.onboarding_done_body)
|
||||
tvHeader.setText(R.string.onboarding_done_header)
|
||||
tvBody.setText(R.string.onboarding_done_body)
|
||||
|
||||
imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8))
|
||||
binding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable(
|
||||
requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8)
|
||||
)
|
||||
updateConstraints(state.currentStep, R.layout.lp_onboarding_done_activation)
|
||||
}
|
||||
|
||||
private fun updateConstraints(currentStep: OnboardingNoteStep, @LayoutRes layoutId: Int) {
|
||||
if (this.previousStep == currentStep) return
|
||||
|
||||
val constraintSet = ConstraintSet()
|
||||
constraintSet.clone(requireContext(), layoutId)
|
||||
constraintSet.applyTo(onboarding_main_container)
|
||||
val transition = InternalNoteLayoutTransition()
|
||||
transition.interpolator = OvershootInterpolator()
|
||||
TransitionManager.beginDelayedTransition(onboarding_main_container, transition)
|
||||
with(binding.onboardingTopContainer) {
|
||||
val constraintSet = ConstraintSet()
|
||||
constraintSet.clone(requireContext(), layoutId)
|
||||
constraintSet.applyTo(onboardingMainContainer)
|
||||
val transition = InternalNoteLayoutTransition()
|
||||
transition.interpolator = OvershootInterpolator()
|
||||
TransitionManager.beginDelayedTransition(onboardingMainContainer, transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,18 +18,12 @@ import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOt
|
|||
import com.tangem.tap.features.onboarding.products.otherCards.redux.OnboardingOtherCardsStep
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding_main.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_container_bottom.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_container_top.*
|
||||
import kotlinx.android.synthetic.main.view_onboarding_progress.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class OnboardingOtherCardsFragment : BaseOnboardingFragment<OnboardingOtherCardsState>() {
|
||||
|
||||
override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_container_top
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
postponeEnterTransition()
|
||||
|
|
@ -39,10 +33,10 @@ class OnboardingOtherCardsFragment : BaseOnboardingFragment<OnboardingOtherCards
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
addBackPressHandler(this)
|
||||
|
||||
imv_front_card.transitionName = ShareElement.imvFrontCard
|
||||
binding.onboardingTopContainer.imvFrontCard.transitionName = ShareElement.imvFrontCard
|
||||
startPostponedEnterTransition()
|
||||
|
||||
toolbar.setTitle(R.string.onboarding_title)
|
||||
binding.toolbar.setTitle(R.string.onboarding_title)
|
||||
store.dispatch(OnboardingOtherCardsAction.LoadCardArtwork)
|
||||
store.dispatch(OnboardingOtherCardsAction.DetermineStepOfScreen)
|
||||
}
|
||||
|
|
@ -57,64 +51,75 @@ class OnboardingOtherCardsFragment : BaseOnboardingFragment<OnboardingOtherCards
|
|||
}
|
||||
|
||||
override fun newState(state: OnboardingOtherCardsState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
if (state.currentStep == OnboardingOtherCardsStep.None) return
|
||||
|
||||
Picasso.get()
|
||||
.load(state.cardArtworkUrl)
|
||||
.error(R.drawable.card_placeholder_black)
|
||||
.placeholder(R.drawable.card_placeholder_black)
|
||||
?.into(imv_front_card)
|
||||
.load(state.cardArtworkUrl)
|
||||
.error(R.drawable.card_placeholder_black)
|
||||
.placeholder(R.drawable.card_placeholder_black)
|
||||
?.into(binding.onboardingTopContainer.imvFrontCard)
|
||||
|
||||
pb_state.max = state.steps.size - 1
|
||||
pb_state.progress = state.progress
|
||||
pbBinding.pbState.max = state.steps.size - 1
|
||||
pbBinding.pbState.progress = state.progress
|
||||
|
||||
when (state.currentStep) {
|
||||
OnboardingOtherCardsStep.CreateWallet -> setupCreateWalletState(state)
|
||||
OnboardingOtherCardsStep.Done -> setupDoneState(state)
|
||||
OnboardingOtherCardsStep.CreateWallet -> setupCreateWalletState()
|
||||
OnboardingOtherCardsStep.Done -> setupDoneState()
|
||||
}
|
||||
showConfetti(state.showConfetti)
|
||||
}
|
||||
|
||||
private fun setupCreateWalletState(state: OnboardingOtherCardsState) {
|
||||
btn_main_action.setText(R.string.onboarding_create_wallet_button_create_wallet)
|
||||
btn_main_action.setOnClickListener { store.dispatch(OnboardingOtherCardsAction.CreateWallet) }
|
||||
btn_alternative_action.setText(R.string.onboarding_button_what_does_it_mean)
|
||||
btn_alternative_action.setOnClickListener { }
|
||||
private fun setupCreateWalletState() = with(binding) {
|
||||
|
||||
tv_header.setText(R.string.onboarding_create_wallet_header)
|
||||
tv_body.setText(R.string.onboarding_create_wallet_body)
|
||||
with(onboardingActionContainer) {
|
||||
btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet)
|
||||
btnMainAction.setOnClickListener { store.dispatch(OnboardingOtherCardsAction.CreateWallet) }
|
||||
btnAlternativeAction.setText(R.string.onboarding_button_what_does_it_mean)
|
||||
btnAlternativeAction.setOnClickListener { }
|
||||
|
||||
imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_circle))
|
||||
tvHeader.setText(R.string.onboarding_create_wallet_header)
|
||||
tvBody.setText(R.string.onboarding_create_wallet_body)
|
||||
|
||||
btnAlternativeAction.isVisible = false // temporary
|
||||
}
|
||||
|
||||
|
||||
binding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable(
|
||||
requireContext().getDrawableCompat(R.drawable.shape_circle)
|
||||
)
|
||||
updateConstraints(R.layout.lp_onboarding_create_wallet)
|
||||
|
||||
btn_alternative_action.isVisible = false // temporary
|
||||
}
|
||||
|
||||
private fun setupDoneState(state: OnboardingOtherCardsState) {
|
||||
btn_main_action.setText(R.string.onboarding_done_button_continue)
|
||||
btn_main_action.setOnClickListener {
|
||||
private fun setupDoneState() = with(binding.onboardingActionContainer) {
|
||||
btnMainAction.setText(R.string.onboarding_done_button_continue)
|
||||
btnMainAction.setOnClickListener {
|
||||
showConfetti(false)
|
||||
store.dispatch(OnboardingOtherCardsAction.Done)
|
||||
}
|
||||
|
||||
btn_alternative_action.isVisible = false
|
||||
btn_alternative_action.setText("")
|
||||
btn_alternative_action.setOnClickListener { }
|
||||
btnAlternativeAction.isVisible = false
|
||||
btnAlternativeAction.setText("")
|
||||
btnAlternativeAction.setOnClickListener { }
|
||||
|
||||
tv_header.setText(R.string.onboarding_done_header)
|
||||
tv_body.setText(R.string.onboarding_done_body)
|
||||
tvHeader.setText(R.string.onboarding_done_header)
|
||||
tvBody.setText(R.string.onboarding_done_body)
|
||||
|
||||
imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8))
|
||||
binding.onboardingTopContainer.imvCardBackground?.setBackgroundDrawable(
|
||||
requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8)
|
||||
)
|
||||
updateConstraints(R.layout.lp_onboarding_done)
|
||||
}
|
||||
|
||||
private fun updateConstraints(@LayoutRes layoutId: Int) {
|
||||
val constraintSet = ConstraintSet()
|
||||
constraintSet.clone(requireContext(), layoutId)
|
||||
constraintSet.applyTo(onboarding_main_container)
|
||||
val transition = InternalNoteLayoutTransition()
|
||||
transition.interpolator = OvershootInterpolator()
|
||||
TransitionManager.beginDelayedTransition(onboarding_main_container, transition)
|
||||
with(binding.onboardingTopContainer) {
|
||||
val constraintSet = ConstraintSet()
|
||||
constraintSet.clone(requireContext(), layoutId)
|
||||
constraintSet.applyTo(onboardingMainContainer)
|
||||
val transition = InternalNoteLayoutTransition()
|
||||
transition.interpolator = OvershootInterpolator()
|
||||
TransitionManager.beginDelayedTransition(onboardingMainContainer, transition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,13 +32,7 @@ import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsStep
|
|||
import com.tangem.tap.features.wallet.redux.Artwork
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding_main.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_container_bottom.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_container_top.*
|
||||
import kotlinx.android.synthetic.main.view_bg_twins_welcome.*
|
||||
import kotlinx.android.synthetic.main.view_onboarding_progress.*
|
||||
import kotlinx.android.synthetic.main.view_onboarding_tv_balance.*
|
||||
|
||||
import com.tangem.wallet.databinding.LayoutOnboardingContainerTopBinding
|
||||
|
||||
class TwinsCardsFragment : BaseOnboardingFragment<TwinCardsState>() {
|
||||
|
||||
|
|
@ -49,12 +43,11 @@ class TwinsCardsFragment : BaseOnboardingFragment<TwinCardsState>() {
|
|||
|
||||
private val assetReader: AssetReader by lazy {
|
||||
object : AssetReader {
|
||||
override fun readAssetAsString(name: String): String = requireContext().readAssetAsString(name)
|
||||
override fun readAssetAsString(name: String): String =
|
||||
requireContext().readAssetAsString(name)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOnboardingTopContainerId(): Int = R.layout.layout_onboarding_container_top
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
postponeEnterTransition()
|
||||
|
|
@ -76,43 +69,44 @@ class TwinsCardsFragment : BaseOnboardingFragment<TwinCardsState>() {
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
addBackPressHandler(this)
|
||||
|
||||
reconfigureLayoutForTwins()
|
||||
reconfigureLayoutForTwins(binding.onboardingTopContainer)
|
||||
|
||||
val typedValue = TypedValue()
|
||||
resources.getValue(R.dimen.device_scale_factor_for_twins_welcome, typedValue, true)
|
||||
val deviceScaleFactorForWelcomeState = typedValue.float
|
||||
|
||||
twinsWidget = TwinsCardWidget(LeapfrogWidget(cards_container), deviceScaleFactorForWelcomeState) {
|
||||
twinsWidget = TwinsCardWidget(LeapfrogWidget(binding.onboardingTopContainer.cardsContainer), deviceScaleFactorForWelcomeState) {
|
||||
285f * deviceScaleFactorForWelcomeState
|
||||
}
|
||||
btnRefreshBalanceWidget = RefreshBalanceWidget(onboarding_main_container)
|
||||
btnRefreshBalanceWidget = RefreshBalanceWidget(binding.onboardingTopContainer.onboardingMainContainer)
|
||||
|
||||
toolbar.title = getText(R.string.twins_recreate_toolbar)
|
||||
binding.toolbar.title = getText(R.string.twins_recreate_toolbar)
|
||||
|
||||
Picasso.get()
|
||||
.load(Artwork.TWIN_CARD_1)
|
||||
.error(R.drawable.card_placeholder_black)
|
||||
.placeholder(R.drawable.card_placeholder_black)
|
||||
?.into(imv_twin_front_card)
|
||||
.load(Artwork.TWIN_CARD_1)
|
||||
.error(R.drawable.card_placeholder_black)
|
||||
.placeholder(R.drawable.card_placeholder_black)
|
||||
?.into(binding.onboardingTopContainer.imvTwinFrontCard)
|
||||
|
||||
Picasso.get()
|
||||
.load(Artwork.TWIN_CARD_2)
|
||||
.error(R.drawable.card_placeholder_white)
|
||||
.placeholder(R.drawable.card_placeholder_white)
|
||||
?.into(imv_twin_back_card)
|
||||
.load(Artwork.TWIN_CARD_2)
|
||||
.error(R.drawable.card_placeholder_white)
|
||||
.placeholder(R.drawable.card_placeholder_white)
|
||||
?.into(binding.onboardingTopContainer.imvTwinBackCard)
|
||||
}
|
||||
|
||||
private fun reconfigureLayoutForTwins() {
|
||||
imv_front_card.hide()
|
||||
imv_card_background.hide()
|
||||
cards_container.show()
|
||||
private fun reconfigureLayoutForTwins(containerBinding: LayoutOnboardingContainerTopBinding) =
|
||||
with(containerBinding) {
|
||||
imvFrontCard.hide()
|
||||
imvCardBackground.hide()
|
||||
cardsContainer.show()
|
||||
|
||||
imv_twin_front_card.transitionName = ShareElement.imvFrontCard
|
||||
imv_twin_back_card.transitionName = ShareElement.imvBackCard
|
||||
imvTwinFrontCard.transitionName = ShareElement.imvFrontCard
|
||||
imvTwinBackCard.transitionName = ShareElement.imvBackCard
|
||||
|
||||
// if don't this, the bg_circle_... is overflow the app_bar
|
||||
app_bar.bringToFront()
|
||||
}
|
||||
// if don't this, the bg_circle_... is overflow the app_bar
|
||||
binding.appBar.bringToFront()
|
||||
}
|
||||
|
||||
override fun subscribeToStore() {
|
||||
store.subscribe(this) { state ->
|
||||
|
|
@ -124,10 +118,10 @@ class TwinsCardsFragment : BaseOnboardingFragment<TwinCardsState>() {
|
|||
}
|
||||
|
||||
override fun newState(state: TwinCardsState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
pb_state.max = state.steps.size - 1
|
||||
pb_state.progress = state.progress
|
||||
pbBinding.pbState.max = state.steps.size - 1
|
||||
pbBinding.pbState.progress = state.progress
|
||||
|
||||
when (state.currentStep) {
|
||||
TwinCardsStep.WelcomeOnly -> setupWelcomeOnlyState(state)
|
||||
|
|
@ -148,13 +142,15 @@ class TwinsCardsFragment : BaseOnboardingFragment<TwinCardsState>() {
|
|||
private fun setBalance(state: TwinCardsState) {
|
||||
if (state.walletBalance.currency.blockchain == Blockchain.Unknown) return
|
||||
|
||||
if (state.balanceCriticalError == null) {
|
||||
val balanceValue = state.walletBalance.value.stripZeroPlainString()
|
||||
tv_balance_value.text = balanceValue
|
||||
tv_balance_currency.text = state.walletBalance.currency.currencySymbol
|
||||
} else {
|
||||
tv_balance_value.text = "–"
|
||||
tv_balance_currency.text = ""
|
||||
with(binding.onboardingTopContainer.onboardingTvBalance) {
|
||||
if (state.balanceCriticalError == null) {
|
||||
val balanceValue = state.walletBalance.value.stripZeroPlainString()
|
||||
tvBalanceValue.text = balanceValue
|
||||
tvBalanceCurrency.text = state.walletBalance.currency.currencySymbol
|
||||
} else {
|
||||
tvBalanceValue.text = "–"
|
||||
tvBalanceCurrency.text = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,203 +165,235 @@ class TwinsCardsFragment : BaseOnboardingFragment<TwinCardsState>() {
|
|||
setupWelcomeState(state) { store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet)) }
|
||||
}
|
||||
|
||||
private fun setupWelcomeState(state: TwinCardsState, mainAction: VoidCallback) {
|
||||
private fun setupWelcomeState(state: TwinCardsState, mainAction: VoidCallback) =
|
||||
with(binding.onboardingActionContainer) {
|
||||
twinsWidget.toWelcome(false) { startPostponedEnterTransition() }
|
||||
|
||||
binding.onboardingTopContainer.onboardingTwinsWelcomeBg.root.show()
|
||||
pbBinding.pbState.hide()
|
||||
|
||||
tvHeader.setText(R.string.twins_onboarding_subtitle)
|
||||
tvBody.text = getString(
|
||||
R.string.twins_onboarding_description_format,
|
||||
state.cardNumber?.pairIndexNumber()
|
||||
)
|
||||
|
||||
btnMainAction.setText(R.string.common_continue)
|
||||
btnMainAction.setOnClickListener { mainAction() }
|
||||
}
|
||||
|
||||
private fun setupWarningState(state: TwinCardsState) = with(binding.onboardingActionContainer) {
|
||||
twinsWidget.toWelcome(false) { startPostponedEnterTransition() }
|
||||
|
||||
onboarding_twins_welcome_bg.show()
|
||||
pb_state.hide()
|
||||
binding.onboardingTopContainer.onboardingTwinsWelcomeBg.root.hide()
|
||||
pbBinding.pbState.hide()
|
||||
chbUnderstand.show()
|
||||
|
||||
tv_header.setText(R.string.twins_onboarding_subtitle)
|
||||
tv_body.text = getString(R.string.twins_onboarding_description_format, state.cardNumber?.pairIndexNumber())
|
||||
tvHeader.setText(R.string.common_warning)
|
||||
tvBody.setText(R.string.twins_recreate_warning)
|
||||
|
||||
btn_main_action.setText(R.string.common_continue)
|
||||
btn_main_action.setOnClickListener { mainAction() }
|
||||
}
|
||||
|
||||
private fun setupWarningState(state: TwinCardsState) {
|
||||
twinsWidget.toWelcome(false) { startPostponedEnterTransition() }
|
||||
|
||||
onboarding_twins_welcome_bg.hide()
|
||||
pb_state.hide()
|
||||
chb_understand.show()
|
||||
|
||||
tv_header.setText(R.string.common_warning)
|
||||
tv_body.setText(R.string.twins_recreate_warning)
|
||||
|
||||
chb_understand.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
chbUnderstand.setOnCheckedChangeListener { buttonView, isChecked ->
|
||||
store.dispatch(TwinCardsAction.SetUserUnderstand(isChecked))
|
||||
}
|
||||
btn_main_action.isEnabled = state.userWasUnderstandIfWalletRecreate
|
||||
btn_main_action.setText(R.string.common_continue)
|
||||
btn_main_action.setOnClickListener {
|
||||
btnMainAction.isEnabled = state.userWasUnderstandIfWalletRecreate
|
||||
btnMainAction.setText(R.string.common_continue)
|
||||
btnMainAction.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.SetStepOfScreen(TwinCardsStep.CreateFirstWallet))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCreateFirstWalletState(state: TwinCardsState) {
|
||||
onboarding_twins_welcome_bg.hide()
|
||||
bg_circle_large.hide()
|
||||
bg_circle_medium.hide()
|
||||
bg_circle_min.hide()
|
||||
chb_understand.hide()
|
||||
pb_state.show()
|
||||
private fun setupCreateFirstWalletState(state: TwinCardsState) =
|
||||
with(binding.onboardingActionContainer) {
|
||||
binding.onboardingTopContainer.onboardingTwinsWelcomeBg.root.hide()
|
||||
binding.onboardingTopContainer.onboardingTwinsWelcomeBg.bgCircleLarge.hide()
|
||||
binding.onboardingTopContainer.onboardingTwinsWelcomeBg.bgCircleMedium.hide()
|
||||
binding.onboardingTopContainer.onboardingTwinsWelcomeBg.bgCircleMin.hide()
|
||||
chbUnderstand.hide()
|
||||
pbBinding.pbState.show()
|
||||
|
||||
onboarding_main_container.beginDelayedTransition()
|
||||
binding.onboardingTopContainer.onboardingMainContainer.beginDelayedTransition()
|
||||
|
||||
when (previousStep) {
|
||||
TwinCardsStep.None -> {
|
||||
twinsWidget.toLeapfrog(false) {
|
||||
when (state.cardNumber) {
|
||||
TwinCardNumber.First -> startPostponedEnterTransition()
|
||||
TwinCardNumber.Second -> {
|
||||
switchToCard(state.cardNumber, false) { startPostponedEnterTransition() }
|
||||
when (previousStep) {
|
||||
TwinCardsStep.None -> {
|
||||
twinsWidget.toLeapfrog(false) {
|
||||
when (state.cardNumber) {
|
||||
TwinCardNumber.First -> startPostponedEnterTransition()
|
||||
TwinCardNumber.Second -> {
|
||||
switchToCard(
|
||||
state.cardNumber,
|
||||
false
|
||||
) { startPostponedEnterTransition() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TwinCardsStep.Welcome, TwinCardsStep.Warning -> {
|
||||
twinsWidget.toLeapfrog(onEnd = { switchToCard(state.cardNumber) })
|
||||
}
|
||||
}
|
||||
TwinCardsStep.Welcome, TwinCardsStep.Warning -> {
|
||||
twinsWidget.toLeapfrog(onEnd = { switchToCard(state.cardNumber) })
|
||||
|
||||
val twinIndexNumber = state.cardNumber?.indexNumber()
|
||||
tvHeader.text = getString(R.string.twins_recreate_title_format, twinIndexNumber)
|
||||
tvBody.setText(R.string.onboarding_twins_interrupt_warning)
|
||||
|
||||
btnMainAction.text = getString(R.string.twins_recreate_button_format, twinIndexNumber)
|
||||
btnMainAction.setOnClickListener {
|
||||
store.dispatch(
|
||||
TwinCardsAction.Wallet.LaunchFirstStep(
|
||||
Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)),
|
||||
assetReader
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
btnAlternativeAction.isVisible = false
|
||||
btnAlternativeAction.isClickable = false
|
||||
}
|
||||
|
||||
private fun setupCreateSecondWalletState(state: TwinCardsState) =
|
||||
with(binding.onboardingActionContainer) {
|
||||
switchToCard(state.cardNumber?.pairNumber())
|
||||
|
||||
val twinPairIndexNumber = state.cardNumber?.pairIndexNumber()
|
||||
tvHeader.text = getString(R.string.twins_recreate_title_format, twinPairIndexNumber)
|
||||
tvBody.setText(R.string.onboarding_twins_interrupt_warning)
|
||||
|
||||
btnMainAction.text =
|
||||
getString(R.string.twins_recreate_button_format, twinPairIndexNumber)
|
||||
btnMainAction.setOnClickListener {
|
||||
store.dispatch(
|
||||
TwinCardsAction.Wallet.LaunchSecondStep(
|
||||
Message(
|
||||
getString(
|
||||
R.string.twins_recreate_title_format,
|
||||
twinPairIndexNumber
|
||||
)
|
||||
),
|
||||
Message(getString(R.string.twins_recreate_title_preparing)),
|
||||
Message(getString(R.string.twins_recreate_title_creating_wallet)),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val twinIndexNumber = state.cardNumber?.indexNumber()
|
||||
tv_header.text = getString(R.string.twins_recreate_title_format, twinIndexNumber)
|
||||
tv_body.setText(R.string.onboarding_twins_interrupt_warning)
|
||||
private fun setupCreateThirdWalletState(state: TwinCardsState) =
|
||||
with(binding.onboardingActionContainer) {
|
||||
switchToCard(state.cardNumber)
|
||||
|
||||
btn_main_action.text = getString(R.string.twins_recreate_button_format, twinIndexNumber)
|
||||
btn_main_action.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.Wallet.LaunchFirstStep(
|
||||
Message(getString(R.string.twins_recreate_title_format, twinIndexNumber)),
|
||||
assetReader
|
||||
))
|
||||
val twinIndexNumber = state.cardNumber?.indexNumber()
|
||||
tvHeader.text = getString(R.string.twins_recreate_title_format, twinIndexNumber)
|
||||
tvBody.setText(R.string.onboarding_twins_interrupt_warning)
|
||||
|
||||
btnMainAction.text = getString(R.string.twins_recreate_button_format, twinIndexNumber)
|
||||
btnMainAction.setOnClickListener {
|
||||
store.dispatch(
|
||||
TwinCardsAction.Wallet.LaunchThirdStep(
|
||||
Message(getString(R.string.twins_recreate_title_format, twinIndexNumber))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
btn_alternative_action.isVisible = false
|
||||
btn_alternative_action.isClickable = false
|
||||
}
|
||||
|
||||
private fun setupCreateSecondWalletState(state: TwinCardsState) {
|
||||
switchToCard(state.cardNumber?.pairNumber())
|
||||
|
||||
val twinPairIndexNumber = state.cardNumber?.pairIndexNumber()
|
||||
tv_header.text = getString(R.string.twins_recreate_title_format, twinPairIndexNumber)
|
||||
tv_body.setText(R.string.onboarding_twins_interrupt_warning)
|
||||
|
||||
btn_main_action.text = getString(R.string.twins_recreate_button_format, twinPairIndexNumber)
|
||||
btn_main_action.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.Wallet.LaunchSecondStep(
|
||||
Message(getString(R.string.twins_recreate_title_format, twinPairIndexNumber)),
|
||||
Message(getString(R.string.twins_recreate_title_preparing)),
|
||||
Message(getString(R.string.twins_recreate_title_creating_wallet)),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCreateThirdWalletState(state: TwinCardsState) {
|
||||
switchToCard(state.cardNumber)
|
||||
|
||||
val twinIndexNumber = state.cardNumber?.indexNumber()
|
||||
tv_header.text = getString(R.string.twins_recreate_title_format, twinIndexNumber)
|
||||
tv_body.setText(R.string.onboarding_twins_interrupt_warning)
|
||||
|
||||
btn_main_action.text = getString(R.string.twins_recreate_button_format, twinIndexNumber)
|
||||
btn_main_action.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.Wallet.LaunchThirdStep(
|
||||
Message(getString(R.string.twins_recreate_title_format, twinIndexNumber))
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setupTopUpWalletState(state: TwinCardsState) {
|
||||
when (previousStep) {
|
||||
TwinCardsStep.None -> {
|
||||
when (state.cardNumber) {
|
||||
TwinCardNumber.First -> {
|
||||
twinsWidget.leapfrogWidget.unfold(false) {
|
||||
twinsWidget.toActivate(false) {
|
||||
private fun setupTopUpWalletState(state: TwinCardsState) =
|
||||
with(binding.onboardingActionContainer) {
|
||||
when (previousStep) {
|
||||
TwinCardsStep.None -> {
|
||||
when (state.cardNumber) {
|
||||
TwinCardNumber.First -> {
|
||||
twinsWidget.leapfrogWidget.unfold(false) {
|
||||
twinsWidget.toActivate(false) {
|
||||
startPostponedEnterTransition()
|
||||
}
|
||||
}
|
||||
}
|
||||
TwinCardNumber.Second -> {
|
||||
switchToCard(state.cardNumber, false) {
|
||||
twinsWidget.toActivate(false)
|
||||
startPostponedEnterTransition()
|
||||
}
|
||||
}
|
||||
}
|
||||
TwinCardNumber.Second -> {
|
||||
switchToCard(state.cardNumber, false) {
|
||||
twinsWidget.toActivate(false)
|
||||
startPostponedEnterTransition()
|
||||
}
|
||||
}
|
||||
}
|
||||
TwinCardsStep.CreateThirdWallet -> {
|
||||
twinsWidget.toActivate()
|
||||
}
|
||||
}
|
||||
TwinCardsStep.CreateThirdWallet -> {
|
||||
twinsWidget.toActivate()
|
||||
}
|
||||
}
|
||||
|
||||
if (state.isBuyAllowed) {
|
||||
btn_main_action.setText(R.string.onboarding_top_up_button_but_crypto)
|
||||
btn_main_action.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.TopUp)
|
||||
if (state.isBuyAllowed) {
|
||||
btnMainAction.setText(R.string.onboarding_top_up_button_but_crypto)
|
||||
btnMainAction.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.TopUp)
|
||||
}
|
||||
|
||||
btnAlternativeAction.isVisible = true
|
||||
btnAlternativeAction.setText(R.string.onboarding_top_up_button_show_wallet_address)
|
||||
btnAlternativeAction.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.ShowAddressInfoDialog)
|
||||
}
|
||||
} else {
|
||||
btnAlternativeAction.setText(R.string.onboarding_button_receive_crypto)
|
||||
btnAlternativeAction.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.ShowAddressInfoDialog)
|
||||
}
|
||||
|
||||
btnAlternativeAction.isVisible = false
|
||||
}
|
||||
|
||||
btn_alternative_action.isVisible = true
|
||||
btn_alternative_action.setText(R.string.onboarding_top_up_button_show_wallet_address)
|
||||
btn_alternative_action.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.ShowAddressInfoDialog)
|
||||
tvHeader.setText(R.string.onboarding_top_up_header)
|
||||
tvBody.setText(R.string.onboarding_top_up_body)
|
||||
|
||||
btnRefreshBalanceWidget.changeState(state.walletBalance.state)
|
||||
if (btnRefreshBalanceWidget.isShowing != true) {
|
||||
btnRefreshBalanceWidget.mainView.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.Balance.Update)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
btn_main_action.setText(R.string.onboarding_button_receive_crypto)
|
||||
btn_main_action.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.ShowAddressInfoDialog)
|
||||
binding.onboardingTopContainer.imvCardBackground.setBackgroundDrawable(
|
||||
requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8)
|
||||
)
|
||||
updateConstraints(state.currentStep, R.layout.lp_onboarding_topup_wallet_twins)
|
||||
}
|
||||
|
||||
private fun setupDoneState(state: TwinCardsState) =
|
||||
with(binding.onboardingActionContainer) {
|
||||
btnMainAction.setText(R.string.onboarding_done_button_continue)
|
||||
btnMainAction.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.Confetti.Hide)
|
||||
store.dispatch(TwinCardsAction.Done)
|
||||
}
|
||||
|
||||
btn_alternative_action.isVisible = false
|
||||
}
|
||||
btnAlternativeAction.isVisible = false
|
||||
btnAlternativeAction.isClickable = false
|
||||
|
||||
tv_header.setText(R.string.onboarding_top_up_header)
|
||||
tv_body.setText(R.string.onboarding_top_up_body)
|
||||
tvHeader.setText(R.string.onboarding_done_header)
|
||||
tvBody.setText(R.string.onboarding_done_body)
|
||||
|
||||
btnRefreshBalanceWidget.changeState(state.walletBalance.state)
|
||||
if (btnRefreshBalanceWidget.isShowing != true) {
|
||||
btnRefreshBalanceWidget.mainView.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.Balance.Update)
|
||||
val layout = when (state.mode) {
|
||||
CreateTwinWalletMode.CreateWallet -> R.layout.lp_onboarding_done_activation_twins
|
||||
CreateTwinWalletMode.RecreateWallet -> R.layout.lp_onboarding_done
|
||||
}
|
||||
updateConstraints(state.currentStep, layout)
|
||||
}
|
||||
imv_card_background.setBackgroundDrawable(requireContext().getDrawableCompat(R.drawable.shape_rectangle_rounded_8))
|
||||
updateConstraints(state.currentStep, R.layout.lp_onboarding_topup_wallet_twins)
|
||||
}
|
||||
|
||||
private fun setupDoneState(state: TwinCardsState) {
|
||||
btn_main_action.setText(R.string.onboarding_done_button_continue)
|
||||
btn_main_action.setOnClickListener {
|
||||
store.dispatch(TwinCardsAction.Confetti.Hide)
|
||||
store.dispatch(TwinCardsAction.Done)
|
||||
}
|
||||
|
||||
btn_alternative_action.isVisible = false
|
||||
btn_alternative_action.isClickable = false
|
||||
|
||||
tv_header.setText(R.string.onboarding_done_header)
|
||||
tv_body.setText(R.string.onboarding_done_body)
|
||||
|
||||
val layout = when (state.mode) {
|
||||
CreateTwinWalletMode.CreateWallet -> R.layout.lp_onboarding_done_activation_twins
|
||||
CreateTwinWalletMode.RecreateWallet -> R.layout.lp_onboarding_done
|
||||
}
|
||||
updateConstraints(state.currentStep, layout)
|
||||
}
|
||||
|
||||
private fun updateConstraints(currentStep: TwinCardsStep, @LayoutRes layoutId: Int) {
|
||||
if (this.previousStep == currentStep) return
|
||||
|
||||
val constraintSet = ConstraintSet()
|
||||
constraintSet.clone(requireContext(), layoutId)
|
||||
constraintSet.applyTo(onboarding_main_container)
|
||||
val transition = InternalNoteLayoutTransition()
|
||||
transition.interpolator = OvershootInterpolator()
|
||||
TransitionManager.beginDelayedTransition(onboarding_main_container, transition)
|
||||
with(binding.onboardingTopContainer) {
|
||||
val constraintSet = ConstraintSet()
|
||||
constraintSet.clone(requireContext(), layoutId)
|
||||
constraintSet.applyTo(onboardingMainContainer)
|
||||
val transition = InternalNoteLayoutTransition()
|
||||
transition.interpolator = OvershootInterpolator()
|
||||
TransitionManager.beginDelayedTransition(onboardingMainContainer, transition)
|
||||
}
|
||||
}
|
||||
|
||||
private fun switchToCard(cardNumber: TwinCardNumber?, animate: Boolean = true, onEnd: VoidCallback = {}) {
|
||||
private fun switchToCard(
|
||||
cardNumber: TwinCardNumber?,
|
||||
animate: Boolean = true,
|
||||
onEnd: VoidCallback = {}
|
||||
) {
|
||||
val position = cardNumber?.number ?: return
|
||||
|
||||
if (twinsWidget.leapfrogWidget.getViewPositionByIndex(1) != position - 1) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import com.tangem.tap.common.analytics.AnalyticsEvent
|
|||
import com.tangem.tap.common.analytics.AnalyticsParam
|
||||
import com.tangem.tap.common.analytics.GetCardSourceParams
|
||||
import com.tangem.tap.common.extensions.dispatchOnMain
|
||||
import com.tangem.tap.common.extensions.dispatchOpenUrl
|
||||
import com.tangem.tap.common.extensions.withMainContext
|
||||
import com.tangem.tap.common.redux.AppState
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
|
|
@ -218,13 +217,11 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
}
|
||||
}
|
||||
is BackupAction.GoToShop -> {
|
||||
backupState.buyAdditionalCardsUrl?.let { url ->
|
||||
store.dispatchOpenUrl(url)
|
||||
store.state.globalState.analyticsHandlers?.triggerEvent(
|
||||
event = AnalyticsEvent.GET_CARD,
|
||||
params = mapOf(AnalyticsParam.SOURCE.param to GetCardSourceParams.ONBOARDING.param)
|
||||
)
|
||||
}
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.Shop))
|
||||
store.state.globalState.analyticsHandlers?.triggerEvent(
|
||||
event = AnalyticsEvent.GET_CARD,
|
||||
params = mapOf(AnalyticsParam.SOURCE.param to GetCardSourceParams.ONBOARDING.param)
|
||||
)
|
||||
}
|
||||
is BackupAction.FinishAddingBackupCards -> {
|
||||
if (backupService.addedBackupCardsCount == 1) {
|
||||
|
|
@ -236,9 +233,11 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
}
|
||||
is BackupAction.CheckAccessCode -> {
|
||||
if (action.accessCode.length < 4) {
|
||||
store.dispatch(BackupAction.SetAccessCodeError(
|
||||
AccessCodeError.CodeTooShort
|
||||
))
|
||||
store.dispatch(
|
||||
BackupAction.SetAccessCodeError(
|
||||
AccessCodeError.CodeTooShort
|
||||
)
|
||||
)
|
||||
} else {
|
||||
store.dispatch(BackupAction.SetAccessCodeError(null))
|
||||
store.dispatch(BackupAction.SaveFirstAccessCode(action.accessCode))
|
||||
|
|
@ -250,9 +249,11 @@ private fun handleBackupAction(appState: () -> AppState?, action: BackupAction)
|
|||
backupService.setAccessCode(action.accessCodeConfirmation)
|
||||
store.dispatch(BackupAction.PrepareToWritePrimaryCard)
|
||||
} else {
|
||||
store.dispatch(BackupAction.SetAccessCodeError(
|
||||
AccessCodeError.CodesDoNotMatch
|
||||
))
|
||||
store.dispatch(
|
||||
BackupAction.SetAccessCodeError(
|
||||
AccessCodeError.CodesDoNotMatch
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
is BackupAction.WritePrimaryCard -> {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,30 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.item_backup_info_adapter.view.*
|
||||
import com.tangem.wallet.databinding.ItemBackupInfoAdapterBinding
|
||||
|
||||
class BackupInfoAdapter : RecyclerView.Adapter<BackupInfoViewHolder>() {
|
||||
|
||||
private val data = backupInfoSnippets
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BackupInfoViewHolder =
|
||||
BackupInfoViewHolder(LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_backup_info_adapter, parent, false))
|
||||
BackupInfoViewHolder(
|
||||
ItemBackupInfoAdapterBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
)
|
||||
|
||||
override fun getItemCount(): Int = data.size
|
||||
|
||||
override fun onBindViewHolder(holder: BackupInfoViewHolder, position: Int) =
|
||||
holder.itemView.run {
|
||||
tv_header.text = getString(data[position].header)
|
||||
tv_body.text = getString(data[position].body)
|
||||
holder.binding.run {
|
||||
tvHeader.text = root.getString(data[position].header)
|
||||
tvBody.text = root.getString(data[position].body)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -51,4 +53,5 @@ private val backupInfoSnippets = listOf(
|
|||
|
||||
)
|
||||
|
||||
class BackupInfoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
|
||||
class BackupInfoViewHolder(val binding: ItemBackupInfoAdapterBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
|
@ -8,6 +8,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.transition.TransitionInflater
|
||||
import androidx.transition.TransitionManager
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.tabs.TabLayoutMediator
|
||||
import com.squareup.picasso.Picasso
|
||||
|
|
@ -23,11 +24,8 @@ import com.tangem.tap.features.onboarding.products.wallet.redux.*
|
|||
import com.tangem.tap.features.onboarding.products.wallet.ui.dialogs.AccessCodeDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_onboarding_wallet.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_buttons_add_cards.*
|
||||
import kotlinx.android.synthetic.main.layout_onboarding_buttons_common.*
|
||||
import kotlinx.android.synthetic.main.view_confetti.*
|
||||
import kotlinx.android.synthetic.main.view_onboarding_progress.*
|
||||
import com.tangem.wallet.databinding.FragmentOnboardingWalletBinding
|
||||
import com.tangem.wallet.databinding.ViewOnboardingProgressBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
||||
|
|
@ -35,6 +33,12 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
|
||||
private var accessCodeDialog: AccessCodeDialog? = null
|
||||
private lateinit var cardsWidget: WalletCardsWidget
|
||||
private val binding: FragmentOnboardingWalletBinding by viewBinding(
|
||||
FragmentOnboardingWalletBinding::bind
|
||||
)
|
||||
private val pbBinding: ViewOnboardingProgressBinding by viewBinding(
|
||||
ViewOnboardingProgressBinding::bind)
|
||||
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -56,19 +60,22 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
val leapfrogCalculator = PropertyCalculator(
|
||||
yTranslationFactor = 25f * deviceScaleFactor,
|
||||
)
|
||||
val leapfrog = LeapfrogWidget(fl_cards_container, leapfrogCalculator)
|
||||
val leapfrog = LeapfrogWidget(binding.flCardsContainer, leapfrogCalculator)
|
||||
cardsWidget = WalletCardsWidget(leapfrog, deviceScaleFactor) { 200f * deviceScaleFactor }
|
||||
startPostponedEnterTransition()
|
||||
|
||||
view_pager_backup_info.adapter = BackupInfoAdapter()
|
||||
TabLayoutMediator(tab_layout_backup_info, view_pager_backup_info) { tab, position ->
|
||||
binding.viewPagerBackupInfo.adapter = BackupInfoAdapter()
|
||||
TabLayoutMediator(
|
||||
binding.tabLayoutBackupInfo,
|
||||
binding.viewPagerBackupInfo
|
||||
) { tab, position ->
|
||||
//Some implementation
|
||||
}.attach()
|
||||
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(toolbar)
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
|
||||
|
||||
store.dispatch(OnboardingWalletAction.Init)
|
||||
toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
binding.toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
|
||||
store.dispatch(OnboardingWalletAction.LoadArtwork)
|
||||
|
||||
|
|
@ -90,16 +97,18 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
}
|
||||
|
||||
override fun newState(state: OnboardingWalletState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
requireActivity().invalidateOptionsMenu()
|
||||
|
||||
loadImageIntoImageView(state.cardArtworkUrl, imv_front_card)
|
||||
loadImageIntoImageView(state.cardArtworkUrl, imv_first_backup_card)
|
||||
loadImageIntoImageView(state.cardArtworkUrl, imv_second_backup_card)
|
||||
with(binding) {
|
||||
loadImageIntoImageView(state.cardArtworkUrl, imvFrontCard)
|
||||
loadImageIntoImageView(state.cardArtworkUrl, imvFirstBackupCard)
|
||||
loadImageIntoImageView(state.cardArtworkUrl, imvSecondBackupCard)
|
||||
}
|
||||
|
||||
pb_state.max = 6
|
||||
pb_state.progress = state.getProgressStep()
|
||||
pbBinding.pbState.max = 6
|
||||
pbBinding.pbState.progress = state.getProgressStep()
|
||||
|
||||
when (state.step) {
|
||||
OnboardingWalletStep.None -> {
|
||||
|
|
@ -120,15 +129,15 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
?.into(view)
|
||||
}
|
||||
|
||||
private fun setupCreateWalletState() {
|
||||
btn_main_action.setText(R.string.onboarding_create_wallet_button_create_wallet)
|
||||
btn_main_action.setOnClickListener { store.dispatch(OnboardingWalletAction.CreateWallet) }
|
||||
btn_alternative_action.hide()
|
||||
private fun setupCreateWalletState() = with(binding) {
|
||||
layoutButtonsCommon.btnMainAction.setText(R.string.onboarding_create_wallet_button_create_wallet)
|
||||
layoutButtonsCommon.btnMainAction.setOnClickListener { store.dispatch(OnboardingWalletAction.CreateWallet) }
|
||||
layoutButtonsCommon.btnAlternativeAction.hide()
|
||||
|
||||
toolbar.title = getText(R.string.onboarding_getting_started)
|
||||
|
||||
tv_header.setText(R.string.onboarding_create_wallet_header)
|
||||
tv_body.setText(R.string.onboarding_create_wallet_body)
|
||||
tvHeader.setText(R.string.onboarding_create_wallet_header)
|
||||
tvBody.setText(R.string.onboarding_create_wallet_body)
|
||||
|
||||
cardsWidget.toFolded(false) { startPostponedEnterTransition() }
|
||||
}
|
||||
|
|
@ -137,7 +146,7 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
private fun setBackupState(state: BackupState) {
|
||||
when (state.backupStep) {
|
||||
BackupStep.InitBackup -> showBackupIntro(state)
|
||||
BackupStep.ScanOriginCard -> showScanOriginCard(state)
|
||||
BackupStep.ScanOriginCard -> showScanOriginCard()
|
||||
BackupStep.AddBackupCards -> showAddBackupCards(state)
|
||||
BackupStep.SetAccessCode -> showSetAccessCode()
|
||||
BackupStep.EnterAccessCode -> showEnterAccessCode(state)
|
||||
|
|
@ -148,65 +157,70 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
}
|
||||
}
|
||||
|
||||
private fun showBackupIntro(state: BackupState) {
|
||||
imv_first_backup_card.show()
|
||||
imv_second_backup_card.show()
|
||||
private fun showBackupIntro(state: BackupState) = with(binding) {
|
||||
imvFirstBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
|
||||
cardsWidget.toWelcome()
|
||||
|
||||
tv_header.hide()
|
||||
tv_body.hide()
|
||||
view_pager_backup_info.show()
|
||||
tab_layout_backup_info.show()
|
||||
tvHeader.hide()
|
||||
tvBody.hide()
|
||||
viewPagerBackupInfo.show()
|
||||
tabLayoutBackupInfo.show()
|
||||
|
||||
with(layoutButtonsCommon) {
|
||||
btnMainAction.text = getText(R.string.onboarding_button_backup_now)
|
||||
btnAlternativeAction.text = getText(R.string.onboarding_button_skip_backup)
|
||||
btnAlternativeAction.show(state.canSkipBackup)
|
||||
btnMainAction.setOnClickListener { store.dispatch(BackupAction.StartBackup) }
|
||||
btnAlternativeAction.setOnClickListener { store.dispatch(BackupAction.DismissBackup) }
|
||||
}
|
||||
|
||||
btn_main_action.text = getText(R.string.onboarding_button_backup_now)
|
||||
btn_alternative_action.text = getText(R.string.onboarding_button_skip_backup)
|
||||
btn_alternative_action.show(state.canSkipBackup)
|
||||
btn_main_action.setOnClickListener { store.dispatch(BackupAction.StartBackup) }
|
||||
btn_alternative_action.setOnClickListener { store.dispatch(BackupAction.DismissBackup) }
|
||||
startPostponedEnterTransition()
|
||||
}
|
||||
|
||||
private fun showScanOriginCard(state: BackupState) {
|
||||
private fun showScanOriginCard() = with(binding) {
|
||||
prepareBackupView()
|
||||
|
||||
cardsWidget.toFolded()
|
||||
|
||||
tv_header.text = getText(R.string.onboarding_title_scan_origin_card)
|
||||
tv_body.text = getString(
|
||||
tvHeader.text = getText(R.string.onboarding_title_scan_origin_card)
|
||||
tvBody.text = getString(
|
||||
R.string.onboarding_subtitle_scan_origin_card,
|
||||
)
|
||||
|
||||
btn_main_action.text = getString(R.string.onboarding_button_scan_origin_card)
|
||||
btn_alternative_action.hide()
|
||||
btn_main_action.setOnClickListener { store.dispatch(BackupAction.ScanPrimaryCard) }
|
||||
with(layoutButtonsCommon) {
|
||||
btnMainAction.text = getString(R.string.onboarding_button_scan_origin_card)
|
||||
btnAlternativeAction.hide()
|
||||
btnMainAction.setOnClickListener { store.dispatch(BackupAction.ScanPrimaryCard) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun prepareBackupView() {
|
||||
private fun prepareBackupView() = with(binding) {
|
||||
toolbar.title = getText(R.string.onboarding_navbar_title_creating_backup)
|
||||
|
||||
tv_header.show()
|
||||
tv_body.show()
|
||||
view_pager_backup_info.hide()
|
||||
tab_layout_backup_info.hide()
|
||||
tvHeader.show()
|
||||
tvBody.show()
|
||||
viewPagerBackupInfo.hide()
|
||||
tabLayoutBackupInfo.hide()
|
||||
|
||||
imv_first_backup_card.show()
|
||||
imv_second_backup_card.show()
|
||||
imvSecondBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
}
|
||||
|
||||
private fun showAddBackupCards(state: BackupState) {
|
||||
private fun showAddBackupCards(state: BackupState) = with(binding) {
|
||||
prepareBackupView()
|
||||
|
||||
accessCodeDialog?.dismiss()
|
||||
accessCodeDialog = null
|
||||
|
||||
layout_buttons_add_cards.show()
|
||||
layout_buttons_common.hide()
|
||||
btn_add_card.text = getText(R.string.onboarding_button_add_backup_card)
|
||||
layoutButtonsAddCards.root.show()
|
||||
layoutButtonsCommon.root.hide()
|
||||
layoutButtonsAddCards.btnAddCard.text = getText(R.string.onboarding_button_add_backup_card)
|
||||
if (state.backupCardsNumber < state.maxBackupCards) {
|
||||
btn_add_card.setOnClickListener { store.dispatch(BackupAction.AddBackupCard) }
|
||||
layoutButtonsAddCards.btnAddCard.setOnClickListener { store.dispatch(BackupAction.AddBackupCard) }
|
||||
} else {
|
||||
btn_add_card.isEnabled = false
|
||||
layoutButtonsAddCards.btnAddCard.isEnabled = false
|
||||
}
|
||||
|
||||
when (state.backupCardsNumber) {
|
||||
|
|
@ -215,27 +229,27 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
cardsWidget.getFirstBackupCardView().animate().alpha(0.6f).setDuration(200)
|
||||
cardsWidget.getSecondBackupCardView().animate().alpha(0.2f).setDuration(200)
|
||||
}
|
||||
tv_header.text = getText(R.string.onboarding_title_no_backup_cards)
|
||||
tv_body.text = getText(R.string.onboarding_subtitle_no_backup_cards)
|
||||
tvHeader.text = getText(R.string.onboarding_title_no_backup_cards)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_no_backup_cards)
|
||||
}
|
||||
1 -> {
|
||||
tv_header.text = getText(R.string.onboarding_title_one_backup_card)
|
||||
tv_body.text = getText(R.string.onboarding_subtitle_one_backup_card)
|
||||
tvHeader.text = getText(R.string.onboarding_title_one_backup_card)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_one_backup_card)
|
||||
|
||||
cardsWidget.getFirstBackupCardView().animate().alpha(1f).setDuration(400)
|
||||
cardsWidget.getSecondBackupCardView().alpha = 0.2f
|
||||
}
|
||||
2 -> {
|
||||
tv_header.text = getText(R.string.onboarding_title_two_backup_cards)
|
||||
tv_body.text = getText(R.string.onboarding_subtitle_two_backup_cards)
|
||||
tvHeader.text = getText(R.string.onboarding_title_two_backup_cards)
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_two_backup_cards)
|
||||
cardsWidget.getFirstBackupCardView().alpha = 1f
|
||||
cardsWidget.getSecondBackupCardView().animate().alpha(1f).setDuration(400)
|
||||
}
|
||||
}
|
||||
|
||||
btn_continue.text = getText(R.string.onboarding_button_finalize_backup)
|
||||
btn_continue.setOnClickListener { store.dispatch(BackupAction.FinishAddingBackupCards) }
|
||||
btn_continue.isEnabled = state.backupCardsNumber != 0
|
||||
layoutButtonsAddCards.btnContinue.text = getText(R.string.onboarding_button_finalize_backup)
|
||||
layoutButtonsAddCards.btnContinue.setOnClickListener { store.dispatch(BackupAction.FinishAddingBackupCards) }
|
||||
layoutButtonsAddCards.btnContinue.isEnabled = state.backupCardsNumber != 0
|
||||
}
|
||||
|
||||
private fun showSetAccessCode() {
|
||||
|
|
@ -266,7 +280,7 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
accessCodeDialog?.showError(state.accessCodeError)
|
||||
}
|
||||
|
||||
private fun showWritePrimaryCard(state: BackupState) {
|
||||
private fun showWritePrimaryCard(state: BackupState) = with(binding) {
|
||||
accessCodeDialog?.dismiss()
|
||||
|
||||
prepareViewForFinalizeStep()
|
||||
|
|
@ -278,33 +292,33 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
}
|
||||
|
||||
val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4))
|
||||
tv_header.text = getText(R.string.onboarding_title_prepare_origin)
|
||||
tv_body.text = getString(
|
||||
tvHeader.text = getText(R.string.onboarding_title_prepare_origin)
|
||||
tvBody.text = getString(
|
||||
R.string.onboarding_subtitle_scan_primary_card_format,
|
||||
state.primaryCardId?.let { cardIdFormatter.getFormattedCardId(it) }
|
||||
)
|
||||
btn_main_action.text = getText(R.string.onboarding_button_backup_origin)
|
||||
btn_main_action.setOnClickListener { store.dispatch(BackupAction.WritePrimaryCard) }
|
||||
layoutButtonsCommon.btnMainAction.text = getText(R.string.onboarding_button_backup_origin)
|
||||
layoutButtonsCommon.btnMainAction.setOnClickListener { store.dispatch(BackupAction.WritePrimaryCard) }
|
||||
|
||||
}
|
||||
|
||||
private fun prepareViewForFinalizeStep() {
|
||||
layout_buttons_add_cards.hide()
|
||||
layout_buttons_common.show()
|
||||
private fun prepareViewForFinalizeStep() = with(binding) {
|
||||
layoutButtonsAddCards.root.hide()
|
||||
layoutButtonsCommon.root.show()
|
||||
|
||||
imv_first_backup_card.show()
|
||||
imv_second_backup_card.show()
|
||||
imvFirstBackupCard.show()
|
||||
imvSecondBackupCard.show()
|
||||
|
||||
toolbar.title = getText(R.string.onboarding_button_finalize_backup)
|
||||
|
||||
imv_card_background.hide()
|
||||
imvCardBackground.hide()
|
||||
|
||||
cardsWidget.toLeapfrog()
|
||||
|
||||
btn_alternative_action.hide()
|
||||
layoutButtonsCommon.btnAlternativeAction.hide()
|
||||
}
|
||||
|
||||
private fun showWriteBackupCard(state: BackupState) {
|
||||
private fun showWriteBackupCard(state: BackupState) = with(binding) {
|
||||
prepareViewForFinalizeStep()
|
||||
|
||||
cardsWidget.getSecondBackupCardView().show(state.backupCardsNumber == 2)
|
||||
|
|
@ -324,46 +338,47 @@ class OnboardingWalletFragment : Fragment(R.layout.fragment_onboarding_wallet),
|
|||
}
|
||||
|
||||
val cardIdFormatter = CardIdFormatter(CardIdDisplayFormat.LastMasked(4))
|
||||
tv_header.text =
|
||||
tvHeader.text =
|
||||
getString(R.string.onboarding_title_backup_card_format, cardNumber)
|
||||
tv_body.text = getString(
|
||||
tvBody.text = getString(
|
||||
R.string.onboarding_subtitle_scan_backup_card_format,
|
||||
cardIdFormatter.getFormattedCardId(state.backupCardIds[cardNumber - 1])
|
||||
)
|
||||
btn_main_action.text = getString(
|
||||
layoutButtonsCommon.btnMainAction.text = getString(
|
||||
R.string.onboarding_button_backup_card_format,
|
||||
cardNumber
|
||||
)
|
||||
|
||||
btn_main_action.setOnClickListener { store.dispatch(BackupAction.WriteBackupCard(cardNumber)) }
|
||||
layoutButtonsCommon.btnMainAction.setOnClickListener {
|
||||
store.dispatch(BackupAction.WriteBackupCard(cardNumber))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showSuccess() {
|
||||
tv_header.text = getText(R.string.onboarding_done_header)
|
||||
private fun showSuccess() = with(binding) {
|
||||
tvHeader.text = getText(R.string.onboarding_done_header)
|
||||
|
||||
tv_header.show()
|
||||
tv_body.show()
|
||||
view_pager_backup_info.hide()
|
||||
tab_layout_backup_info.hide()
|
||||
tvHeader.show()
|
||||
tvBody.show()
|
||||
viewPagerBackupInfo.hide()
|
||||
tabLayoutBackupInfo.hide()
|
||||
|
||||
tv_body.text = getText(R.string.onboarding_subtitle_success_tangem_wallet_onboarding)
|
||||
btn_main_action.text = getText(R.string.onboarding_button_continue_wallet)
|
||||
btn_alternative_action.hide()
|
||||
btn_main_action.setOnClickListener {
|
||||
lav_confetti.cancelAnimation()
|
||||
lav_confetti.hide()
|
||||
tvBody.text = getText(R.string.onboarding_subtitle_success_tangem_wallet_onboarding)
|
||||
layoutButtonsCommon.btnMainAction.text = getText(R.string.onboarding_button_continue_wallet)
|
||||
layoutButtonsCommon.btnAlternativeAction.hide()
|
||||
layoutButtonsCommon.btnMainAction.setOnClickListener {
|
||||
vConfetti.lavConfetti.cancelAnimation()
|
||||
vConfetti.lavConfetti.hide()
|
||||
store.dispatch(OnboardingWalletAction.FinishOnboarding)
|
||||
}
|
||||
|
||||
cardsWidget.leapfrogWidget.fold {
|
||||
fl_cards_container?.hide()
|
||||
imv_card_background?.hide()
|
||||
lav_confetti?.show()
|
||||
lav_confetti?.playAnimation()
|
||||
imv_success?.alpha = 0f
|
||||
imv_success?.show()
|
||||
flCardsContainer.hide()
|
||||
imvCardBackground.hide()
|
||||
vConfetti.lavConfetti.show()
|
||||
vConfetti.lavConfetti.playAnimation()
|
||||
imvSuccess.alpha = 0f
|
||||
imvSuccess.show()
|
||||
|
||||
imv_success?.animate()
|
||||
imvSuccess.animate()
|
||||
?.alpha(1f)
|
||||
?.setDuration(400)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.tangem.tap.features.onboarding.products.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
|
|
@ -11,64 +12,69 @@ import com.tangem.tap.features.onboarding.products.wallet.redux.AccessCodeError
|
|||
import com.tangem.tap.features.onboarding.products.wallet.redux.BackupAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.layout_backup_access_code.*
|
||||
import kotlinx.android.synthetic.main.layout_backup_access_code_info.*
|
||||
import kotlinx.android.synthetic.main.layout_backup_access_code_submit.*
|
||||
import com.tangem.wallet.databinding.LayoutBackupAccessCodeBinding
|
||||
|
||||
class AccessCodeDialog(context: Context) : BottomSheetDialog(context) {
|
||||
|
||||
var binding: LayoutBackupAccessCodeBinding? = null
|
||||
|
||||
init {
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
val dialogView = LayoutInflater.from(context).inflate(R.layout.layout_backup_access_code, null)
|
||||
setContentView(dialogView)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = LayoutBackupAccessCodeBinding
|
||||
.inflate(LayoutInflater.from(context))
|
||||
setContentView(binding!!.root)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
override fun setContentView(view: View) {
|
||||
super.setContentView(view)
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
override fun setOnDismissListener(listener: DialogInterface.OnDismissListener?) {
|
||||
super.setOnDismissListener(listener)
|
||||
binding = null
|
||||
}
|
||||
|
||||
|
||||
fun showInfoScreen() {
|
||||
fun showInfoScreen() = with(binding!!) {
|
||||
behavior.state = BottomSheetBehavior.STATE_EXPANDED
|
||||
access_code_title.text = context.getText(R.string.onboarding_access_code_intro_title)
|
||||
layout_backup_access_code_info.show()
|
||||
layout_backup_access_code_submit.hide()
|
||||
btn_access_code_create.setOnClickListener {
|
||||
accessCodeTitle.text = context.getText(R.string.onboarding_access_code_intro_title)
|
||||
layoutBackupAccessCodeInfo.root.show()
|
||||
layoutBackupAccessCodeSubmit.root.hide()
|
||||
layoutBackupAccessCodeInfo.btnAccessCodeCreate.setOnClickListener {
|
||||
store.dispatch(BackupAction.ShowEnterAccessCodeScreen)
|
||||
}
|
||||
}
|
||||
|
||||
fun showEnterAccessCode() {
|
||||
layout_backup_access_code_info.hide()
|
||||
layout_backup_access_code_submit.show()
|
||||
access_code_title.text = context.getText(R.string.onboarding_access_code_intro_title)
|
||||
btn_access_code_submit.text = context.getText(R.string.common_continue)
|
||||
btn_access_code_submit.setOnClickListener {
|
||||
store.dispatch(BackupAction.CheckAccessCode(et_access_code.text.toString()))
|
||||
fun showEnterAccessCode() = with(binding!!) {
|
||||
layoutBackupAccessCodeInfo.root.hide()
|
||||
layoutBackupAccessCodeSubmit.root.show()
|
||||
accessCodeTitle.text = context.getText(R.string.onboarding_access_code_intro_title)
|
||||
|
||||
with(layoutBackupAccessCodeSubmit) {
|
||||
btnAccessCodeSubmit.text = context.getText(R.string.common_continue)
|
||||
btnAccessCodeSubmit.setOnClickListener {
|
||||
store.dispatch(BackupAction.CheckAccessCode(etAccessCode.text.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun showReenterAccessCode() {
|
||||
layout_backup_access_code_info.hide()
|
||||
layout_backup_access_code_submit.show()
|
||||
access_code_title.text = context.getText(R.string.onboarding_access_code_repeat_code_title)
|
||||
et_access_code.setText("")
|
||||
btn_access_code_submit.text = context.getText(R.string.common_submit)
|
||||
btn_access_code_submit.setOnClickListener {
|
||||
store.dispatch(BackupAction.SaveAccessCodeConfirmation(et_access_code.text.toString()))
|
||||
fun showReenterAccessCode() = with(binding!!) {
|
||||
layoutBackupAccessCodeInfo.root.hide()
|
||||
layoutBackupAccessCodeSubmit.root.show()
|
||||
accessCodeTitle.text = context.getText(R.string.onboarding_access_code_repeat_code_title)
|
||||
with(layoutBackupAccessCodeSubmit) {
|
||||
etAccessCode.setText("")
|
||||
btnAccessCodeSubmit.text = context.getText(R.string.common_submit)
|
||||
btnAccessCodeSubmit.setOnClickListener {
|
||||
store.dispatch(BackupAction.SaveAccessCodeConfirmation(etAccessCode.text.toString()))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun showError(error: AccessCodeError?) {
|
||||
fun showError(error: AccessCodeError?) = with(binding!!.layoutBackupAccessCodeSubmit) {
|
||||
when (error) {
|
||||
AccessCodeError.CodeTooShort ->
|
||||
til_access_code.error = context.getString(R.string.onboarding_access_code_too_short)
|
||||
tilAccessCode.error = context.getString(R.string.onboarding_access_code_too_short)
|
||||
AccessCodeError.CodesDoNotMatch ->
|
||||
til_access_code.error = context.getString(R.string.onboarding_access_codes_doesnt_match)
|
||||
null -> til_access_code.error = null
|
||||
tilAccessCode.error = context.getString(R.string.onboarding_access_codes_doesnt_match)
|
||||
null -> tilAccessCode.error = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import androidx.core.view.postDelayed
|
|||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.tangem.Message
|
||||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
|
|
@ -40,10 +41,7 @@ import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter
|
|||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_send.*
|
||||
import kotlinx.android.synthetic.main.layout_send_address_payid.*
|
||||
import kotlinx.android.synthetic.main.layout_send_amount.*
|
||||
import kotlinx.android.synthetic.main.layout_send_fee.*
|
||||
import com.tangem.wallet.databinding.FragmentSendBinding
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.*
|
||||
|
|
@ -62,6 +60,8 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
private val sendSubscriber = SendStateSubscriber(this)
|
||||
private lateinit var keyboardObserver: KeyboardObserver
|
||||
|
||||
val binding: FragmentSendBinding by viewBinding(FragmentSendBinding::bind)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
addBackPressHandler(this)
|
||||
|
|
@ -77,7 +77,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
store.dispatch(SendActionUi.CheckIfTransactionDataWasProvided)
|
||||
}
|
||||
|
||||
private fun initSendButtonStates() {
|
||||
private fun initSendButtonStates() = with(binding) {
|
||||
btnSend.setOnClickListener {
|
||||
store.dispatch(SendActionUi.SendAmountToRecipient(
|
||||
Message(getString(R.string.initial_message_sign_header))
|
||||
|
|
@ -86,7 +86,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
sendBtn = IndeterminateProgressButtonWidget(btnSend, progress)
|
||||
}
|
||||
|
||||
private fun setupAddressOrPayIdLayout() {
|
||||
private fun setupAddressOrPayIdLayout() = with(binding.lSendAddressPayid) {
|
||||
store.dispatch(SetTruncateHandler { etAddressOrPayId.truncateMiddleWith(it, "...") })
|
||||
store.dispatch(CheckClipboard(requireContext().getFromClipboard()?.toString()))
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupTransactionExtrasLayout() {
|
||||
private fun setupTransactionExtrasLayout() = with(binding.lSendAddressPayid) {
|
||||
etXlmMemo.inputtedTextAsFlow()
|
||||
.debounce(400)
|
||||
.filter {
|
||||
|
|
@ -151,9 +151,9 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
// Delayed launch is needed in order for the UI to be drawn and to process the sent events.
|
||||
// If do not use the delay, then etAmount error field is not displayed when
|
||||
// inserting an incorrect amount by shareUri
|
||||
imvQrCode.postDelayed({
|
||||
binding.lSendAddressPayid.imvQrCode.postDelayed({
|
||||
store.dispatch(PasteAddressPayId(scannedCode))
|
||||
store.dispatch(TruncateOrRestore(!etAddressOrPayId.isFocused))
|
||||
store.dispatch(TruncateOrRestore(!binding.lSendAddressPayid.etAddressOrPayId.isFocused))
|
||||
}, 200)
|
||||
}
|
||||
|
||||
|
|
@ -165,7 +165,7 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
val decimalSeparator = DecimalFormatSymbols.getInstance().decimalSeparator.toString()
|
||||
store.dispatch(AmountAction.SetDecimalSeparator(decimalSeparator))
|
||||
|
||||
tvAmountCurrency.setOnClickListener {
|
||||
binding.lSendAmount.tvAmountCurrency.setOnClickListener {
|
||||
store.dispatch(ToggleMainCurrency)
|
||||
store.dispatch(ReceiptAction.RefreshReceipt)
|
||||
store.dispatch(SendAction.ChangeSendButtonState(store.state.sendState.getButtonState()))
|
||||
|
|
@ -223,8 +223,8 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupFeeLayout() {
|
||||
flExpandCollapse.setOnClickListener {
|
||||
private fun setupFeeLayout() = with(binding.clNetworkFee) {
|
||||
flExpandCollapse.flExpandCollapse.setOnClickListener {
|
||||
store.dispatch(ToggleControlsVisibility)
|
||||
}
|
||||
chipGroup.check(FeeUiHelper.toId(FeeType.NORMAL))
|
||||
|
|
@ -240,12 +240,12 @@ class SendFragment : BaseStoreFragment(R.layout.fragment_send) {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupWarningMessages() {
|
||||
private fun setupWarningMessages() = with(binding) {
|
||||
warningsAdapter = WarningMessagesAdapter()
|
||||
val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
|
||||
rv_warning_messages.layoutManager = layoutManager
|
||||
rv_warning_messages.addItemDecoration(SpacesItemDecoration(rv_warning_messages.dpToPx(16f).toInt()))
|
||||
rv_warning_messages.adapter = warningsAdapter
|
||||
rvWarningMessages.layoutManager = layoutManager
|
||||
rvWarningMessages.addItemDecoration(SpacesItemDecoration(rvWarningMessages.dpToPx(16f).toInt()))
|
||||
rvWarningMessages.adapter = warningsAdapter
|
||||
|
||||
store.dispatch(SendAction.Warnings.Update)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,32 +26,30 @@ import com.tangem.tap.features.send.ui.dialogs.TezosWarningDialog
|
|||
import com.tangem.tap.features.wallet.ui.adapters.WarningMessagesAdapter
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.btn_expand_collapse.*
|
||||
import kotlinx.android.synthetic.main.fragment_send.*
|
||||
import kotlinx.android.synthetic.main.fragment_send.clReceiptContainer
|
||||
import kotlinx.android.synthetic.main.layout_receipt_total.*
|
||||
import kotlinx.android.synthetic.main.layout_receipt_total.view.*
|
||||
import kotlinx.android.synthetic.main.layout_send_address_payid.*
|
||||
import kotlinx.android.synthetic.main.layout_send_amount.*
|
||||
import kotlinx.android.synthetic.main.layout_send_fee.*
|
||||
import kotlinx.android.synthetic.main.layout_send_receipt.*
|
||||
|
||||
/**
|
||||
[REDACTED_AUTHOR]
|
||||
*/
|
||||
class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber<SendState>(fragment) {
|
||||
class SendStateSubscriber(fragment: BaseStoreFragment) :
|
||||
FragmentStateSubscriber<SendState>(fragment) {
|
||||
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
override fun updateWithNewState(fg: BaseStoreFragment, state: SendState) {
|
||||
fg.view ?: return
|
||||
if (fg !is SendFragment) return
|
||||
|
||||
val lastChangedStates = state.lastChangedStates.toList()
|
||||
state.lastChangedStates.clear()
|
||||
fg.main_send_container.beginDelayedTransition()
|
||||
(fg as? SendFragment)?.binding?.mainSendContainer?.beginDelayedTransition()
|
||||
lastChangedStates.forEach {
|
||||
when (it) {
|
||||
StateId.SEND_SCREEN -> handleSendScreen(fg, state)
|
||||
StateId.ADDRESS_PAY_ID -> handleAddressPayIdState(fg, state.addressPayIdState)
|
||||
StateId.TRANSACTION_EXTRAS -> handleTransactionExtrasState(fg, state.transactionExtrasState)
|
||||
StateId.TRANSACTION_EXTRAS -> handleTransactionExtrasState(
|
||||
fg,
|
||||
state.transactionExtrasState
|
||||
)
|
||||
StateId.AMOUNT -> handleAmountState(fg, state.amountState)
|
||||
StateId.FEE -> handleFeeState(fg, state.feeState)
|
||||
StateId.RECEIPT -> handleReceiptState(fg, state.receiptState)
|
||||
|
|
@ -59,57 +57,58 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleTransactionExtrasState(fg: BaseStoreFragment, infoState: TransactionExtrasState) {
|
||||
fun showView(view: View, info: Any?) {
|
||||
view.show(info != null)
|
||||
}
|
||||
showView(fg.xlmMemoContainer, infoState.xlmMemo)
|
||||
showView(fg.xrpDestinationTagContainer, infoState.xrpDestinationTag)
|
||||
showView(fg.binanceMemoContainer, infoState.binanceMemo)
|
||||
private fun handleTransactionExtrasState(fg: SendFragment, infoState: TransactionExtrasState) =
|
||||
with(fg.binding.lSendAddressPayid) {
|
||||
|
||||
infoState.xlmMemo?.let {
|
||||
fg.etXlmMemo.inputType = when (it.selectedMemoType) {
|
||||
XlmMemoType.TEXT -> InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||
XlmMemoType.ID -> InputType.TYPE_CLASS_NUMBER
|
||||
fun showView(view: View, info: Any?) {
|
||||
view.show(info != null)
|
||||
}
|
||||
if (!it.viewFieldValue.isFromUserInput) fg.etXlmMemo.setText(it.viewFieldValue.value)
|
||||
if (it.error != null) {
|
||||
if (it.error == TransactionExtraError.INVALID_XLM_MEMO) {
|
||||
fg.tilXlmMemo.error = fg.getText(R.string.send_error_invalid_memo_id)
|
||||
}
|
||||
} else {
|
||||
fg.tilXlmMemo.error = null
|
||||
}
|
||||
}
|
||||
infoState.xrpDestinationTag?.let {
|
||||
if (infoState.xrpDestinationTag.error != null) {
|
||||
if (infoState.xrpDestinationTag.error == TransactionExtraError.INVALID_DESTINATION_TAG) {
|
||||
fg.tilDestinationTag.error = fg.getText(R.string.send_error_invalid_destination_tag)
|
||||
}
|
||||
} else {
|
||||
fg.tilDestinationTag.error = null
|
||||
}
|
||||
if (!it.viewFieldValue.isFromUserInput) {
|
||||
fg.etDestinationTag.setText(it.viewFieldValue.value)
|
||||
}
|
||||
}
|
||||
infoState.binanceMemo?.let {
|
||||
if (infoState.binanceMemo.error != null) {
|
||||
if (infoState.binanceMemo.error == TransactionExtraError.INVALID_BINANCE_MEMO) {
|
||||
fg.tilBinanceMemo.error = fg.getText(R.string.send_error_invalid_memo_id)
|
||||
}
|
||||
} else {
|
||||
fg.tilBinanceMemo.error = null
|
||||
}
|
||||
if (!it.viewFieldValue.isFromUserInput) {
|
||||
fg.etBinanceMemo.setText(it.viewFieldValue.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
showView(xlmMemoContainer, infoState.xlmMemo)
|
||||
showView(xrpDestinationTagContainer, infoState.xrpDestinationTag)
|
||||
showView(binanceMemoContainer, infoState.binanceMemo)
|
||||
|
||||
private fun handleSendScreen(fg: BaseStoreFragment, state: SendState) {
|
||||
val sendFragment = (fg as? SendFragment) ?: return
|
||||
infoState.xlmMemo?.let {
|
||||
etXlmMemo.inputType = when (it.selectedMemoType) {
|
||||
XlmMemoType.TEXT -> InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||
XlmMemoType.ID -> InputType.TYPE_CLASS_NUMBER
|
||||
}
|
||||
if (!it.viewFieldValue.isFromUserInput) etXlmMemo.setText(it.viewFieldValue.value)
|
||||
if (it.error != null) {
|
||||
if (it.error == TransactionExtraError.INVALID_XLM_MEMO) {
|
||||
tilXlmMemo.error = fg.getText(R.string.send_error_invalid_memo_id)
|
||||
}
|
||||
} else {
|
||||
tilXlmMemo.error = null
|
||||
}
|
||||
}
|
||||
infoState.xrpDestinationTag?.let {
|
||||
if (infoState.xrpDestinationTag.error != null) {
|
||||
if (infoState.xrpDestinationTag.error == TransactionExtraError.INVALID_DESTINATION_TAG) {
|
||||
tilDestinationTag.error =
|
||||
fg.getText(R.string.send_error_invalid_destination_tag)
|
||||
}
|
||||
} else {
|
||||
tilDestinationTag.error = null
|
||||
}
|
||||
if (!it.viewFieldValue.isFromUserInput) {
|
||||
etDestinationTag.setText(it.viewFieldValue.value)
|
||||
}
|
||||
}
|
||||
infoState.binanceMemo?.let {
|
||||
if (infoState.binanceMemo.error != null) {
|
||||
if (infoState.binanceMemo.error == TransactionExtraError.INVALID_BINANCE_MEMO) {
|
||||
tilBinanceMemo.error = fg.getText(R.string.send_error_invalid_memo_id)
|
||||
}
|
||||
} else {
|
||||
tilBinanceMemo.error = null
|
||||
}
|
||||
if (!it.viewFieldValue.isFromUserInput) {
|
||||
etBinanceMemo.setText(it.viewFieldValue.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleSendScreen(fg: SendFragment, state: SendState) = with(fg.binding) {
|
||||
when (state.dialog) {
|
||||
is SendAction.Dialog.TezosWarningDialog -> {
|
||||
if (dialog == null) {
|
||||
|
|
@ -129,147 +128,158 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
}
|
||||
}
|
||||
|
||||
sendFragment.sendBtn.changeState(state.sendButtonState.progressState)
|
||||
sendFragment.sendBtn.mainView.isEnabled = state.sendButtonState.enabled
|
||||
fg.sendBtn.changeState(state.sendButtonState.progressState)
|
||||
fg.sendBtn.mainView.isEnabled = state.sendButtonState.enabled
|
||||
|
||||
val rv = fg.rv_warning_messages
|
||||
val rv = rvWarningMessages
|
||||
val adapter = rv.adapter as? WarningMessagesAdapter ?: return
|
||||
|
||||
adapter.submitList(state.sendWarningsList)
|
||||
rv.show(state.sendWarningsList.isNotEmpty())
|
||||
|
||||
fg.toolbar.title = fg.getString(
|
||||
toolbar.title = fg.getString(
|
||||
R.string.send_title_currency_format,
|
||||
state.amountState.mainCurrency.currencySymbol
|
||||
)
|
||||
}
|
||||
|
||||
private fun handleAddressPayIdState(fg: BaseStoreFragment, state: AddressPayIdState) {
|
||||
fun parseError(context: Context, error: Error?): String? {
|
||||
val resId = when (error) {
|
||||
Error.PAY_ID_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.send_error_payid_unsupported_by_blockchain
|
||||
Error.PAY_ID_NOT_REGISTERED -> R.string.send_error_payid_not_registered
|
||||
Error.PAY_ID_REQUEST_FAILED -> R.string.send_error_payid_request_failed
|
||||
Error.ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.send_validation_invalid_address
|
||||
Error.ADDRESS_SAME_AS_WALLET -> R.string.send_error_address_same_as_wallet
|
||||
else -> null
|
||||
private fun handleAddressPayIdState(fg: SendFragment, state: AddressPayIdState) =
|
||||
with(fg.binding.lSendAddressPayid) {
|
||||
fun parseError(context: Context, error: Error?): String? {
|
||||
val resId = when (error) {
|
||||
Error.PAY_ID_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.send_error_payid_unsupported_by_blockchain
|
||||
Error.PAY_ID_NOT_REGISTERED -> R.string.send_error_payid_not_registered
|
||||
Error.PAY_ID_REQUEST_FAILED -> R.string.send_error_payid_request_failed
|
||||
Error.ADDRESS_INVALID_OR_UNSUPPORTED_BY_BLOCKCHAIN -> R.string.send_validation_invalid_address
|
||||
Error.ADDRESS_SAME_AS_WALLET -> R.string.send_error_address_same_as_wallet
|
||||
else -> null
|
||||
}
|
||||
return if (resId == null) null else context.getString(resId, "", "")
|
||||
}
|
||||
return if (resId == null) null else context.getString(resId, "", "")
|
||||
|
||||
imvPaste.isEnabled = state.pasteIsEnabled
|
||||
|
||||
val et = etAddressOrPayId
|
||||
val til = tilAddressOrPayId
|
||||
val parsedError = parseError(til.context, state.error)
|
||||
|
||||
til.isEnabled = state.inputIsEnabled
|
||||
imvPaste.show(state.inputIsEnabled)
|
||||
imvQrCode.show(state.inputIsEnabled)
|
||||
flPaste.show(state.inputIsEnabled)
|
||||
flQrCode.show(state.inputIsEnabled)
|
||||
|
||||
val hintResId = if (state.sendingToPayIdEnabled) {
|
||||
R.string.send_destination_hint_address_payid
|
||||
} else {
|
||||
R.string.send_destination_hint_address
|
||||
}
|
||||
til.hint = til.getString(hintResId)
|
||||
til.error = parsedError
|
||||
til.isErrorEnabled = parsedError != null
|
||||
til.helperText = state.destinationWalletAddress
|
||||
til.isHelperTextEnabled = state.isPayIdState() && parsedError == null
|
||||
|
||||
if (!state.viewFieldValue.isFromUserInput) et.update(state.viewFieldValue.value)
|
||||
}
|
||||
fg.imvPaste.isEnabled = state.pasteIsEnabled
|
||||
|
||||
val et = fg.etAddressOrPayId
|
||||
val til = fg.tilAddressOrPayId
|
||||
val parsedError = parseError(til.context, state.error)
|
||||
|
||||
til.isEnabled = state.inputIsEnabled
|
||||
fg.imvPaste.show(state.inputIsEnabled)
|
||||
fg.imvQrCode.show(state.inputIsEnabled)
|
||||
fg.flPaste.show(state.inputIsEnabled)
|
||||
fg.flQrCode.show(state.inputIsEnabled)
|
||||
|
||||
val hintResId = if (state.sendingToPayIdEnabled) {
|
||||
R.string.send_destination_hint_address_payid
|
||||
} else {
|
||||
R.string.send_destination_hint_address
|
||||
}
|
||||
til.hint = til.getString(hintResId)
|
||||
til.error = parsedError
|
||||
til.isErrorEnabled = parsedError != null
|
||||
til.helperText = state.destinationWalletAddress
|
||||
til.isHelperTextEnabled = state.isPayIdState() && parsedError == null
|
||||
|
||||
if (!state.viewFieldValue.isFromUserInput) et.update(state.viewFieldValue.value)
|
||||
}
|
||||
|
||||
private fun handleAmountState(fg: BaseStoreFragment, state: AmountState) {
|
||||
private fun handleAmountState(fg: SendFragment, state: AmountState) = with(fg.binding.lSendAmount) {
|
||||
if (state.error != null) {
|
||||
val context = fg.requireContext()
|
||||
val message = when (state.error) {
|
||||
is MultiMessageError -> {
|
||||
val multiError = state.error as MultiMessageError
|
||||
val messageList = multiError.assembleErrors().map { getMessageString(context, it.first, it.second) }
|
||||
val messageList = multiError.assembleErrors()
|
||||
.map { getMessageString(context, it.first, it.second) }
|
||||
multiError.builder(messageList)
|
||||
}
|
||||
else -> context.getString(state.error.messageResource)
|
||||
}
|
||||
fg.tilAmountToSend.enableError(true, message)
|
||||
tilAmountToSend.enableError(true, message)
|
||||
} else {
|
||||
fg.tilAmountToSend.enableError(false)
|
||||
tilAmountToSend.enableError(false)
|
||||
}
|
||||
|
||||
val filter = DecimalDigitsInputFilter(12, state.maxLengthOfAmount, state.decimalSeparator)
|
||||
fg.etAmountToSend.filters = arrayOf(filter)
|
||||
etAmountToSend.filters = arrayOf(filter)
|
||||
val amountToSend = state.viewAmountValue
|
||||
if (!amountToSend.isFromUserInput) fg.etAmountToSend.update(amountToSend.value)
|
||||
if (!amountToSend.isFromUserInput) etAmountToSend.update(amountToSend.value)
|
||||
|
||||
fg.tvAmountCurrency.update(state.mainCurrency.currencySymbol)
|
||||
tvAmountCurrency.update(state.mainCurrency.currencySymbol)
|
||||
(fg as? SendFragment)?.saveMainCurrency(state.mainCurrency.type)
|
||||
|
||||
val balanceText = when (state.mainCurrency.type) {
|
||||
MainCurrencyType.FIAT -> fg.getString(R.string.send_balance_subtitle_format,
|
||||
state.viewBalanceValue, state.mainCurrency.currencySymbol).remove(":")
|
||||
MainCurrencyType.CRYPTO -> fg.getString(R.string.send_balance_subtitle_format,
|
||||
state.mainCurrency.currencySymbol, state.viewBalanceValue)
|
||||
MainCurrencyType.FIAT -> fg.getString(
|
||||
R.string.send_balance_subtitle_format,
|
||||
state.viewBalanceValue, state.mainCurrency.currencySymbol
|
||||
).remove(":")
|
||||
MainCurrencyType.CRYPTO -> fg.getString(
|
||||
R.string.send_balance_subtitle_format,
|
||||
state.mainCurrency.currencySymbol, state.viewBalanceValue
|
||||
)
|
||||
}
|
||||
|
||||
fg.tvBalance.update(balanceText)
|
||||
tvBalance.update(balanceText)
|
||||
|
||||
fg.tilAmountToSend.isEnabled = state.inputIsEnabled
|
||||
tilAmountToSend.isEnabled = state.inputIsEnabled
|
||||
|
||||
val imageRes = if (state.inputIsEnabled) R.drawable.ic_arrows_up_down else 0
|
||||
fg.tvAmountCurrency.setCompoundDrawablesWithIntrinsicBounds(0, 0, imageRes, 0)
|
||||
tvAmountCurrency.setCompoundDrawablesWithIntrinsicBounds(0, 0, imageRes, 0)
|
||||
val textColor = if (state.inputIsEnabled) R.color.blue else R.color.textGray
|
||||
fg.tvAmountCurrency.setTextColor(fg.getColor(textColor))
|
||||
|
||||
tvAmountCurrency.setTextColor(fg.getColor(textColor))
|
||||
}
|
||||
|
||||
private fun handleFeeState(fg: BaseStoreFragment, state: FeeState) {
|
||||
fg.chipGroup.fitChipsByGroupWidth()
|
||||
private fun handleFeeState(fg: SendFragment, state: FeeState) = with(fg.binding.clNetworkFee) {
|
||||
chipGroup.fitChipsByGroupWidth()
|
||||
fg.view?.findViewById<ViewGroup>(R.id.clNetworkFee)?.show(state.mainLayoutIsVisible)
|
||||
flExpandCollapse.imvExpandCollapse.rotation = if (state.controlsLayoutIsVisible) 0f else 180f
|
||||
llFeeControlsContainer.show(state.controlsLayoutIsVisible)
|
||||
chipGroup.show(state.feeChipGroupIsVisible)
|
||||
|
||||
fg.imvExpandCollapse.rotation = if (state.controlsLayoutIsVisible) 0f else 180f
|
||||
fg.llFeeControlsContainer.show(state.controlsLayoutIsVisible)
|
||||
fg.chipGroup.show(state.feeChipGroupIsVisible)
|
||||
|
||||
fg.swIncludeFee.isEnabled = state.includeFeeSwitcherIsEnabled
|
||||
if (fg.swIncludeFee.isChecked != state.feeIsIncluded) {
|
||||
fg.swIncludeFee.isChecked = state.feeIsIncluded
|
||||
swIncludeFee.isEnabled = state.includeFeeSwitcherIsEnabled
|
||||
if (swIncludeFee.isChecked != state.feeIsIncluded) {
|
||||
swIncludeFee.isChecked = state.feeIsIncluded
|
||||
}
|
||||
|
||||
if (state.error == FeeAction.Error.REQUEST_FAILED) {
|
||||
fg.showRetrySnackbar(fg.requireContext().getString(R.string.send_error_fee_request_failed)) {
|
||||
fg.showRetrySnackbar(
|
||||
fg.requireContext().getString(R.string.send_error_fee_request_failed)
|
||||
) {
|
||||
store.dispatch(FeeAction.RequestFee)
|
||||
}
|
||||
}
|
||||
|
||||
val chipId = FeeUiHelper.toId(state.selectedFeeType)
|
||||
if (fg.chipGroup.checkedChipId != chipId && chipId != View.NO_ID) fg.chipGroup.check(chipId)
|
||||
if (chipGroup.checkedChipId != chipId && chipId != View.NO_ID) chipGroup.check(chipId)
|
||||
}
|
||||
|
||||
private fun handleReceiptState(fg: BaseStoreFragment, state: ReceiptState) {
|
||||
val mainLayout = fg.clReceiptContainer as ViewGroup
|
||||
val totalLayout = fg.llTotal as ViewGroup
|
||||
val totalTokenLayout = fg.flTotalTokenCrypto as ViewGroup
|
||||
private fun handleReceiptState(fg: SendFragment, state: ReceiptState) = with(fg.binding.clReceiptContainer) {
|
||||
val mainLayout = clReceiptContainer as ViewGroup
|
||||
val totalLayout = llTotalContainer.llTotal as ViewGroup
|
||||
val totalTokenLayout = llTotalContainer.flTotalTokenCrypto as ViewGroup
|
||||
fun getString(id: Int, vararg formatStrings: String): String =
|
||||
mainLayout.context.getString(id, *formatStrings)
|
||||
mainLayout.context.getString(id, *formatStrings)
|
||||
|
||||
val rough = getString(R.string.sign_rough)
|
||||
fun roughOrEmpty(value: String): String = if (value == ReceiptReducer.EMPTY) value else "$rough $value"
|
||||
fun roughOrEmpty(value: String): String =
|
||||
if (value == ReceiptReducer.EMPTY) value else "$rough $value"
|
||||
|
||||
when (state.visibleTypeOfReceipt) {
|
||||
ReceiptLayoutType.FIAT -> {
|
||||
val receipt = state.fiat ?: return
|
||||
|
||||
llTotalContainer.tvTotalValue
|
||||
totalLayout.show(true)
|
||||
totalTokenLayout.show(false)
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
|
||||
tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
|
||||
tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
|
||||
llTotalContainer.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
|
||||
|
||||
val willSent = getString(R.string.send_total_subtitle_format,
|
||||
receipt.willSentCrypto, receipt.symbols.crypto)
|
||||
totalLayout.tvWillBeSentValue.update(willSent)
|
||||
val willSent = getString(
|
||||
R.string.send_total_subtitle_format,
|
||||
receipt.willSentCrypto, receipt.symbols.crypto
|
||||
)
|
||||
llTotalContainer.tvWillBeSentValue.update(willSent)
|
||||
|
||||
}
|
||||
ReceiptLayoutType.CRYPTO -> {
|
||||
|
|
@ -277,34 +287,34 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
|
||||
totalLayout.show(true)
|
||||
totalTokenLayout.show(false)
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountCrypto} ${receipt.symbols.crypto}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeCrypto} ${receipt.symbols.crypto}")
|
||||
totalLayout.tvTotalValue.update("${receipt.totalCrypto} ${receipt.symbols.crypto}")
|
||||
tvReceiptAmountValue.update("${receipt.amountCrypto} ${receipt.symbols.crypto}")
|
||||
tvReceiptFeeValue.update("${receipt.feeCrypto} ${receipt.symbols.crypto}")
|
||||
llTotalContainer.tvTotalValue.update("${receipt.totalCrypto} ${receipt.symbols.crypto}")
|
||||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold {
|
||||
append(roughOrEmpty(receipt.willSentFiat)).append(" ")
|
||||
append(receipt.symbols.fiat)
|
||||
append(" (fee: ${receipt.feeFiat} ")
|
||||
append(receipt.symbols.fiat).append(")")
|
||||
}
|
||||
totalLayout.tvWillBeSentValue.update(willSent.toString())
|
||||
.bold {
|
||||
append(roughOrEmpty(receipt.willSentFiat)).append(" ")
|
||||
append(receipt.symbols.fiat)
|
||||
append(" (fee: ${receipt.feeFiat} ")
|
||||
append(receipt.symbols.fiat).append(")")
|
||||
}
|
||||
llTotalContainer.tvWillBeSentValue.update(willSent.toString())
|
||||
}
|
||||
ReceiptLayoutType.TOKEN_FIAT -> {
|
||||
val receipt = state.tokenFiat ?: return
|
||||
|
||||
totalLayout.show(true)
|
||||
totalTokenLayout.show(false)
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
|
||||
totalLayout.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
|
||||
tvReceiptAmountValue.update("${receipt.amountFiat} ${receipt.symbols.fiat}")
|
||||
tvReceiptFeeValue.update("${receipt.feeFiat} ${receipt.symbols.fiat}")
|
||||
llTotalContainer.tvTotalValue.update("${roughOrEmpty(receipt.totalFiat)} ${receipt.symbols.fiat}")
|
||||
|
||||
val willSent = getString(
|
||||
R.string.send_total_subtitle_asset_format,
|
||||
receipt.symbols.token ?: "", receipt.willSentToken,
|
||||
receipt.symbols.crypto, receipt.willSentFeeCoin
|
||||
)
|
||||
totalLayout.tvWillBeSentValue.update(willSent)
|
||||
llTotalContainer.tvWillBeSentValue.update(willSent)
|
||||
}
|
||||
ReceiptLayoutType.TOKEN_CRYPTO -> {
|
||||
val receipt = state.tokenCrypto ?: return
|
||||
|
|
@ -312,15 +322,15 @@ class SendStateSubscriber(fragment: BaseStoreFragment) : FragmentStateSubscriber
|
|||
totalLayout.show(false)
|
||||
totalTokenLayout.show(true)
|
||||
|
||||
fg.tvReceiptAmountValue.update("${receipt.amountToken} ${receipt.symbols.token}")
|
||||
fg.tvReceiptFeeValue.update("${receipt.feeCoin} ${receipt.symbols.crypto}")
|
||||
tvReceiptAmountValue.update("${receipt.amountToken} ${receipt.symbols.token}")
|
||||
tvReceiptFeeValue.update("${receipt.feeCoin} ${receipt.symbols.crypto}")
|
||||
|
||||
val willSent = SpannableStringBuilder()
|
||||
.bold {
|
||||
append(roughOrEmpty(receipt.totalFiat)).append(" ")
|
||||
append(receipt.symbols.fiat)
|
||||
}
|
||||
totalTokenLayout.tvTotalTokenCryptoValue.update(willSent.toString())
|
||||
.bold {
|
||||
append(roughOrEmpty(receipt.totalFiat)).append(" ")
|
||||
append(receipt.symbols.fiat)
|
||||
}
|
||||
llTotalContainer.tvTotalTokenCryptoValue.update(willSent.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import android.view.View.OnFocusChangeListener
|
|||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.tap.common.KeyboardObserver
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
|
|
@ -18,12 +19,15 @@ import com.tangem.tap.features.shop.redux.ShopAction
|
|||
import com.tangem.tap.features.shop.redux.ShopState
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_shop.*
|
||||
import com.tangem.wallet.databinding.FragmentShopBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
|
||||
class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber<ShopState> {
|
||||
|
||||
private val binding: FragmentShopBinding by viewBinding(FragmentShopBinding::bind)
|
||||
|
||||
lateinit var keyboardObserver: KeyboardObserver
|
||||
|
||||
override fun subscribeToStore() {
|
||||
store.subscribe(this) { state ->
|
||||
|
|
@ -44,6 +48,11 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber<
|
|||
})
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
keyboardObserver.unregisterListener()
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
|
|
@ -51,41 +60,41 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber<
|
|||
setupProductSelection()
|
||||
setupPromoCodeEditText()
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
requireActivity().onBackPressed()
|
||||
}
|
||||
|
||||
|
||||
val keyboardObserver = KeyboardObserver(requireActivity())
|
||||
keyboardObserver.registerListener { isVisible ->
|
||||
fl_cards.show(!isVisible)
|
||||
keyboardObserver = KeyboardObserver(requireActivity()).apply {
|
||||
registerListener { isVisible ->
|
||||
binding.flCards.show(!isVisible)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCardsImages() {
|
||||
imv_second.animate()
|
||||
binding.imvSecond.animate()
|
||||
.translationY(70f)
|
||||
.scaleX(0.9f)
|
||||
.scaleY(0.9f)
|
||||
.start()
|
||||
imv_third.animate()
|
||||
binding.imvThird.animate()
|
||||
.translationY(140f)
|
||||
.scaleX(0.8f)
|
||||
.scaleY(0.8f)
|
||||
.start()
|
||||
}
|
||||
|
||||
private fun setupProductSelection() {
|
||||
chip_product_1.setOnCheckedChangeListener { _, isChecked ->
|
||||
private fun setupProductSelection() = with(binding) {
|
||||
chipProduct1.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) store.dispatch(ShopAction.SelectProduct(ProductType.WALLET_3_CARDS))
|
||||
}
|
||||
chip_product_2.setOnCheckedChangeListener { _, isChecked ->
|
||||
chipProduct2.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) store.dispatch(ShopAction.SelectProduct(ProductType.WALLET_2_CARDS))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPromoCodeEditText() {
|
||||
et_promo_code.setOnEditorActionListener { view, actionId, event ->
|
||||
private fun setupPromoCodeEditText() = with(binding) {
|
||||
etPromoCode.setOnEditorActionListener { view, actionId, event ->
|
||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||
val imm: InputMethodManager =
|
||||
requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
|
|
@ -96,15 +105,15 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber<
|
|||
return@setOnEditorActionListener false
|
||||
}
|
||||
|
||||
et_promo_code.onFocusChangeListener = OnFocusChangeListener { _, hasFocus ->
|
||||
etPromoCode.onFocusChangeListener = OnFocusChangeListener { _, hasFocus ->
|
||||
if (!hasFocus) {
|
||||
store.dispatch(ShopAction.ApplyPromoCode(et_promo_code.text.toString()))
|
||||
store.dispatch(ShopAction.ApplyPromoCode(etPromoCode.text.toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newState(state: ShopState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
animateProductSelection(state.selectedProduct)
|
||||
handlePriceState(state)
|
||||
|
|
@ -120,43 +129,43 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber<
|
|||
showOrHideThirdCardWithAnimation(show)
|
||||
}
|
||||
|
||||
private fun showOrHideThirdCardWithAnimation(show: Boolean) {
|
||||
private fun showOrHideThirdCardWithAnimation(show: Boolean) = with(binding) {
|
||||
val translationY = if (show) 140f else 0f
|
||||
if (show) imv_third.show()
|
||||
imv_third.animate()
|
||||
if (show) imvThird.show()
|
||||
imvThird.animate()
|
||||
.translationY(translationY)
|
||||
.setListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator) {
|
||||
super.onAnimationEnd(animation)
|
||||
imv_third?.show(show)
|
||||
imvThird?.show(show)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun handlePriceState(state: ShopState) {
|
||||
tv_total.text = state.total
|
||||
tv_total_before_discount.text = state.priceBeforeDiscount
|
||||
private fun handlePriceState(state: ShopState) = with(binding) {
|
||||
tvTotal.text = state.total
|
||||
tvTotalBeforeDiscount.text = state.priceBeforeDiscount
|
||||
|
||||
pb_price.show(state.total == null)
|
||||
pbPrice.show(state.total == null)
|
||||
|
||||
}
|
||||
|
||||
private fun handlePromoCodeState(state: ShopState) {
|
||||
if (state.promoCode == null && !et_promo_code.hasFocus()) {
|
||||
et_promo_code.setText("")
|
||||
private fun handlePromoCodeState(state: ShopState) = with(binding) {
|
||||
if (state.promoCode == null && !etPromoCode.hasFocus()) {
|
||||
etPromoCode.setText("")
|
||||
}
|
||||
pb_promo_code.show(state.promoCodeLoading)
|
||||
pbPromoCode.show(state.promoCodeLoading)
|
||||
}
|
||||
|
||||
private fun handleButtonsState(state: ShopState) {
|
||||
btn_pay_google_pay.show(state.isGooglePayAvailable)
|
||||
btn_alternative_payment.show(state.isGooglePayAvailable)
|
||||
btn_main_action.show(!state.isGooglePayAvailable)
|
||||
private fun handleButtonsState(state: ShopState) = with(binding) {
|
||||
btnPayGooglePay.root.show(state.isGooglePayAvailable)
|
||||
btnAlternativePayment.show(state.isGooglePayAvailable)
|
||||
btnMainAction.show(!state.isGooglePayAvailable)
|
||||
|
||||
if (state.total != null) {
|
||||
btn_alternative_payment.setOnClickListener { store.dispatch(ShopAction.StartWebCheckout) }
|
||||
btn_main_action.setOnClickListener { store.dispatch(ShopAction.StartWebCheckout) }
|
||||
btn_pay_google_pay.setOnClickListener { store.dispatch(ShopAction.BuyWithGooglePay) }
|
||||
btnAlternativePayment.setOnClickListener { store.dispatch(ShopAction.StartWebCheckout) }
|
||||
btnMainAction.setOnClickListener { store.dispatch(ShopAction.StartWebCheckout) }
|
||||
btnPayGooglePay.root.setOnClickListener { store.dispatch(ShopAction.BuyWithGooglePay) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.appcompat.widget.SearchView
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.redux.navigation.NavigationAction
|
||||
import com.tangem.tap.features.tokens.redux.TokensAction
|
||||
|
|
@ -19,7 +20,7 @@ import com.tangem.tap.features.tokens.ui.adapters.CurrenciesAdapter
|
|||
import com.tangem.tap.mainScope
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_add_tokens.*
|
||||
import com.tangem.wallet.databinding.FragmentAddTokensBinding
|
||||
import kotlinx.coroutines.channels.awaitClose
|
||||
import kotlinx.coroutines.flow.*
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
|
@ -29,6 +30,7 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens),
|
|||
StoreSubscriber<TokensState> {
|
||||
|
||||
private lateinit var viewAdapter: CurrenciesAdapter
|
||||
private val binding: FragmentAddTokensBinding by viewBinding(FragmentAddTokensBinding::bind)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
|
@ -57,29 +59,29 @@ class AddTokensFragment : Fragment(R.layout.fragment_add_tokens),
|
|||
store.unsubscribe(this)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) = with(binding) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(toolbar)
|
||||
toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
setupPopularTokensRecyclerView()
|
||||
btn_tokens_save_changes.setOnClickListener {
|
||||
btnTokensSaveChanges.setOnClickListener {
|
||||
store.dispatch(TokensAction.SaveChanges(viewAdapter.getAddedItems()))
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupPopularTokensRecyclerView() {
|
||||
private fun setupPopularTokensRecyclerView() = with(binding) {
|
||||
viewAdapter = CurrenciesAdapter()
|
||||
viewAdapter.setOnItemAddListener {
|
||||
btn_tokens_save_changes.isEnabled = viewAdapter.getAddedItems().isNotEmpty()
|
||||
btnTokensSaveChanges.isEnabled = viewAdapter.getAddedItems().isNotEmpty()
|
||||
}
|
||||
|
||||
rv_popular_tokens.layoutManager = LinearLayoutManager(context)
|
||||
rv_popular_tokens.adapter = viewAdapter
|
||||
rvPopularTokens.layoutManager = LinearLayoutManager(context)
|
||||
rvPopularTokens.adapter = viewAdapter
|
||||
}
|
||||
|
||||
override fun newState(state: TokensState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
viewAdapter.addedCurrencies = state.addedCurrencies
|
||||
viewAdapter.submitUnfilteredList(state.shownCurrencies)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.tokens.ui.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
|
|
@ -20,8 +19,8 @@ import com.tangem.tap.features.tokens.redux.CurrencyListItem
|
|||
import com.tangem.tap.features.tokens.redux.TokensAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.item_currency_subtitle.view.*
|
||||
import kotlinx.android.synthetic.main.item_popular_token.view.*
|
||||
import com.tangem.wallet.databinding.ItemCurrencySubtitleBinding
|
||||
import com.tangem.wallet.databinding.ItemPopularTokenBinding
|
||||
import java.util.*
|
||||
|
||||
class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>(DiffUtilCallback) {
|
||||
|
|
@ -62,18 +61,18 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
|
|||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
return when (viewType) {
|
||||
0 -> TitleViewHolder(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_currency_subtitle, parent, false)
|
||||
binding = ItemCurrencySubtitleBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
)
|
||||
1 -> CurrenciesViewHolder(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_popular_token, parent, false),
|
||||
vhOnItemAddListener
|
||||
binding = ItemPopularTokenBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
onItemAddListener = vhOnItemAddListener
|
||||
)
|
||||
else -> CurrenciesViewHolder(
|
||||
LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_popular_token, parent, false),
|
||||
vhOnItemAddListener
|
||||
binding = ItemPopularTokenBinding
|
||||
.inflate(LayoutInflater.from(parent.context), parent, false),
|
||||
onItemAddListener = vhOnItemAddListener
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -109,15 +108,15 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
|
|||
is CurrencyListItem.BlockchainListItem -> {
|
||||
element.blockchain.currency.toLowerCase(Locale.US)
|
||||
.contains(queryNormalized) ||
|
||||
element.blockchain.fullName.toLowerCase(Locale.US)
|
||||
.contains(queryNormalized)
|
||||
element.blockchain.fullName.toLowerCase(Locale.US)
|
||||
.contains(queryNormalized)
|
||||
|
||||
}
|
||||
is CurrencyListItem.TokenListItem -> {
|
||||
element.token.name.toLowerCase(Locale.US)
|
||||
.contains(queryNormalized) ||
|
||||
element.token.symbol.toLowerCase(Locale.US)
|
||||
.contains(queryNormalized)
|
||||
element.token.symbol.toLowerCase(Locale.US)
|
||||
.contains(queryNormalized)
|
||||
}
|
||||
is CurrencyListItem.TitleListItem -> true
|
||||
}
|
||||
|
|
@ -129,9 +128,9 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
|
|||
}
|
||||
|
||||
class CurrenciesViewHolder(
|
||||
private val view: View,
|
||||
private val binding: ItemPopularTokenBinding,
|
||||
private val onItemAddListener: ((CurrencyListItem) -> Unit),
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(
|
||||
currency: CurrencyListItem,
|
||||
|
|
@ -141,12 +140,14 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
|
|||
when (currency) {
|
||||
is CurrencyListItem.BlockchainListItem -> {
|
||||
val addedBlockchains = addedCurrencies?.blockchains ?: listOf()
|
||||
val currentlyAdded = currentlyAddedItems.filterIsInstance<CurrencyListItem.BlockchainListItem>()
|
||||
val currentlyAdded =
|
||||
currentlyAddedItems.filterIsInstance<CurrencyListItem.BlockchainListItem>()
|
||||
bindBlockchain(currency, addedBlockchains, currentlyAdded)
|
||||
}
|
||||
is CurrencyListItem.TokenListItem -> {
|
||||
val addedTokens = addedCurrencies?.tokens ?: listOf()
|
||||
val currentlyAdded = currentlyAddedItems.filterIsInstance<CurrencyListItem.TokenListItem>()
|
||||
val currentlyAdded =
|
||||
currentlyAddedItems.filterIsInstance<CurrencyListItem.TokenListItem>()
|
||||
bindToken(currency, addedTokens, currentlyAdded)
|
||||
}
|
||||
}
|
||||
|
|
@ -156,13 +157,13 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
|
|||
currency: CurrencyListItem.BlockchainListItem,
|
||||
addedBlockchains: List<Blockchain>,
|
||||
currentlyAdded: List<CurrencyListItem.BlockchainListItem>
|
||||
) {
|
||||
) = with(binding) {
|
||||
val blockchain = currency.blockchain
|
||||
Picasso.get().loadCurrenciesIcon(view.iv_currency, view.tv_token_letter, null, blockchain)
|
||||
Picasso.get().loadCurrenciesIcon(ivCurrency, tvTokenLetter, null, blockchain)
|
||||
|
||||
view.tv_currency_name.text = blockchain.fullName
|
||||
view.tv_currency_symbol.text = blockchain.currency
|
||||
view.btn_add_token.setOnClickListener {
|
||||
tvCurrencyName.text = blockchain.fullName
|
||||
tvCurrencySymbol.text = blockchain.currency
|
||||
btnAddToken.setOnClickListener {
|
||||
onItemAddListener.invoke(currency)
|
||||
currency.isAdded = true
|
||||
modifyAddTokenButton(currency)
|
||||
|
|
@ -178,16 +179,17 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
|
|||
currency: CurrencyListItem.TokenListItem,
|
||||
addedTokens: List<Token>,
|
||||
currentlyAdded: List<CurrencyListItem.TokenListItem>
|
||||
) {
|
||||
) = with(binding) {
|
||||
val token = currency.token
|
||||
Picasso.get().loadCurrenciesIcon(view.iv_currency, view.tv_token_letter, token, token.blockchain)
|
||||
Picasso.get()
|
||||
.loadCurrenciesIcon(ivCurrency, tvTokenLetter, token, token.blockchain)
|
||||
|
||||
view.tv_currency_name.text = token.name
|
||||
view.tv_currency_symbol.text = view.context.getString(
|
||||
tvCurrencyName.text = token.name
|
||||
tvCurrencySymbol.text = tvCurrencySymbol.getString(
|
||||
R.string.token_symbol_address_format,
|
||||
token.symbol, token.contractAddress
|
||||
)
|
||||
view.btn_add_token.setOnClickListener {
|
||||
btnAddToken.setOnClickListener {
|
||||
onItemAddListener.invoke(currency)
|
||||
currency.isAdded = true
|
||||
modifyAddTokenButton(currency)
|
||||
|
|
@ -200,48 +202,52 @@ class CurrenciesAdapter : ListAdapter<CurrencyListItem, RecyclerView.ViewHolder>
|
|||
modifyAddTokenButton(currency)
|
||||
}
|
||||
|
||||
private fun modifyAddTokenButton(currency: CurrencyListItem) {
|
||||
private fun modifyAddTokenButton(currency: CurrencyListItem) = with(binding) {
|
||||
if (currency.isLocked) {
|
||||
view.btn_add_token.setText(R.string.common_add)
|
||||
view.btn_add_token.isEnabled = false
|
||||
btnAddToken.setText(R.string.common_add)
|
||||
btnAddToken.isEnabled = false
|
||||
} else {
|
||||
val text = if (currency.isAdded) R.string.add_token_added else R.string.common_add
|
||||
view.btn_add_token.setText(text)
|
||||
view.btn_add_token.isEnabled = !currency.isAdded
|
||||
btnAddToken.setText(text)
|
||||
btnAddToken.isEnabled = !currency.isAdded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TitleViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
fun bind(title: CurrencyListItem.TitleListItem) {
|
||||
class TitleViewHolder(val binding: ItemCurrencySubtitleBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(title: CurrencyListItem.TitleListItem) = with(binding) {
|
||||
if (title.blockchain != null) {
|
||||
val subtitle = view.getString(title.titleResId, title.blockchain.getTokensName())
|
||||
view.tv_subtitle.text = subtitle.uppercase()
|
||||
view.cl_subtitle_container.setOnClickListener {
|
||||
val subtitle = root.getString(title.titleResId, title.blockchain.getTokensName())
|
||||
tvSubtitle.text = subtitle.uppercase()
|
||||
clSubtitleContainer.setOnClickListener {
|
||||
val rotation = if (title.isContentShown) -90f else 90f
|
||||
store.dispatch(TokensAction.ToggleShowTokensForBlockchain(
|
||||
title.isContentShown, title.blockchain
|
||||
))
|
||||
view.iv_toggle_sublist_visibility.animate().rotation(rotation).withEndAction {
|
||||
showArrow(view, title.isContentShown)
|
||||
store.dispatch(
|
||||
TokensAction.ToggleShowTokensForBlockchain(
|
||||
title.isContentShown, title.blockchain
|
||||
)
|
||||
)
|
||||
ivToggleSublistVisibility.animate().rotation(rotation).withEndAction {
|
||||
showArrow(title.isContentShown)
|
||||
}
|
||||
}
|
||||
showArrow(view, title.isContentShown)
|
||||
showArrow(title.isContentShown)
|
||||
} else {
|
||||
view.tv_subtitle.text = view.getString(title.titleResId).uppercase()
|
||||
view.iv_toggle_sublist_visibility.hide()
|
||||
tvSubtitle.text = root.getString(title.titleResId).uppercase()
|
||||
ivToggleSublistVisibility.hide()
|
||||
}
|
||||
}
|
||||
|
||||
private fun showArrow(view: View, isContentShown: Boolean) {
|
||||
view.iv_toggle_sublist_visibility.show()
|
||||
private fun showArrow(isContentShown: Boolean) = with(binding) {
|
||||
ivToggleSublistVisibility.show()
|
||||
val drawable = if (isContentShown) {
|
||||
R.drawable.ic_arrow_angle_down
|
||||
} else {
|
||||
R.drawable.ic_arrow_angle_right
|
||||
}
|
||||
view.iv_toggle_sublist_visibility.setImageResource(drawable)
|
||||
view.iv_toggle_sublist_visibility.rotation = 0f
|
||||
ivToggleSublistVisibility.setImageResource(drawable)
|
||||
ivToggleSublistVisibility.rotation = 0f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
package com.tangem.tap.features.wallet.ui
|
||||
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.card_balance.*
|
||||
import kotlinx.android.synthetic.main.layout_balance.*
|
||||
import kotlinx.android.synthetic.main.layout_balance_error.*
|
||||
import com.tangem.wallet.databinding.CardBalanceBinding
|
||||
import java.math.BigDecimal
|
||||
|
||||
enum class BalanceStatus {
|
||||
|
|
@ -34,30 +31,34 @@ data class BalanceWidgetData(
|
|||
)
|
||||
|
||||
data class TokenData(
|
||||
val amount: String,
|
||||
val tokenSymbol: String,
|
||||
val fiatAmount: String? = null,
|
||||
val fiatRateString: String? = null,
|
||||
val fiatRate: BigDecimal? = null,
|
||||
val amount: String,
|
||||
val tokenSymbol: String,
|
||||
val fiatAmount: String? = null,
|
||||
val fiatRateString: String? = null,
|
||||
val fiatRate: BigDecimal? = null,
|
||||
)
|
||||
|
||||
|
||||
class BalanceWidget(
|
||||
val fragment: Fragment,
|
||||
val data: BalanceWidgetData,
|
||||
private val isTwinCard: Boolean,
|
||||
private val binding: CardBalanceBinding,
|
||||
private val fragment: WalletFragment,
|
||||
private val data: BalanceWidgetData,
|
||||
private val isTwinCard: Boolean,
|
||||
) {
|
||||
|
||||
fun setup() {
|
||||
|
||||
when (data.status) {
|
||||
BalanceStatus.Loading -> {
|
||||
fragment.l_balance.show()
|
||||
fragment.l_balance_error.hide()
|
||||
fragment.tv_fiat_amount.hide()
|
||||
with(binding) {
|
||||
lBalance.root.show()
|
||||
lBalanceError.root.hide()
|
||||
lBalance.tvFiatAmount.hide()
|
||||
|
||||
lBalance.tvCurrency.text = data.currency
|
||||
lBalance.tvAmount.text = ""
|
||||
}
|
||||
|
||||
fragment.tv_currency.text = data.currency
|
||||
fragment.tv_amount.text = ""
|
||||
|
||||
showStatus(R.id.tv_status_loading)
|
||||
|
||||
|
|
@ -67,18 +68,18 @@ class BalanceWidget(
|
|||
showBalanceWithoutToken(data, false)
|
||||
}
|
||||
}
|
||||
BalanceStatus.VerifiedOnline, BalanceStatus.TransactionInProgress -> {
|
||||
fragment.l_balance.show()
|
||||
fragment.l_balance_error.hide()
|
||||
BalanceStatus.VerifiedOnline, BalanceStatus.TransactionInProgress -> with(binding.lBalance) {
|
||||
root.show()
|
||||
binding.lBalanceError.root.hide()
|
||||
val statusView = if (data.status == BalanceStatus.VerifiedOnline) {
|
||||
R.id.tv_status_verified
|
||||
} else {
|
||||
fragment.tv_status_error.text =
|
||||
fragment.getText(R.string.wallet_balance_tx_in_progress)
|
||||
tvStatusError.text =
|
||||
fragment.getText(R.string.wallet_balance_tx_in_progress)
|
||||
R.id.group_error
|
||||
}
|
||||
showStatus(statusView)
|
||||
fragment.tv_status_error_message.hide()
|
||||
tvStatusErrorMessage.hide()
|
||||
|
||||
if (data.token != null) {
|
||||
showBalanceWithToken(data, true)
|
||||
|
|
@ -86,79 +87,83 @@ class BalanceWidget(
|
|||
showBalanceWithoutToken(data, true)
|
||||
}
|
||||
}
|
||||
BalanceStatus.Unreachable -> {
|
||||
fragment.l_balance.show()
|
||||
fragment.l_balance_error.hide()
|
||||
fragment.tv_fiat_amount.hide()
|
||||
fragment.group_base_currency.hide()
|
||||
BalanceStatus.Unreachable -> with(binding.lBalance) {
|
||||
root.show()
|
||||
binding.lBalanceError.root.hide()
|
||||
tvFiatAmount.hide()
|
||||
groupBaseCurrency.hide()
|
||||
|
||||
val currency = if (data.token != null) data.token.tokenSymbol else data.currency
|
||||
fragment.tv_currency.text = currency
|
||||
fragment.tv_amount.text = ""
|
||||
tvCurrency.text = currency
|
||||
tvAmount.text = ""
|
||||
|
||||
fragment.tv_status_error_message.text = data.errorMessage
|
||||
fragment.tv_status_error.text =
|
||||
fragment.getString(R.string.wallet_balance_blockchain_unreachable)
|
||||
tvStatusErrorMessage.text = data.errorMessage
|
||||
tvStatusError.text =
|
||||
fragment.getString(R.string.wallet_balance_blockchain_unreachable)
|
||||
|
||||
showStatus(R.id.group_error)
|
||||
fragment.tv_status_error_message.show(!data.errorMessage.isNullOrBlank())
|
||||
tvStatusErrorMessage.show(!data.errorMessage.isNullOrBlank())
|
||||
}
|
||||
BalanceStatus.EmptyCard -> {
|
||||
fragment.l_balance.hide()
|
||||
fragment.l_balance_error.show()
|
||||
BalanceStatus.EmptyCard -> with(binding.lBalanceError) {
|
||||
binding.lBalance.root.hide()
|
||||
binding.lBalanceError.root.show()
|
||||
if (isTwinCard) {
|
||||
fragment.tv_error_title.text = fragment.getText(R.string.wallet_error_empty_twin_card)
|
||||
fragment.tv_error_descriptions.text = fragment.getText(R.string.wallet_error_empty_twin_card_subtitle)
|
||||
tvErrorTitle.text = fragment.getText(R.string.wallet_error_empty_twin_card)
|
||||
tvErrorDescriptions.text =
|
||||
fragment.getText(R.string.wallet_error_empty_twin_card_subtitle)
|
||||
} else {
|
||||
fragment.tv_error_title.text = fragment.getText(R.string.wallet_error_empty_card)
|
||||
fragment.tv_error_descriptions.text = fragment.getText(R.string.wallet_error_empty_card_subtitle)
|
||||
tvErrorTitle.text = fragment.getText(R.string.wallet_error_empty_card)
|
||||
tvErrorDescriptions.text =
|
||||
fragment.getText(R.string.wallet_error_empty_card_subtitle)
|
||||
}
|
||||
}
|
||||
BalanceStatus.NoAccount -> {
|
||||
fragment.l_balance.hide()
|
||||
fragment.l_balance_error.show()
|
||||
fragment.tv_error_title.text = fragment.getText(R.string.wallet_error_no_account)
|
||||
fragment.tv_error_descriptions.text =
|
||||
fragment.getString(
|
||||
R.string.wallet_error_no_account_subtitle_format,
|
||||
data.amountToCreateAccount, data.currencySymbol
|
||||
)
|
||||
BalanceStatus.NoAccount -> with(binding.lBalanceError) {
|
||||
binding.lBalance.root.hide()
|
||||
binding.lBalanceError.root.show()
|
||||
tvErrorTitle.text = fragment.getText(R.string.wallet_error_no_account)
|
||||
tvErrorDescriptions.text =
|
||||
fragment.getString(
|
||||
R.string.wallet_error_no_account_subtitle_format,
|
||||
data.amountToCreateAccount, data.currencySymbol
|
||||
)
|
||||
}
|
||||
BalanceStatus.UnknownBlockchain -> {
|
||||
fragment.l_balance.hide()
|
||||
fragment.l_balance_error.show()
|
||||
fragment.tv_error_title.text = fragment.getText(R.string.wallet_error_unsupported_blockchain)
|
||||
fragment.tv_error_descriptions.text =
|
||||
fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle)
|
||||
BalanceStatus.UnknownBlockchain -> with(binding.lBalanceError) {
|
||||
binding.lBalance.root.hide()
|
||||
binding.lBalanceError.root.show()
|
||||
tvErrorTitle.text =
|
||||
fragment.getText(R.string.wallet_error_unsupported_blockchain)
|
||||
tvErrorDescriptions.text =
|
||||
fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showStatus(@IdRes viewRes: Int) {
|
||||
fragment.group_error.show(viewRes == R.id.group_error)
|
||||
fragment.tv_status_loading.show(viewRes == R.id.tv_status_loading)
|
||||
fragment.tv_status_verified.show(viewRes == R.id.tv_status_verified)
|
||||
private fun showStatus(@IdRes viewRes: Int) = with(binding.lBalance) {
|
||||
groupError.show(viewRes == R.id.group_error)
|
||||
tvStatusLoading.show(viewRes == R.id.tv_status_loading)
|
||||
tvStatusVerified.show(viewRes == R.id.tv_status_verified)
|
||||
}
|
||||
|
||||
private fun showBalanceWithToken(data: BalanceWidgetData, showAmount: Boolean) {
|
||||
fragment.group_base_currency.show()
|
||||
fragment.tv_currency.text = data.token?.tokenSymbol
|
||||
fragment.tv_base_currency.text = data.currency
|
||||
fragment.tv_amount.text = if (showAmount) data.token?.amount else ""
|
||||
fragment.tv_base_amount.text = if (showAmount) data.amount else ""
|
||||
private fun showBalanceWithToken(data: BalanceWidgetData, showAmount: Boolean) = with(binding.lBalance) {
|
||||
groupBaseCurrency.show()
|
||||
tvCurrency.text = data.token?.tokenSymbol
|
||||
tvBaseCurrency.text = data.currency
|
||||
tvAmount.text = if (showAmount) data.token?.amount else ""
|
||||
tvBaseAmount.text = if (showAmount) data.amount else ""
|
||||
if (showAmount) {
|
||||
fragment.tv_fiat_amount.show()
|
||||
fragment.tv_fiat_amount.text = data.token?.fiatAmount
|
||||
tvFiatAmount.show()
|
||||
tvFiatAmount.text = data.token?.fiatAmount
|
||||
}
|
||||
}
|
||||
|
||||
private fun showBalanceWithoutToken(data: BalanceWidgetData, showAmount: Boolean) {
|
||||
fragment.group_base_currency.hide()
|
||||
fragment.tv_currency.text = data.currency
|
||||
fragment.tv_amount.text = if (showAmount) data.amount else ""
|
||||
if (showAmount) {
|
||||
fragment.tv_fiat_amount.show()
|
||||
fragment.tv_fiat_amount.text = data.fiatAmountFormatted
|
||||
private fun showBalanceWithoutToken(data: BalanceWidgetData, showAmount: Boolean) =
|
||||
with(binding.lBalance) {
|
||||
groupBaseCurrency.hide()
|
||||
tvCurrency.text = data.currency
|
||||
tvAmount.text = if (showAmount) data.amount else ""
|
||||
if (showAmount) {
|
||||
tvFiatAmount.show()
|
||||
tvFiatAmount.text = data.fiatAmountFormatted
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.squareup.picasso.Picasso
|
||||
import com.tangem.common.extensions.guard
|
||||
import com.tangem.tap.common.SnackbarHandler
|
||||
|
|
@ -22,19 +23,17 @@ import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter
|
|||
import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_details.*
|
||||
import kotlinx.android.synthetic.main.layout_balance_error.*
|
||||
import kotlinx.android.synthetic.main.layout_balance_wallet_details.*
|
||||
import kotlinx.android.synthetic.main.layout_wallet_details.*
|
||||
import kotlinx.android.synthetic.main.layout_wallet_details.card_balance
|
||||
import kotlinx.android.synthetic.main.layout_wallet_details_rent.*
|
||||
import com.tangem.wallet.databinding.FragmentWalletDetailsBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreSubscriber<WalletState> {
|
||||
class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details),
|
||||
StoreSubscriber<WalletState> {
|
||||
|
||||
private lateinit var pendingTransactionAdapter: PendingTransactionsAdapter
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
private val binding: FragmentWalletDetailsBinding by viewBinding(FragmentWalletDetailsBinding::bind)
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setHasOptionsMenu(true)
|
||||
|
|
@ -65,8 +64,8 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(toolbar)
|
||||
toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
|
||||
binding.toolbar.setNavigationOnClickListener { activity?.onBackPressed() }
|
||||
|
||||
|
||||
setupTransactionsRecyclerView()
|
||||
|
|
@ -74,91 +73,98 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
}
|
||||
|
||||
|
||||
private fun setupTransactionsRecyclerView() {
|
||||
private fun setupTransactionsRecyclerView() = with(binding) {
|
||||
pendingTransactionAdapter = PendingTransactionsAdapter()
|
||||
rv_pending_transaction.layoutManager = LinearLayoutManager(requireContext())
|
||||
rv_pending_transaction.adapter = pendingTransactionAdapter
|
||||
rvPendingTransaction.layoutManager = LinearLayoutManager(requireContext())
|
||||
rvPendingTransaction.adapter = pendingTransactionAdapter
|
||||
}
|
||||
|
||||
private fun setupButtons() {
|
||||
btn_confirm.text = getString(R.string.wallet_button_send)
|
||||
btn_confirm.setOnClickListener { store.dispatch(WalletAction.Send()) }
|
||||
private fun setupButtons() = with(binding) {
|
||||
btnConfirm.text = getString(R.string.wallet_button_send)
|
||||
btnConfirm.setOnClickListener { store.dispatch(WalletAction.Send()) }
|
||||
|
||||
btn_share.setOnClickListener { store.dispatch(WalletAction.ShowDialog.QrCode) }
|
||||
binding.lWalletDetails.btnShare.setOnClickListener { store.dispatch(WalletAction.ShowDialog.QrCode) }
|
||||
|
||||
btn_trade.setOnClickListener { store.dispatch(WalletAction.TradeCryptoAction.Buy) }
|
||||
btnTrade.setOnClickListener { store.dispatch(WalletAction.TradeCryptoAction.Buy) }
|
||||
|
||||
btn_sell.setOnClickListener { store.dispatch(WalletAction.TradeCryptoAction.Sell) }
|
||||
btnSell.setOnClickListener { store.dispatch(WalletAction.TradeCryptoAction.Sell) }
|
||||
}
|
||||
|
||||
override fun newState(state: WalletState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
if (state.selectedWallet == null) return
|
||||
val selectedWallet = state.getSelectedWalletData() ?: return
|
||||
|
||||
tv_currency_title.text = selectedWallet.currencyData.currency
|
||||
val currency = selectedWallet.currency
|
||||
if (currency is Currency.Token) {
|
||||
tv_currency_subtitle.text = currency.blockchain.tokenDisplayName()
|
||||
tv_currency_subtitle.show()
|
||||
} else {
|
||||
tv_currency_subtitle.hide()
|
||||
}
|
||||
|
||||
|
||||
showPendingTransactionsIfPresent(selectedWallet.pendingTransactions)
|
||||
setupCurrency(selectedWallet.currencyData, selectedWallet.currency)
|
||||
setupAddressCard(selectedWallet)
|
||||
setupNoInternetHandling(state)
|
||||
setupBalanceData(selectedWallet.currencyData)
|
||||
|
||||
btn_confirm.isEnabled = selectedWallet.mainButton.enabled
|
||||
btn_copy.setOnClickListener {
|
||||
selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString ->
|
||||
store.dispatch(WalletAction.CopyAddress(addressString, requireContext()))
|
||||
}
|
||||
}
|
||||
btn_share.setOnClickListener {
|
||||
selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString ->
|
||||
store.dispatch(WalletAction.ShareAddress(addressString, requireContext()))
|
||||
}
|
||||
}
|
||||
setupButtons(selectedWallet)
|
||||
|
||||
handleDialogs(state.walletDialog)
|
||||
handleCurrencyIcon(selectedWallet)
|
||||
handleWalletRent(selectedWallet.walletRent)
|
||||
|
||||
srl_wallet_details.setOnRefreshListener {
|
||||
|
||||
binding.srlWalletDetails.setOnRefreshListener {
|
||||
if (selectedWallet.currencyData.status != BalanceStatus.Loading) {
|
||||
store.dispatch(WalletAction.LoadWallet(
|
||||
blockchain = selectedWallet.currency.blockchain
|
||||
))
|
||||
store.dispatch(
|
||||
WalletAction.LoadWallet(
|
||||
blockchain = selectedWallet.currency.blockchain
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedWallet.currencyData.status != BalanceStatus.Loading) {
|
||||
srl_wallet_details.isRefreshing = false
|
||||
binding.srlWalletDetails.isRefreshing = false
|
||||
}
|
||||
|
||||
btn_trade.isEnabled = selectedWallet.tradeCryptoState.buyingAllowed
|
||||
btn_sell.show(selectedWallet.tradeCryptoState.sellingAllowed)
|
||||
}
|
||||
|
||||
private fun handleWalletRent(rent: WalletRent?) {
|
||||
private fun setupCurrency(currencyData: BalanceWidgetData, currency: Currency) = with(binding) {
|
||||
tvCurrencyTitle.text = currencyData.currency
|
||||
if (currency is Currency.Token) {
|
||||
binding.tvCurrencySubtitle.text = currency.blockchain.tokenDisplayName()
|
||||
binding.tvCurrencySubtitle.show()
|
||||
} else {
|
||||
binding.tvCurrencySubtitle.hide()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupButtons(selectedWallet: WalletData) = with(binding) {
|
||||
btnConfirm.isEnabled = selectedWallet.mainButton.enabled
|
||||
lWalletDetails.btnCopy.setOnClickListener {
|
||||
selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString ->
|
||||
store.dispatch(WalletAction.CopyAddress(addressString, requireContext()))
|
||||
}
|
||||
}
|
||||
lWalletDetails.btnShare.setOnClickListener {
|
||||
selectedWallet.walletAddresses?.selectedAddress?.address?.let { addressString ->
|
||||
store.dispatch(WalletAction.ShareAddress(addressString, requireContext()))
|
||||
}
|
||||
}
|
||||
btnTrade.isEnabled = selectedWallet.tradeCryptoState.buyingAllowed
|
||||
btnSell.show(selectedWallet.tradeCryptoState.sellingAllowed)
|
||||
}
|
||||
|
||||
private fun handleWalletRent(rent: WalletRent?) = with(binding) {
|
||||
val rent = rent.guard {
|
||||
l_rent_warning.hide()
|
||||
lRentWarning.root.hide()
|
||||
return
|
||||
}
|
||||
|
||||
val warningMessage = requireContext().getString(
|
||||
R.string.solana_rent_warning, rent.minRentValue, rent.rentExemptValue)
|
||||
tv_rent_warning_message.text = warningMessage
|
||||
l_rent_warning.show()
|
||||
R.string.solana_rent_warning, rent.minRentValue, rent.rentExemptValue
|
||||
)
|
||||
lRentWarning.tvRentWarningMessage.text = warningMessage
|
||||
lRentWarning.root.show()
|
||||
}
|
||||
|
||||
private fun handleCurrencyIcon(wallet: WalletData) {
|
||||
private fun handleCurrencyIcon(wallet: WalletData) = with(binding.lWalletDetails.lBalance) {
|
||||
Picasso.get().loadCurrenciesIcon(
|
||||
imageView = iv_currency,
|
||||
textView = tv_token_letter,
|
||||
imageView = ivCurrency,
|
||||
textView = tvTokenLetter,
|
||||
blockchain = wallet.currency.blockchain,
|
||||
token = (wallet.currency as? Currency.Token)?.token
|
||||
)
|
||||
|
|
@ -167,42 +173,48 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
|
||||
private fun showPendingTransactionsIfPresent(pendingTransactions: List<PendingTransaction>) {
|
||||
pendingTransactionAdapter.submitList(pendingTransactions)
|
||||
rv_pending_transaction?.show(pendingTransactions.isNotEmpty())
|
||||
binding.rvPendingTransaction?.show(pendingTransactions.isNotEmpty())
|
||||
}
|
||||
|
||||
private fun setupAddressCard(state: WalletData) {
|
||||
private fun setupAddressCard(state: WalletData) = with(binding.lWalletDetails) {
|
||||
if (state.walletAddresses != null) {
|
||||
if (state.shouldShowMultipleAddress() && state.currency is Currency.Blockchain) {
|
||||
(card_balance as? ViewGroup)?.beginDelayedTransition()
|
||||
chip_group_address_type.show()
|
||||
chip_group_address_type.fitChipsByGroupWidth()
|
||||
(cardBalance as? ViewGroup)?.beginDelayedTransition()
|
||||
chipGroupAddressType.show()
|
||||
chipGroupAddressType.fitChipsByGroupWidth()
|
||||
|
||||
val checkedId = MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type)
|
||||
if (checkedId != View.NO_ID) chip_group_address_type.check(checkedId)
|
||||
val checkedId =
|
||||
MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type)
|
||||
if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId)
|
||||
|
||||
chip_group_address_type.setOnCheckedChangeListener { group, checkedId ->
|
||||
chipGroupAddressType.setOnCheckedChangeListener { group, checkedId ->
|
||||
if (checkedId == -1) return@setOnCheckedChangeListener
|
||||
val type = MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain)
|
||||
val type =
|
||||
MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain)
|
||||
type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) }
|
||||
}
|
||||
} else {
|
||||
chip_group_address_type.hide()
|
||||
chipGroupAddressType.hide()
|
||||
}
|
||||
tv_address.text = state.walletAddresses.selectedAddress.address
|
||||
tv_explore?.setOnClickListener {
|
||||
store.dispatch(WalletAction.ExploreAddress(
|
||||
state.walletAddresses.selectedAddress.exploreUrl,
|
||||
requireContext()))
|
||||
tvAddress.text = state.walletAddresses.selectedAddress.address
|
||||
tvExplore?.setOnClickListener {
|
||||
store.dispatch(
|
||||
WalletAction.ExploreAddress(
|
||||
state.walletAddresses.selectedAddress.exploreUrl,
|
||||
requireContext()
|
||||
)
|
||||
)
|
||||
}
|
||||
iv_qr_code.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode())
|
||||
tv_receive_message.text = getQRReceiveMessage(tv_receive_message.context, state.currency)
|
||||
ivQrCode.setImageBitmap(state.walletAddresses.selectedAddress.shareUrl.toQrCode())
|
||||
tvReceiveMessage.text =
|
||||
getQRReceiveMessage(tvReceiveMessage.context, state.currency)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupNoInternetHandling(state: WalletState) {
|
||||
if (state.state == ProgressState.Error) {
|
||||
if (state.error == ErrorType.NoInternetConnection) {
|
||||
srl_wallet_details?.isRefreshing = false
|
||||
binding.srlWalletDetails.isRefreshing = false
|
||||
(activity as? SnackbarHandler)?.showSnackbar(
|
||||
text = R.string.wallet_notification_no_internet,
|
||||
buttonTitle = R.string.common_retry
|
||||
|
|
@ -213,73 +225,77 @@ class WalletDetailsFragment : Fragment(R.layout.fragment_wallet_details), StoreS
|
|||
}
|
||||
}
|
||||
|
||||
private fun setupBalanceData(data: BalanceWidgetData) {
|
||||
private fun setupBalanceData(data: BalanceWidgetData) = with(binding.lWalletDetails) {
|
||||
when (data.status) {
|
||||
BalanceStatus.Loading -> {
|
||||
l_balance.show()
|
||||
l_balance_error.hide()
|
||||
tv_fiat_amount.hide()
|
||||
tv_amount.text = ""
|
||||
|
||||
lBalance.root.show()
|
||||
lBalanceError.root.hide()
|
||||
lBalance.tvFiatAmount.hide()
|
||||
lBalance.tvAmount.text = ""
|
||||
showStatus(R.id.tv_status_loading)
|
||||
showBalanceWithoutToken(data, false)
|
||||
}
|
||||
BalanceStatus.VerifiedOnline, BalanceStatus.SameCurrencyTransactionInProgress,
|
||||
BalanceStatus.TransactionInProgress -> {
|
||||
l_balance.show()
|
||||
l_balance_error.hide()
|
||||
lBalance.root.show()
|
||||
lBalanceError.root.hide()
|
||||
val statusView = if (data.status == BalanceStatus.VerifiedOnline ||
|
||||
data.status == BalanceStatus.SameCurrencyTransactionInProgress) {
|
||||
data.status == BalanceStatus.SameCurrencyTransactionInProgress
|
||||
) {
|
||||
R.id.tv_status_verified
|
||||
} else {
|
||||
tv_status_error.text =
|
||||
getText(R.string.wallet_balance_tx_in_progress)
|
||||
lBalance.tvStatusError.text =
|
||||
getText(R.string.wallet_balance_tx_in_progress)
|
||||
R.id.group_error
|
||||
}
|
||||
showStatus(statusView)
|
||||
tv_status_error_message.hide()
|
||||
lBalance.tvStatusErrorMessage.hide()
|
||||
showBalanceWithoutToken(data, true)
|
||||
}
|
||||
BalanceStatus.Unreachable -> {
|
||||
l_balance.show()
|
||||
l_balance_error.hide()
|
||||
tv_fiat_amount.hide()
|
||||
lBalance.root.show()
|
||||
lBalanceError.root.hide()
|
||||
lBalance.tvFiatAmount.hide()
|
||||
|
||||
tv_amount.text = ""
|
||||
lBalance.tvAmount.text = ""
|
||||
|
||||
tv_status_error_message.text = data.errorMessage
|
||||
tv_status_error.text =
|
||||
getString(R.string.wallet_balance_blockchain_unreachable)
|
||||
lBalance.tvStatusErrorMessage.text = data.errorMessage
|
||||
lBalance.tvStatusError.text =
|
||||
getString(R.string.wallet_balance_blockchain_unreachable)
|
||||
|
||||
showStatus(R.id.group_error)
|
||||
tv_status_error_message.show(!data.errorMessage.isNullOrBlank())
|
||||
lBalance.tvStatusErrorMessage.show(!data.errorMessage.isNullOrBlank())
|
||||
}
|
||||
|
||||
BalanceStatus.NoAccount -> {
|
||||
l_balance.hide()
|
||||
l_balance_error.show()
|
||||
tv_error_title.text = getText(R.string.wallet_error_no_account)
|
||||
tv_error_descriptions.text =
|
||||
getString(
|
||||
R.string.wallet_error_no_account_subtitle_format,
|
||||
data.amountToCreateAccount, data.currencySymbol
|
||||
)
|
||||
lBalance.root.hide()
|
||||
lBalanceError.root.show()
|
||||
lBalanceError.tvErrorTitle.text = getText(R.string.wallet_error_no_account)
|
||||
lBalanceError.tvErrorDescriptions.text =
|
||||
getString(
|
||||
R.string.wallet_error_no_account_subtitle_format,
|
||||
data.amountToCreateAccount, data.currencySymbol
|
||||
)
|
||||
}
|
||||
}
|
||||
card_pending_transaction_warning.show(data.status == BalanceStatus.SameCurrencyTransactionInProgress)
|
||||
binding.cardPendingTransactionWarning.show(data.status == BalanceStatus.SameCurrencyTransactionInProgress)
|
||||
}
|
||||
|
||||
private fun showStatus(@IdRes viewRes: Int) {
|
||||
group_error.show(viewRes == R.id.group_error)
|
||||
tv_status_loading.show(viewRes == R.id.tv_status_loading)
|
||||
tv_status_verified.show(viewRes == R.id.tv_status_verified)
|
||||
with(binding.lWalletDetails.lBalance) {
|
||||
groupError.show(viewRes == R.id.group_error)
|
||||
tvStatusLoading.show(viewRes == R.id.tv_status_loading)
|
||||
tvStatusVerified.show(viewRes == R.id.tv_status_verified)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showBalanceWithoutToken(data: BalanceWidgetData, showAmount: Boolean) {
|
||||
tv_amount.text = if (showAmount) data.amount else ""
|
||||
if (showAmount) {
|
||||
tv_fiat_amount.show()
|
||||
tv_fiat_amount.text = data.fiatAmountFormatted
|
||||
with(binding.lWalletDetails.lBalance) {
|
||||
tvAmount.text = if (showAmount) data.amount else ""
|
||||
if (showAmount) {
|
||||
tvFiatAmount.show()
|
||||
tvFiatAmount.text = data.fiatAmountFormatted
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.transition.TransitionInflater
|
||||
import by.kirich1409.viewbindingdelegate.viewBinding
|
||||
import com.squareup.picasso.Picasso
|
||||
import com.tangem.tangem_sdk_new.extensions.dpToPx
|
||||
import com.tangem.tap.MainActivity
|
||||
|
|
@ -29,9 +30,7 @@ import com.tangem.tap.features.wallet.ui.wallet.SingleWalletView
|
|||
import com.tangem.tap.features.wallet.ui.wallet.WalletView
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.*
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.toolbar
|
||||
import kotlinx.android.synthetic.main.fragment_wallet_details.*
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
import org.rekotlin.StoreSubscriber
|
||||
|
||||
|
||||
|
|
@ -39,6 +38,8 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
|
||||
private lateinit var warningsAdapter: WarningMessagesAdapter
|
||||
|
||||
private val binding: FragmentWalletBinding by viewBinding(FragmentWalletBinding::bind)
|
||||
|
||||
private var walletView: WalletView = SingleWalletView()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -61,7 +62,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
oldState.walletState == newState.walletState
|
||||
}.select { it.walletState }
|
||||
}
|
||||
walletView.setFragment(this)
|
||||
walletView.setFragment(this, binding)
|
||||
store.dispatch(WalletAction.UpdateWallet())
|
||||
}
|
||||
|
||||
|
|
@ -73,43 +74,45 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(toolbar)
|
||||
(activity as? AppCompatActivity)?.setSupportActionBar(binding.toolbar)
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
binding.toolbar.setNavigationOnClickListener {
|
||||
store.dispatch(NavigationAction.PopBackTo(AppScreen.Home))
|
||||
}
|
||||
setupWarningsRecyclerView()
|
||||
walletView.changeWalletView(this)
|
||||
walletView.changeWalletView(this, binding)
|
||||
}
|
||||
|
||||
private fun setupWarningsRecyclerView() {
|
||||
warningsAdapter = WarningMessagesAdapter()
|
||||
val layoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
|
||||
rv_warning_messages.layoutManager = layoutManager
|
||||
rv_warning_messages.addItemDecoration(SpacesItemDecoration(rv_warning_messages.dpToPx(16f).toInt()))
|
||||
rv_warning_messages.adapter = warningsAdapter
|
||||
with(binding) {
|
||||
rvWarningMessages.layoutManager = layoutManager
|
||||
rvWarningMessages.addItemDecoration(SpacesItemDecoration(rvWarningMessages.dpToPx(16f).toInt()))
|
||||
rvWarningMessages.adapter = warningsAdapter
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun newState(state: WalletState) {
|
||||
if (activity == null) return
|
||||
if (activity == null || view == null) return
|
||||
|
||||
if (state.isMultiwalletAllowed &&
|
||||
state.primaryWallet?.currencyData?.status != BalanceStatus.EmptyCard &&
|
||||
walletView is SingleWalletView
|
||||
) {
|
||||
walletView = MultiWalletView()
|
||||
walletView.changeWalletView(this)
|
||||
walletView.changeWalletView(this, binding)
|
||||
} else if (!state.isMultiwalletAllowed && walletView is MultiWalletView) {
|
||||
walletView = SingleWalletView()
|
||||
walletView.changeWalletView(this)
|
||||
walletView.changeWalletView(this, binding)
|
||||
}
|
||||
walletView.onNewState(state)
|
||||
|
||||
if (!state.shouldShowDetails) {
|
||||
toolbar.menu.removeItem(R.id.details_menu)
|
||||
} else if (toolbar.menu.findItem(R.id.details_menu) == null) {
|
||||
toolbar.inflateMenu(R.menu.wallet)
|
||||
binding.toolbar.menu.removeItem(R.id.details_menu)
|
||||
} else if (binding.toolbar.menu.findItem(R.id.details_menu) == null) {
|
||||
binding.toolbar.inflateMenu(R.menu.wallet)
|
||||
}
|
||||
|
||||
setupNoInternetHandling(state)
|
||||
|
|
@ -117,26 +120,26 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
|
||||
showWarningsIfPresent(state.mainWarningsList)
|
||||
|
||||
srl_wallet.setOnRefreshListener {
|
||||
binding.srlWallet.setOnRefreshListener {
|
||||
if (state.state != ProgressState.Loading) {
|
||||
store.dispatch(WalletAction.LoadData)
|
||||
}
|
||||
}
|
||||
|
||||
if (state.state != ProgressState.Loading) {
|
||||
srl_wallet.isRefreshing = false
|
||||
binding.srlWallet.isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun showWarningsIfPresent(warnings: List<WarningMessage>) {
|
||||
warningsAdapter.submitList(warnings)
|
||||
rv_warning_messages.show(warnings.isNotEmpty())
|
||||
binding.rvWarningMessages.show(warnings.isNotEmpty())
|
||||
}
|
||||
|
||||
private fun setupNoInternetHandling(state: WalletState) {
|
||||
if (state.state == ProgressState.Error) {
|
||||
if (state.error == ErrorType.NoInternetConnection) {
|
||||
srl_wallet_details?.isRefreshing = false
|
||||
binding.srlWallet.isRefreshing = false
|
||||
(activity as? MainActivity)?.showSnackbar(
|
||||
text = R.string.wallet_notification_no_internet,
|
||||
buttonTitle = R.string.common_retry
|
||||
|
|
@ -152,7 +155,7 @@ class WalletFragment : Fragment(R.layout.fragment_wallet), StoreSubscriber<Walle
|
|||
.load(cardImage?.artworkId)
|
||||
.placeholder(R.drawable.card_placeholder_black)
|
||||
?.error(R.drawable.card_placeholder_black)
|
||||
?.into(iv_card)
|
||||
?.into(binding.ivCard)
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
|
|
|||
|
|
@ -1,25 +1,26 @@
|
|||
package com.tangem.tap.features.wallet.ui.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tangem.tap.common.extensions.getDrawableCompat
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.features.wallet.models.PendingTransaction
|
||||
import com.tangem.tap.features.wallet.models.PendingTransactionType
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.item_pending_transaction.view.*
|
||||
import com.tangem.wallet.databinding.ItemPendingTransactionBinding
|
||||
|
||||
class PendingTransactionsAdapter
|
||||
: ListAdapter<PendingTransaction, PendingTransactionsAdapter.TransactionsViewHolder>(DiffUtilCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TransactionsViewHolder {
|
||||
val layout = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_pending_transaction, parent, false)
|
||||
return TransactionsViewHolder(layout)
|
||||
val binding = ItemPendingTransactionBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
return TransactionsViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TransactionsViewHolder, position: Int) {
|
||||
|
|
@ -36,13 +37,13 @@ class PendingTransactionsAdapter
|
|||
) = oldItem == newItem
|
||||
}
|
||||
|
||||
class TransactionsViewHolder(val view: View) :
|
||||
RecyclerView.ViewHolder(view) {
|
||||
class TransactionsViewHolder(val binding: ItemPendingTransactionBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(transaction: PendingTransaction) {
|
||||
|
||||
if (transaction.type == PendingTransactionType.Unknown) {
|
||||
view.hide()
|
||||
binding.root.hide()
|
||||
}
|
||||
|
||||
val transactionDescriptionRes = when (transaction.type) {
|
||||
|
|
@ -60,17 +61,16 @@ class PendingTransactionsAdapter
|
|||
PendingTransactionType.Outgoing -> R.drawable.ic_arrow_right_20
|
||||
PendingTransactionType.Unknown -> return
|
||||
}
|
||||
view.tv_pending_transaction.text = view.context.getString(transactionDescriptionRes)
|
||||
binding.tvPendingTransaction.text = binding.root.getString(transactionDescriptionRes)
|
||||
|
||||
transaction.amountUi?.let { view.tv_pending_transaction_amount.text = "$it " }
|
||||
view.tv_pending_transaction_currency.text = "${transaction.currency}"
|
||||
transaction.amountUi?.let { binding.tvPendingTransactionAmount.text = "$it " }
|
||||
binding.tvPendingTransactionCurrency.text = "${transaction.currency}"
|
||||
|
||||
if (transaction.address != null) {
|
||||
view.tv_pending_transaction_address.text =
|
||||
view.context.getString(transactionAddressRes, transaction.address)
|
||||
binding.tvPendingTransactionAddress.text =
|
||||
binding.root.getString(transactionAddressRes, transaction.address)
|
||||
}
|
||||
|
||||
view.iv_pending_transaction.setImageDrawable(view.context.getDrawableCompat(image))
|
||||
binding.ivPendingTransaction.setImageDrawable(binding.root.context.getDrawableCompat(image))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.tangem.tap.features.wallet.ui.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.ListAdapter
|
||||
|
|
@ -9,6 +8,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.squareup.picasso.Picasso
|
||||
import com.tangem.blockchain.common.Blockchain
|
||||
import com.tangem.blockchain.common.Token
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.loadCurrenciesIcon
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.features.wallet.redux.Currency
|
||||
|
|
@ -17,7 +17,7 @@ import com.tangem.tap.features.wallet.redux.WalletData
|
|||
import com.tangem.tap.features.wallet.ui.BalanceStatus
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.item_currency_wallet.view.*
|
||||
import com.tangem.wallet.databinding.ItemCurrencyWalletBinding
|
||||
|
||||
class WalletAdapter
|
||||
: ListAdapter<WalletData, WalletAdapter.WalletsViewHolder>(DiffUtilCallback) {
|
||||
|
|
@ -32,8 +32,9 @@ class WalletAdapter
|
|||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WalletsViewHolder {
|
||||
val layout = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_currency_wallet, parent, false)
|
||||
val layout = ItemCurrencyWalletBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
return WalletsViewHolder(layout)
|
||||
}
|
||||
|
||||
|
|
@ -51,24 +52,24 @@ class WalletAdapter
|
|||
) = oldItem == newItem
|
||||
}
|
||||
|
||||
class WalletsViewHolder(val view: View) :
|
||||
RecyclerView.ViewHolder(view) {
|
||||
class WalletsViewHolder(val binding: ItemCurrencyWalletBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(wallet: WalletData) {
|
||||
view.tv_currency.text = wallet.currencyData.currency
|
||||
view.tv_amount.text = wallet.currencyData.amount?.takeWhile { !it.isWhitespace() }
|
||||
view.tv_currency_symbol.text = wallet.currencyData.amount?.takeLastWhile { !it.isWhitespace() }
|
||||
view.tv_amount_fiat.text = wallet.currencyData.fiatAmountFormatted
|
||||
view.tv_exchange_rate.text = wallet.fiatRateString
|
||||
view.card_wallet.setOnClickListener {
|
||||
fun bind(wallet: WalletData) = with(binding) {
|
||||
tvCurrency.text = wallet.currencyData.currency
|
||||
tvAmount.text = wallet.currencyData.amount?.takeWhile { !it.isWhitespace() }
|
||||
tvCurrencySymbol.text = wallet.currencyData.amount?.takeLastWhile { !it.isWhitespace() }
|
||||
tvAmountFiat.text = wallet.currencyData.fiatAmountFormatted
|
||||
tvExchangeRate.text = wallet.fiatRateString
|
||||
cardWallet.setOnClickListener {
|
||||
store.dispatch(WalletAction.MultiWallet.SelectWallet(wallet))
|
||||
}
|
||||
val blockchain = wallet.currency.blockchain
|
||||
val token = (wallet.currency as? Currency.Token)?.token
|
||||
|
||||
Picasso.get().loadCurrenciesIcon(
|
||||
imageView = view.iv_currency,
|
||||
textView = view.tv_token_letter,
|
||||
imageView = ivCurrency,
|
||||
textView = tvTokenLetter,
|
||||
token = token, blockchain = blockchain,
|
||||
)
|
||||
|
||||
|
|
@ -77,16 +78,16 @@ class WalletAdapter
|
|||
BalanceStatus.Loading -> {
|
||||
hideWarning()
|
||||
if (wallet.currencyData.amount == null) {
|
||||
view.tv_exchange_rate.text = view.context.getText(R.string.wallet_balance_loading)
|
||||
tvExchangeRate.text = root.getString(R.string.wallet_balance_loading)
|
||||
}
|
||||
}
|
||||
BalanceStatus.TransactionInProgress ->
|
||||
showWarning(view.context.getString(R.string.wallet_balance_tx_in_progress))
|
||||
showWarning(root.getString(R.string.wallet_balance_tx_in_progress))
|
||||
BalanceStatus.Unreachable ->
|
||||
showWarning(view.context.getString(R.string.wallet_balance_blockchain_unreachable))
|
||||
showWarning(root.getString(R.string.wallet_balance_blockchain_unreachable))
|
||||
|
||||
BalanceStatus.NoAccount ->
|
||||
showWarning(view.context.getString(R.string.wallet_error_no_account))
|
||||
showWarning(root.getString(R.string.wallet_error_no_account))
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
|
@ -94,7 +95,7 @@ class WalletAdapter
|
|||
|
||||
private fun showWarning(message: String) {
|
||||
toggleWarning(true)
|
||||
view.tv_status_error_message.text = message
|
||||
binding.tvStatusErrorMessage.text = message
|
||||
}
|
||||
|
||||
private fun hideWarning() {
|
||||
|
|
@ -102,8 +103,8 @@ class WalletAdapter
|
|||
}
|
||||
|
||||
private fun toggleWarning(show: Boolean) {
|
||||
view.tv_exchange_rate.show(!show)
|
||||
view.tv_status_error_message.show(show)
|
||||
binding.tvExchangeRate.show(!show)
|
||||
binding.tvStatusErrorMessage.show(show)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,25 +10,23 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
|
||||
import com.google.android.play.core.review.ReviewManagerFactory
|
||||
import com.tangem.tap.common.analytics.AnalyticsEvent
|
||||
import com.tangem.tap.common.extensions.getActivity
|
||||
import com.tangem.tap.common.extensions.getString
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.redux.global.GlobalAction
|
||||
import com.tangem.tap.domain.configurable.warningMessage.WarningMessage
|
||||
import com.tangem.tap.features.feedback.RateCanBeBetterEmail
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.layout_warning.view.*
|
||||
import com.tangem.wallet.databinding.LayoutWarningBinding
|
||||
import timber.log.Timber
|
||||
|
||||
class WarningMessagesAdapter : ListAdapter<WarningMessage, WarningMessageVH>(DiffUtilCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WarningMessageVH {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
val layout = inflater.inflate(R.layout.layout_warning, parent, false)
|
||||
return WarningMessageVH(layout)
|
||||
val binding = LayoutWarningBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
return WarningMessageVH(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: WarningMessageVH, position: Int) {
|
||||
|
|
@ -44,7 +42,7 @@ class WarningMessagesAdapter : ListAdapter<WarningMessage, WarningMessageVH>(Dif
|
|||
}
|
||||
}
|
||||
|
||||
class WarningMessageVH(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
class WarningMessageVH(val binding: LayoutWarningBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(warning: WarningMessage) {
|
||||
setBgColor(warning.priority)
|
||||
|
|
@ -52,12 +50,12 @@ class WarningMessageVH(val view: View) : RecyclerView.ViewHolder(view) {
|
|||
setupControlButtons(warning)
|
||||
}
|
||||
|
||||
private fun setText(warning: WarningMessage) {
|
||||
private fun setText(warning: WarningMessage) = with(binding) {
|
||||
fun getString(resId: Int?, default: String, formatArgs: String? = null) =
|
||||
if (resId == null) default else view.context.getString(resId, formatArgs)
|
||||
if (resId == null) default else root.getString(resId, formatArgs)
|
||||
|
||||
view.tv_title.text = getString(warning.titleResId, warning.title)
|
||||
view.tv_message.text = getString(
|
||||
tvTitle.text = getString(warning.titleResId, warning.title)
|
||||
tvMessage.text = getString(
|
||||
resId = warning.messageResId, default = warning.message, formatArgs = warning.messageFormatArg
|
||||
)
|
||||
}
|
||||
|
|
@ -68,17 +66,17 @@ class WarningMessageVH(val view: View) : RecyclerView.ViewHolder(view) {
|
|||
WarningMessage.Priority.Warning -> R.color.warning_warning
|
||||
WarningMessage.Priority.Critical -> R.color.warning_critical
|
||||
}
|
||||
view.card_view.setCardBackgroundColor(view.context.resources.getColor(color))
|
||||
binding.cardView.setCardBackgroundColor(binding.root.getColor(color))
|
||||
}
|
||||
|
||||
private fun setupControlButtons(warning: WarningMessage) = when (warning.type) {
|
||||
WarningMessage.Type.Permanent, WarningMessage.Type.TestCard -> {
|
||||
view.group_controls_temporary.hide()
|
||||
view.group_controls_rating.hide()
|
||||
binding.groupControlsTemporary.hide()
|
||||
binding.groupControlsRating.hide()
|
||||
}
|
||||
WarningMessage.Type.Temporary -> {
|
||||
view.group_controls_rating.hide()
|
||||
view.group_controls_temporary.show()
|
||||
binding.groupControlsRating.hide()
|
||||
binding.groupControlsTemporary.show()
|
||||
val buttonAction =
|
||||
when (warning.titleResId) {
|
||||
R.string.warning_important_security_info -> {
|
||||
|
|
@ -92,29 +90,29 @@ class WarningMessageVH(val view: View) : RecyclerView.ViewHolder(view) {
|
|||
}
|
||||
}
|
||||
}
|
||||
val buttonTitle = view.getString(
|
||||
val buttonTitle = binding.root.getString(
|
||||
warning.buttonTextId ?: R.string.how_to_got_it_button
|
||||
)
|
||||
view.btn_got_it.setOnClickListener (buttonAction)
|
||||
view.btn_got_it.text = buttonTitle
|
||||
binding.btnGotIt.setOnClickListener (buttonAction)
|
||||
binding.btnGotIt.text = buttonTitle
|
||||
}
|
||||
WarningMessage.Type.AppRating -> {
|
||||
view.group_controls_temporary.hide()
|
||||
view.group_controls_rating.show()
|
||||
binding.groupControlsTemporary.hide()
|
||||
binding.groupControlsRating.show()
|
||||
val analyticsHandler = store.state.globalState.analyticsHandlers
|
||||
view.btn_close.setOnClickListener {
|
||||
binding.btnClose.setOnClickListener {
|
||||
analyticsHandler?.triggerEvent(AnalyticsEvent.APP_RATING_DISMISS)
|
||||
store.dispatch(GlobalAction.HideWarningMessage(warning))
|
||||
store.dispatch(WalletAction.Warnings.AppRating.RemindLater)
|
||||
}
|
||||
view.btn_can_be_better.setOnClickListener {
|
||||
binding.btnCanBeBetter.setOnClickListener {
|
||||
analyticsHandler?.triggerEvent(AnalyticsEvent.APP_RATING_NEGATIVE)
|
||||
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
|
||||
store.dispatch(GlobalAction.HideWarningMessage(warning))
|
||||
store.dispatch(GlobalAction.SendFeedback(RateCanBeBetterEmail()))
|
||||
}
|
||||
view.btn_really_cool.setOnClickListener {
|
||||
val activity = view.context.getActivity() ?: return@setOnClickListener
|
||||
binding.btnReallyCool.setOnClickListener {
|
||||
val activity = binding.root.context.getActivity() ?: return@setOnClickListener
|
||||
|
||||
analyticsHandler?.triggerEvent(AnalyticsEvent.APP_RATING_POSITIVE)
|
||||
store.dispatch(WalletAction.Warnings.AppRating.SetNeverToShow)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
package com.tangem.tap.features.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.recyclerview.widget.*
|
||||
|
|
@ -12,14 +13,22 @@ import com.tangem.tap.common.extensions.toFormattedString
|
|||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.dialog_wallet_send.*
|
||||
import kotlinx.android.synthetic.main.item_wallet_amount_to_send.view.*
|
||||
|
||||
import com.tangem.wallet.databinding.DialogWalletSendBinding
|
||||
import com.tangem.wallet.databinding.ItemWalletAmountToSendBinding
|
||||
|
||||
class AmountToSendDialog(context: Context) : BottomSheetDialog(context) {
|
||||
|
||||
init {
|
||||
this.setContentView(R.layout.dialog_wallet_send)
|
||||
var binding: DialogWalletSendBinding? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = DialogWalletSendBinding.inflate(LayoutInflater.from(context))
|
||||
setContentView(binding!!.root)
|
||||
}
|
||||
|
||||
override fun setOnCancelListener(listener: DialogInterface.OnCancelListener?) {
|
||||
super.setOnCancelListener(listener)
|
||||
binding = null
|
||||
}
|
||||
|
||||
fun show(amounts: List<Amount>?) {
|
||||
|
|
@ -27,15 +36,15 @@ class AmountToSendDialog(context: Context) : BottomSheetDialog(context) {
|
|||
store.dispatch(WalletAction.Send.Cancel)
|
||||
}
|
||||
|
||||
rv_amounts_to_send.layoutManager = LinearLayoutManager(context)
|
||||
binding!!.rvAmountsToSend.layoutManager = LinearLayoutManager(context)
|
||||
val dividerItemDecoration = DividerItemDecoration(
|
||||
ContextThemeWrapper(rv_amounts_to_send.context, R.style.AppTheme),
|
||||
ContextThemeWrapper(binding!!.root.context, R.style.AppTheme),
|
||||
DividerItemDecoration.VERTICAL
|
||||
)
|
||||
rv_amounts_to_send.addItemDecoration(dividerItemDecoration)
|
||||
binding!!.rvAmountsToSend.addItemDecoration(dividerItemDecoration)
|
||||
|
||||
val viewAdapter = ChooseAmountAdapter()
|
||||
rv_amounts_to_send.adapter = viewAdapter
|
||||
binding!!.rvAmountsToSend.adapter = viewAdapter
|
||||
|
||||
viewAdapter.submitList(amounts)
|
||||
|
||||
|
|
@ -48,9 +57,10 @@ class ChooseAmountAdapter
|
|||
: ListAdapter<Amount, ChooseAmountAdapter.AmountViewHolder>(DiffUtilCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AmountViewHolder {
|
||||
val layout = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_wallet_amount_to_send, parent, false)
|
||||
return AmountViewHolder(layout)
|
||||
val binding = ItemWalletAmountToSendBinding.inflate(
|
||||
LayoutInflater.from(parent.context), parent, false
|
||||
)
|
||||
return AmountViewHolder(binding)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: AmountViewHolder, position: Int) {
|
||||
|
|
@ -67,13 +77,13 @@ class ChooseAmountAdapter
|
|||
) = oldItem == newItem
|
||||
}
|
||||
|
||||
class AmountViewHolder(val view: View) :
|
||||
RecyclerView.ViewHolder(view) {
|
||||
class AmountViewHolder(val binding: ItemWalletAmountToSendBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(amount: Amount) {
|
||||
view.tv_currency_symbol.text = amount.currencySymbol
|
||||
view.tv_amount.text = amount.value?.toFormattedString(amount.decimals)
|
||||
view.setOnClickListener {
|
||||
fun bind(amount: Amount) = with(binding) {
|
||||
tvCurrencySymbol.text = amount.currencySymbol
|
||||
tvAmount.text = amount.value?.toFormattedString(amount.decimals)
|
||||
root.setOnClickListener {
|
||||
store.dispatch(WalletAction.Send.Cancel)
|
||||
store.dispatch(WalletAction.Send(amount))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,36 @@
|
|||
package com.tangem.tap.features.wallet.ui.dialogs
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.tangem.tap.features.wallet.redux.WalletAction
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.dialog_wallet_trade.*
|
||||
import com.tangem.wallet.databinding.DialogWalletTradeBinding
|
||||
|
||||
class ChooseTradeActionDialog(context: Context) : BottomSheetDialog(context) {
|
||||
|
||||
init {
|
||||
this.setContentView(R.layout.dialog_wallet_trade)
|
||||
var binding: DialogWalletTradeBinding? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = DialogWalletTradeBinding.inflate(LayoutInflater.from(context))
|
||||
setContentView(binding!!.root)
|
||||
}
|
||||
|
||||
override fun show() {
|
||||
super.show()
|
||||
|
||||
this.setOnDismissListener {
|
||||
binding = null
|
||||
store.dispatch(WalletAction.HideDialog)
|
||||
}
|
||||
|
||||
dialog_btn_buy.setOnClickListener {
|
||||
binding!!.dialogBtnBuy.setOnClickListener {
|
||||
store.dispatch(WalletAction.TradeCryptoAction.Buy)
|
||||
dismiss()
|
||||
}
|
||||
dialog_btn_sell.setOnClickListener {
|
||||
binding!!.dialogBtnSell.setOnClickListener {
|
||||
store.dispatch(WalletAction.TradeCryptoAction.Sell)
|
||||
dismiss()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,64 +18,64 @@ import com.tangem.tap.features.wallet.ui.adapters.WalletAdapter
|
|||
import com.tangem.tap.features.wallet.ui.dialogs.SignedHashesWarningDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.card_balance.*
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.*
|
||||
import kotlinx.android.synthetic.main.layout_balance_error.*
|
||||
import kotlinx.android.synthetic.main.layout_wallet_long_buttons.*
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
|
||||
|
||||
class MultiWalletView : WalletView {
|
||||
|
||||
private var fragment: WalletFragment? = null
|
||||
private var binding: FragmentWalletBinding? = null
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
private lateinit var walletsAdapter: WalletAdapter
|
||||
|
||||
|
||||
override fun changeWalletView(fragment: WalletFragment) {
|
||||
setFragment(fragment)
|
||||
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
setFragment(fragment, binding)
|
||||
onViewCreated()
|
||||
showMultiWalletView(fragment)
|
||||
setupButtons(fragment)
|
||||
showMultiWalletView(binding)
|
||||
setupButtons(binding)
|
||||
}
|
||||
|
||||
|
||||
private fun showMultiWalletView(fragment: WalletFragment) = with(fragment) {
|
||||
tv_twin_card_number.hide()
|
||||
rv_pending_transaction.hide()
|
||||
l_card_balance.hide()
|
||||
l_address.hide()
|
||||
l_buttons_short.hide()
|
||||
l_buttons_long.hide()
|
||||
btn_scan_multiwallet?.show()
|
||||
rv_multiwallet.show()
|
||||
btn_add_token.show()
|
||||
setupWalletCardNumber(fragment)
|
||||
private fun showMultiWalletView(binding: FragmentWalletBinding) = with(binding) {
|
||||
tvTwinCardNumber.hide()
|
||||
rvPendingTransaction.hide()
|
||||
lCardBalance.root.hide()
|
||||
lAddress.root.hide()
|
||||
lButtonsShort.root.hide()
|
||||
lButtonsLong.root.hide()
|
||||
btnScanMultiwallet.show()
|
||||
rvMultiwallet.show()
|
||||
btnAddToken.show()
|
||||
setupWalletCardNumber(binding)
|
||||
}
|
||||
|
||||
private fun setupWalletCardNumber(fragment: WalletFragment) = with(fragment) {
|
||||
private fun setupWalletCardNumber(binding: FragmentWalletBinding) = with(binding) {
|
||||
val card = store.state.globalState.scanResponse?.card
|
||||
if (card?.backupStatus is Card.BackupStatus.Active) {
|
||||
val cardCount = (card.backupStatus as Card.BackupStatus.Active).cardCount + 1
|
||||
tv_twin_card_number.show()
|
||||
tv_twin_card_number.text =
|
||||
getString(R.string.wallet_twins_chip_format, 1, cardCount)
|
||||
tvTwinCardNumber.show()
|
||||
tvTwinCardNumber.text =
|
||||
fragment?.getString(R.string.wallet_twins_chip_format, 1, cardCount)
|
||||
} else {
|
||||
tv_twin_card_number.hide()
|
||||
tvTwinCardNumber.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setupButtons(fragment: WalletFragment) = with(fragment) {
|
||||
btn_scan_multiwallet?.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
private fun setupButtons(binding: FragmentWalletBinding) = with(binding) {
|
||||
btnScanMultiwallet.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
}
|
||||
|
||||
override fun setFragment(fragment: WalletFragment) {
|
||||
override fun setFragment(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
this.fragment = fragment
|
||||
this.binding = binding
|
||||
}
|
||||
|
||||
override fun removeFragment() {
|
||||
this.fragment = null
|
||||
this.binding = null
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
|
|
@ -86,37 +86,42 @@ class MultiWalletView : WalletView {
|
|||
val fragment = fragment ?: return
|
||||
walletsAdapter = WalletAdapter()
|
||||
walletsAdapter.setHasStableIds(true)
|
||||
fragment.rv_multiwallet.layoutManager = LinearLayoutManager(fragment.requireContext())
|
||||
fragment.rv_multiwallet.adapter = walletsAdapter
|
||||
binding?.rvMultiwallet?.layoutManager = LinearLayoutManager(fragment.requireContext())
|
||||
binding?.rvMultiwallet?.adapter = walletsAdapter
|
||||
}
|
||||
|
||||
override fun onNewState(state: WalletState) {
|
||||
val fragment = fragment ?: return
|
||||
val binding = binding ?: return
|
||||
|
||||
walletsAdapter.submitList(state.wallets, state.primaryBlockchain, state.primaryToken)
|
||||
|
||||
fragment.btn_add_token?.setOnClickListener {
|
||||
binding.btnAddToken.setOnClickListener {
|
||||
store.dispatch(TokensAction.LoadCurrencies)
|
||||
store.dispatch(TokensAction.SetAddedCurrencies(state.wallets))
|
||||
store.dispatch(NavigationAction.NavigateTo(AppScreen.AddTokens))
|
||||
}
|
||||
handleErrorStates(state, fragment)
|
||||
handleErrorStates(state = state, binding = binding, fragment = fragment)
|
||||
handleDialogs(state.walletDialog)
|
||||
}
|
||||
|
||||
private fun handleErrorStates(state: WalletState, fragment: WalletFragment) {
|
||||
private fun handleErrorStates(
|
||||
state: WalletState,
|
||||
binding: FragmentWalletBinding,
|
||||
fragment: WalletFragment
|
||||
) {
|
||||
when (state.primaryWallet?.currencyData?.status) {
|
||||
BalanceStatus.EmptyCard -> {
|
||||
showErrorState(
|
||||
fragment,
|
||||
binding,
|
||||
fragment.getText(R.string.wallet_error_empty_card),
|
||||
fragment.getString(R.string.wallet_error_empty_card_subtitle)
|
||||
)
|
||||
configureButtonsForEmptyWalletState(fragment)
|
||||
configureButtonsForEmptyWalletState(binding)
|
||||
}
|
||||
BalanceStatus.UnknownBlockchain -> {
|
||||
showErrorState(
|
||||
fragment,
|
||||
binding,
|
||||
fragment.getText(R.string.wallet_error_unsupported_blockchain),
|
||||
fragment.getString(R.string.wallet_error_unsupported_blockchain_subtitle)
|
||||
)
|
||||
|
|
@ -125,24 +130,28 @@ class MultiWalletView : WalletView {
|
|||
}
|
||||
|
||||
private fun showErrorState(
|
||||
fragment: WalletFragment, errorTitle: CharSequence, errorDescription: CharSequence,
|
||||
) = with(fragment) {
|
||||
l_card_balance.show()
|
||||
l_balance.hide()
|
||||
l_balance_error.show()
|
||||
rv_multiwallet.hide()
|
||||
btn_add_token.hide()
|
||||
tv_error_title.text = errorTitle
|
||||
tv_error_descriptions.text = errorDescription
|
||||
binding: FragmentWalletBinding, errorTitle: CharSequence, errorDescription: CharSequence,
|
||||
) = with(binding) {
|
||||
lCardBalance.root.show()
|
||||
with(lCardBalance) {
|
||||
lBalance.root.hide()
|
||||
lBalanceError.root.show()
|
||||
rvMultiwallet.show()
|
||||
btnAddToken.hide()
|
||||
lBalanceError.tvErrorTitle.text = errorTitle
|
||||
lBalanceError.tvErrorDescriptions.text = errorDescription
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureButtonsForEmptyWalletState(fragment: WalletFragment) = with(fragment) {
|
||||
btn_scan_multiwallet.hide()
|
||||
l_buttons_long.show()
|
||||
btn_scan_long.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
btn_confirm_long.setOnClickListener { store.dispatch(WalletAction.CreateWallet) }
|
||||
btn_confirm_long.text = fragment.getText(R.string.wallet_button_create_wallet)
|
||||
}
|
||||
private fun configureButtonsForEmptyWalletState(binding: FragmentWalletBinding) =
|
||||
with(binding) {
|
||||
btnScanMultiwallet.hide()
|
||||
lButtonsLong.root.show()
|
||||
lButtonsLong.btnScanLong.setOnClickListener { store.dispatch(WalletAction.Scan) }
|
||||
lButtonsLong.btnConfirmLong.setOnClickListener { store.dispatch(WalletAction.CreateWallet) }
|
||||
lButtonsLong.btnConfirmLong.text =
|
||||
fragment?.getText(R.string.wallet_button_create_wallet)
|
||||
}
|
||||
|
||||
private fun handleDialogs(walletDialog: StateDialog?) {
|
||||
val fragment = fragment ?: return
|
||||
|
|
|
|||
|
|
@ -5,7 +5,10 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.tangem.tap.common.extensions.*
|
||||
import com.tangem.tap.common.extensions.beginDelayedTransition
|
||||
import com.tangem.tap.common.extensions.fitChipsByGroupWidth
|
||||
import com.tangem.tap.common.extensions.hide
|
||||
import com.tangem.tap.common.extensions.show
|
||||
import com.tangem.tap.common.redux.StateDialog
|
||||
import com.tangem.tap.domain.twins.TwinCardNumber
|
||||
import com.tangem.tap.features.onboarding.products.twins.redux.TwinCardsState
|
||||
|
|
@ -15,42 +18,43 @@ import com.tangem.tap.features.wallet.ui.BalanceWidget
|
|||
import com.tangem.tap.features.wallet.ui.MultipleAddressUiHelper
|
||||
import com.tangem.tap.features.wallet.ui.WalletFragment
|
||||
import com.tangem.tap.features.wallet.ui.adapters.PendingTransactionsAdapter
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.*
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.AmountToSendDialog
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.ChooseTradeActionDialog
|
||||
import com.tangem.tap.features.wallet.ui.dialogs.SignedHashesWarningDialog
|
||||
import com.tangem.tap.store
|
||||
import com.tangem.wallet.R
|
||||
import kotlinx.android.synthetic.main.card_balance.*
|
||||
import kotlinx.android.synthetic.main.fragment_wallet.*
|
||||
import kotlinx.android.synthetic.main.layout_address.*
|
||||
import kotlinx.android.synthetic.main.layout_wallet_long_buttons.*
|
||||
import kotlinx.android.synthetic.main.layout_wallet_short_buttons.*
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
|
||||
class SingleWalletView : WalletView {
|
||||
|
||||
private lateinit var pendingTransactionAdapter: PendingTransactionsAdapter
|
||||
private var fragment: WalletFragment? = null
|
||||
private var binding: FragmentWalletBinding? = null
|
||||
private var dialog: Dialog? = null
|
||||
|
||||
override fun setFragment(fragment: WalletFragment) {
|
||||
override fun setFragment(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
this.fragment = fragment
|
||||
this.binding = binding
|
||||
}
|
||||
|
||||
override fun removeFragment() {
|
||||
fragment = null
|
||||
binding = null
|
||||
}
|
||||
|
||||
override fun changeWalletView(fragment: WalletFragment) {
|
||||
setFragment(fragment)
|
||||
override fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding) {
|
||||
setFragment(fragment, binding)
|
||||
onViewCreated()
|
||||
showSingleWalletView(fragment)
|
||||
showSingleWalletView(binding)
|
||||
}
|
||||
|
||||
private fun showSingleWalletView(fragment: WalletFragment) = with(fragment) {
|
||||
rv_multiwallet.hide()
|
||||
btn_add_token.hide()
|
||||
btn_scan_multiwallet?.hide()
|
||||
rv_pending_transaction.hide()
|
||||
l_card_balance.show()
|
||||
l_address.show()
|
||||
private fun showSingleWalletView(binding: FragmentWalletBinding) = with(binding) {
|
||||
rvMultiwallet.hide()
|
||||
btnAddToken.hide()
|
||||
btnScanMultiwallet.hide()
|
||||
rvPendingTransaction.hide()
|
||||
lCardBalance.root.show()
|
||||
lAddress.root.show()
|
||||
}
|
||||
|
||||
override fun onViewCreated() {
|
||||
|
|
@ -61,17 +65,19 @@ class SingleWalletView : WalletView {
|
|||
private fun setupTransactionsRecyclerView() {
|
||||
val fragment = fragment ?: return
|
||||
pendingTransactionAdapter = PendingTransactionsAdapter()
|
||||
fragment.rv_pending_transaction.layoutManager = LinearLayoutManager(fragment.requireContext())
|
||||
fragment.rv_pending_transaction.adapter = pendingTransactionAdapter
|
||||
binding?.rvPendingTransaction?.layoutManager =
|
||||
LinearLayoutManager(fragment.requireContext())
|
||||
binding?.rvPendingTransaction?.adapter = pendingTransactionAdapter
|
||||
}
|
||||
|
||||
override fun onNewState(state: WalletState) {
|
||||
val fragment = fragment ?: return
|
||||
val binding = binding ?: return
|
||||
state.primaryWallet ?: return
|
||||
|
||||
setupTwinCards(state.twinCardsState, fragment)
|
||||
setupButtons(state.primaryWallet, state.isTangemTwins, fragment)
|
||||
setupAddressCard(state.primaryWallet, fragment)
|
||||
setupTwinCards(state.twinCardsState, binding)
|
||||
setupButtons(state.primaryWallet, state.isTangemTwins, binding)
|
||||
setupAddressCard(state.primaryWallet, binding)
|
||||
showPendingTransactionsIfPresent(state.primaryWallet.pendingTransactions)
|
||||
setupBalance(state, state.primaryWallet)
|
||||
handleDialogs(state.walletDialog, fragment)
|
||||
|
|
@ -79,75 +85,81 @@ class SingleWalletView : WalletView {
|
|||
|
||||
private fun showPendingTransactionsIfPresent(pendingTransactions: List<PendingTransaction>) {
|
||||
pendingTransactionAdapter.submitList(pendingTransactions)
|
||||
fragment?.rv_pending_transaction?.show(pendingTransactions.isNotEmpty())
|
||||
binding?.rvPendingTransaction?.show(pendingTransactions.isNotEmpty())
|
||||
}
|
||||
|
||||
|
||||
private fun setupBalance(state: WalletState, primaryWallet: WalletData) {
|
||||
fragment?.apply {
|
||||
this.l_balance.show()
|
||||
BalanceWidget(this, primaryWallet.currencyData, state.isTangemTwins).setup()
|
||||
val fragment = fragment ?: return
|
||||
binding?.apply {
|
||||
lCardBalance.lBalance.root.show()
|
||||
BalanceWidget(
|
||||
binding = this.lCardBalance,
|
||||
fragment = fragment,
|
||||
data = primaryWallet.currencyData,
|
||||
isTwinCard = state.isTangemTwins
|
||||
).setup()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupTwinCards(
|
||||
twinCardsState: TwinCardsState?, fragment: WalletFragment
|
||||
) = with(fragment) {
|
||||
twinCardsState: TwinCardsState?, binding: FragmentWalletBinding
|
||||
) = with(binding) {
|
||||
twinCardsState?.cardNumber?.let { cardNumber ->
|
||||
tv_twin_card_number.show()
|
||||
tvTwinCardNumber.show()
|
||||
val number = when (cardNumber) {
|
||||
TwinCardNumber.First -> 1
|
||||
TwinCardNumber.Second -> 2
|
||||
}
|
||||
tv_twin_card_number.text =
|
||||
this.getString(R.string.wallet_twins_chip_format, number, 2)
|
||||
tvTwinCardNumber.text =
|
||||
fragment?.getString(R.string.wallet_twins_chip_format, number, 2)
|
||||
}
|
||||
if (twinCardsState?.cardNumber == null) {
|
||||
tv_twin_card_number.hide()
|
||||
tvTwinCardNumber.hide()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupButtons(
|
||||
state: WalletData, isTwinsWallet: Boolean, fragment: WalletFragment
|
||||
) = with(fragment){
|
||||
state: WalletData, isTwinsWallet: Boolean, binding: FragmentWalletBinding
|
||||
) = with(binding) {
|
||||
|
||||
setupButtonsType(state, fragment)
|
||||
setupButtonsType(state, binding)
|
||||
|
||||
val btnConfirm = if (state.tradeCryptoState.sellingAllowed ||
|
||||
state.tradeCryptoState.buyingAllowed
|
||||
) {
|
||||
btn_confirm_short
|
||||
lButtonsShort.btnConfirmShort
|
||||
} else {
|
||||
btn_confirm_long
|
||||
lButtonsLong.btnConfirmLong
|
||||
}
|
||||
|
||||
val btnScan = if (state.tradeCryptoState.sellingAllowed ||
|
||||
state.tradeCryptoState.buyingAllowed
|
||||
) {
|
||||
btn_scan_short
|
||||
lButtonsShort.btnScanShort
|
||||
} else {
|
||||
btn_scan_long
|
||||
lButtonsLong.btnScanLong
|
||||
}
|
||||
|
||||
setupConfirmButton(state, btnConfirm, fragment, isTwinsWallet)
|
||||
setupConfirmButton(state, btnConfirm, isTwinsWallet)
|
||||
|
||||
btnScan.setOnClickListener {
|
||||
store.dispatch(WalletAction.Scan)
|
||||
}
|
||||
|
||||
btn_copy.setOnClickListener {
|
||||
lAddress.btnCopy.setOnClickListener {
|
||||
state.walletAddresses?.selectedAddress?.address?.let { addressString ->
|
||||
store.dispatch(WalletAction.CopyAddress(addressString, fragment.requireContext()))
|
||||
store.dispatch(WalletAction.CopyAddress(addressString, fragment!!.requireContext()))
|
||||
}
|
||||
}
|
||||
btn_show_qr.setOnClickListener {
|
||||
lAddress.btnShowQr.setOnClickListener {
|
||||
store.dispatch(WalletAction.ShowDialog.QrCode)
|
||||
}
|
||||
|
||||
setupTradeButton(fragment, state.tradeCryptoState)
|
||||
setupTradeButton(binding, state.tradeCryptoState)
|
||||
}
|
||||
|
||||
private fun setupTradeButton(fragment: WalletFragment, tradeCryptoState: TradeCryptoState) {
|
||||
private fun setupTradeButton(binding: FragmentWalletBinding, tradeCryptoState: TradeCryptoState) {
|
||||
val allowedToBuy = tradeCryptoState.buyingAllowed
|
||||
val allowedToSell = tradeCryptoState.sellingAllowed
|
||||
val action = when {
|
||||
|
|
@ -160,7 +172,7 @@ class SingleWalletView : WalletView {
|
|||
allowedToBuy && !allowedToSell -> R.string.wallet_button_buy
|
||||
!allowedToBuy && allowedToSell -> R.string.wallet_button_sell
|
||||
allowedToBuy && allowedToSell -> R.string.wallet_button_trade
|
||||
else -> R.string.wallet_button_trade
|
||||
else -> R.string.wallet_button_trade
|
||||
}
|
||||
val icon = when {
|
||||
allowedToBuy && !allowedToSell -> R.drawable.ic_arrow_up_short_btn
|
||||
|
|
@ -168,27 +180,27 @@ class SingleWalletView : WalletView {
|
|||
allowedToBuy && allowedToSell -> R.drawable.ic_arrows_up_down_short_btn
|
||||
else -> null
|
||||
}
|
||||
with(fragment) {
|
||||
btn_trade.text = getText(text)
|
||||
btn_trade.setCompoundDrawablesWithIntrinsicBounds(0, icon ?: 0, 0, 0)
|
||||
btn_trade.setOnClickListener { if (action != null) store.dispatch(action) }
|
||||
with(binding) {
|
||||
lButtonsShort.btnTrade.text = fragment?.getText(text)
|
||||
lButtonsShort.btnTrade.setCompoundDrawablesWithIntrinsicBounds(0, icon ?: 0, 0, 0)
|
||||
lButtonsShort.btnTrade.setOnClickListener { if (action != null) store.dispatch(action) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupButtonsType(state: WalletData, fragment: WalletFragment) = with(fragment) {
|
||||
private fun setupButtonsType(state: WalletData, binding: FragmentWalletBinding) = with(binding) {
|
||||
if (state.tradeCryptoState.sellingAllowed ||
|
||||
state.tradeCryptoState.buyingAllowed
|
||||
) {
|
||||
l_buttons_long.hide()
|
||||
l_buttons_short.show()
|
||||
lButtonsLong.root.hide()
|
||||
lButtonsShort.root.show()
|
||||
} else {
|
||||
l_buttons_long.show()
|
||||
l_buttons_short.hide()
|
||||
lButtonsLong.root.show()
|
||||
lButtonsShort.root.hide()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupConfirmButton(
|
||||
state: WalletData, btnConfirm: Button, fragment: WalletFragment, isTwinsWallet: Boolean,
|
||||
state: WalletData, btnConfirm: Button, isTwinsWallet: Boolean,
|
||||
) {
|
||||
val buttonTitle = when (state.mainButton) {
|
||||
is WalletMainButton.SendButton -> R.string.wallet_button_send
|
||||
|
|
@ -200,7 +212,7 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
}
|
||||
}
|
||||
btnConfirm.text = fragment.getString(buttonTitle)
|
||||
btnConfirm.text = fragment?.getString(buttonTitle)
|
||||
btnConfirm.isEnabled = state.mainButton.enabled
|
||||
btnConfirm.setOnClickListener {
|
||||
when (state.mainButton) {
|
||||
|
|
@ -211,33 +223,38 @@ class SingleWalletView : WalletView {
|
|||
}
|
||||
|
||||
|
||||
private fun setupAddressCard(state: WalletData, fragment: WalletFragment) = with(fragment) {
|
||||
private fun setupAddressCard(state: WalletData, binding: FragmentWalletBinding) = with(binding.lAddress) {
|
||||
if (state.walletAddresses != null && state.currency is Currency.Blockchain) {
|
||||
l_address?.show()
|
||||
binding.lAddress.root.show()
|
||||
if (state.shouldShowMultipleAddress()) {
|
||||
(l_address as? ViewGroup)?.beginDelayedTransition()
|
||||
chip_group_address_type.show()
|
||||
chip_group_address_type.fitChipsByGroupWidth()
|
||||
(binding.lAddress.root as? ViewGroup)?.beginDelayedTransition()
|
||||
chipGroupAddressType.show()
|
||||
chipGroupAddressType.fitChipsByGroupWidth()
|
||||
|
||||
val checkedId = MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type)
|
||||
if (checkedId != View.NO_ID) chip_group_address_type.check(checkedId)
|
||||
val checkedId =
|
||||
MultipleAddressUiHelper.typeToId(state.walletAddresses.selectedAddress.type)
|
||||
if (checkedId != View.NO_ID) chipGroupAddressType.check(checkedId)
|
||||
|
||||
chip_group_address_type.setOnCheckedChangeListener { group, checkedId ->
|
||||
chipGroupAddressType.setOnCheckedChangeListener { group, checkedId ->
|
||||
if (checkedId == -1) return@setOnCheckedChangeListener
|
||||
val type = MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain)
|
||||
val type =
|
||||
MultipleAddressUiHelper.idToType(checkedId, state.currency.blockchain)
|
||||
type?.let { store.dispatch(WalletAction.ChangeSelectedAddress(type)) }
|
||||
}
|
||||
} else {
|
||||
chip_group_address_type.hide()
|
||||
chipGroupAddressType.hide()
|
||||
}
|
||||
tv_address.text = state.walletAddresses.selectedAddress.address
|
||||
tv_explore?.setOnClickListener {
|
||||
store.dispatch(WalletAction.ExploreAddress(
|
||||
tvAddress.text = state.walletAddresses.selectedAddress.address
|
||||
tvExplore.setOnClickListener {
|
||||
store.dispatch(
|
||||
WalletAction.ExploreAddress(
|
||||
state.walletAddresses.selectedAddress.exploreUrl,
|
||||
fragment.requireContext()))
|
||||
fragment!!.requireContext()
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
l_address?.hide()
|
||||
binding.lAddress.root.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,15 @@ package com.tangem.tap.features.wallet.ui.wallet
|
|||
|
||||
import com.tangem.tap.features.wallet.redux.WalletState
|
||||
import com.tangem.tap.features.wallet.ui.WalletFragment
|
||||
import com.tangem.wallet.databinding.FragmentWalletBinding
|
||||
|
||||
interface WalletView {
|
||||
|
||||
fun setFragment(fragment: WalletFragment)
|
||||
fun setFragment(fragment: WalletFragment, binding: FragmentWalletBinding)
|
||||
|
||||
fun removeFragment()
|
||||
|
||||
fun changeWalletView(fragment: WalletFragment)
|
||||
fun changeWalletView(fragment: WalletFragment, binding: FragmentWalletBinding)
|
||||
|
||||
fun onViewCreated()
|
||||
|
||||
|
|
|
|||
BIN
app/src/main/res/drawable-hdpi/floating_cards.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
app/src/main/res/drawable-hdpi/meet_tangem.png
Normal file
|
After Width: | Height: | Size: 307 KiB |
BIN
app/src/main/res/drawable-hdpi/revolutionary_wallet.png
Normal file
|
After Width: | Height: | Size: 284 KiB |
BIN
app/src/main/res/drawable-hdpi/thousands_of_currencies.png
Normal file
|
After Width: | Height: | Size: 260 KiB |
BIN
app/src/main/res/drawable-hdpi/wallet_for_everyone.png
Normal file
|
After Width: | Height: | Size: 205 KiB |
BIN
app/src/main/res/drawable-mdpi/floating_cards.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
app/src/main/res/drawable-mdpi/meet_tangem.png
Normal file
|
After Width: | Height: | Size: 154 KiB |
BIN
app/src/main/res/drawable-mdpi/revolutionary_wallet.png
Normal file
|
After Width: | Height: | Size: 124 KiB |
BIN
app/src/main/res/drawable-mdpi/thousands_of_currencies.png
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
app/src/main/res/drawable-mdpi/wallet_for_everyone.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
app/src/main/res/drawable-mdpi/web_3.png
Normal file
|
After Width: | Height: | Size: 98 KiB |
BIN
app/src/main/res/drawable-xhdpi/floating_cards.png
Normal file
|
After Width: | Height: | Size: 291 KiB |
BIN
app/src/main/res/drawable-xhdpi/meet_tangem.png
Normal file
|
After Width: | Height: | Size: 495 KiB |
BIN
app/src/main/res/drawable-xhdpi/revolutionary_wallet.png
Normal file
|
After Width: | Height: | Size: 455 KiB |
BIN
app/src/main/res/drawable-xhdpi/thousands_of_currencies.png
Normal file
|
After Width: | Height: | Size: 442 KiB |
BIN
app/src/main/res/drawable-xhdpi/wallet_for_everyone.png
Normal file
|
After Width: | Height: | Size: 355 KiB |
BIN
app/src/main/res/drawable-xhdpi/web_3.png
Normal file
|
After Width: | Height: | Size: 281 KiB |
BIN
app/src/main/res/drawable-xxhdpi/floating_cards.png
Normal file
|
After Width: | Height: | Size: 597 KiB |
BIN
app/src/main/res/drawable-xxhdpi/meet_tangem.png
Normal file
|
After Width: | Height: | Size: 997 KiB |
BIN
app/src/main/res/drawable-xxhdpi/revolutionary_wallet.png
Normal file
|
After Width: | Height: | Size: 920 KiB |
BIN
app/src/main/res/drawable-xxhdpi/thousands_of_currencies.png
Normal file
|
After Width: | Height: | Size: 911 KiB |
BIN
app/src/main/res/drawable-xxhdpi/wallet_for_everyone.png
Normal file
|
After Width: | Height: | Size: 693 KiB |
BIN
app/src/main/res/drawable-xxhdpi/web_3.png
Normal file
|
After Width: | Height: | Size: 550 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/floating_cards.png
Normal file
|
After Width: | Height: | Size: 983 KiB |
BIN
app/src/main/res/drawable-xxxhdpi/meet_tangem.png
Normal file
|
After Width: | Height: | Size: 1.6 MiB |
BIN
app/src/main/res/drawable-xxxhdpi/revolutionary_wallet.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
app/src/main/res/drawable-xxxhdpi/thousands_of_currencies.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
app/src/main/res/drawable-xxxhdpi/wallet_for_everyone.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
app/src/main/res/drawable-xxxhdpi/web_3.png
Normal file
|
After Width: | Height: | Size: 862 KiB |
14
app/src/main/res/drawable/ic_overlay.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<vector android:autoMirrored="true" android:height="720dp"
|
||||
android:viewportHeight="720" android:viewportWidth="360"
|
||||
android:width="360dp" xmlns:aapt="http://schemas.android.com/aapt" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#F8F9F9" android:pathData="M0,0h360v720h-360z"/>
|
||||
<path android:fillAlpha="0.2" android:pathData="M0,0h360v720h-360z">
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient android:endX="179.591" android:endY="82.4634"
|
||||
android:startX="180" android:startY="0" android:type="linear">
|
||||
<item android:color="#FF090E13" android:offset="0"/>
|
||||
<item android:color="#00000000" android:offset="1"/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
</vector>
|
||||
11
app/src/main/res/layout/fragment_home.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/cv_stories"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
@ -33,8 +33,9 @@
|
|||
android:orientation="vertical"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<FrameLayout
|
||||
<include
|
||||
android:id="@+id/onboarding_top_container"
|
||||
layout="@layout/layout_onboarding_container_top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="@dimen/home_top_weight"
|
||||
|
|
@ -50,6 +51,7 @@
|
|||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<include
|
||||
android:id="@+id/v_confetti"
|
||||
layout="@layout/view_confetti"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@
|
|||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<include
|
||||
android:id="@+id/v_confetti"
|
||||
layout="@layout/view_confetti"
|
||||
android:visibility="gone" />
|
||||
|
||||
|
|
|
|||
|
|
@ -39,12 +39,14 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/l_send_address_payid"
|
||||
layout="@layout/layout_send_address_payid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<include
|
||||
android:id="@+id/l_send_amount"
|
||||
layout="@layout/layout_send_amount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
android:visibility="gone" />
|
||||
|
||||
<include
|
||||
android:id="@+id/v_onboarding_progress"
|
||||
layout="@layout/view_onboarding_progress"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
|||