mirror of
https://github.com/jellyfin/jellyfin-android.git
synced 2026-09-03 05:10:27 +03:00
Refactor and split up extensions (#270)
This commit is contained in:
@@ -8,7 +8,6 @@ import android.os.Bundle
|
||||
import android.os.IBinder
|
||||
import android.view.OrientationEventListener
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -17,7 +16,10 @@ import org.jellyfin.mobile.cast.IChromecast
|
||||
import org.jellyfin.mobile.fragment.ConnectFragment
|
||||
import org.jellyfin.mobile.fragment.WebViewFragment
|
||||
import org.jellyfin.mobile.player.PlayerFragment
|
||||
import org.jellyfin.mobile.utils.*
|
||||
import org.jellyfin.mobile.utils.Constants
|
||||
import org.jellyfin.mobile.utils.PermissionRequestHelper
|
||||
import org.jellyfin.mobile.utils.SmartOrientationListener
|
||||
import org.jellyfin.mobile.utils.replaceFragment
|
||||
import org.jellyfin.mobile.viewmodel.MainViewModel
|
||||
import org.jellyfin.mobile.viewmodel.ServerState
|
||||
import org.jellyfin.mobile.webapp.RemotePlayerService
|
||||
@@ -31,8 +33,6 @@ class MainActivity : AppCompatActivity() {
|
||||
val chromecast: IChromecast = Chromecast()
|
||||
private val permissionRequestHelper: PermissionRequestHelper by inject()
|
||||
|
||||
val rootView: CoordinatorLayout by lazyView(R.id.root_view)
|
||||
|
||||
var serviceBinder: RemotePlayerService.ServiceBinder? = null
|
||||
private set
|
||||
private val serviceConnection: ServiceConnection = object : ServiceConnection {
|
||||
|
||||
@@ -91,10 +91,10 @@ class WebViewFragment : Fragment() {
|
||||
// offsetting 100dp from the center in both directions
|
||||
// uses the maximum available space
|
||||
val verticalCenter = webView.measuredHeight / 2
|
||||
val offset = webView.context.dip(100)
|
||||
val offset = webView.resources.dip(100)
|
||||
|
||||
// Arbitrary, currently 2x minimum touch target size
|
||||
val exclusionWidth = webView.context.dip(96)
|
||||
val exclusionWidth = webView.resources.dip(96)
|
||||
|
||||
webView.systemGestureExclusionRects = listOf(
|
||||
Rect(
|
||||
|
||||
@@ -282,7 +282,7 @@ class PlayerFragment : Fragment() {
|
||||
return false
|
||||
|
||||
// Check whether swipe was started in excluded region
|
||||
if (firstEvent.y < GESTURE_EXCLUSION_AREA_TOP * resources.displayMetrics.density)
|
||||
if (firstEvent.y < resources.dip(GESTURE_EXCLUSION_AREA_TOP))
|
||||
return false
|
||||
|
||||
// Check whether swipe was oriented vertically
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
@file:Suppress("DEPRECATION")
|
||||
|
||||
package org.jellyfin.mobile.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.Point
|
||||
import android.view.Surface
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
|
||||
const val STABLE_LAYOUT_FLAGS = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
|
||||
const val FULLSCREEN_FLAGS = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
|
||||
fun Activity.isFullscreen() = window.decorView.systemUiVisibility.hasFlag(FULLSCREEN_FLAGS)
|
||||
|
||||
fun Activity.enableFullscreen() {
|
||||
window.apply {
|
||||
decorView.systemUiVisibility = FULLSCREEN_FLAGS
|
||||
addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
|
||||
}
|
||||
}
|
||||
|
||||
fun Activity.disableFullscreen(keepStableLayout: Boolean = false) {
|
||||
window.apply {
|
||||
decorView.systemUiVisibility = if (keepStableLayout) STABLE_LAYOUT_FLAGS else 0
|
||||
clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
}
|
||||
}
|
||||
|
||||
fun Activity.lockOrientation() {
|
||||
val display = windowManager.defaultDisplay
|
||||
val size = Point().also(display::getSize)
|
||||
val height = size.y
|
||||
val width = size.x
|
||||
requestedOrientation = when (display.rotation) {
|
||||
Surface.ROTATION_90 -> if (width > height) ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
|
||||
Surface.ROTATION_180 -> if (height > width) ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
||||
Surface.ROTATION_270 -> if (width > height) ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
else -> if (height > width) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package org.jellyfin.mobile.utils
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.add
|
||||
import androidx.fragment.app.replace
|
||||
import org.jellyfin.mobile.MainActivity
|
||||
import org.jellyfin.mobile.R
|
||||
|
||||
inline fun <reified T : Fragment> FragmentManager.addFragment() {
|
||||
beginTransaction().apply {
|
||||
add<T>(R.id.fragment_container)
|
||||
addToBackStack(null)
|
||||
}.commit()
|
||||
}
|
||||
|
||||
inline fun <reified T : Fragment> FragmentManager.replaceFragment(args: Bundle? = null) {
|
||||
beginTransaction().replace<T>(R.id.fragment_container, args = args).commit()
|
||||
}
|
||||
|
||||
inline fun Fragment.requireMainActivity(): MainActivity = requireActivity() as MainActivity
|
||||
@@ -33,8 +33,7 @@ fun MainActivity.requestNoBatteryOptimizations() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val powerManager: PowerManager = getSystemService(AppCompatActivity.POWER_SERVICE) as PowerManager
|
||||
if (!appPreferences.ignoreBatteryOptimizations && !powerManager.isIgnoringBatteryOptimizations(BuildConfig.APPLICATION_ID)) {
|
||||
Snackbar.make(rootView, R.string.battery_optimizations_message, Snackbar.LENGTH_INDEFINITE).apply {
|
||||
// Add action
|
||||
Snackbar.make(findViewById(R.id.root_view), R.string.battery_optimizations_message, Snackbar.LENGTH_INDEFINITE).apply {
|
||||
setAction(android.R.string.ok) {
|
||||
try {
|
||||
val intent = Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
|
||||
@@ -46,7 +45,6 @@ fun MainActivity.requestNoBatteryOptimizations() {
|
||||
// Ignore after the user interacted with the snackbar at least once
|
||||
appPreferences.ignoreBatteryOptimizations = true
|
||||
}
|
||||
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,75 +1,23 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
@file:Suppress("unused", "NOTHING_TO_INLINE")
|
||||
|
||||
package org.jellyfin.mobile.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.Point
|
||||
import android.os.Bundle
|
||||
import android.view.*
|
||||
import android.content.res.Resources
|
||||
import android.view.ContextThemeWrapper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.IdRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.annotation.StyleRes
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.updateMargins
|
||||
import androidx.fragment.app.*
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.jellyfin.mobile.MainActivity
|
||||
import org.jellyfin.mobile.R
|
||||
|
||||
inline fun <T : View> Activity.lazyView(@IdRes id: Int) =
|
||||
lazy(LazyThreadSafetyMode.NONE) { findViewById<T>(id) }
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
const val STABLE_LAYOUT_FLAGS = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
const val FULLSCREEN_FLAGS = View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun Activity.isFullscreen() = window.decorView.systemUiVisibility.hasFlag(FULLSCREEN_FLAGS)
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun Activity.enableFullscreen() {
|
||||
window.apply {
|
||||
decorView.systemUiVisibility = FULLSCREEN_FLAGS
|
||||
addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun Activity.disableFullscreen(keepStableLayout: Boolean = false) {
|
||||
window.apply {
|
||||
decorView.systemUiVisibility = if (keepStableLayout) STABLE_LAYOUT_FLAGS else 0
|
||||
clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun Activity.lockOrientation() {
|
||||
val display = windowManager.defaultDisplay
|
||||
val size = Point().also(display::getSize)
|
||||
val height = size.y
|
||||
val width = size.x
|
||||
requestedOrientation = when (display.rotation) {
|
||||
Surface.ROTATION_90 -> if (width > height) ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
|
||||
Surface.ROTATION_180 -> if (height > width) ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
||||
Surface.ROTATION_270 -> if (width > height) ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||
else -> if (height > width) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||
}
|
||||
}
|
||||
|
||||
inline fun Context.dip(px: Int) = (px * resources.displayMetrics.density).toInt()
|
||||
|
||||
inline fun Context.toast(@StringRes text: Int, duration: Int = Toast.LENGTH_SHORT) =
|
||||
Toast.makeText(this, text, duration).show()
|
||||
@@ -81,24 +29,10 @@ inline fun LifecycleOwner.runOnUiThread(noinline block: suspend CoroutineScope.(
|
||||
lifecycleScope.launch(Dispatchers.Main, block = block)
|
||||
}
|
||||
|
||||
inline fun <reified T : Fragment> FragmentManager.addFragment() {
|
||||
beginTransaction().apply {
|
||||
add<T>(R.id.fragment_container)
|
||||
addToBackStack(null)
|
||||
}.commit()
|
||||
}
|
||||
|
||||
inline fun <reified T : Fragment> FragmentManager.replaceFragment(args: Bundle? = null) {
|
||||
beginTransaction().replace<T>(R.id.fragment_container, args = args).commit()
|
||||
}
|
||||
|
||||
fun LayoutInflater.withThemedContext(context: Context, @StyleRes style: Int): LayoutInflater {
|
||||
return cloneInContext(ContextThemeWrapper(context, style))
|
||||
}
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun Fragment.requireMainActivity(): MainActivity = requireActivity() as MainActivity
|
||||
|
||||
fun View.applyWindowInsetsAsMargins() {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this) { _, insets ->
|
||||
val layoutParams = layoutParams as ViewGroup.MarginLayoutParams
|
||||
@@ -111,3 +45,5 @@ fun View.applyWindowInsetsAsMargins() {
|
||||
insets
|
||||
}
|
||||
}
|
||||
|
||||
inline fun Resources.dip(px: Int) = (px * displayMetrics.density).toInt()
|
||||
|
||||
Reference in New Issue
Block a user