Used kotlin with() whenever possible.
This commit is contained in:
parent
0caa0190d5
commit
9f68f0a41b
2 changed files with 288 additions and 180 deletions
|
@ -147,15 +147,18 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
val fields = arrayListOf<EditText>()
|
// editText, size
|
||||||
|
val fields = arrayListOf<Pair<EditText, Int>>()
|
||||||
|
|
||||||
initConfigurations()
|
initConfigurations()
|
||||||
|
|
||||||
|
with(config.params) {
|
||||||
verticalLayout {
|
verticalLayout {
|
||||||
padding = dip(20)
|
padding = dip(20)
|
||||||
|
|
||||||
|
// config name
|
||||||
textView {
|
textView {
|
||||||
text = config.params.name.toUpperCase()
|
text = name.toUpperCase()
|
||||||
bottomPadding = dip(5)
|
bottomPadding = dip(5)
|
||||||
typeface = Typeface.DEFAULT_BOLD
|
typeface = Typeface.DEFAULT_BOLD
|
||||||
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24f)
|
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24f)
|
||||||
|
@ -164,45 +167,47 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
|
||||||
ellipsize = TextUtils.TruncateAt.END
|
ellipsize = TextUtils.TruncateAt.END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// phone
|
||||||
textInputLayout {
|
textInputLayout {
|
||||||
horizontalPadding = dip(40)
|
horizontalPadding = dip(40)
|
||||||
val phone = editText() {
|
val edtPhone = editText() {
|
||||||
lparams(width = matchParent)
|
lparams(width = matchParent)
|
||||||
inputType = InputType.TYPE_CLASS_PHONE
|
inputType = InputType.TYPE_CLASS_PHONE
|
||||||
hint = getString(R.string.hint_phone_number)
|
hint = getString(R.string.hint_phone_number)
|
||||||
|
|
||||||
if (config.params.phone.isNotBlank()) {
|
if (phone.isNotBlank()) {
|
||||||
setText(config.params.phone)
|
setText(phone)
|
||||||
}
|
}
|
||||||
|
|
||||||
setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_call_black_24dp, 0)
|
setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_call_black_24dp, 0)
|
||||||
setOnFocusChangeListener { view, hasFocus ->
|
setOnFocusChangeListener { view, hasFocus ->
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
config.params.phone = (view as EditText).text.toString()
|
phone = (view as EditText).text.toString()
|
||||||
saveConfig()
|
saveConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fields.add(phone)
|
fields.add(Pair(edtPhone, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// master code
|
||||||
textInputLayout {
|
textInputLayout {
|
||||||
horizontalPadding = dip(40)
|
horizontalPadding = dip(40)
|
||||||
val masterCode = editText() {
|
val edtMasterCode = editText() {
|
||||||
lparams(width = matchParent)
|
lparams(width = matchParent)
|
||||||
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
|
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_VARIATION_PASSWORD
|
||||||
hint = getString(R.string.hint_master_code)
|
hint = getString(R.string.hint_master_code)
|
||||||
filters = arrayOf(InputFilter.LengthFilter(config.params.size))
|
filters = arrayOf(InputFilter.LengthFilter(size))
|
||||||
setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_verified_user_black_24dp, 0)
|
setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_verified_user_black_24dp, 0)
|
||||||
imeOptions = EditorInfo.IME_ACTION_DONE
|
imeOptions = EditorInfo.IME_ACTION_DONE
|
||||||
|
|
||||||
if (config.params.master.isNotBlank()) {
|
if (master.isNotBlank()) {
|
||||||
setText(config.params.master)
|
setText(master)
|
||||||
}
|
}
|
||||||
|
|
||||||
setOnFocusChangeListener { view, hasFocus ->
|
setOnFocusChangeListener { view, hasFocus ->
|
||||||
if (!hasFocus) {
|
if (!hasFocus) {
|
||||||
config.params.master = (view as EditText).text.toString()
|
master = (view as EditText).text.toString()
|
||||||
saveConfig()
|
saveConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,9 +223,10 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fields.add(masterCode)
|
fields.add(Pair(edtMasterCode, size))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// programming title
|
||||||
textView {
|
textView {
|
||||||
topPadding = dip(10)
|
topPadding = dip(10)
|
||||||
text = getString(R.string.programming_heading)
|
text = getString(R.string.programming_heading)
|
||||||
|
@ -228,18 +234,19 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
|
||||||
typeface = Typeface.DEFAULT_BOLD
|
typeface = Typeface.DEFAULT_BOLD
|
||||||
}.lparams(width = matchParent)
|
}.lparams(width = matchParent)
|
||||||
|
|
||||||
|
// options list
|
||||||
|
listView {
|
||||||
val opts = config.opts.sorted()
|
val opts = config.opts.sorted()
|
||||||
val titles = arrayListOf<String>()
|
val titles = arrayListOf<String>()
|
||||||
opts.all {
|
opts.all {
|
||||||
titles.add(it.title)
|
titles.add(it.title)
|
||||||
}
|
}
|
||||||
|
|
||||||
listView {
|
|
||||||
adapter = ArrayAdapter<String>(this@MainActivity, android.R.layout.simple_list_item_1, titles)
|
adapter = ArrayAdapter<String>(this@MainActivity, android.R.layout.simple_list_item_1, titles)
|
||||||
isTextFilterEnabled = true
|
isTextFilterEnabled = true
|
||||||
isScrollbarFadingEnabled = false
|
isScrollbarFadingEnabled = false
|
||||||
onItemClickListener = AdapterView.OnItemClickListener { parent, v, position, id ->
|
onItemClickListener = AdapterView.OnItemClickListener { parent, v, position, id ->
|
||||||
if (validateFields(fields, config.params.size)) {
|
if (validateFields(fields)) {
|
||||||
saveConfig()
|
saveConfig()
|
||||||
startActivity<ProgrammingActivity>(
|
startActivity<ProgrammingActivity>(
|
||||||
"net.thauvin.erik.android.tesremoteprogrammer.models.Params" to config.params,
|
"net.thauvin.erik.android.tesremoteprogrammer.models.Params" to config.params,
|
||||||
|
@ -249,6 +256,7 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
|
||||||
}.lparams(width = matchParent)
|
}.lparams(width = matchParent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
menuInflater.inflate(R.menu.menu_main, menu)
|
menuInflater.inflate(R.menu.menu_main, menu)
|
||||||
|
@ -347,105 +355,203 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
|
||||||
val len = errors.length
|
val len = errors.length
|
||||||
|
|
||||||
with(config) {
|
with(config) {
|
||||||
if (params.name.isBlank()) {
|
// params
|
||||||
|
with(params) {
|
||||||
|
// name
|
||||||
|
if (name.isBlank()) {
|
||||||
errors.append(getString(R.string.validate_missing_param, "name"))
|
errors.append(getString(R.string.validate_missing_param, "name"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.type.isBlank()) {
|
// type
|
||||||
|
if (type.isBlank()) {
|
||||||
errors.append(getString(R.string.validate_missing_param, "type"))
|
errors.append(getString(R.string.validate_missing_param, "type"))
|
||||||
} else if (!Dtmf.isValidType(params.type)) {
|
} else if (!Dtmf.isValidType(type)) {
|
||||||
errors.append(getString(R.string.validate_invalid_param, "type"))
|
errors.append(getString(R.string.validate_invalid_param, "type"))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.size < 1) {
|
// size
|
||||||
|
if (size < 1) {
|
||||||
errors.append(getString(R.string.validate_invalid_param, "size"))
|
errors.append(getString(R.string.validate_invalid_param, "size"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.ack.isBlank()) {
|
// ack
|
||||||
|
if (ack.isBlank()) {
|
||||||
errors.append(getString(R.string.validate_missing_param, "ack"))
|
errors.append(getString(R.string.validate_missing_param, "ack"))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// options
|
||||||
if (opts.size == 0) {
|
if (opts.size == 0) {
|
||||||
errors.append(getString(R.string.validate_missing_opts))
|
errors.append(getString(R.string.validate_missing_opts))
|
||||||
}
|
} else {
|
||||||
|
|
||||||
opts.forEachIndexed { i, option ->
|
opts.forEachIndexed { i, option ->
|
||||||
if (option.fields.size == 0) {
|
// gson will create a null object on trailing comma
|
||||||
errors.append(getString(R.string.validate_missing_fields, i + 1))
|
// see: https://github.com/google/gson/issues/494
|
||||||
|
if (option == null) {
|
||||||
|
errors.append(getString(R.string.validate_syntax_error, "opts[]"))
|
||||||
|
} else {
|
||||||
|
with(option) {
|
||||||
|
// title
|
||||||
|
if (title.isBlank()) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_missing_opts_prop,
|
||||||
|
i + 1,
|
||||||
|
"title"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (option.nosteps && option.nodial) {
|
// nosteps/nodial
|
||||||
errors.append(getString(R.string.validate_invalid_option, i + 1, "nodial/nosteps"))
|
if (nosteps && nodial) {
|
||||||
}
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_option,
|
||||||
if (option.dtmf.isBlank()) {
|
i + 1,
|
||||||
errors.append(getString(R.string.validate_invalid_dtmf, i + 1, "''"))
|
"nodial/nosteps"))
|
||||||
}
|
|
||||||
|
|
||||||
option.fields.forEachIndexed { j, field ->
|
|
||||||
if (field.size <= 0) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1,
|
|
||||||
"size=${field.size}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field.digits.isNotBlank() && !field.digits.isDigits()) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1, "digits"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field.minSize >= 0 && field.minSize > field.size) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1,
|
|
||||||
"minSize=${field.minSize}/size-${field.size}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!field.alpha) {
|
|
||||||
if (field.minSize == 0) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1,
|
|
||||||
"minSize=${field.minSize}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field.min >= 0 || field.max >= 0) {
|
|
||||||
if (field.max < 1) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1,
|
|
||||||
"max=${field.max}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field.min < 0) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1,
|
|
||||||
"min=${field.min}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field.min > field.max) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1,
|
|
||||||
"min=${field.min}/max=${field.max}"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!params.type.isDKS() && !field.zeros) {
|
|
||||||
if (field.min > 0 && field.minSize > 0) {
|
|
||||||
if (field.min.toString().length != field.minSize) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1,
|
|
||||||
"minSize=${field.minSize}/min=${field.min}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (field.size > 0 && field.max > 0) {
|
|
||||||
if (field.max.toString().length != field.size) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_attr, i + 1, j + 1,
|
|
||||||
"size=${field.size}/max=${field.max}"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!option.dtmf.contains(Dtmf.DTMF_FIELD.format(j + 1))) {
|
|
||||||
errors.append(getString(R.string.validate_unused_field, i + 1, j + 1))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dtmf
|
||||||
|
if (dtmf.isBlank()) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_missing_opts_prop,
|
||||||
|
i + 1,
|
||||||
|
"dtmf"))
|
||||||
|
} else if (fields.size == 0) { // fields missing
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_missing_opts_prop,
|
||||||
|
i + 1,
|
||||||
|
"fields"))
|
||||||
|
} else {
|
||||||
val blank = "\\0"
|
val blank = "\\0"
|
||||||
val dtmf = Dtmf.mock(option, blank)
|
val mock = Dtmf.mock(option, blank)
|
||||||
if (!Dtmf.validate(dtmf, "${MainActivity.Companion.PAUSE}${params.ack}${params.alt}$blank")) {
|
|
||||||
errors.append(getString(R.string.validate_invalid_dtmf, i + 1, dtmf.replace(blank, "✓")))
|
if (!Dtmf.validate(mock,
|
||||||
|
"${MainActivity.PAUSE}${params.ack}${params.alt}$blank")) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_opts_prop,
|
||||||
|
i + 1,
|
||||||
|
"dtmf",
|
||||||
|
mock.replace(blank, "✓")))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fields
|
||||||
|
fields.forEachIndexed { j, field ->
|
||||||
|
if (field == null) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_syntax_error,
|
||||||
|
"opts[${i+j}], field[$j]"))
|
||||||
|
} else {
|
||||||
|
with(field) {
|
||||||
|
// size
|
||||||
|
if (size <= 0) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 1),
|
||||||
|
"size=$size"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// digits
|
||||||
|
if (digits.isNotBlank() && !digits.isDigits()) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 1),
|
||||||
|
"digits='$digits'"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// minSize
|
||||||
|
if (minSize >= 0 && minSize > size) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 2),
|
||||||
|
"minSize=$minSize > size=$size"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// numeric fields only
|
||||||
|
if (!alpha) {
|
||||||
|
if (minSize == 0) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 1),
|
||||||
|
"minSize=$minSize"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// min/max
|
||||||
|
if (min >= 0 || max >= 0) {
|
||||||
|
if (max < 1) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 1),
|
||||||
|
"max=$max"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min < 0) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 1),
|
||||||
|
"min=$min"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (min > max) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 2),
|
||||||
|
"min=$min > max=$max"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no leading zeros
|
||||||
|
if (!params.type.isDKS() && !zeros) {
|
||||||
|
// minSize/min
|
||||||
|
if (min >= 0 && minSize > 0) {
|
||||||
|
if (min.toString().length != minSize) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 2),
|
||||||
|
"minSize=$minSize/min=$min"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// size/max
|
||||||
|
if (size > 0 && max > 0) {
|
||||||
|
if (max.toString().length != size) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_invalid_field_prop,
|
||||||
|
i + 1,
|
||||||
|
j + 1,
|
||||||
|
resources.getQuantityString(R.plurals.error_prop, 2),
|
||||||
|
"size=$size/max=$max"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unused fields
|
||||||
|
if (!dtmf.contains(Dtmf.DTMF_FIELD.format(j + 1))) {
|
||||||
|
errors.append(getString(
|
||||||
|
R.string.validate_unused_field,
|
||||||
|
i + 1,
|
||||||
|
j + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -453,17 +559,19 @@ class MainActivity : AppCompatActivity(), AnkoLogger {
|
||||||
return errors.length == len
|
return errors.length == len
|
||||||
}
|
}
|
||||||
|
|
||||||
fun validateFields(fields: ArrayList<EditText>, size: Int): Boolean {
|
fun validateFields(fields: ArrayList<Pair<EditText, Int>>): Boolean {
|
||||||
var isValid = true
|
var isValid = true
|
||||||
|
|
||||||
fields.forEach {
|
fields.forEach {
|
||||||
if (it.text.isNullOrBlank()) {
|
with(it) {
|
||||||
it.error = getString(R.string.error_required)
|
if (first.text.isNullOrBlank()) {
|
||||||
|
first.error = getString(R.string.error_required)
|
||||||
isValid = false
|
isValid = false
|
||||||
} else if (size > 0 && (fields[1].text.length != size)) {
|
} else if (second > 0 && first.text.length != second) {
|
||||||
|
first.error = getString(R.string.error_invalid_size, second,
|
||||||
|
resources.getQuantityString(R.plurals.error_digit, second), "")
|
||||||
isValid = false
|
isValid = false
|
||||||
fields[1].error = getString(R.string.error_invalid_size, size,
|
}
|
||||||
resources.getQuantityString(R.plurals.error_digit, size), "")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import android.os.Parcelable
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
|
|
||||||
data class Option(var title: String,
|
data class Option(var title: String,
|
||||||
var fields: List<Field>,
|
var fields: List<Field?>,
|
||||||
var nodial: Boolean,
|
var nodial: Boolean,
|
||||||
var nosteps: Boolean,
|
var nosteps: Boolean,
|
||||||
var dtmf: String) : Parcelable, Serializable, Comparable<Option> {
|
var dtmf: String) : Parcelable, Serializable, Comparable<Option> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue