Update app launcher icons and add crash prevention

- Update Pezkuwi launcher icon design for all density buckets
- Resize icons to correct Android dimensions (mdpi to xxxhdpi)
- Add error handling to BalanceDetailViewModel flows to prevent crashes
- Handle RPC failures gracefully with logging instead of crashing
This commit is contained in:
2026-01-25 18:00:22 +03:00
parent a506a85d37
commit 95c68744da
16 changed files with 28 additions and 5 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 44 KiB

@@ -71,6 +71,7 @@ import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChangedBy
@@ -79,6 +80,8 @@ import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
import android.util.Log
import io.novafoundation.nova.common.utils.LOG_TAG
private const val ORIGIN_MIGRATION_ALERT = "ORIGIN_MIGRATION_ALERT"
@@ -125,9 +128,17 @@ class BalanceDetailViewModel(
.distinctUntilChangedBy { it.fullId }
private val balanceLocksFlow = balanceLocksInteractor.balanceLocksFlow(assetPayload.chainId, assetPayload.chainAssetId)
.catch { error ->
Log.e(LOG_TAG, "Failed to load balance locks: ${error.message}")
emit(emptyList())
}
.shareInBackground()
private val balanceHoldsFlow = balanceLocksInteractor.balanceHoldsFlow(assetPayload.chainId, assetPayload.chainAssetId)
.catch { error ->
Log.e(LOG_TAG, "Failed to load balance holds: ${error.message}")
emit(emptyList())
}
.shareInBackground()
private val selectedAccountFlow = accountUseCase.selectedMetaAccountFlow()
@@ -166,12 +177,20 @@ class BalanceDetailViewModel(
swapAvailabilityInteractor.swapAvailableFlow(it, viewModelScope)
}
.onStart { emit(false) }
.catch { error ->
Log.e(LOG_TAG, "Failed to check swap availability: ${error.message}")
emit(false)
}
.shareInBackground()
val giftsButtonEnabled = chainAssetFlow.map {
giftsAvailableGiftAssetsUseCase.isGiftsAvailable(it)
}
.onStart { emit(false) }
.catch { error ->
Log.e(LOG_TAG, "Failed to check gifts availability: ${error.message}")
emit(false)
}
.shareInBackground()
val sendEnabled = assetFlow.map {
@@ -279,13 +298,17 @@ class BalanceDetailViewModel(
fun sync() {
launch {
swapAvailabilityInteractor.sync(viewModelScope)
runCatching {
swapAvailabilityInteractor.sync(viewModelScope)
val currency = currencyInteractor.getSelectedCurrency()
val deferredAssetSync = async { walletInteractor.syncAssetsRates(currency) }
val deferredTransactionsSync = async { transactionHistoryMixin.syncFirstOperationsPage() }
val currency = currencyInteractor.getSelectedCurrency()
val deferredAssetSync = async { walletInteractor.syncAssetsRates(currency) }
val deferredTransactionsSync = async { transactionHistoryMixin.syncFirstOperationsPage() }
awaitAll(deferredAssetSync, deferredTransactionsSync)
awaitAll(deferredAssetSync, deferredTransactionsSync)
}.onFailure { error ->
Log.e(LOG_TAG, "Sync failed: ${error.message}")
}
_hideRefreshEvent.value = Event(Unit)
}