Added ability to include literal string in manual steps.
This commit is contained in:
parent
24d2042454
commit
0d8dae2326
7 changed files with 81 additions and 59 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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": [
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue