Last active
March 23, 2020 01:42
-
-
Save am3n/93d2491af9c9085ce032d33ccb2b4c94 to your computer and use it in GitHub Desktop.
This file contains 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
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