diff --git a/app/src/main/java/es/eoinrul/ecwt/DitDahGenerator.kt b/app/src/main/java/es/eoinrul/ecwt/DitDahGenerator.kt index 3baecbc..b85d9b2 100644 --- a/app/src/main/java/es/eoinrul/ecwt/DitDahGenerator.kt +++ b/app/src/main/java/es/eoinrul/ecwt/DitDahGenerator.kt @@ -312,53 +312,6 @@ fun SequenceToString(sequence: List) : String { return ret } -// Almost certainly the wrong way to do this -fun KeycodeToSoundSequence(keycode : Int) : List { - return when(keycode) { - KeyEvent.KEYCODE_A -> StringToSoundSequence("A"); - KeyEvent.KEYCODE_B -> StringToSoundSequence("B"); - KeyEvent.KEYCODE_C -> StringToSoundSequence("C"); - KeyEvent.KEYCODE_D -> StringToSoundSequence("D"); - KeyEvent.KEYCODE_E -> StringToSoundSequence("E"); - KeyEvent.KEYCODE_F -> StringToSoundSequence("F"); - KeyEvent.KEYCODE_G -> StringToSoundSequence("G"); - KeyEvent.KEYCODE_H -> StringToSoundSequence("H"); - KeyEvent.KEYCODE_I -> StringToSoundSequence("I"); - KeyEvent.KEYCODE_J -> StringToSoundSequence("J"); - KeyEvent.KEYCODE_K -> StringToSoundSequence("K"); - KeyEvent.KEYCODE_L -> StringToSoundSequence("L"); - KeyEvent.KEYCODE_M -> StringToSoundSequence("M"); - KeyEvent.KEYCODE_N -> StringToSoundSequence("N"); - KeyEvent.KEYCODE_O -> StringToSoundSequence("O"); - KeyEvent.KEYCODE_P -> StringToSoundSequence("P"); - KeyEvent.KEYCODE_Q -> StringToSoundSequence("Q"); - KeyEvent.KEYCODE_R -> StringToSoundSequence("R"); - KeyEvent.KEYCODE_S -> StringToSoundSequence("S"); - KeyEvent.KEYCODE_T -> StringToSoundSequence("T"); - KeyEvent.KEYCODE_U -> StringToSoundSequence("U"); - KeyEvent.KEYCODE_V -> StringToSoundSequence("V"); - KeyEvent.KEYCODE_W -> StringToSoundSequence("W"); - KeyEvent.KEYCODE_X -> StringToSoundSequence("X"); - KeyEvent.KEYCODE_Y -> StringToSoundSequence("Y"); - KeyEvent.KEYCODE_Z -> StringToSoundSequence("Z"); - KeyEvent.KEYCODE_0 -> StringToSoundSequence("0"); - KeyEvent.KEYCODE_1 -> StringToSoundSequence("1"); - KeyEvent.KEYCODE_2 -> StringToSoundSequence("2"); - KeyEvent.KEYCODE_3 -> StringToSoundSequence("3"); - KeyEvent.KEYCODE_4 -> StringToSoundSequence("4"); - KeyEvent.KEYCODE_5 -> StringToSoundSequence("5"); - KeyEvent.KEYCODE_6 -> StringToSoundSequence("6"); - KeyEvent.KEYCODE_7 -> StringToSoundSequence("7"); - KeyEvent.KEYCODE_8 -> StringToSoundSequence("8"); - KeyEvent.KEYCODE_9 -> StringToSoundSequence("9"); - KeyEvent.KEYCODE_PERIOD -> StringToSoundSequence("."); - //KeyEvent.KEYCODE_S -> StringToSoundSequence("?"); - else -> { - StringToSoundSequence(" ") - } - } -} - data class DitDahGeneratorSettings(var context : Context? = null) { //TODO These values are duplicated in the settings fragment var toneFrequency = 650 diff --git a/app/src/main/java/es/eoinrul/ecwt/SounderActivity.kt b/app/src/main/java/es/eoinrul/ecwt/SounderActivity.kt index fd37812..8888592 100644 --- a/app/src/main/java/es/eoinrul/ecwt/SounderActivity.kt +++ b/app/src/main/java/es/eoinrul/ecwt/SounderActivity.kt @@ -1,45 +1,31 @@ package es.eoinrul.ecwt -import android.content.Context -import android.media.MediaPlayer import android.os.Bundle import android.text.Editable import android.text.TextWatcher -import android.view.KeyEvent -import android.view.inputmethod.InputMethodManager import android.widget.EditText import android.widget.TextView import androidx.appcompat.app.AppCompatActivity -import java.util.* +import kotlin.math.max // Activity that only echos any inputs typed on a keyboard -class SounderActivity : AppCompatActivity() { +class SounderActivity : AppCompatActivity(), DitDahSoundStream.StreamNotificationListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_sounder) //val sounderMode = intent.getStringExtra(SOUNDER_MODE); - - mTextViewTest = findViewById(R.id.keyedText); + mPreviouslySentText = findViewById(R.id.sentText) + mCurrentlySendingText = findViewById(R.id.keyedText) // This is a hidden EditText that's used to bring up the soft keyboard: - mKeyboardInput = findViewById(R.id.sounderInput); + mKeyboardInput = findViewById(R.id.sounderInput) mKeyboardInput?.addTextChangedListener(mInputHandler) - mKeyboardInput?.requestFocus(); + mKeyboardInput?.requestFocus() initSoundPlayer() - onTextEntered("E"); // Display and sound something - this is arbitrary - } - - // This will be called for connected USB/Bluetooth keyboards: - override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { - val sequence = KeycodeToSoundSequence(keyCode) - mTextViewTest?.text = SequenceToString(sequence) - mSoundPlayer?.enqueue(sequence) - mKeyboardInput?.setText("") // Should be empty due to physical keyboard - return true; } override fun onResume() { @@ -48,7 +34,7 @@ class SounderActivity : AppCompatActivity() { } override fun onPause() { - super.onPause(); + super.onPause() mSoundPlayer?.quit() mSoundPlayer = null @@ -57,39 +43,28 @@ class SounderActivity : AppCompatActivity() { private fun initSoundPlayer() { val generatorSettings = DitDahGeneratorSettings(this) mSoundPlayer = DitDahSoundStream(generatorSettings) + mSoundPlayer!!.streamNotificationListener = this + mSpaceDurationMs = (mSoundPlayer!!.durationOf(listOf(SoundTypes.LETTER_SPACE)) * 1000).toLong() } - private fun onTextEntered(typedString : String) { - val sequence = StringToSoundSequence(typedString); + private var mPreviouslySentText : TextView? = null + private var mCurrentlySendingText : TextView? = null + private var mKeyboardInput : EditText? = null - // Display the text: - mTextViewTest?.text = SequenceToString(sequence); + private var mSoundPlayer : DitDahSoundStream? = null + // Flag to indicate if the sound player is waiting to send another symbol: + private var mSoundAwaitingText : Boolean = true - // Then play the sound: - mSoundPlayer?.enqueue(sequence); - - // Finally, clear the input box, as we don't need it anymore: - mKeyboardInput?.setText(""); - } - - private var mTextViewTest : TextView? = null; - private var mKeyboardInput : EditText? = null; - private var mMediaPlayer : MediaPlayer? = null; - - private var mSoundPlayer : DitDahSoundStream? = null; + // Duration of a space with current sound gen. Used to add spaces + // automatically, if user input is slow + private var mSpaceDurationMs : Long = 0 + private var mTimeOfFirstSymbolWait : Long = 0 // Utility to watch our EditText and handle any user input // This only seems to get triggered if we're using the software keyboard private val mInputHandler = object : TextWatcher { override fun afterTextChanged(s: Editable?) { - if(s == null) { - return; - } - - if(s.isNotEmpty()) { - var typedString: String = s.toString().capitalize(); - onTextEntered(typedString) - } + ensurePlaying() } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { @@ -98,4 +73,48 @@ class SounderActivity : AppCompatActivity() { override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { } } + + private fun ensurePlaying() { + if(mSoundAwaitingText && mSoundPlayer != null) { + symbolsExhausted(mSoundPlayer!!) + } + } + + override fun symbolsExhausted(stream: DitDahSoundStream) { + if (!mSoundAwaitingText) { + mTimeOfFirstSymbolWait = System.currentTimeMillis() + } + + mSoundAwaitingText = true + runOnUiThread { + if( mKeyboardInput?.text!!.isNotEmpty() && mSoundAwaitingText ) { + mSoundAwaitingText = false + // Extract and remove the first character + val firstInput = mKeyboardInput!!.text!!.subSequence(0, 1).toString() + mKeyboardInput!!.text = mKeyboardInput!!.text.replace(0, 1, "") + // Move text entry cursor to the end + mKeyboardInput!!.setSelection(mKeyboardInput!!.text.length) + + val sequence = StringToSoundSequence(firstInput.capitalize()) + + val now = System.currentTimeMillis() + val extraSpace = if(now - mTimeOfFirstSymbolWait > mSpaceDurationMs) { + " " + } else { + "" + } + + // Display the text: + mCurrentlySendingText?.text = SequenceToString(sequence) + val maxHistory = 20 + val trimFrom = max(0, mPreviouslySentText?.text!!.length - maxHistory + - extraSpace.length - firstInput.length) + mPreviouslySentText?.text = mPreviouslySentText?.text!!.substring(trimFrom, + mPreviouslySentText?.text!!.length) + extraSpace + firstInput + + // Then play the sound: + mSoundPlayer?.enqueue(sequence) + } + } + } } diff --git a/app/src/main/res/layout/activity_sounder.xml b/app/src/main/res/layout/activity_sounder.xml index 520719a..b926221 100644 --- a/app/src/main/res/layout/activity_sounder.xml +++ b/app/src/main/res/layout/activity_sounder.xml @@ -6,6 +6,21 @@ android:layout_height="match_parent" tools:context="es.eoinrul.ecwt.SounderActivity"> + + + app:layout_constraintTop_toBottomOf="@+id/sentText" /> - + android:layout_margin="16dp" + app:layout_constraintTop_toBottomOf="@+id/keyedText" > diff --git a/fastlane/metadata/android/en-US/changelogs/44.txt b/fastlane/metadata/android/en-US/changelogs/44.txt index 40180d1..ed0417f 100644 --- a/fastlane/metadata/android/en-US/changelogs/44.txt +++ b/fastlane/metadata/android/en-US/changelogs/44.txt @@ -1,2 +1,3 @@ Fixed bug where duration of lessons was too long Added tip if users didn't add spaces to lesson input +Improved "Sounder" UI. Now shows some history and upcoming text.