Add threads list screen for rooms:
- Add `ThreadsListService` to subscribe to thread changes in the room.
- Create `ThreadsListView` and its associated node a presenters (the UI may change).
- Add a menu icon in the room screen to open it.
This is still pending info about unread threads, so several UI components related to it will be hidden.
* Add feature flag and use it to hide the access to this new screen
---------
Co-authored-by: ElementBot <android@element.io>
* Add support for slash commands
* Update screenshots
* Rename module `slash` to `slashcommands`
* Rename `SlashCommand` to `SlashCommandService`
* Introduce MsgType in order to send text message with a different msgtype value.
* Format file and add parameter names, add default values and cleanup
* Add isSupported parameter to filter out unsupported yet commands.
* Slash commands: disable suggestions if the feature is disabled.
* Fix sending shrug command.
* Add missing test on SuggestionsProcessor
* Add tests on MessageComposerPresenter about slash command.
* Fix import ordering
* Add missing tests on CommandExecutor
* Add missing tests in MarkdownTextEditorStateTest
* Slash commands: Improve code when sending message with prefix.
* Slash commands: Add support for /unflip
---------
Co-authored-by: ElementBot <android@element.io>
* Add floating date indicator while scrolling the timeline (#6433)
* Add `FeatureFlags.FloatingDateBadge`. This enables displaying the floating date badge in the timeline as you scroll.
* Don't display the floating badge if the timeline isn't reversed. Otherwise, this will affect talkback users and break the existing navigation
* Use `TimelineItem.formattedDate()` to get the date to display. Always try finding the closest one (usually it will be just the 1st one we try).
* Align designs with iOS. Also fix shadows in fade animation by adding some paddings.
* Update screenshots
---------
Co-authored-by: Gianluca Iavicoli <gianluca.iavicoli04@gmail.com>
Co-authored-by: ElementBot <android@element.io>
Enhanced the payment timeline card to display the recipient/sender address:
- Added truncatedToAddress and truncatedFromAddress to TimelineItemPaymentContent
- New truncateAddress() helper (first 8 + last 6 chars)
- Payment card now shows "To: addr_tes...ytjqp" for sent payments
- And "From: addr_tes...pd0hq" for received payments
- Updated wrapper to expose new properties
The card now displays:
- Amount in ADA (large, bold)
- Sent/Received indicator with Cardano icon
- Truncated recipient/sender address
- Status chip (Pending/Confirmed/Failed with icons)
- Truncated tx hash (tappable to CardanoScan)
- Testnet badge when applicable
- "View on CardanoScan →" link for confirmed transactions
The wallet button should only appear in genuine DM rooms. The previous
logic (isDm || activeMembersCount == 2L) was overly broad as it would
show the wallet in any 2-person room, including private rooms that
are not direct messages.
Now uses only roomInfo.isDm which properly checks:
- isDirect flag is true (Matrix spec DM indicator)
- activeMembersCount <= 2 (at most 2 active members)
This ensures the wallet button only appears in real 1:1 DM rooms.
The isDm check requires isDirect=true which is not set for rooms
created via API. Relax the check to also show the wallet button
in any room with exactly 2 active members.
Phase 4: Final features for Element X ADA alpha
## Wallet Setup Flow
- New setup state machine: WELCOME -> GENERATING -> ADDRESS -> BACKUP_PROMPT -> COMPLETE
- WalletSetupState.kt: state data class and events
- WalletSetupPresenter.kt: generates wallet via CardanoKeyStorage, state transitions
- WalletSetupView.kt: Compose UI with FLAG_SECURE for mnemonic display
- WalletSetupNode.kt: Appyx node with setup callbacks
- Wired into MessagesFlowNode via NavTarget.WalletSetup
- SSSS backup skipped for alpha (local-only, TODO for Phase 5)
## Payment Event Wiring
- PaymentProgressPresenter now sends Matrix payment event on tx confirmation
- Added roomId to PaymentProgressNode.Inputs and NavTarget.Progress
- Calls paymentEventSender.sendPaymentEvent() when SubmissionState.Confirmed
- Non-fatal if event fails (tx already succeeded)
## Files Changed
- features/wallet/impl/setup/ (new directory, 4 files)
- MessagesFlowNode.kt: NavTarget.WalletSetup, navigation wiring
- PaymentFlowNode.kt: roomId passthrough to Progress
- PaymentProgressNode.kt: roomId in Inputs
- PaymentProgressPresenter.kt: event sending on confirmation
Phase 3b: Deferred features completion
Task 1: /pay No-Wallet Guard
- Add noWalletSetup and isCheckingWallet flags to PaymentEntryState
- Update PaymentEntryPresenter to check wallet state early via collectAsState
- Add full-screen "Wallet Required" prompt to PaymentEntryView when no wallet
- Add onOpenWalletSettings callback through the entire navigation chain
- Wire callback in MessagesFlowNode to navigate to WalletPanel
Task 2: Payment Timeline Card (already existed, just fixed event type)
- Fix isPaymentEventType() to check for correct event types:
- co.sulkta.payment.request (was incorrectly com.sulkta.cardano.payment)
- co.sulkta.payment.status (for status updates)
Build verified: assembleGplayDebug passes
- Add WalletPanelView with 4 tabs (Overview, Assets, History, Settings)
- Overview tab shows balance, QR code for receiving, and Send ADA button
- Assets tab shows native tokens held at address
- History tab shows recent transactions with explorer links
- Settings tab shows address, network, and backup/delete options
- Add NativeAsset and TxSummary models to wallet API
- Add getAddressAssets() and getAddressTransactions() to CardanoClient
- Implement new methods in KoiosCardanoClient and FakeCardanoClient
- Add wallet button to MessagesViewTopBar (DM rooms only)
- Add isDmRoom to MessagesState for conditional UI
- Wire navigateToWallet() callback through to MessagesFlowNode
- Add NavTarget.WalletPanel and WalletPanelNode integration
- Add string resources for wallet panel UI
Known limitations:
- Uses Chart icon as placeholder for wallet (Compound lacks wallet icon)
- Wallet setup flow not implemented (TODO)
- Transaction amounts in history need additional API calls to calculate
- CardanoWalletManager moved CardanoClient dep out of AppScope — was causing
Metro MissingBinding at compile time (CardanoClient is SessionScope)
- refreshBalance() now takes balanceLovelace param instead of fetching from client
- WalletState constructor calls fixed with all required fields
- app/build.gradle.kts: added META-INF/gradle/incremental.annotation.processors
to pickFirsts to resolve moshi-kotlin-codegen/lombok resource conflict
- App builds and launches successfully on emulator (verified)
TimelineItemEventContent is a sealed interface in messages:impl, so external
modules cannot add implementers to its hierarchy.
Solution: Create TimelineItemPaymentContentWrapper in messages:impl that
implements the sealed interface and wraps the wallet API's payment content.
Changes:
- Remove inheritance from TimelineItemPaymentContent (wallet:api)
- Add TimelineItemPaymentContentWrapper (messages:impl)
- Update TimelineItemContentFactory to wrap payment content
- Update TimelineItemEventContentView to use wrapper
- Add Timeline.sendRaw() to send custom Matrix events
- Add CustomEventContent type for receiving custom events
- Update TimelineEventContentMapper to handle MsgLikeKind.Other
- Update TimelineItemContentFactory to intercept payment events
- Rewrite DefaultPaymentEventSender to use sendRaw instead of text markers
- Update TimelineItemContentPaymentFactory to parse raw JSON
- Remove text-marker detection from TimelineItemContentMessageFactory
- Update tests to use raw event API
- Mark raw event SDK blocker as RESOLVED in BLOCKERS.md
Event type: co.sulkta.payment.request (reverse-domain format)
Status updates: co.sulkta.payment.status
Benefits:
- Proper Matrix protocol compliance
- No JSON embedded in text messages
- Events won't be indexed by search
- Clean separation from regular messages
Task 7: Timeline Payment Card
- TimelineItemPaymentView integration with TimelineItemEventContentView
- Payment card rendering for both sender and recipient perspectives
- Unit tests for TimelineItemPaymentContent
Task 8: Raw Event Handling
- Modified TimelineItemContentMessageFactory to intercept payment events
- Added isSentByMe parameter propagation through content factories
- FakePaymentEventSender for testing
- Unit tests for TimelineItemContentPaymentFactory
SDK Limitation Workaround:
Since matrix-rust-sdk doesn't expose raw event sending or UnknownContent
raw JSON, payment events are encoded as text messages with a marker:
[cardano-payment:v1]{...json...}
This falls back gracefully for non-wallet clients while enabling
rich payment card rendering for wallet-enabled clients.
Implements the payment flow UI for the Element X ADA wallet:
## Screens
- PaymentEntryScreen: Amount/recipient input with pre-filling from /pay command
- PaymentConfirmationScreen: Transaction details with fee estimation (FLAG_SECURE)
- PaymentProgressScreen: Submission status with polling for confirmation
## Features
- Biometric authentication before payment confirmation
- Matrix user detection with 'hasn't linked wallet' inline message
- CardanoScan explorer link for transaction viewing
- Testnet warning banner
- Insufficient funds detection
## Wire-up
- MessageComposerPresenter intercepts /pay commands
- SlashCommandParser integration for command detection
- Navigation to PaymentFlowNode on valid /pay command
- Snackbar error on parse errors
## Technical
- Circuit presenter pattern with Molecule/Turbine tests
- @PreviewsDayNight for all Composables
- Metro DI integration
- Fake implementations for testing
Includes PaymentEntryPresenterTest, PaymentConfirmationPresenterTest,
PaymentProgressPresenterTest with comprehensive coverage.
* Fix long messages not being clickable
As @bmarty found out, `clip = true` causes the click event to be ignored in some cases. Since we have the shape we want to draw and we're using a custom `onDraw` modifier anyway to cut-out part of the path, we can just draw everything using the modifier and avoid using `clip = true`.
This seems to fix the issue.
* Fix clipping of images or other items that cover the bubble
* Fix borders being displayed for contents
* Extract the layer drawing logic into `drawInLayer` to simplify the inlined code. Remove redundant code, those changes are now in the `drawInLayer` block
* Workaround for lint issue: it seems like detekt can't properly detect usages in content receivers
* Update screenshots
---------
Co-authored-by: ElementBot <android@element.io>