fix: swipe-controls with active engagement panel (#82)

This commit is contained in:
Chris 2022-07-14 17:18:53 +02:00 committed by GitHub
parent 2c2bdf6186
commit 669cb295a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 302 additions and 100 deletions

View File

@ -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);
}
}
}

View File

@ -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

View File

@ -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
)

View File

@ -1,4 +1,6 @@
package app.revanced.integrations.utils
package app.revanced.integrations.shared
import app.revanced.integrations.utils.Event
/**
* WatchWhile player type

View File

@ -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

View File

@ -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
)
}
}

View File

@ -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
}

View File

@ -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
)
}
}

View File

@ -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 {
/**