Get the old value of editText with TextWatcher - mvvm

I want to get the old value of editText with the function beforeTextWatcher.
The problem is that when I tried to get this old value, the returned value is always null , Someone ca help me please
val nomTextWatcher: TextWatcher
get() = object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
userUpdateSignup.setNom(s.toString())
}
override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
if(!s.toString().isEmpty())
userUpdateSignup.setNom(s.toString())
}
}

You can't just using a TextWatcher, you have to store value into the class properties and then check it yourself.
private var myFieldValue : String = ""
[...]
val nomTextWatcher: TextWatcher
get() = object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
userUpdateSignup.setNom(s.toString())
}
override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
// Here you can check differences or what you want
if(!s.toString().isEmpty())
userUpdateSignup.setNom(s.toString())
// After text changed, you have to store it
myFieldValue = s.toString()
}
}

Related

'not found' error but the function is defined

Using this class I'm attempting to modify the String parameter of the constructor and convert it to date :
class OrderInstance(var size: Double,
var side: String,
var trade_id: Int,
var price: Double,
var time: java.util.Date,
var code: String) {
def getTime(time: String): java.util.Date = new java.util.Date()
def this(size: String,
side: String,
trade_id: Int,
price: String,
time: String, code: String) = this(size.toDouble: Double,
side: String,
trade_id: Int,
price.toDouble: Double,
getTime(time: String) : java.util.Date, code: String)
// Step 3 - proper signature for `equals`
// Steps 4 thru 7 - implement a `match` expression
override def equals(that: Any): Boolean =
that match {
case that: OrderInstance => {
that.canEqual(this) &&
this.trade_id == that.trade_id
}
case _ => false
}
// Step 1 - proper signature for `canEqual`
// Step 2 - compare `a` to the current class
def canEqual(a: Any) = a.isInstanceOf[OrderInstance]
// Step 8 - implement a corresponding hashCode c=method
override def hashCode: Int = {
val prime = 31
var result = 1
result = prime * result + trade_id;
result = prime * result + (if (code == null) 0 else code.hashCode)
result
}
override def toString = {
String.valueOf(trade_id)
}
}
This line :
def getTime(time: String): java.util.Date = new java.util.Date()
should be called in order to return a date instead of String. But I receive error :
Error:(54, 7) not found: value getTime
getTime(time: String) : java.util.Date, code: String)
This error is reported at run time, not compile time. Have I not defined the function getTime correctly ?
Update :
I've attempted to make more clear what I'm trying to achieve :
class OrderInstance(var size: Double,
var side: String,
var trade_id: Int,
var price: Double,
var time: String,
var code: String){
this(time) = this(OrderInstance.getTime(time))
def this(size: String,
side: String,
trade_id: Int,
price: String,
time: String, code: String) = this(size.toDouble: Double,
side: String,
trade_id: Int,
price.toDouble: Double,
time : String, code: String)
// Step 3 - proper signature for `equals`
// Steps 4 thru 7 - implement a `match` expression
override def equals(that: Any): Boolean =
that match {
case that: OrderInstance => {
that.canEqual(this) &&
this.trade_id == that.trade_id
}
case _ => false
}
// Step 1 - proper signature for `canEqual`
// Step 2 - compare `a` to the current class
def canEqual(a: Any) = a.isInstanceOf[OrderInstance]
// Step 8 - implement a corresponding hashCode c=method
override def hashCode: Int = {
val prime = 31
var result = 1
result = prime * result + trade_id;
result = prime * result + (if (code == null) 0 else code.hashCode)
result
}
override def toString = {
String.valueOf(trade_id)
}
}
object OrderInstance {
def getTime(time: String): java.util.Date = new java.util.Date()
}
new OrderInstance(1.0 , "" , 1 , 1.0 , "2019-09-13T16:27:19.881Z" , "")
This returns error :
Error:(60, 26) OrderInstance does not take parameters
this(time) = this(OrderInstance.getTime(time))
for line
this(time) = this(OrderInstance.getTime(time))
How to update time to be converted to Date instead of String ?
getTime is an instance method, which you're trying to invoke from a constructor, i.e. before the instance has been created. Since getTime doesn't actually use any instance variables, you'll want to place it in a companion object (the scala equivalent of static)
class OrderInstance(
//...
) {
this(string) = this(OrderInstance.getTime(string))
}
object OrderInstance {
def getTime(time: String): java.util.Date = new java.util.Date()
}
Thanks to answer from user user1186491 this works as expected :
class OrderInstance(var time: java.util.Date){
def this(time: String) = this(
OrderInstance.getTime(time))
}
object OrderInstance {
def getTime(time: String): java.util.Date = new java.util.Date()
}
val o = new OrderInstance("2019-09-13T16:27:19.881Z" )
println(o.time)

