AquaStream/app/src/main/java/com/lagradost/cloudstream3/UIHelper.kt

443 lines
16 KiB
Kotlin
Raw Normal View History

2021-05-12 21:51:02 +00:00
package com.lagradost.cloudstream3
2021-05-20 21:25:41 +00:00
import android.Manifest
2021-06-15 23:25:58 +00:00
import android.annotation.SuppressLint
2021-05-12 21:51:02 +00:00
import android.app.Activity
2021-06-10 23:00:22 +00:00
import android.app.AppOpsManager
2021-05-28 13:38:06 +00:00
import android.content.Context
2021-05-20 21:25:41 +00:00
import android.content.pm.PackageManager
2021-05-15 23:37:42 +00:00
import android.content.res.Resources
2021-06-14 00:00:29 +00:00
import android.graphics.Color
2021-05-28 13:38:06 +00:00
import android.media.AudioAttributes
import android.media.AudioFocusRequest
import android.media.AudioManager
2021-07-17 21:36:50 +00:00
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
2021-05-28 13:38:06 +00:00
import android.os.Build
2021-06-15 23:25:58 +00:00
import android.view.Gravity
import android.view.MenuItem
2021-05-12 21:51:02 +00:00
import android.view.View
2021-06-06 18:06:01 +00:00
import android.view.WindowManager
2021-06-10 23:00:22 +00:00
import android.view.inputmethod.InputMethodManager
2021-07-19 13:19:47 +00:00
import androidx.annotation.AttrRes
2021-06-14 00:00:29 +00:00
import androidx.annotation.ColorInt
2021-05-18 13:43:32 +00:00
import androidx.appcompat.app.AppCompatActivity
2021-06-15 23:25:58 +00:00
import androidx.appcompat.view.ContextThemeWrapper
import androidx.appcompat.view.menu.MenuBuilder
import androidx.appcompat.widget.PopupMenu
2021-05-20 21:25:41 +00:00
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
2021-07-19 13:19:47 +00:00
import androidx.core.graphics.alpha
import androidx.core.graphics.blue
import androidx.core.graphics.green
import androidx.core.graphics.red
2021-06-06 18:06:01 +00:00
import androidx.fragment.app.FragmentActivity
2021-05-15 23:37:42 +00:00
import androidx.preference.PreferenceManager
2021-06-06 18:06:01 +00:00
import com.google.android.gms.cast.framework.CastContext
2021-07-17 14:14:25 +00:00
import com.google.android.gms.cast.framework.CastState
2021-06-06 18:06:01 +00:00
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
2021-07-17 21:36:50 +00:00
import com.google.android.gms.common.wrappers.Wrappers.packageManager
2021-05-18 13:43:32 +00:00
import com.lagradost.cloudstream3.ui.result.ResultFragment
2021-05-28 13:38:06 +00:00
import com.lagradost.cloudstream3.utils.Event
2021-06-14 00:00:29 +00:00
import kotlin.math.roundToInt
2021-05-12 21:51:02 +00:00
object UIHelper {
2021-05-15 23:37:42 +00:00
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)
2021-05-20 21:25:41 +00:00
fun Activity.checkWrite(): Boolean {
2021-07-24 15:13:21 +00:00
return (ContextCompat.checkSelfPermission(
this,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
2021-05-20 21:25:41 +00:00
== PackageManager.PERMISSION_GRANTED)
}
fun Activity.requestRW() {
2021-07-24 15:13:21 +00:00
ActivityCompat.requestPermissions(
this,
2021-05-20 21:25:41 +00:00
arrayOf(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
),
2021-07-24 15:13:21 +00:00
1337
)
2021-05-20 21:25:41 +00:00
}
2021-07-19 13:19:47 +00:00
@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
}
2021-05-18 13:43:32 +00:00
fun AppCompatActivity.loadResult(url: String, slug: String, apiName: String) {
this.runOnUiThread {
2021-06-06 18:06:01 +00:00
viewModelStore.clear()
2021-05-15 23:37:42 +00:00
this.supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim, R.anim.pop_enter, R.anim.pop_exit)
2021-05-22 22:25:56 +00:00
.add(R.id.homeRoot, ResultFragment.newInstance(url, slug, apiName))
2021-05-15 23:37:42 +00:00
.commit()
2021-05-18 13:43:32 +00:00
}
2021-05-15 23:37:42 +00:00
}
2021-06-06 18:06:01 +00:00
fun Context.getStatusBarHeight(): Int {
2021-05-12 21:51:02 +00:00
var result = 0
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
if (resourceId > 0) {
result = resources.getDimensionPixelSize(resourceId)
}
return result
}
2021-06-06 18:06:01 +00:00
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
}
2021-07-15 16:45:25 +00:00
fun Context.fixPaddingStatusbar(v: View) {
2021-05-12 21:51:02 +00:00
v.setPadding(v.paddingLeft, v.paddingTop + getStatusBarHeight(), v.paddingRight, v.paddingBottom)
}
2021-05-15 23:37:42 +00:00
2021-07-15 16:45:25 +00:00
private fun Context.getGridFormat(): String {
2021-05-15 23:37:42 +00:00
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
return settingsManager.getString(getString(R.string.grid_format_key), "grid")!!
}
2021-07-15 16:45:25 +00:00
fun Context.getGridFormatId(): Int {
2021-05-15 23:37:42 +00:00
return when (getGridFormat()) {
"list" -> R.layout.search_result_compact
"compact_list" -> R.layout.search_result_super_compact
else -> R.layout.search_result_grid
}
}
2021-07-15 16:45:25 +00:00
fun Context.getGridIsCompact(): Boolean {
2021-05-15 23:37:42 +00:00
return getGridFormat() != "grid"
}
2021-05-28 13:38:06 +00:00
fun Activity.requestLocalAudioFocus(focusRequest: AudioFocusRequest?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && focusRequest != null) {
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.requestAudioFocus(focusRequest)
} else {
val audioManager: AudioManager =
getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.requestAudioFocus(
null,
AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK
)
}
}
2021-07-24 15:13:21 +00:00
2021-06-16 17:40:02 +00:00
private var currentAudioFocusRequest: AudioFocusRequest? = null
private var currentAudioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null
2021-05-28 13:38:06 +00:00
var onAudioFocusEvent = Event<Boolean>()
2021-06-15 23:25:58 +00:00
private fun getAudioListener(): AudioManager.OnAudioFocusChangeListener? {
2021-06-16 17:40:02 +00:00
if (currentAudioFocusChangeListener != null) return currentAudioFocusChangeListener
currentAudioFocusChangeListener = AudioManager.OnAudioFocusChangeListener {
2021-05-28 13:38:06 +00:00
onAudioFocusEvent.invoke(
when (it) {
2021-06-16 17:40:02 +00:00
AudioManager.AUDIOFOCUS_GAIN -> false
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE -> false
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT -> false
else -> true
2021-05-28 13:38:06 +00:00
}
)
}
2021-06-16 17:40:02 +00:00
return currentAudioFocusChangeListener
2021-05-28 13:38:06 +00:00
}
2021-06-06 18:06:01 +00:00
fun Context.isCastApiAvailable(): Boolean {
val isCastApiAvailable =
GoogleApiAvailability.getInstance()
.isGooglePlayServicesAvailable(applicationContext) == ConnectionResult.SUCCESS
try {
applicationContext?.let { CastContext.getSharedInstance(it) }
} catch (e: Exception) {
println(e)
// track non-fatal
return false
}
return isCastApiAvailable
}
2021-07-17 14:14:25 +00:00
fun Context.isConnectedToChromecast(): Boolean {
if (isCastApiAvailable()) {
val castContext = CastContext.getSharedInstance(this)
if (castContext.castState == CastState.CONNECTED) {
return true
}
}
return false
}
2021-07-17 21:36:50 +00:00
fun Context.isUsingMobileData(): Boolean {
val conManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val networkInfo = conManager.allNetworks
return networkInfo.any {
conManager.getNetworkCapabilities(it)?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true
}
}
fun Context.isAppInstalled(uri: String): Boolean {
val pm = packageManager(this)
var appInstalled = false
appInstalled = try {
pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES)
true
} catch (e: PackageManager.NameNotFoundException) {
false
}
return appInstalled
}
2021-07-17 14:14:25 +00:00
2021-06-14 00:00:29 +00:00
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
}
2021-05-28 13:38:06 +00:00
fun getFocusRequest(): AudioFocusRequest? {
2021-06-16 17:40:02 +00:00
if (currentAudioFocusRequest != null) return currentAudioFocusRequest
currentAudioFocusRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
2021-05-28 13:38:06 +00:00
AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
setAudioAttributes(AudioAttributes.Builder().run {
setUsage(AudioAttributes.USAGE_MEDIA)
setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)
build()
})
setAcceptsDelayedFocusGain(true)
getAudioListener()?.let {
setOnAudioFocusChangeListener(it)
}
build()
}
} else {
null
}
2021-06-16 17:40:02 +00:00
return currentAudioFocusRequest
2021-05-28 13:38:06 +00:00
}
2021-06-06 18:06:01 +00:00
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
2021-06-10 19:43:05 +00:00
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
2021-07-24 15:13:21 +00:00
// 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
2021-06-06 18:06:01 +00:00
// or View.SYSTEM_UI_FLAG_LOW_PROFILE
)
// window.addFlags(View.KEEP_SCREEN_ON)
}
2021-07-24 15:13:21 +00:00
2021-06-10 18:21:42 +00:00
fun FragmentActivity.popCurrentPage() {
val currentFragment = supportFragmentManager.fragments.lastOrNull {
it.isVisible
} ?: return
2021-06-06 18:06:01 +00:00
2021-06-10 18:21:42 +00:00
supportFragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.enter_anim,
R.anim.exit_anim,
R.anim.pop_enter,
R.anim.pop_exit
)
.remove(currentFragment)
.commitAllowingStateLoss()
}
/*
2021-06-06 18:06:01 +00:00
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()
}
}
2021-06-10 18:21:42 +00:00
}*/
2021-06-06 18:06:01 +00:00
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() {
2021-06-10 19:43:05 +00:00
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
) // or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
2021-06-06 18:06:01 +00:00
// window.clearFlags(View.KEEP_SCREEN_ON)
}
2021-06-10 23:00:22 +00:00
fun Context.shouldShowPIPMode(isInPlayer: Boolean): Boolean {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
return settingsManager?.getBoolean("pip_enabled", true) ?: true && isInPlayer
}
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)
}
2021-06-15 23:25:58 +00:00
2021-07-24 15:13:21 +00:00
/**id, icon, stringRes */
2021-06-15 23:25:58 +00:00
@SuppressLint("RestrictedApi")
2021-07-24 15:13:21 +00:00
fun View.popupMenu(
2021-06-15 23:25:58 +00:00
items: List<Triple<Int, Int, Int>>,
2021-07-24 15:13:21 +00:00
onMenuItemClick: MenuItem.() -> Unit,
2021-06-15 23:25:58 +00:00
): 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
}
2021-07-24 15:13:21 +00:00
/**id, stringRes */
@SuppressLint("RestrictedApi")
fun View.popupMenuNoIcons(
2021-06-15 23:25:58 +00:00
items: List<Pair<Int, Int>>,
2021-07-24 15:13:21 +00:00
onMenuItemClick: MenuItem.() -> Unit,
2021-06-15 23:25:58 +00:00
): 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
}
2021-06-26 22:15:19 +00:00
2021-07-24 15:13:21 +00:00
/**id, string */
@SuppressLint("RestrictedApi")
2021-07-25 20:50:16 +00:00
fun View.popupMenuNoIconsAndNoStringRes(
2021-06-26 22:15:19 +00:00
items: List<Pair<Int, String>>,
2021-07-24 15:13:21 +00:00
onMenuItemClick: MenuItem.() -> Unit,
2021-06-26 22:15:19 +00:00
): PopupMenu {
val ctw = ContextThemeWrapper(context, R.style.PopupMenu)
val popup = PopupMenu(ctw, this, Gravity.NO_GRAVITY, R.attr.actionOverflowMenuStyle, 0)
2021-07-24 15:13:21 +00:00
items.forEach { (id, string) ->
popup.menu.add(0, id, 0, string)
2021-06-26 22:15:19 +00:00
}
(popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true)
popup.setOnMenuItemClickListener {
it.onMenuItemClick()
true
}
popup.show()
return popup
}
2021-05-12 21:51:02 +00:00
}