feat: swipe-controls (#50)

This commit is contained in:
Chris 2022-07-05 22:02:27 +02:00 committed by GitHub
parent a1ecb48442
commit 4e27c9f88c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 835 additions and 925 deletions

View File

@ -1,4 +1,5 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'org.jetbrains.kotlin.android'
android { android {
compileSdkVersion 32 compileSdkVersion 32

View File

@ -0,0 +1,33 @@
package app.revanced.integrations.fenster
import app.revanced.integrations.settings.SettingsEnum
/**
* controls fenster feature enablement
*/
object FensterEnablement {
/**
* should fenster be enabled? (global setting)
*/
val shouldEnableFenster: Boolean
get() {
return shouldEnableFensterVolumeControl || shouldEnableFensterBrightnessControl
}
/**
* should swipe controls for volume be enabled?
*/
val shouldEnableFensterVolumeControl: Boolean
get() {
return SettingsEnum.ENABLE_SWIPE_VOLUME_BOOLEAN.boolean
}
/**
* should swipe controls for volume be enabled?
*/
val shouldEnableFensterBrightnessControl: Boolean
get() {
return SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.boolean
}
}

View File

@ -0,0 +1,27 @@
package app.revanced.integrations.fenster
/**
* WatchWhile player types
*/
@Suppress("unused")
enum class WatchWhilePlayerType {
NONE,
HIDDEN,
WATCH_WHILE_MINIMIZED,
WATCH_WHILE_MAXIMIZED,
WATCH_WHILE_FULLSCREEN,
WATCH_WHILE_SLIDING_MAXIMIZED_FULLSCREEN,
WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED,
WATCH_WHILE_SLIDING_MINIMIZED_DISMISSED,
WATCH_WHILE_SLIDING_FULLSCREEN_DISMISSED,
INLINE_MINIMAL,
VIRTUAL_REALITY_FULLSCREEN,
WATCH_WHILE_PICTURE_IN_PICTURE;
companion object {
@JvmStatic
fun safeParseFromString(name: String): WatchWhilePlayerType? {
return values().firstOrNull { it.name == name }
}
}
}

View File

@ -0,0 +1,75 @@
package app.revanced.integrations.fenster.controllers
import android.content.Context
import android.media.AudioManager
import android.os.Build
import app.revanced.integrations.fenster.util.clamp
import app.revanced.integrations.utils.LogHelper
import kotlin.properties.Delegates
/**
* controller to adjust the device volume level
*
* @param context the context to bind the audio service in
* @param targetStream the stream that is being controlled. Must be one of the STREAM_* constants in [AudioManager]
*/
class AudioVolumeController(
context: Context,
private val targetStream: Int = AudioManager.STREAM_MUSIC
) {
/**
* audio service connection
*/
private lateinit var audioManager: AudioManager
private var minimumVolumeIndex by Delegates.notNull<Int>()
private var maximumVolumeIndex by Delegates.notNull<Int>()
init {
// bind audio service
val mgr = context.getSystemService(Context.AUDIO_SERVICE) as? AudioManager
if (mgr == null) {
LogHelper.debug(this.javaClass, "failed to acquire AUDIO_SERVICE")
} else {
audioManager = mgr
maximumVolumeIndex = audioManager.getStreamMaxVolume(targetStream)
minimumVolumeIndex =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) audioManager.getStreamMinVolume(
targetStream
) else 0
}
}
/**
* the current volume, ranging from 0.0 to [maxVolume]
*/
var volume: Int
get() {
// check if initialized correctly
if (!this::audioManager.isInitialized) return 0
// get current volume
return currentVolumeIndex - minimumVolumeIndex
}
set(value) {
// check if initialized correctly
if (!this::audioManager.isInitialized) return
// set new volume
currentVolumeIndex =
(value + minimumVolumeIndex).clamp(minimumVolumeIndex, maximumVolumeIndex)
}
/**
* the maximum possible volume
*/
val maxVolume: Int
get() = maximumVolumeIndex - minimumVolumeIndex
/**
* the current volume index of the target stream
*/
private var currentVolumeIndex: Int
get() = audioManager.getStreamVolume(targetStream)
set(value) = audioManager.setStreamVolume(targetStream, value, 0)
}

View File

@ -0,0 +1,258 @@
package app.revanced.integrations.fenster.controllers
import android.app.Activity
import android.content.Context
import android.util.TypedValue
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ViewGroup
import app.revanced.integrations.fenster.FensterEnablement
import app.revanced.integrations.fenster.util.ScrollDistanceHelper
import app.revanced.integrations.fenster.util.SwipeControlZone
import app.revanced.integrations.fenster.util.applyDimension
import app.revanced.integrations.fenster.util.getSwipeControlZone
import app.revanced.integrations.utils.LogHelper
import kotlin.math.abs
/**
* main controller class for 'FensterV2' swipe controls
*/
class FensterController {
/**
* are the swipe controls currently enabled?
*/
var isEnabled: Boolean
get() = _isEnabled
set(value) {
_isEnabled = value && FensterEnablement.shouldEnableFenster
overlayController?.setOverlayVisible(_isEnabled)
LogHelper.debug(this.javaClass, "FensterController.isEnabled set to $_isEnabled")
}
private var _isEnabled = false
/**
* the activity that hosts the controller
*/
private var hostActivity: Activity? = null
private var audioController: AudioVolumeController? = null
private var screenController: ScreenBrightnessController? = null
private var overlayController: FensterOverlayController? = null
private var gestureListener: FensterGestureListener? = null
private var gestureDetector: GestureDetector? = null
/**
* Initializes the controller.
* this function *may* be called after [initializeOverlay], but must be called before [onTouchEvent]
*
* @param host the activity that hosts the controller. this must be the same activity that the view hook for [onTouchEvent] is on
*/
fun initializeController(host: Activity) {
if (hostActivity != null) {
if (host == hostActivity) {
// function was called twice, ignore the call
LogHelper.debug(
this.javaClass,
"initializeController was called twice, ignoring secondary call"
)
return
}
}
LogHelper.debug(this.javaClass, "initializing FensterV2 controllers")
hostActivity = host
audioController = if (FensterEnablement.shouldEnableFensterVolumeControl)
AudioVolumeController(host) else null
screenController = if (FensterEnablement.shouldEnableFensterBrightnessControl)
ScreenBrightnessController(host) else null
gestureListener = FensterGestureListener(host)
gestureDetector = GestureDetector(host, gestureListener)
}
/**
* Initializes the user feedback overlay, adding it as a child to the provided parent.
* this function *may* not be called, but in that case you'll have no user feedback
*
* @param parent parent view group that the overlay is added to
*/
fun initializeOverlay(parent: ViewGroup) {
LogHelper.debug(this.javaClass, "initializing FensterV2 overlay")
// create and add overlay
overlayController = FensterOverlayController(parent.context)
parent.addView(overlayController!!.overlayRootView, 0)
}
/**
* Process touch events from the view hook.
* the hooked view *must* be a child of the activity used for [initializeController]
*
* @param event the motion event to process
* @return was the event consumed by the controller?
*/
fun onTouchEvent(event: MotionEvent): Boolean {
// if disabled, we shall not consume any events
if (!isEnabled) return false
// if important components are not present, there is no point in processing the event here
if (hostActivity == null || gestureDetector == null || gestureListener == null) {
return false
}
// send event to gesture detector
if (event.action == MotionEvent.ACTION_UP) {
gestureListener?.onUp(event)
}
val consumed = gestureDetector?.onTouchEvent(event) ?: false
// if the event was inside a control zone, we always consume the event
val swipeZone = event.getSwipeControlZone(hostActivity!!)
var inControlZone = false
if (audioController != null) {
inControlZone = inControlZone || swipeZone == SwipeControlZone.VOLUME_CONTROL
}
if (screenController != null) {
inControlZone = inControlZone || swipeZone == SwipeControlZone.BRIGHTNESS_CONTROL
}
return consumed || inControlZone
}
/**
* primary gesture listener that handles the following behaviour:
*
* - Volume & Brightness swipe controls:
* when swiping on the right or left side of the screen, the volume or brightness is adjusted accordingly.
* swipe controls are only unlocked after a long- press in the corresponding screen half
*
* - Fling- to- mute:
* when quickly flinging down, the volume is instantly muted
*/
inner class FensterGestureListener(
private val context: Context
) : GestureDetector.SimpleOnGestureListener() {
/**
* to enable swipe controls, users must first long- press. this flags monitors that long- press
*/
private var inSwipeSession = false
/**
* scroller for volume adjustment
*/
private val volumeScroller = ScrollDistanceHelper(
10.applyDimension(
context,
TypedValue.COMPLEX_UNIT_DIP
)
) { _, _, direction ->
audioController?.apply {
volume += direction
overlayController?.showNewVolume((volume * 100.0) / maxVolume)
}
}
/**
* scroller for screen brightness adjustment
*/
private val brightnessScroller = ScrollDistanceHelper(
1.applyDimension(
context,
TypedValue.COMPLEX_UNIT_DIP
)
) { _, _, direction ->
screenController?.apply {
screenBrightness += direction
overlayController?.showNewBrightness(screenBrightness)
}
}
/**
* custom handler for ACTION_UP event, because GestureDetector doesn't offer that :|
*
* @param e the motion event
*/
fun onUp(e: MotionEvent) {
LogHelper.debug(this.javaClass, "onUp(${e.x}, ${e.y}, ${e.action})")
inSwipeSession = false
volumeScroller.reset()
brightnessScroller.reset()
}
override fun onLongPress(e: MotionEvent?) {
if (e == null) return
LogHelper.debug(this.javaClass, "onLongPress(${e.x}, ${e.y}, ${e.action})")
// enter swipe session with feedback
inSwipeSession = true
overlayController?.notifyEnterSwipeSession()
// make the GestureDetector believe there was a ACTION_UP event
// so it will handle further events
e.action = MotionEvent.ACTION_UP
gestureDetector?.onTouchEvent(e)
}
override fun onScroll(
eFrom: MotionEvent?,
eTo: MotionEvent?,
disX: Float,
disY: Float
): Boolean {
if (eFrom == null || eTo == null) return false
LogHelper.debug(
this.javaClass,
"onScroll(from: [${eFrom.x}, ${eFrom.y}, ${eFrom.action}], to: [${eTo.x}, ${eTo.y}, ${eTo.action}], d: [$disX, $disY])"
)
// ignore if scroll not in scroll session
if (!inSwipeSession) return false
// do the adjustment
when (eFrom.getSwipeControlZone(context)) {
SwipeControlZone.VOLUME_CONTROL -> {
volumeScroller.add(disY.toDouble())
}
SwipeControlZone.BRIGHTNESS_CONTROL -> {
brightnessScroller.add(disY.toDouble())
}
SwipeControlZone.NONE -> {}
}
return true
}
override fun onFling(
eFrom: MotionEvent?,
eTo: MotionEvent?,
velX: Float,
velY: Float
): Boolean {
if (eFrom == null || eTo == null) return false
LogHelper.debug(
this.javaClass,
"onFling(from: [${eFrom.x}, ${eFrom.y}, ${eFrom.action}], to: [${eTo.x}, ${eTo.y}, ${eTo.action}], v: [$velX, $velY])"
)
// filter out flings that are not very vertical
if (abs(velY) < abs(velX * 2)) return false
// check if either of the events was in the volume zone
if ((eFrom.getSwipeControlZone(context) == SwipeControlZone.VOLUME_CONTROL)
|| (eTo.getSwipeControlZone(context) == SwipeControlZone.VOLUME_CONTROL)
) {
// if the fling was very aggressive, trigger instant- mute
if (velY > 5000) {
audioController?.apply {
volume = 0
overlayController?.notifyFlingToMutePerformed()
overlayController?.showNewVolume((volume * 100.0) / maxVolume)
}
}
}
return true
}
}
}

View File

@ -0,0 +1,130 @@
package app.revanced.integrations.fenster.controllers
import android.content.Context
import android.graphics.Color
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.TypedValue
import android.view.HapticFeedbackConstants
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.TextView
import app.revanced.integrations.fenster.util.applyDimension
import kotlin.math.round
/**
* controller for the fenster overlay
*
* @param context the context to create the overlay in
*/
class FensterOverlayController(
context: Context
) {
/**
* the main overlay view
*/
val overlayRootView: RelativeLayout
private val feedbackTextView: TextView
init {
// create root container
overlayRootView = RelativeLayout(context).apply {
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
isClickable = false
isFocusable = false
z = 1000f
//elevation = 1000f
}
// add other views
val feedbackTextViewPadding = 2.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
feedbackTextView = TextView(context).apply {
layoutParams = RelativeLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT
).apply {
addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE)
setPadding(
feedbackTextViewPadding,
feedbackTextViewPadding,
feedbackTextViewPadding,
feedbackTextViewPadding
)
}
setBackgroundColor(Color.BLACK)
setTextColor(Color.WHITE)
setTextSize(TypedValue.COMPLEX_UNIT_SP, 20f)
visibility = View.GONE
}
overlayRootView.addView(feedbackTextView)
}
private val feedbackHideHandler = Handler(Looper.getMainLooper())
private val feedbackHideCallback = Runnable {
feedbackTextView.visibility = View.GONE
}
/**
* set the overlay visibility
*
* @param visible should the overlay be visible?
*/
fun setOverlayVisible(visible: Boolean) {
overlayRootView.visibility = if (visible) View.VISIBLE else View.GONE
}
/**
* show the new volume level on the overlay
*
* @param volume the new volume level, in percent (range 0.0 - 100.0)
*/
fun showNewVolume(volume: Double) {
feedbackTextView.text = "Volume ${round(volume).toInt()}%"
showFeedbackView()
}
/**
* show the new screen brightness on the overlay
*
* @param brightness the new screen brightness, in percent (range 0.0 - 100.0)
*/
fun showNewBrightness(brightness: Double) {
feedbackTextView.text = "Brightness ${round(brightness).toInt()}%"
showFeedbackView()
}
/**
* notify the user that a new swipe- session has started
*/
fun notifyEnterSwipeSession() {
overlayRootView.performHapticFeedback(
HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
)
}
/**
* notify the user that fling-to-mute was triggered
*/
fun notifyFlingToMutePerformed() {
overlayRootView.performHapticFeedback(
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) HapticFeedbackConstants.REJECT else HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING
)
}
/**
* show the feedback view for a given time
*/
private fun showFeedbackView() {
feedbackTextView.visibility = View.VISIBLE
feedbackHideHandler.removeCallbacks(feedbackHideCallback)
feedbackHideHandler.postDelayed(feedbackHideCallback, 2000)
}
}

View File

@ -0,0 +1,27 @@
package app.revanced.integrations.fenster.controllers
import android.app.Activity
import app.revanced.integrations.fenster.util.clamp
/**
* controller to adjust the screen brightness level
*
* @param host the host activity of which the brightness is adjusted
*/
class ScreenBrightnessController(
private val host: Activity
) {
/**
* the current screen brightness in percent, ranging from 0.0 to 100.0
*/
var screenBrightness: Double
get() {
return host.window.attributes.screenBrightness * 100.0
}
set(value) {
val attr = host.window.attributes
attr.screenBrightness = (value.toFloat() / 100f).clamp(0f, 1f)
host.window.attributes = attr
}
}

View File

@ -0,0 +1,26 @@
package app.revanced.integrations.fenster.util
import android.content.Context
import android.util.TypedValue
import kotlin.math.roundToInt
fun Float.clamp(min: Float, max: Float): Float {
if (this < min) return min
if (this > max) return max
return this
}
fun Int.clamp(min: Int, max: Int): Int {
if (this < min) return min
if (this > max) return max
return this
}
fun Int.applyDimension(context: Context, unit: Int): Int {
return TypedValue.applyDimension(
unit,
this.toFloat(),
context.resources.displayMetrics
).roundToInt()
}

View File

@ -0,0 +1,56 @@
package app.revanced.integrations.fenster.util
import kotlin.math.abs
import kotlin.math.sign
/**
* helper for scaling onScroll handler
*
* @param unitDistance absolute distance after which the callback is invoked
* @param callback callback function for when unit distance is reached
*/
class ScrollDistanceHelper(
private val unitDistance: Int,
private val callback: (oldDistance: Double, newDistance: Double, direction: Int) -> Unit
) {
/**
* total distance scrolled
*/
private var scrolledDistance: Double = 0.0
/**
* add a scrolled distance to the total.
* if the [unitDistance] is reached, this function will also invoke the callback
*
* @param distance the distance to add
*/
fun add(distance: Double) {
scrolledDistance += distance
// invoke the callback if we scrolled far enough
while (abs(scrolledDistance) >= unitDistance) {
val oldDistance = scrolledDistance
subtractUnitDistance()
callback.invoke(
oldDistance,
scrolledDistance,
sign(scrolledDistance).toInt()
)
}
}
/**
* reset the distance scrolled to zero
*/
fun reset() {
scrolledDistance = 0.0
}
/**
* subtract the [unitDistance] from the total [scrolledDistance]
*/
private fun subtractUnitDistance() {
scrolledDistance -= (unitDistance * sign(scrolledDistance))
}
}

View File

@ -0,0 +1,82 @@
package app.revanced.integrations.fenster.util
import android.content.Context
import android.util.TypedValue
import android.view.MotionEvent
/**
* zones for swipe controls
*/
enum class SwipeControlZone {
/**
* not in any zone, should do nothing
*/
NONE,
/**
* in volume zone, adjust volume
*/
VOLUME_CONTROL,
/**
* in brightness zone, adjust brightness
*/
BRIGHTNESS_CONTROL;
}
/**
* get the control zone in which this motion event is
*
* @return the swipe control zone
*/
@Suppress("UnnecessaryVariable", "LocalVariableName")
fun MotionEvent.getSwipeControlZone(context: Context): SwipeControlZone {
// get screen size
val screenWidth = device.getMotionRange(MotionEvent.AXIS_X).range
val screenHeight = device.getMotionRange(MotionEvent.AXIS_Y).range
// check in what detection zone the event is in
val _40dp = 40.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP).toFloat()
val _80dp = 80.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP).toFloat()
val _220dp = 220.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP).toFloat()
// Y- Axis:
// -------- 0
// ^
// dead | 40dp
// v
// -------- yDeadTop
// ^
// swipe |
// v
// -------- yDeadBtm
// ^
// dead | 80dp
// v
// -------- screenHeight
val yDeadTop = _40dp
val yDeadBtm = screenHeight - _80dp
// X- Axis:
// 0 xBrigStart xBrigEnd xVolStart xVolEnd screenWidth
// | | | | | |
// | 40dp | 220dp | | 220dp | 40dp |
// | <------> | <------> | <------> | <------> | <------> |
// | dead | brightness | dead | volume | dead |
val xBrightStart = _40dp
val xBrightEnd = xBrightStart + _220dp
val xVolEnd = screenWidth - _40dp
val xVolStart = xVolEnd - _220dp
// test detection zone
if (y in yDeadTop..yDeadBtm) {
return when (x) {
in xBrightStart..xBrightEnd -> SwipeControlZone.BRIGHTNESS_CONTROL
in xVolStart..xVolEnd -> SwipeControlZone.VOLUME_CONTROL
else -> SwipeControlZone.NONE
}
}
// not in bounds
return SwipeControlZone.NONE
}

View File

@ -0,0 +1,103 @@
package app.revanced.integrations.patches;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.view.MotionEvent;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import app.revanced.integrations.fenster.WatchWhilePlayerType;
import app.revanced.integrations.fenster.controllers.FensterController;
import app.revanced.integrations.utils.LogHelper;
/**
* Hook receiver class for 'FensterV2' video swipe controls.
*
* @usedBy app.revanced.patches.youtube.interaction.fenster.patch.FensterPatch
* @smali Lapp/revanced/integrations/patches/FensterSwipePatch;
*/
@SuppressWarnings("unused")
public final class FensterSwipePatch {
/**
* main fenster controller instance
*/
@SuppressLint("StaticFieldLeak")
private static final FensterController FENSTER = new FensterController();
/**
* Hook into the main activity lifecycle
*
* @param thisRef reference to the WatchWhileActivity instance
* @smali Lapp/revanced/integrations/patches/FensterSwipePatch;->WatchWhileActivity_onStartHookEX(Ljava/lang/Object;)V
*/
public static void WatchWhileActivity_onStartHookEX(@Nullable Object thisRef) {
if (thisRef == null) return;
if (thisRef instanceof Activity) {
FENSTER.initializeController((Activity) thisRef);
}
}
/**
* hook into the player overlays lifecycle
*
* @param thisRef reference to the PlayerOverlays instance
* @smali Lapp/revanced/integrations/patches/FensterSwipePatch;->YouTubePlayerOverlaysLayout_onFinishInflateHookEX(Ljava/lang/Object;)V
*/
public static void YouTubePlayerOverlaysLayout_onFinishInflateHookEX(@Nullable Object thisRef) {
if (thisRef == null) return;
if (thisRef instanceof ViewGroup) {
FENSTER.initializeOverlay((ViewGroup) thisRef);
}
}
/**
* Hook into updatePlayerLayout() method
*
* @param type the new player type
* @smali Lapp/revanced/integrations/patches/FensterSwipePatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V
*/
public static void YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(@Nullable Object type) {
if (type == null) return;
// disable processing events if not watching fullscreen video
WatchWhilePlayerType playerType = WatchWhilePlayerType.safeParseFromString(type.toString());
FENSTER.setEnabled(playerType == WatchWhilePlayerType.WATCH_WHILE_FULLSCREEN);
LogHelper.debug(FensterSwipePatch.class, "WatchWhile player type was updated to " + playerType);
}
/**
* Hook into NextGenWatchLayout.onTouchEvent
*
* @param thisRef reference to NextGenWatchLayout instance
* @param motionEvent event parameter
* @return was the event consumed by the hook?
* @smali Lapp/revanced/integrations/patches/FensterSwipePatch;->NextGenWatchLayout_onTouchEventHookEX(Ljava/lang/Object;Ljava/lang/Object;)Z
*/
public static boolean NextGenWatchLayout_onTouchEventHookEX(@Nullable Object thisRef, @Nullable Object motionEvent) {
if (motionEvent == null) return false;
if (motionEvent instanceof MotionEvent) {
return FENSTER.onTouchEvent((MotionEvent) motionEvent);
}
return false;
}
/**
* Hook into NextGenWatchLayout.onInterceptTouchEvent
*
* @param thisRef reference to NextGenWatchLayout instance
* @param motionEvent event parameter
* @return was the event consumed by the hook?
* @smali Lapp/revanced/integrations/patches/FensterSwipePatch;->NextGenWatchLayout_onInterceptTouchEventHookEX(Ljava/lang/Object;Ljava/lang/Object;)Z
*/
public static boolean NextGenWatchLayout_onInterceptTouchEventHookEX(@Nullable Object thisRef, @Nullable Object motionEvent) {
if (motionEvent == null) return false;
if (motionEvent instanceof MotionEvent) {
return FENSTER.onTouchEvent((MotionEvent) motionEvent);
}
return false;
}
}

View File

@ -1,14 +1,14 @@
package app.revanced.integrations.patches; package app.revanced.integrations.patches;
import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.videoswipecontrols.helpers.BrightnessHelper;
public class HDRMaxBrightnessPatch { public class HDRMaxBrightnessPatch {
//Used by app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch //Used by app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch
public static float getHDRBrightness(float original) { public static float getHDRBrightness(float original) {
if (!SettingsEnum.USE_HDR_BRIGHTNESS_BOOLEAN.getBoolean()) return original; if (!SettingsEnum.USE_HDR_BRIGHTNESS_BOOLEAN.getBoolean()) return original;
return SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.getBoolean() ? BrightnessHelper.getBrightness() : -1.0f; //return SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.getBoolean() ? BrightnessHelper.getBrightness() : -1.0f;
return -1;
} }
} }

View File

