From 0d8dae23260783d76a78815d18f73c76798cdbc0 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Thu, 2 Mar 2017 20:32:49 -0800 Subject: [PATCH] Added ability to include literal string in manual steps. --- README.md | 9 +- .../tesremoteprogrammer/MainActivity.kt | 5 +- .../ProgrammingActivity.kt | 105 ++++++++++-------- .../android/tesremoteprogrammer/util/Dtmf.kt | 12 +- app/src/main/res/raw/dks_1802_epd.json | 6 + app/src/main/res/values/strings.xml | 1 + build.gradle | 2 +- 7 files changed, 81 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 1b8fb9e..1a5bb27 100644 --- a/README.md +++ b/README.md @@ -156,10 +156,11 @@ DTMF represent the dialing sequence for the programming steps. A comma (`,`) sho The following markers will be substituted by their actual values upon dialing. -| Marker | Description | -|:-----------|:------------------------------------------------------------------------------| -|`[MASTER]` | Substituted with the Master Code | -|`[FIELD:X]` | Substituted with the field's value, where X is the field number in the array. | +| Marker | Description | +|:--------------|:------------------------------------------------------------------------------------------| +|`[MASTER]` | Substituted with the Master Code | +|`[FIELD:X]` | Substituted with the field's value, where X is the field number in the array. | +|`'Some text'` | Displays the enclosed text as a manual step. The 'nodial' [option](#options) must be set. | #### Validation diff --git a/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/MainActivity.kt b/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/MainActivity.kt index 6ed9e1e..92d01a7 100644 --- a/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/MainActivity.kt +++ b/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/MainActivity.kt @@ -74,6 +74,7 @@ class MainActivity : AppCompatActivity(), AnkoLogger { companion object { val PAUSE = ',' + val QUOTE = "'" } inline fun ViewManager.textInputEditText(theme: Int = 0, init: TextInputEditText.() -> Unit) = ankoView(::TextInputEditText, theme, init) @@ -424,7 +425,7 @@ class MainActivity : AppCompatActivity(), AnkoLogger { R.string.validate_missing_opts_prop, i + 1, "dtmf")) - } else if (fields.isEmpty()) { // fields missing + } else if (!nodial && fields.isEmpty()) { // fields missing errors.append(getString( R.string.validate_missing_opts_prop, i + 1, @@ -442,7 +443,7 @@ class MainActivity : AppCompatActivity(), AnkoLogger { } if (!Dtmf.validate(mock, - "${MainActivity.PAUSE}${params.ack}${params.alt}$blank")) { + "${MainActivity.PAUSE}${params.ack}${params.alt}$blank", nodial)) { errors.append(getString( R.string.validate_invalid_opts_prop, i + 1, diff --git a/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/ProgrammingActivity.kt b/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/ProgrammingActivity.kt index 3c5eb32..348245f 100644 --- a/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/ProgrammingActivity.kt +++ b/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/ProgrammingActivity.kt @@ -91,63 +91,72 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger { lparams(width = matchParent, height = wrapContent) // fields - val it = option.fields.iterator() - while (it.hasNext()) { - val field = it.next() + if (option.fields.isEmpty()) { + // no configurations + autofitTextView { + text = getString(R.string.no_conf_req) + typeface = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC) + }.lparams(width = matchParent, height = matchParent) - textInputLayout { - horizontalPadding = dip(40) - lparams(width = matchParent) + } else { + val it = option.fields.iterator() + while (it.hasNext()) { + val field = it.next() - val inputFilters: ArrayList = ArrayList() + textInputLayout { + horizontalPadding = dip(40) + lparams(width = matchParent) - val editText = textInputEditText() { - hint = field!!.hint + val inputFilters: ArrayList = ArrayList() - if (field.alpha) { - if (params.type.isDKS()) { - inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS - inputFilters.add(AlphaFilter(Dtmf.DKS_EXTRAS)) - } else if (params.type.isLinear()) { - inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_WORDS - inputFilters.add(AlphaFilter(Dtmf.LINEAR_EXTRAS)) + val editText = textInputEditText() { + hint = field!!.hint + + if (field.alpha) { + if (params.type.isDKS()) { + inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS + inputFilters.add(AlphaFilter(Dtmf.DKS_EXTRAS)) + } else if (params.type.isLinear()) { + inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_WORDS + inputFilters.add(AlphaFilter(Dtmf.LINEAR_EXTRAS)) + } + } else { + inputType = InputType.TYPE_CLASS_PHONE + inputFilters.add(NumberFilter(field.digits, if (field.alt) params.alt else empty)) + if (field.max != -1 && field.min != -1) { + inputFilters.add( + MinMaxFilter( + field.min, + field.max, + field.size, + params.type.isDKS() || field.zeros)) + } } - } else { - inputType = InputType.TYPE_CLASS_PHONE - inputFilters.add(NumberFilter(field.digits, if (field.alt) params.alt else empty)) - if (field.max != -1 && field.min != -1) { - inputFilters.add( - MinMaxFilter( - field.min, - field.max, - field.size, - params.type.isDKS() || field.zeros)) + + if (field.size != -1) { + inputFilters.add(InputFilter.LengthFilter(field.size)) } - } - if (field.size != -1) { - inputFilters.add(InputFilter.LengthFilter(field.size)) - } + if (inputFilters.isNotEmpty()) { + filters = inputFilters.toTypedArray() + } - if (inputFilters.isNotEmpty()) { - filters = inputFilters.toTypedArray() - } - - if (!it.hasNext()) { - imeOptions = EditorInfo.IME_ACTION_DONE - setOnEditorActionListener { v, id, event -> - if (id == EditorInfo.IME_ACTION_DONE) { - clearFocus() - val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - imm.hideSoftInputFromWindow(windowToken, 0) - true - } else { - false + if (!it.hasNext()) { + imeOptions = EditorInfo.IME_ACTION_DONE + setOnEditorActionListener { v, id, event -> + if (id == EditorInfo.IME_ACTION_DONE) { + clearFocus() + val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + imm.hideSoftInputFromWindow(windowToken, 0) + true + } else { + false + } } } } + fields.add(editText) } - fields.add(editText) } } } @@ -165,7 +174,7 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger { onClick { if (validateFields(params.type, fields, option)) { val dtmf = Dtmf.build(params.type, params.master, params.ack, option, fields) - if (Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.ack}${params.alt}")) { + if (Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.ack}${params.alt}", option.nodial)) { val begin = if (params.begin.isNotBlank()) { "${params.begin}${MainActivity.PAUSE}" } else { @@ -179,7 +188,7 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger { } startActivity( - StepsActivity.EXTRA_STEPS to "$begin$dtmf$end".split(MainActivity.PAUSE)) + StepsActivity.EXTRA_STEPS to "$begin${dtmf.replace(MainActivity.QUOTE, empty)}$end".split(MainActivity.PAUSE)) } else { Snackbar.make(this@coordinatorLayout, getString(R.string.error_invalid_dtmf, dtmf), @@ -212,7 +221,7 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger { onClick { if (validateFields(params.type, fields, option)) { val dtmf = Dtmf.build(params.type, params.master, params.ack, option, fields) - if (Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.ack}${params.alt}")) { + if (Dtmf.validate(dtmf, "${MainActivity.PAUSE}${params.ack}${params.alt}", option.nodial)) { ProgrammingActivityPermissionsDispatcher.callWithCheck( this@ProgrammingActivity, params.phone, dtmf) } else { diff --git a/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/util/Dtmf.kt b/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/util/Dtmf.kt index 843a85b..03afa6b 100644 --- a/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/util/Dtmf.kt +++ b/app/src/main/java/net/thauvin/erik/android/tesremoteprogrammer/util/Dtmf.kt @@ -173,10 +173,14 @@ class Dtmf { return option.dtmf.replaceAll(replace.toTypedArray()) } - fun validate(dtmf: String, extra: String): Boolean { - dtmf.forEach { - if (!(it.isDigit() || it == ',' || extra.contains(it))) { - return false + fun validate(dtmf: String, extra: String, nodial: Boolean): Boolean { + dtmf.split(MainActivity.PAUSE).forEach { + if (!(nodial && it.endsWith(MainActivity.QUOTE) && it.startsWith(MainActivity.QUOTE))) { + it.forEach { + if (!(it.isDigit() || it == ',' || extra.contains(it))) { + return false + } + } } } return true diff --git a/app/src/main/res/raw/dks_1802_epd.json b/app/src/main/res/raw/dks_1802_epd.json index e4c4b03..4f0ad20 100644 --- a/app/src/main/res/raw/dks_1802_epd.json +++ b/app/src/main/res/raw/dks_1802_epd.json @@ -535,6 +535,12 @@ ], "dtmf": "*41[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3]*" }, + { + "title": "Delete Name", + "fields": [], + "nodial": true, + "dtmf": "*65[MASTER],'NEXT=* or ERASE=0'" + }, { "title": "Add Name", "fields": [ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e5b41de..246c6b8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,6 +21,7 @@ Required Master Code Phone Number + No configuration required. PROGRAMMING Step %1$d of %2$d Missing pause between steps diff --git a/build.gradle b/build.gradle index aaf2092..32e160d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0-rc1' + classpath 'com.android.tools.build:gradle:2.3.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong