diff --git a/app/src/main/kotlin/com/shonar/desktop/Screens.kt b/app/src/main/kotlin/com/shonar/desktop/Screens.kt index 1fc344b..81526cb 100644 --- a/app/src/main/kotlin/com/shonar/desktop/Screens.kt +++ b/app/src/main/kotlin/com/shonar/desktop/Screens.kt @@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.rememberScrollState @@ -853,6 +854,43 @@ fun DetailScreen(state: DesktopState) { Text(it, style = MaterialTheme.typography.labelMedium, color = MaterialTheme.colorScheme.primary) } + // Voice controls FIRST under the summary — before the long + // sections. Every time they sat further down (page bottom, + // then below the bullets) they fell off-screen and read as + // "missing". They act on this summary; they live here. + run { + val report = detail.reportText + val hasTranscript = detail.transcript != null || + (report != null && !report.contains("_No transcript available._")) + val remoteKnown = state.remoteIdFor(detail.file) != null + val sumBusy = detail.jobs.firstOrNull { it.jobType == "summarize" } + ?.status in setOf("queued", "running") + val voicesEnabled = remoteKnown && hasTranscript && !sumBusy + Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + Text("Re-summarize in the voice of", + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant) + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + SUMMARIZE_PERSONAS.forEach { (label, tone) -> + FilterChip( + selected = sumTone == tone, + enabled = voicesEnabled, + onClick = { + sumTone = tone + state.summarize(tone) + }, + label = { Text(label) }, + ) + } + } + if (!voicesEnabled && !remoteKnown) { + Text("Summarize unlocks once this file is uploaded (press Transcribe).", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant) + } + } + } + Spacer(Modifier.height(4.dp)) // Full structured sections (key points, decisions, action // items, questions, details) right on screen — the saved // .md report had them but the live view showed only the @@ -878,38 +916,38 @@ fun DetailScreen(state: DesktopState) { Spacer(Modifier.height(4.dp)) } } - // Voice controls sit directly under the summary — they act on it, - // and at the page bottom (below a long transcript) they read as - // gone. Hoisted above the transcript section; same conditions. + // Re-transcribe + summarize progress (the chips themselves live + // under the summary for the live path; this block also covers a + // file opened as a saved report with no live summary object). if (detail.transcript != null || detail.reportText != null) { - // Honest labels: "Re-…" only when that output actually exists. val report = detail.reportText val hasTranscript = detail.transcript != null || (report != null && !report.contains("_No transcript available._")) val hasSummary = detail.summary != null || (report?.contains("## Summary") == true) val remoteKnown = state.remoteIdFor(detail.file) != null - // A voice chip IS the action: clicking one re-summarizes in - // that voice immediately — no separate Re-summarize button. val sumBusy = detail.jobs.firstOrNull { it.jobType == "summarize" } ?.status in setOf("queued", "running") val voicesEnabled = remoteKnown && hasTranscript && !sumBusy - Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { - Text(if (hasSummary) "Re-summarize in the voice of" - else "Summarize in the voice of", - style = MaterialTheme.typography.labelMedium, - color = MaterialTheme.colorScheme.onSurfaceVariant) - Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { - SUMMARIZE_PERSONAS.forEach { (label, tone) -> - FilterChip( - selected = sumTone == tone, - enabled = voicesEnabled, - onClick = { - sumTone = tone - state.summarize(tone) - }, - label = { Text(label) }, - ) + if (detail.transcript == null) { + // Saved-report path: chips here, same rules. + Column(verticalArrangement = Arrangement.spacedBy(4.dp)) { + Text(if (hasSummary) "Re-summarize in the voice of" + else "Summarize in the voice of", + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant) + Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) { + SUMMARIZE_PERSONAS.forEach { (label, tone) -> + FilterChip( + selected = sumTone == tone, + enabled = voicesEnabled, + onClick = { + sumTone = tone + state.summarize(tone) + }, + label = { Text(label) }, + ) + } } } }