@ -1,51 +0,0 @@
package app.revanced.integrations.patches;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.sponsorblock.player.PlayerType;
import app.revanced.integrations.utils.ReVancedUtils;
import app.revanced.integrations.utils.SwipeHelper;
import app.revanced.integrations.videoswipecontrols.SwipeControlAPI;
public class VideoSwipeControlsPatch {
//ToDo: Write Patch for it.
//See https://drive.google.com/file/d/1FTPRrp6NcIF5LC_ByST1a0wcNoGKcAYS/view?usp=sharing for where it needs to be used.
public static void InitializeFensterController(Context context, ViewGroup viewGroup, ViewConfiguration viewConfiguration) {
SwipeControlAPI.InitializeFensterController(context, viewGroup, viewConfiguration);
}
//ToDo: Write Patch for it.
//See https://drive.google.com/file/d/1Q9TIDDKvc-nQuJWLmCh7jx3ohxPdFIrZ/view?usp=sharing
//And https://drive.google.com/file/d/1byP5SItks9MYB3fDVC39xH_6nBbaH9NY/view?usp=sharing
// for where it needs to be used.
public static boolean FensterTouchEvent(MotionEvent motionEvent) {
return SwipeControlAPI.FensterTouchEvent(motionEvent);
}
//ToDo: Write Patch for it.
//See https://drive.google.com/file/d/1qKmaX4yzAjzYM6T5uUiRtbMxk2zJlwtd/view?usp=sharing for where it needs to be used.
public static boolean isSwipeControlBrightnessEnabled() {
return SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.getBoolean();
}
//ToDo: Write Patch for it.
//See https://drive.google.com/file/d/1TMQxs0ul2_p5_GomE-3J1QWO__M189Da/view?usp=sharing for where it needs to be used.
public static void PlayerTypeChanged(PlayerType playerType) {
SwipeControlAPI.PlayerTypeChanged(playerType);
}
//ToDo: Write Patch for it.
//See https://drive.google.com/file/d/1EoVAyqWOMGUDCovuDb27yeQJBk_CyKsY/view?usp=sharing for where it needs to be used.
public static boolean isSwipeControlEnabled() {
if (ReVancedUtils.getPlayerType() != null && ReVancedUtils.getPlayerType() == PlayerType.WATCH_WHILE_FULLSCREEN && !SwipeHelper.IsControlsShown()) {
return SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.getBoolean() || SettingsEnum.ENABLE_SWIPE_VOLUME_BOOLEAN.getBoolean();
}
return false;
}
}

View File

