Skip to content

feat(chat): in-session transcript search with next/prev navigation#3

Open
arafatamim wants to merge 2 commits into
masterfrom
feat/p2-transcript-search
Open

feat(chat): in-session transcript search with next/prev navigation#3
arafatamim wants to merge 2 commits into
masterfrom
feat/p2-transcript-search

Conversation

@arafatamim

Copy link
Copy Markdown
Owner

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 a ScrollToSearchMatch effect.
  • 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:testDebugUnitTest green on the branch (includes TranscriptSearcherTest, chat suite).
  • ./gradlew.bat :feature:chat:compileDebugKotlin BUILD SUCCESSFUL.

Risk / rollback

  • Isolated to the :feature:chat module; no schema, DI graph, or ACP protocol changes.
  • Rollback = revert the merge or close the PR; no migrations involved.

Notes

  • Branched cleanly from master (2c4f931); diff is exactly the two search commits.
  • When merging alongside the offline-queue work, combine queue's allMessages (messages + pending) with this branch's effectiveWindowSize in ChatScreenSections (windowing must include pending messages AND honor full-window during search).
  • UI change: screenshots/video to follow.

Copilot AI review requested due to automatic review settings July 20, 2026 04:27

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 TranscriptSearcher utilities + unit tests for match finding and index navigation.
  • Extends ChatViewModel/ChatScreen with 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,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants