mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
feat (player): optional rotate button in player and setting to enable auto rotate based on video orientation (#813)
Co-authored-by: coxju <coxju>
This commit is contained in:
parent
db91552f39
commit
a5f7920bca
8 changed files with 144 additions and 9 deletions
|
@ -75,6 +75,7 @@ private const val SUBTITLE_DELAY_BUNDLE_KEY = "subtitle_delay"
|
||||||
|
|
||||||
// All the UI Logic for the player
|
// All the UI Logic for the player
|
||||||
open class FullScreenPlayer : AbstractPlayerFragment() {
|
open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
|
private var isVerticalOrientation: Boolean = false
|
||||||
protected open var lockRotation = true
|
protected open var lockRotation = true
|
||||||
protected open var isFullScreenPlayer = true
|
protected open var isFullScreenPlayer = true
|
||||||
protected open var isTv = false
|
protected open var isTv = false
|
||||||
|
@ -111,6 +112,8 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
protected var playerResizeEnabled = false
|
protected var playerResizeEnabled = false
|
||||||
protected var doubleTapEnabled = false
|
protected var doubleTapEnabled = false
|
||||||
protected var doubleTapPauseEnabled = true
|
protected var doubleTapPauseEnabled = true
|
||||||
|
protected var playerRotateEnabled = false
|
||||||
|
protected var autoPlayerRotateEnabled = false
|
||||||
|
|
||||||
protected var subtitleDelay
|
protected var subtitleDelay
|
||||||
set(value) = try {
|
set(value) = try {
|
||||||
|
@ -286,6 +289,38 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
player.getCurrentPreferredSubtitle() == null
|
player.getCurrentPreferredSubtitle() == null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun restoreOrientationWithSensor(activity: Activity){
|
||||||
|
val currentOrientation = activity.resources.configuration.orientation
|
||||||
|
var orientation = 0
|
||||||
|
when (currentOrientation) {
|
||||||
|
Configuration.ORIENTATION_LANDSCAPE ->
|
||||||
|
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||||
|
|
||||||
|
Configuration.ORIENTATION_SQUARE, Configuration.ORIENTATION_UNDEFINED ->
|
||||||
|
orientation = dynamicOrientation()
|
||||||
|
|
||||||
|
Configuration.ORIENTATION_PORTRAIT ->
|
||||||
|
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|
||||||
|
}
|
||||||
|
activity.requestedOrientation = orientation
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun toggleOrientationWithSensor(activity: Activity){
|
||||||
|
val currentOrientation = activity.resources.configuration.orientation
|
||||||
|
var orientation = 0
|
||||||
|
when (currentOrientation) {
|
||||||
|
Configuration.ORIENTATION_LANDSCAPE ->
|
||||||
|
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|
||||||
|
|
||||||
|
Configuration.ORIENTATION_SQUARE, Configuration.ORIENTATION_UNDEFINED ->
|
||||||
|
orientation = dynamicOrientation()
|
||||||
|
|
||||||
|
Configuration.ORIENTATION_PORTRAIT ->
|
||||||
|
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||||
|
}
|
||||||
|
activity.requestedOrientation = orientation
|
||||||
|
}
|
||||||
|
|
||||||
open fun lockOrientation(activity: Activity) {
|
open fun lockOrientation(activity: Activity) {
|
||||||
val display =
|
val display =
|
||||||
(activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
|
(activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
|
||||||
|
@ -293,24 +328,39 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
val currentOrientation = activity.resources.configuration.orientation
|
val currentOrientation = activity.resources.configuration.orientation
|
||||||
var orientation = 0
|
var orientation = 0
|
||||||
when (currentOrientation) {
|
when (currentOrientation) {
|
||||||
Configuration.ORIENTATION_LANDSCAPE -> orientation =
|
Configuration.ORIENTATION_LANDSCAPE ->
|
||||||
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE else ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
orientation =
|
||||||
|
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90)
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||||
|
else
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE
|
||||||
|
|
||||||
Configuration.ORIENTATION_SQUARE, Configuration.ORIENTATION_UNDEFINED, Configuration.ORIENTATION_PORTRAIT -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
Configuration.ORIENTATION_SQUARE, Configuration.ORIENTATION_UNDEFINED ->
|
||||||
//Configuration.ORIENTATION_PORTRAIT -> orientation =
|
orientation = dynamicOrientation()
|
||||||
// if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_270) ActivityInfo.SCREEN_ORIENTATION_PORTRAIT else ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
|
|
||||||
|
Configuration.ORIENTATION_PORTRAIT ->
|
||||||
|
orientation =
|
||||||
|
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_270)
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
|
else
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT
|
||||||
}
|
}
|
||||||
activity.requestedOrientation = orientation
|
activity.requestedOrientation = orientation
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateOrientation() {
|
private fun updateOrientation(ignoreDynamicOrientation: Boolean = false) {
|
||||||
activity?.apply {
|
activity?.apply {
|
||||||
if(lockRotation) {
|
if(lockRotation) {
|
||||||
if(isLocked) {
|
if(isLocked) {
|
||||||
lockOrientation(this)
|
lockOrientation(this)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
if(ignoreDynamicOrientation){
|
||||||
|
// restore when lock is disabled
|
||||||
|
restoreOrientationWithSensor(this)
|
||||||
|
} else {
|
||||||
|
this.requestedOrientation = dynamicOrientation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -584,7 +634,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
isLocked = !isLocked
|
isLocked = !isLocked
|
||||||
updateOrientation()
|
updateOrientation(true) // set true to ignore auto rotate to stay in current orientation
|
||||||
|
|
||||||
if (isLocked && isShowing) {
|
if (isLocked && isShowing) {
|
||||||
playerBinding?.playerHolder?.postDelayed({
|
playerBinding?.playerHolder?.postDelayed({
|
||||||
|
@ -1326,6 +1376,14 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
ctx.getString(R.string.playback_speed_enabled_key),
|
ctx.getString(R.string.playback_speed_enabled_key),
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
|
playerRotateEnabled = settingsManager.getBoolean(
|
||||||
|
ctx.getString(R.string.rotate_video_key),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
autoPlayerRotateEnabled = settingsManager.getBoolean(
|
||||||
|
ctx.getString(R.string.auto_rotate_video_key),
|
||||||
|
false
|
||||||
|
)
|
||||||
playerResizeEnabled =
|
playerResizeEnabled =
|
||||||
settingsManager.getBoolean(
|
settingsManager.getBoolean(
|
||||||
ctx.getString(R.string.player_resize_enabled_key),
|
ctx.getString(R.string.player_resize_enabled_key),
|
||||||
|
@ -1362,6 +1420,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
playerBinding?.apply {
|
playerBinding?.apply {
|
||||||
playerSpeedBtt.isVisible = playBackSpeedEnabled
|
playerSpeedBtt.isVisible = playBackSpeedEnabled
|
||||||
playerResizeBtt.isVisible = playerResizeEnabled
|
playerResizeBtt.isVisible = playerResizeEnabled
|
||||||
|
playerRotateBtt.isVisible = playerRotateEnabled
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
logError(e)
|
logError(e)
|
||||||
|
@ -1376,6 +1435,11 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
player.handleEvent(CSPlayerEvent.SkipCurrentChapter)
|
player.handleEvent(CSPlayerEvent.SkipCurrentChapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
playerRotateBtt.setOnClickListener {
|
||||||
|
autoHide()
|
||||||
|
toggleRotate()
|
||||||
|
}
|
||||||
|
|
||||||
// init clicks
|
// init clicks
|
||||||
playerResizeBtt.setOnClickListener {
|
playerResizeBtt.setOnClickListener {
|
||||||
autoHide()
|
autoHide()
|
||||||
|
@ -1481,4 +1545,28 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
|
||||||
logError(e)
|
logError(e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SourceLockedOrientationActivity")
|
||||||
|
private fun toggleRotate() {
|
||||||
|
activity?.let {
|
||||||
|
toggleOrientationWithSensor(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun playerDimensionsLoaded(width: Int, height: Int) {
|
||||||
|
isVerticalOrientation = height > width
|
||||||
|
updateOrientation()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dynamicOrientation(): Int {
|
||||||
|
return if (autoPlayerRotateEnabled) {
|
||||||
|
if (isVerticalOrientation) {
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|
||||||
|
} else {
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE // default orientation
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1237,6 +1237,7 @@ class GeneratorPlayer : FullScreenPlayer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun playerDimensionsLoaded(width: Int, height: Int) {
|
override fun playerDimensionsLoaded(width: Int, height: Int) {
|
||||||
|
super.playerDimensionsLoaded(width, height)
|
||||||
setPlayerDimen(width to height)
|
setPlayerDimen(width to height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
app/src/main/res/drawable/screen_rotation.xml
Normal file
10
app/src/main/res/drawable/screen_rotation.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960"
|
||||||
|
android:tint="?attr/white">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M496,778L182,464Q159,441 159,410Q159,379 182,356L356,182Q379,159 410,159Q441,159 464,182L778,496Q801,519 801,550Q801,581 778,604L604,778Q581,801 550,801Q519,801 496,778ZM550,720Q550,720 550,720Q550,720 550,720L720,550Q720,550 720,550Q720,550 720,550L410,240Q410,240 410,240Q410,240 410,240L240,410Q240,410 240,410Q240,410 240,410L550,720ZM480,960Q381,960 293.5,922.5Q206,885 140.5,819.5Q75,754 37.5,666.5Q0,579 0,480L80,480Q80,551 104,616Q128,681 170.5,733Q213,785 272,821.5Q331,858 401,873L296,768L352,712L588,948Q562,954 534.5,957Q507,960 480,960ZM880,480Q880,409 856,344Q832,279 789.5,227Q747,175 688,138.5Q629,102 559,87L664,192L608,248L372,12Q398,6 425.5,3Q453,0 480,0Q579,0 666.5,37.5Q754,75 819.5,140.5Q885,206 922.5,293.5Q960,381 960,480L880,480ZM480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Z"/>
|
||||||
|
</vector>
|
|
@ -550,10 +550,19 @@
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/player_resize_btt"
|
android:id="@+id/player_rotate_btt"
|
||||||
style="@style/VideoButton"
|
style="@style/VideoButton"
|
||||||
android:nextFocusLeft="@id/player_lock"
|
android:nextFocusLeft="@id/player_lock"
|
||||||
|
|
||||||
|
android:nextFocusRight="@id/player_resize_btt"
|
||||||
|
android:text="@string/rotate_video"
|
||||||
|
app:icon="@drawable/screen_rotation" />
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_resize_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:nextFocusLeft="@id/player_rotate_btt"
|
||||||
|
|
||||||
android:nextFocusRight="@id/player_speed_btt"
|
android:nextFocusRight="@id/player_speed_btt"
|
||||||
android:text="@string/video_aspect_ratio_resize"
|
android:text="@string/video_aspect_ratio_resize"
|
||||||
app:icon="@drawable/ic_baseline_aspect_ratio_24" />
|
app:icon="@drawable/ic_baseline_aspect_ratio_24" />
|
||||||
|
|
|
@ -638,6 +638,11 @@
|
||||||
app:icon="@drawable/video_locked" />
|
app:icon="@drawable/video_locked" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_rotate_btt"
|
||||||
|
style="@style/VideoButton"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/player_skip_op"
|
android:id="@+id/player_skip_op"
|
||||||
style="@style/VideoButtonTV"
|
style="@style/VideoButtonTV"
|
||||||
|
|
|
@ -534,6 +534,10 @@
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
android:paddingBottom="10dp">
|
android:paddingBottom="10dp">
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/player_rotate_btt"
|
||||||
|
style="@style/VideoButton"/>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/player_lock"
|
android:id="@+id/player_lock"
|
||||||
style="@style/VideoButton"
|
style="@style/VideoButton"
|
||||||
|
|
|
@ -734,4 +734,10 @@
|
||||||
<string name="logged_account" formatted="true">Logged in as %s</string>
|
<string name="logged_account" formatted="true">Logged in as %s</string>
|
||||||
<string name="skip_startup_account_select_pref">Skip account selection at startup</string>
|
<string name="skip_startup_account_select_pref">Skip account selection at startup</string>
|
||||||
<string name="use_default_account">Use Default Account</string>
|
<string name="use_default_account">Use Default Account</string>
|
||||||
|
<string name="rotate_video">Rotate</string>
|
||||||
|
<string name="rotate_video_key">rotate_video_key</string>
|
||||||
|
<string name="rotate_video_desc">Display a toggle button for screen orientation</string>
|
||||||
|
<string name="auto_rotate_video_key">auto_rotate_video_key</string>
|
||||||
|
<string name="auto_rotate_video_desc">Enable automatic switching of screen orientation based on video orientation</string>
|
||||||
|
<string name="auto_rotate_video">Auto rotate</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -86,6 +86,18 @@
|
||||||
app:defaultValue="true"
|
app:defaultValue="true"
|
||||||
android:summary="@string/enable_skip_op_from_database_des"
|
android:summary="@string/enable_skip_op_from_database_des"
|
||||||
app:key="@string/enable_skip_op_from_database" />
|
app:key="@string/enable_skip_op_from_database" />
|
||||||
|
<SwitchPreference
|
||||||
|
android:icon="@drawable/screen_rotation"
|
||||||
|
android:title="@string/rotate_video"
|
||||||
|
app:defaultValue="false"
|
||||||
|
android:summary="@string/rotate_video_desc"
|
||||||
|
app:key="@string/rotate_video_key" />
|
||||||
|
<SwitchPreference
|
||||||
|
android:icon="@drawable/screen_rotation"
|
||||||
|
android:title="@string/auto_rotate_video"
|
||||||
|
app:defaultValue="false"
|
||||||
|
android:summary="@string/auto_rotate_video_desc"
|
||||||
|
app:key="@string/auto_rotate_video_key" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
|
Loading…
Reference in a new issue