Skip to content

Instantly share code, notes, and snippets.

@projectdelta6
Last active June 30, 2021 15:51
Show Gist options
  • Save projectdelta6/bcfe1ff9292e7c9cd5dac789e399da1b to your computer and use it in GitHub Desktop.
Save projectdelta6/bcfe1ff9292e7c9cd5dac789e399da1b to your computer and use it in GitHub Desktop.
Android kotlin common extensions
/**
* Home for useful extension functions.
*/
//package ...
import android.content.Context
import android.content.Intent
import android.text.Editable
import android.text.Spannable
import android.text.SpannableString
import android.text.TextWatcher
import android.text.style.ForegroundColorSpan
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.appcompat.app.ActionBar
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch
/**
* Validates that the [String] is [isNotBlank][String.isNotBlank] and that it matches our email regex
*/
fun String.isValidEmail(): Boolean = (!isNullOrBlank()) && android.util.Patterns.EMAIL_ADDRESS.matcher(this).matches()
fun Intent.getStringExtra(name: String, defaultValue: String): String = getStringExtra(name) ?: defaultValue
/**
* Convenience Coroutine onClickListener.
*
* Avoid some boilerplate
*/
fun View.setOnClickCoroutine(owner: LifecycleOwner, listener: suspend (view: View) -> Unit) {
this.setOnClickListener { owner.lifecycleScope.launch { listener(it) } }
}
fun Context.getInputMethodManager(): InputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
fun View.showSoftInput() {
val imm = context.getInputMethodManager()
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
}
fun View.hideSoftInput() {
val imm = context.getInputMethodManager()
imm.hideSoftInputFromWindow(windowToken, 0)
}
fun View.visible() {
if (visibility != View.VISIBLE) {
visibility = View.VISIBLE
}
}
fun View.invisible() {
if (visibility != View.INVISIBLE) {
visibility = View.INVISIBLE
}
}
fun View.gone() {
if (visibility != View.GONE) {
visibility = View.GONE
}
}
fun ActionBar.setTitleColor(color: Int) {
val text = SpannableString(title ?: "")
text.setSpan(ForegroundColorSpan(color), 0, text.length, Spannable.SPAN_INCLUSIVE_INCLUSIVE)
title = text
}
fun Boolean?.asInt(): Int {
return if (true == this) 1 else 0
}
/**
* Listen for the IME Option Search event and keyboard Enter key
*
* @param onSearch Callback when Search event triggered, return true if consumed, false otherwise
*/
fun EditText.onIMESearch(onSearch: () -> Boolean) {
setOnEditorActionListener { v, actionId, event ->
val doAction: Boolean = when (actionId) {
EditorInfo.IME_ACTION_SEARCH -> true
else -> {
when (event.action) {
KeyEvent.ACTION_UP -> {
when (event.keyCode) {
KeyEvent.KEYCODE_ENTER,
KeyEvent.KEYCODE_NUMPAD_ENTER -> true
else -> false
}
}
else -> false
}
}
}
if (doAction) {
onSearch.invoke()
} else {
false
}
}
}
/**
* Listen for the IME Option Search event and keyboard Enter key
*
* @param onDone Callback when Search event triggered, return true if consumed, false otherwise
*/
fun EditText.onIMEDone(onDone: () -> Boolean) {
setOnEditorActionListener { v, actionId, event ->
val doAction: Boolean = when (actionId) {
EditorInfo.IME_ACTION_DONE -> true
else -> {
when (event.action) {
KeyEvent.ACTION_UP -> {
when (event.keyCode) {
KeyEvent.KEYCODE_ENTER,
KeyEvent.KEYCODE_NUMPAD_ENTER -> true
else -> false
}
}
else -> false
}
}
}
if (doAction) {
onDone.invoke()
} else {
false
}
}
}
fun <T> MutableList<T>.swap(index1: Int, index2: Int) {
val tmp = this[index1]
this[index1] = this[index2]
this[index2] = tmp
}
private operator fun ActivityResult.component1(): Int {
return resultCode
}
private operator fun ActivityResult.component2(): Intent? {
return data
}
fun Context.dpToPx(dp: Int): Float
= dpToPx(dp.toFloat())
fun Context.dpToPx(dp: Float): Float
= TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, resources.displayMetrics)
//------------------------------------------------------------------------------
///Firebase Auth Extensions
import com.google.android.gms.tasks.Task
import com.google.firebase.auth.AuthCredential
import com.google.firebase.auth.AuthResult
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
/**
* Suspend version of the [FirebaseUser.getIdToken] method.
*
* @param forceRefresh force refreshes the token. Should only be set to true if the token
* is invalidated out of band.
*/
suspend fun FirebaseUser.getIdTokenNow(forceRefresh: Boolean = false): String? {
return suspendCoroutine { continuation ->
this.getIdToken(forceRefresh).addOnCompleteListener { task ->
continuation.resume(task.result?.token)
}
}
}
suspend fun FirebaseAuth.suspendSignInWithEmailAndPassword(email: String, password: String): Task<AuthResult> {
return suspendCoroutine { continuation ->
signInWithEmailAndPassword(email, password).addOnCompleteListener { task ->
continuation.resume(task)
}
}
}
suspend fun FirebaseAuth.suspendCreateUserWithEmailAndPassword(email: String, password: String): Task<AuthResult> {
return suspendCoroutine { continuation ->
createUserWithEmailAndPassword(email, password).addOnCompleteListener { task ->
continuation.resume(task)
}
}
}
suspend fun FirebaseAuth.suspendSignInWithCredential(credential: AuthCredential): Task<AuthResult> {
return suspendCoroutine { continuation ->
signInWithCredential(credential).addOnCompleteListener { task ->
continuation.resume(task)
}
}
}
suspend fun FirebaseUser.suspendLinkWithCredential(credential: AuthCredential): Task<AuthResult> {
return suspendCoroutine { continuation ->
linkWithCredential(credential).addOnCompleteListener { task ->
continuation.resume(task)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment