Last active
June 30, 2021 15:51
-
-
Save projectdelta6/bcfe1ff9292e7c9cd5dac789e399da1b to your computer and use it in GitHub Desktop.
Android kotlin common extensions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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