Skip to content

Instantly share code, notes, and snippets.

@mukandrew
Last active February 27, 2022 04:25
Show Gist options
  • Save mukandrew/6f215791b294901fafab5b5b06f06399 to your computer and use it in GitHub Desktop.
Save mukandrew/6f215791b294901fafab5b5b06f06399 to your computer and use it in GitHub Desktop.
Android Helper Extensions
/**
* To prevent the device to put in sleep after a period of the time
*
* @param enablePreventSleep ON/OFF prevent sleep
*/
internal fun FragmentActivity.setPreventSleep(enablePreventSleep: Boolean) {
if (enablePreventSleep) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
/**
* Selected programmatically the item in the BottomNavigationView
*/
internal fun BottomNavigationView.setSelected(@IdRes id: Int) {
menu.findItem(id)?.run {
selectedItemId = id
isChecked = true
}
}
// region colorByContrast
/**
* @see (https://www.w3.org/TR/AERT/#color-contrast)
* This is an algorithm to resolve a good color for text based on the background color
* If the background color has brightness more than [MIN_DARK_BRIGHTNESS]
* that returns the black color, otherwise returns the WHITE color
*/
private const val RED_VALUE = 299
private const val GREEN_VALUE = 587
private const val BLUE_VALUE = 114
private const val MAGIC_NUMBER = 1000
private const val MIN_DARK_BRIGHTNESS = 130
internal fun Int.getColorByContrast(): Int {
if (android.R.color.transparent == this) return Color.BLACK
val rgb = intArrayOf(Color.red(this), Color.green(this), Color.blue(this))
val brightness = (
(rgb[0].times(RED_VALUE))
.plus((rgb[1].times(GREEN_VALUE)))
.plus((rgb[2].times(BLUE_VALUE)))
).div(MAGIC_NUMBER)
return if (brightness <= MIN_DARK_BRIGHTNESS) Color.WHITE else Color.BLACK
}
// endregion
internal val Context.deviceHeight: Int
get() = resources.displayMetrics.heightPixels
internal val Context.deviceWidth: Int
get() = resources.displayMetrics.widthPixels
private const val STATUS_BAR_HEIGHT_NAME = "status_bar_height"
private const val STATUS_BAR_DEF_TYPE_NAME = "dimen"
private const val STATUS_BAR_DEF_PCKG_NAME = "android"
internal val Context.statusBarHeight: Int
get() {
var resultHeight = resources.getDimensionPixelSize(
R.dimen.default_status_bar_height
)
val statusBarHeightResId = resources.getIdentifier(
"status_bar_height",
"dimen",
"android"
)
if (statusBarHeightResId > 0) {
resultHeight = resources.getDimensionPixelSize(statusBarHeightResId)
}
return resultHeight
}
internal fun Context.openUrlInBrowser(url: String) {
try {
val uri = Uri.parse(url)
val intent = Intent(Intent.ACTION_VIEW, uri)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
} catch (e: Exception) {
}
}
/**
* An extension to add a listener to the back pressed dispatcher from the Activity
*/
internal fun Fragment.addBackPressedListener(callback: OnBackPressedCallback) {
activity?.onBackPressedDispatcher?.addCallback(viewLifecycleOwner, callback)
}
private const val MAIL_TO_VALUE = "mailto:"
/**
* An extension to compose a email for a respective e-mail address
* @param email fill with the address to
*/
internal fun Fragment.sendMail(
email: String,
@StringRes chooserTitleRes: Int
) {
try {
val intent = Intent(Intent.ACTION_SENDTO)
intent.data = Uri.parse(MAIL_TO_VALUE)
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf(email))
requireContext().startActivity(
Intent.createChooser(
intent,
getString(chooserTitleRes)
)
)
} catch (e: Exception) {
Toast.makeText(requireContext(), e.message, Toast.LENGTH_SHORT).show()
}
}
/**
* An extension to close the keyboard,
* creating an workaround when the activity does not have the view with current focus
*/
internal fun Fragment.closeKeyboard() {
val imm =
context?.getSystemService(Context.INPUT_METHOD_SERVICE) as? InputMethodManager ?: return
val view = activity?.currentFocus ?: View(activity).apply {
requestFocus()
}
imm.hideSoftInputFromWindow(view.windowToken, 0)
}
/**
* Hide the SystemUI, that is:
* - NavigationBar
* - StatusBar
*/
internal fun Fragment.hideSystemUI(root: View) {
ViewCompat.getWindowInsetsController(root)?.apply {
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
hide(Type.navigationBars())
hide(Type.statusBars())
}
activity?.window?.apply {
WindowCompat.setDecorFitsSystemWindows(this, true)
}
}
/**
* Show the SystemUI, that is:
* - NavigationBar
* - StatusBar
*/
internal fun Fragment.showSystemUI(root: View) {
ViewCompat.getWindowInsetsController(root)?.apply {
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_BARS_BY_SWIPE
show(Type.navigationBars())
show(Type.statusBars())
}
activity?.window?.apply {
WindowCompat.setDecorFitsSystemWindows(this, true)
}
}
/**
* When there are a lot of nested fragment and needs to get a specific fragment
*/
internal inline fun <reified T : Fragment> Fragment.getParentFragmentByType(): T? {
var parent = parentFragment
while (parent != null && parent !is T) parent = parent.parentFragment
return (parent as? T)
}
/**
* Get the value set in the [setValueToSavedStateInBackStackEntry]
*
* @param removeAfter If you need to remove this value from savedState after get
*/
internal fun <T> Fragment.getValueFromSavedStateInCurrentBackStackEntry(
key: String,
removeAfter: Boolean
): T? {
return findNavController().currentBackStackEntry?.savedStateHandle?.let { savedState ->
savedState.get<T>(key).also { if (removeAfter) savedState.remove<T>(key) }
}
}
/**
* When needs to send value to a back stack fragment
*
* This setter will put the value in the savedState to the backStack navigation entry,
* so you can get this value from any fragment existent in the backStackEntries
*
* @param keyValue a pair with the key value
* @param backStackEntryId The ID for the existent entry in the navigation back stack
*/
internal fun <T> Fragment.setValueToSavedStateInBackStackEntry(
keyValue: Pair<String, T>,
backStackEntryId: Int
) {
findNavController().getBackStackEntry(backStackEntryId).savedStateHandle.set(
keyValue.first,
keyValue.second
)
}
/**
* There is a problem using the plurals and getting the value for 0 quantity
* So, this function resolve this problem using the param zero to return when quantity is 0
*/
internal fun Resources.getQuantityStringZero(
@PluralsRes plurals: Int,
@StringRes zero: Int,
quantity: Int,
param: Int
): String {
if (quantity == 0) return getString(zero)
return getQuantityString(plurals, quantity, param)
}
internal fun View.hideKeyboard() {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(this.windowToken, 0)
}
internal fun View.showKeyboard() {
if (requestFocus()) {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment