diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 685e5cb..6e156e2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,6 +6,8 @@ on: - main paths-ignore: - "**/*.md" + # Lets a release be re-run by hand from the Actions tab if a push event is ever missed. + workflow_dispatch: jobs: Version: @@ -23,6 +25,16 @@ jobs: BASE=$(cat .version | tr -d '[:space:]') echo "version=$BASE" >> $GITHUB_OUTPUT + # Releasing onto an existing tag silently overwrites that release's assets, so a + # forgotten .version bump replaces history instead of publishing. Fail loudly instead. + # ls-remote, not rev-parse: actions/checkout does not fetch tags by default, + # so a local lookup would always miss and the guard would never fire. + if git ls-remote --exit-code --tags origin "refs/tags/v$BASE" >/dev/null 2>&1; then + echo "::error::Tag v$BASE already exists - bump .version before releasing." \ + "Re-running this workflow as-is would overwrite the v$BASE release assets." + exit 1 + fi + Build: needs: Version uses: ./.github/workflows/build.yml diff --git a/.version b/.version index 524cb55..65087b4 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -1.1.1 +1.1.4 diff --git a/Manager/app/build.gradle.kts b/Manager/app/build.gradle.kts index fe87f0c..0b296f3 100644 --- a/Manager/app/build.gradle.kts +++ b/Manager/app/build.gradle.kts @@ -31,8 +31,8 @@ android { defaultConfig { minSdk = 24 targetSdk = 36 - versionCode = 63 - versionName = "1.1.1" + versionCode = 66 + versionName = "1.1.4" vectorDrawables { useSupportLibrary = true diff --git a/patches/data.json b/patches/data.json index 65b516b..8a9c85d 100644 --- a/patches/data.json +++ b/patches/data.json @@ -1,5 +1,5 @@ { "tidalVersionCode": 10004, "tidalApkUrl": "https://github.com/meowarex/rl-mobile/releases/download/latest/tidal-stock.apk", - "patchesVersion": "1.2.1" + "patchesVersion": "1.2.4" } diff --git a/patches/extension/dev/kawarp/KawarpEngine.smali b/patches/extension/dev/kawarp/KawarpEngine.smali index 168027e..6147cab 100644 --- a/patches/extension/dev/kawarp/KawarpEngine.smali +++ b/patches/extension/dev/kawarp/KawarpEngine.smali @@ -34,12 +34,12 @@ .field private volatile coverToken:I -.field private volatile darkenBrightness:F - .field private volatile dithering:F .field private lastFrameUptime:J +.field private volatile nextDarken:F + .field private volatile nextShader:Landroid/graphics/BitmapShader; .field private final paint:Landroid/graphics/Paint; @@ -50,6 +50,8 @@ .field private volatile playing:Z +.field private volatile prevDarken:F + .field private volatile prevShader:Landroid/graphics/BitmapShader; .field private volatile saturation:F @@ -155,7 +157,9 @@ iput-object v1, p0, Ldev/kawarp/KawarpEngine;->paint:Landroid/graphics/Paint; - iput v0, p0, Ldev/kawarp/KawarpEngine;->darkenBrightness:F + iput v0, p0, Ldev/kawarp/KawarpEngine;->prevDarken:F + + iput v0, p0, Ldev/kawarp/KawarpEngine;->nextDarken:F iput v0, p0, Ldev/kawarp/KawarpEngine;->speedFactor:F @@ -163,7 +167,7 @@ move-result v0 - if-eqz v0, :cond_55 + if-eqz v0, :cond_57 new-instance v0, Landroid/graphics/RuntimeShader; @@ -175,7 +179,7 @@ return-void - :cond_55 + :cond_57 new-instance v0, Ljava/lang/IllegalStateException; const-string v1, "KawarpEngine needs API 33+ (AGSL)" @@ -738,11 +742,15 @@ iput-object v1, v0, Ldev/kawarp/KawarpEngine;->nextShader:Landroid/graphics/BitmapShader; + iget v1, v0, Ldev/kawarp/KawarpEngine;->nextDarken:F + + iput v1, v0, Ldev/kawarp/KawarpEngine;->prevDarken:F + invoke-direct {v0, v12}, Ldev/kawarp/KawarpEngine;->brightnessFor(F)F move-result v1 - iput v1, v0, Ldev/kawarp/KawarpEngine;->darkenBrightness:F + iput v1, v0, Ldev/kawarp/KawarpEngine;->nextDarken:F invoke-static {}, Landroid/os/SystemClock;->uptimeMillis()J @@ -760,19 +768,19 @@ iget-object v0, p0, Ldev/kawarp/KawarpEngine;->nextShader:Landroid/graphics/BitmapShader; - if-eqz v0, :cond_ee + if-eqz v0, :cond_f5 const/4 v1, 0x0 cmpg-float v2, p2, v1 - if-lez v2, :cond_ee + if-lez v2, :cond_f5 cmpg-float v2, p3, v1 if-gtz v2, :cond_f - goto/16 :goto_ee + goto/16 :goto_f5 :cond_f invoke-static {}, Landroid/os/SystemClock;->uptimeMillis()J @@ -976,17 +984,27 @@ invoke-virtual {v0, v1, v2}, Landroid/graphics/RuntimeShader;->setFloatUniform(Ljava/lang/String;F)V - iget-object v0, p0, Ldev/kawarp/KawarpEngine;->shader:Landroid/graphics/RuntimeShader; + iget v0, p0, Ldev/kawarp/KawarpEngine;->prevDarken:F - iget v1, p0, Ldev/kawarp/KawarpEngine;->brightness:F + iget v1, p0, Ldev/kawarp/KawarpEngine;->nextDarken:F - iget v2, p0, Ldev/kawarp/KawarpEngine;->darkenBrightness:F + iget v2, p0, Ldev/kawarp/KawarpEngine;->prevDarken:F - mul-float/2addr v1, v2 + sub-float/2addr v1, v2 - const-string v2, "uBright" + mul-float/2addr v1, v6 - invoke-virtual {v0, v2, v1}, Landroid/graphics/RuntimeShader;->setFloatUniform(Ljava/lang/String;F)V + add-float/2addr v0, v1 + + iget-object v1, p0, Ldev/kawarp/KawarpEngine;->shader:Landroid/graphics/RuntimeShader; + + iget v2, p0, Ldev/kawarp/KawarpEngine;->brightness:F + + mul-float/2addr v2, v0 + + const-string v0, "uBright" + + invoke-virtual {v1, v0, v2}, Landroid/graphics/RuntimeShader;->setFloatUniform(Ljava/lang/String;F)V iget-object v0, p0, Ldev/kawarp/KawarpEngine;->shader:Landroid/graphics/RuntimeShader; @@ -1020,8 +1038,8 @@ return p1 - :cond_ee - :goto_ee + :cond_f5 + :goto_f5 const/4 p1, 0x0 return p1 diff --git a/patches/extension/radiant/HomeBackdrop.smali b/patches/extension/radiant/HomeBackdrop.smali index cac08ee..d8c93e3 100644 --- a/patches/extension/radiant/HomeBackdrop.smali +++ b/patches/extension/radiant/HomeBackdrop.smali @@ -5,9 +5,6 @@ # static fields .field public static volatile currentAlbumId:I -# 2 = Stock (TIDAL's blurred cover, follows live play state), 3 = Kawarp (AGSL shader) -.field public static volatile mode:I - # Live play state from the mini-player (t.c PlayState = Playing) .field public static isPlayingState:Landroidx/compose/runtime/MutableState; .annotation system Ldalvik/annotation/Signature; @@ -38,10 +35,6 @@ sput v0, Lradiant/HomeBackdrop;->currentAlbumId:I - const/4 v0, 0x2 - - sput v0, Lradiant/HomeBackdrop;->mode:I - sget-object v0, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean; const/4 v1, 0x0 @@ -73,16 +66,6 @@ return-void .end method -.method public static setModePlayback()V - .locals 1 - - const/4 v0, 0x2 - - sput v0, Lradiant/HomeBackdrop;->mode:I - - return-void -.end method - # from the mini-player state ctor (t.) whenever play state changes. .method public static onPlayState(Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;)V .locals 2 @@ -358,13 +341,7 @@ move-object v9, v1 # v9 = cover uuid - # v10 = isPlaying, mirrored from the Player Backdrop variant - sget v10, Lradiant/HomeBackdrop;->mode:I - - const/4 v11, 0x2 - - if-ne v10, v11, :rl_mode_done - + # v10 = isPlaying, straight from the live mini-player state (both modes follow it) sget-object v10, Lradiant/HomeBackdrop;->isPlayingState:Landroidx/compose/runtime/MutableState; invoke-interface {v10}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object; @@ -377,7 +354,6 @@ move-result v10 - :rl_mode_done const/4 v11, 0x0 # v11 = isSeeking = false const/4 v12, 0x0 # v12 = progress callback = null (unused while not seeking) diff --git a/patches/extension/radiant/Kawarp.smali b/patches/extension/radiant/Kawarp.smali index ce81000..791f61a 100644 --- a/patches/extension/radiant/Kawarp.smali +++ b/patches/extension/radiant/Kawarp.smali @@ -22,7 +22,7 @@ .field private static frameScheduled:Z -.field private static final frameState:Landroidx/compose/runtime/MutableState; +.field private static final frameState:Landroidx/compose/runtime/MutableIntState; .field private static frameTick:I @@ -53,23 +53,19 @@ const/4 v0, 0x0 - invoke-static {v0}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer; + invoke-static {v0}, Landroidx/compose/runtime/SnapshotIntStateKt;->mutableIntStateOf(I)Landroidx/compose/runtime/MutableIntState; move-result-object v1 - const/4 v2, 0x0 - - const/4 v3, 0x2 - - invoke-static {v1, v2, v3, v2}, Landroidx/compose/runtime/SnapshotStateKt;->mutableStateOf$default(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;ILjava/lang/Object;)Landroidx/compose/runtime/MutableState; - - move-result-object v1 - - sput-object v1, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableState; + sput-object v1, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableIntState; sget-object v1, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean; - invoke-static {v1, v2, v3, v2}, Landroidx/compose/runtime/SnapshotStateKt;->mutableStateOf$default(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;ILjava/lang/Object;)Landroidx/compose/runtime/MutableState; + const/4 v2, 0x2 + + const/4 v3, 0x0 + + invoke-static {v1, v3, v2, v3}, Landroidx/compose/runtime/SnapshotStateKt;->mutableStateOf$default(Ljava/lang/Object;Landroidx/compose/runtime/SnapshotMutationPolicy;ILjava/lang/Object;)Landroidx/compose/runtime/MutableState; move-result-object v1 @@ -77,7 +73,7 @@ new-instance v1, Lradiant/Kawarp; - invoke-direct {v1, v2, v0}, Lradiant/Kawarp;->(Ljava/lang/String;I)V + invoke-direct {v1, v3, v0}, Lradiant/Kawarp;->(Ljava/lang/String;I)V sput-object v1, Lradiant/Kawarp;->DRAW:Lradiant/Kawarp; @@ -107,9 +103,9 @@ .method private static draw(Landroidx/compose/ui/graphics/drawscope/DrawScope;)V .registers 6 - sget-object v0, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableState; + sget-object v0, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableIntState; - invoke-interface {v0}, Landroidx/compose/runtime/MutableState;->getValue()Ljava/lang/Object; + invoke-interface {v0}, Landroidx/compose/runtime/MutableIntState;->getIntValue()I invoke-static {}, Landroid/os/SystemClock;->uptimeMillis()J @@ -610,7 +606,7 @@ return-void :cond_11 - sget-object p1, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableState; + sget-object p1, Lradiant/Kawarp;->frameState:Landroidx/compose/runtime/MutableIntState; sget p2, Lradiant/Kawarp;->frameTick:I @@ -618,11 +614,7 @@ sput p2, Lradiant/Kawarp;->frameTick:I - invoke-static {p2}, Ljava/lang/Integer;->valueOf(I)Ljava/lang/Integer; - - move-result-object p2 - - invoke-interface {p1, p2}, Landroidx/compose/runtime/MutableState;->setValue(Ljava/lang/Object;)V + invoke-interface {p1, p2}, Landroidx/compose/runtime/MutableIntState;->setIntValue(I)V invoke-static {}, Lradiant/Kawarp;->schedule()V diff --git a/patches/player-backdrop-kawarp.patch b/patches/player-backdrop-kawarp.patch index 3bdb432..86f8336 100644 --- a/patches/player-backdrop-kawarp.patch +++ b/patches/player-backdrop-kawarp.patch @@ -1,11 +1,9 @@ --- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali +++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali -@@ -4613,8 +4613,10 @@ +@@ -4613,8 +4613,8 @@ move-object/from16 v25, v10 -+ invoke-static {}, Lradiant/HomeBackdrop;->setModeKawarp()V # RL: mirror the mode to Cover Everywhere -+ .line 171 - invoke-static/range {v16 .. v26}, Lcom/tidal/android/feature/playerscreen/ui/composables/p3;->b(Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle;JILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V + invoke-static/range {v16 .. v26}, Lradiant/Kawarp;->b(Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle;JILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V @@ -27,53 +25,16 @@ .line 7 --- a/radiant/HomeBackdrop.smali +++ b/radiant/HomeBackdrop.smali -@@ -83,6 +83,16 @@ - return-void - .end method - -+.method public static setModeKawarp()V -+ .locals 1 -+ -+ const/4 v0, 0x3 -+ -+ sput v0, Lradiant/HomeBackdrop;->mode:I -+ -+ return-void -+.end method -+ - # from the mini-player state ctor (t.) whenever play state changes. - .method public static onPlayState(Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;)V - .locals 2 -@@ -363,8 +373,13 @@ - - const/4 v11, 0x2 - -+ if-eq v10, v11, :rl_live_play -+ -+ const/4 v11, 0x3 # RL: Kawarp follows live play state as well -+ - if-ne v10, v11, :rl_mode_done - -+ :rl_live_play - sget-object v10, Lradiant/HomeBackdrop;->isPlayingState:Landroidx/compose/runtime/MutableState; - - invoke-interface {v10}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object; -@@ -378,6 +393,18 @@ - move-result v10 - - :rl_mode_done -+ # RL: Kawarp renders its own AGSL backdrop rather than TIDAL's blurred cover -+ sget v11, Lradiant/HomeBackdrop;->mode:I -+ -+ const/4 v12, 0x3 -+ -+ if-ne v11, v12, :rl_native_backdrop -+ -+ invoke-static {v8, v9, v10, v13, v0}, Lradiant/Kawarp;->render(ILjava/lang/String;ZLandroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;)V -+ -+ goto :skip -+ -+ :rl_native_backdrop - const/4 v11, 0x0 # v11 = isSeeking = false +@@ -358,11 +358,7 @@ const/4 v12, 0x0 # v12 = progress callback = null (unused while not seeking) + +- move-object v14, v0 # v14 = composer +- +- const/4 v15, 0x0 # v15 = changed flags +- +- invoke-static/range {v8 .. v15}, Lcom/tidal/android/feature/playerscreen/ui/composables/p3;->a(ILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V ++ invoke-static {v8, v9, v10, v13, v0}, Lradiant/Kawarp;->render(ILjava/lang/String;ZLandroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;)V # RL: Radiant AGSL backdrop + + :skip + invoke-interface {v0}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V diff --git a/patches/player-backdrop-playback.patch b/patches/player-backdrop-playback.patch index 19259fc..7dacef8 100644 --- a/patches/player-backdrop-playback.patch +++ b/patches/player-backdrop-playback.patch @@ -1,12 +1,10 @@ --- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali +++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali -@@ -4433,6 +4433,10 @@ +@@ -4433,6 +4433,8 @@ move-object/from16 v25, v10 + sget-object v16, Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle;->DARK_BLUR:Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle; # RL: force native Blur player background -+ -+ invoke-static {}, Lradiant/HomeBackdrop;->setModePlayback()V # RL: mirror rotation to Cover Everywhere + .line 171 invoke-static/range {v16 .. v26}, Lcom/tidal/android/feature/playerscreen/ui/composables/p3;->b(Lcom/tidal/android/feature/playerscreen/ui/model/PlayerBackgroundStyle;JILjava/lang/String;ZZLam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V diff --git a/tools/kawarp-build/src/radiant/Kawarp.java b/tools/kawarp-build/src/radiant/Kawarp.java index 7eaad97..93580d7 100644 --- a/tools/kawarp-build/src/radiant/Kawarp.java +++ b/tools/kawarp-build/src/radiant/Kawarp.java @@ -9,6 +9,8 @@ import android.view.Choreographer; import androidx.compose.foundation.layout.SizeKt; import androidx.compose.foundation.layout.SpacerKt; import androidx.compose.runtime.Composer; +import androidx.compose.runtime.MutableIntState; +import androidx.compose.runtime.SnapshotIntStateKt; import androidx.compose.runtime.MutableState; import androidx.compose.runtime.SnapshotStateKt; import androidx.compose.ui.Modifier; @@ -56,9 +58,12 @@ public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallbac private static final ExecutorService LOADER = Executors.newSingleThreadExecutor(); - /** Bumped every frame so the draw lambda's snapshot read invalidates the draw phase. */ - private static final MutableState frameState = - SnapshotStateKt.mutableStateOf$default(Integer.valueOf(0), null, 2, null); + /** + * Bumped every frame so the draw lambda's snapshot read invalidates the draw phase. + * An int state rather than MutableState: this ticks at 60 Hz, and boxing here + * would allocate an Integer per frame for nothing. + */ + private static final MutableIntState frameState = SnapshotIntStateKt.mutableIntStateOf(0); /** Flips true on any shader failure; read during composition so we recompose onto p3.a. */ private static final MutableState fallbackState = SnapshotStateKt.mutableStateOf$default(Boolean.FALSE, null, 2, null); @@ -186,7 +191,7 @@ public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallbac frameScheduled = false; // Nothing has drawn for a while: the backdrop is off-screen, so stop burning frames. if (SystemClock.uptimeMillis() - lastDrawUptime > IDLE_STOP_MS) return; - frameState.setValue(Integer.valueOf(++frameTick)); + frameState.setIntValue(++frameTick); schedule(); } @@ -203,7 +208,7 @@ public final class Kawarp implements am0.l, Runnable, Choreographer.FrameCallbac private static void draw(DrawScope scope) { // Snapshot read: this is what ties the draw phase to the frame clock. - frameState.getValue(); + frameState.getIntValue(); lastDrawUptime = SystemClock.uptimeMillis(); schedule(); diff --git a/tools/kawarp-build/stubs/androidx/compose/runtime/MutableIntState.java b/tools/kawarp-build/stubs/androidx/compose/runtime/MutableIntState.java new file mode 100644 index 0000000..a679877 --- /dev/null +++ b/tools/kawarp-build/stubs/androidx/compose/runtime/MutableIntState.java @@ -0,0 +1,5 @@ +package androidx.compose.runtime; +public interface MutableIntState extends State { + int getIntValue(); + void setIntValue(int value); +} diff --git a/tools/kawarp-build/stubs/androidx/compose/runtime/SnapshotIntStateKt.java b/tools/kawarp-build/stubs/androidx/compose/runtime/SnapshotIntStateKt.java new file mode 100644 index 0000000..f145815 --- /dev/null +++ b/tools/kawarp-build/stubs/androidx/compose/runtime/SnapshotIntStateKt.java @@ -0,0 +1,4 @@ +package androidx.compose.runtime; +public final class SnapshotIntStateKt { + public static MutableIntState mutableIntStateOf(int value) { return null; } +}