Skip to content

feat: chat profile screen, block/unblock & blocklist - #1174

Merged
bmc08gt merged 15 commits into
code/cashfrom
feat/chat-profile
Jul 31, 2026
Merged

feat: chat profile screen, block/unblock & blocklist#1174
bmc08gt merged 15 commits into
code/cashfrom
feat/chat-profile

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds the tip-DM chat profile screen and a full blocklist feature (block / unblock with an offline-first blocked-users list), plus the supporting data-layer and UI plumbing.

Chat profile

  • Tip-DM profile screen: blurred-avatar header, display name, a Joined {Month Year} line, and a Block action.
  • Vendors profile.v1 UserProfile.join_ts and threads it through the domain UserProfile.joinedAt.
  • Block routes through BlocklistCoordinator and, on success, exits the chat flow back to the Tips list.

Blocklist

  • Offline-first stack: Room blocked_users table (db v25, additive AutoMigration) → BlocklistRemoteMediator (paged, opaque server cursor, atomic replaceAll on refresh) → BlocklistCoordinator (auth-gated, deduped Pager) → BlocklistScreen.
  • Feed consistency: block/unblock optimistically toggle the chat's isHidden flag, and FeedOperations.feed now filters isHidden, so a blocked DM drops out of (and an unblocked one returns to) the Tips feed live — no server round-trip.
  • Launch/resume sync: RealSessionController.onAppInForeground refreshes the blocklist so it stays current without opening the screen.
  • UI: paged LazyColumn with blurred BlurHash avatars, tap-to-unblock (confirmation + per-row spinner via LoadingSuccessState), and a debounced "No One Blocked" empty state (rides out the RemoteMediator → PagingSource hand-off so it never flashes).
  • Slot-driven MenuList/ListItem: a new endSlot overload lets the chat-profile "Block" row swap its chevron for a loading spinner.

Commits (layered)

  1. refactor(myaccount) — reorganize account/profile screens into subpackages
  2. feat(blocklist) — cache blocked users in Room (db v25)
  3. feat(blocklist) — paged RemoteMediator + offline data source
  4. feat(chat) — hide chats from the feed, toggleable locally
  5. feat(ui) — slot-driven end content for MenuList/ListItem
  6. feat(blocklist) — BlocklistCoordinator module + launch/resume sync
  7. feat(blocklist) — blocked-users screen
  8. feat(profile) — expose user join date (join_ts)
  9. feat(messenger) — chat profile screen with block/unblock and join date

Testing

  • ./gradlew :apps:flipcash:app:assembleDebug — green.

bmc08gt added 9 commits July 30, 2026 12:43
…kages

Move MyAccount and UserProfile screen/viewmodel files into internal/myaccount
and internal/userprofile subpackages and update imports/tests accordingly.
Add a blocked_users table (BlockedUserEntity + BlockedUserDao, incl. an atomic
replaceAll) storing each blocked user's id, blocked-at time, and a minimal
resolved display profile so the list renders offline. Bump FlipcashDatabase to
v25 via an additive AutoMigration.
Add BlockedUserDataSource and BlocklistRemoteMediator: page the server blocklist
(opaque cursor, atomic replaceAll on refresh), resolve each user's display
profile via ProfileController, and cache into Room as the single source of truth.
One-way Mapper<> impls convert between server model, entity, and the new core
BlockedUserProfile.
Filter ChatMetadata.isHidden out of FeedOperations.feed so hidden DMs (e.g. a
blocked chat) drop out of the Tips/Contact feeds, and add
ChatCoordinator.setChatHidden (DAO updateHidden -> datasource setHidden) so
blocking/unblocking can flip it optimistically — the feed, which observes Room,
updates live without a server round-trip.
Add ListItem and MenuList overloads that let the caller drive the trailing
endSlot (chevron, loading spinner, etc.) instead of a fixed chevron, so a row
can show per-item state. Existing overloads are unchanged.
New :apps:flipcash:shared:blocklist module with an auth-gated (deduped) Pager
coordinator that owns block/unblock (both toggle the chat's hidden flag) and a
one-shot refresh(). RealSessionController.onAppInForeground now calls
blocklistCoordinator.refresh() so the local blocklist stays current on
launch/resume without opening the screen.
Blocked-users list: an 'Blocked' app bar over a paged LazyColumn of blocked
users (blurred BlurHash avatar + name), tap-to-unblock with a confirmation and
a per-row spinner (LoadingSuccessState), a debounced 'No One Blocked' empty
state, and a blurred mode added to ContactAvatar.
Vendor the profile.v1 UserProfile.join_ts field and thread it through the domain
UserProfile as joinedAt: Instant?, mapped in UserProfileMapper.
Add the tip-DM chat profile screen (blurred-avatar header, name, joined date,
and a Block action that routes through BlocklistCoordinator and returns to the
Tips list on success). Moves ChatParticipant to :core, adds the ChatStep.Profile
step + AppRoute.Menu.Blocklist wiring, the blocklist nav entry, and supporting
chat/media model and component updates.
@github-actions github-actions Bot added type: feature New functionality area: ui Compose UI, theme, components, resources area: network gRPC, connectivity, API, exchange rates area: build-system Gradle, convention plugins, build-logic area: session and removed type: feature New functionality labels Jul 30, 2026
RealSessionController gained a blocklistCoordinator constructor param (launch/
resume blocklist refresh); update the two tests that build it directly so the
session unit-test sources compile.
@github-actions github-actions Bot added the type: feature New functionality label Jul 30, 2026
bmc08gt added 3 commits July 30, 2026 13:25
Drop 9 unused imports left across the chat-profile and blocklist changes
(ChatAmountEntryScreen, ChatActionHandler, Spacer/fillMaxWidth, BlocklistController,
Box/Spacer/Scannable, DepositDelegate).
These slipped into the chat-profile/blocklist branch and are being PR'd on their
own:
- TipCardScreen: share-button/tip-card layout (reverted to code/cash)
- ChatBottomBar: dismiss keyboard on the $ send button (removed the wrap)
- ChatFlowScreen: dismiss keyboard before navigating away (removed the wrap)
- ContactInfoContainer: restore the Indicator spacer + null preview

Pre-existing keyboard.hideIfVisible wraps and the ViewProfile wrap are kept.
@bmc08gt
bmc08gt force-pushed the feat/chat-profile branch from 1637b56 to 2563c87 Compare July 31, 2026 01:01
bmc08gt added 2 commits July 30, 2026 21:05
Add a Blocklist beta feature flag. The My Account blocklist entry only
shows when the flag is enabled, and opening a chat participant's profile
(the entry point to blocking) is gated the same way: ChatViewModel
observes the flag and exposes canViewProfile in its state, so the top-bar
tap and contact-card chevron are suppressed when the flag is off.
Show an error alert when blocking a user from their chat profile or
unblocking from the blocklist fails, so failures aren't silent. Also
switch the unblock confirmation prompt to showMessage.
@bmc08gt
bmc08gt force-pushed the feat/chat-profile branch from 2563c87 to b64d8b4 Compare July 31, 2026 01:05
@bmc08gt
bmc08gt merged commit 96bfa54 into code/cash Jul 31, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the feat/chat-profile branch July 31, 2026 01:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: build-system Gradle, convention plugins, build-logic area: network gRPC, connectivity, API, exchange rates area: session area: ui Compose UI, theme, components, resources type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant