Skip to content

Commit

Permalink
WAL2-89 Remove shielding (#335)
Browse files Browse the repository at this point in the history
## Purpose

Remove shielding. The user can still enable and see their shielded
balance and history, but to unshield the funds CryptoX Concordium wallet
must be used.

## Changes

- Visually remove shielding actions (transfer, shield, unshield)
- Add shielding notice popup shown once
  • Loading branch information
Radiokot authored May 30, 2024
1 parent d27951d commit 45ba3a6
Show file tree
Hide file tree
Showing 16 changed files with 348 additions and 98 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
- Sending WalletConnect transaction with 0 energy if its payload is too large

### Removed
- Shielding – you can still enable and see your shielded balance and history,
but to unshield the funds CryptoX Concordium wallet must be used

## [1.5.1] - 2024-03-18

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ class Session(context: Context) {
return filterPreferences.getHasShowFinalizationRewards(id)
}

fun shieldingNoticeShown() {
authPreferences.setShieldingNoticeShown(true)
}

fun isShieldingNoticeShown():Boolean {
return authPreferences.getShieldingNoticeShown()
}

fun hasSetupPassword(passcodeUsed: Boolean = false) {
_isLoggedIn.value = true
authPreferences.setHasSetupUser(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,14 @@ data class AccountEncryptedAmount(
val selfAmount: String,
var selfAmountDecrypted: Long,
val startIndex: Int
) : Serializable
) : Serializable {
fun isDefaultEmpty(): Boolean =
selfAmount == DEFAULT_EMPTY_ENCRYPTED_AMOUNT &&
incomingAmounts.all { it == DEFAULT_EMPTY_ENCRYPTED_AMOUNT }


companion object {
const val DEFAULT_EMPTY_ENCRYPTED_AMOUNT =
"c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ class AuthPreferences(val context: Context) :
const val PREFKEY_IDENTITY_PENDING_ACKNOWLEDGED = "PREFKEY_IDENTITY_PENDING_ACKNOWLEDGED_"
const val SEED_PHRASE = "SEED_PHRASE"
const val SEED_PHRASE_ENCRYPTED = "SEED_PHRASE_ENCRYPTED"
const val PREFKEY_SHIELDING_NOTICE_SHOWN = "SHIELDING_NOTICE_SHOWN"
}

fun setShieldingNoticeShown(value: Boolean) {
setBoolean(PREFKEY_SHIELDING_NOTICE_SHOWN, value)
}

fun getShieldingNoticeShown(): Boolean {
return getBoolean(PREFKEY_SHIELDING_NOTICE_SHOWN, false)
}

fun setHasSetupUser(value: Boolean) {
Expand Down
28 changes: 25 additions & 3 deletions app/src/main/java/com/concordium/wallet/data/room/Account.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package com.concordium.wallet.data.room

import androidx.room.*
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room.TypeConverters
import com.concordium.wallet.App
import com.concordium.wallet.data.model.*
import com.concordium.wallet.data.model.AccountBaker
import com.concordium.wallet.data.model.AccountDelegation
import com.concordium.wallet.data.model.AccountEncryptedAmount
import com.concordium.wallet.data.model.AccountReleaseSchedule
import com.concordium.wallet.data.model.CredentialWrapper
import com.concordium.wallet.data.model.IdentityAttribute
import com.concordium.wallet.data.model.ShieldedAccountEncryptionStatus
import com.concordium.wallet.data.model.TransactionStatus
import com.concordium.wallet.data.room.typeconverter.AccountTypeConverters
import com.concordium.wallet.util.toBigInteger
import com.google.gson.JsonObject
import java.io.Serializable
import java.math.BigInteger
Expand Down Expand Up @@ -130,6 +140,18 @@ data class Account(
return accountDelegation != null
}

fun mayNeedUnshielding(): Boolean {
if (finalizedEncryptedBalance == null) {
return false
}

val isShieldedBalanceUnknown = encryptedBalanceStatus == ShieldedAccountEncryptionStatus.ENCRYPTED
|| encryptedBalanceStatus == ShieldedAccountEncryptionStatus.PARTIALLYDECRYPTED
val isShieldedBalancePositive = encryptedBalanceStatus == ShieldedAccountEncryptionStatus.DECRYPTED
&& totalShieldedBalance.signum() > 0
return isShieldedBalanceUnknown || isShieldedBalancePositive
}

fun getAtDisposalWithoutStakedOrScheduled(totalBalance: BigInteger): BigInteger {
val stakedAmount: BigInteger = accountDelegation?.stakedAmount
?: accountBaker?.stakedAmount ?: BigInteger.ZERO
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -518,16 +518,7 @@ class AccountDetailsActivity : BaseActivity(), EarnDelegate by EarnDelegateImpl(
private fun updateButtonsSlider() {
if (viewModelAccountDetails.isShielded) {
binding.buttonsSlider.visibility = View.GONE
binding.buttonsShielded.visibility = View.VISIBLE
binding.sendShielded.setOnClickListener {
onSendShieldedClicked()
}
binding.unshield.setOnClickListener {
onShieldFundsClicked()
}
binding.receive.setOnClickListener {
onAddressClicked()
}
// Completely hide and disable shielding actions.
return
}
binding.buttonsSlider.visibility = View.VISIBLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,30 @@ import android.os.Process
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProvider
import com.concordium.wallet.App
import com.concordium.wallet.R
import com.concordium.wallet.core.arch.EventObserver
import com.concordium.wallet.data.model.AppSettings
import com.concordium.wallet.data.model.BakerStakePendingChange
import com.concordium.wallet.data.model.TransactionStatus
import com.concordium.wallet.data.preferences.Preferences
import com.concordium.wallet.data.room.Account
import com.concordium.wallet.data.room.AccountWithIdentity
import com.concordium.wallet.data.util.CurrencyUtil
import com.concordium.wallet.util.TokenUtil
import com.concordium.wallet.databinding.FragmentAccountsOverviewBinding
import com.concordium.wallet.ui.MainViewModel
import com.concordium.wallet.ui.account.accountdetails.AccountDetailsActivity
import com.concordium.wallet.ui.account.accountqrcode.AccountQRCodeActivity
import com.concordium.wallet.ui.base.BaseFragment
import com.concordium.wallet.ui.cis2.SendTokenActivity
import com.concordium.wallet.ui.common.delegates.EarnDelegate
import com.concordium.wallet.ui.common.delegates.EarnDelegateImpl
import com.concordium.wallet.ui.common.delegates.IdentityStatusDelegate
import com.concordium.wallet.ui.common.delegates.IdentityStatusDelegateImpl
import com.concordium.wallet.ui.identity.identitiesoverview.IdentitiesOverviewActivity
import com.concordium.wallet.ui.identity.identityproviderlist.IdentityProviderListActivity
import com.concordium.wallet.ui.cis2.SendTokenActivity
import com.concordium.wallet.util.TokenUtil
import java.math.BigInteger

class AccountsOverviewFragment : BaseFragment(),
Expand Down Expand Up @@ -160,7 +160,6 @@ class AccountsOverviewFragment : BaseFragment(),
viewModel.accountListLiveData.observe(this) { accountList ->
accountList?.let {
accountAdapter.setData(it)
checkForUnencrypted(it)
checkForClosingPools(it)
}
}
Expand All @@ -187,6 +186,16 @@ class AccountsOverviewFragment : BaseFragment(),
)
}
}
viewModel.showShieldingNoticeLiveData.observe(this) {
childFragmentManager.fragments.forEach { fragment ->
if (fragment.tag == ShieldingNoticeDialogFragment.TAG && fragment is DialogFragment) {
fragment.dismissAllowingStateLoss()
}
}

ShieldingNoticeDialogFragment()
.show(childFragmentManager, ShieldingNoticeDialogFragment.TAG)
}
}

private fun checkAppSettings(appSettings: AppSettings?) {
Expand Down Expand Up @@ -293,60 +302,6 @@ class AccountsOverviewFragment : BaseFragment(),
viewModel.loadPoolStatuses(poolIds)
}

private fun checkForUnencrypted(accountList: List<AccountWithIdentity>) {
accountList.forEach {

val hasUnencryptedTransactions =
it.account.finalizedEncryptedBalance?.incomingAmounts?.isNotEmpty()
if ((hasUnencryptedTransactions != null && hasUnencryptedTransactions == true)
&& it.account.transactionStatus == TransactionStatus.FINALIZED
&& !App.appCore.session.isShieldedWarningDismissed(it.account.address)
&& !App.appCore.session.isShieldingEnabled(it.account.address)
&& encryptedWarningDialog == null
) {

val builder = AlertDialog.Builder(context)
builder.setTitle(getString(R.string.account_details_shielded_warning_title))
builder.setMessage(
getString(
R.string.account_details_shielded_warning_text,
it.account.name
)
)
builder.setNegativeButton(
getString(
R.string.account_details_shielded_warning_enable,
it.account.name
)
) { _, _ ->
startShieldedIntroFlow(it.account)
encryptedWarningDialog?.dismiss()
encryptedWarningDialog = null
}
builder.setPositiveButton(getString(R.string.account_details_shielded_warning_dismiss)) { _, _ ->
App.appCore.session.setShieldedWarningDismissed(
it.account.address,
true
)
encryptedWarningDialog?.dismiss()
encryptedWarningDialog = null
checkForUnencrypted(accountList) //Check for other accounts with shielded transactions
}
builder.setCancelable(true)
encryptedWarningDialog = builder.create()//.show()
encryptedWarningDialog?.show()
}
}
}

private fun startShieldedIntroFlow(account: Account) {
val intent = Intent(activity, AccountDetailsActivity::class.java)
intent.putExtra(AccountDetailsActivity.EXTRA_ACCOUNT, account)
intent.putExtra(AccountDetailsActivity.EXTRA_SHIELDED, false)
intent.putExtra(AccountDetailsActivity.EXTRA_CONTINUE_TO_SHIELD_INTRO, true)
startActivityForResult(intent, REQUESTCODE_ACCOUNT_DETAILS)
}

private fun initializeViews() {
mainViewModel.setTitle(getString(R.string.accounts_overview_title))
binding.includeProgress.progressLayout.visibility = View.VISIBLE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class AccountsOverviewViewModel(application: Application) : AndroidViewModel(app
val appSettingsLiveData: LiveData<AppSettings>
get() = _appSettingsLiveData

private val _showShieldingNoticeLiveData = MutableLiveData<Event<Boolean>>()
val showShieldingNoticeLiveData: LiveData<Event<Boolean>>
get() = _showShieldingNoticeLiveData

val localTransfersLoaded: MutableLiveData<Account> by lazy { MutableLiveData<Account>() }

private val identityRepository: IdentityRepository
Expand Down Expand Up @@ -169,17 +173,19 @@ class AccountsOverviewViewModel(application: Application) : AndroidViewModel(app
if (identityCount == 0) {
_stateLiveData.value = State.NO_IDENTITIES
// Set balance, because we know it will be 0
_totalBalanceLiveData.value = TotalBalancesData(BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, false)
if(notifyWaitingLiveData){
_totalBalanceLiveData.value =
TotalBalancesData(BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, false)
if (notifyWaitingLiveData) {
_waitingLiveData.value = false
}
} else {
val accountCount = accountRepository.getCount()
if (accountCount == 0) {
_stateLiveData.value = State.NO_ACCOUNTS
// Set balance, because we know it will be 0
_totalBalanceLiveData.value = TotalBalancesData(BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, false)
if(notifyWaitingLiveData){
_totalBalanceLiveData.value =
TotalBalancesData(BigInteger.ZERO, BigInteger.ZERO, BigInteger.ZERO, false)
if (notifyWaitingLiveData) {
_waitingLiveData.value = false
}
} else {
Expand All @@ -188,6 +194,7 @@ class AccountsOverviewViewModel(application: Application) : AndroidViewModel(app
_waitingLiveData.value = false
}
updateSubmissionStatesAndBalances(notifyWaitingLiveData)
showUnshieldingNoticeIfNeeded()
}
}
}
Expand Down Expand Up @@ -254,5 +261,17 @@ class AccountsOverviewViewModel(application: Application) : AndroidViewModel(app
return false
}

private fun showUnshieldingNoticeIfNeeded() = viewModelScope.launch {
// Show the notice once.
if (App.appCore.session.isShieldingNoticeShown()) {
return@launch
}

val anyAccountsMayNeedUnshielding = accountRepository.getAllDone()
.any(Account::mayNeedUnshielding)

}
if (anyAccountsMayNeedUnshielding) {
_showShieldingNoticeLiveData.postValue(Event(true))
}
}
}
Loading

0 comments on commit 45ba3a6

Please sign in to comment.