Skip to content

Recents search — Android parity with iOS#145

Merged
gemdev111 merged 9 commits intomainfrom
recents-search
Apr 15, 2026
Merged

Recents search — Android parity with iOS#145
gemdev111 merged 9 commits intomainfrom
recents-search

Conversation

@gemdev111
Copy link
Copy Markdown
Contributor

@gemdev111 gemdev111 commented Apr 14, 2026

closes #130

Summary

Implement the recents feature for asset selection flows on Android, matching iOS behavior. Track recently selected assets and display them as chip shortcuts across Send, Buy, Receive, Swap, and Search screens. Split Manage and Search into dedicated screens. Disable asset detail navigation on Manage. Hide tags and filter icon during search.

Changes

Screen split

  • Split AssetsManageScreen into dedicated AssetsManageScreen (toggle visibility) and AssetsSearchScreen (browse/pick assets with recents recording)
  • Manage screen: rows no longer navigate to asset detail (onSelect = null), only the Switch toggles visibility
  • Search screen: no filter icon (availableChains = emptyList()), records RecentType.Search on asset selection
  • Updated AssetsManageNavigation to route assetsManageRouteAssetsManageScreen, assetsSearchRouteAssetsSearchScreen

UI behavior (matching iOS)

  • Tags (TabsBar) hide when search query is active (showTags = query.text.isEmpty())
  • Filter icon hidden when availableChains is empty (search screen)
  • Separate onSelectRecent callback on AssetSelectScene — chip taps navigate only, list taps may record
  • Renamed populartShowedshowPopular

Recents recording (matching iOS)

  • Buy list tap → records Buy type
  • Receive list tap → records Receive type
  • Search list tap → records Search type
  • Send/Swap list tap → no recording (recorded on tx confirmation only)
  • Chip tap → navigate only, never records
  • Removed redundant recording from GetReceiveAssetInfoImpl (was recording on every Receive screen load, causing chip-tap reorder bug) and FiatViewModel (was double-recording on Buy quote fetch)

Lightweight recents query

  • Query the asset table directly instead of the heavy asset_info view — no balance/price/metadata loaded for chips that only render icon + symbol
  • SQL-level filtering via AssetFilter enum (Buyable, Swappable, HasBalance) with NOT :flag OR condition pattern
  • RecentAssetsRequest data class encapsulates query parameters
  • ORDER BY MAX(addedAt) DESC, id ASC for deterministic ordering
  • Recents decoupled from user chain/balance filter toggles via snapshotFlow on query text only

ViewModel updates

  • getRecentType(): RecentType?open val showRecents: Boolean (property, not function)
  • Added open fun assetFilters(): Set<AssetFilter> hook with per-flow overrides (Buy=Buyable, Send=HasBalance, Swap=Swappable)
  • Added UpdateRecentAsset coordinator + updateRecent() method on BaseAssetSelectViewModel
  • PriceAlertsSelectViewModel: showRecents = false
  • Swap recents enabled (was disabled with TODO)

Dead code cleanup

  • Deleted AddBuyRecent interface, impl, and DI registration
  • Removed unused convenience methods from AddRecentActivity
  • Removed addBuyRecent injection from FiatViewModel
  • Fixed FiatViewModelTest to match updated constructor

New files

  • AssetFilter.kt — enum: Buyable, Swappable, HasBalance
  • RecentAssetsRequest.kt — query parameters data class
  • UpdateRecentAsset.kt + UpdateRecentAssetImpl.kt — coordinator for recording recents
  • AssetsSearchScreen.kt — dedicated search screen
  • RecentAssetsConfigTest.kt — tests for per-flow filter contracts

iOS parity checklist

  • Recording: Buy/Receive on selection, Send/Swap on confirmation, Search on selection
  • Chip tap: navigate only, no recording
  • Filtering: Buyable (Buy), HasBalance (Send), Swappable (Swap), none (Receive/Search)
  • Display: hidden on Manage/PriceAlert, shown on Send/Buy/Receive/Swap/Search
  • Tags hide on search
  • Filter icon hidden on search screen
  • Manage rows not tappable (visibility toggle only)
  • Lightweight query from asset table
  • Wallet-scoped recents
  • Limit 10, ordered by most recent

Introduce Search type for tracking asset selection in the search flow.
Add UpdateRecentAsset coordinator with DI wiring. Wire updateRecent
into BaseAssetSelectViewModel and all subclasses.
Separate manage (toggle visibility) and search (browse/pick assets) into
dedicated screens. Record RecentType on asset selection for Buy and
Receive flows. Add onSelectRecent callback to separate chip tap
(navigate only) from list tap (record + navigate). Hide filter icon on
search screen. Rename populartShowed to showPopular.
Replace heavy asset_info query with lightweight query on asset table.
Return Flow<List<Asset>> instead of Flow<List<AssetInfo>>. Add AssetFilter
enum (Buyable, Swappable, HasBalance) with SQL-level filtering via
NOT IN + hasFilters guard pattern. Decouple recents from user chain/balance
toggles using snapshotFlow on query text only. Order by MAX(addedAt) DESC
with deterministic tiebreaker.
Remove addRecentReceive from GetReceiveAssetInfoImpl (was recording on
every Receive screen load, causing chip-tap reorder bug). Remove
addBuyRecent from FiatViewModel (redundant with selection recording).
Delete AddBuyRecent interface, impl, and DI registration. Remove unused
convenience methods from AddRecentActivity.
Verify per-flow asset filter contracts: Buy filters to buyable, Send
filters to has-balance, Receive has no filters. Verify RecentAssetsRequest
defaults and filter composition.
@gemdev111 gemdev111 changed the title Recents search Recents search — Android parity with iOS Apr 14, 2026
@gemdev111 gemdev111 self-assigned this Apr 14, 2026
@gemdev111 gemdev111 marked this pull request as ready for review April 14, 2026 14:31
LocalContentColor.current
else
MaterialTheme.colorScheme.primary,
contentDescription = "Filter by networks",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
contentDescription = "Filter by networks",
contentDescription = null

scrollable = true,
equalWidth = false,
) { item ->
val stringId = when (item) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to view model

Extract AssetTag-to-string mapping into a new AssetTagExt.labelRes() extension (android/ui/.../AssetTagExt.kt) and replace the when block in AssetSelectScene with stringResource(item.labelRes()). Also set the filter icon's contentDescription to null. Centralizes label logic and cleans up the scene view code.
Add tools:replace="android:dataExtractionRules" to the application element in AndroidManifest.xml so the app can override android:dataExtractionRules during manifest merging (resolving conflicts or allowing a custom data extraction rules entry from the app).
@gemdev111 gemdev111 merged commit c82205d into main Apr 15, 2026
3 checks passed
@gemdev111 gemdev111 deleted the recents-search branch April 15, 2026 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consolidate recents

3 participants