mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-03 14:50:49 +00:00
Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay
This commit is contained in:
commit
c3d7df166b
10 changed files with 158 additions and 88 deletions
|
@ -478,15 +478,22 @@ class Settings : FragmentedStorageFileJson() {
|
||||||
@DropdownFieldOptionsId(R.array.rotation_zone)
|
@DropdownFieldOptionsId(R.array.rotation_zone)
|
||||||
var rotationZone: Int = 2;
|
var rotationZone: Int = 2;
|
||||||
|
|
||||||
@FormField(R.string.prefer_webm, FieldForm.TOGGLE, R.string.prefer_webm_description, 16)
|
@FormField(R.string.stability_threshold_time, FieldForm.DROPDOWN, R.string.stability_threshold_time_description, 16)
|
||||||
|
@DropdownFieldOptionsId(R.array.rotation_threshold_time)
|
||||||
|
var stabilityThresholdTime: Int = 1;
|
||||||
|
|
||||||
|
@FormField(R.string.full_autorotate_lock, FieldForm.TOGGLE, R.string.full_autorotate_lock_description, 17)
|
||||||
|
var fullAutorotateLock: Boolean = false;
|
||||||
|
|
||||||
|
@FormField(R.string.prefer_webm, FieldForm.TOGGLE, R.string.prefer_webm_description, 18)
|
||||||
var preferWebmVideo: Boolean = false;
|
var preferWebmVideo: Boolean = false;
|
||||||
@FormField(R.string.prefer_webm_audio, FieldForm.TOGGLE, R.string.prefer_webm_audio_description, 17)
|
@FormField(R.string.prefer_webm_audio, FieldForm.TOGGLE, R.string.prefer_webm_audio_description, 19)
|
||||||
var preferWebmAudio: Boolean = false;
|
var preferWebmAudio: Boolean = false;
|
||||||
|
|
||||||
@FormField(R.string.allow_under_cutout, FieldForm.TOGGLE, R.string.allow_under_cutout_description, 18)
|
@FormField(R.string.allow_under_cutout, FieldForm.TOGGLE, R.string.allow_under_cutout_description, 20)
|
||||||
var allowVideoToGoUnderCutout: Boolean = true;
|
var allowVideoToGoUnderCutout: Boolean = true;
|
||||||
|
|
||||||
@FormField(R.string.autoplay, FieldForm.TOGGLE, R.string.autoplay, 19)
|
@FormField(R.string.autoplay, FieldForm.TOGGLE, R.string.autoplay, 21)
|
||||||
var autoplay: Boolean = false;
|
var autoplay: Boolean = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import com.futo.platformplayer.constructs.Event1
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
@ -17,13 +18,23 @@ class SimpleOrientationListener(
|
||||||
) {
|
) {
|
||||||
private var lastOrientation: Int = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
private var lastOrientation: Int = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||||
private var lastStableOrientation: Int = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
private var lastStableOrientation: Int = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||||
private val stabilityThresholdTime = 500L
|
private var _currentJob: Job? = null
|
||||||
|
|
||||||
val onOrientationChanged = Event1<Int>()
|
val onOrientationChanged = Event1<Int>()
|
||||||
|
|
||||||
private val orientationListener = object : OrientationEventListener(activity, SensorManager.SENSOR_DELAY_UI) {
|
private val orientationListener = object : OrientationEventListener(activity, SensorManager.SENSOR_DELAY_UI) {
|
||||||
override fun onOrientationChanged(orientation: Int) {
|
override fun onOrientationChanged(orientation: Int) {
|
||||||
//val rotationZone = 45
|
//val rotationZone = 45
|
||||||
|
val stabilityThresholdTime = when (Settings.instance.playback.stabilityThresholdTime) {
|
||||||
|
0 -> 100L
|
||||||
|
1 -> 500L
|
||||||
|
2 -> 750L
|
||||||
|
3 -> 1000L
|
||||||
|
4 -> 1500L
|
||||||
|
5 -> 2000L
|
||||||
|
else -> 500L
|
||||||
|
}
|
||||||
|
|
||||||
val rotationZone = when (Settings.instance.playback.rotationZone) {
|
val rotationZone = when (Settings.instance.playback.rotationZone) {
|
||||||
0 -> 15
|
0 -> 15
|
||||||
1 -> 30
|
1 -> 30
|
||||||
|
@ -42,7 +53,8 @@ class SimpleOrientationListener(
|
||||||
if (newOrientation != lastStableOrientation) {
|
if (newOrientation != lastStableOrientation) {
|
||||||
lastStableOrientation = newOrientation
|
lastStableOrientation = newOrientation
|
||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
_currentJob?.cancel()
|
||||||
|
_currentJob = lifecycleScope.launch(Dispatchers.Main) {
|
||||||
try {
|
try {
|
||||||
delay(stabilityThresholdTime)
|
delay(stabilityThresholdTime)
|
||||||
if (newOrientation == lastStableOrientation) {
|
if (newOrientation == lastStableOrientation) {
|
||||||
|
@ -63,6 +75,8 @@ class SimpleOrientationListener(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopListening() {
|
fun stopListening() {
|
||||||
|
_currentJob?.cancel()
|
||||||
|
_currentJob = null
|
||||||
orientationListener.disable()
|
orientationListener.disable()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -310,19 +310,6 @@ class MenuBottomBarFragment : MainActivityFragment() {
|
||||||
if (!StatePayment.instance.hasPaid) {
|
if (!StatePayment.instance.hasPaid) {
|
||||||
newCurrentButtonDefinitions.add(ButtonDefinition(98, R.drawable.ic_paid, R.drawable.ic_paid_filled, R.string.buy, canToggle = false, { it.currentMain is BuyFragment }, { it.navigate<BuyFragment>() }))
|
newCurrentButtonDefinitions.add(ButtonDefinition(98, R.drawable.ic_paid, R.drawable.ic_paid_filled, R.string.buy, canToggle = false, { it.currentMain is BuyFragment }, { it.navigate<BuyFragment>() }))
|
||||||
}
|
}
|
||||||
newCurrentButtonDefinitions.add(ButtonDefinition(97, R.drawable.ic_quiz, R.drawable.ic_quiz_fill, R.string.faq, canToggle = false, { false }, {
|
|
||||||
it.navigate<BrowserFragment>(Settings.URL_FAQ);
|
|
||||||
}))
|
|
||||||
newCurrentButtonDefinitions.add(ButtonDefinition(96, R.drawable.ic_disabled_visible, R.drawable.ic_disabled_visible, R.string.privacy_mode, canToggle = false, { false }, {
|
|
||||||
UIDialogs.showDialog(context, R.drawable.ic_disabled_visible_purple, "Privacy Mode",
|
|
||||||
"All requests will be processed anonymously (unauthenticated), playback and history tracking will be disabled.\n\nTap the icon to disable.", null, 0,
|
|
||||||
UIDialogs.Action("Cancel", {
|
|
||||||
StateApp.instance.setPrivacyMode(false);
|
|
||||||
}, UIDialogs.ActionStyle.NONE),
|
|
||||||
UIDialogs.Action("Enable", {
|
|
||||||
StateApp.instance.setPrivacyMode(true);
|
|
||||||
}, UIDialogs.ActionStyle.PRIMARY));
|
|
||||||
}))
|
|
||||||
|
|
||||||
//Add conditional buttons here, when you add a conditional button, be sure to add the register and unregister events for when the button needs to be updated
|
//Add conditional buttons here, when you add a conditional button, be sure to add the register and unregister events for when the button needs to be updated
|
||||||
|
|
||||||
|
@ -379,13 +366,26 @@ class MenuBottomBarFragment : MainActivityFragment() {
|
||||||
}),
|
}),
|
||||||
ButtonDefinition(1, R.drawable.ic_subscriptions, R.drawable.ic_subscriptions_filled, R.string.subscriptions, canToggle = true, { it.currentMain is SubscriptionsFeedFragment }, { it.navigate<SubscriptionsFeedFragment>() }),
|
ButtonDefinition(1, R.drawable.ic_subscriptions, R.drawable.ic_subscriptions_filled, R.string.subscriptions, canToggle = true, { it.currentMain is SubscriptionsFeedFragment }, { it.navigate<SubscriptionsFeedFragment>() }),
|
||||||
ButtonDefinition(2, R.drawable.ic_creators, R.drawable.ic_creators_filled, R.string.creators, canToggle = false, { it.currentMain is CreatorsFragment }, { it.navigate<CreatorsFragment>() }),
|
ButtonDefinition(2, R.drawable.ic_creators, R.drawable.ic_creators_filled, R.string.creators, canToggle = false, { it.currentMain is CreatorsFragment }, { it.navigate<CreatorsFragment>() }),
|
||||||
ButtonDefinition(3, R.drawable.ic_sources, R.drawable.ic_sources_filled, R.string.sources, canToggle = false, { it.currentMain is SourcesFragment }, { it.navigate<SourcesFragment>() }),
|
ButtonDefinition(3, R.drawable.ic_sources, R.drawable.ic_sources_filled, R.string.sources, canToggle = true, { it.currentMain is SourcesFragment }, { it.navigate<SourcesFragment>() }),
|
||||||
ButtonDefinition(4, R.drawable.ic_playlist, R.drawable.ic_playlist_filled, R.string.playlists, canToggle = false, { it.currentMain is PlaylistsFragment }, { it.navigate<PlaylistsFragment>() }),
|
ButtonDefinition(4, R.drawable.ic_playlist, R.drawable.ic_playlist_filled, R.string.playlists, canToggle = false, { it.currentMain is PlaylistsFragment }, { it.navigate<PlaylistsFragment>() }),
|
||||||
ButtonDefinition(5, R.drawable.ic_history, R.drawable.ic_history, R.string.history, canToggle = false, { it.currentMain is HistoryFragment }, { it.navigate<HistoryFragment>() }),
|
ButtonDefinition(5, R.drawable.ic_history, R.drawable.ic_history, R.string.history, canToggle = false, { it.currentMain is HistoryFragment }, { it.navigate<HistoryFragment>() }),
|
||||||
ButtonDefinition(6, R.drawable.ic_download, R.drawable.ic_download, R.string.downloads, canToggle = false, { it.currentMain is DownloadsFragment }, { it.navigate<DownloadsFragment>() }),
|
ButtonDefinition(6, R.drawable.ic_download, R.drawable.ic_download, R.string.downloads, canToggle = false, { it.currentMain is DownloadsFragment }, { it.navigate<DownloadsFragment>() }),
|
||||||
ButtonDefinition(8, R.drawable.ic_chat, R.drawable.ic_chat_filled, R.string.comments, canToggle = true, { it.currentMain is CommentsFragment }, { it.navigate<CommentsFragment>() }),
|
ButtonDefinition(8, R.drawable.ic_chat, R.drawable.ic_chat_filled, R.string.comments, canToggle = true, { it.currentMain is CommentsFragment }, { it.navigate<CommentsFragment>() }),
|
||||||
ButtonDefinition(9, R.drawable.ic_subscriptions, R.drawable.ic_subscriptions_filled, R.string.subscription_group_menu, canToggle = true, { it.currentMain is SubscriptionGroupListFragment }, { it.navigate<SubscriptionGroupListFragment>() }),
|
ButtonDefinition(9, R.drawable.ic_subscriptions, R.drawable.ic_subscriptions_filled, R.string.subscription_group_menu, canToggle = true, { it.currentMain is SubscriptionGroupListFragment }, { it.navigate<SubscriptionGroupListFragment>() }),
|
||||||
ButtonDefinition(10, R.drawable.ic_help_square, R.drawable.ic_help_square_fill, R.string.tutorials, canToggle = true, { it.currentMain is TutorialFragment }, { it.navigate<TutorialFragment>() }),
|
ButtonDefinition(10, R.drawable.ic_help_square, R.drawable.ic_help_square_fill, R.string.tutorials, canToggle = true, { it.currentMain is TutorialFragment }, { it.navigate<TutorialFragment>() }),
|
||||||
|
ButtonDefinition(11, R.drawable.ic_quiz, R.drawable.ic_quiz_fill, R.string.faq, canToggle = true, { false }, {
|
||||||
|
it.navigate<BrowserFragment>(Settings.URL_FAQ)
|
||||||
|
}),
|
||||||
|
ButtonDefinition(12, R.drawable.ic_disabled_visible, R.drawable.ic_disabled_visible, R.string.privacy_mode, canToggle = true, { false }, {
|
||||||
|
UIDialogs.showDialog(it.requireContext(), R.drawable.ic_disabled_visible_purple, "Privacy Mode",
|
||||||
|
"All requests will be processed anonymously (unauthenticated), playback and history tracking will be disabled.\n\nTap the icon to disable.", null, 0,
|
||||||
|
UIDialogs.Action("Cancel", {
|
||||||
|
StateApp.instance.setPrivacyMode(false);
|
||||||
|
}, UIDialogs.ActionStyle.NONE),
|
||||||
|
UIDialogs.Action("Enable", {
|
||||||
|
StateApp.instance.setPrivacyMode(true);
|
||||||
|
}, UIDialogs.ActionStyle.PRIMARY));
|
||||||
|
}),
|
||||||
ButtonDefinition(7, R.drawable.ic_settings, R.drawable.ic_settings_filled, R.string.settings, canToggle = false, { false }, {
|
ButtonDefinition(7, R.drawable.ic_settings, R.drawable.ic_settings_filled, R.string.settings, canToggle = false, { false }, {
|
||||||
val c = it.context ?: return@ButtonDefinition;
|
val c = it.context ?: return@ButtonDefinition;
|
||||||
Logger.i(TAG, "settings preventPictureInPicture()");
|
Logger.i(TAG, "settings preventPictureInPicture()");
|
||||||
|
@ -396,7 +396,6 @@ class MenuBottomBarFragment : MainActivityFragment() {
|
||||||
c.overridePendingTransition(R.anim.slide_in_up, R.anim.slide_darken);
|
c.overridePendingTransition(R.anim.slide_in_up, R.anim.slide_darken);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
//96 is reserved for privacy button
|
|
||||||
//98 is reserved for buy button
|
//98 is reserved for buy button
|
||||||
//99 is reserved for more button
|
//99 is reserved for more button
|
||||||
);
|
);
|
||||||
|
|
|
@ -397,23 +397,43 @@ class SourceDetailFragment : MainFragment() {
|
||||||
UIDialogs.Action("Cancel", {}, UIDialogs.ActionStyle.NONE),
|
UIDialogs.Action("Cancel", {}, UIDialogs.ActionStyle.NONE),
|
||||||
UIDialogs.Action("Login", {
|
UIDialogs.Action("Login", {
|
||||||
LoginActivity.showLogin(StateApp.instance.context, config) {
|
LoginActivity.showLogin(StateApp.instance.context, config) {
|
||||||
|
try {
|
||||||
StatePlugins.instance.setPluginAuth(config.id, it);
|
StatePlugins.instance.setPluginAuth(config.id, it);
|
||||||
reloadSource(config.id);
|
reloadSource(config.id);
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||||
|
context?.let { c -> UIDialogs.showGeneralErrorDialog(c, "Failed to set plugin authentication (loginSource, loginWarning)", e) }
|
||||||
|
}
|
||||||
|
Logger.e(TAG, "Failed to set plugin authentication (loginSource, loginWarning)", e)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}, UIDialogs.ActionStyle.PRIMARY))
|
}, UIDialogs.ActionStyle.PRIMARY))
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
LoginActivity.showLogin(StateApp.instance.context, config) {
|
LoginActivity.showLogin(StateApp.instance.context, config) {
|
||||||
|
try {
|
||||||
StatePlugins.instance.setPluginAuth(config.id, it);
|
StatePlugins.instance.setPluginAuth(config.id, it);
|
||||||
reloadSource(config.id);
|
reloadSource(config.id);
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||||
|
context?.let { c -> UIDialogs.showGeneralErrorDialog(c, "Failed to set plugin authentication (loginSource)", e) }
|
||||||
|
}
|
||||||
|
Logger.e(TAG, "Failed to set plugin authentication (loginSource)", e)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
private fun logoutSource(clear: Boolean = true) {
|
private fun logoutSource(clear: Boolean = true) {
|
||||||
val config = _config ?: return;
|
val config = _config ?: return;
|
||||||
|
|
||||||
|
try {
|
||||||
StatePlugins.instance.setPluginAuth(config.id, null);
|
StatePlugins.instance.setPluginAuth(config.id, null);
|
||||||
reloadSource(config.id);
|
reloadSource(config.id);
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||||
|
context?.let { c -> UIDialogs.showGeneralErrorDialog(c, "Failed to clear plugin authentication", e) }
|
||||||
|
}
|
||||||
|
Logger.e(TAG, "Failed to clear plugin authentication", e)
|
||||||
|
}
|
||||||
|
|
||||||
//TODO: Maybe add a dialog option..
|
//TODO: Maybe add a dialog option..
|
||||||
if(Settings.instance.plugins.clearCookiesOnLogout && clear) {
|
if(Settings.instance.plugins.clearCookiesOnLogout && clear) {
|
||||||
|
|
|
@ -97,6 +97,7 @@ class VideoDetailFragment : MainFragment {
|
||||||
val isMaximized = state == State.MAXIMIZED
|
val isMaximized = state == State.MAXIMIZED
|
||||||
val isFullScreenPortraitAllowed = Settings.instance.playback.fullscreenPortrait;
|
val isFullScreenPortraitAllowed = Settings.instance.playback.fullscreenPortrait;
|
||||||
val bypassRotationPrevention = Settings.instance.other.bypassRotationPrevention;
|
val bypassRotationPrevention = Settings.instance.other.bypassRotationPrevention;
|
||||||
|
val fullAutorotateLock = Settings.instance.playback.fullAutorotateLock
|
||||||
val currentRequestedOrientation = a.requestedOrientation
|
val currentRequestedOrientation = a.requestedOrientation
|
||||||
var currentOrientation = if (_currentOrientation == -1) currentRequestedOrientation else _currentOrientation
|
var currentOrientation = if (_currentOrientation == -1) currentRequestedOrientation else _currentOrientation
|
||||||
if (currentOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT && !Settings.instance.playback.reversePortrait)
|
if (currentOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT && !Settings.instance.playback.reversePortrait)
|
||||||
|
@ -105,6 +106,7 @@ class VideoDetailFragment : MainFragment {
|
||||||
val isAutoRotate = Settings.instance.playback.isAutoRotate()
|
val isAutoRotate = Settings.instance.playback.isAutoRotate()
|
||||||
val isFs = isFullscreen
|
val isFs = isFullscreen
|
||||||
|
|
||||||
|
if (fullAutorotateLock) {
|
||||||
if (isFs && isMaximized) {
|
if (isFs && isMaximized) {
|
||||||
if (isFullScreenPortraitAllowed) {
|
if (isFullScreenPortraitAllowed) {
|
||||||
if (isAutoRotate) {
|
if (isAutoRotate) {
|
||||||
|
@ -124,8 +126,27 @@ class VideoDetailFragment : MainFragment {
|
||||||
} else {
|
} else {
|
||||||
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (isFs && isMaximized) {
|
||||||
|
if (isFullScreenPortraitAllowed) {
|
||||||
|
a.requestedOrientation = currentOrientation
|
||||||
|
} else if (currentOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || currentOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
|
||||||
|
a.requestedOrientation = currentOrientation
|
||||||
|
} else if (currentRequestedOrientation == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE || currentRequestedOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
|
||||||
|
//Don't change anything
|
||||||
|
} else {
|
||||||
|
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
|
||||||
|
}
|
||||||
|
} else if (bypassRotationPrevention) {
|
||||||
|
a.requestedOrientation = currentOrientation
|
||||||
|
} else if (currentOrientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT || currentOrientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {
|
||||||
|
a.requestedOrientation = currentOrientation
|
||||||
|
} else {
|
||||||
|
a.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log.i(TAG, "updateOrientation (isFs = ${isFs}, currentOrientation = ${currentOrientation}, currentRequestedOrientation = ${currentRequestedOrientation}, isMaximized = ${isMaximized}, isAutoRotate = ${isAutoRotate}, isFullScreenPortraitAllowed = ${isFullScreenPortraitAllowed}) resulted in requested orientation ${activity?.requestedOrientation}");
|
Log.i(TAG, "updateOrientation (isFs = ${isFs}, currentOrientation = ${currentOrientation}, fullAutorotateLock = ${fullAutorotateLock}, currentRequestedOrientation = ${currentRequestedOrientation}, isMaximized = ${isMaximized}, isAutoRotate = ${isAutoRotate}, isFullScreenPortraitAllowed = ${isFullScreenPortraitAllowed}) resulted in requested orientation ${activity?.requestedOrientation}");
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
|
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
|
||||||
|
|
|
@ -2360,20 +2360,11 @@ class VideoDetailView : ConstraintLayout {
|
||||||
_layoutRecommended.visibility = View.VISIBLE
|
_layoutRecommended.visibility = View.VISIBLE
|
||||||
_commentsList.clear()
|
_commentsList.clear()
|
||||||
|
|
||||||
val url = _url
|
|
||||||
if (url != null) {
|
|
||||||
_layoutRecommended.addView(LoaderView(context).apply {
|
_layoutRecommended.addView(LoaderView(context).apply {
|
||||||
layoutParams = LinearLayout.LayoutParams(60.dp(resources), 60.dp(resources))
|
layoutParams = LinearLayout.LayoutParams(60.dp(resources), 60.dp(resources))
|
||||||
start()
|
start()
|
||||||
})
|
})
|
||||||
_taskLoadRecommendations.run(url)
|
_taskLoadRecommendations.run(null)
|
||||||
} else {
|
|
||||||
_layoutRecommended.addView(TextView(context).apply {
|
|
||||||
layoutParams = LinearLayout.LayoutParams(60.dp(resources), 60.dp(resources))
|
|
||||||
textSize = 12.0f
|
|
||||||
text = "No recommendations found"
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2385,7 +2376,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
|
|
||||||
if (_tabIndex == 2) {
|
if (_tabIndex == 2) {
|
||||||
_layoutRecommended.removeAllViews()
|
_layoutRecommended.removeAllViews()
|
||||||
if (results == null) {
|
if (results == null || results.isEmpty()) {
|
||||||
_layoutRecommended.addView(TextView(context).apply {
|
_layoutRecommended.addView(TextView(context).apply {
|
||||||
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {
|
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply {
|
||||||
setMargins(20.dp(resources), 20.dp(resources), 20.dp(resources), 20.dp(resources))
|
setMargins(20.dp(resources), 20.dp(resources), 20.dp(resources), 20.dp(resources))
|
||||||
|
@ -2767,7 +2758,15 @@ class VideoDetailView : ConstraintLayout {
|
||||||
}
|
}
|
||||||
} else TaskHandler(IPlatformVideoDetails::class.java, {fragment.lifecycleScope});
|
} else TaskHandler(IPlatformVideoDetails::class.java, {fragment.lifecycleScope});
|
||||||
|
|
||||||
private val _taskLoadRecommendations = TaskHandler<String, IPager<IPlatformContent>?>(StateApp.instance.scopeGetter, { video?.getContentRecommendations(StatePlatform.instance.getContentClient(it)) })
|
private val _taskLoadRecommendations = TaskHandler<String?, IPager<IPlatformContent>?>(StateApp.instance.scopeGetter, {
|
||||||
|
video?.let { v ->
|
||||||
|
if (v is VideoLocal) {
|
||||||
|
StatePlatform.instance.getContentRecommendations(v.url)
|
||||||
|
} else {
|
||||||
|
video?.getContentRecommendations(StatePlatform.instance.getContentClient(v.url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
.success { setRecommendations(it?.getResults()?.filter { it is IPlatformVideo }?.map { it as IPlatformVideo }, "No recommendations found") }
|
.success { setRecommendations(it?.getResults()?.filter { it is IPlatformVideo }?.map { it as IPlatformVideo }, "No recommendations found") }
|
||||||
.exception<Throwable> {
|
.exception<Throwable> {
|
||||||
setRecommendations(null, it.message)
|
setRecommendations(null, it.message)
|
||||||
|
|
|
@ -10,6 +10,8 @@ import com.futo.platformplayer.api.media.platforms.js.SourceAuth
|
||||||
import com.futo.platformplayer.api.media.platforms.js.SourceCaptchaData
|
import com.futo.platformplayer.api.media.platforms.js.SourceCaptchaData
|
||||||
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
||||||
import com.futo.platformplayer.api.media.platforms.js.SourcePluginDescriptor
|
import com.futo.platformplayer.api.media.platforms.js.SourcePluginDescriptor
|
||||||
|
import com.futo.platformplayer.fragment.mainactivity.main.SourceDetailFragment
|
||||||
|
import com.futo.platformplayer.fragment.mainactivity.main.SourceDetailFragment.Companion
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.models.ImageVariable
|
import com.futo.platformplayer.models.ImageVariable
|
||||||
import com.futo.platformplayer.stores.FragmentedStorage
|
import com.futo.platformplayer.stores.FragmentedStorage
|
||||||
|
@ -128,7 +130,15 @@ class StatePlugins {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
LoginActivity.showLogin(context, config) {
|
LoginActivity.showLogin(context, config) {
|
||||||
|
try {
|
||||||
StatePlugins.instance.setPluginAuth(config.id, it);
|
StatePlugins.instance.setPluginAuth(config.id, it);
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||||
|
UIDialogs.showGeneralErrorDialog(context, "Failed to set plugin authentication (loginPlugin)", e)
|
||||||
|
}
|
||||||
|
Logger.e(SourceDetailFragment.TAG, "Failed to set plugin authentication (loginPlugin)", e)
|
||||||
|
return@showLogin
|
||||||
|
}
|
||||||
|
|
||||||
StateApp.instance.scope.launch(Dispatchers.IO) {
|
StateApp.instance.scope.launch(Dispatchers.IO) {
|
||||||
StatePlatform.instance.reloadClient(context, id);
|
StatePlatform.instance.reloadClient(context, id);
|
||||||
|
|
|
@ -29,6 +29,14 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent">
|
app:layout_constraintRight_toRightOf="parent">
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_autoplay"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
app:srcCompat="@drawable/autoplay_24px" />
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/button_cast"
|
android:id="@+id/button_cast"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
|
@ -133,20 +141,6 @@
|
||||||
android:scaleType="fitCenter"
|
android:scaleType="fitCenter"
|
||||||
android:layout_marginBottom="18dp" />
|
android:layout_marginBottom="18dp" />
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_autoplay"
|
|
||||||
android:layout_width="55dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:clickable="true"
|
|
||||||
app:srcCompat="@drawable/autoplay_24px"
|
|
||||||
app:layout_constraintRight_toLeftOf="@id/button_fullscreen"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/button_fullscreen"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/button_fullscreen"
|
|
||||||
android:paddingStart="5dp"
|
|
||||||
android:paddingTop="15dp"
|
|
||||||
android:paddingEnd="5dp"
|
|
||||||
android:scaleType="fitCenter"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/text_position"
|
android:id="@+id/text_position"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|
|
@ -57,6 +57,14 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent">
|
app:layout_constraintRight_toRightOf="parent">
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_autoplay"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
app:srcCompat="@drawable/autoplay_24px" />
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/button_cast"
|
android:id="@+id/button_cast"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
|
@ -147,20 +155,6 @@
|
||||||
app:layout_constraintLeft_toRightOf="@id/layout_play_pause"
|
app:layout_constraintLeft_toRightOf="@id/layout_play_pause"
|
||||||
app:layout_constraintBottom_toBottomOf="parent" />
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
<ImageButton
|
|
||||||
android:id="@+id/button_autoplay"
|
|
||||||
android:layout_width="55dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:clickable="true"
|
|
||||||
app:srcCompat="@drawable/autoplay_24px"
|
|
||||||
app:layout_constraintRight_toLeftOf="@id/button_fullscreen"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/button_fullscreen"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/button_fullscreen"
|
|
||||||
android:paddingStart="5dp"
|
|
||||||
android:paddingTop="15dp"
|
|
||||||
android:paddingEnd="5dp"
|
|
||||||
android:scaleType="fitCenter"/>
|
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/button_fullscreen"
|
android:id="@+id/button_fullscreen"
|
||||||
android:layout_width="55dp"
|
android:layout_width="55dp"
|
||||||
|
|
|
@ -377,8 +377,12 @@
|
||||||
<string name="reverse_portrait_description">Allow app to flip into reverse portrait</string>
|
<string name="reverse_portrait_description">Allow app to flip into reverse portrait</string>
|
||||||
<string name="rotation_zone">Rotation zone</string>
|
<string name="rotation_zone">Rotation zone</string>
|
||||||
<string name="rotation_zone_description">Specify the sensitivity of rotation zones (decrease to make less sensitive)</string>
|
<string name="rotation_zone_description">Specify the sensitivity of rotation zones (decrease to make less sensitive)</string>
|
||||||
|
<string name="stability_threshold_time">Stability threshold time</string>
|
||||||
|
<string name="stability_threshold_time_description">Specify the duration the orientation needs to be the same to trigger a rotation</string>
|
||||||
<string name="prefer_webm">Prefer Webm Video Codecs</string>
|
<string name="prefer_webm">Prefer Webm Video Codecs</string>
|
||||||
<string name="prefer_webm_description">If player should prefer Webm codecs (vp9/opus) over mp4 codecs (h264/AAC), may result in worse compatibility.</string>
|
<string name="prefer_webm_description">If player should prefer Webm codecs (vp9/opus) over mp4 codecs (h264/AAC), may result in worse compatibility.</string>
|
||||||
|
<string name="full_autorotate_lock">Full auto rotate lock</string>
|
||||||
|
<string name="full_autorotate_lock_description">Prevent any rotation while rotation lock is engaged (even flipping between landscape and landscape reverse).</string>
|
||||||
<string name="prefer_webm_audio">Prefer Webm Audio Codecs</string>
|
<string name="prefer_webm_audio">Prefer Webm Audio Codecs</string>
|
||||||
<string name="prefer_webm_audio_description">If player should prefer Webm codecs (opus) over mp4 codecs (AAC), may result in worse compatibility.</string>
|
<string name="prefer_webm_audio_description">If player should prefer Webm codecs (opus) over mp4 codecs (AAC), may result in worse compatibility.</string>
|
||||||
<string name="allow_under_cutout">Allow video under cutout</string>
|
<string name="allow_under_cutout">Allow video under cutout</string>
|
||||||
|
@ -966,4 +970,12 @@
|
||||||
<item>30</item>
|
<item>30</item>
|
||||||
<item>45</item>
|
<item>45</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="rotation_threshold_time">
|
||||||
|
<item>100</item>
|
||||||
|
<item>500</item>
|
||||||
|
<item>750</item>
|
||||||
|
<item>1000</item>
|
||||||
|
<item>1500</item>
|
||||||
|
<item>2000</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue