diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml
index 6d96304..7e68305 100644
--- a/common/src/main/res/values/strings.xml
+++ b/common/src/main/res/values/strings.xml
@@ -2766,6 +2766,8 @@
Trust Score
Apply & Actions
Use our Telegram MiniApp for Digital Kurdistan citizenship services.\n\nTo earn PEZ rewards, you must hold a Welatî ticket and stake at least 10 HEZ.\n\nNon-citizens can only benefit from HEZ rewards.
+ Start Tracking
+ Score tracking started!
Hejmara Kurd Le Cihane
diff --git a/feature-assets/build.gradle b/feature-assets/build.gradle
index 7ad29d2..5d2c584 100644
--- a/feature-assets/build.gradle
+++ b/feature-assets/build.gradle
@@ -95,7 +95,7 @@ dependencies {
implementation insetterDep
implementation shimmerDep
- implementation flexBoxDep
+ api flexBoxDep
implementation chartsDep
diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/data/model/PezkuwiDashboardData.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/data/model/PezkuwiDashboardData.kt
index 904f52f..c6e4037 100644
--- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/data/model/PezkuwiDashboardData.kt
+++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/data/model/PezkuwiDashboardData.kt
@@ -7,5 +7,6 @@ data class PezkuwiDashboardData(
val roles: List,
val trustScore: BigInteger,
val welatiCount: Int,
- val citizenshipStatus: CitizenshipStatus = CitizenshipStatus.NOT_STARTED
+ val citizenshipStatus: CitizenshipStatus = CitizenshipStatus.NOT_STARTED,
+ val isTrackingScore: Boolean = false
)
diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/data/repository/PezkuwiDashboardRepository.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/data/repository/PezkuwiDashboardRepository.kt
index 4c7f492..ea5d897 100644
--- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/data/repository/PezkuwiDashboardRepository.kt
+++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/data/repository/PezkuwiDashboardRepository.kt
@@ -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
diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt
index a60e904..e412963 100644
--- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt
+++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListFragment.kt
@@ -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))
diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt
index 9a068ed..43d54f2 100644
--- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt
+++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/BalanceListViewModel.kt
@@ -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>()
val shareReferralEvent: LiveData> = _shareReferralEvent
+ private val _showTrackingSuccessEvent = MutableLiveData>()
+ val showTrackingSuccessEvent: LiveData> = _showTrackingSuccessEvent
+
+ private val _trackingLoading = MutableLiveData(false)
+ val trackingLoading: LiveData = _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()
diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt
index 5389db0..eb4ddf0 100644
--- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt
+++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/di/BalanceListModule.kt
@@ -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
)
}
diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/PezkuwiDashboardModel.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/PezkuwiDashboardModel.kt
index 6e133c2..11a5940 100644
--- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/PezkuwiDashboardModel.kt
+++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/model/PezkuwiDashboardModel.kt
@@ -6,5 +6,6 @@ data class PezkuwiDashboardModel(
val roles: List,
val trustScore: String,
val welatiCount: String,
- val citizenshipStatus: CitizenshipStatus = CitizenshipStatus.NOT_STARTED
+ val citizenshipStatus: CitizenshipStatus = CitizenshipStatus.NOT_STARTED,
+ val isTrackingScore: Boolean = false
)
diff --git a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/PezkuwiDashboardAdapter.kt b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/PezkuwiDashboardAdapter.kt
index 8508628..e623c5a 100644
--- a/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/PezkuwiDashboardAdapter.kt
+++ b/feature-assets/src/main/java/io/novafoundation/nova/feature_assets/presentation/balance/list/view/PezkuwiDashboardAdapter.kt
@@ -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) {
diff --git a/feature-assets/src/main/res/layout/item_pezkuwi_dashboard.xml b/feature-assets/src/main/res/layout/item_pezkuwi_dashboard.xml
index 259a33b..f915859 100644
--- a/feature-assets/src/main/res/layout/item_pezkuwi_dashboard.xml
+++ b/feature-assets/src/main/res/layout/item_pezkuwi_dashboard.xml
@@ -69,6 +69,22 @@
android:textColor="#FFD54F"
android:textSize="16sp"
android:textStyle="bold" />
+
+