mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-05-25 11:02:08 +02:00
Merge branch 'auto-rotate-fixes' into 'master'
more rotation/orientation fixes See merge request videostreaming/grayjay!57
This commit is contained in:
commit
9b3f90f922
@ -415,7 +415,7 @@ class Settings : FragmentedStorageFileJson() {
|
|||||||
@FormField(R.string.simplify_sources, FieldForm.TOGGLE, R.string.simplify_sources_description, 4)
|
@FormField(R.string.simplify_sources, FieldForm.TOGGLE, R.string.simplify_sources_description, 4)
|
||||||
var simplifySources: Boolean = true;
|
var simplifySources: Boolean = true;
|
||||||
|
|
||||||
@FormField(R.string.force_allow_full_screen_rotation, FieldForm.TOGGLE, R.string.force_allow_full_screen_rotation_description, 5)
|
@FormField(R.string.force_enable_auto_rotate_in_full_screen, FieldForm.TOGGLE, R.string.force_enable_auto_rotate_in_full_screen_description, 5)
|
||||||
var forceAllowFullScreenRotation: Boolean = false
|
var forceAllowFullScreenRotation: Boolean = false
|
||||||
|
|
||||||
@FormField(R.string.background_behavior, FieldForm.DROPDOWN, -1, 6)
|
@FormField(R.string.background_behavior, FieldForm.DROPDOWN, -1, 6)
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package com.futo.platformplayer.fragment.mainactivity.main
|
package com.futo.platformplayer.fragment.mainactivity.main
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.content.Context
|
||||||
import android.content.pm.ActivityInfo
|
import android.content.pm.ActivityInfo
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.OrientationEventListener
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowInsets
|
import android.view.WindowInsets
|
||||||
@ -28,10 +29,15 @@ import com.futo.platformplayer.models.PlatformVideoWithTime
|
|||||||
import com.futo.platformplayer.models.UrlVideoWithTime
|
import com.futo.platformplayer.models.UrlVideoWithTime
|
||||||
import com.futo.platformplayer.states.StatePlayer
|
import com.futo.platformplayer.states.StatePlayer
|
||||||
import com.futo.platformplayer.views.containers.SingleViewTouchableMotionLayout
|
import com.futo.platformplayer.views.containers.SingleViewTouchableMotionLayout
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
|
//region Fragment
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
class VideoDetailFragment : MainFragment {
|
class VideoDetailFragment() : MainFragment() {
|
||||||
override val isMainView: Boolean = false;
|
override val isMainView: Boolean = false;
|
||||||
override val hasBottomBar: Boolean = true;
|
override val hasBottomBar: Boolean = true;
|
||||||
override val isOverlay: Boolean = true;
|
override val isOverlay: Boolean = true;
|
||||||
@ -76,8 +82,10 @@ class VideoDetailFragment : MainFragment {
|
|||||||
private var _loadUrlOnCreate: UrlVideoWithTime? = null;
|
private var _loadUrlOnCreate: UrlVideoWithTime? = null;
|
||||||
private var _leavingPiP = false;
|
private var _leavingPiP = false;
|
||||||
|
|
||||||
//region Fragment
|
private var _landscapeOrientationListener: LandscapeOrientationListener? = null
|
||||||
constructor() : super()
|
private var _portraitOrientationListener: PortraitOrientationListener? = null
|
||||||
|
private var _lastSetOrientation: Int = Configuration.ORIENTATION_UNDEFINED
|
||||||
|
private var _ignoreNextNewOrientation = false
|
||||||
|
|
||||||
fun nextVideo() {
|
fun nextVideo() {
|
||||||
_viewDetail?.nextVideo(true, true, true);
|
_viewDetail?.nextVideo(true, true, true);
|
||||||
@ -101,6 +109,15 @@ class VideoDetailFragment : MainFragment {
|
|||||||
|
|
||||||
val isSmallWindow = isSmallWindow()
|
val isSmallWindow = isSmallWindow()
|
||||||
|
|
||||||
|
val temp = _lastSetOrientation
|
||||||
|
|
||||||
|
if (_ignoreNextNewOrientation) {
|
||||||
|
_ignoreNextNewOrientation = false
|
||||||
|
} else {
|
||||||
|
// the device has rotated so update our state tracking what the physical orientation of the device is
|
||||||
|
_lastSetOrientation = newConfig.orientation
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isSmallWindow
|
isSmallWindow
|
||||||
&& newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
|
&& newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||||
@ -113,6 +130,7 @@ class VideoDetailFragment : MainFragment {
|
|||||||
&& isFullscreen
|
&& isFullscreen
|
||||||
&& !Settings.instance.playback.fullscreenPortrait
|
&& !Settings.instance.playback.fullscreenPortrait
|
||||||
&& newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
|
&& newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||||
|
&& temp == Configuration.ORIENTATION_LANDSCAPE
|
||||||
&& isLandscapeVideo
|
&& isLandscapeVideo
|
||||||
) {
|
) {
|
||||||
_viewDetail?.setFullscreen(false)
|
_viewDetail?.setFullscreen(false)
|
||||||
@ -153,20 +171,48 @@ class VideoDetailFragment : MainFragment {
|
|||||||
|
|
||||||
val isSmallWindow = isSmallWindow()
|
val isSmallWindow = isSmallWindow()
|
||||||
|
|
||||||
|
val autoRotateEnabled = android.provider.Settings.System.getInt(
|
||||||
|
context?.contentResolver,
|
||||||
|
android.provider.Settings.System.ACCELEROMETER_ROTATION, 0
|
||||||
|
) == 1
|
||||||
|
|
||||||
// For small windows if the device isn't landscape right now and full screen portrait isn't allowed then we should force landscape
|
// For small windows if the device isn't landscape right now and full screen portrait isn't allowed then we should force landscape
|
||||||
if (isSmallWindow && isFullscreen && !isFullScreenPortraitAllowed && resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT && !rotationLock && isLandscapeVideo) {
|
if (isSmallWindow && isFullscreen && !isFullScreenPortraitAllowed && _lastSetOrientation != Configuration.ORIENTATION_LANDSCAPE && !rotationLock && isLandscapeVideo) {
|
||||||
if (Settings.instance.playback.forceAllowFullScreenRotation) {
|
if (Settings.instance.playback.forceAllowFullScreenRotation) {
|
||||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||||
} else {
|
} else {
|
||||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||||
}
|
}
|
||||||
|
// the next orientation change will not reflect the device because we are manually setting the orientation to landscape
|
||||||
|
_ignoreNextNewOrientation = true
|
||||||
|
if (autoRotateEnabled
|
||||||
|
) {
|
||||||
|
// start listening for the device to rotate to landscape
|
||||||
|
// at which point we'll be able to set requestedOrientation to back to UNSPECIFIED
|
||||||
|
_landscapeOrientationListener?.enableListener()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// For small windows if the device isn't in a portrait orientation and we're in the maximized state then we should force portrait
|
// For small windows if the device isn't in a portrait orientation and we're in the maximized state then we should force portrait
|
||||||
else if (isSmallWindow && !isMinimizingFromFullScreen && !isFullscreen && state == State.MAXIMIZED && resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
else if (isSmallWindow && !isMinimizingFromFullScreen && !isFullscreen && state == State.MAXIMIZED && _lastSetOrientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|
||||||
|
// the next orientation change will not reflect the device because we are manually setting the orientation to portrait
|
||||||
|
_ignoreNextNewOrientation = true
|
||||||
|
if (autoRotateEnabled
|
||||||
|
) {
|
||||||
|
// start listening for the device to rotate to portrait
|
||||||
|
// at which point we'll be able to set requestedOrientation to back to UNSPECIFIED
|
||||||
|
_portraitOrientationListener?.enableListener()
|
||||||
|
} else {
|
||||||
|
// the rotation state resets to portrait when changing requestedOrientation
|
||||||
|
_lastSetOrientation = Configuration.ORIENTATION_PORTRAIT
|
||||||
|
}
|
||||||
} else if (rotationLock) {
|
} else if (rotationLock) {
|
||||||
|
_portraitOrientationListener?.disableListener()
|
||||||
|
_landscapeOrientationListener?.disableListener()
|
||||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LOCKED
|
||||||
} else {
|
} else {
|
||||||
|
_portraitOrientationListener?.disableListener()
|
||||||
|
_landscapeOrientationListener?.disableListener()
|
||||||
a.requestedOrientation = if (isReversePortraitAllowed) {
|
a.requestedOrientation = if (isReversePortraitAllowed) {
|
||||||
ActivityInfo.SCREEN_ORIENTATION_FULL_USER
|
ActivityInfo.SCREEN_ORIENTATION_FULL_USER
|
||||||
} else {
|
} else {
|
||||||
@ -341,6 +387,26 @@ class VideoDetailFragment : MainFragment {
|
|||||||
StatePlayer.instance.onRotationLockChanged.subscribe(this) {
|
StatePlayer.instance.onRotationLockChanged.subscribe(this) {
|
||||||
updateOrientation()
|
updateOrientation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_landscapeOrientationListener = LandscapeOrientationListener(requireContext())
|
||||||
|
{
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
// delay to make sure that the system auto rotate updates
|
||||||
|
delay(300)
|
||||||
|
_lastSetOrientation = Configuration.ORIENTATION_LANDSCAPE
|
||||||
|
updateOrientation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_portraitOrientationListener = PortraitOrientationListener(requireContext())
|
||||||
|
{
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
// delay to make sure that the system auto rotate updates
|
||||||
|
delay(300)
|
||||||
|
_lastSetOrientation = Configuration.ORIENTATION_PORTRAIT
|
||||||
|
updateOrientation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return _view!!;
|
return _view!!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,6 +508,9 @@ class VideoDetailFragment : MainFragment {
|
|||||||
SettingsActivity.settingsActivityClosed.remove(this)
|
SettingsActivity.settingsActivityClosed.remove(this)
|
||||||
StatePlayer.instance.onRotationLockChanged.remove(this)
|
StatePlayer.instance.onRotationLockChanged.remove(this)
|
||||||
|
|
||||||
|
_landscapeOrientationListener?.disableListener()
|
||||||
|
_portraitOrientationListener?.disableListener()
|
||||||
|
|
||||||
_viewDetail?.let {
|
_viewDetail?.let {
|
||||||
_viewDetail = null;
|
_viewDetail = null;
|
||||||
it.onDestroy();
|
it.onDestroy();
|
||||||
@ -535,3 +604,65 @@ class VideoDetailFragment : MainFragment {
|
|||||||
//TODO: Determine if encapsulated would be readable enough
|
//TODO: Determine if encapsulated would be readable enough
|
||||||
//endregion
|
//endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LandscapeOrientationListener(
|
||||||
|
context: Context,
|
||||||
|
private val onLandscapeDetected: () -> Unit
|
||||||
|
) : OrientationEventListener(context) {
|
||||||
|
|
||||||
|
private var isListening = false
|
||||||
|
|
||||||
|
override fun onOrientationChanged(orientation: Int) {
|
||||||
|
if (!isListening) return
|
||||||
|
|
||||||
|
if (orientation in 60..120 || orientation in 240..300) {
|
||||||
|
onLandscapeDetected()
|
||||||
|
disableListener()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enableListener() {
|
||||||
|
if (!isListening) {
|
||||||
|
isListening = true
|
||||||
|
enable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disableListener() {
|
||||||
|
if (isListening) {
|
||||||
|
isListening = false
|
||||||
|
disable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PortraitOrientationListener(
|
||||||
|
context: Context,
|
||||||
|
private val onPortraitDetected: () -> Unit
|
||||||
|
) : OrientationEventListener(context) {
|
||||||
|
|
||||||
|
private var isListening = false
|
||||||
|
|
||||||
|
override fun onOrientationChanged(orientation: Int) {
|
||||||
|
if (!isListening) return
|
||||||
|
|
||||||
|
if (orientation in 0..30 || orientation in 330..360 || orientation in 150..210) {
|
||||||
|
onPortraitDetected()
|
||||||
|
disableListener()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enableListener() {
|
||||||
|
if (!isListening) {
|
||||||
|
isListening = true
|
||||||
|
enable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun disableListener() {
|
||||||
|
if (isListening) {
|
||||||
|
isListening = false
|
||||||
|
disable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -287,8 +287,8 @@
|
|||||||
<string name="planned_content_notifications_description">Schedules discovered planned content as notifications, resulting in more accurate notifications for this content.</string>
|
<string name="planned_content_notifications_description">Schedules discovered planned content as notifications, resulting in more accurate notifications for this content.</string>
|
||||||
<string name="attempt_to_utilize_byte_ranges">Attempt to utilize byte ranges</string>
|
<string name="attempt_to_utilize_byte_ranges">Attempt to utilize byte ranges</string>
|
||||||
<string name="auto_update">Auto Update</string>
|
<string name="auto_update">Auto Update</string>
|
||||||
<string name="force_allow_full_screen_rotation">Force Allow Full Screen Rotation</string>
|
<string name="force_enable_auto_rotate_in_full_screen">Force Enable Auto-Rotate In Full-Screen Mode</string>
|
||||||
<string name="force_allow_full_screen_rotation_description">Allow auto-rotation between the two landscape orientations even when you disable auto-rotate at the system level.</string>
|
<string name="force_enable_auto_rotate_in_full_screen_description">Force enable auto-rotation between the two landscape orientations in full-screen mode, even when you disable auto-rotate at the system level.</string>
|
||||||
<string name="simplify_sources">Simplify sources</string>
|
<string name="simplify_sources">Simplify sources</string>
|
||||||
<string name="simplify_sources_description">Deduplicate sources by resolution so that only more relevant sources are visible.</string>
|
<string name="simplify_sources_description">Deduplicate sources by resolution so that only more relevant sources are visible.</string>
|
||||||
<string name="automatic_backup">Automatic Backup</string>
|
<string name="automatic_backup">Automatic Backup</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user