Skip to content

Instantly share code, notes, and snippets.

View afollestad's full-sized avatar
📱

Aidan Follestad afollestad

📱
View GitHub Profile
@afollestad
afollestad / ViewLifecycleOwner.kt
Created December 14, 2018 18:49
Create a lifecycle owner for a view without any boiler plate
import android.view.View
import android.view.View.OnAttachStateChangeListener
import androidx.lifecycle.LifecycleOwner
/** @author Aidan Follestad (@afollestad) */
class ViewLifecycleOwner(view: View) : LifecycleOwner, OnAttachStateChangeListener {
private val lifecycle = SimpleLifecycle(this)
init {
@afollestad
afollestad / BroadcastReceiver.kt
Last active January 14, 2024 10:23
A Lifecycle components aware BroadcastReceiver DSL (Kotlin)
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
import androidx.lifecycle.Lifecycle.Event.ON_START
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import android.content.BroadcastReceiver as StockReceiver
@afollestad
afollestad / ViewExt.kt
Last active March 2, 2022 21:02
Some simple Kotlin view extensions
import android.view.View
import android.view.View.GONE
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.view.ViewTreeObserver
import android.widget.AdapterView
import android.widget.Spinner
fun View.show() {
visibility = VISIBLE
@afollestad
afollestad / TestLiveData.kt
Created December 7, 2018 07:00
Observe LiveData in a test like you can with Rx test subscribers.
/** @author Aidan Follestad (@afollestad) */
class TestLiveData<T>(data: LiveData<T>) {
private val receivedValues = mutableListOf<T>()
private val observer = Observer<T> { emission ->
emission?.let { receivedValues.add(it) }
}
init {
data.observeForever(observer)
@afollestad
afollestad / LiveDataDistinct.kt
Created December 7, 2018 06:59
Similar to an Rx operator. Filters out same-values from LiveData streams.
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Observer
/** @author Aidan Follestad (@afollestad) */
class DistinctLiveData<T>(source1: LiveData<T>) : MediatorLiveData<T>() {
private var isInitialized = false
private var lastValue: T? = null
@afollestad
afollestad / LiveDataZip.kt
Created December 7, 2018 06:55
Merge two live data into one
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Observer
typealias Zipper<T, K, R> = (T, K) -> R
/** @author Aidan Follestad (@afollestad) */
class ZipLiveData<T, K, R>(
source1: LiveData<T>,
source2: LiveData<K>,
import android.view.View
import android.view.ViewTreeObserver
fun View.onLayout(cb: () -> Unit) {
if (this.viewTreeObserver.isAlive) {
this.viewTreeObserver.addOnGlobalLayoutListener(
object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
cb()
this@onLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
import kotlin.math.ceil
const val SECOND: Long = 1000
const val MINUTE = SECOND * 60
const val HOUR = MINUTE * 60
const val DAY = HOUR * 24
const val WEEK = DAY * 7
const val MONTH = WEEK * 4
fun Long.timeString() = when {
import android.view.View
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
fun View.scopeWhileAttached(
context: CoroutineContext,
exec: CoroutineScope.() -> Unit
) {
val job = Job(context[Job])
import android.content.ContentValues
/**
* Returns a [ContentValues] instance which contains only values that have changed between
* the receiver (original) and parameter (new) instances.
*/
fun ContentValues.diffFrom(contentValues: ContentValues): ContentValues {
val diff = ContentValues()
for ((name, oldValue) in this.valueSet()) {
val newValue = contentValues.get(name)