@ -31,9 +31,14 @@ public enum SettingsEnum {
USE_HDR_BRIGHTNESS_BOOLEAN("pref_hdr_autobrightness", true), USE_HDR_BRIGHTNESS_BOOLEAN("pref_hdr_autobrightness", true),
ENABLE_SWIPE_BRIGHTNESS_BOOLEAN("pref_xfenster_brightness", true), ENABLE_SWIPE_BRIGHTNESS_BOOLEAN("pref_xfenster_brightness", true),
ENABLE_SWIPE_VOLUME_BOOLEAN("pref_xfenster_volume", true), ENABLE_SWIPE_VOLUME_BOOLEAN("pref_xfenster_volume", true),
@Deprecated
SWIPE_THRESHOLD_INTEGER("pref_xfenster_swipe_threshold", 30), SWIPE_THRESHOLD_INTEGER("pref_xfenster_swipe_threshold", 30),
@Deprecated
SWIPE_PADDING_TOP_INTEGER("pref_xfenster_swipe_padding_top", 50), SWIPE_PADDING_TOP_INTEGER("pref_xfenster_swipe_padding_top", 50),
@Deprecated
SWIPE_USE_TABLET_MODE("pref_xfenster_tablet", false), SWIPE_USE_TABLET_MODE("pref_xfenster_tablet", false),
MAX_BUFFER_INTEGER("pref_max_buffer_ms", 120000), MAX_BUFFER_INTEGER("pref_max_buffer_ms", 120000),
PLAYBACK_MAX_BUFFER_INTEGER("pref_buffer_for_playback_ms", 2500), PLAYBACK_MAX_BUFFER_INTEGER("pref_buffer_for_playback_ms", 2500),
MAX_PLAYBACK_BUFFER_AFTER_REBUFFER_INTEGER("pref_buffer_for_playback_after_rebuffer_ms", 5000), MAX_PLAYBACK_BUFFER_AFTER_REBUFFER_INTEGER("pref_buffer_for_playback_after_rebuffer_ms", 5000),
@ -58,17 +63,17 @@ public enum SettingsEnum {
Context context = ReVancedUtils.getContext(); Context context = ReVancedUtils.getContext();
if (context != null) { if (context != null) {
for (SettingsEnum setting : values()) { for (SettingsEnum setting : values()) {
Object value = null; Object value;
if (setting.name().endsWith("BOOLEAN")) { if (setting.name().endsWith("BOOLEAN")) {
value = SharedPrefHelper.getBoolean(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath()); value = SharedPrefHelper.getBoolean(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath(), (boolean)setting.getDefaultValue());
} else if (setting.name().endsWith("INTEGER")) { } else if (setting.name().endsWith("INTEGER")) {
value = SharedPrefHelper.getInt(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath()); value = SharedPrefHelper.getInt(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath(), (int)setting.getDefaultValue());
} else if (setting.name().endsWith("STRING")) { } else if (setting.name().endsWith("STRING")) {
value = SharedPrefHelper.getString(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath()); value = SharedPrefHelper.getString(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath(), (String)setting.getDefaultValue());
} else if (setting.name().endsWith("LONG")) { } else if (setting.name().endsWith("LONG")) {
value = SharedPrefHelper.getLong(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath()); value = SharedPrefHelper.getLong(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath(), (long)setting.getDefaultValue());
} else if (setting.name().endsWith(("FLOAT"))) { } else if (setting.name().endsWith(("FLOAT"))) {
value = SharedPrefHelper.getFloat(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath()); value = SharedPrefHelper.getFloat(context, SharedPrefHelper.SharedPrefNames.YOUTUBE, setting.getPath(), (float)setting.getDefaultValue());
} else { } else {
LogHelper.printException(SettingsEnum.class, "Setting does not end with a valid Type. Name is: " + setting.name()); LogHelper.printException(SettingsEnum.class, "Setting does not end with a valid Type. Name is: " + setting.name());
continue; continue;

View File

@ -23,7 +23,6 @@ import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils; import app.revanced.integrations.utils.ReVancedUtils;
import app.revanced.integrations.videoplayer.autorepeat.AutoRepeat; import app.revanced.integrations.videoplayer.autorepeat.AutoRepeat;
import app.revanced.integrations.videoswipecontrols.SwipeGestureListener;
import app.revanced.integrations.utils.ScreenSizeHelper; import app.revanced.integrations.utils.ScreenSizeHelper;
import app.revanced.integrations.videoplayer.videourl.Copy; import app.revanced.integrations.videoplayer.videourl.Copy;
import app.revanced.integrations.videoplayer.videourl.CopyWithTimeStamp; import app.revanced.integrations.videoplayer.videourl.CopyWithTimeStamp;
@ -175,34 +174,6 @@ public class ReVancedSettingsFragment extends PreferenceFragment {
SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.setValue(((SwitchPreference) xSwipeControlPreferenceScreen.findPreference(str)).isChecked()); SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.setValue(((SwitchPreference) xSwipeControlPreferenceScreen.findPreference(str)).isChecked());
} else if (str.equals(SettingsEnum.ENABLE_SWIPE_VOLUME_BOOLEAN.getPath())) { } else if (str.equals(SettingsEnum.ENABLE_SWIPE_VOLUME_BOOLEAN.getPath())) {
SettingsEnum.ENABLE_SWIPE_VOLUME_BOOLEAN.setValue(((SwitchPreference) xSwipeControlPreferenceScreen.findPreference(str)).isChecked()); SettingsEnum.ENABLE_SWIPE_VOLUME_BOOLEAN.setValue(((SwitchPreference) xSwipeControlPreferenceScreen.findPreference(str)).isChecked());
} else if (str.equals(SettingsEnum.SWIPE_USE_TABLET_MODE.getPath())) {
SettingsEnum.SWIPE_USE_TABLET_MODE.setValue(((SwitchPreference) xSwipeControlPreferenceScreen.findPreference(str)).isChecked());
} else if (str.equals(SettingsEnum.SWIPE_THRESHOLD_INTEGER.getPath())) {
EditTextPreference editTextPreference6 = (EditTextPreference) xSwipeControlPreferenceScreen.findPreference(str);
if (editTextPreference6 != null) {
int val = 0;
editTextPreference6.setSummary(editTextPreference6.getText());
try {
val = Integer.parseInt(editTextPreference6.getText());
} catch (NumberFormatException unused) {
val = 0;
}
SwipeGestureListener.SWIPE_THRESHOLD = val;
SettingsEnum.SWIPE_THRESHOLD_INTEGER.setValue(val);
}
} else if (str.equals(SettingsEnum.SWIPE_PADDING_TOP_INTEGER.getPath())) {
EditTextPreference editTextPreference6 = (EditTextPreference) xSwipeControlPreferenceScreen.findPreference(str);
if (editTextPreference6 != null) {
int val = 0;
editTextPreference6.setSummary(editTextPreference6.getText());
try {
val = Integer.parseInt(editTextPreference6.getText());
} catch (NumberFormatException unused) {
val = 0;
}
SwipeGestureListener.TOP_PADDING = val;
SettingsEnum.SWIPE_PADDING_TOP_INTEGER.setValue(val);
}
} else if ("revanced_ryd_enabled".equals(str) && ReVancedUtils.getContext() != null && settingsInitialized) { } else if ("revanced_ryd_enabled".equals(str) && ReVancedUtils.getContext() != null && settingsInitialized) {
rebootDialog(ReVancedSettingsFragment.this.getActivity()); rebootDialog(ReVancedSettingsFragment.this.getActivity());
} else if (str.equals("pref_auto_repeat_button")) { } else if (str.equals("pref_auto_repeat_button")) {

View File

@ -1,8 +0,0 @@
package app.revanced.integrations.videoswipecontrols;
/* loaded from: classes6.dex */
public enum Coverage {
FULL,
RIGHT,
LEFT
}

View File

@ -1,7 +0,0 @@
package app.revanced.integrations.videoswipecontrols;
/* loaded from: classes6.dex */
public enum Orientation {
HORIZONTAL,
VERTICAL
}

View File

@ -1,73 +0,0 @@
package app.revanced.integrations.videoswipecontrols;
import android.content.Context;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.sponsorblock.NewSegmentHelperLayout;
import app.revanced.integrations.sponsorblock.SponsorBlockUtils;
import app.revanced.integrations.sponsorblock.player.PlayerType;
import app.revanced.integrations.sponsorblock.player.ui.SponsorBlockView;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
import app.revanced.integrations.utils.SwipeHelper;
public class SwipeControlAPI {
private static SwipeGestureController swipeGestureController;
public static void InitializeFensterController(Context context, ViewGroup viewGroup, ViewConfiguration viewConfiguration) {
swipeGestureController = new SwipeGestureController();
swipeGestureController.setFensterEventsListener(new SwipeListener(context, viewGroup), context, viewConfiguration);
LogHelper.debug(SwipeControlAPI.class, "XFenster initialized");
}
public static boolean FensterTouchEvent(MotionEvent motionEvent) {
if (swipeGestureController == null) {
LogHelper.debug(SwipeControlAPI.class, "fensterGestureController is null");
return false;
} else if (motionEvent == null) {
LogHelper.debug(SwipeControlAPI.class, "motionEvent is null");
return false;
} else if (!SwipeHelper.IsControlsShown()) {
return swipeGestureController.onTouchEvent(motionEvent);
} else {
LogHelper.debug(SwipeControlAPI.class, "skipping onTouchEvent dispatching because controls are shown.");
return false;
}
}
public static void PlayerTypeChanged(PlayerType playerType) {
LogHelper.debug(SwipeControlAPI.class, playerType.toString());
if (ReVancedUtils.getPlayerType() != playerType) {
if (playerType == PlayerType.WATCH_WHILE_FULLSCREEN) {
EnableSwipeControl();
} else {
DisableSwipeControl();
}
if (playerType == PlayerType.WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED || playerType == PlayerType.WATCH_WHILE_MINIMIZED || playerType == PlayerType.WATCH_WHILE_PICTURE_IN_PICTURE) {
NewSegmentHelperLayout.hide();
}
SponsorBlockView.playerTypeChanged(playerType);
SponsorBlockUtils.playerTypeChanged(playerType);
}
ReVancedUtils.setPlayerType(playerType);
}
private static void EnableSwipeControl() {
if (SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.getBoolean() || SettingsEnum.ENABLE_SWIPE_VOLUME_BOOLEAN.getBoolean()) {
SwipeGestureController swipeGestureController2 = swipeGestureController;
swipeGestureController2.TouchesEnabled = true;
((SwipeListener) swipeGestureController2.listener).enable(SettingsEnum.ENABLE_SWIPE_BRIGHTNESS_BOOLEAN.getBoolean(), SettingsEnum.ENABLE_SWIPE_VOLUME_BOOLEAN.getBoolean());
}
}
private static void DisableSwipeControl() {
SwipeGestureController swipeGestureController2 = swipeGestureController;
swipeGestureController2.TouchesEnabled = false;
((SwipeListener) swipeGestureController2.listener).disable();
}
}

View File

@ -1,24 +0,0 @@
package app.revanced.integrations.videoswipecontrols;
import android.view.MotionEvent;
/* loaded from: classes6.dex */
public interface SwipeEventsListener {
void onDown(MotionEvent motionEvent);
void onHorizontalScroll(MotionEvent motionEvent, float f);
void onSwipeBottom();
void onSwipeLeft();
void onSwipeRight();
void onSwipeTop();
void onTap();
void onUp();
void onVerticalScroll(MotionEvent motionEvent, float f);
}

View File

@ -1,31 +0,0 @@
package app.revanced.integrations.videoswipecontrols;
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import app.revanced.integrations.utils.LogHelper;
/* loaded from: classes6.dex */
public class SwipeGestureController {
public boolean TouchesEnabled = false;
private GestureDetector gestureDetector;
public SwipeEventsListener listener;
public boolean onTouchEvent(MotionEvent event) {
if (event == null || !this.TouchesEnabled || event.getPointerCount() > 1) {
return false;
}
if (event.getAction() == 1) {
this.listener.onUp();
LogHelper.debug(SwipeGestureController.class, "Touch up");
}
return this.gestureDetector.onTouchEvent(event);
}
public void setFensterEventsListener(SwipeEventsListener listener, Context context, ViewConfiguration viewConfiguration) {
this.listener = listener;
this.gestureDetector = new GestureDetector(context, new SwipeGestureListener(listener, viewConfiguration));
}
}

View File

@ -1,105 +0,0 @@
package app.revanced.integrations.videoswipecontrols;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import app.revanced.integrations.utils.LogHelper;
/* loaded from: classes6.dex */
public class SwipeGestureListener implements GestureDetector.OnGestureListener {
private boolean ignoreScroll = false;
private final SwipeEventsListener listener;
private final int minFlingVelocity;
public static int SWIPE_THRESHOLD = 0;
public static int TOP_PADDING = 20;
public SwipeGestureListener(SwipeEventsListener listener, ViewConfiguration viewConfiguration) {
this.listener = listener;
this.minFlingVelocity = viewConfiguration.getScaledMinimumFlingVelocity();
}
@Override // android.view.GestureDetector.OnGestureListener
public boolean onSingleTapUp(MotionEvent e) {
this.listener.onTap();
return false;
}
@Override // android.view.GestureDetector.OnGestureListener
public void onLongPress(MotionEvent e) {
LogHelper.debug(SwipeGestureListener.class, "Long Press");
}
@Override // android.view.GestureDetector.OnGestureListener
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
LogHelper.debug(SwipeGestureListener.class, "Scroll");
if (e1 == null || e2 == null) {
if (e1 == null) {
LogHelper.debug(SwipeGestureListener.class, "e1 is null");
}
if (e2 == null) {
LogHelper.debug(SwipeGestureListener.class, "e2 is null");
}
return false;
} else if (this.ignoreScroll) {
LogHelper.debug(SwipeGestureListener.class, "Scroll ignored");
return false;
} else {
float deltaY = e2.getY() - e1.getY();
float deltaX = e2.getX() - e1.getX();
if (Math.abs(deltaX) > Math.abs(deltaY)) {
if (Math.abs(deltaX) > SWIPE_THRESHOLD) {
this.listener.onHorizontalScroll(e2, deltaX);
String message = deltaX > 0.0f ? "Slide right" : "Slide left";
LogHelper.debug(SwipeGestureListener.class, message);
}
} else if (Math.abs(deltaY) > SWIPE_THRESHOLD) {
this.listener.onVerticalScroll(e2, deltaY);
String message = deltaY > 0.0f ? "Slide down" : "Slide up";
LogHelper.debug(SwipeGestureListener.class, message);
}
return false;
}
}
@Override // android.view.GestureDetector.OnGestureListener
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
LogHelper.debug(SwipeGestureListener.class, "Fling");
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > this.minFlingVelocity) {
if (diffX > 0.0f) {
this.listener.onSwipeRight();
} else {
this.listener.onSwipeLeft();
}
}
} else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > this.minFlingVelocity) {
if (diffY > 0.0f) {
this.listener.onSwipeBottom();
} else {
this.listener.onSwipeTop();
}
}
return true;
} catch (Exception exception) {
exception.printStackTrace();
return false;
}
}
@Override // android.view.GestureDetector.OnGestureListener
public void onShowPress(MotionEvent e) {
LogHelper.debug(SwipeGestureListener.class, "Show Press");
}
@Override // android.view.GestureDetector.OnGestureListener
public boolean onDown(MotionEvent e) {
LogHelper.debug(SwipeGestureListener.class, "Down - x: " + e.getX() + " y: " + e.getY());
this.ignoreScroll = e.getY() <= TOP_PADDING;
this.listener.onDown(e);
return false;
}
}

View File

@ -1,284 +0,0 @@
package app.revanced.integrations.videoswipecontrols;
import android.content.Context;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
import app.revanced.integrations.videoswipecontrols.seekbar.BrightnessSeekBar;
import app.revanced.integrations.videoswipecontrols.seekbar.VolumeSeekBar;
import app.revanced.integrations.utils.SwipeHelper;
import app.revanced.integrations.settingsmenu.ReVancedSettingsFragment;
/* loaded from: classes6.dex */
public class SwipeListener implements SwipeEventsListener {
public static final int ONE_FINGER = 1;
Handler handler;
float mBrightnessDownPos;
int mBrightnessDownProgress;
ViewGroup mViewGroup;
float mVolumeDownPos;
int mVolumeDownProgress;
float mTouchProgressOffset = 0.0f;
protected int mPaddingTop = 0;
protected int mPaddingBottom = 0;
protected int mPaddingLeft = 0;
protected int mPaddingRight = 0;
Orientation brightnessOrientation = Orientation.VERTICAL;
Orientation volumeOrientation = Orientation.VERTICAL;
Coverage brightnessCoverage = Coverage.LEFT;
Coverage volumeCoverage = Coverage.RIGHT;
BrightnessSeekBar mBrightness = new BrightnessSeekBar();
VolumeSeekBar mVolume = new VolumeSeekBar();
public SwipeListener(Context context, ViewGroup viewGroup) {
this.mViewGroup = viewGroup;
this.mBrightness.initialise(context, viewGroup);
this.mVolume.initialise(context, viewGroup);
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onTap() {
LogHelper.debug(SwipeListener.class, "onTap");
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onHorizontalScroll(MotionEvent event, float delta) {
LogHelper.debug(SwipeListener.class, "onHorizontalScroll - y: " + ((int) event.getY()) + " x: " + ((int) event.getX()));
if (event.getPointerCount() == 1) {
if (this.brightnessOrientation == Orientation.HORIZONTAL && (this.brightnessCoverage == Coverage.FULL || getCoverageHorizontal(event) == this.brightnessCoverage)) {
updateBrightnessProgressBarHorizontal(event);
}
if (this.volumeOrientation != Orientation.HORIZONTAL) {
return;
}
if (this.volumeCoverage == Coverage.FULL || getCoverageHorizontal(event) == this.volumeCoverage) {
updateVolumeProgressBarHorizontal(event);
}
}
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onVerticalScroll(MotionEvent event, float delta) {
LogHelper.debug(SwipeListener.class, "onVerticalScroll - y: " + ((int) event.getY()) + " x: " + ((int) event.getX()));
if (event.getPointerCount() == 1) {
if (this.brightnessOrientation == Orientation.VERTICAL && (this.brightnessCoverage == Coverage.FULL || getCoverageVertical(event) == this.brightnessCoverage)) {
updateBrightnessProgressBarVertical(event);
}
if (this.volumeOrientation != Orientation.VERTICAL) {
return;
}
if (this.volumeCoverage == Coverage.FULL || getCoverageVertical(event) == this.volumeCoverage) {
updateVolumeProgressBarVertical(event);
}
}
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onSwipeRight() {
LogHelper.debug(SwipeListener.class, "onSwipeRight");
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onSwipeLeft() {
LogHelper.debug(SwipeListener.class, "onSwipeLeft");
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onSwipeBottom() {
LogHelper.debug(SwipeListener.class, "onSwipeBottom");
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onSwipeTop() {
LogHelper.debug(SwipeListener.class, "onSwipeTop");
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onDown(MotionEvent event) {
LogHelper.debug(SwipeListener.class, "onDown");
if (event.getPointerCount() == 1) {
if (this.brightnessOrientation == Orientation.VERTICAL && (this.brightnessCoverage == Coverage.FULL || getCoverageVertical(event) == this.brightnessCoverage)) {
this.mBrightnessDownPos = getProgressVertical(event, this.mBrightness.Max);
}
if (this.volumeOrientation == Orientation.VERTICAL && (this.volumeCoverage == Coverage.FULL || getCoverageVertical(event) == this.volumeCoverage)) {
this.mVolumeDownPos = getProgressVertical(event, this.mVolume.Max);
}
if (this.brightnessOrientation == Orientation.HORIZONTAL && (this.brightnessCoverage == Coverage.FULL || getCoverageHorizontal(event) == this.brightnessCoverage)) {
this.mBrightnessDownPos = getProgressHorizontal(event, this.mBrightness.Max);
}
if (this.volumeOrientation == Orientation.HORIZONTAL && (this.volumeCoverage == Coverage.FULL || getCoverageHorizontal(event) == this.volumeCoverage)) {
this.mVolumeDownPos = getProgressHorizontal(event, this.mVolume.Max);
}
this.mVolumeDownProgress = this.mVolume.Progress;
this.mBrightnessDownProgress = this.mBrightness.Progress;
}
}
@Override // app.revanced.integrations.videoplayer.Fenster.FensterEventsListener
public void onUp() {
LogHelper.debug(SwipeListener.class, "onUp");
hideNotifications();
}
public void disable() {
if (this.mBrightness != null) {
this.mBrightness.disable();
}
if (this.mVolume != null) {
this.mVolume.disable();
}
hideNotifications();
}
public void enable(boolean brightness, boolean volume) {
checkPlayerOverlaysView();
if (brightness && this.mBrightness != null) {
this.mBrightness.enable();
}
if (volume && this.mVolume != null) {
this.mVolume.enable();
}
}
public void hideNotifications() {
if (this.handler == null) {
this.handler = new Handler();
}
// from class: app.revanced.integrations.videoplayer.Fenster.XFenster.1
// java.lang.Runnable
this.handler.postDelayed(() -> {
SwipeListener.this.mVolume.hide();
SwipeListener.this.mBrightness.hide();
}, 2000L);
}
private void updateVolumeProgressBarVertical(MotionEvent event) {
float difference = getDifferenceVertical(this.mVolumeDownPos, getProgressVertical(event, this.mVolume.Max));
if (this.mBrightness.isVisible()) {
this.mBrightness.hide();
}
this.mVolume.manuallyUpdate((int) (this.mVolumeDownProgress + difference));
}
private void updateBrightnessProgressBarVertical(MotionEvent event) {
float difference = getDifferenceVertical(this.mBrightnessDownPos, getProgressVertical(event, this.mBrightness.Max));
if (this.mVolume.isVisible()) {
this.mVolume.hide();
}
this.mBrightness.manuallyUpdate((int) (this.mBrightnessDownProgress + difference));
}
private void updateVolumeProgressBarHorizontal(MotionEvent event) {
float difference = getDifferenceHorizontal(this.mVolumeDownPos, getProgressHorizontal(event, this.mVolume.Max));
if (this.mBrightness.isVisible()) {
this.mBrightness.hide();
}
this.mVolume.manuallyUpdate((int) (this.mVolumeDownProgress + difference));
}
private void updateBrightnessProgressBarHorizontal(MotionEvent event) {
float difference = getDifferenceHorizontal(this.mBrightnessDownPos, getProgressHorizontal(event, this.mBrightness.Max));
if (this.mVolume.isVisible()) {
this.mVolume.hide();
}
this.mBrightness.manuallyUpdate((int) (this.mBrightnessDownProgress + difference));
}
private float getDifferenceVertical(float downProgress, float newProgress) {
float diff = downProgress - newProgress;
return diff * (-1.0f);
}
private float getDifferenceHorizontal(float downProgress, float newProgress) {
float diff = downProgress - newProgress;
return diff;
}
private float getProgressVertical(MotionEvent event, int maxSteps) {
float progress = calculateProgressVertical(event, maxSteps);
LogHelper.debug(SwipeListener.class, "Progress vertical: " + progress);
return progress;
}
private float getProgressHorizontal(MotionEvent event, int maxSteps) {
float progress = calculateProgressHorizontal(event, maxSteps);
LogHelper.debug(SwipeListener.class, "Progress horizontal: " + progress);
return progress;
}
private float calculateProgressVertical(MotionEvent event, int maxSteps) {
float scale;
int height = this.mViewGroup.getHeight();
LogHelper.debug(SwipeListener.class, "calculateProgressVertical - height: " + height);
int available = (height - this.mPaddingTop) - this.mPaddingBottom;
int y = height - ((int) event.getY());
float progress = 0.0f;
if (y < this.mPaddingBottom) {
scale = 0.0f;
} else if (y > height - this.mPaddingTop) {
scale = 1.0f;
} else {
scale = (y - this.mPaddingBottom) / available;
progress = this.mTouchProgressOffset;
}
return progress + (maxSteps * scale);
}
private float calculateProgressHorizontal(MotionEvent event, int maxSteps) {
float scale;
int width = this.mViewGroup.getWidth();
int available = (width - this.mPaddingLeft) - this.mPaddingRight;
int x = width - ((int) event.getX());
float progress = 0.0f;
if (x < this.mPaddingRight) {
scale = 0.0f;
} else if (x > width - this.mPaddingLeft) {
scale = 1.0f;
} else {
scale = (x - this.mPaddingRight) / available;
progress = this.mTouchProgressOffset;
}
return progress + (maxSteps * scale);
}
private Coverage getCoverageHorizontal(MotionEvent event) {
int halfScreen = this.mViewGroup.getHeight() / 2;
int y = (int) event.getY();
return y <= halfScreen ? Coverage.LEFT : Coverage.RIGHT;
}
private Coverage getCoverageVertical(MotionEvent event) {
int halfScreen = this.mViewGroup.getWidth() / 2;
int x = (int) event.getX();
return x <= halfScreen ? Coverage.LEFT : Coverage.RIGHT;
}
private void checkPlayerOverlaysView() {
try {
if ((this.mViewGroup.getHeight() == 0 || this.mViewGroup.getWidth() == 0) && SwipeHelper.nextGenWatchLayout != null) {
View layout = SwipeHelper.nextGenWatchLayout.findViewById(getIdentifier());
if (layout != null) {
this.mViewGroup = (ViewGroup) layout;
this.mBrightness.refreshViewGroup(this.mViewGroup, ReVancedSettingsFragment.overlayContext);
this.mVolume.refreshViewGroup(this.mViewGroup);
LogHelper.debug(SwipeListener.class, "player_overlays refreshed");
} else {
LogHelper.debug(SwipeListener.class, "player_overlays was not found");
}
}
} catch (Exception ex) {
LogHelper.printException(SwipeListener.class, "Unable to refresh player_overlays layout", ex);
}
}
private static int getIdentifier() {
Context context = ReVancedUtils.getContext();
assert context != null;
return context.getResources().getIdentifier("player_overlays", "id", context.getPackageName());
}
}

View File

@ -1,50 +0,0 @@
package app.revanced.integrations.videoswipecontrols.helpers;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.view.WindowManager;
import app.revanced.integrations.utils.LogHelper;
/* loaded from: classes6.dex */
public class BrightnessHelper {
static Context bContext;
public static float getBrightness() {
Context context = bContext;
if (context == null) {
return -1.0f;
}
return ((Activity) context).getWindow().getAttributes().screenBrightness;
}
public static int getBrightness(Context context) {
bContext = context;
return (int) (((Activity) context).getWindow().getAttributes().screenBrightness * 100.0f);
}
public static void setBrightness(Context context, int brightness) {
LogHelper.debug(BrightnessHelper.class, "Setting brightness: " + brightness);
float bright = brightness / 100.0f;
WindowManager.LayoutParams lp = ((Activity) context).getWindow().getAttributes();
lp.screenBrightness = bright;
((Activity) context).getWindow().setAttributes(lp);
}
public static void setBrightness2(Context context, int brightness) {
LogHelper.debug(BrightnessHelper.class, "Setting brightness: " + brightness);
ContentResolver cResolver = context.getContentResolver();
android.provider.Settings.System.putInt(cResolver, "screen_brightness", brightness);
}
public static int getBrightness2(Context context) {
ContentResolver cResolver = context.getContentResolver();
try {
return android.provider.Settings.System.getInt(cResolver, "screen_brightness");
} catch (android.provider.Settings.SettingNotFoundException e) {
return 0;
}
}
}

View File

@ -1,132 +0,0 @@
package app.revanced.integrations.videoswipecontrols.seekbar;
import android.content.Context;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.SharedPrefHelper;
import app.revanced.integrations.videoswipecontrols.helpers.BrightnessHelper;
/* loaded from: classes6.dex */
public class BrightnessSeekBar {
public static final int MAX_BRIGHTNESS = 100;
public static final int MIN_BRIGHTNESS = 0;
public int Max;
public int Progress;
private boolean enabled;
Handler handler;
private final String mBrightnessKey = "revanced_brightness_value";
Context mContext;
TextView mTextView;
ViewGroup mViewGroup;
public void initialise(Context context, ViewGroup viewGroup) {
this.enabled = false;
this.mViewGroup = viewGroup;
this.mContext = context;
float systemBrightness = android.provider.Settings.System.getFloat(this.mContext.getContentResolver(), "screen_brightness", -1.0f);
int _systemBrightness = (int) ((systemBrightness / 255.0f) * 100.0f);
this.Progress = SharedPrefHelper.getInt(this.mContext, SharedPrefHelper.SharedPrefNames.YOUTUBE, "revanced_brightness_value", Integer.valueOf(_systemBrightness)).intValue();
this.Max = 100;
this.mTextView = new TextView(context);
this.mTextView.setTextSize(24.0f);
this.mTextView.setBackgroundColor(Integer.MIN_VALUE);
this.mTextView.setTextColor(-1);
this.mViewGroup.addView(this.mTextView);
}
/**
* @param context YouTubePlayerOverlaysLayout.overlayContext
*/
public void refreshViewGroup(ViewGroup viewGroup, Context context) {
if (this.mTextView.getParent() != null) {
((ViewGroup) this.mTextView.getParent()).removeView(this.mTextView);
}
this.mContext = context;
this.mViewGroup = viewGroup;
this.mViewGroup.addView(this.mTextView);
}
private void updateBrightnessProgress() {
this.Progress = BrightnessHelper.getBrightness(this.mContext);
if (this.mTextView != null) {
this.mTextView.setText("Brightness: " + this.Progress);
if (!isVisible()) {
this.mTextView.setVisibility(View.VISIBLE);
}
}
LogHelper.debug(BrightnessSeekBar.class, "updateBrightnessProgress: " + this.Progress);
}
private void disableBrightness() {
BrightnessHelper.setBrightness(this.mContext, -1);
}
public void setBrightness(int brightness) {
if (this.enabled) {
if (brightness < 0) {
brightness = 0;
} else if (brightness > 100) {
brightness = 100;
}
BrightnessHelper.setBrightness(this.mContext, brightness);
updateBrightnessProgress();
}
}
public void manuallyUpdate(int update) {
if (this.enabled) {
setBrightness(update);
}
}
public void hide() {
if (isVisible()) {
this.mTextView.setVisibility(View.INVISIBLE);
}
}
public void hideDelayed() {
if (this.handler == null) {
this.handler = new Handler();
}
this.handler.postDelayed(new Runnable() { // from class: app.revanced.integrations.videoplayer.Fenster.Seekbar.BrightnessSeekBar.1
@Override // java.lang.Runnable
public void run() {
BrightnessSeekBar.this.hide();
}
}, 2000L);
}
public boolean isVisible() {
if (this.mTextView != null && this.mTextView.getVisibility() == View.VISIBLE) {
return true;
}
return false;
}
public void disable() {
this.enabled = false;
SharedPrefHelper.saveInt(this.mContext, SharedPrefHelper.SharedPrefNames.YOUTUBE,"revanced_brightness_value", Integer.valueOf(this.Progress));
disableBrightness();
LogHelper.debug(BrightnessSeekBar.class, "Brightness swipe disabled");
}
public void enable() {
this.enabled = true;
float systemBrightness = android.provider.Settings.System.getFloat(this.mContext.getContentResolver(), "screen_brightness", -1.0f);
int _systemBrightness = (int) ((systemBrightness / 255.0f) * 100.0f);
int brightness = SharedPrefHelper.getInt(this.mContext, SharedPrefHelper.SharedPrefNames.YOUTUBE,"revanced_brightness_value", Integer.valueOf(_systemBrightness)).intValue();
if (brightness < 0) {
brightness = 0;
} else if (brightness > 100) {
brightness = 100;
}
BrightnessHelper.setBrightness(this.mContext, brightness);
LogHelper.debug(BrightnessSeekBar.class, "Brightness swipe enabled");
}
}

View File

@ -1,123 +0,0 @@
package app.revanced.integrations.videoswipecontrols.seekbar;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import app.revanced.integrations.utils.LogHelper;
/* loaded from: classes6.dex */
public class VolumeSeekBar {
public int Max;
public int Progress;
private AudioManager audioManager;
private boolean enabled;
Handler handler;
private boolean isRegistered;
private Context mContext;
TextView mTextView;
ViewGroup mViewGroup;
private final BroadcastReceiver volumeReceiver = new BroadcastReceiver() { // from class: app.revanced.integrations.videoplayer.Fenster.Seekbar.VolumeSeekBar.1
@Override // android.content.BroadcastReceiver
public void onReceive(Context context, Intent intent) {
VolumeSeekBar.this.updateVolumeProgress();
VolumeSeekBar.this.hideDelayed();
}
};
public void initialise(Context context, ViewGroup viewGroup) {
this.enabled = false;
this.mViewGroup = viewGroup;
this.mContext = context;
this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
this.Max = this.audioManager.getStreamMaxVolume(3);
this.Progress = this.audioManager.getStreamVolume(3);
this.mTextView = new TextView(context);
this.mTextView.setTextSize(24.0f);
this.mTextView.setBackgroundColor(Integer.MIN_VALUE);
this.mTextView.setTextColor(-1);
this.mViewGroup.addView(this.mTextView);
}
public void refreshViewGroup(ViewGroup viewGroup) {
if (this.mTextView.getParent() != null) {
((ViewGroup) this.mTextView.getParent()).removeView(this.mTextView);
}
this.mViewGroup = viewGroup;
this.mViewGroup.addView(this.mTextView);
}
/* JADX INFO: Access modifiers changed from: private */
public void updateVolumeProgress() {
this.Progress = this.audioManager.getStreamVolume(3);
if (this.mTextView != null) {
this.mTextView.setText("Volume: " + this.Progress);
if (!isVisible()) {
this.mTextView.setVisibility(View.VISIBLE);
}
}
LogHelper.debug(VolumeSeekBar.class, "updateVolumeProgress: " + this.Progress);
}
private void setVolume(int volume) {
this.audioManager.setStreamVolume(3, volume, 0);
updateVolumeProgress();
}
private void registerVolumeReceiver() {
this.mContext.registerReceiver(this.volumeReceiver, new IntentFilter("android.media.VOLUME_CHANGED_ACTION"));
this.isRegistered = true;
}
public void unregisterVolumeReceiver() {
this.mContext.unregisterReceiver(this.volumeReceiver);
this.isRegistered = false;
}
public void manuallyUpdate(int update) {
if (this.enabled) {
setVolume(update);
}
}
public void hide() {
if (isVisible()) {
this.mTextView.setVisibility(View.INVISIBLE);
}
}
public void hideDelayed() {
if (this.handler == null) {
this.handler = new Handler();
}
// from class: app.revanced.integrations.videoplayer.Fenster.Seekbar.VolumeSeekBar.2
// java.lang.Runnable
this.handler.postDelayed(VolumeSeekBar.this::hide, 2000L);
}
public boolean isVisible() {
return this.mTextView != null && this.mTextView.getVisibility() == View.VISIBLE;
}
public void disable() {
this.enabled = false;
if (this.isRegistered) {
unregisterVolumeReceiver();
}
}
public void enable() {
this.enabled = true;
this.Progress = this.audioManager.getStreamVolume(3);
if (!this.isRegistered) {
registerVolumeReceiver();
}
}
}

View File

@ -60,9 +60,12 @@
<PreferenceScreen android:title="@string/revanced_xfenster_title" android:key="xfenster_screen" android:summary="@string/revanced_xfenster_screen_summary"> <PreferenceScreen android:title="@string/revanced_xfenster_title" android:key="xfenster_screen" android:summary="@string/revanced_xfenster_screen_summary">
<SwitchPreference android:title="@string/revanced_xfenster_brightness_title" android:key="pref_xfenster_brightness" android:defaultValue="false" android:summaryOn="@string/revanced_xfenster_brightness_summary_on" android:summaryOff="@string/revanced_xfenster_brightness_summary_off" /> <SwitchPreference android:title="@string/revanced_xfenster_brightness_title" android:key="pref_xfenster_brightness" android:defaultValue="false" android:summaryOn="@string/revanced_xfenster_brightness_summary_on" android:summaryOff="@string/revanced_xfenster_brightness_summary_off" />
<SwitchPreference android:title="@string/revanced_xfenster_volume_title" android:key="pref_xfenster_volume" android:defaultValue="false" android:summaryOn="@string/revanced_xfenster_volume_summary_on" android:summaryOff="@string/revanced_xfenster_volume_summary_off" /> <SwitchPreference android:title="@string/revanced_xfenster_volume_title" android:key="pref_xfenster_volume" android:defaultValue="false" android:summaryOn="@string/revanced_xfenster_volume_summary_on" android:summaryOff="@string/revanced_xfenster_volume_summary_off" />
<!--
<SwitchPreference android:title="@string/revanced_xfenster_tablet_title" android:key="pref_xfenster_tablet" android:defaultValue="false" android:summaryOn="@string/revanced_xfenster_tablet_summary_on" android:summaryOff="@string/revanced_xfenster_tablet_summary_off" /> <SwitchPreference android:title="@string/revanced_xfenster_tablet_title" android:key="pref_xfenster_tablet" android:defaultValue="false" android:summaryOn="@string/revanced_xfenster_tablet_summary_on" android:summaryOff="@string/revanced_xfenster_tablet_summary_off" />
<EditTextPreference android:numeric="integer" android:title="@string/revanced_swipe_threshold_title" android:key="pref_xfenster_swipe_threshold" android:summary="@string/revanced_swipe_threshold_summary" android:defaultValue="0" /> <EditTextPreference android:numeric="integer" android:title="@string/revanced_swipe_threshold_title" android:key="pref_xfenster_swipe_threshold" android:summary="@string/revanced_swipe_threshold_summary" android:defaultValue="0" />
<EditTextPreference android:numeric="integer" android:title="@string/revanced_swipe_padding_top_title" android:key="pref_xfenster_swipe_padding_top" android:summary="@string/revanced_swipe_padding_top_summary" android:defaultValue="20" /> <EditTextPreference android:numeric="integer" android:title="@string/revanced_swipe_padding_top_title" android:key="pref_xfenster_swipe_padding_top" android:summary="@string/revanced_swipe_padding_top_summary" android:defaultValue="20" />
-->
</PreferenceScreen> </PreferenceScreen>
<PreferenceScreen android:title="@string/revanced_buffer_title" android:key="buffer_screen"> <PreferenceScreen android:title="@string/revanced_buffer_title" android:key="buffer_screen">
<EditTextPreference android:numeric="integer" android:title="@string/revanced_maximum_buffer_title" android:key="pref_max_buffer_ms" android:summary="@string/revanced_maximum_buffer_summary" android:defaultValue="120000" /> <EditTextPreference android:numeric="integer" android:title="@string/revanced_maximum_buffer_title" android:key="pref_max_buffer_ms" android:summary="@string/revanced_maximum_buffer_summary" android:defaultValue="120000" />

View File

@ -6,6 +6,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.2.1' classpath 'com.android.tools.build:gradle:7.2.1'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files