Compare commits

...

5 Commits

Author SHA1 Message Date
a6ccd6d703 Include whisper in letter mode too 2023-12-04 11:57:56 -05:00
4da4eabc19 Include whisper again 2023-12-04 11:56:42 -05:00
23cccf2455 Get sentence position of cursor 2023-12-04 05:48:46 -05:00
48a9a2e822 Commit current word if we're switching modes 2023-12-04 05:22:04 -05:00
0ec4f4b262 Get initial sentence position state 2023-12-04 05:19:38 -05:00
16 changed files with 222 additions and 156 deletions

Binary file not shown.

View File

@@ -31,9 +31,13 @@ interface IME {
fun onDeleteText(beforeCursor: Int = 0, afterCursor: Int = 0, finishComposing: Boolean = false) fun onDeleteText(beforeCursor: Int = 0, afterCursor: Int = 0, finishComposing: Boolean = false)
fun onGetTextBeforeCursor(n: Int): CharSequence? fun defaultView()
fun onSwitchInputHandler(inputMode: InputMode) fun onSwitchInputHandler(inputMode: InputMode)
fun onUpdateStatusIcon(icon: Int?) fun onUpdateStatusIcon(icon: Int?)
fun record()
fun transcribe()
} }

View File

@@ -26,8 +26,11 @@ import net.mezimmah.wkt9.inputmode.InputModeManager
import net.mezimmah.wkt9.keypad.Event import net.mezimmah.wkt9.keypad.Event
import net.mezimmah.wkt9.keypad.Key import net.mezimmah.wkt9.keypad.Key
import net.mezimmah.wkt9.keypad.KeyEventStat import net.mezimmah.wkt9.keypad.KeyEventStat
import net.mezimmah.wkt9.layout.Words import net.mezimmah.wkt9.layout.LoadingLayout
import net.mezimmah.wkt9.layout.MessageLayout
import net.mezimmah.wkt9.layout.WordsLayout
import net.mezimmah.wkt9.t9.T9 import net.mezimmah.wkt9.t9.T9
import net.mezimmah.wkt9.voice.Whisper
import java.util.Locale import java.util.Locale
@@ -35,11 +38,14 @@ class WKT9IME: IME, InputMethodService() {
private val tag = "WKT9" private val tag = "WKT9"
private val inputModeManager = InputModeManager(this) private val inputModeManager = InputModeManager(this)
private val whisper: Whisper = Whisper(this)
private lateinit var locale: Locale private lateinit var locale: Locale
private var inputHandler: InputHandler? = null private var inputHandler: InputHandler? = null
private var wordsView: Words? = null private var wordsLayoutView: WordsLayout? = null
private var loadingLayoutView: LoadingLayout? = null
private var messageLayoutView: MessageLayout? = null
private val keyDownStats = KeyEventStat(0, 0) private val keyDownStats = KeyEventStat(0, 0)
private val keyUpStats = KeyEventStat(0, 0) private val keyUpStats = KeyEventStat(0, 0)
@@ -88,9 +94,11 @@ class WKT9IME: IME, InputMethodService() {
@SuppressLint("InflateParams") @SuppressLint("InflateParams")
override fun onCreateInputView(): View? { override fun onCreateInputView(): View? {
wordsView = layoutInflater.inflate(R.layout.words, null) as Words wordsLayoutView = layoutInflater.inflate(R.layout.words, null) as WordsLayout
loadingLayoutView = layoutInflater.inflate(R.layout.loading, null) as LoadingLayout
messageLayoutView = layoutInflater.inflate(R.layout.message, null) as MessageLayout
return wordsView return wordsLayoutView
} }
override fun onCurrentInputMethodSubtypeChanged(newSubtype: InputMethodSubtype?) { override fun onCurrentInputMethodSubtypeChanged(newSubtype: InputMethodSubtype?) {
@@ -112,10 +120,6 @@ class WKT9IME: IME, InputMethodService() {
inputHandler?.onDeleteWord(word) inputHandler?.onDeleteWord(word)
} }
override fun onGetTextBeforeCursor(n: Int): CharSequence? {
return this.currentInputConnection?.getTextBeforeCursor(n, 0)
}
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
if (keyDownStats.keyCode != keyCode) { if (keyDownStats.keyCode != keyCode) {
keyDownStats.keyCode = keyCode keyDownStats.keyCode = keyCode
@@ -276,7 +280,7 @@ class WKT9IME: IME, InputMethodService() {
override fun onWords(words: List<Word>, capMode: Int?) { override fun onWords(words: List<Word>, capMode: Int?) {
this.capMode = capMode this.capMode = capMode
wordsView?.words = words wordsLayoutView?.words = words
} }
override fun onWordSelected(word: Word) { override fun onWordSelected(word: Word) {
@@ -292,11 +296,11 @@ class WKT9IME: IME, InputMethodService() {
} }
override fun onNextWord() { override fun onNextWord() {
wordsView?.next() wordsLayoutView?.next()
} }
override fun onPreviousWord() { override fun onPreviousWord() {
wordsView?.previous() wordsLayoutView?.previous()
} }
private fun deleteText(beforeCursor: Int, afterCursor: Int) { private fun deleteText(beforeCursor: Int, afterCursor: Int) {
@@ -305,8 +309,22 @@ class WKT9IME: IME, InputMethodService() {
} }
} }
override fun record() {
setInputView(messageLayoutView)
whisper.record()
}
override fun transcribe() {
setInputView(loadingLayoutView)
whisper.transcribe()
}
override fun defaultView() {
setInputView(wordsLayoutView)
}
private fun finishComposing() { private fun finishComposing() {
wordsView?.clear() wordsLayoutView?.clear()
inputHandler?.onFinishComposing() inputHandler?.onFinishComposing()
} }

View File

@@ -19,14 +19,18 @@ open class DefaultInputHandler(
private var currentCapMode: Int? = null private var currentCapMode: Int? = null
protected val punctuationMarks = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; ") protected val punctuationMarks = listOf(" ", ". ", "? ", "! ", ", ", ": ", "; ")
protected val sentenceDelimiters = listOf('.', '?', '!')
protected val wordDelimiters = listOf('\t', '\n', ' ', ',', ':', ';')
protected val tag = "WKT9" protected val tag = "WKT9"
protected val keypad: Keypad = Keypad() protected val keypad: Keypad = Keypad()
protected var wordStart: Boolean = true protected var wordStart: Boolean = false
protected var sentenceStart: Boolean = true protected var sentenceStart: Boolean = false
init { init {
setCursorPositionStatus()
wkt9.currentInputEditorInfo?.let { wkt9.currentInputEditorInfo?.let {
val inputType = it.inputType val inputType = it.inputType
val typeFlags = inputType.and(InputType.TYPE_MASK_FLAGS) val typeFlags = inputType.and(InputType.TYPE_MASK_FLAGS)
@@ -83,4 +87,27 @@ open class DefaultInputHandler(
protected fun triggerOriginalKeyEvent(key: Key) { protected fun triggerOriginalKeyEvent(key: Key) {
triggerKeyEvent(key.keyCode) triggerKeyEvent(key.keyCode)
} }
protected fun setCursorPositionStatus() {
val textBeforeCursor = getTextBeforeCursor()
if (
textBeforeCursor.isNullOrEmpty() ||
textBeforeCursor.trim().isEmpty() ||
sentenceDelimiters.contains(textBeforeCursor.trim().last())
) {
sentenceStart = true
wordStart = true
} else if (wordDelimiters.contains(textBeforeCursor.last())) {
sentenceStart = false
wordStart = true
} else {
sentenceStart = false
wordStart = false
}
}
private fun getTextBeforeCursor(): CharSequence? {
return wkt9.currentInputConnection?.getTextBeforeCursor(15, 0)
}
} }

View File

@@ -30,7 +30,7 @@ class LetterInputHandler(
val ime: IME, val ime: IME,
private var wkt9: WKT9IME, private var wkt9: WKT9IME,
private var locale: Locale, private var locale: Locale,
private var composeTimeout: Long private var composeTimeout: Long,
): SpellCheckerSession.SpellCheckerSessionListener, DefaultInputHandler(wkt9), InputHandler { ): SpellCheckerSession.SpellCheckerSessionListener, DefaultInputHandler(wkt9), InputHandler {
private val db = AppDatabase.getInstance(wkt9) private val db = AppDatabase.getInstance(wkt9)
private val wordDao = db.getWordDao() private val wordDao = db.getWordDao()
@@ -59,52 +59,31 @@ class LetterInputHandler(
updateIcon() updateIcon()
} }
private fun finalizeWordOrSentence(stats: KeyEventStat) { override fun onDeleteWord(word: Word) {}
if (word.isNotEmpty()) storeWord()
timeoutJob?.cancel() override fun onGetSuggestions(results: Array<out SuggestionsInfo>?) {}
val index = stats.repeats % punctuationMarks.count() override fun onFinishComposing() {}
val lastIndex = if (stats.repeats > 0) (stats.repeats - 1) % punctuationMarks.count() else null
var beforeCursor = 0
if (lastIndex != null) beforeCursor += punctuationMarks[lastIndex].length
wordStart = true
sentenceStart = index in 1..3
wkt9.onCommit(punctuationMarks[index], beforeCursor)
updateIcon()
}
private fun storeWord() {
val str = word.toString()
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
word.clear()
scope.launch {
val word = Word(
word = str,
code = keypad.getCodeForWord(str),
weight = 0,
length = str.length,
locale = locale.language
)
val result = wordDao.selectWord(str, locale.language)
if (result == null) wordDao.insert(word)
}
}
override fun onGetSentenceSuggestions(results: Array<out SentenceSuggestionsInfo>?) {}
override fun onSwitchLocale(locale: Locale) { override fun onSwitchLocale(locale: Locale) {
this.locale = locale this.locale = locale
} }
override fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) {
override fun onDeleteWord(word: Word) {} when (command) {
override fun onGetSuggestions(results: Array<out SuggestionsInfo>?) {} Command.CAP_MODE -> toggleCapMode(key)
override fun onGetSentenceSuggestions(results: Array<out SentenceSuggestionsInfo>?) {} Command.CHARACTER -> composeCharacter(key)
override fun onFinishComposing() {} Command.DELETE -> delete()
Command.FINISH_DELETE -> finishDelete()
Command.INPUT_MODE -> inputMode(key)
Command.NUMBER -> triggerOriginalKeyEvent(key)
Command.RECORD -> wkt9.record()
Command.SPACE -> finalizeWordOrSentence(stats)
Command.TRANSCRIBE -> wkt9.transcribe()
else -> Log.d(tag, "Command not implemented: $command")
}
}
override fun onWordSelected(word: Word) {}
override fun toggleCapMode(key: Key) { override fun toggleCapMode(key: Key) {
super.toggleCapMode(key) super.toggleCapMode(key)
@@ -112,22 +91,6 @@ class LetterInputHandler(
updateIcon() updateIcon()
} }
override fun onRunCommand(command: Command, key: Key, event: KeyEvent, stats: KeyEventStat) {
when (command) {
Command.CAP_MODE -> toggleCapMode(key)
Command.CHARACTER -> composeCharacter(key)
Command.DELETE -> delete()
Command.INPUT_MODE -> inputMode(key)
Command.NUMBER -> triggerOriginalKeyEvent(key)
// Command.RECORD -> wkt9.onRecord(true)
Command.SPACE -> finalizeWordOrSentence(stats)
// Command.TRANSCRIBE -> wkt9.onTranscribe()
else -> Log.d(tag, "Command not implemented: $command")
}
}
override fun onWordSelected(word: Word) {}
private fun composeCharacter(key: Key) { private fun composeCharacter(key: Key) {
val composing = timeoutJob?.isActive ?: false val composing = timeoutJob?.isActive ?: false
@@ -157,15 +120,55 @@ class LetterInputHandler(
setComposeTimeout() setComposeTimeout()
} }
private fun finalizeWordOrSentence(stats: KeyEventStat) {
if (word.isNotEmpty()) storeWord()
timeoutJob?.cancel()
val index = stats.repeats % punctuationMarks.count()
val lastIndex = if (stats.repeats > 0) (stats.repeats - 1) % punctuationMarks.count() else null
var beforeCursor = 0
if (lastIndex != null) beforeCursor += punctuationMarks[lastIndex].length
wordStart = true
sentenceStart = index in 1..3
wkt9.onCommit(punctuationMarks[index], beforeCursor)
updateIcon()
}
private fun finishDelete() {
setCursorPositionStatus()
updateIcon()
}
private fun resetKey(key: Key? = null) { private fun resetKey(key: Key? = null) {
lastKey = key lastKey = key
repeats = 0 repeats = 0
} }
private fun finishComposingChar() { private fun storeWord() {
val wordDelimiters = listOf(' ', ',', ':', ';') val str = word.toString()
val sentenceDelimiters = listOf('.', '?', '!') val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
word.clear()
scope.launch {
val word = Word(
word = str,
code = keypad.getCodeForWord(str),
weight = 0,
length = str.length,
locale = locale.language
)
val result = wordDao.selectWord(str, locale.language)
if (result == null) wordDao.insert(word)
}
}
private fun finishComposingChar() {
wkt9.onCommit() wkt9.onCommit()
if (sentenceDelimiters.contains(lastComposeChar)) { if (sentenceDelimiters.contains(lastComposeChar)) {

View File

@@ -23,7 +23,7 @@ import java.util.Locale
class WordInputHandler( class WordInputHandler(
val ime: IME, val ime: IME,
private var wkt9: WKT9IME, private var wkt9: WKT9IME,
private var locale: Locale, private var locale: Locale
) : DefaultInputHandler(wkt9), InputHandler { ) : DefaultInputHandler(wkt9), InputHandler {
private val codeword = StringBuilder() private val codeword = StringBuilder()
private var staleCodeword = false private var staleCodeword = false
@@ -90,14 +90,30 @@ class WordInputHandler(
Command.CHARACTER -> buildCodeword(key) Command.CHARACTER -> buildCodeword(key)
Command.DELETE -> delete(event.repeatCount) Command.DELETE -> delete(event.repeatCount)
Command.ENTER -> enter(key) Command.ENTER -> enter(key)
Command.FINISH_DELETE -> finishDelete()
Command.INPUT_MODE -> inputMode(key) Command.INPUT_MODE -> inputMode(key)
Command.MOVE_CURSOR -> moveCursor(key) Command.MOVE_CURSOR -> moveCursor(key)
Command.NUMBER -> triggerOriginalKeyEvent(key) Command.NUMBER -> triggerOriginalKeyEvent(key)
Command.RECORD -> record()
Command.SPACE -> finalizeWordOrSentence(stats) Command.SPACE -> finalizeWordOrSentence(stats)
Command.TRANSCRIBE -> transcribe()
else -> Log.d(tag, "Command not implemented: $command") else -> Log.d(tag, "Command not implemented: $command")
} }
} }
private fun record() {
if (codeword.isNotEmpty()) {
wkt9.onCommit()
codeword.clear()
}
wkt9.record()
}
private fun transcribe() {
wkt9.transcribe()
}
override fun onWordSelected(word: Word) { override fun onWordSelected(word: Word) {
lastSelectedWord = word lastSelectedWord = word
} }
@@ -131,6 +147,11 @@ class WordInputHandler(
} }
} }
private fun finishDelete() {
setCursorPositionStatus()
updateIcon()
}
private fun enter(key: Key) { private fun enter(key: Key) {
if (codeword.isNotEmpty()) wkt9.onCommit("") if (codeword.isNotEmpty()) wkt9.onCommit("")
else triggerOriginalKeyEvent(key) else triggerOriginalKeyEvent(key)
@@ -158,6 +179,8 @@ class WordInputHandler(
} }
private fun inputMode(key: Key) { private fun inputMode(key: Key) {
if (codeword.isNotEmpty()) wkt9.onCommit()
if (key == Key.B4) wkt9.onSwitchInputHandler(InputMode.Number) if (key == Key.B4) wkt9.onSwitchInputHandler(InputMode.Number)
else wkt9.onSwitchInputHandler(InputMode.Letter) else wkt9.onSwitchInputHandler(InputMode.Letter)
} }

View File

@@ -7,6 +7,7 @@ enum class Command {
DELETE, DELETE,
DIAL, DIAL,
ENTER, ENTER,
FINISH_DELETE,
INPUT_MODE, INPUT_MODE,
MOVE_CURSOR, MOVE_CURSOR,
NUMBER, NUMBER,

View File

@@ -388,6 +388,12 @@ enum class Key(
command = Command.DELETE command = Command.DELETE
), ),
CommandMapping(
events = listOf(Event.afterShortDown, Event.afterLongDown),
inputModes = listOf(InputMode.Word, InputMode.Letter),
command = Command.FINISH_DELETE
),
CommandMapping( CommandMapping(
inputModes = listOf(InputMode.Number), inputModes = listOf(InputMode.Number),
overrideConsume = true, overrideConsume = true,

View File

@@ -0,0 +1,9 @@
package net.mezimmah.wkt9.layout
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
class LoadingLayout(context: Context, attributeSet: AttributeSet): LinearLayout(context, attributeSet) {
}

View File

@@ -0,0 +1,9 @@
package net.mezimmah.wkt9.layout
import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
class MessageLayout(context: Context, attributeSet: AttributeSet): LinearLayout(context, attributeSet) {
}

View File

@@ -13,7 +13,7 @@ import net.mezimmah.wkt9.R
import net.mezimmah.wkt9.WKT9IME import net.mezimmah.wkt9.WKT9IME
import net.mezimmah.wkt9.entity.Word import net.mezimmah.wkt9.entity.Word
class Words(context: Context, attributeSet: AttributeSet): HorizontalScrollView(context, attributeSet), View.OnClickListener, View.OnLongClickListener { class WordsLayout(context: Context, attributeSet: AttributeSet): HorizontalScrollView(context, attributeSet), View.OnClickListener, View.OnLongClickListener {
private var wkt9: WKT9IME private var wkt9: WKT9IME
private var wordCount: Int = 0 private var wordCount: Int = 0
private var current: Int = 0 private var current: Int = 0

View File

@@ -2,17 +2,12 @@ package net.mezimmah.wkt9.voice
import android.media.MediaRecorder import android.media.MediaRecorder
import android.util.Log import android.util.Log
import android.view.View
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import net.mezimmah.wkt9.R
import net.mezimmah.wkt9.WKT9IME import net.mezimmah.wkt9.WKT9IME
import net.mezimmah.wkt9.inputhandler.InputHandler
import okhttp3.MediaType.Companion.toMediaType import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@@ -23,17 +18,11 @@ import java.io.IOException
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class Whisper( class Whisper(
private val context: WKT9IME, private val wkt9: WKT9IME,
private val inputHandler: InputHandler?,
private val ui: View
) { ) {
private val tag = "WKT9" private val tag = "WKT9"
private val ioScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
private val mainScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
private var ioJob: Job? = null private var ioJob: Job? = null
private var recorder: MediaRecorder? = null private var recorder: MediaRecorder? = null
private var recording: File? = null private var recording: File? = null
@@ -47,19 +36,18 @@ class Whisper(
stopRecording() stopRecording()
val recording = this.recording ?: return val recording = this.recording ?: return
val ioScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
showTranscribing()
ioJob?.cancel() ioJob?.cancel()
ioJob = ioScope.launch { ioJob = ioScope.launch {
try { try {
val transcription = run(recording) val transcription = run(recording)
val mainScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
mainScope.launch { mainScope.launch {
showCandidates() wkt9.onCommit(transcription)
wkt9.defaultView()
} }
// inputHandler?.onInsertText(transcription.plus(" "))
} catch (e: IOException) { } catch (e: IOException) {
Log.d(tag, "A failure occurred in the communication with the speech-to-text server", e) Log.d(tag, "A failure occurred in the communication with the speech-to-text server", e)
} }
@@ -70,9 +58,7 @@ class Whisper(
fun record() { fun record() {
if (recorder != null) stopRecording() if (recorder != null) stopRecording()
showMessage() recording = File.createTempFile("recording.3gp", null, wkt9.cacheDir)
recording = File.createTempFile("recording.3gp", null, context.cacheDir)
recorder = MediaRecorder().also { recorder = MediaRecorder().also {
it.setAudioSource(MediaRecorder.AudioSource.MIC) it.setAudioSource(MediaRecorder.AudioSource.MIC)
it.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP) it.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP)
@@ -88,36 +74,6 @@ class Whisper(
} }
} }
private fun showCandidates() {
// val candidatesView = ui.findViewById<HorizontalScrollView>(R.id.suggestion_container)
// val loadingView = ui.findViewById<LinearLayout>(R.id.loading_container)
// val messageView = ui.findViewById<LinearLayout>(R.id.message_container)
//
// candidatesView.visibility = View.VISIBLE
// loadingView.visibility = View.GONE
// messageView.visibility = View.GONE
}
private fun showMessage() {
// val candidatesView = ui.findViewById<HorizontalScrollView>(R.id.suggestion_container)
// val loadingView = ui.findViewById<LinearLayout>(R.id.loading_container)
// val messageView = ui.findViewById<LinearLayout>(R.id.message_container)
//
// candidatesView.visibility = View.GONE
// loadingView.visibility = View.GONE
// messageView.visibility = View.VISIBLE
}
private fun showTranscribing() {
// val candidatesView = ui.findViewById<HorizontalScrollView>(R.id.suggestion_container)
// val loadingView = ui.findViewById<LinearLayout>(R.id.loading_container)
// val messageView = ui.findViewById<LinearLayout>(R.id.message_container)
//
// candidatesView.visibility = View.GONE
// loadingView.visibility = View.VISIBLE
// messageView.visibility = View.GONE
}
private fun stopRecording() { private fun stopRecording() {
recorder?.run { recorder?.run {
stop() stop()

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<net.mezimmah.wkt9.layout.LoadingLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="44dp"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:theme="@style/Theme.AppCompat.DayNight"
android:gravity="bottom"
android:background="@color/black"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/suggestions"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content"
android:layout_height="40dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textColor="@color/suggestion_text"
android:paddingVertical="5dp"
android:paddingHorizontal="8dp"
android:textSize="20sp"
android:textFontWeight="400"
android:text="Transcribing..." />
</net.mezimmah.wkt9.layout.LoadingLayout>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <net.mezimmah.wkt9.layout.MessageLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="44dp" android:layout_height="44dp"
@@ -10,11 +10,11 @@
android:background="@color/black" android:background="@color/black"
android:orientation="horizontal"> android:orientation="horizontal">
<ProgressBar <ImageView
android:id="@+id/suggestions" android:layout_height="40dp"
style="?android:attr/progressBarStyleLarge"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="40dp" /> android:src="@drawable/mic"/>
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
@@ -24,6 +24,6 @@
android:paddingHorizontal="8dp" android:paddingHorizontal="8dp"
android:textSize="20sp" android:textSize="20sp"
android:textFontWeight="400" android:textFontWeight="400"
android:text="Transcribing, please wait..." /> android:text="Recording..." />
</LinearLayout> </net.mezimmah.wkt9.layout.MessageLayout>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/suggestion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp">
<TextView
android:id="@+id/suggestion_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textColor="@color/suggestion_text"
android:minWidth="40dp"
android:paddingVertical="5dp"
android:paddingHorizontal="8dp"
android:textSize="20sp"
android:textFontWeight="400" />
</LinearLayout>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<net.mezimmah.wkt9.layout.Words xmlns:android="http://schemas.android.com/apk/res/android" <net.mezimmah.wkt9.layout.WordsLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
@@ -14,4 +14,4 @@
android:layout_height="44dp" android:layout_height="44dp"
android:orientation="horizontal" /> android:orientation="horizontal" />
</net.mezimmah.wkt9.layout.Words> </net.mezimmah.wkt9.layout.WordsLayout>