PixelDroid-App-Android/app/src/main/java/org/pixeldroid/app/utils/Utils.kt

222 lines
7.4 KiB
Kotlin
Raw Normal View History

2021-04-22 11:47:18 +02:00
package org.pixeldroid.app.utils
2021-09-18 13:11:10 +02:00
import android.content.*
import android.content.res.Resources
2021-09-18 13:11:10 +02:00
import android.graphics.Bitmap
2022-07-10 13:42:19 +02:00
import android.graphics.Color
2021-09-18 13:11:10 +02:00
import android.graphics.ImageDecoder
import android.graphics.Matrix
import android.net.ConnectivityManager
import android.net.Uri
import android.os.Build
2021-09-18 13:11:10 +02:00
import android.provider.MediaStore
import android.util.DisplayMetrics
import android.view.WindowManager
2022-07-27 15:55:33 +02:00
import android.webkit.MimeTypeMap
2022-07-10 13:42:19 +02:00
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.StyleRes
import androidx.appcompat.app.AppCompatDelegate
import androidx.browser.customtabs.CustomTabsIntent
import androidx.exifinterface.media.ExifInterface
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
2022-07-10 13:42:19 +02:00
import androidx.preference.PreferenceManager
2021-05-22 13:03:13 +02:00
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
2022-07-10 13:42:19 +02:00
import com.google.android.material.color.MaterialColors
2022-07-29 15:11:14 +02:00
import com.google.gson.JsonDeserializer
import com.google.gson.JsonElement
import com.google.gson.JsonPrimitive
import com.google.gson.JsonSerializer
2021-02-04 20:44:31 +01:00
import okhttp3.HttpUrl
import org.pixeldroid.app.R
2022-07-29 15:11:14 +02:00
import java.time.Instant
import java.time.format.DateTimeFormatter
import java.util.*
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KProperty
fun hasInternet(context: Context): Boolean {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
return cm.activeNetwork != null
}
2021-02-04 20:44:31 +01:00
/**
* Check if domain is valid or not
*/
fun validDomain(domain: String?): Boolean {
domain?.apply {
try {
HttpUrl.Builder().host(replace("https://", "")).scheme("https").build()
} catch (e: IllegalArgumentException) {
return false
}
} ?: return false
return true
}
fun Uri.fileExtension(contentResolver: ContentResolver): String? {
return if (scheme == "content") {
contentResolver.getType(this)?.takeLastWhile { it != '/' }
} else {
2022-07-27 15:55:33 +02:00
MimeTypeMap.getFileExtensionFromUrl(toString()).ifEmpty { null }
}
}
2022-07-27 15:55:33 +02:00
fun Uri.getMimeType(contentResolver: ContentResolver, fallback: String = "image/*"): String {
return if (scheme == "content") {
contentResolver.getType(this)
} else {
MimeTypeMap.getFileExtensionFromUrl(toString())
?.run { MimeTypeMap.getSingleton().getMimeTypeFromExtension(lowercase(Locale.getDefault())) }
2022-07-27 15:55:33 +02:00
} ?: fallback
}
fun Context.displayDimensionsInPx(): Pair<Int, Int> {
val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Pair(windowManager.currentWindowMetrics.bounds.width(), windowManager.currentWindowMetrics.bounds.height())
} else {
val metrics = DisplayMetrics()
@Suppress("DEPRECATION")
windowManager.defaultDisplay.getMetrics(metrics)
Pair(metrics.widthPixels, metrics.heightPixels)
}
}
fun normalizeDomain(domain: String): String {
return "https://" + domain
.replace("http://", "")
.replace("https://", "")
.trim(Char::isWhitespace)
}
2022-06-18 22:21:19 +02:00
fun BaseActivity.openUrl(url: String): Boolean {
val intent = CustomTabsIntent.Builder().build()
return try {
intent.launchUrl(this, Uri.parse(url))
true
} catch (e: ActivityNotFoundException) {
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
try {
startActivity(browserIntent)
true
} catch(e: ActivityNotFoundException) {
false
}
}
}
2021-05-22 13:03:13 +02:00
fun RecyclerView.limitedLengthSmoothScrollToPosition(targetItem: Int) {
layoutManager?.apply {
val maxScroll = 3
when (this) {
is LinearLayoutManager -> {
val topItem = findFirstVisibleItemPosition()
val distance = topItem - targetItem
val anchorItem = when {
distance > maxScroll -> targetItem + maxScroll
distance < -maxScroll -> targetItem - maxScroll
else -> topItem
}
if (anchorItem != topItem) scrollToPosition(anchorItem)
post {
smoothScrollToPosition(targetItem)
}
}
else -> smoothScrollToPosition(targetItem)
}
}
}
/**
* @brief Updates the application's theme depending on the given preferences and resources
*/
2022-07-10 13:42:19 +02:00
fun setThemeFromPreferences(preferences: SharedPreferences, resources: Resources) {
val themes = resources.getStringArray(R.array.theme_values)
//Set the theme
when(preferences.getString("theme", "")) {
//Light
themes[1] -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
}
//Dark
themes[2] -> {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
}
else -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
2020-09-10 20:20:23 +02:00
}
}
}
}
2022-07-10 13:42:19 +02:00
@StyleRes
fun Context.themeNoActionBar(): Int? {
2022-07-10 13:42:19 +02:00
return when(PreferenceManager.getDefaultSharedPreferences(this).getInt("themeColor", 0)) {
// No theme was chosen: the user wants to use the system dynamic color (from wallpaper for example)
-1 -> null
2022-07-10 13:42:19 +02:00
1 -> R.style.AppTheme2_NoActionBar
2 -> R.style.AppTheme3_NoActionBar
3 -> R.style.AppTheme4_NoActionBar
else -> R.style.AppTheme5_NoActionBar
2022-07-10 13:42:19 +02:00
}
}
@StyleRes
fun Context.themeActionBar(): Int? {
2022-07-10 13:42:19 +02:00
return when(PreferenceManager.getDefaultSharedPreferences(this).getInt("themeColor", 0)) {
// No theme was chosen: the user wants to use the system dynamic color (from wallpaper for example)
-1 -> null
2022-07-10 13:42:19 +02:00
1 -> R.style.AppTheme2
2 -> R.style.AppTheme3
3 -> R.style.AppTheme4
else -> R.style.AppTheme5
2022-07-10 13:42:19 +02:00
}
}
@ColorInt
fun Context.getColorFromAttr(@AttrRes attrColor: Int): Int = MaterialColors.getColor(this, attrColor, Color.BLACK)
2022-07-29 15:11:14 +02:00
val typeAdapterInstantDeserializer: JsonDeserializer<Instant> = JsonDeserializer { json: JsonElement, _, _ ->
DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(
json.asString, Instant::from
)
}
val typeAdapterInstantSerializer: JsonSerializer<Instant> = JsonSerializer { src: Instant, _, _ ->
JsonPrimitive(DateTimeFormatter.ISO_INSTANT.format(src))
}
/**
* Delegated property to use in fragments to prevent memory leaks of bindings.
* This makes it unnecessary to set binding to null in onDestroyView.
* The value should be assigned in the Fragment's onCreateView()
*/
fun <T> Fragment.bindingLifecycleAware(): ReadWriteProperty<Fragment, T> =
object : ReadWriteProperty<Fragment, T>, DefaultLifecycleObserver {
private var binding: T? = null
override fun onDestroy(owner: LifecycleOwner) {
binding = null
}
override fun getValue(thisRef: Fragment, property: KProperty<*>): T = binding!!
override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
binding = value
this@bindingLifecycleAware.viewLifecycleOwner.lifecycle.addObserver(this)
}
}