package com.tommasoberlose.anotherwidget.utils import android.animation.* import android.content.pm.PackageManager import android.view.View import android.view.ViewAnimationUtils import android.widget.Toast import android.app.Activity import android.app.WallpaperManager import android.content.* import android.net.Uri import androidx.browser.customtabs.CustomTabsIntent import androidx.core.content.ContextCompat import android.content.res.Configuration import android.provider.Settings import android.util.Patterns import java.security.NoSuchAlgorithmException import kotlin.math.max import android.content.Intent import android.content.res.Resources import android.graphics.drawable.Drawable import android.util.DisplayMetrics import android.util.TypedValue import android.view.animation.AlphaAnimation import android.widget.RelativeLayout import androidx.annotation.UiThread import androidx.appcompat.app.AppCompatDelegate import androidx.browser.customtabs.CustomTabColorSchemeParams import androidx.core.animation.addListener import androidx.core.view.isVisible import com.tommasoberlose.anotherwidget.R import com.tommasoberlose.anotherwidget.components.OnSingleClickListener import com.tommasoberlose.anotherwidget.global.Preferences import java.util.* fun PackageManager.missingSystemFeature(name: String): Boolean = !hasSystemFeature(name) fun Context.toast(message: String, long: Boolean = false) { val toast = Toast.makeText(this, message, if (long) Toast.LENGTH_LONG else Toast.LENGTH_SHORT) // toast.setGravity(Gravity.CENTER, 0, 0) toast.show() } fun Int.toPixel(context: Context): Int = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), context.resources.displayMetrics).toInt() fun Float.toPixel(context: Context): Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, context.resources.displayMetrics) fun View.reveal(initialX: Int? = null, initialY: Int? = null) { when (visibility) { View.VISIBLE -> { val anim = ViewAnimationUtils.createCircularReveal(this, initialX ?: this.measuredWidth / 2, initialY ?: this.measuredHeight / 2, max(width.toFloat(), height.toFloat()), 0f) .apply { duration = 200 } anim.addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { visibility = View.GONE super.onAnimationEnd(animation) } }) anim.start() } else -> { val anim = ViewAnimationUtils.createCircularReveal(this, initialX ?: this.measuredWidth / 2, initialY ?: this.measuredHeight / 2, 0f, max(width.toFloat(), height.toFloat())) .apply { duration = 200 } visibility = View.VISIBLE anim.start() } } } fun View.expand(duration: Long = 500L) { clearAnimation() try { val animator = (tag as ValueAnimator) animator.removeAllListeners() animator.cancel() } catch (ex: java.lang.Exception) {} layoutParams = layoutParams.apply { height = RelativeLayout.LayoutParams.WRAP_CONTENT } measure(0, 0) val initialHeight = measuredHeight val anim = ValueAnimator.ofFloat( alpha, 1f ).apply { this.duration = duration addUpdateListener { val animatedValue = animatedValue as Float layoutParams = layoutParams.apply { height = (initialHeight * animatedValue).toInt() } translationY = (initialHeight * animatedValue - initialHeight) alpha = animatedValue } addListener( onStart = { isVisible = true } ) } tag = anim anim.start() } fun View.collapse(duration: Long = 500L) { clearAnimation() try { val animator = (tag as ValueAnimator) animator.removeAllListeners() animator.cancel() } catch (ex: java.lang.Exception) {} val initialHeight = measuredHeight val anim = ValueAnimator.ofFloat( alpha, 0f ).apply { this.duration = duration addUpdateListener { val animatedValue = animatedValue as Float layoutParams = layoutParams.apply { height = (initialHeight * animatedValue).toInt() } translationY = (initialHeight * animatedValue - initialHeight) alpha = animatedValue } addListener( onEnd = { isVisible = false } ) } tag = anim anim.start() } fun Context.openURI(url: String) { try { val builder: CustomTabsIntent.Builder = CustomTabsIntent.Builder() builder.setDefaultColorSchemeParams(CustomTabColorSchemeParams.Builder().setToolbarColor(ContextCompat.getColor(this, R.color.colorPrimary)).build()) val customTabsIntent: CustomTabsIntent = builder.build() customTabsIntent.launchUrl(this, Uri.parse(url)) } catch (e: Exception) { try { val openIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) startActivity(openIntent) } catch (ignored: Exception) { val clipboard: ClipboardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText(getString(R.string.app_name), url) clipboard.setPrimaryClip(clip) Toast.makeText(this, R.string.error_opening_uri, Toast.LENGTH_LONG).show() } } } fun Context.isTablet(): Boolean { return (resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE } fun String.md5(): String { val mD5 = "MD5" try { // Create MD5 Hash val digest = java.security.MessageDigest .getInstance(mD5) digest.update(toByteArray()) val messageDigest = digest.digest() // Create Hex String val hexString = StringBuilder() for (aMessageDigest in messageDigest) { var h = Integer.toHexString(0xFF and aMessageDigest.toInt()) while (h.length < 2) h = "0$h" hexString.append(h) } return hexString.toString() } catch (e: NoSuchAlgorithmException) { e.printStackTrace() } return "" } fun String.isValidEmail(): Boolean = this.isNotEmpty() && Patterns.EMAIL_ADDRESS.matcher(this).matches() fun Context.isDarkTheme(): Boolean { return Preferences.darkThemePreference == AppCompatDelegate.MODE_NIGHT_YES || Preferences.darkThemePreference == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM && resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES } fun Activity.isNotificationAccessGranted(): Boolean = Settings.Secure.getString(this.contentResolver,"enabled_notification_listeners").contains(this.packageName) fun Float.convertDpToPixel(context: Context): Float { val resources: Resources = context.resources val metrics: DisplayMetrics = resources.displayMetrics val px: Float = this * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT) return px } fun Float.convertSpToPixels(context: Context): Float { return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this, context.resources.displayMetrics) } fun Context.checkGrantedPermission(permission: String): Boolean { return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED } fun Context.getCurrentWallpaper(): Drawable? = try { WallpaperManager.getInstance(this).drawable } catch (e: Exception) { null } fun String.getCapWordString(): String { return try { val ar = this.split(" ") var newText = "" for (t: String in ar) { newText += " " newText += t.substring(0, 1).toUpperCase(Locale.getDefault()) newText += t.substring(1) } newText.substring(1) } catch (e: Exception) { this } } fun Context.checkIfFitInstalled(): Boolean { return try { packageManager.getPackageInfo("com.google.android.apps.fitness", PackageManager.GET_ACTIVITIES) true } catch (e: Exception) { false } } fun Intent.isDefaultSet(context: Context): Boolean { val pm = context.packageManager return try { resolveActivity(pm) != null && resolveActivity(pm).packageName.isNotBlank() } catch (ex: java.lang.Exception) { false } } fun Locale.isMetric(): Boolean { return when (country.toUpperCase(this)) { "US", "LR", "MM", "GB" -> false else -> true } } fun View.setOnSingleClickListener(l: View.OnClickListener) { setOnClickListener(OnSingleClickListener(l)) } fun View.setOnSingleClickListener(l: (View) -> Unit) { setOnClickListener(OnSingleClickListener(l)) } fun ignoreExceptions(function: () -> Unit) = run { try { function.invoke() } catch (ex: Exception) { ex.printStackTrace() } }