diff --git a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/KnownPatch.kt b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/KnownPatch.kt index 5d2ec5d..38d7bbe 100644 --- a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/KnownPatch.kt +++ b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/KnownPatch.kt @@ -148,15 +148,15 @@ enum class KnownPatch( default = Disabled, defaultVariantIndex = 2, variants = listOf( - PatchVariant( // 0: Floating — stock rounded pill (no patch; the progress border is an option) + PatchVariant( // 0: Floating — stock rounded pill titleRes = R.string.patch_mini_player_variant_floating_title, fileNames = emptyList(), ), - PatchVariant( // 1: Grey — square, theme background (shown as "Legacy" when Dynamic BG is on) + PatchVariant( // 1: Grey — square titleRes = R.string.patch_mini_player_variant_square_grey_title, fileNames = listOf("mini-player-grey.patch"), ), - PatchVariant( // 2: Black — square, forced black background (hidden when Dynamic BG is on) + PatchVariant( // 2: Black — square black background titleRes = R.string.patch_mini_player_variant_square_black_title, fileNames = listOf("mini-player-black.patch"), ), @@ -193,10 +193,24 @@ enum class KnownPatch( extensionFiles = listOf( "radiant/MiniPlayerGestures.smali", "radiant/MiniPlayerGestures\$Gesture.smali", + "radiant/MiniPlayerGestures\$FeedbackLayer.smali", + "radiant/MiniPlayerGestures\$FeedbackResetAnimator.smali", "radiant/MiniPlayerGestures\$RootGesture.smali", "radiant/MiniPlayerGestures\$ApplyPending.smali", ), ), + PatchOption.Choice( + key = "swipe_up_drag", + titleRes = R.string.patch_mini_player_drag_title, + descRes = R.string.patch_mini_player_drag_desc, + entries = listOf( + ChoiceEntry(R.string.patch_mini_player_drag_static, value = "0x0"), + ChoiceEntry(R.string.patch_mini_player_drag_drag, value = "0x1"), + ), + defaultIndex = 1, + requiresOption = "gestures", + token = "RL_MINI_PLAYER_SWIPE_UP_DRAG", + ), // Swipe left/right to skip PatchOption.Toggle( key = "next_prev", diff --git a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchOption.kt b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchOption.kt index b32a26e..4ce2e8e 100644 --- a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchOption.kt +++ b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchOption.kt @@ -32,6 +32,8 @@ sealed interface PatchOption { val hidesVariants: List = emptyList(), /** Variant title overrides (index -> @StringRes) applied while this toggle is on. */ val relabelVariants: Map = emptyMap(), + /** Placeholder name (without the surrounding `__`) baked into the `.patch` files. */ + val token: String? = null, ) : PatchOption /** A continuous (or stepped) numeric value within [valueRange]. */ @@ -60,9 +62,12 @@ sealed interface PatchOption { @StringRes override val descRes: Int, val entries: List, val defaultIndex: Int = 0, + val requiresOption: String? = null, + val token: String? = null, ) : PatchOption } data class ChoiceEntry( @StringRes val labelRes: Int, + val value: String? = null, ) diff --git a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchOptions.kt b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchOptions.kt index 0676722..96a1292 100644 --- a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchOptions.kt +++ b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchOptions.kt @@ -52,6 +52,10 @@ data class PatchOptions( fun sliderValue(spec: PatchSpec, option: OptionSpec.Slider): Float = (optionFloats["${spec.id}/${option.key}"] ?: option.default).coerceIn(option.min, option.max) + fun choiceIndex(spec: PatchSpec, option: OptionSpec.Choice): Int = + (optionInts["${spec.id}/${option.key}"] ?: option.defaultIndex) + .coerceIn(0, option.entries.lastIndex.coerceAtLeast(0)) + fun isToggleOn(spec: PatchSpec, option: OptionSpec.Toggle): Boolean = optionBools["${spec.id}/${option.key}"] ?: option.default @@ -111,10 +115,27 @@ data class PatchOptions( for (spec in specs) { if (!isEnabled(spec)) continue for (option in spec.advancedOptions) { - if (option !is OptionSpec.Slider) continue - val token = option.token ?: continue - val encode = option.encode ?: continue - put("__${token}__", encode.encode(sliderValue(spec, option))) + when (option) { + is OptionSpec.Toggle -> { + val token = option.token ?: continue + put("__${token}__", if (isToggleActive(spec, option)) "0x1" else "0x0") + } + is OptionSpec.Slider -> { + val token = option.token ?: continue + val encode = option.encode ?: continue + put("__${token}__", encode.encode(sliderValue(spec, option))) + } + is OptionSpec.Choice -> { + val token = option.token ?: continue + val gatedOff = option.requiresOption?.let { key -> + spec.advancedOptions.filterIsInstance() + .firstOrNull { it.key == key } + ?.let { !isToggleOn(spec, it) } + } ?: false + val index = if (gatedOff) 0 else choiceIndex(spec, option) + put("__${token}__", option.values.getOrNull(index) ?: continue) + } + } } } } diff --git a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchSpec.kt b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchSpec.kt index 03a7780..22aa3d7 100644 --- a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchSpec.kt +++ b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/PatchSpec.kt @@ -68,6 +68,8 @@ sealed interface OptionSpec { val hidesVariants: List = emptyList(), /** Variant title overrides (index -> title) applied while this toggle is on. */ val relabelVariants: Map = emptyMap(), + /** Placeholder name (without the surrounding `__`) baked into the `.patch` files. */ + val token: String? = null, ) : OptionSpec @Immutable @@ -96,10 +98,13 @@ sealed interface OptionSpec { @SerialName("choice") data class Choice( override val key: String, - override val title: String, + override val title: String = "", override val description: String = "", val entries: List = emptyList(), val defaultIndex: Int = 0, + val values: List = emptyList(), + val requiresOption: String? = null, + val token: String? = null, ) : OptionSpec } @@ -162,6 +167,7 @@ private fun PatchOption.toSpec(resolve: (Int) -> String): OptionSpec = when (thi requiresOption = requiresOption, hidesVariants = hidesVariants, relabelVariants = relabelVariants.mapValues { resolve(it.value) }, + token = token, ) is PatchOption.Slider -> OptionSpec.Slider( @@ -184,6 +190,9 @@ private fun PatchOption.toSpec(resolve: (Int) -> String): OptionSpec = when (thi description = resolve(descRes), entries = entries.map { resolve(it.labelRes) }, defaultIndex = defaultIndex, + values = entries.map { it.value ?: "" }, + requiresOption = requiresOption, + token = token, ) } diff --git a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/components/PatchAdvancedOptionsSheet.kt b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/components/PatchAdvancedOptionsSheet.kt index b6a0e74..6c1b8cf 100644 --- a/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/components/PatchAdvancedOptionsSheet.kt +++ b/Manager/app/src/main/kotlin/com/meowarex/rlmobile/ui/screens/patchopts/components/PatchAdvancedOptionsSheet.kt @@ -1,5 +1,8 @@ package com.meowarex.rlmobile.ui.screens.patchopts.components +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.background +import androidx.compose.foundation.border import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.* @@ -11,6 +14,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role @@ -87,18 +91,91 @@ fun PatchAdvancedOptionsSheet( HorizontalDivider() - val sheetOptions = patch.advancedOptions.filter { it !is OptionSpec.Toggle || !it.inline } + val parentKeys = patch.advancedOptions + .filterIsInstance() + .filter { !it.inline } + .map { it.key } + .toSet() + val sheetOptions = patch.advancedOptions.filter { option -> + when { + option is OptionSpec.Toggle && option.inline -> false + option is OptionSpec.Toggle && option.requiresOption in parentKeys -> false + else -> true + } + } for (option in sheetOptions) key(option.key) { val lock = patch.optionLock(option, selectedVariant) { state.toggle(patch, it) } when (option) { - is OptionSpec.Toggle -> ToggleOptionRow( - title = option.title, - description = option.description, - checked = state.toggle(patch, option), - onCheckedChange = { state.setToggle(patch, option, it) }, - locked = lock != OptionLock.Free, - onLockedTap = { lockDialog = lock }, - ) + is OptionSpec.Toggle -> { + val toggleOn = state.toggle(patch, option) + val gatedChoices = patch.advancedOptions.filterIsInstance() + .filter { it.requiresOption == option.key } + val gatedToggles = patch.advancedOptions.filterIsInstance() + .filter { it.requiresOption == option.key && !it.inline } + val hasSubOptions = gatedChoices.isNotEmpty() || gatedToggles.isNotEmpty() + val carded = hasSubOptions && toggleOn + + Column( + modifier = if (carded) { + Modifier + .fillMaxWidth() + .clip(MaterialTheme.shapes.medium) + .background(MaterialTheme.colorScheme.primary.copy(alpha = 0.07f)) + .border( + width = 1.5.dp, + color = MaterialTheme.colorScheme.primary.copy(alpha = 0.55f), + shape = MaterialTheme.shapes.medium, + ) + .padding(horizontal = 12.dp, vertical = 4.dp) + } else { + Modifier.fillMaxWidth() + }, + ) { + ToggleOptionRow( + title = option.title, + description = option.description, + checked = toggleOn, + onCheckedChange = { state.setToggle(patch, option, it) }, + locked = lock != OptionLock.Free, + onLockedTap = { lockDialog = lock }, + modifier = if (hasSubOptions) Modifier.padding(vertical = 6.dp) else Modifier, + ) + if (hasSubOptions) { + AnimatedVisibility(visible = toggleOn) { + Column( + verticalArrangement = Arrangement.spacedBy(10.dp), + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 8.dp), + ) { + gatedChoices.forEach { choice -> + key(choice.key) { + ChoiceOptionRow( + title = choice.title, + entries = choice.entries, + selectedIndex = state.choice(patch, choice), + onSelect = { state.setChoice(patch, choice, it) }, + ) + } + } + gatedToggles.forEach { sub -> + key(sub.key) { + val subLock = patch.optionLock(sub, selectedVariant) { state.toggle(patch, it) } + ToggleOptionRow( + title = sub.title, + description = sub.description, + checked = state.toggle(patch, sub), + onCheckedChange = { state.setToggle(patch, sub, it) }, + locked = subLock != OptionLock.Free, + onLockedTap = { lockDialog = subLock }, + ) + } + } + } + } + } + } + } is OptionSpec.Slider -> SliderOptionRow( title = option.title, @@ -110,13 +187,15 @@ fun PatchAdvancedOptionsSheet( onValueChange = { state.setSlider(patch, option, it) }, ) - is OptionSpec.Choice -> ChoiceOptionRow( - title = option.title, - description = option.description, - entries = option.entries, - selectedIndex = state.choice(patch, option), - onSelect = { state.setChoice(patch, option, it) }, - ) + is OptionSpec.Choice -> + if (option.requiresOption == null) { + ChoiceOptionRow( + title = option.title, + entries = option.entries, + selectedIndex = state.choice(patch, option), + onSelect = { state.setChoice(patch, option, it) }, + ) + } } } @@ -147,13 +226,14 @@ private fun ToggleOptionRow( onCheckedChange: (Boolean) -> Unit, locked: Boolean = false, onLockedTap: () -> Unit = {}, + modifier: Modifier = Modifier, ) { val interactionSource = remember(::MutableInteractionSource) Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(12.dp), - modifier = Modifier + modifier = modifier .fillMaxWidth() .clickable( interactionSource = interactionSource, @@ -279,18 +359,25 @@ private fun snapToNearestStep( @Composable private fun ChoiceOptionRow( - title: String, - description: String, entries: List, selectedIndex: Int, onSelect: (Int) -> Unit, + title: String = "", + modifier: Modifier = Modifier, ) { Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(8.dp), + modifier = modifier.fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(6.dp), + horizontalAlignment = Alignment.CenterHorizontally, ) { - OptionText(title = title, description = description) - + if (title.isNotEmpty()) { + Text( + text = title, + style = MaterialTheme.typography.labelMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center, + ) + } SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) { entries.forEachIndexed { index, entry -> SegmentedButton( diff --git a/Manager/app/src/main/res/values/strings.xml b/Manager/app/src/main/res/values/strings.xml index 9b7c46e..2aaa020 100644 --- a/Manager/app/src/main/res/values/strings.xml +++ b/Manager/app/src/main/res/values/strings.xml @@ -295,6 +295,10 @@ Integrates the Seekbar into the control panel at the bottom of the screen. Mini-Player Gestures Swipe up on the mini-player to open the full player. + Swipe Up Style + Whether the player follows your finger when swiping up to open it. + Static + Drag Next/Previous Gestures Swipe left or right on the mini-player to skip tracks. Mini-Player Dynamic Background diff --git a/patches/data.json b/patches/data.json index d4af060..1ea66ae 100644 --- a/patches/data.json +++ b/patches/data.json @@ -1,5 +1,5 @@ { "tidalVersionCode": 9090, "tidalApkUrl": "https://github.com/meowarex/rl-mobile/releases/download/latest/tidal-stock.apk", - "patchesVersion": "0.9.12" + "patchesVersion": "0.9.13" } diff --git a/patches/extension/radiant/MiniPlayerGestures$FeedbackLayer.smali b/patches/extension/radiant/MiniPlayerGestures$FeedbackLayer.smali new file mode 100644 index 0000000..f6e8821 --- /dev/null +++ b/patches/extension/radiant/MiniPlayerGestures$FeedbackLayer.smali @@ -0,0 +1,70 @@ +.class public final Lradiant/MiniPlayerGestures$FeedbackLayer; +.super Ljava/lang/Object; +.implements Lyl0/l; + + +# annotations +.annotation system Ldalvik/annotation/EnclosingClass; + value = Lradiant/MiniPlayerGestures; +.end annotation + +.annotation system Ldalvik/annotation/InnerClass; + accessFlags = 0x19 + name = "FeedbackLayer" +.end annotation + + +# static fields +.field public static final INSTANCE:Lradiant/MiniPlayerGestures$FeedbackLayer; + + +# direct methods +.method static constructor ()V + .locals 1 + + new-instance v0, Lradiant/MiniPlayerGestures$FeedbackLayer; + + invoke-direct {v0}, Lradiant/MiniPlayerGestures$FeedbackLayer;->()V + + sput-object v0, Lradiant/MiniPlayerGestures$FeedbackLayer;->INSTANCE:Lradiant/MiniPlayerGestures$FeedbackLayer; + + return-void +.end method + +.method private constructor ()V + .locals 0 + + invoke-direct {p0}, Ljava/lang/Object;->()V + + return-void +.end method + + +# virtual methods +.method public final invoke(Landroidx/compose/ui/graphics/GraphicsLayerScope;)Lkotlin/u; + .locals 1 + + sget-object v0, Lradiant/MiniPlayerGestures;->v:Landroidx/compose/runtime/MutableFloatState; + + invoke-interface {v0}, Landroidx/compose/runtime/MutableFloatState;->getFloatValue()F + + move-result v0 + + invoke-interface {p1, v0}, Landroidx/compose/ui/graphics/GraphicsLayerScope;->setTranslationY(F)V + + sget-object p1, Lkotlin/u;->a:Lkotlin/u; + + return-object p1 +.end method + +.method public bridge synthetic invoke(Ljava/lang/Object;)Ljava/lang/Object; + .locals 0 + + check-cast p1, Landroidx/compose/ui/graphics/GraphicsLayerScope; + + invoke-virtual {p0, p1}, Lradiant/MiniPlayerGestures$FeedbackLayer;->invoke(Landroidx/compose/ui/graphics/GraphicsLayerScope;)Lkotlin/u; + + move-result-object p1 + + return-object p1 +.end method diff --git a/patches/extension/radiant/MiniPlayerGestures$FeedbackResetAnimator.smali b/patches/extension/radiant/MiniPlayerGestures$FeedbackResetAnimator.smali new file mode 100644 index 0000000..e0f1c4b --- /dev/null +++ b/patches/extension/radiant/MiniPlayerGestures$FeedbackResetAnimator.smali @@ -0,0 +1,60 @@ +.class public final Lradiant/MiniPlayerGestures$FeedbackResetAnimator; +.super Ljava/lang/Object; +.implements Landroid/animation/ValueAnimator$AnimatorUpdateListener; + + +# annotations +.annotation system Ldalvik/annotation/EnclosingClass; + value = Lradiant/MiniPlayerGestures; +.end annotation + +.annotation system Ldalvik/annotation/InnerClass; + accessFlags = 0x19 + name = "FeedbackResetAnimator" +.end annotation + + +# direct methods +.method public constructor ()V + .locals 0 + + invoke-direct {p0}, Ljava/lang/Object;->()V + + return-void +.end method + + + +# virtual methods +.method public final onAnimationUpdate(Landroid/animation/ValueAnimator;)V + .locals 3 + + move-object v0, p1 + + invoke-virtual {p1}, Landroid/animation/ValueAnimator;->getAnimatedValue()Ljava/lang/Object; + + move-result-object v1 + + check-cast v1, Ljava/lang/Float; + + invoke-virtual {v1}, Ljava/lang/Float;->floatValue()F + + move-result v1 + + invoke-static {v1}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + + invoke-virtual {v0}, Landroid/animation/ValueAnimator;->getAnimatedFraction()F + + move-result v1 + + const/high16 v2, 0x3f800000 # 1.0f + + cmpg-float v1, v1, v2 + + if-gez v1, :done + + invoke-static {v0}, Lradiant/MiniPlayerGestures;->clearSwipeFeedbackAnimator(Landroid/animation/ValueAnimator;)V + + :done + return-void +.end method diff --git a/patches/extension/radiant/MiniPlayerGestures$Gesture.smali b/patches/extension/radiant/MiniPlayerGestures$Gesture.smali index f7b00e2..276e404 100644 --- a/patches/extension/radiant/MiniPlayerGestures$Gesture.smali +++ b/patches/extension/radiant/MiniPlayerGestures$Gesture.smali @@ -38,9 +38,12 @@ # True once horizontal movement wins (prevents later vertical start) .field public j:Z +# Drag option enabled +.field public final k:Z + # direct methods -.method public constructor (Lyl0/l;Landroidx/compose/material3/SheetState;)V +.method public constructor (Lyl0/l;Landroidx/compose/material3/SheetState;Z)V .locals 0 invoke-direct {p0}, Ljava/lang/Object;->()V @@ -49,6 +52,8 @@ iput-object p2, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState; + iput-boolean p3, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z + return-void .end method @@ -150,6 +155,10 @@ iput-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->e:Z + iget-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z + + if-eqz v0, :done + iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState; iget v0, p0, Lradiant/MiniPlayerGestures$Gesture;->b:F @@ -158,6 +167,7 @@ invoke-direct {p0}, Lradiant/MiniPlayerGestures$Gesture;->openPlayer()V + :done return-void .end method @@ -189,6 +199,8 @@ # ACTION_DOWN :down + invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V + invoke-static {p1}, Lradiant/MiniPlayerGestures;->beginMotion(Landroid/view/MotionEvent;)V invoke-virtual {p1}, Landroid/view/MotionEvent;->getRawY()F @@ -221,6 +233,12 @@ iput-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->j:Z + iget v0, p0, Lradiant/MiniPlayerGestures$Gesture;->b:F + + invoke-static {v0}, Lradiant/MiniPlayerGestures;->beginSwipeGesture(F)V + + :skip_feedback_down + goto :done # ACTION_MOVE @@ -253,8 +271,17 @@ if-eqz v3, :maybe_start + invoke-static {}, Lradiant/MiniPlayerGestures;->suppressHorizontalGestures()V + + iget-boolean v3, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z + + if-eqz v3, :feedback_active + invoke-direct {p0, v2, v5, v6}, Lradiant/MiniPlayerGestures$Gesture;->dragSheet(FJ)V + :feedback_active + invoke-static {v2}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V + goto :store_last :maybe_start @@ -281,28 +308,60 @@ move-result v8 - const/high16 v9, 0x41800000 # 16.0f + const/high16 v9, 0x40c00000 # 6.0f axis deadzone invoke-static {v9}, Lradiant/MiniPlayerGestures$Gesture;->dp(F)F move-result v9 + invoke-static {}, Lradiant/MiniPlayerGestures;->isHorizontalGestureLocked()Z + + move-result v10 + + if-eqz v10, :horizontal_check + + const/4 v10, 0x0 + + invoke-static {v10}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + + goto :store_last + + :horizontal_check + cmpg-float v10, v7, v9 - if-gez v10, :vertical_check + if-gez v10, :horizontal_dominance - const/high16 v10, 0x3fc00000 # 1.5f + goto :vertical_check + + :horizontal_dominance + + const v10, 0x3f8ccccd # 1.1f mul-float/2addr v10, v8 - cmpl-float v10, v7, v10 + cmpg-float v10, v7, v10 - if-lez v10, :vertical_check + if-gez v10, :horizontal_wins + + goto :vertical_check + + :horizontal_wins + + invoke-static {}, Lradiant/MiniPlayerGestures;->lockHorizontalGesture()Z + + move-result v10 + + if-eqz v10, :store_last const/4 v10, 0x1 iput-boolean v10, p0, Lradiant/MiniPlayerGestures$Gesture;->j:Z + const/4 v10, 0x0 + + invoke-static {v10}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + goto :store_last # At least 16dp up to open the player @@ -313,10 +372,12 @@ if-lez v10, :vertical_dominance + invoke-static {v2}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V + goto :store_last :vertical_dominance - const/high16 v10, 0x3fc00000 # 1.5f -> has to dominate horizontal mov. by 1.5x + const v10, 0x3f8ccccd # 1.1f -> early vertical axis lock mul-float/2addr v7, v10 @@ -327,10 +388,29 @@ goto :store_last :begin + invoke-static {}, Lradiant/MiniPlayerGestures;->lockVerticalGesture()Z + + move-result v10 + + if-eqz v10, :store_last + invoke-direct {p0, v2, v5, v6}, Lradiant/MiniPlayerGestures$Gesture;->startSheet(FJ)V + iget-boolean v10, p0, Lradiant/MiniPlayerGestures$Gesture;->e:Z + + if-eqz v10, :store_last + + invoke-static {}, Lradiant/MiniPlayerGestures;->suppressHorizontalGestures()V + + iget-boolean v10, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z + + if-eqz v10, :feedback_begin + invoke-direct {p0, v2, v5, v6}, Lradiant/MiniPlayerGestures$Gesture;->dragSheet(FJ)V + :feedback_begin + invoke-static {v2}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V + :store_last iput v0, p0, Lradiant/MiniPlayerGestures$Gesture;->c:F @@ -345,7 +425,11 @@ iget-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->e:Z - if-eqz v0, :finish + if-eqz v0, :up_no_drag + + iget-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->k:Z + + if-eqz v0, :open_simple invoke-static {p1}, Lradiant/MiniPlayerGestures;->trackMotion(Landroid/view/MotionEvent;)V @@ -367,6 +451,28 @@ invoke-direct {p0, v0}, Lradiant/MiniPlayerGestures$Gesture;->finishSheet(F)V + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V + + goto :finish + + :up_no_drag + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V + + goto :finish + + :open_simple + invoke-static {}, Lradiant/MiniPlayerGestures;->suppressHorizontalGestures()V + + invoke-virtual {p1}, Landroid/view/MotionEvent;->getRawY()F + + move-result v0 + + iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lyl0/l; + + invoke-static {v1, v0}, Lradiant/MiniPlayerGestures;->completeSimpleSwipe(Lyl0/l;F)Z + + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V + :finish invoke-direct {p0}, Lradiant/MiniPlayerGestures$Gesture;->reset()V @@ -377,7 +483,9 @@ :cancel iget-boolean v0, p0, Lradiant/MiniPlayerGestures$Gesture;->e:Z - if-eqz v0, :cancel_reset + if-eqz v0, :cancel_no_active + + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V iget-object v0, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState; @@ -385,6 +493,11 @@ invoke-static {v0, v1}, Lradiant/MiniPlayerGestures;->cancelDrag(Landroidx/compose/material3/SheetState;Lyl0/l;)V + goto :cancel_reset + + :cancel_no_active + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V + :cancel_reset invoke-direct {p0}, Lradiant/MiniPlayerGestures$Gesture;->reset()V diff --git a/patches/extension/radiant/MiniPlayerGestures$RootGesture.smali b/patches/extension/radiant/MiniPlayerGestures$RootGesture.smali index 27b0319..8400a41 100644 --- a/patches/extension/radiant/MiniPlayerGestures$RootGesture.smali +++ b/patches/extension/radiant/MiniPlayerGestures$RootGesture.smali @@ -40,16 +40,16 @@ iget-object v0, p0, Lradiant/MiniPlayerGestures$RootGesture;->b:Landroidx/compose/material3/SheetState; - invoke-static {v0}, Lradiant/MiniPlayerGestures;->isDragging(Landroidx/compose/material3/SheetState;)Z - - move-result v1 - - if-eqz v1, :done - invoke-virtual {p1}, Landroid/view/MotionEvent;->getActionMasked()I move-result v1 + invoke-static {v0}, Lradiant/MiniPlayerGestures;->isDragging(Landroidx/compose/material3/SheetState;)Z + + move-result v2 + + if-eqz v2, :maybe_reset_only + const/4 v2, 0x1 if-eq v1, v2, :up @@ -64,6 +64,51 @@ goto :done + :maybe_reset_only + const/4 v2, 0x1 + + if-eq v1, v2, :simple_up + + const/4 v2, 0x3 + + if-eq v1, v2, :reset_only + + const/4 v2, 0x2 + + if-eq v1, v2, :simple_move + + goto :done + + :reset_only + invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V + + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V + + goto :done + + :simple_move + invoke-virtual {p1}, Landroid/view/MotionEvent;->getRawY()F + + move-result v1 + + invoke-static {v1}, Lradiant/MiniPlayerGestures;->updateSimpleSwipe(F)Z + + goto :done + + :simple_up + invoke-virtual {p1}, Landroid/view/MotionEvent;->getRawY()F + + move-result v1 + + iget-object v2, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lyl0/l; + + invoke-static {v2, v1}, Lradiant/MiniPlayerGestures;->completeSimpleSwipe(Lyl0/l;F)Z + + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V + + goto :done + + # ACTION_MOVE :move invoke-static {p1}, Lradiant/MiniPlayerGestures;->trackMotion(Landroid/view/MotionEvent;)V @@ -102,6 +147,8 @@ invoke-static {v0, v2, v1}, Lradiant/MiniPlayerGestures;->finishDrag(Landroidx/compose/material3/SheetState;Lyl0/l;F)V + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V + goto :done # ACTION_CANCEL @@ -110,6 +157,8 @@ invoke-static {v0, v2}, Lradiant/MiniPlayerGestures;->cancelDrag(Landroidx/compose/material3/SheetState;Lyl0/l;)V + invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V + :done sget-object p1, Lkotlin/u;->a:Lkotlin/u; diff --git a/patches/extension/radiant/MiniPlayerGestures.smali b/patches/extension/radiant/MiniPlayerGestures.smali index 2be4df3..daf6067 100644 --- a/patches/extension/radiant/MiniPlayerGestures.smali +++ b/patches/extension/radiant/MiniPlayerGestures.smali @@ -50,8 +50,43 @@ # Mini player media state .field private static r:Z +# AppScaffold context +.field private static s:Lyl0/l; + +.field private static t:Landroidx/compose/material3/SheetState; + +.field private static u:Z + +# Feedback offset +.field public static v:Landroidx/compose/runtime/MutableFloatState; + +.field private static w:Landroid/animation/ValueAnimator; + +# Gesture axis lock: 0 = none, 1 = vertical, 2 = horizontal +.field private static x:I + +# Swipe gesture start Y +.field private static y:F + +# Relative to Y drag offset +.field private static z:F + # direct methods +.method static constructor ()V + .locals 1 + + const/4 v0, 0x0 + + invoke-static {v0}, Landroidx/compose/runtime/PrimitiveSnapshotStateKt;->mutableFloatStateOf(F)Landroidx/compose/runtime/MutableFloatState; + + move-result-object v0 + + sput-object v0, Lradiant/MiniPlayerGestures;->v:Landroidx/compose/runtime/MutableFloatState; + + return-void +.end method + .method private constructor ()V .locals 0 @@ -60,6 +95,119 @@ return-void .end method +.method public static animateSwipeFeedbackReset()V + .locals 7 + + sget-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + if-eqz v0, :read_offset + + invoke-virtual {v0}, Landroid/animation/ValueAnimator;->cancel()V + + const/4 v0, 0x0 + + sput-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + :read_offset + sget-object v0, Lradiant/MiniPlayerGestures;->v:Landroidx/compose/runtime/MutableFloatState; + + invoke-interface {v0}, Landroidx/compose/runtime/MutableFloatState;->getFloatValue()F + + move-result v0 + + invoke-static {v0}, Ljava/lang/Math;->abs(F)F + + move-result v1 + + const/4 v3, 0x0 + + const/high16 v2, 0x3f000000 # 0.5f + + cmpg-float v1, v1, v2 + + if-lez v1, :snap_zero + + const/4 v1, 0x2 + + new-array v1, v1, [F + + const/4 v2, 0x0 + + aput v0, v1, v2 + + const/4 v0, 0x1 + + aput v3, v1, v0 + + invoke-static {v1}, Landroid/animation/ValueAnimator;->ofFloat([F)Landroid/animation/ValueAnimator; + + move-result-object v1 + + const-wide/16 v4, 0xb4 # 180ms + + invoke-virtual {v1, v4, v5}, Landroid/animation/ValueAnimator;->setDuration(J)Landroid/animation/ValueAnimator; + + new-instance v0, Landroid/view/animation/DecelerateInterpolator; + + const/high16 v4, 0x3fc00000 # 1.5f + + invoke-direct {v0, v4}, Landroid/view/animation/DecelerateInterpolator;->(F)V + + invoke-virtual {v1, v0}, Landroid/animation/ValueAnimator;->setInterpolator(Landroid/animation/TimeInterpolator;)V + + new-instance v0, Lradiant/MiniPlayerGestures$FeedbackResetAnimator; + + invoke-direct {v0}, Lradiant/MiniPlayerGestures$FeedbackResetAnimator;->()V + + invoke-virtual {v1, v0}, Landroid/animation/ValueAnimator;->addUpdateListener(Landroid/animation/ValueAnimator$AnimatorUpdateListener;)V + + sput-object v1, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + invoke-virtual {v1}, Landroid/animation/ValueAnimator;->start()V + + return-void + + :snap_zero + invoke-static {v3}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + + return-void +.end method + +.method public static beginSwipeFeedback()V + .locals 1 + + sget-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + if-eqz v0, :zero + + invoke-virtual {v0}, Landroid/animation/ValueAnimator;->cancel()V + + const/4 v0, 0x0 + + sput-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + :zero + const/4 v0, 0x0 + + invoke-static {v0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + + return-void +.end method + +.method public static beginSwipeGesture(F)V + .locals 1 + + sput p0, Lradiant/MiniPlayerGestures;->y:F + + const/4 v0, 0x0 + + sput v0, Lradiant/MiniPlayerGestures;->z:F + + invoke-static {}, Lradiant/MiniPlayerGestures;->beginSwipeFeedback()V + + return-void +.end method + .method public static applyPendingDrag(Landroidx/compose/material3/SheetState;)V .locals 5 @@ -473,6 +621,114 @@ sget-boolean v0, Lradiant/MiniPlayerGestures;->b:Z + if-nez v0, :yes + + invoke-static {}, Lradiant/MiniPlayerGestures;->isHorizontalGestureSuppressed()Z + + move-result v0 + + return v0 + + :yes + const/4 v0, 0x1 + + return v0 +.end method + +.method public static isHorizontalGestureSuppressed()Z + .locals 2 + + sget v0, Lradiant/MiniPlayerGestures;->x:I + + const/4 v1, 0x1 + + if-ne v0, v1, :no + + const/4 v0, 0x1 + + return v0 + + :no + const/4 v0, 0x0 + + return v0 +.end method + +.method public static isHorizontalGestureLocked()Z + .locals 2 + + sget v0, Lradiant/MiniPlayerGestures;->x:I + + const/4 v1, 0x2 + + if-ne v0, v1, :no + + const/4 v0, 0x1 + + return v0 + + :no + const/4 v0, 0x0 + + return v0 +.end method + +.method public static lockHorizontalGesture()Z + .locals 2 + + sget v0, Lradiant/MiniPlayerGestures;->x:I + + const/4 v1, 0x1 + + if-ne v0, v1, :lock + + const/4 v0, 0x0 + + return v0 + + :lock + const/4 v0, 0x2 + + sput v0, Lradiant/MiniPlayerGestures;->x:I + + const/4 v0, 0x1 + + return v0 + +.end method + +.method public static resetGestureLock()V + .locals 1 + + const/4 v0, 0x0 + + sput v0, Lradiant/MiniPlayerGestures;->x:I + + sput v0, Lradiant/MiniPlayerGestures;->y:F + + sput v0, Lradiant/MiniPlayerGestures;->z:F + + return-void +.end method + +.method public static lockVerticalGesture()Z + .locals 2 + + sget v0, Lradiant/MiniPlayerGestures;->x:I + + const/4 v1, 0x2 + + if-ne v0, v1, :lock + + const/4 v0, 0x0 + + return v0 + + :lock + const/4 v0, 0x1 + + sput v0, Lradiant/MiniPlayerGestures;->x:I + return v0 .end method @@ -492,6 +748,63 @@ return-void .end method +.method public static configure(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V + .locals 0 + + sput-object p0, Lradiant/MiniPlayerGestures;->s:Lyl0/l; + + sput-object p1, Lradiant/MiniPlayerGestures;->t:Landroidx/compose/material3/SheetState; + + sput-boolean p2, Lradiant/MiniPlayerGestures;->u:Z + + return-void +.end method + +.method public static clearSwipeFeedbackAnimator(Landroid/animation/ValueAnimator;)V + .locals 1 + + sget-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + if-ne v0, p0, :done + + const/4 v0, 0x0 + + sput-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + :done + return-void +.end method + +.method private static dp(F)F + .locals 1 + + invoke-static {}, Landroid/content/res/Resources;->getSystem()Landroid/content/res/Resources; + + move-result-object v0 + + invoke-virtual {v0}, Landroid/content/res/Resources;->getDisplayMetrics()Landroid/util/DisplayMetrics; + + move-result-object v0 + + iget v0, v0, Landroid/util/DisplayMetrics;->density:F + + mul-float/2addr p0, v0 + + return p0 +.end method + +.method public static feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; + .locals 1 + + sget-object v0, Lradiant/MiniPlayerGestures$FeedbackLayer;->INSTANCE:Lradiant/MiniPlayerGestures$FeedbackLayer; + + invoke-static {p0, v0}, Landroidx/compose/ui/graphics/GraphicsLayerModifierKt;->graphicsLayer(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier; + + move-result-object p0 + + return-object p0 +.end method + .method private static clampReleaseVelocity(F)F .locals 4 @@ -535,12 +848,12 @@ return p0 .end method -.method public static modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;)Landroidx/compose/ui/Modifier; +.method public static modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;Z)Landroidx/compose/ui/Modifier; .locals 1 new-instance v0, Lradiant/MiniPlayerGestures$Gesture; - invoke-direct {v0, p1, p2}, Lradiant/MiniPlayerGestures$Gesture;->(Lyl0/l;Landroidx/compose/material3/SheetState;)V + invoke-direct {v0, p1, p2, p3}, Lradiant/MiniPlayerGestures$Gesture;->(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V invoke-static {p0, v0}, Landroidx/compose/ui/input/pointer/PointerInteropFilter_androidKt;->motionEventSpy(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier; @@ -549,6 +862,249 @@ return-object p0 .end method +.method public static trackAreaModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; + .locals 3 + + sget-object v0, Lradiant/MiniPlayerGestures;->s:Lyl0/l; + + if-eqz v0, :done + + sget-object v1, Lradiant/MiniPlayerGestures;->t:Landroidx/compose/material3/SheetState; + + if-eqz v1, :done + + sget-boolean v2, Lradiant/MiniPlayerGestures;->u:Z + + invoke-static {p0, v0, v1, v2}, Lradiant/MiniPlayerGestures;->modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;Z)Landroidx/compose/ui/Modifier; + + move-result-object p0 + + :done + return-object p0 +.end method + +.method public static setSwipeFeedback(F)V + .locals 5 + + const/4 v4, 0x0 + + cmpl-float v0, p0, v4 + + if-gtz v0, :snap_zero + + sget-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + if-eqz v0, :rubber_band + + invoke-virtual {v0}, Landroid/animation/ValueAnimator;->cancel()V + + const/4 v0, 0x0 + + sput-object v0, Lradiant/MiniPlayerGestures;->w:Landroid/animation/ValueAnimator; + + :rubber_band + invoke-static {p0}, Ljava/lang/Math;->abs(F)F + + move-result v0 + + const/high16 v1, 0x41800000 # 16.0f dp travel + + invoke-static {v1}, Lradiant/MiniPlayerGestures;->dp(F)F + + move-result v1 + + cmpg-float v2, v0, v1 + + if-lez v2, :publish + + sub-float/2addr v0, v1 + + const v2, 0x3e19999a # 0.15f resistance after 16dp + + mul-float/2addr v0, v2 + + const/high16 v2, 0x3d800000 # 0.0625f max up travel + + mul-float/2addr v2, v1 + + invoke-static {v0, v2}, Ljava/lang/Math;->min(FF)F + + move-result v0 + + add-float/2addr v0, v1 + + neg-float p0, v0 + + :publish + invoke-static {p0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + + return-void + + :snap_zero + invoke-static {v4}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + + return-void +.end method + +.method public static setSwipeFeedbackFromDrag(F)V + .locals 3 + + sput p0, Lradiant/MiniPlayerGestures;->z:F + + const/4 v0, 0x0 + + cmpl-float v1, p0, v0 + + if-ltz v1, :maybe_up + + invoke-static {v0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + + return-void + + :maybe_up + const/high16 v0, 0x40c00000 # 6.0f feedback deadzone + + invoke-static {v0}, Lradiant/MiniPlayerGestures;->dp(F)F + + move-result v0 + + neg-float v1, v0 + + cmpg-float v2, p0, v1 + + if-gtz v2, :snap_zero + + add-float/2addr p0, v0 + + invoke-static {p0}, Lradiant/MiniPlayerGestures;->setSwipeFeedback(F)V + + return-void + + :snap_zero + const/4 v0, 0x0 + + invoke-static {v0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + + return-void +.end method + +.method public static completeSimpleSwipe(Lyl0/l;F)Z + .locals 4 + + sget-boolean v0, Lradiant/MiniPlayerGestures;->u:Z + + if-nez v0, :no + + sget v0, Lradiant/MiniPlayerGestures;->x:I + + const/4 v1, 0x1 + + if-ne v0, v1, :no + + sget-boolean v0, Lradiant/MiniPlayerGestures;->r:Z + + if-eqz v0, :consume_no + + sget v0, Lradiant/MiniPlayerGestures;->y:F + + sub-float/2addr p1, v0 + + sput p1, Lradiant/MiniPlayerGestures;->z:F + + const/high16 v0, 0x42400000 # 48.0f release threshold + + invoke-static {v0}, Lradiant/MiniPlayerGestures;->dp(F)F + + move-result v0 + + neg-float v0, v0 + + cmpg-float v2, p1, v0 + + if-lez v2, :open + + :consume_no + invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V + + const/4 v0, 0x0 + + return v0 + + :open + invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V + + sget-object v0, Lcom/tidal/android/feature/appscaffold/ui/b$b;->a:Lcom/tidal/android/feature/appscaffold/ui/b$b; + + invoke-interface {p0, v0}, Lyl0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object; + + const/4 v0, 0x1 + + return v0 + + :no + const/4 v0, 0x0 + + return v0 +.end method + +.method public static updateSimpleSwipe(F)Z + .locals 3 + + sget-boolean v0, Lradiant/MiniPlayerGestures;->u:Z + + if-nez v0, :no + + sget v0, Lradiant/MiniPlayerGestures;->x:I + + const/4 v1, 0x1 + + if-ne v0, v1, :no + + sget v0, Lradiant/MiniPlayerGestures;->y:F + + sub-float/2addr p0, v0 + + invoke-static {p0}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V + + const/4 v0, 0x1 + + return v0 + + :no + const/4 v0, 0x0 + + return v0 +.end method + +.method public static setSwipeFeedbackDirect(F)V + .locals 1 + + sget-object v0, Lradiant/MiniPlayerGestures;->v:Landroidx/compose/runtime/MutableFloatState; + + invoke-interface {v0, p0}, Landroidx/compose/runtime/MutableFloatState;->setFloatValue(F)V + + return-void +.end method + +.method public static suppressHorizontalGestures()V + .locals 2 + + sget v0, Lradiant/MiniPlayerGestures;->x:I + + const/4 v1, 0x2 + + if-ne v0, v1, :lock + + return-void + + :lock + const/4 v0, 0x1 + + sput v0, Lradiant/MiniPlayerGestures;->x:I + + return-void +.end method + .method private static minFlingVelocity()F .locals 2 @@ -1007,6 +1563,8 @@ :apply + invoke-static {p1}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackFromDrag(F)V + invoke-static {p0}, Lradiant/MiniPlayerGestures;->applyPendingDrag(Landroidx/compose/material3/SheetState;)V const/4 v0, 0x3 diff --git a/patches/extension/radiant/MiniPlayerTrackGestures.smali b/patches/extension/radiant/MiniPlayerTrackGestures.smali index 5cfa1ff..8cffda8 100644 --- a/patches/extension/radiant/MiniPlayerTrackGestures.smali +++ b/patches/extension/radiant/MiniPlayerTrackGestures.smali @@ -126,6 +126,8 @@ .method public static beginDrag(FF)V .locals 2 + invoke-static {}, Lradiant/MiniPlayerGestures;->resetGestureLock()V + sput p0, Lradiant/MiniPlayerTrackGestures;->e:F sput p1, Lradiant/MiniPlayerTrackGestures;->f:F @@ -188,6 +190,24 @@ .method public static finishDrag(FF)I .locals 5 + invoke-static {}, Lradiant/MiniPlayerGestures;->isAnyDragging()Z + + move-result v0 + + if-eqz v0, :check_active + + const/4 v0, 0x0 + + sput-boolean v0, Lradiant/MiniPlayerTrackGestures;->g:Z + + sput-boolean v0, Lradiant/MiniPlayerTrackGestures;->h:Z + + invoke-static {}, Lradiant/MiniPlayerTrackGestures;->animateReset()V + + return v0 + + :check_active + sget-boolean v0, Lradiant/MiniPlayerTrackGestures;->g:Z if-nez v0, :active @@ -336,17 +356,38 @@ goto :done :accept + invoke-static {}, Lradiant/MiniPlayerGestures;->lockHorizontalGesture()Z + + move-result v2 + + if-eqz v2, :cancel_locked + const/4 v2, 0x1 sput-boolean v2, Lradiant/MiniPlayerTrackGestures;->h:Z :publish + const/4 v2, 0x0 + + invoke-static {v2}, Lradiant/MiniPlayerGestures;->setSwipeFeedbackDirect(F)V + invoke-static {}, Lradiant/MiniPlayerTrackGestures;->suppressTapOpen()V invoke-static {p0}, Lradiant/MiniPlayerTrackGestures;->setDragOffset(F)V :done return-void + + :cancel_locked + const/4 v0, 0x0 + + sput-boolean v0, Lradiant/MiniPlayerTrackGestures;->g:Z + + sput-boolean v0, Lradiant/MiniPlayerTrackGestures;->h:Z + + invoke-static {}, Lradiant/MiniPlayerTrackGestures;->animateReset()V + + goto :done .end method .method private static dp(F)F diff --git a/patches/manifest.json b/patches/manifest.json index 273f80d..cc2a095 100644 --- a/patches/manifest.json +++ b/patches/manifest.json @@ -35,14 +35,14 @@ "order": 30, "fileNames": ["player-backdrop.patch"], "title": "Player Backdrop", - "description": "Restores the legacy translucent backdrop blur behind the player.", + "description": "Restores the legacy translucent backdrop blur behind the player", "default": true, "advancedOptions": [ { "type": "slider", "key": "blur_strength", "title": "Blur Strength", - "description": "How strongly the album art behind the player is blurred. 0% is sharp, 50% matches the original look.", + "description": "How strongly the album art behind the player is blurred", "default": 50, "min": 0, "max": 100, @@ -55,7 +55,7 @@ "type": "slider", "key": "dimming", "title": "Backdrop Dimming", - "description": "Darkens the backdrop so the foreground controls stay legible.", + "description": "Darkens the backdrop so the foreground controls stay legible", "default": 50, "min": 0, "max": 100, @@ -163,16 +163,28 @@ "type": "toggle", "key": "gestures", "title": "Mini-Player Gestures", - "description": "Swipe up on the mini-player to open the full player.", + "description": "Adds swipe up gesture to the mini-player to reopen the player", "default": true, "fileNames": ["mini-player-gestures.patch"], "extensionFiles": [ "radiant/MiniPlayerGestures.smali", "radiant/MiniPlayerGestures$Gesture.smali", + "radiant/MiniPlayerGestures$FeedbackLayer.smali", + "radiant/MiniPlayerGestures$FeedbackResetAnimator.smali", "radiant/MiniPlayerGestures$RootGesture.smali", "radiant/MiniPlayerGestures$ApplyPending.smali" ] }, + { + "type": "choice", + "key": "swipe_up_drag", + "title": "Swipe Up Style", + "entries": ["Static", "Drag"], + "values": ["0x0", "0x1"], + "defaultIndex": 1, + "requiresOption": "gestures", + "token": "RL_MINI_PLAYER_SWIPE_UP_DRAG" + }, { "type": "toggle", "key": "next_prev", diff --git a/patches/mini-player-gestures-left-right.patch b/patches/mini-player-gestures-left-right.patch index 6e9be1a..615a79a 100644 --- a/patches/mini-player-gestures-left-right.patch +++ b/patches/mini-player-gestures-left-right.patch @@ -1,16 +1,14 @@ --- a/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali +++ b/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali -@@ -1746,6 +1746,10 @@ - invoke-static {v9, v10, v15, v6, v8}, Landroidx/compose/foundation/layout/PaddingKt;->padding-qDBjuR0(Landroidx/compose/ui/Modifier;FFFF)Landroidx/compose/ui/Modifier; - +@@ -1768,3 +1768,7 @@ move-result-object v6 +- + + invoke-static {v6, v1}, Lradiant/MiniPlayerTrackGestures;->trackModifier(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier; # attach horizontal swipe listener + + move-result-object v6 - ++ .line 38 - sget-object v21, Landroidx/compose/ui/Alignment;->Companion:Landroidx/compose/ui/Alignment$Companion; @@ -1884,5 +1888,5 @@ .line 56 iget-object v6, v0, Lcom/tidal/android/feature/appscaffold/ui/s;->b:Lcom/tidal/android/feature/appscaffold/ui/p; diff --git a/patches/mini-player-gestures.patch b/patches/mini-player-gestures.patch index b9af323..ffdbf1e 100644 --- a/patches/mini-player-gestures.patch +++ b/patches/mini-player-gestures.patch @@ -1,41 +1,10 @@ --- a/com/tidal/android/feature/appscaffold/ui/composable/i.smali +++ b/com/tidal/android/feature/appscaffold/ui/composable/i.smali -@@ -2832,27 +2832,5 @@ -- .line 150 -- sget-object v8, Lkotlin/u;->a:Lkotlin/u; -- -- .line 151 -- invoke-interface {v15}, Landroidx/compose/runtime/Composer;->rememberedValue()Ljava/lang/Object; -- -- move-result-object v10 -- -- .line 152 -- invoke-virtual/range {v22 .. v22}, Landroidx/compose/runtime/Composer$Companion;->getEmpty()Ljava/lang/Object; -- -- move-result-object v11 -- -- if-ne v10, v11, :cond_48 -- -- .line 153 -- sget-object v10, Lcom/tidal/android/feature/appscaffold/ui/composable/AppScaffoldKt$AppScaffold$3$2$1$1;->a:Lcom/tidal/android/feature/appscaffold/ui/composable/AppScaffoldKt$AppScaffold$3$2$1$1; -- -- invoke-interface {v15, v10}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V -- -- .line 154 -- :cond_48 -- check-cast v10, Landroidx/compose/ui/input/pointer/PointerInputEventHandler; -- -- invoke-static {v0, v8, v10}, Landroidx/compose/ui/input/pointer/SuspendingPointerInputFilterKt;->pointerInput(Landroidx/compose/ui/Modifier;Ljava/lang/Object;Landroidx/compose/ui/input/pointer/PointerInputEventHandler;)Landroidx/compose/ui/Modifier; -+ move-object/from16 v8, v25 # SheetState from AppScaffold -+ -+ invoke-static {v0, v6, v8}, Lradiant/MiniPlayerGestures;->modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;)Landroidx/compose/ui/Modifier; # attach swipe up listener - - move-result-object v0 -@@ -2427,6 +2406,12 @@ +@@ -2427,6 +2427,12 @@ move-object/from16 v16, v9 .line 99 -+ move-object/from16 v9, v25 # same SheetState used by the modal sheet ++ move-object/from16 v9, v25 # SheetState + + invoke-static {v5, v6, v9}, Lradiant/MiniPlayerGestures;->rootModifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;)Landroidx/compose/ui/Modifier; # continue drag after player recomposition + @@ -44,7 +13,15 @@ invoke-static {v15, v5}, Landroidx/compose/ui/ComposedModifierKt;->materializeModifier(Landroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; move-result-object v9 - +@@ -2832,2 +2838,8 @@ ++ move-object/from16 v8, v25 # SheetState from AppScaffold ++ ++ const/4 v10, __RL_MINI_PLAYER_SWIPE_UP_DRAG__ # Enable Drag option ++ ++ invoke-static {v6, v8, v10}, Lradiant/MiniPlayerGestures;->configure(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V ++ + .line 150 + sget-object v8, Lkotlin/u;->a:Lkotlin/u; --- a/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali +++ b/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali @@ -1243,5 +1243,21 @@ @@ -67,9 +44,30 @@ + + :rl_set_media + invoke-static {v5}, Lradiant/MiniPlayerGestures;->setHasMiniPlayerMedia(Z)V - +- ++ invoke-virtual {v1}, Ljava/lang/Object;->getClass()Ljava/lang/Class; - +@@ -1750,2 +1766,6 @@ ++ invoke-static {v6}, Lradiant/MiniPlayerGestures;->trackAreaModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # attach swipe up listener ++ ++ move-result-object v6 ++ + .line 38 + sget-object v21, Landroidx/compose/ui/Alignment;->Companion:Landroidx/compose/ui/Alignment$Companion; +@@ -1923,2 +1943,6 @@ ++ invoke-static {v4}, Lradiant/MiniPlayerGestures;->feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move cover (swipe up feedback) ++ ++ move-result-object v4 ++ + .line 63 + invoke-virtual/range {v22 .. v22}, Lcom/squareup/ui/market/core/theme/MarketStylesheet$c;->p0()Lc20/a; +@@ -2034,2 +2058,6 @@ ++ invoke-static {v4}, Lradiant/MiniPlayerGestures;->feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move title/artist (swipe up feedback) ++ ++ move-result-object v4 ++ + .line 72 + invoke-virtual/range {p2 .. p2}, Landroidx/compose/foundation/layout/Arrangement;->getTop()Landroidx/compose/foundation/layout/Arrangement$Vertical; --- a/androidx/compose/material3/ModalBottomSheetKt$ModalBottomSheet$4$1.smali +++ b/androidx/compose/material3/ModalBottomSheetKt$ModalBottomSheet$4$1.smali @@ -210,8 +210,10 @@