feat(chat): in-session transcript search with next/prev navigation#3
Open
arafatamim wants to merge 2 commits into
Open
feat(chat): in-session transcript search with next/prev navigation#3arafatamim wants to merge 2 commits into
arafatamim wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds in-session transcript search to :feature:chat, including match navigation (next/prev), UI controls in the top bar, and match highlighting inside message bubbles so users can jump through long transcripts.
Changes:
- Introduces
TranscriptSearcherutilities + unit tests for match finding and index navigation. - Extends
ChatViewModel/ChatScreenwith search intents/state and scrolling to the active match. - Updates chat UI (top bar, message list windowing, message rendering) to support search UX and highlights.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| feature/chat/src/test/kotlin/com/tamimarafat/ferngeist/feature/chat/TranscriptSearcherTest.kt | Adds unit tests covering match finding, case-insensitivity, and wrap-around navigation helpers. |
| feature/chat/src/main/res/values/strings.xml | Adds accessibility strings for search controls and “no matches” state. |
| feature/chat/src/main/kotlin/com/tamimarafat/ferngeist/feature/chat/ui/MessageBubble.kt | Adds query-based highlighting + “current match” emphasis to message rendering. |
| feature/chat/src/main/kotlin/com/tamimarafat/ferngeist/feature/chat/ui/ChatTopBar.kt | Adds search UI (field, counter, next/prev, close) and focus behavior. |
| feature/chat/src/main/kotlin/com/tamimarafat/ferngeist/feature/chat/ui/ChatScreenSections.kt | Adds forceFullWindow mode so matches outside the current window remain reachable. |
| feature/chat/src/main/kotlin/com/tamimarafat/ferngeist/feature/chat/ui/ChatScreen.kt | Handles scroll-to-match effects and auto-scroll-to-first-match behavior; wires UI callbacks. |
| feature/chat/src/main/kotlin/com/tamimarafat/ferngeist/feature/chat/TranscriptSearcher.kt | Implements match finding and match index navigation helpers; defines TranscriptMatch. |
| feature/chat/src/main/kotlin/com/tamimarafat/ferngeist/feature/chat/ChatViewModel.kt | Adds search intents/state and match navigation logic, emitting a scroll effect. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+225
to
+233
| if (searchQuery.isNotBlank()) { | ||
| val annotated = buildHighlightedText( | ||
| text = segment.text, | ||
| query = searchQuery, | ||
| restingHighlight = restingHighlight, | ||
| currentHighlight = currentHighlight, | ||
| currentMatchStart = currentMatchStart, | ||
| defaultColor = MaterialTheme.colorScheme.onSurface, | ||
| ) |
Comment on lines
+645
to
+646
| val lowerText = text.lowercase() | ||
| val lowerQuery = query.trim().lowercase() |
Comment on lines
+55
to
+62
| val lowerQuery = trimmed.lowercase() | ||
| val results = mutableListOf<TranscriptMatch>() | ||
|
|
||
| messages.forEachIndexed { index, message -> | ||
| val text = message.searchableText() | ||
| if (text.isBlank()) return@forEachIndexed | ||
|
|
||
| val lowerText = text.lowercase() |
Comment on lines
+29
to
+32
| fun ChatMessage.searchableText(): String = when (role) { | ||
| ChatMessage.Role.ASSISTANT -> segments.joinToString(" ") { it.text } | ||
| else -> content | ||
| } |
Comment on lines
+291
to
+292
| val searchMatchCount = state.searchMatches.size | ||
| val currentMatchDisplayIndex = if (searchMatchCount > 0) state.currentMatchIndex + 1 else 0 |
| import androidx.compose.animation.slideOutVertically | ||
| import androidx.compose.foundation.layout.Arrangement | ||
| import androidx.compose.foundation.layout.Row | ||
| import androidx.compose.foundation.layout.widthIn |
Comment on lines
+336
to
+340
| private fun handleUpdateSearchQuery(query: String) { | ||
| val matches = findTranscriptMatches(state.value.messages, query) | ||
| updateState { | ||
| copy( | ||
| searchQuery = query, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Adds Priority 2 in-session transcript search to the chat screen: users can search the current session's messages and jump between matches, so long transcripts are navigable without manual scrolling.
TranscriptSearcher: pure match-finding over messages (case-insensitive, handles overlapping matches correctly).ChatViewModel: search intents (ToggleSearch,UpdateSearchQuery,NextSearchMatch,PreviousSearchMatch,CloseSearch), match state, and aScrollToSearchMatcheffect.ChatTopBar: search input UI with match counter and next/prev controls.MessageBubble: highlights matched substrings with contrast-safe styling.ChatScreenSections: renders the full message window while search is active (forceFullWindow) so off-window matches are reachable.Scope
8 files, +742/-77. New unit test
TranscriptSearcherTest(+196).Test evidence
./gradlew.bat :feature:chat:testDebugUnitTestgreen on the branch (includesTranscriptSearcherTest, chat suite)../gradlew.bat :feature:chat:compileDebugKotlinBUILD SUCCESSFUL.Risk / rollback
:feature:chatmodule; no schema, DI graph, or ACP protocol changes.Notes
master(2c4f931); diff is exactly the two search commits.allMessages(messages + pending) with this branch'seffectiveWindowSizeinChatScreenSections(windowing must include pending messages AND honor full-window during search).