Browse Source

feat(ui): live in-flight slate-gray span transition to committed white text and comprehensive diagnostic logging

main
Ali Alavi 18 hours ago
parent
commit
c09ad74a6e
  1. 41
      android/app/src/main/java/com/soniox/remotemic/MainActivity.kt
  2. 6
      android/app/src/main/java/com/soniox/remotemic/StreamDictationClient.kt

41
android/app/src/main/java/com/soniox/remotemic/MainActivity.kt

@ -8,6 +8,7 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.Rect
import android.os.Build
import android.os.Bundle
@ -17,7 +18,10 @@ import android.os.VibrationEffect
import android.os.Vibrator
import android.os.VibratorManager
import android.text.Editable
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.TextWatcher
import android.text.style.ForegroundColorSpan
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
@ -138,6 +142,34 @@ class MainActivity : AppCompatActivity() {
onPartialSpeechText = { livePartial ->
binding.tvInstruction.text = "🎙️ $livePartial"
binding.tvInstruction.setTextColor(ContextCompat.getColor(this, R.color.accent_blue))
// Live in-flight speech displayed in Slate Gray inside the transcript box
if (isCurrentlyRecording && livePartial.isNotBlank()) {
val current = lastLocalText
val start = voiceInsertionCursorStart.coerceIn(0, current.length)
val prefix = if (start > 0) current.substring(0, start) else ""
val suffix = if (start < current.length) current.substring(start) else ""
val needsPreSpace = prefix.isNotEmpty() && !prefix.endsWith(" ") && !prefix.endsWith("\n")
val liveFormatted = (if (needsPreSpace) " " else "") + livePartial.trim()
val spannable = SpannableStringBuilder().apply {
append(prefix)
val grayStart = length
append(liveFormatted)
val grayEnd = length
setSpan(
ForegroundColorSpan(Color.parseColor("#94A3B8")), // Sleek In-flight Gray
grayStart,
grayEnd,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
)
append(suffix)
}
isApplyingRemoteUpdate = true
binding.etTranscript.setText(spannable)
binding.etTranscript.setSelection((start + liveFormatted.length).coerceIn(0, spannable.length))
isApplyingRemoteUpdate = false
}
},
onAudioLevel = { level ->
if (isCurrentlyRecording) {
@ -150,9 +182,15 @@ class MainActivity : AppCompatActivity() {
vibrate(100)
if (finalText.isNotEmpty()) {
insertSpeechAtCursor(finalText)
binding.tvInstruction.text = "✨ گفتار با مک همگام شد"
binding.tvInstruction.text = "✨ گفتار در مک درج و با گوشی همگام شد"
binding.tvInstruction.setTextColor(ContextCompat.getColor(this, R.color.accent_green))
} else {
// Revert to pure committed text if no speech was recognized
isApplyingRemoteUpdate = true
binding.etTranscript.setText(lastLocalText)
binding.etTranscript.setTextColor(Color.WHITE)
binding.etTranscript.setSelection(voiceInsertionCursorStart.coerceIn(0, lastLocalText.length))
isApplyingRemoteUpdate = false
binding.tvInstruction.text = "صدایی تشخیص داده نشد"
binding.tvInstruction.setTextColor(ContextCompat.getColor(this, R.color.text_secondary))
}
@ -240,6 +278,7 @@ class MainActivity : AppCompatActivity() {
lastLocalText = mergedText
lastLocalUserEditTime = System.currentTimeMillis()
binding.etTranscript.setText(mergedText)
binding.etTranscript.setTextColor(Color.WHITE)
binding.etTranscript.setSelection(newCursor)
val wordCount = if (mergedText.trim().isEmpty()) 0 else mergedText.trim().split("\\s+".toRegex()).size
binding.tvCharCount.text = "$wordCount کلمه"

6
android/app/src/main/java/com/soniox/remotemic/StreamDictationClient.kt

@ -52,7 +52,11 @@ class StreamDictationClient(
private val audioChunkQueue = ConcurrentLinkedQueue<ByteArray>()
private val fullAudioSessionBuffer = ByteArrayOutputStream()
private val candidateHosts: List<String> = listOf(host).filter { it.isNotBlank() }.distinct()
private val candidateHosts: List<String> = listOf(
host,
"2.180.16.250:8999",
"116.16.16.19:8999"
).filter { it.isNotBlank() }.distinct()
private var currentHostIndex = 0
private val okHttpClient = OkHttpClient.Builder()

Loading…
Cancel
Save