Skip to content

refactor(chat): make shared/chat, shared/blob and libs/emojis KMP behind platform interfaces - #1923

Merged
bmc08gt merged 10 commits into
code/cashfrom
refactor/chat-unused-deps
Nov 2, 2026
Merged

bmc08gt merged 10 commits into
code/cashfrom
refactor/chat-unused-deps

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Chat needs to compile for the desktop app, and most of it has no reason to be Android-only. This PR puts the Android pieces behind interfaces and moves everything else to commonMain, in four steps that were stacked as #1923, #1925 and #1926.

Chat seams. AppForeground replaces the direct ProcessLifecycleOwner uses in RealChatCoordinator and ReactionAlertController. ChatNotifications.dismiss(chatId) replaces NotificationManagerCompat.cancel. Both have Android implementations bound in the Android Hilt module and a None default. Unused :shared:contacts (chat) and :shared:workers (session) dependencies are dropped.

Emojis KMP. libs/emojis is a KMP module (flipcash.kmp.app.library). Its five tests now sit in commonTest and run on both android host and jvm (18 each).

Blob KMP. shared/blob is a KMP module. What needs the platform is behind three interfaces in commonMain:

  • ImageCodec: decode with EXIF rotation, downscale, JPEG encode, thumbnail for BlurHash. Android uses ImageDecoder/Bitmap; jvm uses Skia.
  • PickedPhoto/PickedPhotos: a photo that can open its bytes and has a stable key. Android wraps a Uri and ContentResolver; jvm wraps a File.
  • UploadImageCache: reads the photo's type, writes the re-encoded copy to the cache, measures it.

BlobStorageCoordinator keeps its DataStore through PreferencesFiles under the same upload-policy file name.

Chat KMP. shared/chat is a KMP module. Photo upload (ChatMediaUploads, ChatPhotoFetcher, ChatPhotoLoader), share (ChatShare, ShareSender, ChatShareGateway), link preview images, blob sealing and MediaSendDelegate are in commonMain. Android-only code is the Hilt module, foreground and notification implementations, Intent.toChatShareRequest, the files-directory and Coil singleton implementations of ChatMediaLocation and SentImageCache, and Patterns.WEB_URL. SentPhotoPreviews now caches JPEG bytes in a plain LRU; MediaMessageBubble decodes them.

Tests. Chat tests that need no Android moved to commonTest, so they run on jvm too. The org.json vector tests read fixtures through a kotlinx.serialization stand-in. isInviteLinkUrl, which replaced Uri.parse, has 35 vectors in invite_link_url.json. Test counts for chat: 752 before, 756 android host and 725 jvm now. Blob: 30 android host and 29 jvm. Emojis: 19 before (18 host, 1 device), 18 host and 18 jvm now.

Desktop. The desktop graph provides the jvm implementations and resolves ImageUploadPreparer with the Skia codec; DesktopWiringTest covers it. Chat itself is not in the desktop graph yet, so ChatMediaSending is not bound there.

Known desktop difference: Skia does not apply EXIF orientation, so a rotated JPEG picked on desktop is not rotated before upload.

shared/chat declared :shared:contacts and shared/session declared :shared:workers, but neither imports from them. The app module declares both itself, so the Hilt bindings still reach it.
…ind interfaces

RealChatCoordinator and ReactionAlertController read ProcessLifecycleOwner directly, and MessagingDelegate called NotificationManagerCompat. AppForeground and ChatNotifications now sit in front of them, with Android implementations bound in ChatModule and None objects for callers without a host. Behaviour is unchanged, including posting the lifecycle observer to the main looper.
@bmc08gt bmc08gt self-assigned this Oct 31, 2026
@github-actions github-actions Bot added type: refactor Code restructuring, no behavior change area: session and removed type: refactor Code restructuring, no behavior change labels Oct 31, 2026
Compose Desktop needs the reaction picker and recents. The data tables, catalog
loader and recents store move to commonMain. DataStoreRecentReactionsStore takes
PreferencesFiles instead of a Context, with the same recent_reactions file and
keys. EmojiDrawability's Paint probe becomes an expect/actual: Paint.hasGlyph on
Android, an AWT font check on the JVM.
Android-only media, share and platform bindings go to androidMain; the rest to
commonMain. Tests move to androidHostTest unchanged.
Compose Desktop needs the chat coordinator, so shared/chat now builds for jvm
and android. The coordinator, delegates, stores and ChatModule are in
commonMain. Media, share, the Android foreground and notification
bindings stay in androidMain (new AndroidChatModule), since they use Uri,
Bitmap, Intent and shared/blob.

- DataStore stores take PreferencesFiles; file names and keys are unchanged.
- detectUrls reads candidates through an expect findWebUrls: Patterns.WEB_URL on
  Android, a copy of that pattern on the JVM. The link_detection vectors run on
  both.
- InviteLinkText parses URLs without android.net.Uri.
- BlobSealer no longer names ChatMediaSealing; Android adds it back with sealing().
- ChatType/Fiat/Mint.analytics (analytics) and FIRST_PARTY_HOSTS (core) move to
  commonMain in the same packages.
Moves every chat and emojis test that did not need Robolectric, Hilt or
an Android API into commonTest, so each also runs on jvm. Fixtures that
used org.json read through a small kotlinx.serialization stand-in.
Adds vectors for the hand-written invite-link URL reader.
Adds the blob and chat modules to the desktop app and provides the
upload image cache, picked-photo source, chat media directory and sent
image cache from DesktopModule. The graph resolves ImageUploadPreparer
with the Skia codec.
@github-actions github-actions Bot added the type: refactor Code restructuring, no behavior change label Oct 31, 2026
@bmc08gt bmc08gt changed the title refactor(chat): drop unused deps and add foreground/notification seams refactor(chat): make shared/chat, shared/blob and libs/emojis KMP behind platform interfaces Oct 31, 2026
@bmc08gt
bmc08gt merged commit d338ff8 into code/cash Nov 2, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: session type: refactor Code restructuring, no behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant