Commit Graph

106 Commits

Author SHA1 Message Date
pezkuwichain 7906a20f96 fix: stop swallowed errors from silently killing balance/updater sync
StatemineAssetBalance and NativeAssetBalance's startSyncingBalance()
wrapped setup and subscription failures in runCatching{}/catch{} that
returned emptyFlow()/NoCause instead of propagating. This meant
FullSyncPaymentUpdater's retryWhen (added for the Tron fix) never
actually engaged for these asset types - a transient failure silently
and permanently stopped sync for that asset (HEZ, PEZ, USDT, DOT, ...)
with only a logcat line as evidence. Let the exceptions propagate so
the existing retry boundary can do its job.

ChainRegistry.currentChains ran registerChain()/unregisterChain() per
chain, unguarded, inside a plain (non-Supervisor) CoroutineScope and an
Eagerly-shared flow that never restarts once it dies. One bad chain row
could permanently kill sync for every chain. Isolated each chain's
register/unregister in its own runCatching, and switched the scope to
a SupervisorJob as defense in depth.

ChainUpdaterGroupUpdateSystem.runUpdaters() called getRuntime() and
built per-chain updater flows with no error boundary; callers merge
several chains' results together, so one chain's failure (e.g. a
disabled chain throwing DisabledChainException) could kill
governance/staking/crowdloan sync for every other chain in the group.
Wrapped the body in flow{} + catch to isolate failures per chain.
2026-07-08 13:54:44 -07:00
pezkuwichain 4aebac305f fix: retry balance sync on failure for ALL chains, not just Tron
Generalizes today's Tron balance-polling fix - the same silent-death
bug exists in the shared Substrate sync path used by every chain
(Interlay, Kintsugi, Karura, Acala, Hydration, Polkadex, and any other
orml/statemine asset), not just Tron-specific code.

FullSyncPaymentUpdater.syncAsset() previously used runCatching around
the one-time startSyncingBalance() call and a separate .catch on the
resulting flow - either path failing (a transient WSS hiccup during
setup, an orml currencyId-decode edge case, a node not supporting a
specific RPC method during round-robin, a dropped connection later)
permanently ended that asset's sync for the Updater's lifetime: no
retry, only a Log.e line, and mapNotNull silently dropped the null
result. Since no balance update flow ever emits, AssetCache never
creates a DB row for that asset, and every UI surface (main list,
multi-chain picker) reads via an INNER JOIN that requires that row -
so the asset stays invisible with zero user-visible error until app
restart, which has the same odds of failing again.

Live-tested: Interlay/Kintsugi's node URLs are all reachable (manual
WSS handshake test, 101 Switching Protocols), and none of these chains
are blacklisted - so this wasn't a connectivity or config issue, it
was this retry gap.

Wraps both the initial subscription call and the ongoing flow in one
flow{} builder with retryWhen (30s fixed interval, matching Tron's
polling interval) instead of runCatching + .catch, so a transient
failure at either point just gets retried instead of permanently
killing sync for that asset.
2026-07-08 11:57:26 -07:00
pezkuwichain 21d2896493 fix: retry Tron balance polling on failure instead of permanently dying
Real user on a fresh install reported TRX and USDT-TRC20 never
appearing anywhere in the Tokens list (not "zero balance", genuinely
absent - including from the multi-chain USDT chain picker). Traced
the full pipeline; every layer up to and including
TypeBasedAssetSourceRegistry, ChainRegistry, address derivation, and
TronGridApi wiring was already correct.

Root cause: pollingBalanceFlow() had no retry around fetch() - any
single transient failure (DNS hiccup, timeout, momentary connectivity
loss during app cold start) threw out of the `while(true)` loop,
killing the flow permanently. The collector
(FullSyncPaymentUpdater.syncAsset()) only logs and gives up on
failure, it doesn't resubscribe. Since the asset's first balance
write never happens, AssetCache never inserts a DB row for it, and
every UI surface (main list, multi-chain picker, search) reads
exclusively via an INNER JOIN that requires that row to exist - so
the asset is invisible everywhere, permanently, with zero
user-visible error.

Swallow fetch() failures and retry on the next interval instead of
letting them escape the loop - one bad poll no longer blackholes the
asset for the rest of the app session.

Also fixes a related but separate gap found while tracing this:
RealSecretsMetaAccount.multiChainEncryptionIn() had no isTronBased
branch (only isEthereumBased), unlike DefaultMetaAccount's
hasAccountIn/accountIdIn which already handle Tron correctly. This
didn't cause the missing-tokens bug, but would have broken "export
account" (JSON key backup) for Tron - fixed by routing Tron through
MultiChainEncryption.Ethereum, matching what
RealTronTransactionService already does for actual transaction
signing (same secp256k1 keypair).
2026-07-08 11:33:54 -07:00
pezkuwichain 15aa33000b fix: don't show perpetual "Connecting" for Tron chains in Networks list
Real user reported Tron stuck showing "Connecting..." forever in the
Networks screen after the ChainRegistry fix (which correctly skips
creating a ChainConnection for Tron, since TronGrid is a plain REST
API, not WSS). NetworkListAdapterItemFactory.getConnectingState()
rendered every non-Connected state (including the Disconnected
default a missing connection pool entry falls back to) as
"Connecting" with an indefinite shimmer - there was no way to
distinguish "never had a connection to begin with" from "still
negotiating one".

Tron doesn't have a meaningful WS connection state at all (its actual
balance/transfer operations poll TronGridApi directly, confirmed
independent of ChainConnection), so there's nothing correct to show
here - treat it the same as the already-existing isDisabled early
return (no status badge) rather than defaulting into the generic
"still connecting" UI.
2026-07-08 10:21:56 -07:00
pezkuwichain 74728a8477 feat(dashboard): collapsible Pezkuwi card, minimal by default
Card now opens in a slim single-line pill showing only Trust Score.
Tapping it expands to the full card (citizen status, world Kurdish
count, referral actions); a chevron in the expanded header collapses
it back. Expand state persists across scroll/recycling within the
session but resets to collapsed on a fresh app launch.
2026-07-08 10:18:04 -07:00
pezkuwichain be887e5f50 Merge main: pull in critical Tron ChainConnection fix + CI infra fixes
main now has the fix for a serious bug that also affects this branch:
ChainRegistry unconditionally attempted a WSS connection for every
chain including Tron (whose node is a plain REST API, not WSS),
hanging indefinitely and blocking all subsequent chain registration
in the sequential registration loop - a real freeze risk for any user
with the Tron chain enabled, found while diagnosing balances_test.yml.

