Skip to content

Instantly share code, notes, and snippets.

@SerggioC
Created September 6, 2022 16:34
Show Gist options
  • Save SerggioC/0de52b67341ea523bfc49c027a270ed7 to your computer and use it in GitHub Desktop.
Save SerggioC/0de52b67341ea523bfc49c027a270ed7 to your computer and use it in GitHub Desktop.
IPEditText
import android.content.Context
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.EditText
import android.widget.LinearLayout
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import pt.zonesoft.pdacheckout2.R
class IPEditText(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
private val mFirstIP: EditText
private val mSecondIP: BackPressEditText
private val mThirdIP: BackPressEditText
private val mFourthIP: BackPressEditText
private val mPort: EditText
private var class1: Short = 0
private var class2: Short = 0
private var class3: Short = 0
private var class4: Short = 0
private var port: Int = 0
init {
val view = LayoutInflater.from(context).inflate(R.layout.custom_ip_port_edittext, this)
mFirstIP = view.findViewById(R.id.ip_first)
mSecondIP = view.findViewById(R.id.ip_second)
mThirdIP = view.findViewById(R.id.ip_third)
mFourthIP = view.findViewById(R.id.ip_fourth)
mPort = view.findViewById(R.id.port)
operatingEditText()
}
private val scope: CoroutineScope = CoroutineScope(Dispatchers.Main)
fun EditText.temporaryError(error: String) {
scope.launch {
[email protected] = error
delay(3000)
[email protected] = null
}
}
interface TextWatch : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable) {}
}
private fun operatingEditText() {
mFirstIP.addTextChangedListener(object : TextWatch {
private var previous: String = ""
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
super.beforeTextChanged(s, start, count, after)
previous = s.toString()
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (s.isNotEmpty()) {
val typed = s.toString().trim()
class1 = if (typed.contains(".")) {
typed.dropLast(1).toShortOrNull() ?: 0
} else {
typed.toShortOrNull() ?: 0
}
changeText(class1.toString())
if (class1 < 0 || class1 > 255) {
mFirstIP.temporaryError("Invalid $class1")
changeText(previous)
return
}
if (typed.contains(".") || typed.contains(".").not() && typed.length >= 3 || class1 > 25) {
mSecondIP.isFocusable = true
mSecondIP.requestFocus()
}
}
}
private fun changeText(text: String) {
mFirstIP.removeTextChangedListener(this)
mFirstIP.setText(text)
mFirstIP.setSelection(text.length)
mFirstIP.addTextChangedListener(this)
}
})
mSecondIP.deleteListener = object : InputInterface {
override fun onDeleteKeyPressed() {
mFirstIP.isFocusable = true
mFirstIP.requestFocus()
}
}
mSecondIP.addTextChangedListener(object : TextWatch {
private var previous: String = ""
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
super.beforeTextChanged(s, start, count, after)
previous = s.toString()
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (s.isNotEmpty()) {
val typed = s.toString().trim()
class2 = if (typed.contains(".")) {
typed.dropLast(1).toShortOrNull() ?: 0
} else {
typed.toShortOrNull() ?: 0
}
changeText(class2.toString())
if (class2 < 0 || class2 > 255) {
mSecondIP.temporaryError("Invalid $class2")
changeText(previous)
return
}
if (typed.contains(".") || typed.contains(".").not() && typed.length >= 3 || class2 > 25) {
mThirdIP.isFocusable = true
mThirdIP.requestFocus()
}
}
}
private fun changeText(text: String) {
mSecondIP.removeTextChangedListener(this)
mSecondIP.setText(text)
mSecondIP.setSelection(text.length)
mSecondIP.addTextChangedListener(this)
}
})
mThirdIP.deleteListener = object : InputInterface {
override fun onDeleteKeyPressed() {
mSecondIP.isFocusable = true
mSecondIP.requestFocus()
}
}
mThirdIP.addTextChangedListener(object : TextWatch {
private var previous: String = ""
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
super.beforeTextChanged(s, start, count, after)
previous = s.toString()
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (s.isNotEmpty()) {
val typed = s.toString().trim()
class3 = if (typed.contains(".")) {
typed.dropLast(1).toShortOrNull() ?: 0
} else {
typed.toShortOrNull() ?: 0
}
changeText(class3.toString())
if (class3 < 0 || class3 > 255) {
mThirdIP.temporaryError("Invalid $class3")
changeText(previous)
return
}
if (typed.contains(".") || typed.contains(".").not() && typed.length >= 3 || class3 > 25) {
mFourthIP.isFocusable = true
mFourthIP.requestFocus()
}
}
}
private fun changeText(text: String) {
mThirdIP.removeTextChangedListener(this)
mThirdIP.setText(text)
mThirdIP.setSelection(text.length)
mThirdIP.addTextChangedListener(this)
}
})
mFourthIP.deleteListener = object : InputInterface {
override fun onDeleteKeyPressed() {
mThirdIP.isFocusable = true
mThirdIP.requestFocus()
}
}
mFourthIP.addTextChangedListener(object : TextWatch {
private var previous: String = ""
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
super.beforeTextChanged(s, start, count, after)
previous = s.toString()
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (s.isNotEmpty()) {
val typed = s.toString().trim()
class4 = if (typed.contains(".")) {
typed.dropLast(1).toShortOrNull() ?: 0
} else {
typed.toShortOrNull() ?: 0
}
changeText(class4.toString())
if (class4 < 0 || class4 > 255) {
mFourthIP.temporaryError("Invalid $class4")
changeText(previous)
return
}
if (typed.contains(".") || typed.contains(".").not() && typed.length >= 3 || class4 > 25) {
mPort.isFocusable = true
mPort.requestFocus()
}
}
}
private fun changeText(text: String) {
mFourthIP.removeTextChangedListener(this)
mFourthIP.setText(text)
mFourthIP.setSelection(text.length)
mFourthIP.addTextChangedListener(this)
}
})
mPort.addTextChangedListener(object : TextWatch {
private var previous: String = ""
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
super.beforeTextChanged(s, start, count, after)
previous = s.toString()
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
if (s.isNotEmpty()) {
val value = s.toString().trim().toIntOrNull() ?: 0
if (value <= 0 || value > 65535) {
mPort.temporaryError("Invalid $value")
changeText(previous)
}
port = value
}
}
private fun changeText(text: String) {
mPort.removeTextChangedListener(this)
mPort.setText(text)
mPort.setSelection(text.length)
mPort.addTextChangedListener(this)
}
})
}
fun setIPPort(ipPortString: String?, defaultPort: String = "1433") {
val classes: List<String>? = ipPortString?.split(".")
mFirstIP.setText(classes?.getOrNull(0) ?: "")
mSecondIP.setText(classes?.getOrNull(1) ?: "")
mThirdIP.setText(classes?.getOrNull(2) ?: "")
val cp = (classes?.getOrNull(3) ?: "").split(":")
mFourthIP.setText(cp.getOrNull(0) ?: "")
var port = cp.getOrNull(1)
if (port.isNullOrEmpty()) port = defaultPort
mPort.setText(port)
}
fun getIPPort(): String {
return "$class1.$class2.$class3.$class4:$port"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment