Skip to content

feat: Conversation Mode — real-time two-way translation #71

@2sem

Description

@2sem

Summary

Build a Conversation Mode as a sheet presented from TranslationScreen. This is the app's hero differentiator — a face-to-face translation flow with alternating speaker bubbles.

Entry Point

Add a pill button in the language row between the two LanguagePickerButton components:

[ EN  ▾ ]  [ Conversation ]  [ ⇄ ]  [ KO  ▾ ]

Tapping it presents ConversationView as a .sheet with .presentationDetents([.large]).

ConversationView Layout

Sheet handle
Title: "Conversation"  |  [EN • KO pill]  |  [✕]

ScrollView (auto-scrolls to bottom)
  ConversationBubble — Person A (left-aligned, normal orientation)
  ConversationBubble — Person B (right-aligned, rotated 180°)
  ...

[Empty state: bubble icon + "Tap mic or type to begin"]

──────────────────────────────────
[🎙]  [text field: "Speak or type..."]  [➤]
      [ Person A ]  [ Person B ]   ← speaker toggle
──────────────────────────────────

ConversationBubble Spec

  • Source text: .caption, .secondary — above the translated text
  • Translated text: .body, .primary
  • Language flag badge: 16pt circle in the top corner
  • Person A bubble: accent color at 15% opacity
  • Person B bubble: neutral Color.appInputOutputBackground, rotated 180°: .rotationEffect(.degrees(180))
  • Max width: 75% of screen width
  • Corner radii: 16pt, tail corner reduced to 4pt (UnevenRoundedRectangle, iOS 17+)
  • Timestamp: shown in .caption2, .tertiaryLabel when >60s gap between bubbles

Behaviour

  • Active speaker's language is used for speech recognition
  • On recognition finish → auto-translate → append both source + translated bubbles
  • No manual "Translate" button in conversation mode
  • ScrollViewReader auto-scrolls to the latest bubble (.easeOut(duration: 0.3))
  • Speaker toggle: tappable pill pair with haptic feedback (.impactOccurred(intensity: 0.6))
  • On dismiss with ≥2 bubbles: confirm "Leave conversation?" alert. If history is implemented, offer "Save to History" option.

Also

  • Remove or raise the hardcoded 100-character limit (TranslationViewModel.maxTextLength) — it breaks real conversation use

Files

  • Projects/App/Sources/Screens/TranslationScreen.swift
  • Projects/App/Sources/ViewModels/TranslationViewModel.swift
  • Projects/App/Sources/Screens/SpeechRecognitionScreen.swift

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions