mirror of
https://github.com/pezkuwichain/pezkuwi-wallet-android.git
synced 2026-04-22 02:07:58 +00:00
feat: add Start Tracking button for StakingScore on dashboard
Query StakingScore::StakingStartBlock from People Chain to check tracking status. Show "Start Tracking" button for approved citizens who haven't opted in yet. Submits start_score_tracking() extrinsic with loading state and error handling to prevent duplicate calls.
This commit is contained in:
@@ -95,7 +95,7 @@ dependencies {
|
||||
implementation insetterDep
|
||||
|
||||
implementation shimmerDep
|
||||
implementation flexBoxDep
|
||||
api flexBoxDep
|
||||
|
||||
implementation chartsDep
|
||||
|
||||
|
||||
+2
-1
@@ -7,5 +7,6 @@ data class PezkuwiDashboardData(
|
||||
val roles: List<String>,
|
||||
val trustScore: BigInteger,
|
||||
val welatiCount: Int,
|
||||
val citizenshipStatus: CitizenshipStatus = CitizenshipStatus.NOT_STARTED
|
||||
val citizenshipStatus: CitizenshipStatus = CitizenshipStatus.NOT_STARTED,
|
||||
val isTrackingScore: Boolean = false
|
||||
)
|
||||
|
||||
+12
-1
@@ -36,12 +36,14 @@ class PezkuwiDashboardRepository(
|
||||
val trustScore = queryTrustScore(chainId, accountId)
|
||||
val welatiCount = fetchWelatiCount()
|
||||
val kycStatus = runCatching { queryKycStatus(chainId, accountId) }.getOrDefault(CitizenshipStatus.NOT_STARTED)
|
||||
val isTrackingScore = queryIsTrackingScore(chainId, accountId)
|
||||
|
||||
return PezkuwiDashboardData(
|
||||
roles = roles.ifEmpty { listOf("Non-Citizen") },
|
||||
trustScore = trustScore,
|
||||
welatiCount = welatiCount,
|
||||
citizenshipStatus = kycStatus
|
||||
citizenshipStatus = kycStatus,
|
||||
isTrackingScore = isTrackingScore
|
||||
)
|
||||
}
|
||||
|
||||
@@ -73,6 +75,15 @@ class PezkuwiDashboardRepository(
|
||||
}
|
||||
}.getOrDefault(BigInteger.ZERO)
|
||||
|
||||
suspend fun queryIsTrackingScore(chainId: String, accountId: AccountId): Boolean = runCatching {
|
||||
remoteStorageDataSource.query(chainId) {
|
||||
val module = runtime.metadata.moduleOrNull("StakingScore") ?: return@query false
|
||||
module.storage("StakingStartBlock").query(accountId, binding = { decoded ->
|
||||
decoded != null
|
||||
})
|
||||
}
|
||||
}.getOrDefault(false)
|
||||
|
||||
suspend fun queryFreeBalance(chainId: String, accountId: AccountId): BigInteger = runCatching {
|
||||
remoteStorageDataSource.query(chainId) {
|
||||
val systemModule = runtime.metadata.moduleOrNull("System") ?: return@query BigInteger.ZERO
|
||||
|
||||
+13
@@ -33,6 +33,7 @@ import io.novafoundation.nova.feature_assets.presentation.balance.list.view.Asse
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.ManageAssetsAdapter
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.ManageAssetsHolder
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.PezkuwiDashboardAdapter
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.list.view.PezkuwiDashboardHolder
|
||||
import io.novafoundation.nova.feature_assets.presentation.citizenship.CitizenshipBottomSheet
|
||||
@@ -189,6 +190,14 @@ class BalanceListFragment :
|
||||
}
|
||||
startActivity(Intent.createChooser(intent, null))
|
||||
}
|
||||
|
||||
viewModel.showTrackingSuccessEvent.observeEvent {
|
||||
Toast.makeText(requireContext(), R.string.pezkuwi_dashboard_tracking_success, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
viewModel.trackingLoading.observe(viewLifecycleOwner) { loading ->
|
||||
pezkuwiDashboardAdapter.setTrackingLoading(loading)
|
||||
}
|
||||
}
|
||||
|
||||
override fun assetClicked(asset: Chain.Asset) {
|
||||
@@ -278,6 +287,10 @@ class BalanceListFragment :
|
||||
viewModel.shareReferralClicked()
|
||||
}
|
||||
|
||||
override fun onStartTrackingClicked() {
|
||||
viewModel.startTrackingClicked()
|
||||
}
|
||||
|
||||
private fun setupRecyclerViewSpacing() {
|
||||
binder.balanceListAssets.addSpaceItemDecoration {
|
||||
add(SpaceBetween(AssetsHeaderHolder, PezkuwiDashboardHolder, spaceDp = 8))
|
||||
|
||||
+41
-2
@@ -65,7 +65,12 @@ import io.novafoundation.nova.feature_wallet_api.presentation.formatters.amount.
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.model.FractionPartStyling
|
||||
import io.novafoundation.nova.feature_wallet_connect_api.domain.sessions.WalletConnectSessionsUseCase
|
||||
import io.novafoundation.nova.feature_wallet_connect_api.presentation.mapNumberOfActiveSessionsToUi
|
||||
import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService
|
||||
import io.novafoundation.nova.feature_account_api.data.ethereum.transaction.TransactionOrigin
|
||||
import io.novafoundation.nova.runtime.ext.ChainGeneses
|
||||
import io.novafoundation.nova.runtime.multiNetwork.ChainRegistry
|
||||
import io.novafoundation.nova.runtime.multiNetwork.chain.model.Chain
|
||||
import io.novasama.substrate_sdk_android.runtime.extrinsic.call
|
||||
import java.text.NumberFormat
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.flow.combine
|
||||
@@ -104,7 +109,9 @@ class BalanceListViewModel(
|
||||
private val novaCardRestrictionCheckMixin: NovaCardRestrictionCheckMixin,
|
||||
private val maskingModeUseCase: MaskingModeUseCase,
|
||||
private val giftsRestrictionCheckMixin: GiftsRestrictionCheckMixin,
|
||||
private val pezkuwiDashboardInteractor: PezkuwiDashboardInteractor
|
||||
private val pezkuwiDashboardInteractor: PezkuwiDashboardInteractor,
|
||||
private val extrinsicService: ExtrinsicService,
|
||||
private val chainRegistry: ChainRegistry
|
||||
) : BaseViewModel(), Browserable.Presentation by Browserable() {
|
||||
|
||||
private val maskableAmountFormatterFlow = maskableValueFormatterProvider.provideFormatter()
|
||||
@@ -122,6 +129,12 @@ class BalanceListViewModel(
|
||||
private val _shareReferralEvent = MutableLiveData<Event<String>>()
|
||||
val shareReferralEvent: LiveData<Event<String>> = _shareReferralEvent
|
||||
|
||||
private val _showTrackingSuccessEvent = MutableLiveData<Event<Unit>>()
|
||||
val showTrackingSuccessEvent: LiveData<Event<Unit>> = _showTrackingSuccessEvent
|
||||
|
||||
private val _trackingLoading = MutableLiveData(false)
|
||||
val trackingLoading: LiveData<Boolean> = _trackingLoading
|
||||
|
||||
val bannersMixin = promotionBannersMixinFactory.create(bannerSourceFactory.assetsSource(), viewModelScope)
|
||||
|
||||
private val selectedCurrency = currencyInteractor.observeSelectCurrency()
|
||||
@@ -239,7 +252,8 @@ class BalanceListViewModel(
|
||||
roles = data.roles,
|
||||
trustScore = data.trustScore.toString(),
|
||||
welatiCount = NumberFormat.getIntegerInstance().format(data.welatiCount),
|
||||
citizenshipStatus = data.citizenshipStatus
|
||||
citizenshipStatus = data.citizenshipStatus,
|
||||
isTrackingScore = data.isTrackingScore
|
||||
)
|
||||
}
|
||||
.getOrNull()
|
||||
@@ -425,6 +439,31 @@ class BalanceListViewModel(
|
||||
_shareReferralEvent.postValue(Event(shareText))
|
||||
}
|
||||
|
||||
fun startTrackingClicked() {
|
||||
if (_trackingLoading.value == true) return
|
||||
_trackingLoading.value = true
|
||||
|
||||
launchUnit {
|
||||
try {
|
||||
val chain = chainRegistry.getChain(ChainGeneses.PEZKUWI_PEOPLE)
|
||||
val result = extrinsicService.submitExtrinsic(chain, TransactionOrigin.SelectedWallet) {
|
||||
call(
|
||||
moduleName = "StakingScore",
|
||||
callName = "start_score_tracking",
|
||||
arguments = emptyMap()
|
||||
)
|
||||
}
|
||||
result.getOrThrow()
|
||||
_showTrackingSuccessEvent.postValue(Event(Unit))
|
||||
fullSync()
|
||||
} catch (e: Exception) {
|
||||
showError(e.message ?: "Score tracking failed")
|
||||
} finally {
|
||||
_trackingLoading.postValue(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun novaCardClicked() = launchUnit {
|
||||
novaCardRestrictionCheckMixin.checkRestrictionAndDo {
|
||||
router.openNovaCard()
|
||||
|
||||
+6
-1
@@ -42,6 +42,7 @@ import io.novafoundation.nova.feature_wallet_api.presentation.formatters.amount.
|
||||
import io.novafoundation.nova.feature_wallet_api.presentation.formatters.amount.FiatFormatter
|
||||
import io.novafoundation.nova.common.presentation.masking.formatter.MaskableValueFormatterProvider
|
||||
import io.novafoundation.nova.feature_assets.presentation.balance.common.gifts.GiftsRestrictionCheckMixin
|
||||
import io.novafoundation.nova.feature_account_api.data.extrinsic.ExtrinsicService
|
||||
import io.novafoundation.nova.feature_wallet_connect_api.domain.sessions.WalletConnectSessionsUseCase
|
||||
|
||||
@Module(includes = [ViewModelModule::class])
|
||||
@@ -127,6 +128,8 @@ class BalanceListModule {
|
||||
fiatFormatter: FiatFormatter,
|
||||
giftsRestrictionCheckMixin: GiftsRestrictionCheckMixin,
|
||||
pezkuwiDashboardInteractor: PezkuwiDashboardInteractor,
|
||||
extrinsicService: ExtrinsicService,
|
||||
chainRegistry: ChainRegistry,
|
||||
): ViewModel {
|
||||
return BalanceListViewModel(
|
||||
promotionBannersMixinFactory = promotionBannersMixinFactory,
|
||||
@@ -149,7 +152,9 @@ class BalanceListModule {
|
||||
maskingModeUseCase = maskingModeUseCase,
|
||||
fiatFormatter = fiatFormatter,
|
||||
giftsRestrictionCheckMixin = giftsRestrictionCheckMixin,
|
||||
pezkuwiDashboardInteractor = pezkuwiDashboardInteractor
|
||||
pezkuwiDashboardInteractor = pezkuwiDashboardInteractor,
|
||||
extrinsicService = extrinsicService,
|
||||
chainRegistry = chainRegistry
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -6,5 +6,6 @@ data class PezkuwiDashboardModel(
|
||||
val roles: List<String>,
|
||||
val trustScore: String,
|
||||
val welatiCount: String,
|
||||
val citizenshipStatus: CitizenshipStatus = CitizenshipStatus.NOT_STARTED
|
||||
val citizenshipStatus: CitizenshipStatus = CitizenshipStatus.NOT_STARTED,
|
||||
val isTrackingScore: Boolean = false
|
||||
)
|
||||
|
||||
+19
-2
@@ -23,22 +23,29 @@ class PezkuwiDashboardAdapter(
|
||||
fun onBasvuruClicked()
|
||||
fun onSignClicked()
|
||||
fun onShareReferralClicked()
|
||||
fun onStartTrackingClicked()
|
||||
}
|
||||
|
||||
private var model: PezkuwiDashboardModel? = null
|
||||
private var trackingLoading: Boolean = false
|
||||
|
||||
fun setModel(model: PezkuwiDashboardModel) {
|
||||
this.model = model
|
||||
notifyChangedIfShown()
|
||||
}
|
||||
|
||||
fun setTrackingLoading(loading: Boolean) {
|
||||
this.trackingLoading = loading
|
||||
notifyChangedIfShown()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PezkuwiDashboardHolder {
|
||||
val binding = ItemPezkuwiDashboardBinding.inflate(parent.inflater(), parent, false)
|
||||
return PezkuwiDashboardHolder(binding, handler)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: PezkuwiDashboardHolder, position: Int) {
|
||||
model?.let { holder.bind(it) }
|
||||
model?.let { holder.bind(it, trackingLoading) }
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
@@ -59,13 +66,23 @@ class PezkuwiDashboardHolder(
|
||||
binder.pezkuwiDashboardBasvuruButton.setOnClickListener { handler.onBasvuruClicked() }
|
||||
binder.pezkuwiDashboardSignButton.setOnClickListener { handler.onSignClicked() }
|
||||
binder.pezkuwiDashboardShareButton.setOnClickListener { handler.onShareReferralClicked() }
|
||||
binder.pezkuwiDashboardStartTrackingButton.setOnClickListener { handler.onStartTrackingClicked() }
|
||||
}
|
||||
|
||||
fun bind(model: PezkuwiDashboardModel) {
|
||||
fun bind(model: PezkuwiDashboardModel, trackingLoading: Boolean = false) {
|
||||
bindRoles(model.roles)
|
||||
binder.pezkuwiDashboardTrustValue.text = model.trustScore
|
||||
binder.pezkuwiDashboardWelatiCount.text = model.welatiCount
|
||||
bindButtons(model.citizenshipStatus)
|
||||
|
||||
val showTracking = !model.isTrackingScore && model.citizenshipStatus == CitizenshipStatus.APPROVED
|
||||
binder.pezkuwiDashboardStartTrackingButton.visibility = if (showTracking) View.VISIBLE else View.GONE
|
||||
|
||||
if (showTracking) {
|
||||
binder.pezkuwiDashboardStartTrackingButton.isEnabled = !trackingLoading
|
||||
binder.pezkuwiDashboardStartTrackingButton.text = if (trackingLoading) "..." else
|
||||
binder.root.context.getString(R.string.pezkuwi_dashboard_start_tracking)
|
||||
}
|
||||
}
|
||||
|
||||
private fun bindButtons(status: CitizenshipStatus) {
|
||||
|
||||
@@ -69,6 +69,22 @@
|
||||
android:textColor="#FFD54F"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/pezkuwiDashboardStartTrackingButton"
|
||||
style="@style/Widget.MaterialComponents.Button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:minWidth="0dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:text="@string/pezkuwi_dashboard_start_tracking"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="11sp"
|
||||
android:visibility="gone"
|
||||
app:backgroundTint="#FF9800"
|
||||
app:cornerRadius="8dp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user