Skip to content

Instantly share code, notes, and snippets.

View KSPExtensions.kt
import com.google.devtools.ksp.getClassDeclarationByName
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.*
/**
* Reified function to check if receiver [KSType] is assignable from [T] class
*/
inline fun <reified T> KSType.isAssignableFrom(resolver: Resolver): Boolean {
val classDeclaration = requireNotNull(resolver.getClassDeclarationByName<T>()) {
"Unable to resolve ${KSClassDeclaration::class.simpleName} for type ${T::class.simpleName}"
@NikolaDespotoski
NikolaDespotoski / RegisterForActivityResultDetector.kt
Last active Nov 2, 2020
RegisterForActivityResultDetector LINT detector that warns on incorrect usage of registerForActivityResult
View RegisterForActivityResultDetector.kt
/*
* Copyright (C) 2020 Nikola Despotoski
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
@NikolaDespotoski
NikolaDespotoski / FlowIterable.kt
Last active Oct 5, 2020
Filter items from Iterable with Flow
View FlowIterable.kt
suspend fun <T, R : Iterable<T>> Flow<Iterable<T>>.filterIterable(predicate: suspend (T) -> Boolean): Flow<R> =
transform {
flow {
val emitted = arrayListOf<T>()
for (item in it) {
if (predicate(item)) {
emitted.add(item)
}
}
emit(emitted)
@NikolaDespotoski
NikolaDespotoski / TaskKt.kt
Created Sep 8, 2020
Await Google Play Services Task in coroutine
View TaskKt.kt
suspend fun <TResult> Task<TResult>.awaitTask() =
suspendCancellableCoroutine<Task<TResult>> { continuation ->
addOnCompleteListener {
continuation.resume(it)
}
}
suspend fun <TResult> Task<TResult>.awaitTaskResult() =
suspendCancellableCoroutine<TResult> { continuation ->
addOnCanceledListener {
@NikolaDespotoski
NikolaDespotoski / AnimationKtx.kt
Last active Sep 8, 2020
Extensions for Android Animation package.
View AnimationKtx.kt
data class AnimationListenerChain(val animation: Animation, val listener: Animation.AnimationListener = object : Animation.AnimationListener() {
override fun onAnimationStart(animation: Animation?) {}
override fun onAnimationEnd(animation: Animation?) {}
override fun onAnimationRepeat(animation: Animation?) {}
})
inline fun Animation.doOnStart(crossinline onStart: () -> Unit): AnimationListenerChain {
val chain = AnimationListenerChain(this)
@NikolaDespotoski
NikolaDespotoski / ChainActivityResultCallback.kt
Created Jul 22, 2020
Chain activity result callbacks using plus operator
View ChainActivityResultCallback.kt
operator fun <O> ActivityResultCallback<O>.plus(another: ActivityResultCallback<O>) = ActivityResultCallback<O> {
this@plus.onActivityResult(it)
another.onActivityResult(it)
}
View SuspendingFragmentAwait.kt
suspend fun <F : Fragment> FragmentManager.awaitFragmentById(idRes: Int) =
suspendCancellableCoroutine<F> {
val backStackListener = object : FragmentManager.OnBackStackChangedListener {
override fun onBackStackChanged() {
val f = findFragmentById(idRes) as F?
if (f != null) {
removeOnBackStackChangedListener(this)
it.resume(f)
}
}
View SuspendingBleScanner.kt
object SuspendingBleScanner {
suspend fun BluetoothLeScanner.startScan(timeout: Long, scanFilters: List<ScanFilter>? = null, settings: ScanSettings? = null): List<ScanResult> {
check(timeout <= 0L) { "BLE scan timeout must be > 0" }
var scanCallback: ScanCallback? = null
val accumulator = mutableListOf<ScanResult>()
return try {
withTimeout(timeout) {
suspendCancellableCoroutine<List<ScanResult>> { continuation ->
scanCallback = object : ScanCallback() {
View PrepareCall.kt
fun <I, O> prepareCall(activityResultContractor: ActivityResultContractor<I, O>,activityResultCallback: ActivityResultCallback<O>)
: ActivityResultLauncher<I> = prepareCall(object : ActivityResultContract<I, O>() {
override fun createIntent(input: I): Intent = activityResultContractor.createIntent(input)
override fun parseResult(resultCode: Int, intent: Intent?): O = activityResultContractor.parseResult(resultCode, intent)
}, activityResultCallback)
}
View ProductsViewModel.kt
class ProductsViewModel @Inject constructor(
 private val activityResultContractor: ActivityResultContractor<Nothing, String>,
  private val coroutineProvider: CoroutineProvider,
 private val productInteractor: ProductInteractor
) : ViewModel(), ActivityResultCallback<String>,
 ActivityResultContractor<Unit, String> by activityResultContractor{
override fun onActivityResult(result: String?) {
 // do something with the result
 }