feat: FTS5 full-text message search#5373
Conversation
❌ 11 Tests Failed:
View the top 3 failed test(s) by shortest run time
View the full list of 4 ❄️ flaky test(s)
To view more test analytics, go to the Test Analytics Dashboard |
0e59ed7 to
b117e19
Compare
📄 Docs staleness check — advisoryThis PR modifies user-facing UI source files but does not update any page under
Changed source files: What to check:
New page checklist (if adding a new doc page):
If this PR does not require a doc update (e.g., internal refactor, bug fix, test change), add the
|
🖼️ Preview staleness check — advisoryThis PR modifies UI composables but does not update any
Changed UI files: What to check:
Adding previews checklist:
If this PR does not require preview updates (e.g., logic-only change, non-visual refactor), add the |
Squash merge of PR #5373 into release/2.8.0. Adds full-text search to the messaging screen using SQLite FTS5, enabling users to find messages within a conversation. Includes PacketFts entity, FTS5 MATCH queries, backfill migration, and search UI with real-time results. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🔗 Release 2.8.0 Integration ReportBranch: Integration Changes Required
Merge Guidance
|
Adds full-text search to the messaging screen using SQLite FTS5: - New PacketFts entity (content-sync FTS5 table) tracking message_text - Search UI with contextual search bar, prev/next navigation, and result count - Term highlighting in message bubbles during active search - Scroll-to-match when navigating between search results - Efficient backfill via json_extract SQL UPDATE (no OOM risk) - Query sanitization wrapping tokens in quotes to escape FTS5 special chars - 300ms debounce with minimum 2-char threshold Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Wrap backfill writes in NonCancellable to prevent connection pool leaks when coroutine scope is cancelled mid-write - Add countPacketsNeedingBackfill() query to avoid starting a write transaction when no work is needed - Use BundledSQLiteDriver in DatabaseBuilder for consistent test behavior Found during release/2.8.0 integration testing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
0efee5a to
9b7a304
Compare
Android framework SQLite supports FTS5 at API 26+ (our minSdk). BundledSQLiteDriver loads a JNI native lib that causes UnsatisfiedLinkError in Robolectric unit tests. Removing it entirely from the Android source set — framework SQLite handles both production and in-memory test databases correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
f734092 to
ae6228d
Compare
Room's default AndroidSQLiteDriver delegates to framework SQLite, which under Robolectric is shadowed by a native SQLite build that lacks the FTS5 extension. This causes 'no such module: FTS5' errors when the PacketFts entity triggers table creation. Fix by: 1. Setting BundledSQLiteDriver on both getDatabaseBuilder and getInMemoryDatabaseBuilder (bundled SQLite includes FTS5) 2. Adding sqlite-bundled-jvm as testRuntimeOnly in androidApp and runtimeOnly in core:database androidHostTest to provide the host-platform native library for JVM-based test execution 3. Using BundledSQLiteDriver in MigrationTest's in-memory builder Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Adds full-text search to the messaging screen using SQLite FTS5, enabling users to find messages within a conversation.
Changes
Database Layer
PacketFts— new@Fts5(contentEntity = Packet::class)entity that mirrorsmessage_textfor full-text indexingPacket.messageText— new column populated at insert time fromDataPacket.textPacketDao— FTS5 MATCH queries (searchMessages,searchMessagesInConversation), plusbackfillMessageTexts()usingjson_extractfor efficient one-shot backfillRepository Layer
PacketRepository.searchMessages()— sanitizes user input (double-quote wrapping per token), scopes to contact key optionallymessageTextat insert time in both message save pathsUI Layer
MessageSearchBar— M3 contextual search bar with text field, "X of Y" counter, prev/next arrows, and clear buttonsearchResultIndexStateFlow withnavigateToNext/Previous, scroll-to-match viaLaunchedEffectHighlightedTextcomposable highlights matching tokens in message bubbles usingtertiaryContainercolorBackfill Strategy
On database switch, a single SQL
UPDATEwithjson_extract(data, "$.text")populatesmessage_textfor historical packets, followed by an FTS5rebuildcommand. Zero rows loaded into memory.Screenshots
TODO: Add screenshots of search bar and highlighted results
Testing