mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-17 13:32:38 +02:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eaeaf3538f | |||
| 85e381a85e | |||
| 1b7ee8231b | |||
| 1b8b8f5738 | |||
| 53df19b477 | |||
| ccf21b7580 | |||
| 4189d62a57 | |||
| 9a3e3af614 | |||
| f7187400dc | |||
| f55a7f0a7b | |||
| d6d35a645e | |||
| e719dcc7f5 | |||
| bc5bc5450c | |||
| f4bade0c2e | |||
| 9be59c674d | |||
| a1dec23c20 | |||
| ed926c4e37 | |||
| ab360ed6f6 | |||
| 569ba3d651 | |||
| 60fe28c2fe |
@@ -82,3 +82,9 @@
|
||||
[submodule "app/src/stable/assets/sources/dailymotion"]
|
||||
path = app/src/stable/assets/sources/dailymotion
|
||||
url = ../plugins/dailymotion.git
|
||||
[submodule "app/src/stable/assets/sources/apple-podcast"]
|
||||
path = app/src/stable/assets/sources/apple-podcast
|
||||
url = ../plugins/apple-podcasts.git
|
||||
[submodule "app/src/unstable/assets/sources/apple-podcasts"]
|
||||
path = app/src/unstable/assets/sources/apple-podcasts
|
||||
url = ../plugins/apple-podcasts.git
|
||||
|
||||
@@ -415,8 +415,8 @@ class Settings : FragmentedStorageFileJson() {
|
||||
@FormField(R.string.simplify_sources, FieldForm.TOGGLE, R.string.simplify_sources_description, 4)
|
||||
var simplifySources: Boolean = true;
|
||||
|
||||
@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
|
||||
@FormField(R.string.always_allow_reverse_landscape_auto_rotate, FieldForm.TOGGLE, R.string.always_allow_reverse_landscape_auto_rotate_description, 5)
|
||||
var alwaysAllowReverseLandscapeAutoRotate: Boolean = true
|
||||
|
||||
@FormField(R.string.background_behavior, FieldForm.DROPDOWN, -1, 6)
|
||||
@DropdownFieldOptionsId(R.array.player_background_behavior)
|
||||
|
||||
@@ -122,7 +122,11 @@ class SyncPairActivity : AppCompatActivity() {
|
||||
} catch (e: Throwable) {
|
||||
withContext(Dispatchers.Main) {
|
||||
_layoutPairingError.visibility = View.VISIBLE
|
||||
_textError.text = e.message
|
||||
if(e.message == "Failed to connect") {
|
||||
_textError.text = "Failed to connect.\n\nThis may be due to not being on the same network, due to firewall, or vpn.\nSync currently operates only over local direct connections."
|
||||
}
|
||||
else
|
||||
_textError.text = e.message
|
||||
_layoutPairing.visibility = View.GONE
|
||||
Logger.e(TAG, "Failed to pair", e)
|
||||
}
|
||||
|
||||
+61
-35
@@ -1,10 +1,14 @@
|
||||
package com.futo.platformplayer.fragment.mainactivity.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.database.ContentObserver
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import android.view.OrientationEventListener
|
||||
import android.view.View
|
||||
@@ -84,8 +88,7 @@ class VideoDetailFragment() : MainFragment() {
|
||||
|
||||
private var _landscapeOrientationListener: LandscapeOrientationListener? = null
|
||||
private var _portraitOrientationListener: PortraitOrientationListener? = null
|
||||
private var _lastSetOrientation: Int = Configuration.ORIENTATION_UNDEFINED
|
||||
private var _ignoreNextNewOrientation = false
|
||||
private var _autoRotateObserver: AutoRotateObserver? = null
|
||||
|
||||
fun nextVideo() {
|
||||
_viewDetail?.nextVideo(true, true, true);
|
||||
@@ -96,32 +99,27 @@ class VideoDetailFragment() : MainFragment() {
|
||||
}
|
||||
|
||||
private fun isSmallWindow(): Boolean {
|
||||
return min(
|
||||
resources.configuration.screenWidthDp,
|
||||
resources.configuration.screenHeightDp
|
||||
) < resources.getInteger(R.integer.column_width_dp) * 2
|
||||
return resources.configuration.smallestScreenWidthDp < resources.getInteger(R.integer.column_width_dp) * 2
|
||||
}
|
||||
|
||||
private fun isAutoRotateEnabled(): Boolean {
|
||||
return android.provider.Settings.System.getInt(
|
||||
context?.contentResolver,
|
||||
android.provider.Settings.System.ACCELEROMETER_ROTATION, 0
|
||||
) == 1
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
||||
val isLandscapeVideo: Boolean = _viewDetail?.isLandscapeVideo() ?: false
|
||||
|
||||
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 (
|
||||
isSmallWindow
|
||||
&& newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
&& !isFullscreen
|
||||
&& !isInPictureInPicture
|
||||
&& state == State.MAXIMIZED
|
||||
) {
|
||||
_viewDetail?.setFullscreen(true)
|
||||
@@ -130,7 +128,6 @@ class VideoDetailFragment() : MainFragment() {
|
||||
&& isFullscreen
|
||||
&& !Settings.instance.playback.fullscreenPortrait
|
||||
&& newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
&& temp == Configuration.ORIENTATION_LANDSCAPE
|
||||
&& isLandscapeVideo
|
||||
) {
|
||||
_viewDetail?.setFullscreen(false)
|
||||
@@ -159,6 +156,8 @@ class VideoDetailFragment() : MainFragment() {
|
||||
) {
|
||||
_viewDetail?.setFullscreen(true)
|
||||
}
|
||||
|
||||
updateOrientation()
|
||||
}
|
||||
|
||||
fun updateOrientation() {
|
||||
@@ -166,25 +165,20 @@ class VideoDetailFragment() : MainFragment() {
|
||||
val isFullScreenPortraitAllowed = Settings.instance.playback.fullscreenPortrait
|
||||
val isReversePortraitAllowed = Settings.instance.playback.reversePortrait
|
||||
val rotationLock = StatePlayer.instance.rotationLock
|
||||
val alwaysAllowReverseLandscapeAutoRotate = Settings.instance.playback.alwaysAllowReverseLandscapeAutoRotate
|
||||
|
||||
val isLandscapeVideo: Boolean = _viewDetail?.isLandscapeVideo() ?: false
|
||||
val isLandscapeVideo: Boolean = _viewDetail?.isLandscapeVideo() ?: true
|
||||
|
||||
val isSmallWindow = isSmallWindow()
|
||||
|
||||
val autoRotateEnabled = android.provider.Settings.System.getInt(
|
||||
context?.contentResolver,
|
||||
android.provider.Settings.System.ACCELEROMETER_ROTATION, 0
|
||||
) == 1
|
||||
val autoRotateEnabled = isAutoRotateEnabled()
|
||||
|
||||
// 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 && _lastSetOrientation != Configuration.ORIENTATION_LANDSCAPE && !rotationLock && isLandscapeVideo) {
|
||||
if (Settings.instance.playback.forceAllowFullScreenRotation) {
|
||||
if (isSmallWindow && isFullscreen && !isFullScreenPortraitAllowed && resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT && !rotationLock && isLandscapeVideo) {
|
||||
if (alwaysAllowReverseLandscapeAutoRotate){
|
||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
} else {
|
||||
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
|
||||
@@ -192,19 +186,21 @@ class VideoDetailFragment() : MainFragment() {
|
||||
_landscapeOrientationListener?.enableListener()
|
||||
}
|
||||
}
|
||||
// For small windows if always all reverse landscape then we'll lock the orientation to landscape when system auto-rotate is off to make sure that locking
|
||||
// and unlockiung in the player settings keep orientation in landscape
|
||||
else if (isSmallWindow && isFullscreen && !isFullScreenPortraitAllowed && alwaysAllowReverseLandscapeAutoRotate && !rotationLock && isLandscapeVideo && !autoRotateEnabled) {
|
||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
}
|
||||
// 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 && _lastSetOrientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
// only do this if auto-rotate is on portrait is forced when leaving full screen for autorotate off
|
||||
else if (isSmallWindow && !isMinimizingFromFullScreen && !isFullscreen && state == State.MAXIMIZED && resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
||||
@SuppressLint("SourceLockedOrientationActivity")
|
||||
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) {
|
||||
_portraitOrientationListener?.disableListener()
|
||||
@@ -395,7 +391,6 @@ class VideoDetailFragment() : MainFragment() {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
// delay to make sure that the system auto rotate updates
|
||||
delay(delayBeforeRemoveRotationLock)
|
||||
_lastSetOrientation = Configuration.ORIENTATION_LANDSCAPE
|
||||
updateOrientation()
|
||||
}
|
||||
}
|
||||
@@ -404,10 +399,13 @@ class VideoDetailFragment() : MainFragment() {
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
// delay to make sure that the system auto rotate updates
|
||||
delay(delayBeforeRemoveRotationLock)
|
||||
_lastSetOrientation = Configuration.ORIENTATION_PORTRAIT
|
||||
updateOrientation()
|
||||
}
|
||||
}
|
||||
_autoRotateObserver = AutoRotateObserver(requireContext(), Handler(Looper.getMainLooper())) {
|
||||
updateOrientation()
|
||||
}
|
||||
_autoRotateObserver?.startObserving()
|
||||
|
||||
return _view!!;
|
||||
}
|
||||
@@ -512,6 +510,7 @@ class VideoDetailFragment() : MainFragment() {
|
||||
|
||||
_landscapeOrientationListener?.disableListener()
|
||||
_portraitOrientationListener?.disableListener()
|
||||
_autoRotateObserver?.stopObserving()
|
||||
|
||||
_viewDetail?.let {
|
||||
_viewDetail = null;
|
||||
@@ -584,6 +583,11 @@ class VideoDetailFragment() : MainFragment() {
|
||||
showSystemUI()
|
||||
}
|
||||
|
||||
// temporarily force the device to portrait if auto-rotate is disabled to prevent landscape when exiting full screen on a small device
|
||||
// @SuppressLint("SourceLockedOrientationActivity")
|
||||
// if (!isFullscreen && isSmallWindow() && !isAutoRotateEnabled() && !isMinimizingFromFullScreen) {
|
||||
// activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|
||||
// }
|
||||
updateOrientation();
|
||||
_view?.allowMotion = !fullscreen;
|
||||
}
|
||||
@@ -668,3 +672,25 @@ class PortraitOrientationListener(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AutoRotateObserver(context: Context, handler: Handler, private val onAutoRotateChanged: () -> Unit) : ContentObserver(handler) {
|
||||
private val contentResolver = context.contentResolver
|
||||
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
super.onChange(selfChange)
|
||||
|
||||
onAutoRotateChanged()
|
||||
}
|
||||
|
||||
fun startObserving() {
|
||||
contentResolver.registerContentObserver(
|
||||
android.provider.Settings.System.getUriFor(android.provider.Settings.System.ACCELEROMETER_ROTATION),
|
||||
false,
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
fun stopObserving() {
|
||||
contentResolver.unregisterContentObserver(this)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -2384,8 +2384,13 @@ class VideoDetailView : ConstraintLayout {
|
||||
}
|
||||
|
||||
fun isLandscapeVideo(): Boolean? {
|
||||
val videoSourceWidth = _player.exoPlayer?.player?.videoSize?.width
|
||||
val videoSourceHeight = _player.exoPlayer?.player?.videoSize?.height
|
||||
var videoSourceWidth = _player.exoPlayer?.player?.videoSize?.width
|
||||
var videoSourceHeight = _player.exoPlayer?.player?.videoSize?.height
|
||||
|
||||
if (video?.video?.videoSources?.isNotEmpty() == true && (videoSourceWidth == null || videoSourceHeight == null || videoSourceWidth == 0 || videoSourceHeight == 0)) {
|
||||
videoSourceWidth = video?.video?.videoSources!![0].width
|
||||
videoSourceHeight = video?.video?.videoSources!![0].height
|
||||
}
|
||||
|
||||
return if (videoSourceWidth == null || videoSourceHeight == null || videoSourceWidth == 0 || videoSourceHeight == 0){
|
||||
null
|
||||
|
||||
@@ -592,11 +592,6 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
fun setFullScreen(fullScreen: Boolean) {
|
||||
// prevent fullscreen before the video has loaded to make sure we know whether it's a vertical or horizontal video
|
||||
if(exoPlayer?.player?.videoSize?.height ?: 0 == 0 && fullScreen){
|
||||
return
|
||||
}
|
||||
|
||||
updateRotateLock()
|
||||
|
||||
if (isFullScreen == fullScreen) {
|
||||
|
||||
@@ -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="attempt_to_utilize_byte_ranges">Attempt to utilize byte ranges</string>
|
||||
<string name="auto_update">Auto Update</string>
|
||||
<string name="force_enable_auto_rotate_in_full_screen">Force Enable Auto-Rotate In Full-Screen Mode</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="always_allow_reverse_landscape_auto_rotate">Always allow reverse landscape auto-rotate</string>
|
||||
<string name="always_allow_reverse_landscape_auto_rotate_description">There will always be auto-rotation between the two landscape orientations in full-screen mode, even when you disable auto-rotate in system settings.</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="automatic_backup">Automatic Backup</string>
|
||||
|
||||
+1
Submodule app/src/stable/assets/sources/apple-podcast added at f79c7141bc
Submodule app/src/stable/assets/sources/bilibili updated: 258c71e4f5...764316618b
Submodule app/src/stable/assets/sources/odysee updated: 8ddb2e2f15...5186dcd6c2
Submodule app/src/stable/assets/sources/soundcloud updated: 9a10cb8e78...90bceac198
Submodule app/src/stable/assets/sources/youtube updated: 59d694b619...1be5025b47
@@ -12,7 +12,8 @@
|
||||
"cf8ea74d-ad9b-489e-a083-539b6aa8648c": "sources/bilibili/build/BiliBiliConfig.json",
|
||||
"4e365633-6d3f-4267-8941-fdc36631d813": "sources/spotify/build/SpotifyConfig.json",
|
||||
"9c87e8db-e75d-48f4-afe5-2d203d4b95c5": "sources/dailymotion/build/DailymotionConfig.json",
|
||||
"e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json"
|
||||
"e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json",
|
||||
"89ae4889-0420-4d16-ad6c-19c776b28f99": "sources/apple-podcasts/ApplePodcastsConfig.json"
|
||||
},
|
||||
"SOURCES_EMBEDDED_DEFAULT": [
|
||||
"35ae969a-a7db-11ed-afa1-0242ac120002"
|
||||
|
||||
+1
Submodule app/src/unstable/assets/sources/apple-podcasts added at f79c7141bc
Submodule app/src/unstable/assets/sources/bilibili updated: 258c71e4f5...764316618b
Submodule app/src/unstable/assets/sources/odysee updated: 8ddb2e2f15...5186dcd6c2
Submodule app/src/unstable/assets/sources/soundcloud updated: 9a10cb8e78...90bceac198
Submodule app/src/unstable/assets/sources/youtube updated: 59d694b619...1be5025b47
@@ -12,7 +12,8 @@
|
||||
"cf8ea74d-ad9b-489e-a083-539b6aa8648c": "sources/bilibili/build/BiliBiliConfig.json",
|
||||
"4e365633-6d3f-4267-8941-fdc36631d813": "sources/spotify/build/SpotifyConfig.json",
|
||||
"9c87e8db-e75d-48f4-afe5-2d203d4b95c5": "sources/dailymotion/build/DailymotionConfig.json",
|
||||
"e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json"
|
||||
"e8b1ad5f-0c6d-497d-a5fa-0a785a16d902": "sources/bitchute/BitchuteConfig.json",
|
||||
"89ae4889-0420-4d16-ad6c-19c776b28f99": "sources/apple-podcasts/ApplePodcastsConfig.json"
|
||||
},
|
||||
"SOURCES_EMBEDDED_DEFAULT": [
|
||||
"35ae969a-a7db-11ed-afa1-0242ac120002"
|
||||
|
||||
+1
-1
Submodule dep/futopay updated: 829baef9f0...21afe43dff
Reference in New Issue
Block a user