/*
 * Copyright 2019 Louis Cognault Ayeva Derman. Use of this source code is governed by the Apache 2.0 license.
 */
package splitties.lifecycle.coroutines

import androidx.lifecycle.GenericLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.*
import kotlin.coroutines.resume

/**
 * This function returns/resumes as soon as the state of this [Lifecycle] is at least the
 * passed [state].
 *
 * [Lifecycle.State.DESTROYED] is forbidden, to avoid leaks.
 */
@PotentialFutureAndroidXLifecycleKtxApi
@UseExperimental(ExperimentalCoroutinesApi::class)
suspend fun Lifecycle.awaitState(state: Lifecycle.State) {
    require(state != Lifecycle.State.DESTROYED) {
        "DESTROYED is a terminal state that is forbidden for awaitState(…), to avoid leaks."
    }
    if (currentState >= state) return // Fast path
    @UseExperimental(MainDispatcherPerformanceIssueWorkaround::class)
    withContext(Dispatchers.MainAndroid.immediate) {
        if (currentState == Lifecycle.State.DESTROYED) { // Fast path to cancellation
            cancel()
        } else suspendCancellableCoroutine<Unit> { c ->
            val observer = object : GenericLifecycleObserver {
                override fun onStateChanged(source: LifecycleOwner?, event: Lifecycle.Event) {
                    if (currentState >= state) {
                        removeObserver(this)
                        c.resume(Unit)
                    } else if (currentState == Lifecycle.State.DESTROYED) {
                        c.cancel()
                    }
                }
            }
            addObserver(observer)
            c.invokeOnCancellation { removeObserver(observer) }
        }
    }
}

/*
 * Copyright 2019 Louis Cognault Ayeva Derman. Use of this source code is governed by the Apache 2.0 license.
 */
package splitties.lifecycle.coroutines

import androidx.lifecycle.GenericLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import kotlinx.coroutines.*
import kotlin.coroutines.resume

/**
 * This function returns/resumes as soon as the state of this [Lifecycle] is at least the
 * passed [state].
 *
 * [Lifecycle.State.DESTROYED] is forbidden, to avoid leaks.
 */
@PotentialFutureAndroidXLifecycleKtxApi
suspend fun Lifecycle.awaitState(state: Lifecycle.State) {
    require(state != Lifecycle.State.DESTROYED) {
        "DESTROYED is a terminal state that is forbidden for awaitState(…), to avoid leaks."
    }
    if (currentState >= state) return // Fast path
    @UseExperimental(MainDispatcherPerformanceIssueWorkaround::class)
    withContext(Dispatchers.MainAndroid.immediate) {
        if (currentState == Lifecycle.State.DESTROYED) { // Fast path to cancellation
            cancel()
        } else suspendCancellableCoroutine<Unit> { c ->
            val observer = object : GenericLifecycleObserver {
                override fun onStateChanged(source: LifecycleOwner?, event: Lifecycle.Event) {
                    if (currentState >= state) {
                        removeObserver(this)
                        c.resume(Unit)
                    } else if (currentState == Lifecycle.State.DESTROYED) {
                        c.cancel()
                    }
                }
            }
            addObserver(observer)
            c.invokeOnCancellation { removeObserver(observer) }
        }
    }
}

Remove no longer needed experimental annotation
Remove no longer needed experimental annotation

LouisCAD/Splitties,LouisCAD/Splitties,LouisCAD/Splitties