Also pulls in the various CI-only fixes from PR #11 (unrelated to
app behavior).
2026-07-08 08:39:31 -07:00
pezkuwichain 7dea79dbee fix: use arm64-v8a emulator image on macos-14 runners (#11)
* fix: use arm64-v8a emulator image on macos-14 runners

The "Run balances tests" job has been failing on every scheduled run
for weeks: the emulator requested an x86 system image while
macos-14 GitHub-hosted runners are Apple Silicon (aarch64) - QEMU2
refuses to boot a mismatched-architecture image ("Avd's CPU
Architecture 'x86' is not supported by the QEMU2 emulator on
aarch64 host"), so every adb command against the never-booted
emulator failed with "device not found" for the full 10-minute
boot timeout on every run.

* fix(ci): run balances-test emulator on ubuntu-latest with KVM instead of macos-14

macos-14 (Apple Silicon) GitHub-hosted runners don't expose nested
virtualization to guests, so the Android emulator's HVF backend fails
with HV_UNSUPPORTED and the job times out waiting for boot - this
affects both x86 and arm64-v8a system images, so the arch: arm64-v8a
change alone wasn't sufficient. macos-13 (which previously supported
this via HAXM) was retired by GitHub.

Linux hosted runners support KVM-accelerated emulators once the kvm
device's udev permissions are relaxed, which is the documented setup
for reactivecircus/android-emulator-runner and also faster/cheaper
than macOS runners.

* fix(ci): build instrumentialTest androidTest APK to match AllureAndroidJUnitRunner

run_balances_test.sh has always targeted
io.novafoundation.nova.debug.test/io.qameta.allure.android.runners.AllureAndroidJUnitRunner,
but android_build.yml's "Build debug tests" step built the plain
debug variant's androidTest APK, whose manifest declares the module
default runner (androidx.test.runner.AndroidJUnitRunner, from
allmodules.gradle) - AllureAndroidJUnitRunner is only wired via
testInstrumentationRunner on the dedicated instrumentialTest build
type (app/build.gradle), which was apparently created for exactly
this purpose but never actually wired into CI. Result:
INSTRUMENTATION_FAILED as soon as the emulator boot issue was fixed
and this step was reached for the first time.

instrumentialTest initWith buildTypes.debug (same applicationIdSuffix
'.debug', same default debug signing), so it installs under the same
package next to the already-built debug app APK - only the
androidTest APK's build type needs to change, not the main app build.

Only balances_test.yml sets build-debug-tests: true, so this doesn't
affect any other android_build.yml caller (pull_request.yml has it
explicitly disabled with its own separate pre-existing TODO).

* test: temporarily point android_build.yml ref at this branch for verification

TEMPORARY - reusable workflow calls (uses: ...@ref) pin to that ref's
copy regardless of the caller's branch, so android_build.yml's fix
never actually ran in the previous verification attempts even though
it was committed to this branch. Must revert to @main before merging
this PR, once android_build.yml's changes are on main.

* fix(ci): declare AllureAndroidJUnitRunner on debug build type, not instrumentialTest

AGP only ever compiles one androidTest APK per module, tied to
android.testBuildType (default "debug", never overridden in this
project) - so a testInstrumentationRunner override on any other build
type, including instrumentialTest, is unreachable regardless of which
gradle task or main-app variant is used. That's why the previous
attempt (assembleInstrumentialTestAndroidTest) failed outright: no
such task exists, since androidTest is only ever generated for
testBuildType.

Reverts the previous commit's task/path changes back to
assembleDebugAndroidTest / app/androidTest/debug/..., and instead
moves the testInstrumentationRunner override onto the debug build
type itself, which is what androidTest actually compiles against and
what run_balances_test.sh has always targeted. Also drops the dead
override from instrumentialTest now that it's confirmed non-functional
there.

* debug(ci): dump pm list instrumentation before running balances test

Diagnostic only - the previous fix (testInstrumentationRunner moved
to the debug build type's defaultConfig) still hit the identical
INSTRUMENTATION_FAILED for AllureAndroidJUnitRunner even though both
APKs now install successfully with the corrected paths. Need to see
what PackageManager actually registered for the installed test APK
rather than keep guessing from Gradle DSL evaluation-order theory -
allmodules.gradle's subprojects{} block also sets
testInstrumentationRunner on every module including app, and it's not
yet confirmed which assignment wins.

* fix(ci): use current io.pezkuwichain.wallet package instead of stale upstream name

Diagnostic (pm list instrumentation) confirmed the real, final root
cause: AllureAndroidJUnitRunner IS correctly registered on-device
after the previous fix, but under the app's real applicationId
(io.pezkuwichain.wallet, set in build.gradle since the Pezkuwi rebrand)
- not the pre-rebrand upstream Nova Wallet package
(io.novafoundation.nova) these scripts still hardcoded. Every previous
INSTRUMENTATION_FAILED was simply am instrument targeting a package
that was never installed.

Also fixes the identical stale reference in run_instrumental_tests.sh
(currently unused by any workflow, but has the same bug).

The BalancesIntegrationTest class's own Kotlin package
(io.novafoundation.nova.balances) is untouched - that's the test
class's real source package on disk, unrelated to the app's
applicationId, and was never part of the bug.

* fix(ci): bound run-tests to 25min and unbuffer python output

Latest verification run hung for 1h15m+ inside am instrument with
zero visible progress - had to be cancelled manually. Post-mortem:
Python's stdout is fully buffered (not line-buffered) when piped
under GitHub Actions' `run:`, so the script's own 5s heartbeat prints
(explicitly there to avoid CI's inactivity-based cancellation) never
actually reached the log until the buffer filled near the very end,
making the run look identical to a genuine hang for its entire
duration with no way to tell what BalancesIntegrationTest was doing.

- timeout-minutes: 25 on run-tests bounds any future hang to a fixed,
  reasonable ceiling instead of requiring a manual cancel after an
  hour+.
- python -u unbuffers stdout so the next run's logs show real-time
  heartbeat/output, giving actual visibility into where a hang (or
  slow chain RPC) occurs instead of a silent multi-hour gap.

Root cause of the hang itself is still open - this only makes it
diagnosable and bounds its cost.

* fix: skip WSS ChainConnection setup for Tron-based chains

Real root cause of the 1h15m+ hang in the previous verification run
(had to be cancelled manually): ChainRegistry registers all chains
sequentially (diff.newOrUpdated.forEach { registerChain(it) }), and
registerConnection() unconditionally called
connectionPool.setupConnection(chain), which creates a ChainConnection
backed by a WSS-only SocketService - for every chain, with no check
for chain type. Tron's node (https://api.trongrid.io) is a plain REST
API with no WebSocket support, so this connection attempt just hangs
forever with no timeout, and since registration is sequential and
Pezkuwi chains (including Tron) are ordered first in the merged chain
list, every chain after it in the list never finishes registering
either - including all the third-party chains BalancesIntegrationTest
actually exercises.

This isn't just a test problem: any real user with the Tron chain
enabled would hit the same registry-wide freeze during chain sync.

Tron balance/transfer operations already go through their own
TronGridApi REST client (built in the Phase 1/2 Tron work),
independent of ConnectionPool/ChainConnection - confirmed nothing else
reads chainRegistry.getConnection() for a Tron chain id - so skipping
ChainConnection setup entirely for isTronBased chains is safe.

* debug(ci): stream live logcat during test run

Diagnostic only. Previous fix (skip WSS ChainConnection for
isTronBased chains) did NOT resolve the hang - identical symptom
(silent for the full 25min timeout, just heartbeats, nothing from the
actual test process). Need real device-side visibility into what's
actually happening (network calls, coroutine timeouts, ANRs) instead
of guessing blind from am instrument's own stdout/stderr, which stays
completely silent until the process exits.

* debug(ci): SIGQUIT thread dump 3min into a hung run, bump logcat to debug level

Previous diagnostic (live logcat at info level) showed the app staying
genuinely alive (GC cycles, system chatter) but produced zero signal
from the test itself after the initial successful chains.json fetch -
no WSS/DB/coroutine activity visible, likely because relevant logging
is below info level. Static code reading (ChainConnection.setup(),
ChainSyncService.syncUp(), ChainFetcher) hasn't turned up an obvious
blocking call, and this exact hang predates this session by at least
a month (zero successes in the last 100 scheduled runs going back to
2026-06-09) - so it's a real, previously-latent bug in the app/test
itself, never previously reached because every earlier run failed at
an earlier CI-infra stage.

kill -3 on the app process forces ART to dump every thread's Java
stack trace to logcat (the standard ANR-diagnosis technique) - this
should show exactly which coroutine/thread is parked and where,
instead of continuing to guess from log filtering.

* fix(ci): bump run-tests timeout to 90min, drop now-unneeded SIGQUIT diagnostic

With the chain blacklist fixed, the previous run genuinely started
executing the 160-case parameterized test suite (visible TestRunner
started/finished events for real chains) instead of hanging silently
- first time this has happened in this entire investigation.

It still hit the 25min ceiling: each test case has an explicit
withTimeout(80.seconds), and several chains that aren't fully dead
(so not blacklisted) but are slow/unresponsive burn the full 80s
before failing. With 160 total test cases, the worst-case aggregate
easily exceeds 25 minutes even with zero actual hangs - so the
timeout needs to be realistic for the test's own design, not just
long enough to catch a true infinite hang. 90min matches
android_build.yml's existing precedent for this project's CI jobs.

The SIGQUIT-after-3-minutes diagnostic added earlier is now
counterproductive noise: any healthy run legitimately takes far
longer than 3 minutes to get through 160 cases, so it would fire on
every run rather than only genuine hangs. Removed now that its actual
purpose (finding the real hang) is done - the blacklist was the
answer, not something a thread dump would have caught anyway (dead
sockets, not deadlocked application code).

* chore: revert temporary android_build.yml ref pin back to @main

Was pointed at this branch only to verify android_build.yml's own
fixes actually took effect during iteration (reusable workflow calls
resolve against the ref they're pinned to, not the caller's branch).
android_build.yml is now byte-identical to main (the wrong task-name
attempt was fully reverted in an earlier commit), so this is a no-op
functionally - just restoring the correct long-term reference before
merge.
2026-07-08 06:36:31 -07:00
pezkuwichain 4a2fc5681a ci: add workflow_dispatch escape hatch to pull_request.yml (#8)
pull_request-triggered runs of this workflow have stopped firing
entirely for at least one recent PR (no check-suite created at all
for the GitHub Actions app, while two other installed apps sit stuck
in "queued") - root cause is outside what's fixable via the repo's
own Actions config/API access. This adds a manual workflow_dispatch
path (branch input) so a build+test run can still be triggered
directly against any branch while that's being sorted out.
2026-07-07 11:56:50 -07:00
pezkuwichain 351114b349 feat: insert TRX into default token order after BNB 2026-07-07 11:00:50 -07:00
pezkuwichain 99ed9486fe feat: extend default token order (BTC, ETH, BNB, AVAX, LINK, UNI, TAO)
Extends the existing HEZ/PEZ/USDT/DOT/KSM/USDC priority list with
seven more major tokens, keeping the same alphabetical fallback for
everything else.
2026-07-07 11:00:16 -07:00
pezkuwichain 30a86418df release: bump versionName to 1.1.2 (Tron send/transfer) 2026-07-07 08:50:42 -07:00
pezkuwichain 4537be4496 fix: ktlint violations (nested-comment doc text, line length)
Doc comments describing "/wallet/*" endpoints were parsed as opening
a nested block comment (Kotlin block comments nest, unlike Java/C),
leaving the outer KDoc unterminated - not just a lint nit, ktlint
flagged these as invalid Kotlin files. Reworded to drop the trailing
"*". Also wraps two over-long function signatures/calls.
2026-07-07 07:17:43 -07:00
pezkuwichain 3cd07abe55 Add Tron (TRC20/TRX) send/transfer support
Reuses the existing generic fee-sufficiency validation
(sufficientTransferableBalanceToPayOriginFee) and send flow
unchanged. Transaction construction goes through TronGrid's own
createtransaction/triggersmartcontract endpoints (verified live
against Shasta testnet) rather than a hand-rolled protobuf
implementation; signing reuses the existing secp256k1 path
(SignerPayloadRaw.skipMessageHashing) already used for Ethereum,
no new crypto library. Also fixes a Phase 1 gap: Chain.isValidAddress()
had no isTronBased branch, so every Tron send would have failed
address validation.

No Energy staking/delegation/rental UI - only Tron's default
protocol behavior (burn TRX to cover Bandwidth/Energy shortfall).
2026-07-07 07:08:22 -07:00
pezkuwichain 46d2a91510 Add read-only Tron (TRC20) chain family support (#9)
* Add read-only Tron (TRC20) chain family support

Adds Tron as a third chain family alongside Substrate and EVM:
address derivation (BIP44 coin type 195, secp256k1 reused from the
existing Ethereum path, Base58Check encoding), TronGrid-backed TRX
and TRC20 USDT balance display, and a Room migration for the new
per-account Tron key/address columns. Read-only only — no send,
signing, or broadcast support yet.

* fix: exhaustive when branches for Trc20/TronNative asset types

ChainExt.kt's onChainAssetId and Common.kt's existentialDepositError
both switch exhaustively over Chain.Asset.Type and didn't have cases
for the new Trc20/TronNative variants, breaking compilation. Trc20
mirrors EvmErc20 (contract address as the on-chain id, dust burns
rather than transfers on removal); TronNative mirrors EvmNative.
2026-07-07 06:03:20 -07:00
pezkuwichain 85bde7e448 Redesign: dashboard card + action row (v1.1.1) (#6)
* redesign(dashboard): brand-book restyle of Pezkuwi dashboard card

Match the brand book / handoff screenshot:
- bg_pezkuwi_dashboard: blue/indigo gradient -> frosted dark-navy surface
  (#1C1F2E) with a 1px periwinkle hairline, 20dp corners.
- item_pezkuwi_dashboard: replace hardcoded non-brand colors —
  trust value amber #FFD54F -> zer #FDB813; welati count -> positive #2FC864;
  Approve/start buttons Material-green -> kesk #009639; Sign red -> sor #E2231A;
  Share button yellow #FDD835 -> frosted-navy secondary #2A2F45 (white text);
  blue-grey text -> brand white tokens. Pill-er 12dp button corners.

* redesign(actions): circular action buttons (primary green Send + dark rest)

Match the brand-book screenshot: the balance action row (Send/Receive/Swap/
Buy/Gift) becomes circular icon buttons with a label below — Send on a kesk
green circle, the rest on frosted-dark circles. IDs preserved (used only for
click + isEnabled), so AssetsTotalBalanceView keeps working.

* redesign(dashboard): pro-level Pezkuwi card layout

Rework the card to match the brand-book screenshot: header row with a small
Newroz-flame icon + title/roles on the left and the citizen count on the right;
trust score row; full-height (48dp) pill-er (14dp) action buttons — Approve
(kesk, bold), Sign (sor), Share (frosted-dark with hairline). Adds the small
ic_nevroz_flame icon.

* release: bump versionName to 1.1.1 (dashboard & action-row redesign)
2026-06-14 23:34:49 -07:00
pezkuwichain 37c2edc6cd ci(deploy): support staged production rollout (userFraction) (#5)
Add an 'inProgress' status + a user_fraction input so production releases can
roll out gradually (e.g. 0.2 = 20%) instead of only 100% (completed).
userFraction is passed only when status=inProgress; ignored otherwise.
2026-06-14 23:02:50 -07:00
pezkuwichain 87bacc3f7c ci: fix develop PR build signing (validateSigningDevelop) (#4)
* ci: wire develop_key.jks into PR build (fix validateSigningDevelop)

The PR build runs assembleDevelop (signingConfigs.dev = develop_key.jks) but the
reusable workflow only decoded github/market keystores, so validateSigningDevelop
always failed. Add a develop-keystore decode step (reusing the existing
BASE64_DEV_KEYSTORE_FILE secret + CI_KEYSTORE_* passwords) and pass
keystore-file-name: develop_key.jks from pull_request.yml.

[temp] pin reusable workflow to the branch to validate before merge; reverted to
@main in the next commit.

* ci: revert reusable-workflow pin back to @main

Fix validated green on PR #4 (test/Build app and test passed, develop signing
works). Restore @main pin for the final merged state.
2026-06-14 22:51:12 -07:00
pezkuwichain 22422c85da Redesign: brand-book alignment + forbidden-color purge (v1.1.0) (#3)
* redesign(colors): purge forbidden magenta/purple from palette

Brand book permits only the Kurdistan palette (kesk/sor/zer/fire) + navy.
Replace the four Nova-legacy violations in common colors.xml (names preserved,
so no references break):
- crowdloan_banner_gradient_start  #BD387F -> #009639 (kesk)
- networks_banner_gradient_end     #661D78 -> #017A2F (kesk-700)
- chip_on_card_background           #443679 -> #3D999EC7 (frosted periwinkle)
- button_wallet_connect_background  #353D67 -> #1F2A4D (neutral navy)

Repo-wide grep confirmed no other hardcoded magenta/purple literals or
purple/pink-named resources remain.

* redesign(type): adopt brand fonts (Space Grotesk / Plus Jakarta Sans / JetBrains Mono)

Brand book typography. Add OFL static fonts under common/res/font and repoint
the theme font attrs (consumed app-wide via ?attr/font* in styles.xml):
- fontRegular     -> Plus Jakarta Sans Regular (body/UI)
- fontSemiBold    -> Plus Jakarta Sans SemiBold
- fontBold/ExtraBold -> Space Grotesk Bold (display: balances, titles)
- fontExtraLight  -> Plus Jakarta Sans Light
- Monospace text appearance (addresses/hashes) -> JetBrains Mono

Static TTFs chosen (minSdk 24 < variable-font API 26). All five verified to
cover Turkish + Kurdish Kurmancî glyphs (ş ğ ı İ ê î û ç …).

* redesign(splash): replace map+wordmark logo with Newroz flame brand mark

The first-launch splash logo (ic_loading_screen_logo) showed a Kurdistan map
with a baked-in wordmark. Per the brand book the mark is the Newroz flame.
Rasterized assets/nevroz-fire-flame.svg into the existing 6 density slots
(same pixel dimensions = drop-in, no bg_splash.xml change, transparent WebP so
it composites cleanly over the splash background).

* redesign(onboarding): welcome hero -> Global United States of Pezkuwi

Replace the legacy onboarding hero (ic_create_wallet_background, whose six
density PNGs had inconsistent broken dimensions) with the brand 'Global United
States of Pezkuwi' infographic. Consolidate to a single high-res WebP in
drawable-nodpi (1408x768, 204K vs 1.75MB PNG) and switch the welcome ImageView
scaleType centerCrop -> fitCenter so it shows full and uncropped above the
CTA buttons, per the brand book.

* redesign(assets): purge magenta/purple from raster illustrations

colors.xml only covers named colors; these raster drawables still carried
forbidden magenta/purple/pink pixels. Selectively rotate the 255-350 deg hue
band (purple-magenta-pink) toward kesk green/teal across all densities,
preserving gradients, shapes and the on-brand blues:
- ic_pink_siri, ic_networks_banner_image, ic_no_added_networks,
  ic_import_option_hardware, tinder_gov (6 densities each).
Third-party ic_powered_by_oak (OAK Network trademark) left untouched.
crowdloan_banner_image is being handled separately.

* redesign(assets): de-pink crowdloan banner across all densities

The crowdloan banner's magenta sphere was recolored to brand sor red (xxxhdpi).
Propagate that fix to the other five densities by downscaling the corrected
xxxhdpi master (LANCZOS), so every device shows the same brand-clean banner.
Pink-pixel scan now 0% on all six variants.

* chore: remove pre-production debug code (release-blocker)

CHANGELOG_PEZKUWI listed debug code to strip before production; two items were
still live:
- FeeLoaderV2Provider: the fee-retry dialog showed a raw "DEBUG: <err> | Runtime:
  <diagnostics>" string to users -> reverted to the localized resource string and
  dropped the diagnostics lookup.
- RuntimeFactory: removed the companion lastDiagnostics field and its assignment
  (plus the now-dangling diagnostic vars), and the matching log line in the
  PezkuwiLiveTransferTest androidTest.
Items #3-#6 were already clean. Repo now has no 'DEBUG:' literals or
lastDiagnostics references. CHANGELOG marked cleaned.

* docs: add BRAND.md — enforceable wallet brand rules

Kurdistan-only palette (no pink/magenta/purple), brand fonts, Newroz flame mark,
a PR brand checklist with a raster pink-scan snippet, the third-party-logo
exception, and the Apache-2.0 attribution rule (keep LICENSE/NOTICE). Points to
the canonical brand book at wiki.pezkuwichain.io/brand.

* release: bump versionName to 1.1.0 (brand-book UI redesign)

Live Play version is 1.0.4; minor bump for the UI redesign. versionCode stays
CI-managed (CI_BUILD_ID). Add the v1.1.0 entry to CHANGELOG_PEZKUWI.
2026-06-14 22:20:33 -07:00
pezkuwichain f5df785a42 fix(ci): free disk space before building debug androidTest APKs (#1)
The scheduled 'Run balances tests' workflow has been failing for weeks
with 'No space left on device' — assembleDebug + assembleDebugAndroidTest
for every module exceeds the ~14 GB free on GitHub-hosted runners.

Add an opt-in free-disk-space input to the reusable build workflow that
removes preinstalled toolchains we never use (dotnet, ghc, CodeQL, swift,
boost, etc., ~30+ GB), and enable it for the balances test build. Other
callers of the reusable workflow are unaffected.
2026-06-11 07:22:10 -07:00
pezkuwichain 5245f86678 fix: use main branch in github release workflow v1.0.4 2026-04-20 22:16:43 +03:00
pezkuwichain 817ce246b4 fix: remove trailing blank lines before closing braces (ktlint) 2026-04-20 16:57:22 +03:00
pezkuwichain a793993c1f fix: use Locale.US for DecimalFormat to fix $0 price display on Turkish locale devices
Bump version to 1.0.4
2026-04-20 16:28:16 +03:00
pezkuwichain f5b38eed8c chore: remove Branch.io SDK and route deep links through own domain
Branch.io was inherited from Nova Wallet fork but never configured.
Removed SDK integration, manifest intent filters, Gradle dependencies,
Dagger DI modules, and string resources. Deep linking now routes
exclusively through app.pezkuwichain.io with verified assetlinks.json.
2026-03-23 22:59:05 +03:00
pezkuwichain 28d0391d72 fix: store native libs uncompressed with 16KB zip alignment
Set jniLibs.useLegacyPackaging = false to ensure .so files are stored
uncompressed and 16KB-aligned within the AAB, as required by Google Play
for Android 15+ compatibility.
2026-03-14 19:50:06 +03:00
pezkuwichain 64d727dd21 fix: 16KB page alignment for all native libraries
- Rebuild renderscript-toolkit.aar from source with NDK 27 and 16KB alignment
- Rebuild libsr25519java.so from substrate-sdk source with 16KB alignment
- Realign libsqlcipher.so ELF segments to 16KB (preserves JNI API compatibility)
- Add jniLibs overrides for sr25519java and sqlcipher to replace AAR versions
- All native .so files now have 0x4000 (16KB) LOAD segment alignment
2026-03-14 18:35:15 +03:00
pezkuwichain 55df31b29b feat: prepare v1.0.3 production release with 16KB page alignment
- Add 16KB page size alignment for native Rust libraries (Google Play requirement)
- Make Play Store workflow parametric (track/status as inputs)
- Update release notes for all languages (en, tr, ku)
- Add .gitignore entries for node_modules and version.properties
2026-03-14 16:49:39 +03:00
pezkuwichain b4932c8b6e chore: bump version to 1.0.2 for Play Store release
Complete Turkish and Kurdish translations for all UI strings.
2026-03-11 06:27:11 +03:00
pezkuwichain 2fe578048b Fix unescaped apostrophes and remaining positional format specifiers in translations 2026-03-11 02:09:20 +03:00
pezkuwichain a91b1cb22b Fix positional format specifiers in English strings.xml 2026-03-11 01:56:24 +03:00
pezkuwichain ed0ffe0a3c Fix positional format specifiers in Kurdish strings.xml 2026-03-11 01:27:45 +03:00
pezkuwichain cc44f22163 fix: use positional format specifiers in Turkish translations
Convert multiple %s to %1$s, %2$s etc. in strings with multiple
substitutions to comply with Android resource format requirements.
2026-03-11 01:19:45 +03:00
pezkuwichain 8bbeddf2ba feat: complete Turkish and Kurdish translations for all UI strings
Turkish: expanded from 55 strings to full 2018 translatable strings
Kurdish: added 2 missing strings for complete coverage
2026-03-11 01:09:50 +03:00
pezkuwichain c965746f8f fix: use commit-count based versionCode to prevent downgrade on Firebase
CI_BUILD_ID was using github.run_number which is per-workflow, causing
different workflows to produce different versionCodes (144 vs 9).
Now computed from git commit count + offset, consistent across all workflows.
Also added bundle task to local auto-increment.
v1.0.1
2026-03-10 02:18:55 +03:00
pezkuwichain 8d150266fb fix: detect on-chain dispatch errors for citizenship and staking extrinsics
Switch from submitExtrinsic (fire-and-forget) to submitExtrinsicAndAwaitExecution
which waits for block inclusion and checks ExtrinsicFailed events. Previously the
app showed success even when pallet-level errors occurred (e.g. ReferrerNotCitizen,
AlreadyExists). Now dispatch errors are properly surfaced to the user.
2026-03-09 02:46:49 +03:00
pezkuwichain 44fd64496b feat: add complete Pezkuwi/citizenship translations to all 14 languages
Added (KYC) suffix to Apply&Actions button label in all languages.
Added ~29 missing citizenship and dashboard string keys to 12 languages
that were missing them (ru, es, pt, fr, it, ko, ja, zh-rCN, in, vi, hu, pl).
Added 3 missing dashboard keys to TR and KU.
2026-03-08 23:57:41 +03:00
pezkuwichain 84d0f39f8a fix: replace setFragmentResult with interface callback for citizenship dismiss
setFragmentResult API not available in this project. Use CitizenshipDismissListener
interface instead for parent-child fragment communication.
2026-03-08 19:06:21 +03:00
pezkuwichain 138c0199c9 fix: auto-refresh Pezkuwi dashboard card after actions
Add dashboardRefreshSignal to trigger re-fetch on swipe-to-refresh,
onResume, citizenship bottom sheet dismiss, and score tracking.
Rename button label to "Apply & Actions (KYC)" for clarity.
2026-03-08 17:32:40 +03:00
pezkuwichain cbce1070b4 Bump version to 1.0.1 and add release notes 2026-03-05 16:46:23 +03:00
pezkuwichain ba057617d3 fix: ktlint multiline-if-else braces in PezkuwiDashboardAdapter 2026-03-05 02:40:08 +03:00
pezkuwichain 91f2b5d254 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.
2026-03-05 02:33:31 +03:00
pezkuwichain 6939dfd4c3 Fix auto-pr to not fail when branches are already in sync 2026-03-02 15:08:24 +03:00
pezkuwichain 2177683838 Replace force-push sync with PR-based auto-merge workflow 2026-03-02 14:22:29 +03:00
pezkuwichain 81b0491691 fix: use safe call for nullable String in ifBlank 2026-03-01 22:22:41 +03:00
pezkuwichain 5705d0d578 fix: resolve citizenship bottom sheet not opening on button tap
Event(null) was swallowed by EventObserver's ?.let pattern, preventing
the CitizenshipBottomSheet from opening when tapping dashboard buttons.
Changed to Event("") with ifBlank conversion to preserve null referrer
semantics while ensuring the observer callback fires.
2026-03-01 22:08:19 +03:00
pezkuwichain d33a0a6289 fix: use https telegram link in dashboard share referral button 2026-02-28 04:22:16 +03:00
pezkuwichain 5771fbc10b fix: use https telegram link instead of custom scheme for sharing
Custom scheme pezkuwiwallet:// is not clickable in WhatsApp and
other messaging apps. Use https://t.me/pezkuwichainBot?start=ADDRESS
which is universally clickable and auto-fills the referrer field.
2026-02-28 02:40:06 +03:00
pezkuwichain 66be33c43e fix: disable referrer input when pre-filled from deep link
Prevent user from editing or clearing the referrer address when it
comes from a referral deep link to ensure correct on-chain submission.
2026-02-28 02:00:08 +03:00
pezkuwichain 33c6559a41 fix: connect referral link to blockchain via deep link handler
When Alice shares a referral link, it now generates a deep link URL
(pezkuwiwallet://pezkuwi/open/citizenship?referrer=address) that
auto-opens the citizenship form with Alice's address pre-filled as
the referrer, fixing the bug where referrer defaulted to founder.
2026-02-27 22:11:34 +03:00
pezkuwichain 894e5dac22 fix: prevent staking dashboard hang when exposure flag not cached
isPagedExposuresUsed() called storageCache.getEntry() which suspends
forever if the entry doesn't exist. The flag is only written by
ValidatorExposureUpdater (staking detail flow), so the dashboard
would hang indefinitely waiting for it.

Check cache first with isFullKeyInCache() and default to paged
exposures when the flag is absent. Also remove debug log statements.
2026-02-27 13:41:26 +03:00
pezkuwichain 2d0d46688e fix: save exposure flag for uncertain state to prevent setup screen hang
When neither paged nor legacy exposures exist for the current era,
ValidatorExposureUpdater returned early without saving the
PagedExposuresUsed flag. This caused storageCache.getEntry() to
suspend indefinitely, blocking the staking setup screen.

Save the flag as false for UNCERTAIN state so downstream code
can proceed with empty exposure data instead of hanging.
2026-02-27 04:30:53 +03:00