Added digits field property.

This commit is contained in:
Erik C. Thauvin 2016-08-31 09:16:29 -07:00
parent 9d100901b5
commit 72e75f3eaa
13 changed files with 192 additions and 86 deletions

View file

@ -54,14 +54,14 @@ Parameters define the configuration's global settings.
}
```
| Parameter | Description | Required |
|:-----------|:-------------------------------------------------------------------------------------------------|:---------|
|`name` | The name of the configuration. | Yes |
|`ack` | The key used to acknowledge or terminate programming steps. Most systems use the `*` or `#` key. | Yes |
|`alt` | They key used to in place of numbers when applicable. DKS systems use the `#` key | No |
|`begin` | The begin programming manual sequence. For example Linear uses `0` and `2` pressed together. | No |
|`end` | The end programming manual sequence. For example DSK uses `0` and `#` pressed together. | No |
|`size` | The size (number of digits) of the master code. Most systems use 4 or 6. | Yes |
| Property | Description | Required |
|:---------|:-------------------------------------------------------------------------------------------------|:---------|
|`name` | The name of the configuration. | Yes |
|`ack` | The key used to acknowledge or terminate programming steps. Most systems use the `*` or `#` key. | Yes |
|`alt` | They key used to in place of numbers when applicable. DKS systems use the `#` key | No |
|`begin` | The begin programming manual sequence. For example Linear uses `0` and `2` pressed together. | No |
|`end` | The end programming manual sequence. For example DSK uses `0` and `#` pressed together. | No |
|`size` | The size (number of digits) of the master code. Most systems use 4 or 6. | Yes |
### Options
@ -134,7 +134,8 @@ Fields represent the data entry text fields on option screens.
|`min` | Set the minimum value of a numeric field. | No |
|`max` | Set the maximum value of a numeric field. | No |
|`alpha` | Set to `dks` or `linear` for alphanumeric fields. | No |
|`alt` | Set to `true` if the field accepts the `alt` [parameter](#parameters) value in place of a digit. | No |
'`digits` | Set digits that are allowed. For example DKS uses `1234567` for days of the week: Sun=1... Sat=7. | No |
|`alt` | Set to `true` if the field accepts the `alt` [parameter](#parameters) value in place of a digit. | No |
|`zeros` | Set to `true` by default. Allows numeric values with leading zeros (i.e. `001`), based on the `size`. | No |

View file

@ -44,6 +44,7 @@ import com.google.gson.JsonSyntaxException
import net.thauvin.erik.android.tesremoteprogrammer.models.Config
import net.thauvin.erik.android.tesremoteprogrammer.models.Configurations
import net.thauvin.erik.android.tesremoteprogrammer.util.Dtmf
import net.thauvin.erik.android.tesremoteprogrammer.util.isDigits
import org.jetbrains.anko.*
import org.jetbrains.anko.design.textInputLayout
import permissions.dispatcher.NeedsPermission
@ -382,6 +383,14 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "minSize/size"))
}
if (field.digits.isNotBlank() && !field.digits.isDigits()) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "digits"))
}
if (!Dtmf.isValidAlpha(field.alpha)) {
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "alpha"))
}
if (field.alpha.isBlank()) {
if (field.min >= 0 || field.max >= 0) {
if (field.max < 1) {

View file

@ -108,8 +108,7 @@ class ProgrammingActivity : AppCompatActivity(), AnkoLogger {
}
} else {
inputType = InputType.TYPE_CLASS_PHONE
inputFilters.add(NumberFilter("0123456789" +
if (field.alt) "${params.alt}" else ""))
inputFilters.add(NumberFilter(field.digits, if (field.alt) params.alt else ""))
if (field.max != -1 && field.min != -1) {
inputFilters.add(
MinMaxFilter(field.min, field.max, field.size, field.zeros))

View file

@ -48,7 +48,7 @@ class AlphaFilter : InputFilter {
for (i in start..end - 1) {
val c = source[i]
if (c.isLetterOrDigit() || extras.contains(c)) {
sb.append(c.toUpperCase())
sb.append(c)
}
}
return sb.toString()

View file

@ -20,12 +20,19 @@ package net.thauvin.erik.android.tesremoteprogrammer.filters
import android.text.InputFilter
import android.text.SpannableStringBuilder
import android.text.Spanned
import net.thauvin.erik.android.tesremoteprogrammer.util.isDigits
import org.jetbrains.anko.AnkoLogger
class NumberFilter : InputFilter {
class NumberFilter : InputFilter, AnkoLogger {
private val allowed: String
private val digits = "0123456789"
constructor(allowed: String) {
this.allowed = allowed
constructor(allowed: String, alt: String) {
this.allowed = if (allowed.isDigits()) {
"$allowed$alt"
} else {
"$digits$alt"
}
}
override fun filter(source: CharSequence,

View file

@ -23,6 +23,7 @@ import java.io.Serializable
data class Field(var hint: String,
var alpha: String,
var digits: String,
val alt: Boolean,
var zeros: Boolean,
var minSize: Int,
@ -39,9 +40,10 @@ data class Field(var hint: String,
}
}
constructor() : this("", "", false, true, -1, -1, -1, -1)
constructor() : this("", "", "", false, true, -1, -1, -1, -1)
constructor(source: Parcel) : this(
source.readString(),
source.readString(),
source.readString(),
1.equals(source.readInt()),
@ -56,6 +58,7 @@ data class Field(var hint: String,
override fun writeToParcel(dest: Parcel?, flags: Int) {
dest?.writeString(hint)
dest?.writeString(alpha)
dest?.writeString(digits)
dest?.writeInt((if (alt) 1 else 0))
dest?.writeInt((if (zeros) 1 else 0))
dest?.writeInt(minSize)

View file

@ -31,6 +31,67 @@ class Dtmf {
val DKS_EXTRAS = " "
val LINEAR_EXTRAS = ", -."
private fun dksAlphaToDigits(text: String, ack: String): String {
val result = StringBuffer()
text.toUpperCase().forEach { c ->
when (c) {
'A' -> result.append("2$ack${MainActivity.PAUSE}")
'B' -> result.append("22$ack${MainActivity.PAUSE}")
'C' -> result.append("222$ack${MainActivity.PAUSE}")
'D' -> result.append("3$ack${MainActivity.PAUSE}")
'E' -> result.append("33$ack${MainActivity.PAUSE}")
'F' -> result.append("333$ack${MainActivity.PAUSE}")
'G' -> result.append("4$ack${MainActivity.PAUSE}")
'H' -> result.append("44$ack${MainActivity.PAUSE}")
'I' -> result.append("444$ack${MainActivity.PAUSE}")
'J' -> result.append("5$ack${MainActivity.PAUSE}")
'K' -> result.append("55$ack${MainActivity.PAUSE}")
'L' -> result.append("555$ack${MainActivity.PAUSE}")
'M' -> result.append("6$ack${MainActivity.PAUSE}")
'N' -> result.append("66$ack${MainActivity.PAUSE}")
'O' -> result.append("666$ack${MainActivity.PAUSE}")
'P' -> result.append("7$ack${MainActivity.PAUSE}")
'Q' -> result.append("77$ack${MainActivity.PAUSE}")
'R' -> result.append("777$ack${MainActivity.PAUSE}")
'S' -> result.append("7777$ack${MainActivity.PAUSE}")
'T' -> result.append("8$ack${MainActivity.PAUSE}")
'U' -> result.append("88$ack${MainActivity.PAUSE}")
'V' -> result.append("888$ack${MainActivity.PAUSE}")
'W' -> result.append("9$ack${MainActivity.PAUSE}")
'X' -> result.append("99$ack${MainActivity.PAUSE}")
'Y' -> result.append("999$ack${MainActivity.PAUSE}")
'Z' -> result.append("9999$ack${MainActivity.PAUSE}")
'0' -> result.append("0$ack${MainActivity.PAUSE}")
'1' -> result.append("11$ack${MainActivity.PAUSE}")
'2' -> result.append("2222$ack${MainActivity.PAUSE}")
'3' -> result.append("3333$ack${MainActivity.PAUSE}")
'4' -> result.append("4444$ack${MainActivity.PAUSE}")
'5' -> result.append("5555$ack${MainActivity.PAUSE}")
'6' -> result.append("6666$ack${MainActivity.PAUSE}")
'7' -> result.append("77777$ack${MainActivity.PAUSE}")
'8' -> result.append("8888$ack${MainActivity.PAUSE}")
'9' -> result.append("99999$ack${MainActivity.PAUSE}")
' ' -> result.append("1$ack${MainActivity.PAUSE}")
}
}
return result.toString()
}
fun isValidAlpha(alpha: String) : Boolean {
return alpha.isBlank() || alpha.equals(DKS, true) || alpha.equals(LINEAR, true)
}
private fun linearAlphaToDigits(text: String): String {
val result = StringBuffer()
@ -91,62 +152,6 @@ class Dtmf {
return result.toString()
}
private fun dksAlphaToDigits(text: String, ack: String): String {
val result = StringBuffer()
text.toUpperCase().forEach { c ->
when (c) {
'A' -> result.append("2$ack${MainActivity.PAUSE}")
'B' -> result.append("22$ack${MainActivity.PAUSE}")
'C' -> result.append("222$ack${MainActivity.PAUSE}")
'D' -> result.append("3$ack${MainActivity.PAUSE}")
'E' -> result.append("33$ack${MainActivity.PAUSE}")
'F' -> result.append("333$ack${MainActivity.PAUSE}")
'G' -> result.append("4$ack${MainActivity.PAUSE}")
'H' -> result.append("44$ack${MainActivity.PAUSE}")
'I' -> result.append("444$ack${MainActivity.PAUSE}")
'J' -> result.append("5$ack${MainActivity.PAUSE}")
'K' -> result.append("55$ack${MainActivity.PAUSE}")
'L' -> result.append("555$ack${MainActivity.PAUSE}")
'M' -> result.append("6$ack${MainActivity.PAUSE}")
'N' -> result.append("66$ack${MainActivity.PAUSE}")
'O' -> result.append("666$ack${MainActivity.PAUSE}")
'P' -> result.append("7$ack${MainActivity.PAUSE}")
'Q' -> result.append("77$ack${MainActivity.PAUSE}")
'R' -> result.append("777$ack${MainActivity.PAUSE}")
'S' -> result.append("7777$ack${MainActivity.PAUSE}")
'T' -> result.append("8$ack${MainActivity.PAUSE}")
'U' -> result.append("88$ack${MainActivity.PAUSE}")
'V' -> result.append("888$ack${MainActivity.PAUSE}")
'W' -> result.append("9$ack${MainActivity.PAUSE}")
'X' -> result.append("99$ack${MainActivity.PAUSE}")
'Y' -> result.append("999$ack${MainActivity.PAUSE}")
'Z' -> result.append("9999$ack${MainActivity.PAUSE}")
'0' -> result.append("0$ack${MainActivity.PAUSE}")
'1' -> result.append("11$ack${MainActivity.PAUSE}")
'2' -> result.append("2222$ack${MainActivity.PAUSE}")
'3' -> result.append("3333$ack${MainActivity.PAUSE}")
'4' -> result.append("4444$ack${MainActivity.PAUSE}")
'5' -> result.append("5555$ack${MainActivity.PAUSE}")
'6' -> result.append("6666$ack${MainActivity.PAUSE}")
'7' -> result.append("77777$ack${MainActivity.PAUSE}")
'8' -> result.append("8888$ack${MainActivity.PAUSE}")
'9' -> result.append("99999$ack${MainActivity.PAUSE}")
' ' -> result.append("1$ack${MainActivity.PAUSE}")
}
}
return result.toString()
}
fun build(master: String,
ack: String,
option: Option,

View file

@ -17,6 +17,20 @@
*/
package net.thauvin.erik.android.tesremoteprogrammer.util
fun String.isDigits() : Boolean {
if (isBlank()) {
return false
}
forEach {
if (!it.isDigit()) {
return false
}
}
return true
}
fun String.replaceAll(replace: Array<Pair<String, String>>): String {
val result = StringBuilder(this)
var offset: Int

View file

@ -330,11 +330,30 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3][FIELD:4]*,[FIELD:5]*,[FIELD:6][FIELD:7]*,[FIELD:8]*,[FIELD:9]*"
},
{
"title": "Enable/Disable Automatic Relay Time Zone",
"fields": [
{
"hint": "Time Zone (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "OFF=0 ON=1",
"size": 1,
"min": 0,
"max": 1
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*"
},
{
"title": "Set 4-Digit Entry Code Time Zone",
"fields": [
@ -383,7 +402,8 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
},
{
"hint": "Lower 4-Digit Boundary",
@ -456,7 +476,8 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
},
{
"hint": "Lower 4-Digit Boundary",

View file

@ -330,11 +330,30 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3][FIELD:4]*,[FIELD:5]*,[FIELD:6][FIELD:7]*,[FIELD:8]*,[FIELD:9]*"
},
{
"title": "Enable/Disable Automatic Relay Time Zone",
"fields": [
{
"hint": "Time Zone (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "OFF=0 ON=1",
"size": 1,
"min": 0,
"max": 1
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*"
},
{
"title": "Set 4-Digit Entry Code Time Zone",
"fields": [
@ -383,7 +402,8 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
},
{
"hint": "Lower 4-Digit Boundary",
@ -456,7 +476,8 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
},
{
"hint": "Lower 4-Digit Boundary",

View file

@ -202,11 +202,30 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
}
],
"dtmf": "*35[MASTER],[FIELD:1][FIELD:2]*,[FIELD:3][FIELD:4]*,[FIELD:5]*,[FIELD:6]*,[FIELD:7]*"
},
{
"title": "Enable/Disable Automatic Relay Time Zone",
"fields": [
{
"hint": "Time Zone (1..4)",
"size": 1,
"min": 1,
"max": 4
},
{
"hint": "OFF=0 ON=1",
"size": 1,
"min": 0,
"max": 1
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*"
},
{
"title": "Set 4-Digit Entry Code Time Zone",
"fields": [
@ -231,7 +250,8 @@
{
"hint": "Days of Week (Sun=1..Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
},
{
"hint": "Lower 4-Digit Boundary",
@ -268,7 +288,8 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
},
{
"hint": "Lower 5-Digit Boundary",

View file

@ -113,7 +113,8 @@
{
"hint": "Active Days of Week (Sun=1..Sat=7, or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
}
],
"dtmf": "*34[MASTER],[FIELD:1]*,[FIELD:2][FIELD:3]*,[FIELD:4]*,[FIELD:5]*"
@ -148,7 +149,8 @@
{
"hint": "Active Days of Week (Sun=1..Sat=7, or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2][FIELD:3]*,[FIELD:4]*,[FIELD:5]*"
@ -201,7 +203,8 @@
{
"hint": "Active Days of Week (Sun=1..Sat=7, or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
}
],
"dtmf": "*36[MASTER],[FIELD:1]*,[FIELD:2][FIELD:3][FIELD:4]*,[FIELD:5][FIELD:6][FIELD:7]*,[FIELD:8]"
@ -254,7 +257,8 @@
{
"hint": "Active Days of Week (Sun=1..Sat=7, or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
}
],
"dtmf": "*37[MASTER],[FIELD:1]*,[FIELD:2][FIELD:3][FIELD:4]*,[FIELD:5][FIELD:6][FIELD:7]*,[FIELD:8]"

View file

@ -160,7 +160,8 @@
{
"hint": "Days of Week (Sun=1, Sat=7 or #)",
"size": 7,
"alt": true
"alt": true,
"digits": "1234567"
}
],
"dtmf": "*35[MASTER],[FIELD:1]*,[FIELD:2]*,[FIELD:3][FIELD:4]*,[FIELD:5][FIELD:6]*,[FIELD:7]*,[FIELD:8]*"