Added ability to include literal string in manual steps.

This commit is contained in:
Erik C. Thauvin 2017-03-02 20:32:49 -08:00
parent 24d2042454
commit 0d8dae2326
7 changed files with 81 additions and 59 deletions

View file

@ -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. The following markers will be substituted by their actual values upon dialing.
| Marker | Description | | Marker | Description |
|:-----------|:------------------------------------------------------------------------------| |:--------------|:------------------------------------------------------------------------------------------|
|`[MASTER]` | Substituted with the Master Code | |`[MASTER]` | Substituted with the Master Code |
|`[FIELD:X]` | Substituted with the field's value, where X is the field number in the array. | |`[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 #### Validation

View file

@ -74,6 +74,7 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
companion object { companion object {
val PAUSE = ',' val PAUSE = ','
val QUOTE = "'"
} }
inline fun ViewManager.textInputEditText(theme: Int = 0, init: TextInputEditText.() -> Unit) = ankoView(::TextInputEditText, theme, init) 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, R.string.validate_missing_opts_prop,
i + 1, i + 1,
"dtmf")) "dtmf"))
} else if (fields.isEmpty()) { // fields missing } else if (!nodial && fields.isEmpty()) { // fields missing
errors.append(getString( errors.append(getString(
R.string.validate_missing_opts_prop, R.string.validate_missing_opts_prop,
i + 1, i + 1,
@ -442,7 +443,7 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
} }
if (!Dtmf.validate(mock, if (!Dtmf.validate(mock,
"${MainActivity.PAUSE}${params.ack}${params.alt}$blank")) { "${MainActivity.PAUSE}${params.ack}${params.alt}$blank", nodial)) {
errors.append(getString( errors.append(getString(
R.string.validate_invalid_opts_prop, R.string.validate_invalid_opts_prop,
i + 1, i + 1,

View file

@ -91,63 +91,72 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
lparams(width = matchParent, height = wrapContent) lparams(width = matchParent, height = wrapContent)
// fields // fields
val it = option.fields.iterator() if (option.fields.isEmpty()) {
while (it.hasNext()) { // no configurations
val field = it.next() autofitTextView {
text = getString(R.string.no_conf_req)
typeface = Typeface.create(Typeface.DEFAULT, Typeface.ITALIC)
}.lparams(width = matchParent, height = matchParent)
textInputLayout { } else {
horizontalPadding = dip(40) val it = option.fields.iterator()
lparams(width = matchParent) while (it.hasNext()) {
val field = it.next()
val inputFilters: ArrayList<InputFilter> = ArrayList() textInputLayout {
horizontalPadding = dip(40)
lparams(width = matchParent)
val editText = textInputEditText() { val inputFilters: ArrayList<InputFilter> = ArrayList()
hint = field!!.hint
if (field.alpha) { val editText = textInputEditText() {
if (params.type.isDKS()) { hint = field!!.hint
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
inputFilters.add(AlphaFilter(Dtmf.DKS_EXTRAS)) if (field.alpha) {
} else if (params.type.isLinear()) { if (params.type.isDKS()) {
inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_WORDS inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
inputFilters.add(AlphaFilter(Dtmf.LINEAR_EXTRAS)) 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 if (field.size != -1) {
inputFilters.add(NumberFilter(field.digits, if (field.alt) params.alt else empty)) inputFilters.add(InputFilter.LengthFilter(field.size))
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) { if (inputFilters.isNotEmpty()) {
inputFilters.add(InputFilter.LengthFilter(field.size)) filters = inputFilters.toTypedArray()
} }
if (inputFilters.isNotEmpty()) { if (!it.hasNext()) {
filters = inputFilters.toTypedArray() imeOptions = EditorInfo.IME_ACTION_DONE
} setOnEditorActionListener { v, id, event ->
if (id == EditorInfo.IME_ACTION_DONE) {
if (!it.hasNext()) { clearFocus()
imeOptions = EditorInfo.IME_ACTION_DONE val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
setOnEditorActionListener { v, id, event -> imm.hideSoftInputFromWindow(windowToken, 0)
if (id == EditorInfo.IME_ACTION_DONE) { true
clearFocus() } else {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager false
imm.hideSoftInputFromWindow(windowToken, 0) }
true
} else {
false
} }
} }
} }
fields.add(editText)
} }
fields.add(editText)
} }
} }
} }
@ -165,7 +174,7 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
onClick { onClick {
if (validateFields(params.type, fields, option)) { if (validateFields(params.type, fields, option)) {
val dtmf = Dtmf.build(params.type, params.master, params.ack, option, fields) 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()) { val begin = if (params.begin.isNotBlank()) {
"${params.begin}${MainActivity.PAUSE}" "${params.begin}${MainActivity.PAUSE}"
} else { } else {
@ -179,7 +188,7 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
} }
startActivity<StepsActivity>( startActivity<StepsActivity>(
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 { } else {
Snackbar.make(this@coordinatorLayout, Snackbar.make(this@coordinatorLayout,
getString(R.string.error_invalid_dtmf, dtmf), getString(R.string.error_invalid_dtmf, dtmf),
@ -212,7 +221,7 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
onClick { onClick {
if (validateFields(params.type, fields, option)) { if (validateFields(params.type, fields, option)) {
val dtmf = Dtmf.build(params.type, params.master, params.ack, option, fields) 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( ProgrammingActivityPermissionsDispatcher.callWithCheck(
this@ProgrammingActivity, params.phone, dtmf) this@ProgrammingActivity, params.phone, dtmf)
} else { } else {

View file

@ -173,10 +173,14 @@ class Dtmf {
return option.dtmf.replaceAll(replace.toTypedArray()) return option.dtmf.replaceAll(replace.toTypedArray())
} }
fun validate(dtmf: String, extra: String): Boolean { fun validate(dtmf: String, extra: String, nodial: Boolean): Boolean {
dtmf.forEach { dtmf.split(MainActivity.PAUSE).forEach {
if (!(it.isDigit() || it == ',' || extra.contains(it))) { if (!(nodial && it.endsWith(MainActivity.QUOTE) && it.startsWith(MainActivity.QUOTE))) {
return false it.forEach {
if (!(it.isDigit() || it == ',' || extra.contains(it))) {
return false
}
}
} }
} }
return true return true

View file

@ -535,6 +535,12 @@
], ],
"dtmf": "*41[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3]*" "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", "title": "Add Name",
"fields": [ "fields": [

View file

@ -21,6 +21,7 @@
<string name="error_required">Required</string> <string name="error_required">Required</string>
<string name="hint_master_code">Master Code</string> <string name="hint_master_code">Master Code</string>
<string name="hint_phone_number">Phone Number</string> <string name="hint_phone_number">Phone Number</string>
<string name="no_conf_req">No configuration required.</string>
<string name="programming_heading">PROGRAMMING</string> <string name="programming_heading">PROGRAMMING</string>
<string name="title_template_step">Step <xliff:g id="step_number">%1$d</xliff:g> of <xliff:g id="steps_count">%2$d</xliff:g></string> <string name="title_template_step">Step <xliff:g id="step_number">%1$d</xliff:g> of <xliff:g id="steps_count">%2$d</xliff:g></string>
<string name="validate_dtmf_nopause">Missing pause between steps</string> <string name="validate_dtmf_nopause">Missing pause between steps</string>

View file

@ -6,7 +6,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { 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" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong