Reorganize and group modules

This commit is contained in:
MM20
2022-12-13 17:37:26 +01:00
parent bac24baad2
commit 3f8880a90a
995 changed files with 501 additions and 298 deletions
+4
View File
@@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
/
</manifest>
@@ -0,0 +1,11 @@
package de.mm20.launcher2.ktx
import android.location.Address
fun Address.formatToString(
): String {
val sb = StringBuilder()
if (locality != null) sb.append(locality).append(", ")
if (countryCode != null) sb.append(countryCode)
return sb.toString()
}
@@ -0,0 +1,31 @@
package de.mm20.launcher2.ktx
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.core.content.ContextCompat
val Context.dp: Float
get() = resources.displayMetrics.density
val Context.sp: Float
get() = resources.displayMetrics.scaledDensity
fun Context.checkPermission(permission: String): Boolean {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}
fun Context.tryStartActivity(intent: Intent, bundle: Bundle? = null): Boolean {
return try {
startActivity(intent, bundle)
true
} catch (e: ActivityNotFoundException) {
false
} catch (e: SecurityException) {
false
}
}
@@ -0,0 +1,7 @@
package de.mm20.launcher2.ktx
import kotlin.math.ceil
fun Double.ceilToInt(): Int {
return ceil(this).toInt()
}
@@ -0,0 +1,25 @@
package de.mm20.launcher2.ktx
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.ColorFilter
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import androidx.annotation.Px
import androidx.core.graphics.drawable.toBitmap
fun Drawable.toBitmapOrNull(
@Px width: Int = intrinsicWidth,
@Px height: Int = intrinsicHeight,
config: Bitmap.Config? = null
): Bitmap? {
if (this is BitmapDrawable && bitmap == null) return null
return toBitmap(width, height, config)
}
fun Drawable.drawWithColorFilter(canvas: Canvas, colorFilter: ColorFilter?) {
val cf = this.colorFilter
this.colorFilter = colorFilter
this.draw(canvas)
this.colorFilter = cf
}
@@ -0,0 +1,36 @@
package de.mm20.launcher2.ktx
import android.os.Build
import androidx.annotation.ChecksSdkIntAtLeast
import org.json.JSONObject
fun jsonObjectOf(vararg pairs: Pair<String, Any?>): JSONObject {
val json = JSONObject()
for ((k, v) in pairs) {
when (v) {
is Float -> json.put(k, v.toDouble())
is Double -> json.put(k, v)
is Int -> json.put(k, v)
is Long -> json.put(k, v)
is Boolean -> json.put(k, v)
is String -> json.put(k, v)
else -> json.put(k, v)
}
}
return json
}
@ChecksSdkIntAtLeast(parameter = 0)
fun isAtLeastApiLevel(apiLevel: Int): Boolean {
return Build.VERSION.SDK_INT >= apiLevel
}
inline fun <reified T> Any?.castTo(): T {
@Suppress("UNCHECKED_CAST")
return this as T
}
inline fun <reified T> Any?.castToOrNull(): T? {
@Suppress("UNCHECKED_CAST")
return this as? T
}
@@ -0,0 +1,7 @@
package de.mm20.launcher2.ktx
import kotlin.math.ceil
fun Float.ceilToInt(): Int {
return ceil(this).toInt()
}
@@ -0,0 +1,9 @@
package de.mm20.launcher2.ktx
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import java.io.InputStream
fun InputStream.asBitmap(options : BitmapFactory.Options? = null): Bitmap? {
return BitmapFactory.decodeStream(this, null, options)
}
@@ -0,0 +1,19 @@
package de.mm20.launcher2.ktx
import androidx.core.graphics.ColorUtils
import androidx.core.graphics.blue
import androidx.core.graphics.green
import androidx.core.graphics.red
fun Int.isBrightColor(): Boolean {
val darkness = 1 - (0.299 * red + 0.587 * green + 0.114 * blue) / 255
return darkness < 0.5
}
val Int.sat : Float
get() {
FloatArray(3).also {
ColorUtils.RGBToHSL(red, green, blue, it)
return it[1]
}
}
@@ -0,0 +1,12 @@
package de.mm20.launcher2.ktx
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
fun LayerDrawable.getDrawableOrNull(index: Int): Drawable? {
return try {
this.getDrawable(index)
} catch (e: IndexOutOfBoundsException) {
return null
}
}
@@ -0,0 +1,13 @@
package de.mm20.launcher2.ktx
import java.util.*
fun <T> List<T>.randomElement(): T {
if (isEmpty()) throw IndexOutOfBoundsException("List is empty")
return get(Random().nextInt(size))
}
fun <T> List<T>.randomElementOrNull(): T? {
if (isEmpty()) return null
return get(Random().nextInt(size))
}
@@ -0,0 +1,9 @@
package de.mm20.launcher2.ktx
import android.app.Notification
import android.content.Context
import android.graphics.drawable.Drawable
fun Notification.getBadgeIcon(context: Context, packageName: String): Drawable? {
return smallIcon.loadDrawable(context)
}
@@ -0,0 +1,19 @@
package de.mm20.launcher2.ktx
import android.graphics.Rect
import android.graphics.RectF
fun Rect.translate(x: Int, y: Int): Rect {
top += y
bottom += y
left += x
right += x
return this
}
fun Rect.toRectF(other: RectF) {
other.left = left.toFloat()
other.bottom = bottom.toFloat()
other.right = right.toFloat()
other.top = top.toFloat()
}
@@ -0,0 +1,25 @@
package de.mm20.launcher2.ktx
import android.graphics.RectF
fun RectF.scale(factor: Float) {
val newWidth = width() * factor
val newHeight = height() * factor
bottom += newHeight - height()
right += newWidth - width()
}
fun RectF.translate(x: Float, y: Float): RectF {
top += y
bottom += y
left += x
right += x
return this
}
infix fun RectF.copyTo(other: RectF) {
other.top = top
other.left = left
other.right = right
other.bottom = bottom
}
@@ -0,0 +1,29 @@
package de.mm20.launcher2.ktx
import android.content.res.Resources
import android.content.res.TypedArray
import android.graphics.drawable.Drawable
fun Resources.getIntArrayOrNull(id: Int): IntArray? {
return try {
getIntArray(id)
} catch (e: Resources.NotFoundException) {
null
}
}
fun Resources.getDrawableOrNull(id: Int, theme: Resources.Theme? = null): Drawable? {
return try {
getDrawable(id, theme)
} catch (e: Resources.NotFoundException) {
null
}
}
fun Resources.obtainTypedArrayOrNull(id: Int): TypedArray? {
return try {
obtainTypedArray(id)
} catch (e: Resources.NotFoundException) {
null
}
}
@@ -0,0 +1,17 @@
package de.mm20.launcher2.ktx
import android.content.SharedPreferences
fun SharedPreferences.Editor.putDouble(key: String, value: Double) {
putLong(key, value.toBits())
}
fun SharedPreferences.getDouble(key: String): Double? {
if (contains(key)) return Double.fromBits(getLong(key, 0))
return null
}
fun SharedPreferences.getDouble(key: String, defValue: Double): Double {
if (contains(key)) return Double.fromBits(getLong(key, 0))
return defValue
}
@@ -0,0 +1,32 @@
package de.mm20.launcher2.ktx
import com.github.promeg.pinyinhelper.Pinyin
import org.apache.commons.lang3.StringUtils
import java.net.URLDecoder
import java.util.*
fun String.decodeUrl(charset: String): String? {
return URLDecoder.decode(this, charset)
}
/**
* Normalize a string to lowercase string
* This is used for substring matching.
* Characters must be normalized independently so that
* A.contains(B) -> A.normalize().contains(B.normalize()) is true.
*/
fun String.normalize(): String {
return StringUtils.stripAccents(this.romanize().lowercase(Locale.getDefault()))
.replace("æ", "ae")
.replace("œ", "oe")
.replace("ß", "ss")
}
/**
* Romanize a string, transliterate non-latin characters into latin
* This is used for sorting. The resulting string represents the position where the original
* string should be sorted in the latin alphabet.
*/
fun String.romanize(): String {
return Pinyin.toPinyin(this, "")
}
@@ -0,0 +1,13 @@
package de.mm20.launcher2.ktx
import android.graphics.drawable.Drawable
import android.widget.TextView
import androidx.annotation.DrawableRes
fun TextView.setStartCompoundDrawable(drawable: Drawable?) {
setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null)
}
fun TextView.setStartCompoundDrawable(@DrawableRes drawableRes: Int) {
setCompoundDrawablesRelativeWithIntrinsicBounds(drawableRes, 0, 0, 0)
}
@@ -0,0 +1,12 @@
package de.mm20.launcher2.ktx
import android.content.Context
import android.os.Process
import android.os.UserHandle
import android.os.UserManager
fun UserHandle.getSerialNumber(context: Context): Long {
if (this == Process.myUserHandle()) return 0L
val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager
return userManager.getSerialNumberForUser(this)
}
@@ -0,0 +1,26 @@
package de.mm20.launcher2.ktx
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
val View.dp: Float
get() = context.dp
val View.sp: Float
get() = context.sp
fun View.asViewGroup(): ViewGroup? {
return this as? ViewGroup
}
val View.lifecycleScope
get() = (context as LifecycleOwner).lifecycleScope
val View.lifecycleOwner
get() = (context as LifecycleOwner)
fun View.setPadding(vertical: Int, horizontal: Int) {
setPadding(vertical, horizontal, vertical, horizontal)
}
@@ -0,0 +1,52 @@
package de.mm20.launcher2.ktx
import org.junit.Assert
import org.junit.Test
internal class StringKtTest {
@Test
fun stringNormalizer_diacritics() {
Assert.assertEquals("a b c d e f g h i j", "À b ç d Ę F Ğ h ï j".normalize())
}
@Test
fun stringNormalizer_ligatures() {
Assert.assertEquals("aeoessss", "ÆŒßẞ".normalize())
}
@Test
fun stringNormalizer_search() {
val pairs = listOf(
"文件" to "jian",
"文件" to "jiàn",
"文件" to "",
"génération" to "Generation",
"Kvæsitso" to "kvaes",
"Übersetzer" to "uberset",
)
for ((str, q) in pairs) {
Assert.assertTrue(str.normalize().contains(q.normalize()))
}
}
/**
* Test that A.contains(B) -> A.normalize().contains(B.normalize())
*/
@Test
fun stringNormalize_substring_implication() {
val pairs = listOf(
"文件" to "",
"génération" to "énér",
"Kvæsitso" to "æ",
"Übersetzer" to "übe",
)
for ((str, q) in pairs) {
Assert.assertTrue(
if (str.contains(q)) str.normalize().contains(q.normalize())
else true
)
}
}
}