diff --git a/TODO b/TODO index e4669ff..90132ed 100644 --- a/TODO +++ b/TODO @@ -1,10 +1,9 @@ Basic: -* Record inputs for koch lesson -* Koch result analysis screen * Remember last lesson Polish: * Better user input +* Better statistics on results * Visual styling * Settings info text * Extract UI strings into resource file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7224df2..c826c64 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,7 +9,12 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + + diff --git a/app/src/main/java/es/eoinrul/ecwt/TrainingActivity.kt b/app/src/main/java/es/eoinrul/ecwt/TrainingActivity.kt index 7ac5299..c7350ce 100644 --- a/app/src/main/java/es/eoinrul/ecwt/TrainingActivity.kt +++ b/app/src/main/java/es/eoinrul/ecwt/TrainingActivity.kt @@ -1,6 +1,7 @@ package es.eoinrul.ecwt import android.app.Activity +import android.content.Intent import android.os.Bundle import android.view.KeyEvent import android.view.View @@ -10,6 +11,8 @@ import androidx.appcompat.app.AppCompatActivity import androidx.preference.PreferenceManager import kotlin.random.Random +const val TRAINING_ANSWER = "es.eoinrul.ecwt.TRAINING_ANSWER" +const val TRAINING_COPIED = "es.eoinrul.ecwt.TRAINING_COPIED" class TrainingActivity : AppCompatActivity(), DitDahSoundStream.StreamNotificationListener { @@ -44,6 +47,12 @@ class TrainingActivity : AppCompatActivity(), super.onPause(); mSoundPlayer?.quit() mSoundPlayer = null + + if(mLessonStarted) { + // Shut down the soft keyboard + val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0); + } } override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { @@ -67,9 +76,23 @@ class TrainingActivity : AppCompatActivity(), } override fun streamFinished(stream: DitDahSoundStream) { + // The lesson text has an extra space at the end, which we don't want to grade + var lessonText = mLessonText.trim() + // The input text has a leading space that we don't want to grade + var inputText = mEnteredTextView.text.trim() + + val intent = Intent(this, TrainingResultsActivity::class.java).apply { + putExtra(TRAINING_ANSWER, lessonText) + putExtra(TRAINING_COPIED, inputText) + putExtra(TRAINING_ALPHABET, mAlphabet) // For a "retry" button + } + startActivity(intent); } fun onStartTrainingClicked(view : View) { + if(mLessonStarted) + return + mEnteredTextView.text = " " // Bring up the soft keyboard @@ -98,11 +121,14 @@ class TrainingActivity : AppCompatActivity(), } mSoundPlayer!!.enqueue(StringToSoundSequence(lessonText)) + mLessonStarted = true + mLessonText = lessonText } private var mAlphabet : String = "" private var mSoundPlayer : DitDahSoundStream? = null private lateinit var mEnteredTextView : TextView private var mLessonStarted : Boolean = false + private var mLessonText : String = "" } diff --git a/app/src/main/java/es/eoinrul/ecwt/TrainingResultsActivity.kt b/app/src/main/java/es/eoinrul/ecwt/TrainingResultsActivity.kt index fe7943f..221fd7e 100644 --- a/app/src/main/java/es/eoinrul/ecwt/TrainingResultsActivity.kt +++ b/app/src/main/java/es/eoinrul/ecwt/TrainingResultsActivity.kt @@ -1,12 +1,51 @@ package es.eoinrul.ecwt +import android.content.Intent import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.view.View +import android.widget.TextView +import kotlinx.android.synthetic.main.activity_level_select.* +import kotlin.math.min class TrainingResultsActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_training_results) + + var userInputText = intent.getStringExtra(TRAINING_COPIED).toLowerCase() + var correctText = intent.getStringExtra(TRAINING_ANSWER).toLowerCase() + + var editDistance = levenshtein(correctText, userInputText) + + var fractionCorrect : Float = (correctText.length - editDistance).toFloat() / correctText.length.toFloat() + var percentCorrect = if(editDistance == 0) { 100 } else { (fractionCorrect * 100.0f).toInt() } + + findViewById(R.id.resultSummary).text = "Score: " + percentCorrect + "%\nMade " + editDistance.toString() + " mistakes" + + // TODO Could have a per-character breakdown here + // TODO Next lesson button? + } + + fun onTryAgainButtonPressed(view : View) { + val intent = Intent(this, TrainingActivity::class.java).apply { + putExtra(TRAINING_ALPHABET, intent.getStringExtra(TRAINING_ALPHABET)) + } + startActivity(intent); + } + + private fun levenshtein(a : String, b : String) : Int { + if(a.isEmpty()) return b.length + if(b.isEmpty()) return a.length + + if(a[0] == b[0]) { + return levenshtein(a.substring(1), b.substring(1)) + } else { + var insertDistance = levenshtein(a, b.substring(1)) + var deleteDistance = levenshtein(a.substring(1), b) + var substituteDistance = levenshtein(a.substring(1), b.substring(1)) + return 1 + min(min(insertDistance, deleteDistance), substituteDistance) + } } } diff --git a/app/src/main/res/layout/activity_training_results.xml b/app/src/main/res/layout/activity_training_results.xml index 3720f6c..a6ab091 100644 --- a/app/src/main/res/layout/activity_training_results.xml +++ b/app/src/main/res/layout/activity_training_results.xml @@ -6,4 +6,24 @@ android:layout_height="match_parent" tools:context=".TrainingResultsActivity"> + + +