mirror of
https://github.com/revanced/revanced-integrations
synced 2024-11-16 22:50:31 +01:00
fix: swipe-controls
with active engagement panel (#82)
This commit is contained in:
parent
2c2bdf6186
commit
669cb295a1
@ -0,0 +1,29 @@
|
||||
package app.revanced.integrations.patches;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.integrations.shared.PlayerOverlays;
|
||||
|
||||
/**
|
||||
* Hook receiver class for 'player-overlays-hook' patch
|
||||
*
|
||||
* @usedBy app.revanced.patches.youtube.misc.playeroverlay.patch.PlayerOverlaysHookPatch
|
||||
* @smali Lapp/revanced/integrations/patches/PlayerOverlaysHookPatch;
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class PlayerOverlaysHookPatch {
|
||||
/**
|
||||
* Hook into YouTubePlayerOverlaysLayout.onFinishInflate() method
|
||||
*
|
||||
* @param thisRef reference to the view
|
||||
* @smali YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava / lang / Object ;)V
|
||||
*/
|
||||
public static void YouTubePlayerOverlaysLayout_onFinishInflateHook(@Nullable Object thisRef) {
|
||||
if (thisRef == null) return;
|
||||
if (thisRef instanceof ViewGroup) {
|
||||
PlayerOverlays.attach((ViewGroup) thisRef);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ package app.revanced.integrations.patches;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import app.revanced.integrations.utils.LogHelper;
|
||||
import app.revanced.integrations.utils.PlayerType;
|
||||
import app.revanced.integrations.shared.PlayerType;
|
||||
|
||||
/**
|
||||
* Hook receiver class for 'player-type-hook' patch
|
||||
|
@ -0,0 +1,97 @@
|
||||
package app.revanced.integrations.shared
|
||||
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import app.revanced.integrations.swipecontrols.misc.Rectangle
|
||||
import app.revanced.integrations.utils.Event
|
||||
|
||||
/**
|
||||
* hooking class for player overlays
|
||||
*/
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
object PlayerOverlays {
|
||||
|
||||
/**
|
||||
* called when the overlays finished inflating
|
||||
*/
|
||||
val onInflate = Event<ViewGroup>()
|
||||
|
||||
/**
|
||||
* called when new children are added or removed from the overlay
|
||||
*/
|
||||
val onChildrenChange = Event<ChildrenChangeEventArgs>()
|
||||
|
||||
/**
|
||||
* called when the overlay layout changes
|
||||
*/
|
||||
val onLayoutChange = Event<LayoutChangeEventArgs>()
|
||||
|
||||
/**
|
||||
* start listening for events on the provided view group
|
||||
*
|
||||
* @param overlaysLayout the overlays view group
|
||||
*/
|
||||
@JvmStatic
|
||||
fun attach(overlaysLayout: ViewGroup) {
|
||||
onInflate.invoke(overlaysLayout)
|
||||
overlaysLayout.setOnHierarchyChangeListener(object :
|
||||
ViewGroup.OnHierarchyChangeListener {
|
||||
override fun onChildViewAdded(parent: View?, child: View?) {
|
||||
if (parent is ViewGroup && child is View) {
|
||||
onChildrenChange(
|
||||
ChildrenChangeEventArgs(
|
||||
parent,
|
||||
child,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChildViewRemoved(parent: View?, child: View?) {
|
||||
if (parent is ViewGroup && child is View) {
|
||||
onChildrenChange(
|
||||
ChildrenChangeEventArgs(
|
||||
parent,
|
||||
child,
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
overlaysLayout.addOnLayoutChangeListener { view, newLeft, newTop, newRight, newBottom, oldLeft, oldTop, oldRight, oldBottom ->
|
||||
if (view is ViewGroup) {
|
||||
onLayoutChange(
|
||||
LayoutChangeEventArgs(
|
||||
view,
|
||||
Rectangle(
|
||||
oldLeft,
|
||||
oldTop,
|
||||
oldRight - oldLeft,
|
||||
oldBottom - oldTop
|
||||
),
|
||||
Rectangle(
|
||||
newLeft,
|
||||
newTop,
|
||||
newRight - newLeft,
|
||||
newBottom - newTop
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ChildrenChangeEventArgs(
|
||||
val overlaysLayout: ViewGroup,
|
||||
val childView: View,
|
||||
val wasChildRemoved: Boolean
|
||||
)
|
||||
|
||||
data class LayoutChangeEventArgs(
|
||||
val overlaysLayout: ViewGroup,
|
||||
val oldRect: Rectangle,
|
||||
val newRect: Rectangle
|
||||
)
|
@ -1,4 +1,6 @@
|
||||
package app.revanced.integrations.utils
|
||||
package app.revanced.integrations.shared
|
||||
|
||||
import app.revanced.integrations.utils.Event
|
||||
|
||||
/**
|
||||
* WatchWhile player type
|
@ -3,7 +3,7 @@ package app.revanced.integrations.swipecontrols
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import app.revanced.integrations.settings.SettingsEnum
|
||||
import app.revanced.integrations.utils.PlayerType
|
||||
import app.revanced.integrations.shared.PlayerType
|
||||
|
||||
/**
|
||||
* provider for configuration for volume and brightness swipe controls
|
||||
|
@ -0,0 +1,140 @@
|
||||
package app.revanced.integrations.swipecontrols.controller
|
||||
|
||||
import android.content.Context
|
||||
import android.util.TypedValue
|
||||
import android.view.View
|
||||
import app.revanced.integrations.shared.LayoutChangeEventArgs
|
||||
import app.revanced.integrations.shared.PlayerOverlays
|
||||
import app.revanced.integrations.swipecontrols.misc.Rectangle
|
||||
import app.revanced.integrations.swipecontrols.misc.applyDimension
|
||||
import app.revanced.integrations.utils.ReVancedUtils
|
||||
|
||||
/**
|
||||
* Y- Axis:
|
||||
* -------- 0
|
||||
* ^
|
||||
* dead | 40dp
|
||||
* v
|
||||
* -------- yDeadTop
|
||||
* ^
|
||||
* swipe |
|
||||
* v
|
||||
* -------- yDeadBtm
|
||||
* ^
|
||||
* dead | 80dp
|
||||
* v
|
||||
* -------- screenHeight
|
||||
*
|
||||
* X- Axis:
|
||||
* 0 xBrigStart xBrigEnd xVolStart xVolEnd screenWidth
|
||||
* | | | | | |
|
||||
* | 20dp | 3/8 | 2/8 | 3/8 | 20dp |
|
||||
* | <------> | <------> | <------> | <------> | <------> |
|
||||
* | dead | brightness | dead | volume | dead |
|
||||
* | <--------------------------------> |
|
||||
* 1/1
|
||||
*/
|
||||
@Suppress("PrivatePropertyName")
|
||||
class SwipeZonesController(
|
||||
context: Context,
|
||||
private val fallbackScreenRect: () -> Rectangle
|
||||
) {
|
||||
/**
|
||||
* 20dp, in pixels
|
||||
*/
|
||||
private val _20dp = 20.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
|
||||
/**
|
||||
* 40dp, in pixels
|
||||
*/
|
||||
private val _40dp = 40.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
|
||||
/**
|
||||
* 80dp, in pixels
|
||||
*/
|
||||
private val _80dp = 80.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
|
||||
/**
|
||||
* id for R.id.engagement_panel
|
||||
*/
|
||||
private val engagementPanelId =
|
||||
ReVancedUtils.getResourceIdByName(context, "id", "engagement_panel")
|
||||
|
||||
/**
|
||||
* current bounding rectangle of the player overlays
|
||||
*/
|
||||
private var playerRect: Rectangle? = null
|
||||
|
||||
/**
|
||||
* current bounding rectangle of the engagement_panel
|
||||
*/
|
||||
private var engagementPanelRect = Rectangle(0, 0, 0, 0)
|
||||
|
||||
/**
|
||||
* listener for player overlays layout change
|
||||
*/
|
||||
private fun onOverlaysLayoutChanged(args: LayoutChangeEventArgs) {
|
||||
// update engagement panel bounds
|
||||
val engagementPanel = args.overlaysLayout.findViewById<View>(engagementPanelId)
|
||||
engagementPanelRect =
|
||||
if (engagementPanel == null || engagementPanel.visibility != View.VISIBLE) {
|
||||
Rectangle(0, 0, 0, 0)
|
||||
} else {
|
||||
Rectangle(
|
||||
engagementPanel.x.toInt(),
|
||||
engagementPanel.y.toInt(),
|
||||
engagementPanel.width,
|
||||
engagementPanel.height
|
||||
)
|
||||
}
|
||||
|
||||
// update player bounds
|
||||
playerRect = args.newRect
|
||||
}
|
||||
|
||||
init {
|
||||
PlayerOverlays.onLayoutChange += this::onOverlaysLayoutChanged
|
||||
}
|
||||
|
||||
/**
|
||||
* rectangle of the area that is effectively usable for swipe controls
|
||||
*/
|
||||
private val effectiveSwipeRect: Rectangle
|
||||
get() {
|
||||
val p = if (playerRect != null) playerRect!! else fallbackScreenRect()
|
||||
return Rectangle(
|
||||
p.x + _20dp,
|
||||
p.y + _40dp,
|
||||
p.width - engagementPanelRect.width - _20dp,
|
||||
p.height - _20dp - _80dp
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* the rectangle of the volume control zone
|
||||
*/
|
||||
val volume: Rectangle
|
||||
get() {
|
||||
val zoneWidth = (effectiveSwipeRect.width * 3) / 8
|
||||
return Rectangle(
|
||||
effectiveSwipeRect.right - zoneWidth,
|
||||
effectiveSwipeRect.top,
|
||||
zoneWidth,
|
||||
effectiveSwipeRect.height
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* the rectangle of the screen brightness control zone
|
||||
*/
|
||||
val brightness: Rectangle
|
||||
get() {
|
||||
val zoneWidth = (effectiveSwipeRect.width * 3) / 8
|
||||
return Rectangle(
|
||||
effectiveSwipeRect.left,
|
||||
effectiveSwipeRect.top,
|
||||
zoneWidth,
|
||||
effectiveSwipeRect.height
|
||||
)
|
||||
}
|
||||
}
|
@ -4,11 +4,11 @@ import android.content.Context
|
||||
import android.util.TypedValue
|
||||
import android.view.GestureDetector
|
||||
import android.view.MotionEvent
|
||||
import app.revanced.integrations.swipecontrols.views.SwipeControlsHostLayout
|
||||
import app.revanced.integrations.swipecontrols.misc.ScrollDistanceHelper
|
||||
import app.revanced.integrations.swipecontrols.misc.applyDimension
|
||||
import app.revanced.integrations.swipecontrols.misc.contains
|
||||
import app.revanced.integrations.swipecontrols.misc.toPoint
|
||||
import app.revanced.integrations.swipecontrols.views.SwipeControlsHostLayout
|
||||
import app.revanced.integrations.utils.LogHelper
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.pow
|
||||
@ -98,7 +98,24 @@ open class SwipeGestureController(
|
||||
onUp(motionEvent)
|
||||
}
|
||||
|
||||
return detector.onTouchEvent(motionEvent) or shouldForceInterceptEvents
|
||||
return if (shouldForceInterceptEvents || inSwipeZone(motionEvent)) {
|
||||
detector.onTouchEvent(motionEvent) or shouldForceInterceptEvents
|
||||
} else false
|
||||
}
|
||||
|
||||
/**
|
||||
* check if provided motion event is in any active swipe zone?
|
||||
*
|
||||
* @param e the event to check
|
||||
* @return is the event in any active swipe zone?
|
||||
*/
|
||||
open fun inSwipeZone(e: MotionEvent): Boolean {
|
||||
val inVolumeZone = if (controller.config.enableVolumeControls)
|
||||
(e.toPoint() in controller.zones.volume) else false
|
||||
val inBrightnessZone = if (controller.config.enableBrightnessControl)
|
||||
(e.toPoint() in controller.zones.brightness) else false
|
||||
|
||||
return inVolumeZone || inBrightnessZone
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,8 +200,8 @@ open class SwipeGestureController(
|
||||
|
||||
// then, process the event
|
||||
when (eFrom.toPoint()) {
|
||||
in controller.volumeZone -> volumeScroller.add(disY.toDouble())
|
||||
in controller.brightnessZone -> brightnessScroller.add(disY.toDouble())
|
||||
in controller.zones.volume -> volumeScroller.add(disY.toDouble())
|
||||
in controller.zones.brightness -> brightnessScroller.add(disY.toDouble())
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
@ -1,73 +0,0 @@
|
||||
package app.revanced.integrations.swipecontrols.misc
|
||||
|
||||
import android.content.Context
|
||||
import android.util.TypedValue
|
||||
|
||||
//TODO reimplement this, again with 1/3rd for the zone size
|
||||
// because in shorts, the screen is way less wide than this code expects!
|
||||
/**
|
||||
* Y- Axis:
|
||||
* -------- 0
|
||||
* ^
|
||||
* dead | 40dp
|
||||
* v
|
||||
* -------- yDeadTop
|
||||
* ^
|
||||
* swipe |
|
||||
* v
|
||||
* -------- yDeadBtm
|
||||
* ^
|
||||
* dead | 80dp
|
||||
* v
|
||||
* -------- screenHeight
|
||||
*
|
||||
* X- Axis:
|
||||
* 0 xBrigStart xBrigEnd xVolStart xVolEnd screenWidth
|
||||
* | | | | | |
|
||||
* | 40dp | 200dp | | 200dp | 40dp |
|
||||
* | <------> | <------> | <------> | <------> | <------> |
|
||||
* | dead | brightness | dead | volume | dead |
|
||||
*/
|
||||
@Suppress("LocalVariableName")
|
||||
object SwipeZonesHelper {
|
||||
|
||||
/**
|
||||
* get the zone for volume control
|
||||
*
|
||||
* @param context the current context
|
||||
* @param screenRect the screen rectangle in the current orientation
|
||||
* @return the rectangle for the control zone
|
||||
*/
|
||||
fun getVolumeControlZone(context: Context, screenRect: Rectangle): Rectangle {
|
||||
val _40dp = 40.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
val _80dp = 80.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
val _200dp = 200.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
|
||||
return Rectangle(
|
||||
screenRect.right - _40dp - _200dp,
|
||||
screenRect.top + _40dp,
|
||||
_200dp,
|
||||
screenRect.height - _40dp - _80dp
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* get the zone for brightness control
|
||||
*
|
||||
* @param context the current context
|
||||
* @param screenRect the screen rectangle in the current orientation
|
||||
* @return the rectangle for the control zone
|
||||
*/
|
||||
fun getBrightnessControlZone(context: Context, screenRect: Rectangle): Rectangle {
|
||||
val _40dp = 40.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
val _80dp = 80.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
val _200dp = 200.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
|
||||
|
||||
return Rectangle(
|
||||
screenRect.left + _40dp,
|
||||
screenRect.top + _40dp,
|
||||
_200dp,
|
||||
screenRect.height - _40dp - _80dp
|
||||
)
|
||||
}
|
||||
}
|
@ -7,16 +7,16 @@ import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import app.revanced.integrations.shared.PlayerType
|
||||
import app.revanced.integrations.swipecontrols.SwipeControlsConfigurationProvider
|
||||
import app.revanced.integrations.swipecontrols.controller.AudioVolumeController
|
||||
import app.revanced.integrations.swipecontrols.controller.ScreenBrightnessController
|
||||
import app.revanced.integrations.swipecontrols.controller.SwipeZonesController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.NoPtSSwipeGestureController
|
||||
import app.revanced.integrations.swipecontrols.controller.gesture.SwipeGestureController
|
||||
import app.revanced.integrations.swipecontrols.misc.Rectangle
|
||||
import app.revanced.integrations.swipecontrols.misc.SwipeControlsOverlay
|
||||
import app.revanced.integrations.swipecontrols.misc.SwipeZonesHelper
|
||||
import app.revanced.integrations.utils.LogHelper
|
||||
import app.revanced.integrations.utils.PlayerType
|
||||
|
||||
/**
|
||||
* The main controller for volume and brightness swipe controls
|
||||
@ -64,6 +64,11 @@ class SwipeControlsHostLayout(
|
||||
*/
|
||||
val overlay: SwipeControlsOverlay
|
||||
|
||||
/**
|
||||
* current instance of [SwipeZonesController]
|
||||
*/
|
||||
val zones: SwipeZonesController
|
||||
|
||||
/**
|
||||
* main gesture controller
|
||||
*/
|
||||
@ -83,6 +88,9 @@ class SwipeControlsHostLayout(
|
||||
addView(it)
|
||||
}
|
||||
|
||||
// create swipe zone controller
|
||||
zones = SwipeZonesController(context) { Rectangle(x.toInt(), y.toInt(), width, height) }
|
||||
|
||||
// listen for changes in the player type
|
||||
PlayerType.onChange += this::onPlayerTypeChanged
|
||||
}
|
||||
@ -148,24 +156,6 @@ class SwipeControlsHostLayout(
|
||||
SwipeGestureController(hostActivity, this)
|
||||
else NoPtSSwipeGestureController(hostActivity, this)
|
||||
|
||||
/**
|
||||
* the current screen rectangle
|
||||
*/
|
||||
private val screenRect: Rectangle
|
||||
get() = Rectangle(x.toInt(), y.toInt(), width, height)
|
||||
|
||||
/**
|
||||
* the rectangle of the volume control zone
|
||||
*/
|
||||
val volumeZone: Rectangle
|
||||
get() = SwipeZonesHelper.getVolumeControlZone(hostActivity, screenRect)
|
||||
|
||||
/**
|
||||
* the rectangle of the screen brightness control zone
|
||||
*/
|
||||
val brightnessZone: Rectangle
|
||||
get() = SwipeZonesHelper.getBrightnessControlZone(hostActivity, screenRect)
|
||||
|
||||
|
||||
interface TouchEventListener {
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user