Skip to content

Instantly share code, notes, and snippets.

@am3n
Last active March 23, 2020 01:42
Show Gist options
  • Save am3n/93d2491af9c9085ce032d33ccb2b4c94 to your computer and use it in GitHub Desktop.
Save am3n/93d2491af9c9085ce032d33ccb2b4c94 to your computer and use it in GitHub Desktop.
import android.Manifest
import android.annotation.SuppressLint
import android.app.*
import android.content.*
import android.content.pm.PackageManager
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.content.res.ColorStateList
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
import android.graphics.Point
import android.graphics.Typeface
import android.graphics.drawable.Drawable
import android.net.ConnectivityManager
import android.net.NetworkInfo
import android.net.wifi.WifiManager
import android.os.*
import android.provider.Settings
import android.telephony.TelephonyManager
import android.view.KeyEvent
import android.view.View
import android.view.Window
import android.view.WindowManager
import android.view.animation.*
import android.view.inputmethod.InputMethodManager
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.*
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.IconCompat.createWithResource
import androidx.core.view.ViewCompat
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import com.google.android.material.snackbar.Snackbar
import com.jaredrummler.android.device.DeviceName
import ir.dariacard.pos.BuildConfig
import ir.dariacard.pos.R
import java.io.BufferedReader
import java.io.File
import java.lang.Double.isNaN
import java.lang.Integer.parseInt
import java.math.BigDecimal
import java.math.BigInteger
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.collections.HashMap
import kotlin.math.pow
import kotlin.math.sqrt
object AppUtils
//------------------------------------------------------------
val Int.iPx2Dp: Int get() = (this / Resources.getSystem().displayMetrics.density).toInt()
val Int.iDp2Px: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()
val Int.fPx2Dp: Float get() = this / Resources.getSystem().displayMetrics.density
val Int.fDp2Px: Float get() = this * Resources.getSystem().displayMetrics.density
val Float.iPx2Dp: Int get() = (this / Resources.getSystem().displayMetrics.density).toInt()
val Float.iDp2Px: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()
val Float.fPx2Dp: Float get() = this / Resources.getSystem().displayMetrics.density
val Float.fDp2Px: Float get() = this * Resources.getSystem().displayMetrics.density
val Int.bool: Boolean get() = this > 0
fun String?.toBooleanOrNull(): Boolean? {
try {
if (this != null && this != "null" && this != "Null" && this != "NULL")
return this.toBoolean()
} catch (e: Exception) {
}
return null
}
fun String.isNumeric() = toLongOrNull() != null
fun String.isAlphabet() = matches(Regex("[a-zA-Z]+"))
fun String.isAlphabetAndNumber() = matches(Regex("[a-zA-Z0-9]+")) && !isNumeric() && !isAlphabet()
fun String.isPhoneNumber() = isNumeric() &&
((startsWith("09") && length == 11) ||
(startsWith("989") && length == 12) ||
(startsWith("+989") && length == 13))
inline fun <reified T: Any> String.removeNoneNumeric(): Any {
return when (T::class) {
Short::class -> {
return replace(Regex("[^\\d]"), "").toShortOrNull() ?: 0
}
Int::class -> {
return replace(Regex("[^\\d]"), "").toIntOrNull() ?: 0
}
Long::class -> {
return replace(Regex("[^\\d]"), "").toLongOrNull() ?: 0
}
BigInteger::class -> {
return replace(Regex("[^\\d]"), "").toBigIntegerOrNull() ?: 0
}
BigDecimal::class -> {
return replace(Regex("[^\\d]"), "").toBigDecimalOrNull() ?: 0
}
Float::class -> {
return replace(Regex("[^\\d.]"), "").toFloatOrNull() ?: 0
}
Double::class -> {
return replace(Regex("[^\\d.]"), "").toDoubleOrNull() ?: 0
}
else -> 0
}
}
fun String.replaceLast(toReplace: String, replacement: String): String {
val start = this.lastIndexOf(toReplace);
val builder = StringBuilder()
builder.append(this.substring(0, start))
builder.append(replacement)
builder.append(this.substring(start + toReplace.length))
return builder.toString()
}
//-----------------------------------------------------------
class Num2Persian(private val value: Any) {
private val delimiter = " و "
private val zero = "صفر"
private val negative = "منفی "
private val letters: Array<Array<String>> = arrayOf(
arrayOf("", "یک", "دو", "سه", "چهار", "پنج", "شش", "هفت", "هشت", "نه"),
arrayOf("ده", "یازده", "دوازده", "سیزده", "چهارده", "پانزده", "شانزده", "هفده", "هجده", "نوزده", "بیست"),
arrayOf("", "", "بیست", "سی", "چهل", "پنجاه", "شصت", "هفتاد", "هشتاد", "نود"),
arrayOf("", "یکصد", "دویست", "سیصد", "چهارصد", "پانصد", "ششصد", "هفتصد", "هشتصد", "نهصد"),
arrayOf(
"", " هزار", " میلیون", " میلیارد", " بیلیون", " بیلیارد", " تریلیون", " تریلیارد", "کوآدریلیون",
" کادریلیارد", " کوینتیلیون", " کوانتینیارد", " سکستیلیون", " سکستیلیارد", " سپتیلیون", "سپتیلیارد",
" اکتیلیون", " اکتیلیارد", " نانیلیون", " نانیلیارد", " دسیلیون", " دسیلیارد"
)
)
private val decimalSuffixes: Array<String> = arrayOf(
"", "دهم", "صدم", "هزارم", "ده‌هزارم", "صد‌هزارم", "میلیونوم", "ده‌میلیونوم", "صدمیلیونوم", "میلیاردم", "ده‌میلیاردم", "صد‌‌میلیاردم"
)
private fun prepareNumber(num: Any): List<String> {
var out: Any = num
if (out is Number) {
out = out.toString()
}
out = out as String
val numLen = out.length % 3
if (numLen == 1) {
out = "00${out}"
} else if (numLen == 2) {
out = "0${out}"
}
return splitStringBySize(out, 3)
}
private fun splitStringBySize(str: String, size: Int): List<String> {
val split = mutableListOf<String>()
for (i in 0 until (str.length / size)) {
split.add(str.substring(i * size, ((i + 1) * size).coerceAtMost(str.length)))
}
return split
}
private fun threeNumbersToLetter(num: String): String {
if (num == "") {
return ""
}
val parsedInt = parseInt(num)
if (parsedInt < 10) {
return letters[0][parsedInt]
}
if (parsedInt < 20) {
return letters[1][parsedInt - 10]
}
if (parsedInt < 100) {
val one = parsedInt % 10
val ten = (parsedInt - one) / 10
if (one > 0) {
return letters[2][ten] + delimiter + letters[0][one]
}
return letters[2][ten]
}
val one = parsedInt % 10
val hundreds = (parsedInt - (parsedInt % 100)) / 100
val ten = (parsedInt - ((hundreds * 100) + one)) / 10
var out = arrayOf(letters[3][hundreds])
val secondPart = ((ten * 10) + one)
if (secondPart > 0) {
if (secondPart < 10) {
out = out.plus(letters[0][secondPart])
} else if (secondPart <= 20) {
out = out.plus(letters[1][secondPart - 10])
} else {
out = out.plus(letters[2][ten])
if (one > 0) {
out = out.plus(letters[0][one])
}
}
}
return out.joinToString(delimiter)
}
private fun convertDecimalPart(dp: String): String {
var decimalPart = dp.replace(Regex("0*$"), "")
if (decimalPart == "") {
return ""
}
if (decimalPart.length > 11) {
decimalPart = decimalPart.substring(0, 11)
}
return " ممیز " + Num2Persian(decimalPart).get() + " " + decimalSuffixes[decimalPart.length]
}
fun get(): String {
// Clear Non digits
var input = value.toString().replace(Regex("[^\\d.]"), "") // /[^0-9.-]/g
var isNegative = false
val doubleParse = input.toDoubleOrNull() ?: return zero
// return zero if this isn't a valid number
if (isNaN(doubleParse)) {
return zero
}
// check for zero
if (doubleParse == 0.toDouble()){
return zero
}
// set negative flag:true if the number is less than 0
if (doubleParse < 0){
isNegative = true
input = input.replace(Regex("[\\-]"), "")
}
// Declare Parts
var decimalPart = ""
var integerPart = input
val pointIndex = input.indexOf('.')
// Check for float numbers form string and split Int/Dec
if (pointIndex > -1) {
integerPart = input.substring(0, pointIndex)
decimalPart = input.substring(pointIndex + 1, input.length)
}
if (integerPart.length > 66) {
return "خارج از محدوده"
}
// Split to sections
val slicedNumber = prepareNumber(integerPart)
// Fetch Sections and convert
var output = arrayOf<String>()
val splitLen = slicedNumber.size
for (index in 0 until splitLen) {
val sectionTitle = letters[4][splitLen - (index + 1)]
val converted = threeNumbersToLetter(slicedNumber[index])
if (converted !== "") {
output = output.plus(converted + sectionTitle)
}
}
// Convert Decimal part
if (decimalPart.isNotEmpty()) {
decimalPart = convertDecimalPart(decimalPart)
}
return (if(isNegative) negative else "") + output.joinToString(delimiter) + decimalPart
}
}
fun String.persianLetter(): String { return Num2Persian(this).get() }
fun Number.persianLetter(): String { return Num2Persian(this).get() }
//-----------------------------------------------------------
fun Random.nextInt(min: Int, max: Int): Int {
if (min >= max) {
return Random().nextInt()
}
return Random().nextInt((max - min) + 1) + min
}
//-----------------------------------------------------------
val statusBarHeight: Int
get() {
var result = 0
val resourceId = Resources.getSystem().getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = Resources.getSystem().getDimensionPixelSize(resourceId)
}
return result
}
val Context.actionBarHeight: Int
get() {
val styledAttributes = this.theme?.obtainStyledAttributes(intArrayOf(android.R.attr.actionBarSize))
val result = styledAttributes?.getDimension(0, 0f)?.toInt()
styledAttributes?.recycle()
return result ?: 0
}
val navigaionBarHeight: Int
get() {
var navigationBarHeight = 0
val resourceId = Resources.getSystem().getIdentifier("navigation_bar_height", "dimen", "android")
if (resourceId > 0) {
navigationBarHeight = Resources.getSystem().getDimensionPixelSize(resourceId)
}
return navigationBarHeight
}
fun Context.getScreenSize(): Point {
val wm = this.getSystemService(Context.WINDOW_SERVICE) as WindowManager?
val display = wm?.defaultDisplay
val size = Point()
display?.getSize(size)
return size
}
fun Window.hideNavAndStus() {
val flags = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
//View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
//View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
this.decorView.systemUiVisibility = flags
this.decorView.setOnSystemUiVisibilityChangeListener { visibility ->
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
this.decorView.systemUiVisibility = flags
}
}
}
fun Context.havePermission(permission: String): Boolean {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}
fun Context.device(): HashMap<String, String> {
val map = HashMap<String, String>()
map["appVersionCode"] = BuildConfig.VERSION_CODE.toString()
map["appVersionName"] = BuildConfig.VERSION_NAME
map["androidApiLevel"] = Build.VERSION.SDK_INT.toString()
map["deviceImei"] = IMEI
map["deviceModel"] = Build.BRAND
try {
map["deviceModel"] += " : " + DeviceName.getDeviceName()
} catch (e: Exception) {
e.printStackTrace()
}
map["deviceScreenClass"] = "Unknown"
when {
this.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK == Configuration.SCREENLAYOUT_SIZE_LARGE ->
map["deviceScreenClass"] = "Large"
this.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK == Configuration.SCREENLAYOUT_SIZE_NORMAL ->
map["deviceScreenClass"] = "Normal"
this.resources.configuration.screenLayout and Configuration.SCREENLAYOUT_SIZE_MASK == Configuration.SCREENLAYOUT_SIZE_SMALL ->
map["deviceScreenClass"] = "Small"
}
val metrics = this.resources.displayMetrics
val density = metrics.density
map["deviceDpiClass"] = "Unknown"
when {
density <= 0.75f -> map["deviceDpiClass"] = "ldpi"
density <= 1.0f -> map["deviceDpiClass"] = "mdpi"
density <= 1.5f -> map["deviceDpiClass"] = "hdpi"
density <= 2.0f -> map["deviceDpiClass"] = "xhdpi"
density <= 3.0f -> map["deviceDpiClass"] = "xxhdpi"
density <= 4.0f -> map["deviceDpiClass"] = "xxxhdpi"
}
val orientation = this.resources.configuration.orientation
val wm = this.getSystemService(Context.WINDOW_SERVICE) as WindowManager?
val display = wm?.defaultDisplay
val screenSize = Point()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
display?.getRealSize(screenSize)
} else {
display?.getSize(screenSize)
}
val screensizeX = screenSize.x
val screensizeY = screenSize.y
val width = if (orientation == Configuration.ORIENTATION_PORTRAIT) screensizeX else screensizeY
val height = if (orientation == Configuration.ORIENTATION_PORTRAIT) screensizeY else screensizeX
val wi = width.toDouble() / metrics.xdpi.toDouble()
val hi = height.toDouble() / metrics.ydpi.toDouble()
val x = wi.pow(2.0)
val y = hi.pow(2.0)
val screenInches = sqrt(x + y)
map["deviceScreenSize"] = String.format(Locale.US, "%.2f", screenInches)
map["deviceScreenDimensionsDpis"] = (width / density).toInt().toString() + " x " + (height / density).toInt()
map["deviceScreenDimensionsPixels"] = "$width x $height"
return map
}
//------------------------------------------------------------
val Context.ANDROIDID: String @SuppressLint("HardwareIds")
get() {
return Settings.Secure.getString(this.contentResolver, Settings.Secure.ANDROID_ID)
}
val Context.IMEI: String @SuppressLint("MissingPermission", "HardwareIds") get() {
if (this.havePermission(Manifest.permission.READ_PHONE_STATE)) {
try {
val telephonyManager = this.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?
if (telephonyManager!=null)
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
telephonyManager.imei
} else {
telephonyManager.deviceId
}
} catch (e: Exception) {
e.printStackTrace()
}
}
return ""
}
val serialDevice: String @SuppressLint("MissingPermission", "HardwareIds")
get() =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
try {
Build.getSerial()
} catch (t: Throwable) {
Build.SERIAL
}
} else {
Build.SERIAL
}
// FirebaseInstanceId.getInstance().getId(); can return uniqe id
//------------------------------------------------------------
fun onIO(func: () -> Unit) {
Thread(func).start()
}
fun onIO(func: () -> Unit, delay: Long) {
if (delay <= 0)
onIO(func)
else
onUI(
{ onIO(func) },
delay
)
}
private val UI_EXECUTER = Handler(Looper.getMainLooper())
fun onUI(func: () -> Unit) {
UI_EXECUTER.post(func)
}
fun onUI(func: () -> Unit, delay: Long) {
if (delay <= 0)
func.invoke()
else
UI_EXECUTER.postDelayed(func, delay)
}
//------------------------------------------------------------
fun Context.isServiceRunning(serviceClass: Class<*>): Boolean {
val className = serviceClass.name
val manager = activityManager
return manager?.getRunningServices(Integer.MAX_VALUE)?.any { className == it.service.className } ?: false
}
fun Context.showKeyboard() = try {
val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?
imm?.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0)
} catch (e: Exception) {
e.printStackTrace()
}
fun Context.hideKeyboard(view: View?) = try {
val imm = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?
imm?.hideSoftInputFromWindow(view?.windowToken, 0)
} catch (e: Exception) {
e.printStackTrace()
}
fun Context.drawable(@DrawableRes drawableResource: Int): Drawable? = ContextCompat.getDrawable(this, drawableResource)
fun Context.color(@ColorRes color: Int) = ContextCompat.getColor(this, color)
fun Context.string(@StringRes string: Int) = getString(string)
//------------------------------------------------------------
val Context.notificationManager: NotificationManager?
get() = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?
val Context.connectivityManager: ConnectivityManager?
@SuppressLint("ServiceCast")
get() = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
val Context.powerManager: PowerManager?
get() = getSystemService(Context.POWER_SERVICE) as PowerManager?
val Context.activityManager: ActivityManager?
get() = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager?
val Context.wifiManager: WifiManager?
@SuppressLint("ServiceCast")
get() = applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager?
//------------------------------------------------------------
val Context.ssid: String?
get() {
val info = wifiManager?.connectionInfo
return info?.ssid
}
//--------------------------------------------------------------
fun Context.openInBrowser(url: String) {
try {
/* todo: need dependency
val url = Uri.parse(url)
val intent = CustomTabsIntent.Builder()
.setToolbarColor(getResourceColor(R.attr.colorPrimary))
.build()
intent.launchUrl(this, url)*/
} catch (e: Exception) {
toast(e.message)
}
}
//---------------------------------------------------------------
fun Context.minimizeApp() {
val startMain = Intent(Intent.ACTION_MAIN)
startMain.addCategory(Intent.CATEGORY_HOME)
startMain.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(startMain)
}
//--------------------------------------------------------------
/* todo: need dependency
inline fun<reified W : ListenableWorker> Context.enqueueWorker(func: OneTimeWorkRequest.Builder.() -> Unit) {
val builder = OneTimeWorkRequestBuilder<W>()
builder.func()
val workerRequest = builder.build()
WorkManager.getInstance(this.applicationContext).enqueue(workerRequest)
}*/
//--------------------------------------------------------------
object Shortcut {
fun create(activity: Activity, scClass: Class<*>, name: String?) {
if (Build.VERSION.SDK_INT >= 26)
postApi26CreateShortcut(
activity,
scClass,
name
)
else
preApi26CreateShortcut(activity, scClass, name)
}
private fun preApi26CreateShortcut(activity: Activity, scClass: Class<*>, name: String?) {
// Get preference value to check the app run first time.
val appPreferences = activity.getSharedPreferences("def", Context.MODE_PRIVATE)
val isFirstRun = appPreferences.getBoolean("isFirstRun", false)
if (!isFirstRun) { // Create an explict intent it will be used to call Our application by click on the short cut
val shortcutIntent = Intent(activity, scClass)
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val addIntent = Intent()
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent)
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name)
val icon = Intent.ShortcutIconResource.fromContext(activity,
R.mipmap.ic_launcher
)
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, icon)
addIntent.action = "com.android.launcher.action.INSTALL_SHORTCUT"
addIntent.putExtra("duplicate", false)
activity.sendBroadcast(addIntent)
// Set preference as true
val editor: SharedPreferences.Editor = appPreferences.edit()
editor.putBoolean("isFirstRun", true)
editor.apply()
}
}
@SuppressLint("NewApi")
private fun postApi26CreateShortcut(activity: Activity?, scClass: Class<*>, name: String?) {
val sm = activity?.getSystemService(ShortcutManager::class.java)
if (sm != null && sm.isRequestPinShortcutSupported) {
var shortcutExists = false
// We create the shortcut multiple times if given the
// opportunity. If the shortcut exists, put up
// a toast message and exit.
val shortcuts = sm.pinnedShortcuts
for (i in 0 until shortcuts.size) {
shortcutExists = shortcuts[i].id == name
if (shortcutExists)
break
}
if (!shortcutExists) {
// this intent is used to wake up the broadcast receiver.
// I couldn't get createShortcutResultIntent to work but
// just a simple intent as used for a normal broadcast
// intent works fine.
val broadcastIntent = Intent(name)
broadcastIntent.putExtra("msg", "approve");
// wait up to N seconds for user input, then continue
// on assuming user's choice was deny.
val waitFor = WaitFor(activity, 10).execute()
// create an anonymous broadcaster. Unregister when done.
activity.registerReceiver(object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
activity.unregisterReceiver(this)
waitFor.cancel(true)
}
}, IntentFilter(name))
// this is the intent that actually creates the shortcut.
val shortcutIntent = Intent(activity, scClass)
shortcutIntent.action = name
val shortcutInfo = ShortcutInfo
.Builder(activity, name)
.setShortLabel(activity.string(R.string.app_name))
.setIcon(createWithResource(activity,
R.mipmap.ic_launcher
).toIcon(activity))
.setIntent(shortcutIntent)
.build()
val successCallback = PendingIntent.getBroadcast(activity, 99, broadcastIntent, 0)
// Shortcut gets created here.
sm.requestPinShortcut(shortcutInfo, successCallback.intentSender)
}
}
}
class WaitFor(private val activity: Activity?, n: Int) : AsyncTask<Void, Void, Void?>() {
private var waitPeriod: Long = n * 1000L
override fun doInBackground(vararg params: Void?): Void? {
try {
Thread.sleep(waitPeriod)
val bi = Intent(params[0].toString())
bi.putExtra("msg", "deny")
activity?.sendBroadcast(bi)
} catch (ignore: Throwable) {}
return null
}
}
}
//---------------------------------------------------------------
fun Context.toast(@StringRes resource: Int, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, resource, duration).show()
}
fun Context.toast(text: String?, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, text.orEmpty(), duration).show()
}
//----------------------------------------------------------------
fun Context.snack(
view: View?, text: String?, duration: Int = Snackbar.LENGTH_LONG,
@ColorRes textColor: Int = 0, textSizeSp: Float = 0f,
@ColorRes backgroundColor: Int = 0,
actionText: String? = "", @ColorRes actionTextColor: Int = 0, action: () -> Unit = {}
): Snackbar? {
if (view == null || text == null) return null
val snackbar = Snackbar.make(view, text, duration)
if (actionText?.isNotEmpty() == true) {
snackbar.setAction(actionText) { action.invoke() }
snackbar.setActionTextColor(
when {
actionTextColor != 0 -> color(actionTextColor)
else -> color(R.color.colorAccent)
}
)
}
val snackbarView = snackbar.view
if (backgroundColor != 0)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
snackbarView.backgroundTintList = ColorStateList.valueOf(color(backgroundColor))
else
snackbarView.setBackgroundColor(color(backgroundColor))
snackbarView.findViewById<TextView?>(com.google.android.material.R.id.snackbar_text)?.apply {
if (textColor != 0)
setTextColor(color(textColor))
if (textSizeSp != 0f)
textSize = textSizeSp
}
snackbarView.findViewById<TextView?>(com.google.android.material.R.id.snackbar_action)
?.typeface = Typeface.createFromAsset(assets, "fonts/shabnam/fd/Shabnam_Bold_FD.ttf")
ViewCompat.setLayoutDirection(snackbar.view, ViewCompat.LAYOUT_DIRECTION_RTL)
snackbar.show()
return snackbar
}
fun snack(
view: View?, text: String?, duration: Int = Snackbar.LENGTH_LONG,
@ColorInt textColor: Int = 0, textSizeSp: Float = 0f,
@ColorInt backgroundColor: Int = 0,
actionText: String? = "", @ColorInt actionTextColor: Int = 0, action: () -> Unit = {}
): Snackbar? {
if (view == null || text == null) return null
val snackbar = Snackbar.make(view, text, duration)
if (actionText?.isNotEmpty() == true) {
snackbar.setAction(actionText) { action.invoke() }
snackbar.setActionTextColor(
when {
actionTextColor != 0 -> actionTextColor
view.context != null -> view.context?.color(R.color.colorAccent) ?: Color.CYAN
else -> Color.CYAN
}
)
}
val snackbarView = snackbar.view
if (backgroundColor != 0)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
snackbarView.backgroundTintList = ColorStateList.valueOf(backgroundColor)
else
snackbarView.setBackgroundColor(backgroundColor)
snackbarView.findViewById<TextView?>(com.google.android.material.R.id.snackbar_text)?.apply {
if (textColor != 0)
setTextColor(textColor)
if (textSizeSp != 0f)
textSize = textSizeSp
}
snackbarView.findViewById<TextView?>(com.google.android.material.R.id.snackbar_action)
?.typeface = Typeface.createFromAsset(view.context?.assets, "fonts/shabnam/fd/Shabnam_Bold_FD.ttf")
ViewCompat.setLayoutDirection(snackbar.view, ViewCompat.LAYOUT_DIRECTION_RTL)
snackbar.show()
return snackbar
}
//----------------------------------------------------------------
inline fun Context.notification(channelId: String, func: NotificationCompat.Builder.() -> Unit): Notification {
val builder = NotificationCompat.Builder(this, channelId)
builder.func()
return builder.build()
}
//-----------------------------------------------------------------
fun Context.sendLocalBroadcast(intent: Intent) {
LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
}
fun Context.sendLocalBroadcastSync(intent: Intent) {
LocalBroadcastManager.getInstance(this).sendBroadcastSync(intent)
}
//------------------------------------------------------------------
@RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
fun Context.isNetworkConnected(): Boolean {
(this.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?)?.let { cm ->
val activeNetwork: NetworkInfo? = cm.activeNetworkInfo
return activeNetwork != null && activeNetwork.isConnectedOrConnecting
}
return false
}
//--------------------------------------------------------------------
fun ImageView.rotate(start: Boolean) {
this.clearAnimation()
if (start) {
val rotateAnimation = RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, .5f, Animation.RELATIVE_TO_SELF, .5f)
rotateAnimation.interpolator = AccelerateDecelerateInterpolator()
rotateAnimation.fillAfter = true
rotateAnimation.repeatCount = -1
rotateAnimation.duration = 1000
this.startAnimation(rotateAnimation)
}
}
fun ImageView.rotateHide(start: Boolean) {
if (start) {
val rotateAnimation = RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF, .5f, Animation.RELATIVE_TO_SELF, .5f)
rotateAnimation.interpolator = AccelerateDecelerateInterpolator()
rotateAnimation.fillAfter = true
rotateAnimation.repeatCount = -1
rotateAnimation.duration = 1000
val alphaAnimation = AlphaAnimation(0f, 1f)
alphaAnimation.interpolator = AccelerateInterpolator()
alphaAnimation.fillAfter = true
alphaAnimation.duration = 200
alphaAnimation.startOffset = 100
val animatorSet = AnimationSet(false)
animatorSet.addAnimation(rotateAnimation)
animatorSet.addAnimation(alphaAnimation)
animatorSet.fillAfter = true
this.clearAnimation()
this.startAnimation(animatorSet)
} else {
val alphaAnimation = AlphaAnimation(1f, 0f)
alphaAnimation.interpolator = DecelerateInterpolator()
alphaAnimation.fillAfter = true
alphaAnimation.duration = 300
this.clearAnimation()
this.startAnimation(alphaAnimation)
}
}
//--------------------------------------------------------------------
class SafeClickListener(
private var defaultInterval: Int = 1000,
private val onSafeCLick: (View) -> Unit
) : View.OnClickListener {
private var lastTimeClicked: Long = 0
override fun onClick(v: View) {
if (SystemClock.elapsedRealtime() - lastTimeClicked < defaultInterval)
return
lastTimeClicked = SystemClock.elapsedRealtime()
onSafeCLick(v)
}
}
fun View.setSafeOnClickListener(onSafeClick: (View) -> Unit) {
val safeClickListener = SafeClickListener {
onSafeClick(it)
}
setOnClickListener(safeClickListener)
}
//------------------------------------------------------------------------
interface CustomFragment {
fun onBackPressed()
}
fun View.onBackPressed(customFragment: CustomFragment?) {
this.isFocusableInTouchMode = true
this.requestFocus()
this.setOnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_DOWN) {
customFragment?.onBackPressed()
return@setOnKeyListener true
}
return@setOnKeyListener false
}
}
fun View.onBackPressed(callback: () -> Unit) {
this.isFocusableInTouchMode = true
this.requestFocus()
this.setOnKeyListener { _, keyCode, event ->
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_DOWN) {
callback()
return@setOnKeyListener true
}
return@setOnKeyListener false
}
}
//---------------------------------------------------------------------
interface KParcelable : Parcelable {
override fun describeContents() = 0
override fun writeToParcel(dest: Parcel, flags: Int)
}
// Creator factory functions
inline fun <reified T> parcelableCreator(
crossinline create: (Parcel) -> T
) =
object : Parcelable.Creator<T> {
override fun createFromParcel(source: Parcel) = create(source)
override fun newArray(size: Int) = arrayOfNulls<T>(size)
}
inline fun <reified T> parcelableClassLoaderCreator(
crossinline create: (Parcel, ClassLoader) -> T
) =
object : Parcelable.ClassLoaderCreator<T> {
override fun createFromParcel(source: Parcel, loader: ClassLoader) =
create(source, loader)
override fun createFromParcel(source: Parcel) =
createFromParcel(source, T::class.java.classLoader!!)
override fun newArray(size: Int) = arrayOfNulls<T>(size)
}
// Parcel extensions
fun Parcel.readBool() = readInt() != 0
fun Parcel.writeBool(value: Boolean?) = writeInt(if (value==true) 1 else 0)
inline fun <reified T : Enum<T>> Parcel.readEnum() = readString()?.let { enumValueOf<T>(it) }
fun <T : Enum<T>> Parcel.writeEnum(value: T?) = writeString(value?.name)
inline fun <T> Parcel.readNullable(reader: () -> T) = if (readInt() != 0) reader() else null
inline fun <T> Parcel.writeNullable(value: T?, writer: (T) -> Unit) {
if (value != null) {
writeInt(1)
writer(value)
} else {
writeInt(0)
}
}
fun Parcel.readDate() = readNullable { Date(readLong()) }
fun Parcel.writeDate(value: Date?) = writeNullable(value) { writeLong(it.time) }
fun Parcel.readBigInteger() = readNullable { BigInteger(createByteArray()) }
fun Parcel.writeBigInteger(value: BigInteger?) = writeNullable(value) { writeByteArray(it.toByteArray()) }
fun Parcel.readBigDecimal() = readNullable { BigDecimal(BigInteger(createByteArray()), readInt()) }
fun Parcel.writeBigDecimal(value: BigDecimal?) = writeNullable(value) {
writeByteArray(it.unscaledValue().toByteArray())
writeInt(it.scale())
}
fun <T : Parcelable> Parcel.readTypedObjectCompat(c: Parcelable.Creator<T>) = readNullable { c.createFromParcel(this) }
fun <T : Parcelable> Parcel.writeTypedObjectCompat(value: T?, parcelableFlags: Int) = writeNullable(value) { it.writeToParcel(this, parcelableFlags) }
//---------------------------------------------------------------------
val File.sizeInBytes get() = this.length()
val File.sizeInKB get() = this.sizeInBytes / 1024
val File.sizeInMB get() = this.sizeInKB / 1024
//---------------------------------------------------------------------
val BufferedReader.lines: Iterator<String?> get() = object : Iterator<String?> {
var line: String? = this@lines.readLine()
override fun next(): String? {
val lastLine = line
line = this@lines.readLine()
return lastLine
}
override fun hasNext() = line != null
}
//-----------------------------------------------------------------------------------
fun pingGoogle(callback: (Boolean) -> Unit) {
ping(callback, "google.com")
}
fun ping(callback: (Boolean) -> Unit, address: String) {
var myCallback: ((Boolean) -> Unit)? = callback
Thread {
var wait4p = true
onUI({
if (wait4p) {
wait4p = false
myCallback?.invoke(false)
myCallback = null
}
}, 700)
try {
val command = "ping -c 1 $address"
val ret = Runtime.getRuntime().exec(command).waitFor() == 0
wait4p = false
onUI {
myCallback?.invoke(ret)
myCallback = null
}
} catch (t: Throwable) {
onUI {
myCallback?.invoke(false)
myCallback = null
}
t.printStackTrace()
}
}.start()
}
//-----------------------------------------------------------------------------------
fun ipToInt(addr: String): Int {
val addrArray = addr.split("\\.")
var num = 0
for (i in addrArray.indices) {
val power = 3-i
num += (parseInt(addrArray[i]) %256 * 256.0.pow(power.toDouble()).toInt())
}
return num
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment