356 lines
12 KiB
Kotlin
356 lines
12 KiB
Kotlin
package com.lagradost.cloudstream3.utils
|
|
|
|
import android.Manifest
|
|
import android.annotation.SuppressLint
|
|
import android.app.Activity
|
|
import android.app.AppOpsManager
|
|
import android.content.Context
|
|
import android.content.pm.PackageManager
|
|
import android.content.res.Resources
|
|
import android.graphics.Color
|
|
import android.os.Build
|
|
import android.os.Bundle
|
|
import android.view.Gravity
|
|
import android.view.MenuItem
|
|
import android.view.View
|
|
import android.view.WindowManager
|
|
import android.view.inputmethod.InputMethodManager
|
|
import android.widget.ImageView
|
|
import androidx.annotation.*
|
|
import androidx.appcompat.view.ContextThemeWrapper
|
|
import androidx.appcompat.view.menu.MenuBuilder
|
|
import androidx.appcompat.widget.PopupMenu
|
|
import androidx.core.app.ActivityCompat
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.core.graphics.alpha
|
|
import androidx.core.graphics.blue
|
|
import androidx.core.graphics.green
|
|
import androidx.core.graphics.red
|
|
import androidx.fragment.app.Fragment
|
|
import androidx.fragment.app.FragmentActivity
|
|
import androidx.navigation.fragment.NavHostFragment
|
|
import androidx.preference.PreferenceManager
|
|
import com.bumptech.glide.Glide
|
|
import com.bumptech.glide.load.model.GlideUrl
|
|
import com.lagradost.cloudstream3.R
|
|
import com.lagradost.cloudstream3.mvvm.logError
|
|
import kotlin.math.roundToInt
|
|
|
|
|
|
object UIHelper {
|
|
val Int.toPx: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()
|
|
val Float.toPx: Float get() = (this * Resources.getSystem().displayMetrics.density)
|
|
val Int.toDp: Int get() = (this / Resources.getSystem().displayMetrics.density).toInt()
|
|
val Float.toDp: Float get() = (this / Resources.getSystem().displayMetrics.density)
|
|
|
|
fun Activity.checkWrite(): Boolean {
|
|
return (ContextCompat.checkSelfPermission(
|
|
this,
|
|
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
|
)
|
|
== PackageManager.PERMISSION_GRANTED)
|
|
}
|
|
|
|
fun Activity.requestRW() {
|
|
ActivityCompat.requestPermissions(
|
|
this,
|
|
arrayOf(
|
|
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
|
Manifest.permission.READ_EXTERNAL_STORAGE
|
|
),
|
|
1337
|
|
)
|
|
}
|
|
|
|
fun Fragment.hideKeyboard() {
|
|
activity?.window?.decorView?.clearFocus()
|
|
view.let {
|
|
if (it != null) {
|
|
activity?.hideKeyboard(it)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun Activity?.navigate(@IdRes navigation : Int, arguments : Bundle? = null) {
|
|
if(this is FragmentActivity) {
|
|
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment?)?.navController?.navigate(
|
|
navigation, arguments
|
|
)
|
|
}
|
|
}
|
|
|
|
@ColorInt
|
|
fun Context.getResourceColor(@AttrRes resource: Int, alphaFactor: Float = 1f): Int {
|
|
val typedArray = obtainStyledAttributes(intArrayOf(resource))
|
|
val color = typedArray.getColor(0, 0)
|
|
typedArray.recycle()
|
|
|
|
if (alphaFactor < 1f) {
|
|
val alpha = (color.alpha * alphaFactor).roundToInt()
|
|
return Color.argb(alpha, color.red, color.green, color.blue)
|
|
}
|
|
|
|
return color
|
|
}
|
|
|
|
fun ImageView?.setImage(url : String?) {
|
|
if(this == null || url.isNullOrBlank()) return
|
|
try {
|
|
GlideApp.with(this.context)
|
|
.load(GlideUrl(url))
|
|
.into(this)
|
|
} catch (e : Exception) {
|
|
logError(e)
|
|
}
|
|
}
|
|
|
|
fun adjustAlpha(@ColorInt color: Int, factor: Float): Int {
|
|
val alpha = (Color.alpha(color) * factor).roundToInt()
|
|
val red = Color.red(color)
|
|
val green = Color.green(color)
|
|
val blue = Color.blue(color)
|
|
return Color.argb(alpha, red, green, blue)
|
|
}
|
|
|
|
fun Context.colorFromAttribute(attribute: Int): Int {
|
|
val attributes = obtainStyledAttributes(intArrayOf(attribute))
|
|
val color = attributes.getColor(0, 0)
|
|
attributes.recycle()
|
|
return color
|
|
}
|
|
|
|
fun Activity.hideSystemUI() {
|
|
// Enables regular immersive mode.
|
|
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
|
|
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
window.decorView.systemUiVisibility = (
|
|
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
// Set the content to appear under the system bars so that the
|
|
// content doesn't resize when the system bars hide and show.
|
|
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
|
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
// Hide the nav bar and status bar
|
|
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
|
or View.SYSTEM_UI_FLAG_FULLSCREEN
|
|
// or View.SYSTEM_UI_FLAG_LOW_PROFILE
|
|
)
|
|
// window.addFlags(View.KEEP_SCREEN_ON)
|
|
}
|
|
|
|
fun FragmentActivity.popCurrentPage() {
|
|
this.onBackPressed()
|
|
/*val currentFragment = supportFragmentManager.fragments.lastOrNull {
|
|
it.isVisible
|
|
} ?: return
|
|
|
|
supportFragmentManager.beginTransaction()
|
|
.setCustomAnimations(
|
|
R.anim.enter_anim,
|
|
R.anim.exit_anim,
|
|
R.anim.pop_enter,
|
|
R.anim.pop_exit
|
|
)
|
|
.remove(currentFragment)
|
|
.commitAllowingStateLoss()*/
|
|
}
|
|
/*
|
|
fun FragmentActivity.popCurrentPage(isInPlayer: Boolean, isInExpandedView: Boolean, isInResults: Boolean) {
|
|
val currentFragment = supportFragmentManager.fragments.lastOrNull {
|
|
it.isVisible
|
|
}
|
|
?: //this.onBackPressed()
|
|
return
|
|
|
|
/*
|
|
if (tvActivity == null) {
|
|
requestedOrientation = if (settingsManager?.getBoolean("force_landscape", false) == true) {
|
|
ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
|
} else {
|
|
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
|
}
|
|
}*/
|
|
|
|
// No fucked animations leaving the player :)
|
|
when {
|
|
isInPlayer -> {
|
|
supportFragmentManager.beginTransaction()
|
|
//.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit)
|
|
.remove(currentFragment)
|
|
.commitAllowingStateLoss()
|
|
}
|
|
isInExpandedView && !isInResults -> {
|
|
supportFragmentManager.beginTransaction()
|
|
.setCustomAnimations(
|
|
R.anim.enter_anim,//R.anim.enter_from_right,
|
|
R.anim.exit_anim,//R.anim.exit_to_right,
|
|
R.anim.pop_enter,
|
|
R.anim.pop_exit
|
|
)
|
|
.remove(currentFragment)
|
|
.commitAllowingStateLoss()
|
|
}
|
|
else -> {
|
|
supportFragmentManager.beginTransaction()
|
|
.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim, R.anim.pop_enter, R.anim.pop_exit)
|
|
.remove(currentFragment)
|
|
.commitAllowingStateLoss()
|
|
}
|
|
}
|
|
}*/
|
|
|
|
fun Context.getStatusBarHeight(): Int {
|
|
var result = 0
|
|
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
|
|
if (resourceId > 0) {
|
|
result = resources.getDimensionPixelSize(resourceId)
|
|
}
|
|
return result
|
|
}
|
|
|
|
fun Context.fixPaddingStatusbar(v: View) {
|
|
v.setPadding(v.paddingLeft, v.paddingTop + getStatusBarHeight(), v.paddingRight, v.paddingBottom)
|
|
}
|
|
fun Context.getNavigationBarHeight(): Int {
|
|
var result = 0
|
|
val resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android")
|
|
if (resourceId > 0) {
|
|
result = resources.getDimensionPixelSize(resourceId)
|
|
}
|
|
return result
|
|
}
|
|
|
|
private fun Context.getGridFormat(): String {
|
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
|
return settingsManager.getString(getString(R.string.grid_format_key), "grid")!!
|
|
}
|
|
|
|
fun Context.getGridFormatId(): Int {
|
|
return when (getGridFormat()) {
|
|
"list" -> R.layout.search_result_compact
|
|
"compact_list" -> R.layout.search_result_super_compact
|
|
else -> R.layout.search_result_grid
|
|
}
|
|
}
|
|
|
|
fun Context.getGridIsCompact(): Boolean {
|
|
return getGridFormat() != "grid"
|
|
}
|
|
|
|
fun Activity.changeStatusBarState(hide: Boolean): Int {
|
|
return if (hide) {
|
|
window?.setFlags(
|
|
WindowManager.LayoutParams.FLAG_FULLSCREEN,
|
|
WindowManager.LayoutParams.FLAG_FULLSCREEN
|
|
)
|
|
0
|
|
} else {
|
|
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
|
this.getStatusBarHeight()
|
|
}
|
|
}
|
|
|
|
// Shows the system bars by removing all the flags
|
|
// except for the ones that make the content appear under the system bars.
|
|
fun Activity.showSystemUI() {
|
|
window.decorView.systemUiVisibility = (
|
|
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
|
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
|
) // or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
|
// window.clearFlags(View.KEEP_SCREEN_ON)
|
|
}
|
|
|
|
fun Context.shouldShowPIPMode(isInPlayer: Boolean): Boolean {
|
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
|
return settingsManager?.getBoolean("pip_enabled", true) ?: true && isInPlayer
|
|
}
|
|
|
|
@RequiresApi(Build.VERSION_CODES.O)
|
|
fun Context.hasPIPPermission(): Boolean {
|
|
val appOps =
|
|
getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
|
|
return appOps.checkOpNoThrow(
|
|
AppOpsManager.OPSTR_PICTURE_IN_PICTURE,
|
|
android.os.Process.myUid(),
|
|
packageName
|
|
) == AppOpsManager.MODE_ALLOWED
|
|
}
|
|
|
|
fun Context.hideKeyboard(view: View) {
|
|
val inputMethodManager = getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
|
|
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
|
|
}
|
|
|
|
|
|
/**id, icon, stringRes */
|
|
@SuppressLint("RestrictedApi")
|
|
fun View.popupMenu(
|
|
items: List<Triple<Int, Int, Int>>,
|
|
onMenuItemClick: MenuItem.() -> Unit,
|
|
): PopupMenu {
|
|
val ctw = ContextThemeWrapper(context, R.style.PopupMenu)
|
|
val popup = PopupMenu(ctw, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0)
|
|
|
|
items.forEach { (id, icon, stringRes) ->
|
|
popup.menu.add(0, id, 0, stringRes).setIcon(icon)
|
|
}
|
|
|
|
(popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true)
|
|
|
|
popup.setOnMenuItemClickListener {
|
|
it.onMenuItemClick()
|
|
true
|
|
}
|
|
|
|
popup.show()
|
|
return popup
|
|
}
|
|
|
|
/**id, stringRes */
|
|
@SuppressLint("RestrictedApi")
|
|
fun View.popupMenuNoIcons(
|
|
items: List<Pair<Int, Int>>,
|
|
onMenuItemClick: MenuItem.() -> Unit,
|
|
): PopupMenu {
|
|
val ctw = ContextThemeWrapper(context, R.style.PopupMenu)
|
|
val popup = PopupMenu(ctw, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0)
|
|
|
|
items.forEach { (id, stringRes) ->
|
|
popup.menu.add(0, id, 0, stringRes)
|
|
}
|
|
|
|
(popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true)
|
|
|
|
popup.setOnMenuItemClickListener {
|
|
it.onMenuItemClick()
|
|
true
|
|
}
|
|
|
|
popup.show()
|
|
return popup
|
|
}
|
|
|
|
/**id, string */
|
|
@SuppressLint("RestrictedApi")
|
|
fun View.popupMenuNoIconsAndNoStringRes(
|
|
items: List<Pair<Int, String>>,
|
|
onMenuItemClick: MenuItem.() -> Unit,
|
|
): PopupMenu {
|
|
val ctw = ContextThemeWrapper(context, R.style.PopupMenu)
|
|
val popup = PopupMenu(ctw, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0)
|
|
|
|
items.forEach { (id, string) ->
|
|
popup.menu.add(0, id, 0, string)
|
|
}
|
|
|
|
(popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true)
|
|
|
|
popup.setOnMenuItemClickListener {
|
|
it.onMenuItemClick()
|
|
true
|
|
}
|
|
|
|
popup.show()
|
|
return popup
|
|
}
|
|
} |