How to avoid duplicate initializing when adopting protocol?

I know I can do this with super class, but Swift doesn’t support abstract class, and I wanna use protocol instead. However, when there are many property requirements, I find it really hard to avoid duplicate self.xxx = xxx code.. Example:
protocol ManyProperties {
var a: Int { get }
var b: Int { get }
var c: Int { get }
var d: Int { get }
}
struct S: ManyProperties {
let a: Int
let b: Int
let c: Int
let d: Int
init(a: Int, b: Int, c: Int, d: Int) {
self.a = a
self.b = b
self.c = c
self.d = d
}
}
class C: ManyProperties {
let a: Int
let b: Int
let c: Int
let d: Int
// duplicate initializing
init(a: Int, b: Int, c: Int, d: Int) {
self.a = a
self.b = b
self.c = c
self.d = d
}
}
I really want to type something like super.init() and I do not want inheritance. How can I accomplish this?
Structs has a free memberwise initializer, so you don't need to write this kind of init for them:
struct S: ManyProperties {
let a, b, c, d: Int
}
but for the class you have some options:
1- Use base class and inherit from it instead of conforming to protocol:
class ManyPropertiesClass: ManyProperties {
let a: Int
let b: Int
let c: Int
let d: Int
// duplicate initializing
init(a: Int, b: Int, c: Int, d: Int) {
self.a = a
self.b = b
self.c = c
self.d = d
}
}
class C: ManyPropertiesClass {
}
2- Add init inside the protocol, so it forces you to implement it with a little autocompletion help
protocol ManyProperties: class {
var a: Int { get }
var b: Int { get }
var c: Int { get }
var d: Int { get }
init(a: Int, b: Int, c: Int, d: Int)}
}
3- define another initializer inside the protocol and make variables setable so the compiler knows that all properties are initialized. Then you can extend the protocol to have the initializer:
protocol ManyProperties: class {
var a: Int { get set }
var b: Int { get set }
var c: Int { get set }
var d: Int { get set }
init()
}
extension ManyProperties {
init(a: Int, b: Int, c: Int, d: Int) {
self.init()
self.a = a
self.b = b
self.c = c
self.d = d
}
}
class C: ManyProperties {
var a: Int = 0
var b: Int = 0
var c: Int = 0
var d: Int = 0
required init() {}
}

unexpected non-void return value in void function

Below is my code. I'm learning closures. I'm getting an error that my function would not return a value. Can someone help?
func operationOnNumbers(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) {
let result = operation(a, b)
print(result)
return result
}
let addClosure = {(a: Int, b: Int) in
a + b
}
operationOnNumbers(5, 7, operation: addClosure)
Use this modified code as you have missed return type in the function ( -> Int)
func operationOnNumbers(_ a: Int, _ b: Int, operation: (Int, Int) -> Int) -> Int{
let result = operation(a, b)
print(result)
return result
}
let addClosure = {(a: Int, b: Int) in
a + b
}
operationOnNumbers(5, 7, operation: addClosure)

Scala: Function with dynamic contract as argument

I have the following enum.
object Smth extends Enumeration {
class Value(name: String, func: (String, Int) => Boolean) extends super.Val(name)
private def opA(index: Int) : Boolean ={
index > 0
}
private def opB(x: String, index: Int) : Boolean ={
index > 0 && x.length > 0
}
val x = new Value("X", opA) // type mismatch error for opA
val y = new Value("Y", opB)
}
Enum constructor takes as an argument a function, of type (String, Int) => Boolean. Is it possible to create enum constructor in such a way that it will accept functions with 2 distinct contracts, for example:
(String, Int) => Boolean
(Int) => Boolean
I am trying to avoid using default value for argument, in function definition.
This is how I would like to use it.
if(Smth.x.func(0)) { do smth }
else if(Smth.y.func("str", 0)) { do smthElse }
If you just want default value you can do this:
class Value(val name: String, val func: (String, Int) => Boolean) extends super.Val(name) {
def apply(name: String, func: (Int) => Boolean): Value =
new Value(name, (x -> func("default value", x)))
}

How to generalize the round methods

I have the following four methods, using BigDecimal to round a number:
private def round(input: Byte, scale: Int): Byte = {
BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).byteValue()
}
private def round(input: Short, scale: Int): Short = {
BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).shortValue()
}
private def round(input: Int, scale: Int): Int = {
BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).intValue()
}
private def round(input: Long, scale: Int): Long = {
BigDecimal(input).setScale(scale, RoundingMode.HALF_UP).longValue()
}
And plan to generalize it into a single round:
private def round[T](input: Any, scale: Int, f: (BigDecimal) => T): T = {
f(BigDecimal(input.asInstanceOf[T]).setScale(scale, RoundingMode.HALF_UP))
}
and use this round like this:
round[Byte](b, scale, _.byteValue)
round[Short](s, scale, _.shortValue)
But the above generalized round didn't work because BigDecimal.apply cannot apply to T, what am I supposed to do?
You could use the Numeric type class
def round[T](input: T, scale: Int, f: BigDecimal => T)(implicit n: Numeric[T]): T = {
f(BigDecimal(n.toDouble(input)).setScale(scale, RoundingMode.HALF_UP))
}
Which can be used as:
round(5.525, 2, _.doubleValue)
res0: Double = 5.53
round(123456789L, -5, _.longValue)
res1: Long = 123500000
Another way might be to create a BigDecimalConverter type class, which is not as concise but solves the issue of converting to Double (which is not a good idea for a generic function, like Régis Jean-Gilles commented below).
Updated with a fromBigDecimal method to clean up the round function (thanks to Régis Jean-Gilles).
trait BigDecimalConverter[T] {
def toBigDecimal(in: T) : BigDecimal
def fromBigDecimal(bd: BigDecimal) : T
}
object BigDecimalConverter {
implicit object IntToBigDecimal extends BigDecimalConverter[Int] {
def toBigDecimal(in: Int) = BigDecimal(in)
def fromBigDecimal(bd: BigDecimal) = bd.toInt
}
implicit object DoubleToBigDecimal extends BigDecimalConverter[Double] {
def toBigDecimal(in: Double) = BigDecimal(in)
def fromBigDecimal(bd: BigDecimal) = bd.toDouble
}
implicit object LongToBigDecimal extends BigDecimalConverter[Long] {
def toBigDecimal(in: Long) = BigDecimal(in)
def fromBigDecimal(bd: BigDecimal) = bd.toLong
}
implicit object BigDecimalToBigDecimal extends BigDecimalConverter[BigDecimal] {
def toBigDecimal(in: BigDecimal) = in
def fromBigDecimal(bd: BigDecimal) = bd
}
}
def round[T](input: T, scale: Int)(implicit bdc: BigDecimalConverter[T]): T =
bdc.fromBigDecimal(
bdc.toBigDecimal(input).setScale(scale, BigDecimal.RoundingMode.HALF_UP)
)
Which can be correctly used with Double, Long, BigDecimal, ... :
round(10, 1)
round(Long.MaxValue - 1000L, -1)
round(BigDecimal("1234"), -2)