Kotlin tricks
print(nullableList
.run { // calls methods on 'this', return method's result
toMutableList()
.apply{ add(9)} } // calls methods on 'this' and returns 'this'
.groupBy { it % 3 })
sealed class Payloads {
data class Favorite (var favorited: Boolean): Payloads()
data class Retweet (var retweeted: Boolean): Payloads()
data class CountUpdate (
var favorites: Long,
var retweets: Long,
var replies: Long): Payloads()
}
fun onBindViewHolder() {
payloads.forEach {
when (it) {
is Payloads.Favorite -> { holder.favouriteIcon.isActivated = it.favorited}
// ...
}
}
}
class PaymentRobot {
fun amount(value: Long) { }
fun send() {}
}
fun payment(body: PaymentRobot.() -> Unit) = PaymentRobot().apply(body)
@Test
fun sendMoney() {
payment {
amount(10)
send()
}
}
package ds.wifimagicswitcher.prefs
import android.content.Context
import android.content.SharedPreferences
import ds.wifimagicswitcher.utils.T
import kotlin.properties.ReadWriteProperty
// https://gist.github.com/deviant-studio/85bbd34beffe33372c2d
object KotlinPrefsSetup {
@Volatile var isBatching = false
lateinit var prefs: SharedPreferences
lateinit var edit: SharedPreferences.Editor
/**
* Run it on App start
*/
fun init(ctx: Context, name: String) {
prefs = ctx.getSharedPreferences(name, Context.MODE_PRIVATE)
edit = prefs.edit()
}
}
@Synchronized fun prefsBatch(f: () -> Unit) {
KotlinPrefsSetup.isBatching = true
f()
KotlinPrefsSetup.isBatching = false
KotlinPrefsSetup.edit.apply()
}
fun prefsKey<T>(default: T): PrefsDelegate<T> = PrefsDelegate(default)
class PrefsDelegate<T>(val default: T) : ReadWriteProperty<Any?, T> {
var value: T = default
@Suppress("unchecked_cast")
override fun get(thisRef: Any?, property: PropertyMetadata): T {
val n = property.name
val prefs = KotlinPrefsSetup.prefs
when (value) {
is String -> return prefs.getString(n, default as String) as T
is Int -> return prefs.getInt(n, default as Int) as T
is Long -> return prefs.getLong(n, default as Long) as T
is Float -> return prefs.getFloat(n, default as Float) as T
is Boolean -> return prefs.getBoolean(n, default as Boolean) as T
is Set<*> -> return prefs.getStringSet(n, default as Set<String>) as T
else -> throw IllegalArgumentException()
}
}
@Suppress("unchecked_cast")
override fun set(thisRef: Any?, property: PropertyMetadata, value: T) {
this.value = value
val n = property.name
val e = KotlinPrefsSetup.edit
when (value) {
is String -> e.putString(n, value)
is Int -> e.putInt(n, value)
is Long -> e.putLong(n, value)
is Float -> e.putFloat(n, value)
is Boolean -> e.putBoolean(n, value)
is Set<*> -> e.putStringSet(n, value as Set<String>)
else -> throw IllegalArgumentException()
}
if (!KotlinPrefsSetup.isBatching)
e.apply()
}
}
// Return the set of products that were ordered by every customer
fun Shop.getSetOfProductsOrderedByEveryCustomer(): Set<Product> {
val setOfOrderedProducts = customers.flatMap { it.orders.flatMap { it.products }}.toSet()
// return setOfOrderedProducts.filter { item ->
// customers.all { it.orders.flatMap { it.products }.contains(item) }
// }.toSet()
return customers.fold (setOfOrderedProducts) { orderedByAll, customer ->
orderedByAll.intersect( customer.orders.flatMap { it.products }.toSet() )
}
}
// imageView.loadFrom(url)
// 10.toPx(context)
class LazyProperty(val initializer: () -> Int) {
// val lazy: Int by lazy {
// initializer()
// }
var value: Int? = null
val lazy: Int
get() {
if (value == null) {
value = initializer()
}
return value!!
}
}
@RequiresApi(Build.VERSION_CODES.KITKAT)
class MyListener: Transition.TransitionListener by EmptyTransitionListener {
override fun onTransitionCancel(transition: Transition?) {
}
}
@RequiresApi(Build.VERSION_CODES.KITKAT)
object EmptyTransitionListener: Transition.TransitionListener {
override fun onTransitionEnd(transition: Transition?) { }
override fun onTransitionResume(transition: Transition?) { }
override fun onTransitionPause(transition: Transition?) { }
override fun onTransitionCancel(transition: Transition?) { }
override fun onTransitionStart(transition: Transition?) { }
}
fun usage() {
val views = LinearLayout(activity)
views.forEach { view ->
TODO()
}
val first = views[0]
views -= first
views += first
if (view in views) TODO()
if (BuildConfig.DEBUG) Log.d("Test", ": View count: ${views.size}")
val visibleHeight = views.children()
.filter { it.visibility == View.VISIBLE }
.sumBy { it.measuredHeight }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
val result = trace("foo") {
TODO("expensive calculation")
}
}
}
// note.1: Extension methods will desugar into static method where the view group is a first parameter
// note.2: without inline lambda would cause anonymous class to be created, which would encapsulate everything
// to avoid that - use inline keyword. So method becomes free to use
inline fun ViewGroup.forEach(action: (View) -> Unit) {
for (index in 0 until childCount) {
action(getChildAt(index))
}
}
// Transform our view group into iterable
fun ViewGroup.children() = object: Iterable<View> {
override fun iterator()= object: Iterator<View> {
var index = 0
override fun hasNext() = index < childCount
override fun next() = getChildAt(index++)
}
}
operator fun ViewGroup.get(index: Int): View? = getChildAt(index)
operator fun ViewGroup.minusAssign(child: View?) = removeView(child)
operator fun ViewGroup.plusAssign(child: View?) = addView(child)
operator fun ViewGroup.contains(child: View?) = indexOfChild(child) != -1
val ViewGroup.size: Int
get() = childCount
@RequiresApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
inline fun <T>trace(sectionName: String, body: () -> T): T {
Trace.beginSection(sectionName)
try {
return body()
} finally {
Trace.endSection()
}
}
fun doSomethingToDb(db: SQLiteDatabase) {
db.transaction {
delete("users", "first_name = ?", arrayOf("jake"))
}
}
class UserPersistance(private val db: SQLiteDatabase) {
// property delegation
private val deleteByFirstName by lazy {
db.compileStatement("DELETE FROM users WHERE first_name = ?")
}
fun deleteByFirstName(name: String) {
db.transaction {
deleteByFirstName.bindString(1, name)
deleteByFirstName.execute()
}
}
}
// Lamba with recievers - is kinda lambda extension function
inline fun SQLiteDatabase.transaction(body: SQLiteDatabase.() -> Unit) {
beginTransaction()
try {
body()
setTransactionSuccessful()
} finally {
endTransaction()
}
}
@Suppress("UNCHECKED_CAST")
private fun <T> bindView(id: Int) = object: kotlin.properties.ReadOnlyProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>) = findViewById(id) as T
}