Compare commits

...
25 Commits
Author SHA1 Message Date
meoware.exe 2150b87371 Merge pull request #71 from meowarex/dev
Word by Word Lyrics <3
2026-07-18 15:04:56 +10:00
meoware.exe 0d82c16168 Readme Update 2026-07-18 15:04:31 +10:00
meoware.exe 4c257f7ad9 Word by Word Lyrics <3 2026-07-18 15:02:07 +10:00
meoware.exe 7458df8eba Merge pull request #69 from meowarex/dev
Lyrics Button Hotfix <3
2026-07-17 00:01:18 +10:00
meoware.exe 6a5771cf9e Readme changes <3 2026-07-17 00:00:49 +10:00
meoware.exe a8a576c994 Lyrics Button Hotfix <3 2026-07-16 23:00:03 +10:00
meoware.exe 585666c403 Merge pull request #68 from meowarex/dev
Player Backdrop Image Settings <3
2026-07-14 01:54:31 +10:00
meoware.exe 90c008082f Player Backdrop Image Settings <3 2026-07-14 01:33:30 +10:00
meoware.exe c2a2586306 Merge pull request #67 from meowarex/dev
Upgrade Tidal Version + Native Blur <3
2026-07-14 00:35:34 +10:00
meoware.exe 2291f4064e Upgrade Tidal Version + Native Blur <3 2026-07-14 00:31:41 +10:00
meoware.exe f6a4de0cc7 Fix Missing Blocks on Patches <3 2026-07-06 16:56:56 +10:00
meoware.exe 4911e7703d Merge pull request #66 from meowarex/dev
Nav Bar Color Hotfix <3
2026-07-06 14:25:27 +10:00
meoware.exe f9a174eafa Nav Bar Color Hotfix <3 2026-07-06 14:24:51 +10:00
meoware.exe 49fe4c0d91 Merge pull request #65 from meowarex/dev
APK Bump + Offline Support + Playing From
2026-07-05 23:03:16 +10:00
meoware.exe 189e3d28a2 Offline Repatch + Force Incompatible (Dev Option) 2026-07-05 23:00:14 +10:00
meoware.exe aae2f54fab Update APK Version & Add Playing From 2026-07-05 20:58:22 +10:00
meoware.exe 191dcca239 Merge pull request #64 from meowarex/dev
Waze Integration + Integrations UI <3
2026-07-03 20:20:14 +10:00
meoware.exe 08aee155c9 Integrations UI + Package Name Warnings/Gate <3 2026-07-03 20:19:16 +10:00
meoware.exe 47c9c37236 Merge pull request #63 from Se7en-dev/feat/waze-support-patch
[PATCH] Waze Integration
2026-07-03 15:46:39 +10:00
Se7en-dev 50b99b6193 feat(waze patch): customizable themeColor 2026-07-02 22:56:09 +02:00
Se7en-dev 03271bf26d feat(waze patch): Tidal cyan accent color for waze 2026-07-02 20:44:24 +02:00
Se7en-dev 75f8187526 feat(waze patch): waze media menu browse source options 2026-07-02 20:26:12 +02:00
Se7en-dev 523f0a342b feat(patch): waze integration patch 2026-07-02 15:49:18 +02:00
meoware.exe fb4c776c61 Merge pull request #60 from meowarex/dev
Fold Cover Everywhere -> Player Backdrop
2026-06-26 23:02:05 +10:00
meoware.exe cbf04d9fa7 Fold Cover Everywhere -> Player Backdrop 2026-06-26 23:01:26 +10:00
93 changed files with 5157 additions and 1329 deletions
+10
View File
@@ -228,3 +228,13 @@ fun ProviderFactory.execIgnoreCode(vararg command: String): String = try {
} catch (_: Exception) {
""
}
// Sync Local Cached Assets with Repo Releases to keep them up to date
val syncBundledManifest by tasks.registering(Copy::class) {
val src = rootProject.rootDir.resolve("../patches/manifest.json")
onlyIf { src.exists() }
from(src)
into(layout.projectDirectory.dir("src/main/assets"))
rename { "patches-manifest.json" }
}
tasks.named("preBuild") { dependsOn(syncBundledManifest) }
@@ -0,0 +1,434 @@
{
"version": 1,
"patches": [
{
"id": "EnableLegacyUi",
"order": 10,
"fileNames": [
"enable-legacy-ui.patch"
],
"title": "Enable Legacy UI",
"description": "[This patch will stop working soon] - Replaces the New Compose based UI with the Legacy UI (disables player-market-ui feature flag)",
"default": false,
"requires": [
"DebugMenuUnlock"
],
"disables": [
"LyricsDisableCover",
"LyricsReplaceLyricsButton",
"LyricsReplaceShareButton",
"LyricsRlApi",
"LyricsKeepControlsVisible",
"PlayerBackdrop",
"QualityBadgeColors",
"PlayerMovePlayingFrom",
"PlayerOneHanded",
"LyricsProgressPill",
"MiniPlayerRedesign"
]
},
{
"id": "LyricsRlApi",
"order": 20,
"fileNames": [
"lyrics-rl-api.patch",
"lyrics-rl-api-observer.patch",
"lyrics-rl-api-isrc.patch"
],
"title": "Radiant Lyrics API - WIP",
"description": "Use Radiant Lyrics API to fetch Lyrics (Higher quality & More providers). Pick how the highlight moves: whole Line or word-by-word (Word).",
"default": false,
"defaultVariantIndex": 0,
"variants": [
{
"title": "Line",
"fileNames": []
},
{
"title": "Word",
"fileNames": [
"lyrics-rl-api-word.patch"
]
}
]
},
{
"id": "PlayerBackdrop",
"order": 30,
"fileNames": [],
"title": "Player Backdrop",
"description": "Lets you fully adjust how the player backdrop blur looks and behaves",
"default": true,
"defaultVariantIndex": 2,
"variants": [
{
"title": "Static",
"fileNames": [
"player-backdrop-static.patch"
],
"extensionFiles": [
"radiant/BackdropFx.smali"
]
},
{
"title": "Animated",
"fileNames": [
"player-backdrop-animated.patch"
],
"extensionFiles": [
"radiant/BackdropFx.smali"
]
},
{
"title": "Playback",
"fileNames": [
"player-backdrop-playback.patch"
],
"extensionFiles": [
"radiant/BackdropFx.smali"
]
}
],
"advancedOptions": [
{
"type": "slider",
"key": "blur_strength",
"title": "Blur Strength",
"description": "The value of Blur applied to the backdrop cover",
"default": 50,
"min": 0,
"max": 100,
"steps": 19,
"displayAsPercent": true,
"token": "RL_BLUR",
"encode": {
"kind": "int",
"scale": 1.0
}
},
{
"type": "slider",
"key": "contrast",
"title": "Contrast",
"description": "The value of Contrast applied to the backdrop cover",
"default": 50,
"min": 0,
"max": 100,
"steps": 19,
"displayAsPercent": true,
"token": "RL_CONTRAST",
"encode": {
"kind": "floatBits",
"scale": 0.02
}
},
{
"type": "slider",
"key": "saturation",
"title": "Saturation",
"description": "The value of Saturation applied to the backdrop cover",
"default": 50,
"min": 0,
"max": 100,
"steps": 19,
"displayAsPercent": true,
"token": "RL_SATURATION",
"encode": {
"kind": "floatBits",
"scale": 0.02
}
},
{
"type": "slider",
"key": "brightness",
"title": "Brightness",
"description": "The value of Brightness applied to the backdrop cover",
"default": 50,
"min": 0,
"max": 100,
"steps": 19,
"displayAsPercent": true,
"token": "RL_BRIGHTNESS",
"encode": {
"kind": "floatBits",
"scale": 0.02
}
},
{
"type": "toggle",
"key": "cover_everywhere",
"title": "Cover Everywhere - WIP",
"description": "Applies TIDAL's native blurred album-art backdrop to every Compose based page (Home & Collection)",
"default": false,
"inline": true,
"fileNames": [
"home-backdrop.patch",
"collection-backdrop.patch",
"cover-capture.patch"
]
}
]
},
{
"id": "QualityBadgeColors",
"order": 36,
"fileNames": [
"player-quality-badge-colors.patch"
],
"title": "Quality Badge Colors",
"description": "Brings color back to the player quality badge.",
"default": true
},
{
"id": "PlayerMovePlayingFrom",
"order": 37,
"fileNames": [
"player-move-playing-from.patch"
],
"extensionFiles": [
"radiant/PlayingFrom.smali"
],
"title": "Playing From",
"description": "Shows the source name (playlist/album/mix) above the track title",
"default": true
},
{
"id": "PlayerOneHanded",
"order": 38,
"fileNames": [
"player-one-handed.patch"
],
"title": "One-Handed Mode",
"description": "Mirrors the bottom player buttons left-to-right for easier one-handed reach.",
"default": false
},
{
"id": "LyricsProgressPill",
"order": 40,
"fileNames": [
"lyrics-progress-pill.patch",
"lyrics-fade-region.patch"
],
"title": "Lyrics Progress Pill",
"description": "Restores the old Track Progress Pill in the top of the Lyrics screen!",
"default": true,
"requires": [
"LyricsDisableCover",
"LyricsReplaceLyricsButton",
"LyricsReplaceShareButton"
]
},
{
"id": "LyricsDisableCover",
"order": 41,
"fileNames": [
"lyrics-disable-cover.patch"
],
"title": "Disable Lyrics Cover",
"description": "Removes the mini track cover from the lyrics screen.",
"default": true
},
{
"id": "LyricsReplaceLyricsButton",
"order": 42,
"fileNames": [
"lyrics-replace-lyrics-button.patch",
"lyrics-sparkle-conditional-visibility.patch"
],
"title": "Replace Lyrics Button",
"description": "Replaces the Lyrics button with the RL Sparkle!",
"default": true
},
{
"id": "LyricsReplaceShareButton",
"order": 43,
"fileNames": [
"lyrics-replace-share-button.patch"
],
"title": "Replace Share Button",
"description": "Replaces the share button with the Tidal Connect button from the top of the screen. (it's in the menu already)",
"default": true
},
{
"id": "MiniPlayerRedesign",
"order": 50,
"fileNames": [],
"title": "Redesigned Mini-Player",
"description": "Integrates the Seekbar into the control panel at the bottom of the screen.",
"default": false,
"defaultVariantIndex": 2,
"variants": [
{
"title": "Floating",
"fileNames": []
},
{
"title": "Grey",
"fileNames": [
"mini-player-grey.patch"
]
},
{
"title": "Black",
"fileNames": [
"mini-player-black.patch"
]
}
],
"advancedOptions": [
{
"type": "toggle",
"key": "dynamic_bg",
"title": "Mini-Player Dynamic Background",
"description": "Colorizes the Mini-Player depending on the currently playing track.",
"default": false,
"inline": true,
"fileNames": [
"mini-player-dynamic-bg.patch"
],
"extensionFiles": [
"radiant/MiniPlayerBackground.smali"
],
"hidesVariants": [
2
],
"relabelVariants": {
"1": "Legacy"
}
},
{
"type": "toggle",
"key": "border",
"title": "Progress Border",
"description": "Draws an animated progress ring around the floating mini-player. Requires the Floating style.",
"default": false,
"requiresVariant": 0,
"fileNames": [
"mini-player-floating-border.patch"
],
"extensionFiles": [
"radiant/MiniSeekerFloating.smali"
]
},
{
"type": "toggle",
"key": "gestures",
"title": "Mini-Player Gestures",
"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",
"title": "Next/Previous Gestures",
"description": "Swipe left or right on the mini-player to skip tracks.",
"default": false,
"requiresOption": "gestures",
"fileNames": [
"mini-player-gestures-left-right.patch"
],
"extensionFiles": [
"radiant/MiniPlayerTrackGestures.smali",
"radiant/MiniPlayerTrackGestures$Gesture.smali",
"radiant/MiniPlayerTrackGestures$OffsetLayer.smali",
"radiant/MiniPlayerTrackGestures$ResetAnimator.smali",
"radiant/MiniPlayerTrackGestures$TextDraw.smali",
"com/tidal/android/feature/appscaffold/ui/r$c.smali"
]
}
]
},
{
"id": "LyricsKeepControlsVisible",
"order": 60,
"fileNames": [
"lyrics-keep-controls-visible.patch"
],
"extensionFiles": [
"radiant/LyricsReinitGuard.smali"
],
"title": "Keep Controls Visible",
"description": "Inverts the auto-hide behavior on the lyrics screen, playback controls stay visible by default and only hide when you tap them off. Also stops the open lyrics view from randomly closing when the player re-fetches the same track.",
"default": true
},
{
"id": "WazeIntegration",
"order": 90,
"category": "integration",
"pathLocked": true,
"fileNames": [
"integration-waze-playback.patch"
],
"extensionFiles": [
"radiant/WazeInitReceiver.smali",
"radiant/WazeServiceConnection.smali"
],
"title": "Waze Integration",
"description": "Control TIDAL playback from the Waze app",
"default": true,
"advancedOptions": [
{
"type": "choice",
"key": "browse_root",
"title": "Media Menu",
"entries": [
"Auto Menu",
"Home",
"Recents"
],
"values": [
"ROOT_AUTO",
"HOME_V2::home_page_v2_id",
"RECENTLY_PLAYED::home/pages/CONTINUE_LISTEN_TO/view-all"
],
"defaultIndex": 0,
"token": "RL_WAZE_ROOT_ID"
},
{
"type": "color",
"key": "accent_color",
"title": "Accent Color",
"default": -16747037,
"token": "RL_WAZE_THEME_COLOR"
}
]
},
{
"id": "DebugMenuUnlock",
"order": 100,
"fileNames": [
"debug-menu-unlock.patch"
],
"title": "Unlock Debug Menu",
"description": "Reveals TIDAL's hidden Debug Menu in Settings. (Unlocks Feature Flags & the legacy Debug Options)",
"default": false
}
]
}
@@ -22,7 +22,8 @@ class PathManager(
val patchingDownloadDir = patchingDir.resolve("downloads")
val cacheDownloadDir = context.cacheDir.resolve("downloads")
// Persistent Stash of assets for Offline Repatching
val cacheDownloadDir = patchingDir.resolve("downloads-cache")
val customComponentsDir = patchingDir.resolve("custom")
@@ -34,11 +35,15 @@ class PathManager(
val patchedApk = patchingWorkingDir.resolve("patched.apk")
// Persistent snapshot of the last successful release fetch (build info + patches asset URL)
val cachedReleaseInfo = patchingDir.resolve("release-info.json")
fun clearCache() {
val targets = arrayOf(
patchingDownloadDir,
patchingWorkingDir,
cacheDownloadDir,
cachedReleaseInfo,
context.cacheDir,
)
for (dir in targets) {
@@ -54,6 +59,16 @@ class PathManager(
.resolve("patches")
.resolve("$version.zip")
fun hasCachedTidalApk(version: Int, split: String = "base"): Boolean {
val rel = "tidal/$version/$split.apk"
return patchingDownloadDir.resolve(rel).exists() || cacheDownloadDir.resolve(rel).exists()
}
fun hasCachedSmaliPatches(version: SemVer): Boolean {
val rel = "patches/$version.zip"
return patchingDownloadDir.resolve(rel).exists() || cacheDownloadDir.resolve(rel).exists()
}
fun customTidalApks() = customTidalApksDir.listFiles()?.asList() ?: emptyList()
fun customSmaliPatches() = customPatchesDir.listFiles()?.asList() ?: emptyList()
@@ -12,6 +12,8 @@ class PreferencesManager(preferences: SharedPreferences) : BasePreferenceManager
var devMode by booleanPreference("dev_mode", false)
var installer by enumPreference<InstallerSetting>("installer", InstallerSetting.PackageInstaller)
var keepPatchedApks by booleanPreference("keep_patched_apks", false)
// Dev: force-apply path-gated ("incompatible") patches even under a non-stock package name
var bypassIncompatible by booleanPreference("bypass_incompatible", false)
var showPlayProtectWarning by booleanPreference("show_play_protect_warning", true)
var autoUpdateCheck by booleanPreference("auto_update_check", true)
@@ -0,0 +1,32 @@
package com.meowarex.rlmobile.manager
import android.util.Log
import com.meowarex.rlmobile.BuildConfig
import com.meowarex.rlmobile.network.models.RLBuildInfo
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
// Snapshot of the last successful release fetch (build info + patches asset URL)
@Serializable
data class CachedReleaseInfo(
val data: RLBuildInfo,
val patchesAssetUrl: String,
)
object ReleaseInfoCache {
fun load(paths: PathManager, json: Json): CachedReleaseInfo? = try {
paths.cachedReleaseInfo
.takeIf { it.exists() }
?.let { json.decodeFromString<CachedReleaseInfo>(it.readText()) }
} catch (t: Throwable) {
Log.w(BuildConfig.TAG, "Failed to read cached release info", t)
null
}
fun save(paths: PathManager, json: Json, info: CachedReleaseInfo) = try {
paths.cachedReleaseInfo.parentFile?.mkdirs()
paths.cachedReleaseInfo.writeText(json.encodeToString(info))
} catch (t: Throwable) {
Log.w(BuildConfig.TAG, "Failed to cache release info", t)
}
}
@@ -26,11 +26,16 @@ class PatchManifestStep(private val options: PatchOptions) : Step() {
?: throw IllegalArgumentException("No manifest found in APK")
container.log("Patching manifest")
val wazeDefault = container.getStep<SmaliPatchStep>().specs
.firstOrNull { it.id == "WazeIntegration" }?.defaultEnabled ?: false
val enableWazeIntegration = options.patchStates["WazeIntegration"] ?: wazeDefault
val patchedManifest = ManifestPatcher.patchManifest(
manifestBytes = manifest,
packageName = options.packageName,
appName = options.appName,
debuggable = options.debuggable,
enableWazeIntegration = enableWazeIntegration,
)
container.log("Repacking apk with patched manifest")
@@ -1,5 +1,6 @@
package com.meowarex.rlmobile.patcher.steps.patch
import android.content.Context
import com.meowarex.rlmobile.R
import com.meowarex.rlmobile.manager.PathManager
import com.meowarex.rlmobile.patcher.StepRunner
@@ -10,6 +11,7 @@ import com.meowarex.rlmobile.patcher.steps.download.CopyDependenciesStep
import com.meowarex.rlmobile.patcher.steps.download.DownloadPatchesStep
import com.meowarex.rlmobile.ui.screens.patchopts.PatchManifest
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
import com.meowarex.rlmobile.ui.screens.patchopts.PatchSpec
import com.meowarex.rlmobile.ui.screens.patchopts.builtinPatchSpecs
import com.android.tools.smali.baksmali.Baksmali
import com.android.tools.smali.baksmali.BaksmaliOptions
@@ -31,6 +33,10 @@ class SmaliPatchStep(
) : Step(), IDexProvider, KoinComponent {
private val paths: PathManager by inject()
private val json: Json by inject()
private val context: Context by inject()
var specs: List<PatchSpec> = emptyList()
private set
override val group = StepGroup.Patch
override val localizedName = R.string.patch_step_patch_smali
@@ -55,7 +61,7 @@ class SmaliPatchStep(
container.log("Failed to parse manifest.json (${t.message}); using built-in patch specs")
null
}
val specs = manifestSpecs ?: builtinPatchSpecs { "" }
specs = manifestSpecs ?: builtinPatchSpecs(context, json)
container.log(
"Loaded ${specs.size} patch specs from " +
if (manifestSpecs != null) "manifest.json" else "built-in list"
@@ -95,7 +101,19 @@ class SmaliPatchStep(
val entry = zip.openEntry(patchFile)
?: throw FileNotFoundException("Missing zip entry: $patchFile")
out.canonicalFile.parentFile?.mkdirs()
out.writeBytes(entry.read())
var smaliText = entry.read()
.decodeToString()
.replace("\r\n", "\n")
for ((token, value) in substitutions) {
if (smaliText.contains(token)) {
smaliText = smaliText.replace(token, value)
container.log("Applied substitution $token -> $value in $patchFile")
}
}
UNRESOLVED_TOKEN.find(smaliText)?.let { match ->
throw Error("Unresolved option placeholder ${match.value} in $patchFile")
}
out.writeText(smaliText)
container.log("Extracted extension smali: $relative")
continue
}
@@ -1,19 +1,30 @@
package com.meowarex.rlmobile.patcher.steps.prepare
import android.app.Application
import android.util.Log
import androidx.compose.runtime.Stable
import com.meowarex.rlmobile.R
import com.meowarex.rlmobile.manager.CachedReleaseInfo
import com.meowarex.rlmobile.manager.PathManager
import com.meowarex.rlmobile.manager.ReleaseInfoCache
import com.meowarex.rlmobile.network.models.RLBuildInfo
import com.meowarex.rlmobile.network.services.RadiantLyricsGithubService
import com.meowarex.rlmobile.network.utils.getOrThrow
import com.meowarex.rlmobile.patcher.StepRunner
import com.meowarex.rlmobile.patcher.steps.StepGroup
import com.meowarex.rlmobile.patcher.steps.base.Step
import com.meowarex.rlmobile.util.isOnline
import kotlinx.serialization.json.Json
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import kotlin.coroutines.cancellation.CancellationException
@Stable
class FetchInfoStep : Step(), KoinComponent {
private val github: RadiantLyricsGithubService by inject()
private val context: Application by inject()
private val paths: PathManager by inject()
private val json: Json by inject()
override val group = StepGroup.Prepare
override val localizedName = R.string.patch_step_fetch_info
@@ -25,6 +36,33 @@ class FetchInfoStep : Step(), KoinComponent {
private set
override suspend fun execute(container: StepRunner) {
// Fetch the latest release and refresh the cache (when online)
if (context.isOnline()) {
try {
fetchFromRemote(container)
return
} catch (e: CancellationException) {
throw e
} catch (t: Throwable) {
container.log("Failed to fetch latest release: ${Log.getStackTraceString(t)}")
container.log("Falling back to cached release info for a local re-patch")
}
} else {
container.log("No network connection — using cached release info for a local re-patch")
}
val cached = ReleaseInfoCache.load(paths, json)
?: throw IllegalStateException(
"Could not fetch the latest release and no cached release info is available. " +
"Connect to the internet and try again."
)
data = cached.data
patchesAssetUrl = cached.patchesAssetUrl
container.log("Using cached build info: $data")
container.log("Cached patches asset URL: $patchesAssetUrl")
}
private suspend fun fetchFromRemote(container: StepRunner) {
container.log("Fetching latest release from ${RadiantLyricsGithubService.REPO_OWNER}/${RadiantLyricsGithubService.REPO_NAME}")
val release = github.getLatestRelease(force = true).getOrThrow()
@@ -33,14 +71,19 @@ class FetchInfoStep : Step(), KoinComponent {
?.browserDownloadUrl
?: throw IllegalStateException("No ${RadiantLyricsGithubService.DATA_JSON_ASSET_NAME} asset found in latest release ${release.tagName}")
patchesAssetUrl = release.assets
val patchesUrl = release.assets
.find { it.name == RadiantLyricsGithubService.PATCHES_ASSET_NAME }
?.browserDownloadUrl
?: throw IllegalStateException("No ${RadiantLyricsGithubService.PATCHES_ASSET_NAME} asset found in latest release ${release.tagName}")
container.log("Fetching build info from $dataJsonUrl")
data = github.getBuildInfo(dataJsonUrl, force = true).getOrThrow()
val buildInfo = github.getBuildInfo(dataJsonUrl, force = true).getOrThrow()
data = buildInfo
patchesAssetUrl = patchesUrl
container.log("Fetched build info: $data")
container.log("Patches asset URL: $patchesAssetUrl")
ReleaseInfoCache.save(paths, json, CachedReleaseInfo(buildInfo, patchesUrl))
}
}
@@ -18,12 +18,16 @@ object ManifestPatcher {
private const val IS_SPLIT_REQUIRED = "isSplitRequired"
private const val REQUIRED_SPLIT_TYPES = "requiredSplitTypes"
private const val SPLIT_TYPES = "splitTypes"
private const val WAZE_PACKAGE = "com.waze"
private const val WAZE_INIT_RECEIVER = "radiant.WazeInitReceiver"
private const val WAZE_ACTION_INIT = "com.waze.sdk.audio.ACTION_INIT"
fun patchManifest(
manifestBytes: ByteArray,
packageName: String,
appName: String,
debuggable: Boolean,
enableWazeIntegration: Boolean,
): ByteArray {
// Extract original package name to rewrite every reference to it
// (permissions, provider authorities) to the new packageName.
@@ -84,6 +88,49 @@ object ManifestPatcher {
}
return when (name) {
"queries" -> object : NodeVisitor(nv) {
private var hasWazePackage = false
override fun child(ns: String?, name: String): NodeVisitor {
val visitor = super.child(ns, name)
return if (enableWazeIntegration && name == "package") {
object : NodeVisitor(visitor) {
override fun attr(
ns: String?,
name: String?,
resourceId: Int,
type: Int,
value: Any?,
) {
if (name == "name" && value == WAZE_PACKAGE) {
hasWazePackage = true
}
super.attr(ns, name, resourceId, type, value)
}
}
} else {
visitor
}
}
override fun end() {
if (enableWazeIntegration && !hasWazePackage) {
super.child(null, "package").apply {
attr(
ANDROID_NAMESPACE,
"name",
android.R.attr.name,
TYPE_STRING,
WAZE_PACKAGE,
)
end()
}
}
super.end()
}
}
"uses-permission" -> object : NodeVisitor(nv) {
override fun attr(ns: String?, name: String?, resourceId: Int, type: Int, value: Any?) {
if (name != "maxSdkVersion") {
@@ -132,6 +179,7 @@ object ManifestPatcher {
private var addUseEmbeddedDex = true
private var addExtractNativeLibs = true
private var addMetadata = true
private var hasWazeInitReceiver = false
override fun attr(ns: String?, name: String, resourceId: Int, type: Int, value: Any?) {
if (name == REQUEST_LEGACY_EXTERNAL_STORAGE) addLegacyStorage = false
@@ -161,6 +209,22 @@ object ManifestPatcher {
return when (name) {
"activity" -> ReplaceAttrsVisitor(visitor, mapOf("label" to appName))
"receiver" -> object : NodeVisitor(visitor) {
override fun attr(
ns: String?,
name: String,
resourceId: Int,
type: Int,
value: Any?
) {
if (name == "name" && value == WAZE_INIT_RECEIVER) {
hasWazeInitReceiver = true
}
super.attr(ns, name, resourceId, type, value)
}
}
"provider" -> object : NodeVisitor(visitor) {
override fun attr(
ns: String?,
@@ -219,6 +283,39 @@ object ManifestPatcher {
0
)
if (enableWazeIntegration && !hasWazeInitReceiver) {
super.child(null, "receiver").apply {
attr(
ANDROID_NAMESPACE,
"name",
android.R.attr.name,
TYPE_STRING,
WAZE_INIT_RECEIVER,
)
attr(
ANDROID_NAMESPACE,
"exported",
android.R.attr.exported,
TYPE_INT_BOOLEAN,
1,
)
child(null, "intent-filter").apply {
child(null, "action").apply {
attr(
ANDROID_NAMESPACE,
"name",
android.R.attr.name,
TYPE_STRING,
WAZE_ACTION_INIT,
)
end()
}
end()
}
end()
}
}
super.end()
}
}
@@ -9,6 +9,7 @@ import com.meowarex.rlmobile.network.utils.SemVer
import com.meowarex.rlmobile.ui.screens.componentopts.PatchComponent
import com.meowarex.rlmobile.ui.screens.patchopts.*
import com.meowarex.rlmobile.ui.theme.ManagerTheme
import kotlinx.serialization.json.Json
import kotlin.time.Clock
// This preview has scrollable/interactable content that cannot be tested from an IDE preview
@@ -21,7 +22,7 @@ private fun PatchOptionsScreenPreview(
parameters: PatchOptionsParameters,
) {
val context = LocalContext.current
val specs = remember { builtinPatchSpecs { context.getString(it) } }
val specs = remember { builtinPatchSpecs(context, Json { ignoreUnknownKeys = true }) }
ManagerTheme {
PatchOptionsScreenContent(
@@ -29,18 +30,22 @@ private fun PatchOptionsScreenPreview(
isDevMode = parameters.isDevMode,
debuggable = parameters.debuggable,
setDebuggable = {},
bypassIncompatible = false,
setBypassIncompatible = {},
appName = parameters.appName,
appNameIsError = parameters.appNameIsError,
setAppName = {},
packageName = parameters.packageName,
packageNameState = parameters.packageNameState,
setPackageName = {},
packageNameLocked = parameters.packageName == PatchOptions.Default.packageName,
onUnlockPackageName = {},
onLockPackageName = {},
customTidalApk = parameters.customTidalApk,
onSelectCustomTidalApk = {},
customPatches = parameters.customPatches,
onSelectCustomPatches = {},
specs = specs,
enabledPatchCount = specs.size,
isPatchEnabled = { true },
onTogglePatch = { _, _ -> },
patchLockState = { PatchLock.Free },
@@ -19,7 +19,9 @@ import cafe.adriel.voyager.core.model.screenModelScope
import com.github.diamondminer88.zip.ZipReader
import com.meowarex.rlmobile.BuildConfig
import com.meowarex.rlmobile.R
import com.meowarex.rlmobile.manager.PathManager
import com.meowarex.rlmobile.manager.PreferencesManager
import com.meowarex.rlmobile.manager.ReleaseInfoCache
import com.meowarex.rlmobile.network.models.GithubCommit
import com.meowarex.rlmobile.network.models.RLBuildInfo
import com.meowarex.rlmobile.network.services.RadiantLyricsGithubService
@@ -42,6 +44,7 @@ class HomeModel(
private val github: RadiantLyricsGithubService,
private val json: Json,
private val prefs: PreferencesManager,
private val paths: PathManager,
) : ScreenModel {
var state by mutableStateOf<HomeState>(HomeState.Loading)
@@ -170,16 +173,23 @@ class HomeModel(
refreshingLock.withLock {
val pkg = fetchInstalled()
// Skip the remote fetch entirely when offline
val online = application.isOnline()
if (online) {
val remote = async(Dispatchers.IO) { if (remoteDataJson == null) fetchRemoteData() }
remote.await()
}
val install = pkg?.toInstallData()
val latest = remoteDataJson?.tidalVersionCode
val offlineRepatchReady = hasOfflineRepatchAssets()
mainThread {
state = HomeState.Loaded(
install = install,
latestTidalVersionCode = latest,
offline = !online,
offlineRepatchReady = offlineRepatchReady,
)
maybeCheckManagerUpdate(pkg)
}
@@ -257,6 +267,13 @@ class HomeModel(
)
}
// check if an offline "Local Repatch" is possible
private fun hasOfflineRepatchAssets(): Boolean {
val info = ReleaseInfoCache.load(paths, json) ?: return false
return paths.hasCachedTidalApk(info.data.tidalVersionCode) &&
paths.hasCachedSmaliPatches(info.data.patchesVersion)
}
private suspend fun fetchRemoteData() {
val release = try {
github.getLatestRelease().fold(
@@ -210,14 +210,19 @@ private fun ColumnScope.HomeContent(
}
val blockedByManagerUpdate = managerUpdateAvailable && (patchesBehind || tidalBehind)
val canLocalRepatch = install != null && state.offlineRepatchReady
val onlineEnabled = state.latestTidalVersionCode != null || install != null
val buttonEnabled = !blockedByManagerUpdate && (if (state.offline) canLocalRepatch else onlineEnabled)
Button(
onClick = if (install == null) onInstall else onRepatch,
enabled = state.latestTidalVersionCode != null && !blockedByManagerUpdate,
enabled = buttonEnabled,
modifier = Modifier.fillMaxWidth(),
) {
val label = when {
blockedByManagerUpdate -> "Manager Update Required"
state.latestTidalVersionCode == null -> "Loading…"
state.offline && install != null -> "Local Repatch"
state.offline -> "No Network"
install == null && state.latestTidalVersionCode == null -> "Loading…"
install == null -> "Install"
patchesBehind && tidalBehind -> "Update Patches & TIDAL"
patchesBehind -> "Update Patches"
@@ -234,6 +239,18 @@ private fun ColumnScope.HomeContent(
)
}
if (state.offline && install != null) {
Text(
text = "No Network Connection",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center,
modifier = Modifier
.fillMaxWidth()
.padding(top = 6.dp),
)
}
AnimatedVisibility(visible = install != null) {
Row(
horizontalArrangement = Arrangement.spacedBy(2.dp),
@@ -8,5 +8,7 @@ sealed interface HomeState {
data class Loaded(
val install: InstallData?,
val latestTidalVersionCode: Int?,
val offline: Boolean = false,
val offlineRepatchReady: Boolean = false,
) : HomeState
}
@@ -1,259 +0,0 @@
package com.meowarex.rlmobile.ui.screens.patchopts
import androidx.annotation.StringRes
import com.meowarex.rlmobile.R
import com.meowarex.rlmobile.ui.screens.patchopts.PatchDefault.Disabled
import com.meowarex.rlmobile.ui.screens.patchopts.PatchDefault.Enabled
data class PatchVariant(
@StringRes val titleRes: Int,
val fileNames: List<String>,
val extensionFiles: List<String> = emptyList(),
)
enum class KnownPatch(
val order: Int, // Patch order in the UI List (lower = higher up) [Main Patches: multiples of 10 | Sub Patches: multiples of 1]
val fileNames: List<String>,
val extensionFiles: List<String> = emptyList(),
@StringRes val titleRes: Int,
@StringRes val descRes: Int,
val default: PatchDefault, // Default state of the patch in the UI List (enabled/disabled)
val requires: List<KnownPatch> = emptyList(),
val disables: List<KnownPatch> = emptyList(),
val variants: List<PatchVariant> = emptyList(),
val defaultVariantIndex: Int = 0,
val advancedOptions: List<PatchOption> = emptyList(),
) {
LyricsDisableCover(
order = 41,
fileNames = listOf("lyrics-disable-cover.patch"),
titleRes = R.string.patch_lyrics_disable_cover_title,
descRes = R.string.patch_lyrics_disable_cover_desc,
default = Enabled,
),
LyricsReplaceLyricsButton(
order = 42,
fileNames = listOf(
"lyrics-replace-lyrics-button.patch",
"lyrics-sparkle-conditional-visibility.patch",
),
titleRes = R.string.patch_lyrics_replace_button_title,
descRes = R.string.patch_lyrics_replace_button_desc,
default = Enabled,
),
LyricsReplaceShareButton(
order = 43,
fileNames = listOf("lyrics-replace-share-button.patch"),
titleRes = R.string.patch_lyrics_replace_share_button_title,
descRes = R.string.patch_lyrics_replace_share_button_desc,
default = Enabled,
),
LyricsRlApi(
order = 20,
fileNames = listOf(
"lyrics-rl-api.patch",
"lyrics-rl-api-observer.patch",
),
titleRes = R.string.patch_lyrics_rl_api_title,
descRes = R.string.patch_lyrics_rl_api_desc,
default = Disabled,
),
LyricsKeepControlsVisible(
order = 60,
fileNames = listOf("lyrics-keep-controls-visible.patch"),
titleRes = R.string.patch_lyrics_keep_controls_title,
descRes = R.string.patch_lyrics_keep_controls_desc,
default = Enabled,
),
PlayerBackdrop(
order = 30,
fileNames = listOf("player-backdrop.patch"),
titleRes = R.string.patch_player_backdrop_title,
descRes = R.string.patch_player_backdrop_desc,
default = Enabled,
advancedOptions = listOf(
PatchOption.Slider(
key = "blur_strength",
titleRes = R.string.patch_opt_backdrop_blur_title,
descRes = R.string.patch_opt_backdrop_blur_desc,
default = 50f,
valueRange = 0f..100f,
steps = 19, // dots every 5% (0,5,…,100); snap only when locked
displayAsPercent = true,
token = "RL_BLUR_BITS",
encode = SmaliEncode(EncodeKind.FloatBits, scale = 1.8f),
),
PatchOption.Slider(
key = "dimming",
titleRes = R.string.patch_opt_backdrop_dimming_title,
descRes = R.string.patch_opt_backdrop_dimming_desc,
default = 50f, // 50% == the original -0x80000000
valueRange = 0f..100f,
steps = 19, // dots every 5%
displayAsPercent = true,
token = "RL_SCRIM_ARGB",
encode = SmaliEncode(EncodeKind.ArgbAlpha),
),
),
),
QualityBadgeColors(
order = 36,
fileNames = listOf("player-quality-badge-colors.patch"),
titleRes = R.string.patch_quality_badge_colors_title,
descRes = R.string.patch_quality_badge_colors_desc,
default = Enabled,
),
PlayerOneHanded(
order = 37,
fileNames = listOf("player-one-handed.patch"),
titleRes = R.string.patch_player_one_handed_title,
descRes = R.string.patch_player_one_handed_desc,
default = Disabled,
),
CoverEverywhere(
order = 35,
fileNames = listOf(
"home-backdrop.patch",
"collection-backdrop.patch",
"cover-capture.patch",
),
titleRes = R.string.patch_cover_everywhere_title,
descRes = R.string.patch_cover_everywhere_desc,
default = Disabled,
),
DebugMenuUnlock(
order = 100,
fileNames = listOf("debug-menu-unlock.patch"),
titleRes = R.string.patch_debug_menu_unlock_title,
descRes = R.string.patch_debug_menu_unlock_desc,
default = Disabled,
),
LyricsProgressPill(
order = 40,
fileNames = listOf(
"lyrics-progress-pill.patch",
"lyrics-fade-region.patch",
),
titleRes = R.string.patch_lyrics_progress_pill_title,
descRes = R.string.patch_lyrics_progress_pill_desc,
default = Enabled,
requires = listOf(LyricsDisableCover, LyricsReplaceLyricsButton, LyricsReplaceShareButton),
),
MiniPlayerRedesign(
order = 50,
fileNames = emptyList(),
titleRes = R.string.patch_mini_player_redesign_title,
descRes = R.string.patch_mini_player_redesign_desc,
default = Disabled,
defaultVariantIndex = 2,
variants = listOf(
PatchVariant( // 0: Floating — stock rounded pill
titleRes = R.string.patch_mini_player_variant_floating_title,
fileNames = emptyList(),
),
PatchVariant( // 1: Grey — square
titleRes = R.string.patch_mini_player_variant_square_grey_title,
fileNames = listOf("mini-player-grey.patch"),
),
PatchVariant( // 2: Black — square black background
titleRes = R.string.patch_mini_player_variant_square_black_title,
fileNames = listOf("mini-player-black.patch"),
),
),
advancedOptions = listOf(
PatchOption.Toggle(
key = "dynamic_bg",
titleRes = R.string.patch_mini_player_dynamic_bg_title,
descRes = R.string.patch_mini_player_dynamic_bg_desc,
default = false,
inline = true,
fileNames = listOf("mini-player-dynamic-bg.patch"),
extensionFiles = listOf("radiant/MiniPlayerBackground.smali"),
hidesVariants = listOf(2),
relabelVariants = mapOf(1 to R.string.patch_mini_player_variant_legacy_title),
),
// Animated progress border around the floating pill
PatchOption.Toggle(
key = "border",
titleRes = R.string.patch_mini_player_border_title,
descRes = R.string.patch_mini_player_border_desc,
default = false,
requiresVariant = 0,
fileNames = listOf("mini-player-floating-border.patch"),
extensionFiles = listOf("radiant/MiniSeekerFloating.smali"),
),
// Swipe up to open the full player
PatchOption.Toggle(
key = "gestures",
titleRes = R.string.patch_mini_player_gestures_title,
descRes = R.string.patch_mini_player_gestures_desc,
default = true,
fileNames = listOf("mini-player-gestures.patch"),
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",
titleRes = R.string.patch_mini_player_left_right_gestures_title,
descRes = R.string.patch_mini_player_left_right_gestures_desc,
default = false,
requiresOption = "gestures",
fileNames = listOf("mini-player-gestures-left-right.patch"),
extensionFiles = listOf(
"radiant/MiniPlayerTrackGestures.smali",
"radiant/MiniPlayerTrackGestures\$Gesture.smali",
"radiant/MiniPlayerTrackGestures\$OffsetLayer.smali",
"radiant/MiniPlayerTrackGestures\$ResetAnimator.smali",
"radiant/MiniPlayerTrackGestures\$TextDraw.smali",
"com/tidal/android/feature/appscaffold/ui/q\$c.smali",
),
),
),
),
EnableLegacyUi(
order = 10,
fileNames = listOf("enable-legacy-ui.patch"),
titleRes = R.string.patch_enable_legacy_ui_title,
descRes = R.string.patch_enable_legacy_ui_desc,
default = Disabled,
requires = listOf(DebugMenuUnlock),
disables = listOf(
LyricsDisableCover,
LyricsReplaceLyricsButton,
LyricsReplaceShareButton,
LyricsRlApi,
LyricsKeepControlsVisible,
PlayerBackdrop,
QualityBadgeColors,
LyricsProgressPill,
CoverEverywhere,
MiniPlayerRedesign,
),
);
companion object {
val All: List<KnownPatch> = entries.sortedWith(
compareBy({ it.order }, { it.fileNames.firstOrNull() ?: it.name })
)
}
}
@@ -1,6 +0,0 @@
package com.meowarex.rlmobile.ui.screens.patchopts
enum class PatchDefault(val isEnabled: Boolean) {
Enabled(true),
Disabled(false),
}
@@ -1,73 +0,0 @@
package com.meowarex.rlmobile.ui.screens.patchopts
import androidx.annotation.StringRes
sealed interface PatchOption {
/** Stable identifier, unique within a single patch. */
val key: String
@get:StringRes
val titleRes: Int
@get:StringRes
val descRes: Int
/** A simple on/off switch. */
data class Toggle(
override val key: String,
@StringRes override val titleRes: Int,
@StringRes override val descRes: Int,
val default: Boolean,
/** Patch files applied only while this toggle is on (and its patch is enabled). */
val fileNames: List<String> = emptyList(),
/** Helper smali extracted only while this toggle is on. */
val extensionFiles: List<String> = emptyList(),
/** Render inline beneath the variant selector instead of inside the advanced sheet. */
val inline: Boolean = false,
/** Greyed out (with the lock dialog) unless this variant index is the selected one. */
val requiresVariant: Int? = null,
/** Greyed out unless the sibling option with this key is currently on. */
val requiresOption: String? = null,
/** Variant indices hidden from the picker while this toggle is on. */
val hidesVariants: List<Int> = emptyList(),
/** Variant title overrides (index -> @StringRes) applied while this toggle is on. */
val relabelVariants: Map<Int, Int> = emptyMap(),
/** Placeholder name (without the surrounding `__`) baked into the `.patch` files. */
val token: String? = null,
) : PatchOption
/** A continuous (or stepped) numeric value within [valueRange]. */
data class Slider(
override val key: String,
@StringRes override val titleRes: Int,
@StringRes override val descRes: Int,
val default: Float,
val valueRange: ClosedFloatingPointRange<Float>,
/** Number of discrete steps between the range ends (0 = continuous). */
val steps: Int = 0,
/** Render the value as a rounded percentage (e.g. "50%"). */
val displayAsPercent: Boolean = false,
/** Optional unit suffix shown after the value (e.g. "dp"). */
@StringRes val unitRes: Int? = null,
/** Placeholder name (without the surrounding `__`) baked into the `.patch` files. */
val token: String? = null,
/** How the chosen value becomes the smali literal that replaces the [token]. */
val encode: SmaliEncode? = null,
) : PatchOption
/** A single choice out of a small list, rendered as a segmented control. */
data class Choice(
override val key: String,
@StringRes override val titleRes: Int,
@StringRes override val descRes: Int,
val entries: List<ChoiceEntry>,
val defaultIndex: Int = 0,
val requiresOption: String? = null,
val token: String? = null,
) : PatchOption
}
data class ChoiceEntry(
@StringRes val labelRes: Int,
val value: String? = null,
)
@@ -56,6 +56,9 @@ data class PatchOptions(
(optionInts["${spec.id}/${option.key}"] ?: option.defaultIndex)
.coerceIn(0, option.entries.lastIndex.coerceAtLeast(0))
fun colorValue(spec: PatchSpec, option: OptionSpec.Color): Int =
optionInts["${spec.id}/${option.key}"] ?: option.default
fun isToggleOn(spec: PatchSpec, option: OptionSpec.Toggle): Boolean =
optionBools["${spec.id}/${option.key}"] ?: option.default
@@ -76,6 +79,8 @@ data class PatchOptions(
if (spec.variants.isEmpty()) {
if (!enabled) addAll(spec.fileNames)
} else {
// base fileNames apply for every variant while enabled; disable them when off
if (!enabled) addAll(spec.fileNames)
val selected = variantIndex(spec)
spec.variants.forEachIndexed { index, variant ->
if (!enabled || index != selected) addAll(variant.fileNames)
@@ -135,6 +140,10 @@ data class PatchOptions(
val index = if (gatedOff) 0 else choiceIndex(spec, option)
put("__${token}__", option.values.getOrNull(index) ?: continue)
}
is OptionSpec.Color -> {
val token = option.token ?: continue
put("__${token}__", colorValue(spec, option).toString())
}
}
}
}
@@ -43,6 +43,24 @@ class PatchOptionsModel(
fetchPkgNameStateDebounced()
}
/** Patches flagged [PatchSpec.pathLocked] only work under the stock package name. */
fun isBlockedByPackageName(spec: PatchSpec): Boolean =
spec.pathLocked && packageName != PatchOptions.Default.packageName && !bypassIncompatible
/** The package-name field starts locked & editing requires confirming the unlock dialog */
var packageNameLocked by mutableStateOf(prefilledOptions.packageName == PatchOptions.Default.packageName)
private set
fun unlockPackageName() {
packageNameLocked = false
}
/** Re-locking snaps the package name back to the stock default */
fun lockPackageName() {
packageNameLocked = true
changePackageName(PatchOptions.Default.packageName)
}
var appName by mutableStateOf(prefilledOptions.appName)
private set
@@ -61,10 +79,20 @@ class PatchOptionsModel(
debuggable = value
}
/** Dev override: force-allow path-gated ("incompatible") patches under a non-stock package name. */
var bypassIncompatible by mutableStateOf(prefs.bypassIncompatible)
private set
fun changeBypassIncompatible(value: Boolean) {
bypassIncompatible = value
prefs.bypassIncompatible = value
validatePatchSelection()
}
// The accordion renders from [specs]. It defaults to the compiled-in (localized) list and is
// rebuilt from a custom zip's manifest.json whenever a custom patch set is selected. (Rminder for others about the new custom patch selection flow)
private val builtinSpecs: List<PatchSpec> = builtinPatchSpecs { context.getString(it) }
private val builtinSpecs: List<PatchSpec> = builtinPatchSpecs(context, json)
var specs by mutableStateOf(builtinSpecs)
private set
@@ -83,7 +111,7 @@ class PatchOptionsModel(
.coerceIn(0, spec.variants.lastIndex.coerceAtLeast(0))
fun isPatchEnabled(spec: PatchSpec): Boolean =
patchStates[spec.id] ?: spec.defaultEnabled
!isBlockedByPackageName(spec) && (patchStates[spec.id] ?: spec.defaultEnabled)
fun setPatchEnabled(spec: PatchSpec, enabled: Boolean) {
val byId = specs.associateBy { it.id }
@@ -153,11 +181,19 @@ class PatchOptionsModel(
optionInts = optionInts + (keyOf(spec, option) to index)
}
fun colorValue(spec: PatchSpec, option: OptionSpec.Color): Int =
optionInts[keyOf(spec, option)] ?: option.default
fun setColorValue(spec: PatchSpec, option: OptionSpec.Color, value: Int) {
optionInts = optionInts + (keyOf(spec, option) to value)
}
fun isAdvancedModified(spec: PatchSpec): Boolean = spec.advancedOptions.any { option ->
when (option) {
is OptionSpec.Toggle -> toggleValue(spec, option) != option.default
is OptionSpec.Slider -> sliderValue(spec, option) != option.default
is OptionSpec.Choice -> choiceValue(spec, option) != option.defaultIndex
is OptionSpec.Color -> colorValue(spec, option) != option.default
}
}
@@ -175,11 +211,14 @@ class PatchOptionsModel(
setSlider = ::setSliderValue,
choice = ::choiceValue,
setChoice = ::setChoiceValue,
color = ::colorValue,
setColor = ::setColorValue,
isModified = ::isAdvancedModified,
reset = ::resetAdvanced,
)
fun lockState(spec: PatchSpec): PatchLock {
if (isBlockedByPackageName(spec)) return PatchLock.RequiresDefaultPackage
if (spec.variants.isNotEmpty()) return PatchLock.Free
val byId = specs.associateBy { it.id }
@@ -206,9 +245,6 @@ class PatchOptionsModel(
return PatchLock.Free
}
val enabledPatchCount: Int
get() = specs.count { isPatchEnabled(it) }
var customTidalApk by mutableStateOf<PatchComponent?>(null)
private set
var customPatches by mutableStateOf<PatchComponent?>(null)
@@ -255,6 +291,7 @@ class PatchOptionsModel(
val bytes = ZipReader(file).use { it.openEntry(MANIFEST_NAME)?.read() } ?: return null
json.decodeFromString(PatchManifest.serializer(), bytes.decodeToString())
.patches
.sortedBy { it.order } // manifest is authoritative for UI order (not KnownPatch)
.takeIf { it.isNotEmpty() }
} catch (t: Throwable) {
Log.w(BuildConfig.TAG, "Failed to parse $MANIFEST_NAME; using built-in list", t)
@@ -294,10 +331,19 @@ class PatchOptionsModel(
null
}
/** Default (non-custom) source: the latest release manifest, falling back to the built-in list. */
private fun loadCachedReleaseManifestSpecs(): List<PatchSpec>? =
paths.cacheDownloadDir
.listFiles { f -> f.name.startsWith("manifest-") && f.name.endsWith(".zip") }
?.maxByOrNull { it.lastModified() }
?.let { loadManifestSpecs(it) }
?.also { Log.i(BuildConfig.TAG, "Loaded ${it.size} patches from cached release manifest (offline)") }
/** Default (non-custom) source: latest release manifest → last cached manifest → built-in list. */
private fun loadDefaultSpecs() = screenModelScope.launchIO {
mainThread { specsLoading = true }
val loaded = loadLatestReleaseSpecs() ?: builtinSpecs
// Only hit the network when actually online
val loaded = (if (context.isOnline()) loadLatestReleaseSpecs() else null)
?: loadCachedReleaseManifestSpecs() ?: builtinSpecs
mainThread {
specs = loaded
validatePatchSelection()
@@ -323,7 +369,10 @@ class PatchOptionsModel(
debuggable = debuggable,
customTidalApk = customTidalApk,
customPatches = customPatches,
patchStates = patchStates,
// Hard-disable package-name-bound patches so the patcher can't apply
patchStates = patchStates.toMutableMap().apply {
specs.filter { isBlockedByPackageName(it) }.forEach { this[it.id] = false }
},
selectedVariants = selectedVariants,
optionFloats = optionFloats,
optionBools = optionBools,
@@ -385,4 +434,7 @@ sealed class PatchLock {
data object Free : PatchLock()
data class LockedOn(val by: PatchSpec) : PatchLock()
data class LockedOff(val by: PatchSpec) : PatchLock()
/** Locked off because the install uses a non-default package name */
data object RequiresDefaultPackage : PatchLock()
}
@@ -19,7 +19,9 @@ import com.meowarex.rlmobile.R
import com.meowarex.rlmobile.ui.components.*
import com.meowarex.rlmobile.ui.screens.componentopts.PatchComponent
import com.meowarex.rlmobile.ui.screens.patching.PatchingScreen
import androidx.compose.runtime.saveable.rememberSaveable
import com.meowarex.rlmobile.ui.screens.patchopts.components.PackageNameStateLabel
import com.meowarex.rlmobile.ui.screens.patchopts.components.PackageNameUnlockDialog
import com.meowarex.rlmobile.ui.screens.patchopts.components.PatchOptionsAppBar
import com.meowarex.rlmobile.ui.screens.patchopts.components.PatchSelectionAccordion
import com.meowarex.rlmobile.ui.screens.patchopts.components.options.*
@@ -46,6 +48,8 @@ class PatchOptionsScreen(
debuggable = model.debuggable,
setDebuggable = model::changeDebuggable,
bypassIncompatible = model.bypassIncompatible,
setBypassIncompatible = model::changeBypassIncompatible,
appName = model.appName,
appNameIsError = model.appNameIsError,
@@ -55,13 +59,16 @@ class PatchOptionsScreen(
packageNameState = model.packageNameState,
setPackageName = model::changePackageName,
packageNameLocked = model.packageNameLocked,
onUnlockPackageName = model::unlockPackageName,
onLockPackageName = model::lockPackageName,
customTidalApk = model.customTidalApk,
customPatches = model.customPatches,
onSelectCustomTidalApk = { model.selectCustomTidalApk(navigator) },
onSelectCustomPatches = { model.selectCustomPatches(navigator) },
specs = model.specs,
enabledPatchCount = model.enabledPatchCount,
isPatchEnabled = model::isPatchEnabled,
onTogglePatch = model::setPatchEnabled,
patchLockState = model::lockState,
@@ -84,6 +91,8 @@ fun PatchOptionsScreenContent(
debuggable: Boolean,
setDebuggable: (Boolean) -> Unit,
bypassIncompatible: Boolean,
setBypassIncompatible: (Boolean) -> Unit,
appName: String,
appNameIsError: Boolean,
@@ -93,13 +102,16 @@ fun PatchOptionsScreenContent(
packageNameState: PackageNameState,
setPackageName: (String) -> Unit,
packageNameLocked: Boolean,
onUnlockPackageName: () -> Unit,
onLockPackageName: () -> Unit,
customTidalApk: PatchComponent?,
onSelectCustomTidalApk: () -> Unit,
customPatches: PatchComponent?,
onSelectCustomPatches: () -> Unit,
specs: List<PatchSpec>,
enabledPatchCount: Int,
isPatchEnabled: (PatchSpec) -> Boolean,
onTogglePatch: (PatchSpec, Boolean) -> Unit,
patchLockState: (PatchSpec) -> PatchLock,
@@ -110,6 +122,19 @@ fun PatchOptionsScreenContent(
isConfigValid: Boolean,
onInstall: () -> Unit,
) {
var showPkgUnlockDialog by rememberSaveable { mutableStateOf(false) }
if (showPkgUnlockDialog) {
PackageNameUnlockDialog(
// With "Bypass Incompatible" on, path-gated patches are force-applied, not disabled.
blockedTitles = if (bypassIncompatible) emptyList() else specs.filter { it.pathLocked }.map { it.title },
onConfirm = {
showPkgUnlockDialog = false
onUnlockPackageName()
},
onDismiss = { showPkgUnlockDialog = false },
)
}
Scaffold(
topBar = { PatchOptionsAppBar(isUpdate = isUpdate) },
) { paddingValues ->
@@ -159,6 +184,10 @@ fun PatchOptionsScreenContent(
valueIsDefault = packageNameIsDefault,
onValueChange = setPackageName,
onValueReset = { setPackageName(PatchOptions.Default.packageName) },
locked = packageNameLocked,
onLockClick = {
if (packageNameLocked) showPkgUnlockDialog = true else onLockPackageName()
},
) {
PackageNameStateLabel(
state = packageNameState,
@@ -167,10 +196,16 @@ fun PatchOptionsScreenContent(
}
}
val (integrations, patches) = remember(specs) { specs.partition { it.isIntegration } }
if (integrations.isNotEmpty()) {
PatchSelectionAccordion(
specs = specs,
enabledCount = enabledPatchCount,
totalCount = specs.size,
iconRes = R.drawable.ic_extension,
titleRes = R.string.patchopts_integrations_title,
descriptionRes = R.string.patchopts_integrations_desc,
specs = integrations,
enabledCount = integrations.count(isPatchEnabled),
totalCount = integrations.size,
isEnabled = isPatchEnabled,
onToggle = onTogglePatch,
lockState = patchLockState,
@@ -179,6 +214,23 @@ fun PatchOptionsScreenContent(
optionState = optionState,
modifier = Modifier.padding(top = 4.dp),
)
}
PatchSelectionAccordion(
iconRes = R.drawable.ic_healing,
titleRes = R.string.patchopts_patches_title,
descriptionRes = R.string.patchopts_patches_desc,
specs = patches,
enabledCount = patches.count(isPatchEnabled),
totalCount = patches.size,
isEnabled = isPatchEnabled,
onToggle = onTogglePatch,
lockState = patchLockState,
variantIndex = variantIndex,
onSelectVariant = onSelectVariant,
optionState = optionState,
modifier = if (integrations.isEmpty()) Modifier.padding(top = 4.dp) else Modifier,
)
if (isDevMode) {
TextDivider(
@@ -221,6 +273,14 @@ fun PatchOptionsScreenContent(
)
}
}
SwitchPatchOption(
icon = painterResource(R.drawable.ic_lock_open),
name = stringResource(R.string.patchopts_bypass_incompatible_title),
description = stringResource(R.string.patchopts_bypass_incompatible_desc),
value = bypassIncompatible,
onValueChange = setBypassIncompatible,
)
}
Spacer(Modifier.weight(1f))
@@ -1,9 +1,11 @@
package com.meowarex.rlmobile.ui.screens.patchopts
import android.content.Context
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.Stable
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlin.math.roundToInt
@Serializable
@@ -29,7 +31,16 @@ data class PatchSpec(
val variants: List<VariantSpec> = emptyList(),
val defaultVariantIndex: Int = 0,
val advancedOptions: List<OptionSpec> = emptyList(),
)
val category: String = CATEGORY_PATCH,
val pathLocked: Boolean = false,
) {
val isIntegration: Boolean get() = category == CATEGORY_INTEGRATION
companion object {
const val CATEGORY_PATCH = "patch"
const val CATEGORY_INTEGRATION = "integration"
}
}
@Immutable
@Serializable
@@ -37,6 +48,7 @@ data class VariantSpec(
val title: String,
val fileNames: List<String> = emptyList(),
val extensionFiles: List<String> = emptyList(),
val enabled: Boolean = true,
)
/** A single advanced option. Discriminated by `"type"` in JSON. */
@@ -106,6 +118,18 @@ sealed interface OptionSpec {
val requiresOption: String? = null,
val token: String? = null,
) : OptionSpec
@Immutable
@Serializable
@SerialName("color")
data class Color(
override val key: String,
override val title: String = "",
override val description: String = "",
val default: Int = 0,
/** Placeholder name (without the surrounding `__`) baked into the `.patch`/extension files. */
val token: String? = null,
) : OptionSpec
}
@Serializable
@@ -136,68 +160,21 @@ data class SmaliEncode(
}
}
fun builtinPatchSpecs(resolve: (Int) -> String): List<PatchSpec> =
KnownPatch.All.map { patch ->
PatchSpec(
id = patch.name,
order = patch.order,
fileNames = patch.fileNames,
extensionFiles = patch.extensionFiles,
title = resolve(patch.titleRes),
description = resolve(patch.descRes),
defaultEnabled = patch.default.isEnabled,
requires = patch.requires.map { it.name },
disables = patch.disables.map { it.name },
variants = patch.variants.map { VariantSpec(resolve(it.titleRes), it.fileNames, it.extensionFiles) },
defaultVariantIndex = patch.defaultVariantIndex,
advancedOptions = patch.advancedOptions.map { it.toSpec(resolve) },
)
}
/** Asset filename of the bundled fallback manifest snapshot (a copy of the release manifest.json). */
const val BUNDLED_MANIFEST_ASSET = "patches-manifest.json"
private fun PatchOption.toSpec(resolve: (Int) -> String): OptionSpec = when (this) {
is PatchOption.Toggle -> OptionSpec.Toggle(
key = key,
title = resolve(titleRes),
description = resolve(descRes),
default = default,
fileNames = fileNames,
extensionFiles = extensionFiles,
inline = inline,
requiresVariant = requiresVariant,
requiresOption = requiresOption,
hidesVariants = hidesVariants,
relabelVariants = relabelVariants.mapValues { resolve(it.value) },
token = token,
)
is PatchOption.Slider -> OptionSpec.Slider(
key = key,
title = resolve(titleRes),
description = resolve(descRes),
default = default,
min = valueRange.start,
max = valueRange.endInclusive,
steps = steps,
displayAsPercent = displayAsPercent,
unit = unitRes?.let(resolve),
token = token,
encode = encode,
)
is PatchOption.Choice -> OptionSpec.Choice(
key = key,
title = resolve(titleRes),
description = resolve(descRes),
entries = entries.map { resolve(it.labelRes) },
defaultIndex = defaultIndex,
values = entries.map { it.value ?: "" },
requiresOption = requiresOption,
token = token,
)
// Fallback patch list (snapshot of the release manifest bundled in the app's assets)
fun builtinPatchSpecs(context: Context, json: Json): List<PatchSpec> = try {
context.assets.open(BUNDLED_MANIFEST_ASSET).use { it.readBytes() }
.let { json.decodeFromString(PatchManifest.serializer(), it.decodeToString()) }
.patches
.sortedBy { it.order }
} catch (t: Throwable) {
emptyList()
}
@Immutable
data class EffectiveVariant(val originalIndex: Int, val title: String)
data class EffectiveVariant(val originalIndex: Int, val title: String, val enabled: Boolean = true)
fun PatchSpec.effectiveVariants(isOptionOn: (OptionSpec.Toggle) -> Boolean): List<EffectiveVariant> {
if (variants.isEmpty()) return emptyList()
@@ -210,19 +187,22 @@ fun PatchSpec.effectiveVariants(isOptionOn: (OptionSpec.Toggle) -> Boolean): Lis
}
}
return variants.mapIndexedNotNull { index, variant ->
if (index in hidden) null else EffectiveVariant(index, relabel[index] ?: variant.title)
if (index in hidden) null
else EffectiveVariant(index, relabel[index] ?: variant.title, variant.enabled)
}
}
fun PatchSpec.resolveVariantIndex(stored: Int, isOptionOn: (OptionSpec.Toggle) -> Boolean): Int {
val visible = effectiveVariants(isOptionOn)
if (visible.isEmpty() || visible.any { it.originalIndex == stored }) return stored
// never resolve onto a greyed/disabled variant
if (visible.isEmpty() || visible.any { it.originalIndex == stored && it.enabled }) return stored
val relabelKeys = buildSet {
for (option in advancedOptions) {
if (option is OptionSpec.Toggle && isOptionOn(option)) addAll(option.relabelVariants.keys)
}
}
return visible.firstOrNull { it.originalIndex in relabelKeys }?.originalIndex
return visible.firstOrNull { it.originalIndex in relabelKeys && it.enabled }?.originalIndex
?: visible.firstOrNull { it.enabled }?.originalIndex
?: visible.first().originalIndex
}
@@ -258,6 +238,8 @@ class PatchOptionState(
val setSlider: (PatchSpec, OptionSpec.Slider, Float) -> Unit,
val choice: (PatchSpec, OptionSpec.Choice) -> Int,
val setChoice: (PatchSpec, OptionSpec.Choice, Int) -> Unit,
val color: (PatchSpec, OptionSpec.Color) -> Int,
val setColor: (PatchSpec, OptionSpec.Color, Int) -> Unit,
val isModified: (PatchSpec) -> Boolean,
val reset: (PatchSpec) -> Unit,
) {
@@ -270,6 +252,8 @@ class PatchOptionState(
setSlider = { _, _, _ -> },
choice = { _, option -> option.defaultIndex },
setChoice = { _, _, _ -> },
color = { _, option -> option.default },
setColor = { _, _, _ -> },
isModified = { false },
reset = {},
)
@@ -0,0 +1,88 @@
package com.meowarex.rlmobile.ui.screens.patchopts.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.fromHtml
import androidx.compose.ui.unit.dp
import com.meowarex.rlmobile.R
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
/**
* Confirms unlocking the package-name field, warning that a custom name
* blocks the listed patches/integrations from working.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PackageNameUnlockDialog(
blockedTitles: List<String>,
onConfirm: () -> Unit,
onDismiss: () -> Unit,
) {
BasicAlertDialog(onDismissRequest = onDismiss) {
Surface(
shape = MaterialTheme.shapes.large,
color = MaterialTheme.colorScheme.surfaceContainerHigh,
tonalElevation = 6.dp,
) {
Column(
modifier = Modifier.padding(start = 24.dp, end = 12.dp, top = 20.dp, bottom = 8.dp),
verticalArrangement = Arrangement.spacedBy(6.dp),
) {
Text(
text = stringResource(R.string.patchopts_pkgname_warning_title),
style = MaterialTheme.typography.titleLarge,
)
Text(
text = AnnotatedString.fromHtml(
stringResource(R.string.patchopts_pkgname_warning_msg, PatchOptions.Default.packageName),
),
style = MaterialTheme.typography.bodyLarge,
)
if (blockedTitles.isNotEmpty()) {
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier.padding(start = 4.dp),
) {
for (title in blockedTitles) {
Text(
text = "$title",
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.Bold,
)
}
}
}
Text(
text = stringResource(R.string.patchopts_pkgname_warning_permanent),
style = MaterialTheme.typography.bodyLarge,
)
Box(modifier = Modifier.fillMaxWidth()) {
Row(modifier = Modifier.align(Alignment.CenterEnd)) {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.action_cancel))
}
TextButton(onClick = onConfirm) {
Text(stringResource(R.string.action_continue))
}
}
}
}
}
}
}
@@ -7,6 +7,8 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
@@ -15,11 +17,15 @@ 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.graphics.Color
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.fromHtml
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
@@ -196,6 +202,12 @@ fun PatchAdvancedOptionsSheet(
onSelect = { state.setChoice(patch, option, it) },
)
}
is OptionSpec.Color -> ColorOptionRow(
title = option.title,
color = state.color(patch, option),
onColorChange = { state.setColor(patch, option, it) },
)
}
}
@@ -378,6 +390,39 @@ private fun ChoiceOptionRow(
textAlign = TextAlign.Center,
)
}
if (entries.size > 3) {
var expanded by rememberSaveable { mutableStateOf(false) }
val selectedLabel = entries.getOrNull(selectedIndex).orEmpty()
Box(modifier = Modifier.fillMaxWidth()) {
OutlinedButton(
onClick = { expanded = true },
modifier = Modifier.fillMaxWidth(),
) {
Text(
text = selectedLabel,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
DropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false },
modifier = Modifier.fillMaxWidth(),
) {
entries.forEachIndexed { index, entry ->
DropdownMenuItem(
text = { Text(entry) },
onClick = {
onSelect(index)
expanded = false
},
)
}
}
}
return@Column
}
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
entries.forEachIndexed { index, entry ->
SegmentedButton(
@@ -400,6 +445,150 @@ private fun ChoiceOptionRow(
}
}
@Composable
private fun ColorOptionRow(
title: String,
color: Int,
onColorChange: (Int) -> Unit,
) {
var showPicker by rememberSaveable { mutableStateOf(false) }
val selectedColor = color.withOpaqueAlpha()
val materialYouColor = MaterialTheme.colorScheme.primary.toArgb().withOpaqueAlpha()
val presets = listOf(
stringResource(R.string.patch_waze_color_waze_default),
stringResource(R.string.patch_waze_color_tidal_cyan),
stringResource(R.string.patch_waze_color_material_you),
)
val presetColors = listOf(WAZE_DEFAULT, TIDAL_CYAN, materialYouColor)
val selectedPreset = presetColors.indexOf(selectedColor)
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(
text = title,
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.align(Alignment.CenterHorizontally),
)
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(10.dp),
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.medium)
.clickable { showPicker = true }
.padding(vertical = 4.dp),
) {
ColorSwatch(color = selectedColor)
Text(
text = selectedColor.toRgbHex(),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.primary,
)
}
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
presets.forEachIndexed { index, label ->
SegmentedButton(
selected = index == selectedPreset,
onClick = { onColorChange(presetColors[index]) },
shape = SegmentedButtonDefaults.itemShape(index = index, count = presets.size),
icon = {},
label = {
Text(
text = label,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.labelMedium,
)
},
)
}
}
}
if (showPicker) {
ColorPickerDialog(
initialColor = selectedColor,
onDismiss = { showPicker = false },
onColorSelected = {
onColorChange(it)
showPicker = false
},
)
}
}
@Composable
private fun ColorSwatch(color: Int, modifier: Modifier = Modifier) {
Box(
modifier = modifier
.size(32.dp)
.clip(CircleShape)
.background(Color(color))
.border(1.dp, MaterialTheme.colorScheme.outlineVariant, CircleShape),
)
}
@Composable
private fun ColorPickerDialog(
initialColor: Int,
onDismiss: () -> Unit,
onColorSelected: (Int) -> Unit,
) {
var color by rememberSaveable(initialColor) { mutableIntStateOf(initialColor.withOpaqueAlpha()) }
var hex by rememberSaveable(initialColor) { mutableStateOf(color.toRgbHex()) }
val parsedHex = parseRgbHex(hex)
AlertDialog(
onDismissRequest = onDismiss,
title = { Text(stringResource(R.string.patch_color_picker_title)) },
text = {
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(12.dp),
) {
ColorSwatch(color = parsedHex ?: color, modifier = Modifier.size(40.dp))
OutlinedTextField(
value = hex,
onValueChange = { value ->
hex = value
parseRgbHex(value)?.let { color = it }
},
label = { Text(stringResource(R.string.patch_color_picker_hex)) },
singleLine = true,
isError = parsedHex == null,
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Characters,
keyboardType = KeyboardType.Ascii,
),
supportingText = if (parsedHex == null) {
{ Text(stringResource(R.string.patch_color_picker_hex_error)) }
} else null,
modifier = Modifier.weight(1f),
)
}
}
},
confirmButton = {
TextButton(
enabled = parsedHex != null,
onClick = { parsedHex?.let(onColorSelected) },
) {
Text(stringResource(R.string.action_done))
}
},
dismissButton = {
TextButton(onClick = onDismiss) {
Text(stringResource(R.string.action_cancel))
}
},
)
}
@Composable
private fun OptionText(
title: String,
@@ -432,6 +621,26 @@ private fun formatSliderValue(option: OptionSpec.Slider, value: Float): String {
}
}
private const val OPAQUE_ALPHA = -0x1000000
private const val WAZE_DEFAULT = -16747037 // #ff0075e3
private const val TIDAL_CYAN = -14549268 // #ff21feec
private fun Int.withOpaqueAlpha(): Int = (this and 0x00FFFFFF) or OPAQUE_ALPHA
private fun Int.toRgbHex(): String = "#" +
(this and 0x00FFFFFF).toString(16).uppercase().padStart(6, '0')
private fun parseRgbHex(value: String): Int? {
val clean = value.trim()
.removePrefix("#")
.removePrefix("0x")
.removePrefix("0X")
if (clean.length != 6 && clean.length != 8) return null
val parsed = clean.toLongOrNull(16) ?: return null
val rgb = if (clean.length == 8) parsed and 0x00FFFFFFL else parsed
return (0xFF000000L or rgb).toInt()
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun OptionLockDialog(lock: OptionLock, onDismiss: () -> Unit) {
@@ -1,6 +1,8 @@
package com.meowarex.rlmobile.ui.screens.patchopts.components
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
@@ -27,6 +29,7 @@ import com.meowarex.rlmobile.R
import com.meowarex.rlmobile.ui.screens.patchopts.OptionSpec
import com.meowarex.rlmobile.ui.screens.patchopts.PatchLock
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptionState
import com.meowarex.rlmobile.ui.screens.patchopts.PatchOptions
import com.meowarex.rlmobile.ui.screens.patchopts.PatchSpec
import com.meowarex.rlmobile.ui.screens.patchopts.effectiveVariants
import com.meowarex.rlmobile.ui.screens.patchopts.resolveVariantIndex
@@ -35,6 +38,9 @@ private data class LockInfo(val patch: PatchSpec, val lock: PatchLock)
@Composable
fun PatchSelectionAccordion(
@DrawableRes iconRes: Int,
@StringRes titleRes: Int,
@StringRes descriptionRes: Int,
specs: List<PatchSpec>,
enabledCount: Int,
totalCount: Int,
@@ -69,12 +75,17 @@ fun PatchSelectionAccordion(
.clickable(role = Role.Button) { expanded = !expanded }
.padding(horizontal = 16.dp, vertical = 14.dp),
) {
Icon(
painter = painterResource(iconRes),
contentDescription = null,
)
Column(
verticalArrangement = Arrangement.spacedBy(2.dp),
modifier = Modifier.weight(1f),
) {
Text(
text = stringResource(R.string.patchopts_patches_title),
text = stringResource(titleRes),
style = MaterialTheme.typography.titleMedium,
)
Text(
@@ -106,7 +117,7 @@ fun PatchSelectionAccordion(
.padding(horizontal = 16.dp, vertical = 12.dp),
) {
Text(
text = stringResource(R.string.patchopts_patches_desc),
text = stringResource(descriptionRes),
style = MaterialTheme.typography.bodySmall,
modifier = Modifier
.alpha(.7f)
@@ -158,15 +169,18 @@ fun PatchSelectionAccordion(
.fillMaxWidth()
.padding(bottom = 8.dp),
) {
if (patch.variants.isNotEmpty()) {
val effective = patch.effectiveVariants { optionState.toggle(patch, it) }
val resolved = patch.resolveVariantIndex(variantIndex(patch)) {
val resolvedVariant =
if (patch.variants.isNotEmpty())
patch.resolveVariantIndex(variantIndex(patch)) {
optionState.toggle(patch, it)
}
else -1
if (patch.variants.isNotEmpty()) {
val effective = patch.effectiveVariants { optionState.toggle(patch, it) }
PatchVariantSelector(
variants = effective,
selectedIndex = effective
.indexOfFirst { it.originalIndex == resolved }
.indexOfFirst { it.originalIndex == resolvedVariant }
.coerceAtLeast(0),
onSelect = { pos ->
effective.getOrNull(pos)?.let { onSelectVariant(patch, it.originalIndex) }
@@ -175,6 +189,9 @@ fun PatchSelectionAccordion(
}
for (option in inlineToggles) key(option.key) {
val show = option.requiresVariant == null ||
option.requiresVariant == resolvedVariant
if (show) {
InlineToggleRow(
title = option.title,
description = option.description,
@@ -182,6 +199,7 @@ fun PatchSelectionAccordion(
onCheckedChange = { optionState.setToggle(patch, option, it) },
)
}
}
if (hasSheetOptions) {
Box(
@@ -372,6 +390,11 @@ private fun PatchLockDialog(
R.string.patch_lock_blocked_msg,
lock.by.title,
)
PatchLock.RequiresDefaultPackage -> Triple(
R.string.patch_lock_pkgname_title,
R.string.patch_lock_pkgname_msg,
PatchOptions.Default.packageName,
)
PatchLock.Free -> return
}
@@ -391,7 +414,7 @@ private fun PatchLockDialog(
)
Text(
text = AnnotatedString.fromHtml(stringResource(msgRes, blockerTitle)),
style = MaterialTheme.typography.titleMedium,
style = MaterialTheme.typography.bodyLarge,
)
Box(modifier = Modifier.fillMaxWidth()) {
TextButton(
@@ -22,7 +22,8 @@ fun PatchVariantSelector(
variants.forEachIndexed { index, variant ->
SegmentedButton(
selected = index == selectedIndex,
onClick = { onSelect(index) },
enabled = variant.enabled,
onClick = { if (variant.enabled) onSelect(index) },
shape = SegmentedButtonDefaults.itemShape(
index = index,
count = variants.size,
@@ -3,8 +3,12 @@ package com.meowarex.rlmobile.ui.screens.patchopts.components.options
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.meowarex.rlmobile.R
import com.meowarex.rlmobile.ui.components.Label
import com.meowarex.rlmobile.ui.components.ResetToDefaultButton
@@ -18,6 +22,8 @@ fun TextPatchOption(
onValueChange: (String) -> Unit,
onValueReset: () -> Unit,
modifier: Modifier = Modifier,
locked: Boolean? = null,
onLockClick: () -> Unit = {},
extra: (@Composable ColumnScope.() -> Unit)? = null,
) {
Label(
@@ -30,16 +36,41 @@ fun TextPatchOption(
onValueChange = onValueChange,
isError = valueIsError,
singleLine = true,
enabled = locked != true,
colors = OutlinedTextFieldDefaults.colors(
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
focusedContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
errorContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
disabledContainerColor = MaterialTheme.colorScheme.surfaceContainerLow,
),
trailingIcon = {
Row(verticalAlignment = Alignment.CenterVertically) {
if (locked != true) {
ResetToDefaultButton(
enabled = !valueIsDefault,
onClick = onValueReset,
)
}
if (locked != null) {
IconButton(
onClick = onLockClick,
modifier = Modifier.size(32.dp),
) {
Icon(
painter = painterResource(
if (locked) R.drawable.ic_lock else R.drawable.ic_lock_open,
),
contentDescription = stringResource(
if (locked) R.string.patchopts_field_unlock else R.string.patchopts_field_lock,
),
tint = if (locked) MaterialTheme.colorScheme.primary
else MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(18.dp),
)
}
Spacer(Modifier.width(8.dp))
}
}
},
modifier = Modifier
.fillMaxWidth()
@@ -5,6 +5,8 @@ import android.app.Activity
import android.content.*
import android.content.pm.PackageManager
import android.content.res.Resources
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.net.Uri
import android.os.*
import android.provider.Settings
@@ -63,6 +65,15 @@ fun Context.getPackageVersion(pkg: String): Pair<String?, Int> {
.let { it.versionName to it.versionCode }
}
// Whether the device currently has a validated internet connection
fun Context.isOnline(): Boolean {
val cm = getSystemService<ConnectivityManager>() ?: return true
val network = cm.activeNetwork ?: return false
val caps = cm.getNetworkCapabilities(network) ?: return false
return caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) &&
caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
}
fun Context.isPackageInstalled(packageName: String): Boolean {
return try {
packageManager.getPackageInfo(packageName, 0)
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="#e8eaed"
android:pathData="M218,856L104,742Q81,719 81,686Q81,653 104,630L630,104Q653,81 686,81Q719,81 742,104L856,218Q879,241 879,274Q879,307 856,330L330,856Q307,879 274,879Q241,879 218,856ZM508,734L734,508L856,630Q879,653 879,686Q879,719 856,742L742,856Q719,879 686,879Q653,879 630,856L508,734ZM480,600Q497,600 508.5,588.5Q520,577 520,560Q520,543 508.5,531.5Q497,520 480,520Q463,520 451.5,531.5Q440,543 440,560Q440,577 451.5,588.5Q463,600 480,600ZM400,520Q417,520 428.5,508.5Q440,497 440,480Q440,463 428.5,451.5Q417,440 400,440Q383,440 371.5,451.5Q360,463 360,480Q360,497 371.5,508.5Q383,520 400,520ZM560,520Q577,520 588.5,508.5Q600,497 600,480Q600,463 588.5,451.5Q577,440 560,440Q543,440 531.5,451.5Q520,463 520,480Q520,497 531.5,508.5Q543,520 560,520ZM225,451L104,330Q81,307 81,274Q81,241 104,218L218,104Q241,81 274,81Q307,81 330,104L452,226L225,451ZM480,440Q497,440 508.5,428.5Q520,417 520,400Q520,383 508.5,371.5Q497,360 480,360Q463,360 451.5,371.5Q440,383 440,400Q440,417 451.5,428.5Q463,440 480,440Z" />
</vector>
+25 -1
View File
@@ -180,7 +180,7 @@
<string name="install_error_timeout">Installer timed out</string>
<string name="install_group_prepare">Prepare</string>
<string name="install_group_download">Download dependencies</string>
<string name="install_group_download">Download Batteries</string>
<string name="install_group_patch">Patch APK</string>
<string name="install_group_install">Install APK</string>
@@ -247,14 +247,23 @@
<string name="patchopts_custom_tidal_apk_desc">Provide your own Stock TIDAL APK to patch instead of the version from Github.</string>
<string name="patchopts_custom_patches_title">Custom Patches</string>
<string name="patchopts_custom_patches_desc">Provide your own Patches Zip to use instead of the ones from Github.</string>
<string name="patchopts_bypass_incompatible_title">Bypass Incompatible</string>
<string name="patchopts_bypass_incompatible_desc">Force-allow path-gated patches. This can be VERY DANGEROUS!</string>
<string name="patchopts_divider_basic">Basic</string>
<string name="patchopts_divider_advanced">Advanced</string>
<string name="patchopts_patches_title">Patches</string>
<string name="patchopts_patches_desc">Toggle which patches are applied during installation. Unchecked patches are skipped entirely.</string>
<string name="patchopts_patches_summary">%1$d of %2$d enabled</string>
<string name="patchopts_integrations_title">Integrations</string>
<string name="patchopts_integrations_desc">Connect TIDAL to other systems/apps</string>
<string name="patchopts_pkgname_warning_title">Custom Package Name</string>
<string name="patchopts_pkgname_warning_msg">Installing under a package name other than &lt;b>%s&lt;/b> will block the following from working:</string>
<string name="patchopts_pkgname_warning_permanent">The package name is permanent once installed (requires a fresh install)</string>
<string name="patchopts_advanced_button">Advanced Options</string>
<string name="patchopts_advanced_sheet_label">Advanced Options</string>
<string name="patchopts_toggle_snap">Toggle snapping to steps</string>
<string name="patchopts_field_unlock">Unlock editing</string>
<string name="patchopts_field_lock">Lock and reset to default</string>
<string name="patch_lyrics_disable_cover_title">Disable Lyrics Cover</string>
<string name="patch_lyrics_disable_cover_desc">Removes the mini track cover from the lyrics screen.</string>
@@ -286,6 +295,19 @@
<string
name="patch_debug_menu_unlock_desc"
>Reveals TIDAL\'s hidden Debug Menu in Settings. (Unlocks Feature Flags &amp; the legacy Debug Options)</string>
<string name="patch_waze_integration_title">Waze Integration</string>
<string name="patch_waze_integration_desc">Control TIDAL playback from the Waze app</string>
<string name="patch_waze_browse_root_title">Media Menu</string>
<string name="patch_waze_accent_color_title">Accent Color</string>
<string name="patch_waze_color_waze_default">Waze Default</string>
<string name="patch_waze_color_tidal_cyan">TIDAL Cyan</string>
<string name="patch_waze_color_material_you">Material You</string>
<string name="patch_waze_root_auto">Auto Menu</string>
<string name="patch_waze_root_home">Home</string>
<string name="patch_waze_root_recents">Recents</string>
<string name="patch_color_picker_title">Custom color</string>
<string name="patch_color_picker_hex">Hex color</string>
<string name="patch_color_picker_hex_error">Use #RRGGBB or #AARRGGBB.</string>
<string name="patch_enable_legacy_ui_title">Enable Legacy UI</string>
<string
name="patch_enable_legacy_ui_desc"
@@ -320,6 +342,8 @@
<string name="patch_lock_blocked_title">Patch Blocked!</string>
<string name="patch_lock_required_msg">Patch Required by &lt;b>%s&lt;/b>.</string>
<string name="patch_lock_blocked_msg">Patch Blocked by &lt;b>%s&lt;/b>.</string>
<string name="patch_lock_pkgname_title">Original Package Name Invalid!</string>
<string name="patch_lock_pkgname_msg">This only works while the app keeps its original &lt;b>%s&lt;/b> package name. Reset the Package Name option to enable it.&lt;br/>&lt;br/>An existing install can\'t be renamed (requires a fresh install)</string>
<string name="patch_opt_lock_title">Option Locked</string>
<string name="patch_opt_lock_needs_variant">Requires the &lt;b>%s&lt;/b> style.</string>
<string name="patch_opt_lock_needs_option">Requires the &lt;b>%s&lt;/b> option.</string>
+20 -5
View File
@@ -2,13 +2,25 @@
A Manager app for Android that patches TIDAL to bring the Radiant Lyrics experience to mobile.
## What it does
## What it does?
- Blurred album art background in the player
- Progress pill overlay in lyrics mode - restored from old UI
- Hides the ugly cover art when in lyrics mode
This project adds ALLOT of completely Optional & Customisable Patches/Integrations to TIDAL on Android (iOS SoonTM).
Every Patch & Integration can be disabled/enabled & adjusted exactly how you want TIDAL to feel/look <3
### Patches:
- Insane Customisation of the Player Backdrop
- Higher quality lyrics from more providers (WIP)
- Progress pill overlay in lyrics mode (restored from old UI)
- Keeps lyrics controls visible
- One-handed player controls
- Redesigned mini-player with gestures
- Word Level Lyrics (Word by Word) <3
- Syllable Level lyrics (SoonTM)
### Integrations
- Waze | Control TIDAL playback from Waze
### Disclaimer
@@ -18,7 +30,10 @@ This project is not affiliated with TIDAL in any way. Use at your own risk.
## Installation
### Batteries <3
- Android 10.0+ & >340 DPI
- Phone of some unknown description
- The smallest amount of brain damage
- Android 7.0+ & >340 DPI
- Internet
- Paid TIDAL Account
### Steps
+16 -5
View File
@@ -1,11 +1,22 @@
--- a/com/tidal/android/feature/appscaffold/ui/p.smali
+++ b/com/tidal/android/feature/appscaffold/ui/p.smali
@@ -51,6 +51,8 @@
--- a/com/tidal/android/feature/appscaffold/ui/q.smali
+++ b/com/tidal/android/feature/appscaffold/ui/q.smali
@@ -55,6 +55,8 @@
.line 10
iput-object p4, p0, Lcom/tidal/android/feature/appscaffold/ui/p;->d:Ljava/lang/String;
iput-object p4, p0, Lcom/tidal/android/feature/appscaffold/ui/q;->d:Ljava/lang/String;
+ invoke-static {p3, p4}, Lradiant/HomeBackdrop;->fromMiniPlayer(ILjava/lang/String;)V # capture cover state
+
.line 11
.line 12
iput-boolean p5, p0, Lcom/tidal/android/feature/appscaffold/ui/p;->e:Z
iput-boolean p5, p0, Lcom/tidal/android/feature/appscaffold/ui/q;->e:Z
--- a/com/tidal/android/feature/appscaffold/ui/t.smali
+++ b/com/tidal/android/feature/appscaffold/ui/t.smali
@@ -23,6 +23,8 @@
.method public constructor <init>(Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$ItemType;Lcom/tidal/android/feature/appscaffold/ui/q;Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;Z)V
.locals 0
+ invoke-static {p3}, Lradiant/HomeBackdrop;->onPlayState(Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;)V # RL: publish live play state to Cover Everywhere
+
.line 1
invoke-virtual {p1}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
+2 -2
View File
@@ -1,5 +1,5 @@
{
"tidalVersionCode": 9090,
"tidalVersionCode": 10004,
"tidalApkUrl": "https://github.com/meowarex/rl-mobile/releases/download/latest/tidal-stock.apk",
"patchesVersion": "0.9.13"
"patchesVersion": "0.12.0"
}
+6 -5
View File
@@ -8,9 +8,9 @@
+ return v0 # bypass debug flag
+
.line 1
iget-object v0, p0, Lcom/tidal/android/core/debug/DebugFeatureInteractorDefault;->a:Lcom/tidal/android/featureflags/l;
iget-object v0, p0, Lcom/tidal/android/core/debug/DebugFeatureInteractorDefault;->a:Lcom/tidal/android/featureflags/n;
@@ -98,6 +101,14 @@
@@ -99,6 +102,14 @@
}
.end annotation
@@ -23,9 +23,9 @@
+ return-object v0 # short-circuit b()
+
.line 1
sget-object v0, Lj50/a;->a:Ljava/lang/String;
sget-object v0, Lo50/a;->a:Ljava/lang/String;
@@ -261,5 +272,8 @@
@@ -261,6 +272,9 @@
.method public final c()Z
.locals 3
@@ -33,4 +33,5 @@
+ return v0 # bypass debug flag
+
.line 1
sget-object v0, Lj50/a;->a:Ljava/lang/String;
sget-object v0, Lo50/a;->a:Ljava/lang/String;
+3 -4
View File
@@ -1,7 +1,6 @@
--- a/kg/e.smali
+++ b/kg/e.smali
@@ -26,8 +26,8 @@
new-instance v0, Lkg/e;
--- a/hg/d.smali
+++ b/hg/d.smali
@@ -27,7 +27,7 @@
.line 2
.line 3
@@ -1,13 +1,12 @@
.class public final Lcom/tidal/android/feature/appscaffold/ui/q$c;
.super Lcom/tidal/android/feature/appscaffold/ui/q;
.class public final Lcom/tidal/android/feature/appscaffold/ui/r$c;
.super Lcom/tidal/android/feature/appscaffold/ui/r;
.source "SourceFile"
# Synthetic mini-player event used by right swipe (previous/rewind).
# TIDAL already exposes q$a for next in this path
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
value = Lcom/tidal/android/feature/appscaffold/ui/q;
value = Lcom/tidal/android/feature/appscaffold/ui/r;
.end annotation
.annotation system Ldalvik/annotation/InnerClass;
@@ -17,18 +16,18 @@
# static fields
.field public static final a:Lcom/tidal/android/feature/appscaffold/ui/q$c;
.field public static final a:Lcom/tidal/android/feature/appscaffold/ui/r$c;
# direct methods
.method static constructor <clinit>()V
.locals 1
new-instance v0, Lcom/tidal/android/feature/appscaffold/ui/q$c;
new-instance v0, Lcom/tidal/android/feature/appscaffold/ui/r$c;
invoke-direct {v0}, Lcom/tidal/android/feature/appscaffold/ui/q;-><init>()V
invoke-direct {v0}, Lcom/tidal/android/feature/appscaffold/ui/r;-><init>()V
sput-object v0, Lcom/tidal/android/feature/appscaffold/ui/q$c;->a:Lcom/tidal/android/feature/appscaffold/ui/q$c;
sput-object v0, Lcom/tidal/android/feature/appscaffold/ui/r$c;->a:Lcom/tidal/android/feature/appscaffold/ui/r$c;
return-void
.end method
@@ -45,7 +44,7 @@
return v0
:cond_0
instance-of p1, p1, Lcom/tidal/android/feature/appscaffold/ui/q$c;
instance-of p1, p1, Lcom/tidal/android/feature/appscaffold/ui/r$c;
if-nez p1, :cond_1
+133
View File
@@ -0,0 +1,133 @@
.class public final Lradiant/BackdropFx;
.super Ljava/lang/Object;
.method public static apply(Landroid/graphics/Bitmap;)Landroid/graphics/Bitmap;
.locals 14
const v0, __RL_CONTRAST__
const v1, __RL_SATURATION__
const v2, __RL_BRIGHTNESS__
# cm = ColorMatrix(); cm.setSaturation(s)
new-instance v3, Landroid/graphics/ColorMatrix;
invoke-direct {v3}, Landroid/graphics/ColorMatrix;-><init>()V
invoke-virtual {v3, v1}, Landroid/graphics/ColorMatrix;->setSaturation(F)V
# o = 128 - 128*c (contrast pivot at mid-grey, 0..255 space)
const/high16 v4, 0x43000000
mul-float v5, v4, v0
sub-float v5, v4, v5
# contrast matrix: diag = c, offset column = o
const/16 v6, 0x14
new-array v7, v6, [F
const/4 v8, 0x0
aput v0, v7, v8
const/4 v8, 0x4
aput v5, v7, v8
const/4 v8, 0x6
aput v0, v7, v8
const/16 v8, 0x9
aput v5, v7, v8
const/16 v8, 0xc
aput v0, v7, v8
const/16 v8, 0xe
aput v5, v7, v8
const/high16 v9, 0x3f800000
const/16 v8, 0x12
aput v9, v7, v8
new-instance v8, Landroid/graphics/ColorMatrix;
invoke-direct {v8, v7}, Landroid/graphics/ColorMatrix;-><init>([F)V
invoke-virtual {v3, v8}, Landroid/graphics/ColorMatrix;->postConcat(Landroid/graphics/ColorMatrix;)V
# brightness matrix: diag = b
new-array v7, v6, [F
const/4 v8, 0x0
aput v2, v7, v8
const/4 v8, 0x6
aput v2, v7, v8
const/16 v8, 0xc
aput v2, v7, v8
const/16 v8, 0x12
aput v9, v7, v8
new-instance v8, Landroid/graphics/ColorMatrix;
invoke-direct {v8, v7}, Landroid/graphics/ColorMatrix;-><init>([F)V
invoke-virtual {v3, v8}, Landroid/graphics/ColorMatrix;->postConcat(Landroid/graphics/ColorMatrix;)V
# out = createBitmap(w, h, ARGB_8888)
invoke-virtual {p0}, Landroid/graphics/Bitmap;->getWidth()I
move-result v10
invoke-virtual {p0}, Landroid/graphics/Bitmap;->getHeight()I
move-result v11
sget-object v12, Landroid/graphics/Bitmap$Config;->ARGB_8888:Landroid/graphics/Bitmap$Config;
invoke-static {v10, v11, v12}, Landroid/graphics/Bitmap;->createBitmap(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;
move-result-object v10
# canvas over out
new-instance v11, Landroid/graphics/Canvas;
invoke-direct {v11, v10}, Landroid/graphics/Canvas;-><init>(Landroid/graphics/Bitmap;)V
# paint with the color-matrix filter
new-instance v12, Landroid/graphics/Paint;
invoke-direct {v12}, Landroid/graphics/Paint;-><init>()V
new-instance v13, Landroid/graphics/ColorMatrixColorFilter;
invoke-direct {v13, v3}, Landroid/graphics/ColorMatrixColorFilter;-><init>(Landroid/graphics/ColorMatrix;)V
invoke-virtual {v12, v13}, Landroid/graphics/Paint;->setColorFilter(Landroid/graphics/ColorFilter;)Landroid/graphics/ColorFilter;
# draw the blurred bitmap through the filter
const/4 v0, 0x0
invoke-virtual {v11, p0, v0, v0, v12}, Landroid/graphics/Canvas;->drawBitmap(Landroid/graphics/Bitmap;FFLandroid/graphics/Paint;)V
invoke-virtual {p0}, Landroid/graphics/Bitmap;->recycle()V
return-object v10
.end method
+114 -69
View File
@@ -5,6 +5,20 @@
# static fields
.field public static volatile currentAlbumId:I
# 0 = Static, 1 = Animated (always rotate), 2 = Playback (follow live play state)
.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;
value = {
"Landroidx/compose/runtime/MutableState<",
"Ljava/lang/Boolean;",
">;"
}
.end annotation
.end field
.field public static coverUuidState:Landroidx/compose/runtime/MutableState;
.annotation system Ldalvik/annotation/Signature;
value = {
@@ -24,6 +38,24 @@
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
const/4 v2, 0x2
const/4 v3, 0x0
invoke-static {v0, v1, 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 v0
sput-object v0, Lradiant/HomeBackdrop;->isPlayingState:Landroidx/compose/runtime/MutableState;
const/4 v0, 0x0
const/4 v1, 0x0
@@ -41,6 +73,64 @@
return-void
.end method
.method public static setModeStatic()V
.locals 1
const/4 v0, 0x0
sput v0, Lradiant/HomeBackdrop;->mode:I
return-void
.end method
.method public static setModeAnimated()V
.locals 1
const/4 v0, 0x1
sput v0, Lradiant/HomeBackdrop;->mode:I
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.<init>) whenever play state changes.
.method public static onPlayState(Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;)V
.locals 2
sget-object v0, Lradiant/HomeBackdrop;->isPlayingState:Landroidx/compose/runtime/MutableState;
if-nez v0, :cond_ready
return-void
:cond_ready
sget-object v1, Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;->Playing:Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;
if-ne p0, v1, :cond_paused
sget-object v1, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
goto :goto_set
:cond_paused
sget-object v1, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;
:goto_set
invoke-interface {v0, v1}, Landroidx/compose/runtime/MutableState;->setValue(Ljava/lang/Object;)V
return-void
.end method
.method private constructor <init>()V
.locals 0
@@ -271,97 +361,52 @@
if-eqz v2, :skip
sget v2, Lradiant/HomeBackdrop;->currentAlbumId:I
new-instance v3, Lcom/tidal/android/feature/playerscreen/ui/composables/n0;
invoke-direct {v3, v2, v1}, Lcom/tidal/android/feature/playerscreen/ui/composables/n0;-><init>(ILjava/lang/String;)V
sget-object v4, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion;
const/4 v5, 0x0
const/4 v6, 0x1
const/4 v7, 0x0
invoke-static {v4, v5, v6, v7}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
move-result-object v4
const/high16 v5, 0x42200000
invoke-static {v5}, Landroidx/compose/ui/unit/Dp;->constructor-impl(F)F
move-result v5
sget-object v6, Landroidx/compose/ui/draw/BlurredEdgeTreatment;->Companion:Landroidx/compose/ui/draw/BlurredEdgeTreatment$Companion;
invoke-virtual {v6}, Landroidx/compose/ui/draw/BlurredEdgeTreatment$Companion;->getRectangle---Goahg()Landroidx/compose/ui/graphics/Shape;
move-result-object v6
invoke-static {v4, v5, v6}, Landroidx/compose/ui/draw/BlurKt;->blur-F8QBwvs(Landroidx/compose/ui/Modifier;FLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier;
move-result-object v4
sget-object v5, Landroidx/compose/ui/layout/ContentScale;->Companion:Landroidx/compose/ui/layout/ContentScale$Companion;
invoke-virtual {v5}, Landroidx/compose/ui/layout/ContentScale$Companion;->getCrop()Landroidx/compose/ui/layout/ContentScale;
move-result-object v5
move-object/from16 v6, v3
const/4 v7, 0x0
move-object/from16 v8, v4
# Render TIDAL's NATIVE DarkBlurBackground (p3.a)
sget-object v8, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion;
const/4 v9, 0x0
move-object/from16 v10, v5
const/4 v10, 0x1
move-object/from16 v11, v1 # uuid as cache key
const/4 v11, 0x0
const/4 v12, 0x0
invoke-static {v8, v9, v10, v11}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
move-object/from16 v13, v0
move-result-object v13 # v13 = fillMaxSize modifier
const/4 v14, 0x0
sget v8, Lradiant/HomeBackdrop;->currentAlbumId:I # v8 = album id
const/16 v15, 0x48
move-object v9, v1 # v9 = cover uuid
invoke-static/range {v6 .. v15}, Lxd0/f;->a(Lyl0/l;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/ColorFilter;Landroidx/compose/ui/layout/ContentScale;Ljava/lang/Object;Lyl0/a;Landroidx/compose/runtime/Composer;II)V
# v10 = isPlaying, mirrored from the Player Backdrop variant
sget v10, Lradiant/HomeBackdrop;->mode:I
sget-object v3, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion;
const/4 v11, 0x2
const/4 v4, 0x0
if-ne v10, v11, :rl_mode_done
const/4 v5, 0x1
sget-object v10, Lradiant/HomeBackdrop;->isPlayingState:Landroidx/compose/runtime/MutableState;
const/4 v6, 0x0
invoke-interface {v10}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object;
invoke-static {v3, v4, v5, v6}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
move-result-object v10
move-result-object v3
check-cast v10, Ljava/lang/Boolean;
const v4, -0x80000000
invoke-virtual {v10}, Ljava/lang/Boolean;->booleanValue()Z
invoke-static {v4}, Landroidx/compose/ui/graphics/ColorKt;->Color(I)J
move-result v10
move-result-wide v4
:rl_mode_done
const/4 v11, 0x0 # v11 = isSeeking = false
invoke-static {}, Landroidx/compose/ui/graphics/RectangleShapeKt;->getRectangleShape()Landroidx/compose/ui/graphics/Shape;
const/4 v12, 0x0 # v12 = progress callback = null (unused while not seeking)
move-result-object v6
move-object v14, v0 # v14 = composer
invoke-static {v3, v4, v5, v6}, Landroidx/compose/foundation/BackgroundKt;->background-bw27NRU(Landroidx/compose/ui/Modifier;JLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier;
const/4 v15, 0x0 # v15 = changed flags
move-result-object v3
const/4 v4, 0x0
invoke-static {v3, v0, v4}, Landroidx/compose/foundation/layout/SpacerKt;->Spacer(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
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
:skip
invoke-interface {v0}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V
+61
View File
@@ -0,0 +1,61 @@
.class public final Lradiant/IsrcCache;
.super Ljava/lang/Object;
# Caches trackId(String) -> ISRC(String), captured from TIDAL's own track mapper
.field public static final map:Ljava/util/concurrent/ConcurrentHashMap;
.method static constructor <clinit>()V
.locals 1
new-instance v0, Ljava/util/concurrent/ConcurrentHashMap;
invoke-direct {v0}, Ljava/util/concurrent/ConcurrentHashMap;-><init>()V
sput-object v0, Lradiant/IsrcCache;->map:Ljava/util/concurrent/ConcurrentHashMap;
return-void
.end method
.method private constructor <init>()V
.locals 0
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public static put(Ljava/lang/String;Ljava/lang/String;)V
.locals 1
if-eqz p0, :ret
if-eqz p1, :ret
sget-object v0, Lradiant/IsrcCache;->map:Ljava/util/concurrent/ConcurrentHashMap;
invoke-virtual {v0, p0, p1}, Ljava/util/concurrent/ConcurrentHashMap;->put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
:ret
return-void
.end method
.method public static get(Ljava/lang/String;)Ljava/lang/String;
.locals 2
const/4 v0, 0x0
if-eqz p0, :none
sget-object v1, Lradiant/IsrcCache;->map:Ljava/util/concurrent/ConcurrentHashMap;
invoke-virtual {v1, p0}, Ljava/util/concurrent/ConcurrentHashMap;->get(Ljava/lang/Object;)Ljava/lang/Object;
move-result-object v0
check-cast v0, Ljava/lang/String;
:none
return-object v0
.end method
@@ -0,0 +1,27 @@
.class public final Lradiant/LyricsReinitGuard;
.super Ljava/lang/Object;
.source "LyricsReinitGuard.smali"
# static fields
# stuff that makes lyrics view stays open.. i forgot what it actually does other than short circuit a call or some shit <3
.field public static lastMediaId:I
.field public static lastVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
# direct methods
.method static constructor <clinit>()V
.locals 1
const/4 v0, -0x1
sput v0, Lradiant/LyricsReinitGuard;->lastMediaId:I
const/4 v0, 0x0
sput-object v0, Lradiant/LyricsReinitGuard;->lastVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
return-void
.end method
@@ -83,7 +83,7 @@
const/16 v7, 0x8
invoke-static/range {v0 .. v7}, Landroidx/compose/animation/SingleValueAnimationKt;->animateColorAsState-euL9pac(JLandroidx/compose/animation/core/AnimationSpec;Ljava/lang/String;Lyl0/l;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
invoke-static/range {v0 .. v7}, Landroidx/compose/animation/SingleValueAnimationKt;->animateColorAsState-euL9pac(JLandroidx/compose/animation/core/AnimationSpec;Ljava/lang/String;Lam0/l;Landroidx/compose/runtime/Composer;II)Landroidx/compose/runtime/State;
move-result-object v0
@@ -1,6 +1,6 @@
.class public final Lradiant/MiniPlayerGestures$FeedbackLayer;
.super Ljava/lang/Object;
.implements Lyl0/l;
.implements Lam0/l;
# annotations
@@ -1,6 +1,6 @@
.class public final Lradiant/MiniPlayerGestures$Gesture;
.super Ljava/lang/Object;
.implements Lyl0/l;
.implements Lam0/l;
# annotations
.annotation system Ldalvik/annotation/EnclosingClass;
@@ -14,7 +14,7 @@
# instance fields
.field public final a:Lyl0/l;
.field public final a:Lam0/l;
# Y at ACTION_DOWN
.field public b:F
@@ -43,12 +43,12 @@
# direct methods
.method public constructor <init>(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V
.method public constructor <init>(Lam0/l;Landroidx/compose/material3/SheetState;Z)V
.locals 0
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
iput-object p1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lyl0/l;
iput-object p1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lam0/l;
iput-object p2, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState;
@@ -90,9 +90,9 @@
iget-object v0, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState;
iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lyl0/l;
iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lam0/l;
invoke-static {v0, v1, p1}, Lradiant/MiniPlayerGestures;->finishDrag(Landroidx/compose/material3/SheetState;Lyl0/l;F)V
invoke-static {v0, v1, p1}, Lradiant/MiniPlayerGestures;->finishDrag(Landroidx/compose/material3/SheetState;Lam0/l;F)V
return-void
.end method
@@ -100,11 +100,11 @@
.method private openPlayer()V
.locals 2
iget-object v0, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lyl0/l;
iget-object v0, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lam0/l;
sget-object v1, Lcom/tidal/android/feature/appscaffold/ui/b$b;->a:Lcom/tidal/android/feature/appscaffold/ui/b$b;
invoke-interface {v0, v1}, Lyl0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
invoke-interface {v0, v1}, Lam0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
return-void
.end method
@@ -467,9 +467,9 @@
move-result v0
iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lyl0/l;
iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lam0/l;
invoke-static {v1, v0}, Lradiant/MiniPlayerGestures;->completeSimpleSwipe(Lyl0/l;F)Z
invoke-static {v1, v0}, Lradiant/MiniPlayerGestures;->completeSimpleSwipe(Lam0/l;F)Z
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
@@ -489,9 +489,9 @@
iget-object v0, p0, Lradiant/MiniPlayerGestures$Gesture;->f:Landroidx/compose/material3/SheetState;
iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lyl0/l;
iget-object v1, p0, Lradiant/MiniPlayerGestures$Gesture;->a:Lam0/l;
invoke-static {v0, v1}, Lradiant/MiniPlayerGestures;->cancelDrag(Landroidx/compose/material3/SheetState;Lyl0/l;)V
invoke-static {v0, v1}, Lradiant/MiniPlayerGestures;->cancelDrag(Landroidx/compose/material3/SheetState;Lam0/l;)V
goto :cancel_reset
@@ -1,6 +1,6 @@
.class public final Lradiant/MiniPlayerGestures$RootGesture;
.super Ljava/lang/Object;
.implements Lyl0/l;
.implements Lam0/l;
# annotations
@@ -15,18 +15,18 @@
# instance fields
.field public final a:Lyl0/l;
.field public final a:Lam0/l;
.field public final b:Landroidx/compose/material3/SheetState;
# direct methods
.method public constructor <init>(Lyl0/l;Landroidx/compose/material3/SheetState;)V
.method public constructor <init>(Lam0/l;Landroidx/compose/material3/SheetState;)V
.locals 0
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
iput-object p1, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lyl0/l;
iput-object p1, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lam0/l;
iput-object p2, p0, Lradiant/MiniPlayerGestures$RootGesture;->b:Landroidx/compose/material3/SheetState;
@@ -100,9 +100,9 @@
move-result v1
iget-object v2, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lyl0/l;
iget-object v2, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lam0/l;
invoke-static {v2, v1}, Lradiant/MiniPlayerGestures;->completeSimpleSwipe(Lyl0/l;F)Z
invoke-static {v2, v1}, Lradiant/MiniPlayerGestures;->completeSimpleSwipe(Lam0/l;F)Z
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
@@ -143,9 +143,9 @@
move-result v1
iget-object v2, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lyl0/l;
iget-object v2, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lam0/l;
invoke-static {v0, v2, v1}, Lradiant/MiniPlayerGestures;->finishDrag(Landroidx/compose/material3/SheetState;Lyl0/l;F)V
invoke-static {v0, v2, v1}, Lradiant/MiniPlayerGestures;->finishDrag(Landroidx/compose/material3/SheetState;Lam0/l;F)V
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
@@ -153,9 +153,9 @@
# ACTION_CANCEL
:cancel
iget-object v2, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lyl0/l;
iget-object v2, p0, Lradiant/MiniPlayerGestures$RootGesture;->a:Lam0/l;
invoke-static {v0, v2}, Lradiant/MiniPlayerGestures;->cancelDrag(Landroidx/compose/material3/SheetState;Lyl0/l;)V
invoke-static {v0, v2}, Lradiant/MiniPlayerGestures;->cancelDrag(Landroidx/compose/material3/SheetState;Lam0/l;)V
invoke-static {}, Lradiant/MiniPlayerGestures;->animateSwipeFeedbackReset()V
@@ -23,7 +23,7 @@
.field private static g:Landroidx/compose/material3/SheetState;
# Material3 settle lambda
.field private static h:Lyl0/l;
.field private static h:Lam0/l;
# Latest MotionEvent eventTime for drag updates
.field private static i:J
@@ -51,7 +51,7 @@
.field private static r:Z
# AppScaffold context
.field private static s:Lyl0/l;
.field private static s:Lam0/l;
.field private static t:Landroidx/compose/material3/SheetState;
@@ -321,7 +321,7 @@
sput-object v0, Lradiant/MiniPlayerGestures;->g:Landroidx/compose/material3/SheetState;
sput-object v0, Lradiant/MiniPlayerGestures;->h:Lyl0/l;
sput-object v0, Lradiant/MiniPlayerGestures;->h:Lam0/l;
sput v0, Lradiant/MiniPlayerGestures;->d:F
@@ -437,7 +437,7 @@
return-void
.end method
.method public static cancelDrag(Landroidx/compose/material3/SheetState;Lyl0/l;)V
.method public static cancelDrag(Landroidx/compose/material3/SheetState;Lam0/l;)V
.locals 1
invoke-static {p0}, Lradiant/MiniPlayerGestures;->isDragging(Landroidx/compose/material3/SheetState;)Z
@@ -450,13 +450,13 @@
sget-object p0, Lcom/tidal/android/feature/appscaffold/ui/b$a;->a:Lcom/tidal/android/feature/appscaffold/ui/b$a;
invoke-interface {p1, p0}, Lyl0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
invoke-interface {p1, p0}, Lam0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
:done
return-void
.end method
.method public static finishDrag(Landroidx/compose/material3/SheetState;Lyl0/l;F)V
.method public static finishDrag(Landroidx/compose/material3/SheetState;Lam0/l;F)V
.locals 6
invoke-static {p0}, Lradiant/MiniPlayerGestures;->isDragging(Landroidx/compose/material3/SheetState;)Z
@@ -469,7 +469,7 @@
if-ne v0, p0, :fallback_snap
sget-object v0, Lradiant/MiniPlayerGestures;->h:Lyl0/l;
sget-object v0, Lradiant/MiniPlayerGestures;->h:Lam0/l;
if-eqz v0, :fallback_snap
@@ -485,7 +485,7 @@
move-result-object p0
invoke-interface {v0, p0}, Lyl0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
invoke-interface {v0, p0}, Lam0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
goto/16 :done
@@ -589,7 +589,7 @@
sget-object p0, Lcom/tidal/android/feature/appscaffold/ui/b$a;->a:Lcom/tidal/android/feature/appscaffold/ui/b$a;
invoke-interface {p1, p0}, Lyl0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
invoke-interface {p1, p0}, Lam0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
:done
return-void
@@ -748,10 +748,10 @@
return-void
.end method
.method public static configure(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V
.method public static configure(Lam0/l;Landroidx/compose/material3/SheetState;Z)V
.locals 0
sput-object p0, Lradiant/MiniPlayerGestures;->s:Lyl0/l;
sput-object p0, Lradiant/MiniPlayerGestures;->s:Lam0/l;
sput-object p1, Lradiant/MiniPlayerGestures;->t:Landroidx/compose/material3/SheetState;
@@ -798,7 +798,7 @@
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;
invoke-static {p0, v0}, Landroidx/compose/ui/graphics/GraphicsLayerModifierKt;->graphicsLayer(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier;
move-result-object p0
@@ -848,14 +848,14 @@
return p0
.end method
.method public static modifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;Z)Landroidx/compose/ui/Modifier;
.method public static modifier(Landroidx/compose/ui/Modifier;Lam0/l;Landroidx/compose/material3/SheetState;Z)Landroidx/compose/ui/Modifier;
.locals 1
new-instance v0, Lradiant/MiniPlayerGestures$Gesture;
invoke-direct {v0, p1, p2, p3}, Lradiant/MiniPlayerGestures$Gesture;-><init>(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V
invoke-direct {v0, p1, p2, p3}, Lradiant/MiniPlayerGestures$Gesture;-><init>(Lam0/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;
invoke-static {p0, v0}, Landroidx/compose/ui/input/pointer/PointerInteropFilter_androidKt;->motionEventSpy(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier;
move-result-object p0
@@ -865,7 +865,7 @@
.method public static trackAreaModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
.locals 3
sget-object v0, Lradiant/MiniPlayerGestures;->s:Lyl0/l;
sget-object v0, Lradiant/MiniPlayerGestures;->s:Lam0/l;
if-eqz v0, :done
@@ -875,7 +875,7 @@
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;
invoke-static {p0, v0, v1, v2}, Lradiant/MiniPlayerGestures;->modifier(Landroidx/compose/ui/Modifier;Lam0/l;Landroidx/compose/material3/SheetState;Z)Landroidx/compose/ui/Modifier;
move-result-object p0
@@ -988,7 +988,7 @@
return-void
.end method
.method public static completeSimpleSwipe(Lyl0/l;F)Z
.method public static completeSimpleSwipe(Lam0/l;F)Z
.locals 4
sget-boolean v0, Lradiant/MiniPlayerGestures;->u:Z
@@ -1035,7 +1035,7 @@
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;
invoke-interface {p0, v0}, Lam0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
const/4 v0, 0x1
@@ -1307,26 +1307,26 @@
return p0
.end method
.method public static rootModifier(Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/material3/SheetState;)Landroidx/compose/ui/Modifier;
.method public static rootModifier(Landroidx/compose/ui/Modifier;Lam0/l;Landroidx/compose/material3/SheetState;)Landroidx/compose/ui/Modifier;
.locals 1
new-instance v0, Lradiant/MiniPlayerGestures$RootGesture;
invoke-direct {v0, p1, p2}, Lradiant/MiniPlayerGestures$RootGesture;-><init>(Lyl0/l;Landroidx/compose/material3/SheetState;)V
invoke-direct {v0, p1, p2}, Lradiant/MiniPlayerGestures$RootGesture;-><init>(Lam0/l;Landroidx/compose/material3/SheetState;)V
invoke-static {p0, v0}, Landroidx/compose/ui/input/pointer/PointerInteropFilter_androidKt;->motionEventSpy(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier;
invoke-static {p0, v0}, Landroidx/compose/ui/input/pointer/PointerInteropFilter_androidKt;->motionEventSpy(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier;
move-result-object p0
return-object p0
.end method
.method public static setSettleCallback(Landroidx/compose/material3/SheetState;Lyl0/l;)V
.method public static setSettleCallback(Landroidx/compose/material3/SheetState;Lam0/l;)V
.locals 0
sput-object p0, Lradiant/MiniPlayerGestures;->g:Landroidx/compose/material3/SheetState;
sput-object p1, Lradiant/MiniPlayerGestures;->h:Lyl0/l;
sput-object p1, Lradiant/MiniPlayerGestures;->h:Lam0/l;
return-void
.end method
@@ -1,6 +1,6 @@
.class public final Lradiant/MiniPlayerTrackGestures$Gesture;
.super Ljava/lang/Object;
.implements Lyl0/l;
.implements Lam0/l;
# annotations
@@ -15,16 +15,16 @@
# instance fields
.field public final a:Lyl0/l;
.field public final a:Lam0/l;
# direct methods
.method public constructor <init>(Lyl0/l;)V
.method public constructor <init>(Lam0/l;)V
.locals 0
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
iput-object p1, p0, Lradiant/MiniPlayerTrackGestures$Gesture;->a:Lyl0/l;
iput-object p1, p0, Lradiant/MiniPlayerTrackGestures$Gesture;->a:Lam0/l;
return-void
.end method
@@ -32,11 +32,11 @@
.method private nextTrack()V
.locals 2
iget-object v0, p0, Lradiant/MiniPlayerTrackGestures$Gesture;->a:Lyl0/l;
iget-object v0, p0, Lradiant/MiniPlayerTrackGestures$Gesture;->a:Lam0/l;
sget-object v1, Lcom/tidal/android/feature/appscaffold/ui/q$a;->a:Lcom/tidal/android/feature/appscaffold/ui/q$a; # Tidal's built-in next track mini-player event
sget-object v1, Lcom/tidal/android/feature/appscaffold/ui/r$a;->a:Lcom/tidal/android/feature/appscaffold/ui/r$a; # Tidal's built-in next track mini-player event
invoke-interface {v0, v1}, Lyl0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
invoke-interface {v0, v1}, Lam0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
return-void
.end method
@@ -44,11 +44,11 @@
.method private previousTrack()V
.locals 2
iget-object v0, p0, Lradiant/MiniPlayerTrackGestures$Gesture;->a:Lyl0/l;
iget-object v0, p0, Lradiant/MiniPlayerTrackGestures$Gesture;->a:Lam0/l;
sget-object v1, Lcom/tidal/android/feature/appscaffold/ui/q$c;->a:Lcom/tidal/android/feature/appscaffold/ui/q$c; # Our synthetic previous track event
sget-object v1, Lcom/tidal/android/feature/appscaffold/ui/r$c;->a:Lcom/tidal/android/feature/appscaffold/ui/r$c; # Our synthetic previous track event
invoke-interface {v0, v1}, Lyl0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
invoke-interface {v0, v1}, Lam0/l;->invoke(Ljava/lang/Object;)Ljava/lang/Object;
return-void
.end method
@@ -1,6 +1,6 @@
.class public final Lradiant/MiniPlayerTrackGestures$OffsetLayer;
.super Ljava/lang/Object;
.implements Lyl0/l;
.implements Lam0/l;
# annotations
@@ -1,6 +1,6 @@
.class public final Lradiant/MiniPlayerTrackGestures$TextDraw;
.super Ljava/lang/Object;
.implements Lyl0/l;
.implements Lam0/l;
# annotations
@@ -101,7 +101,13 @@
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0
invoke-static {v7, v8, v9}, Landroidx/compose/animation/i;->b(Landroidx/compose/ui/graphics/drawscope/DrawContext;J)V
invoke-interface {v7}, Landroidx/compose/ui/graphics/drawscope/DrawContext;->getCanvas()Landroidx/compose/ui/graphics/Canvas;
move-result-object v0
invoke-interface {v0}, Landroidx/compose/ui/graphics/Canvas;->restore()V
invoke-interface {v7, v8, v9}, Landroidx/compose/ui/graphics/drawscope/DrawContext;->setSize-uvyYCjk(J)V
sget-object p1, Lkotlin/u;->a:Lkotlin/u;
@@ -110,7 +116,13 @@
:catchall_0
move-exception v0
invoke-static {v7, v8, v9}, Landroidx/compose/animation/i;->b(Landroidx/compose/ui/graphics/drawscope/DrawContext;J)V
invoke-interface {v7}, Landroidx/compose/ui/graphics/drawscope/DrawContext;->getCanvas()Landroidx/compose/ui/graphics/Canvas;
move-result-object v1
invoke-interface {v1}, Landroidx/compose/ui/graphics/Canvas;->restore()V
invoke-interface {v7, v8, v9}, Landroidx/compose/ui/graphics/drawscope/DrawContext;->setSize-uvyYCjk(J)V
throw v0
.end method
@@ -419,7 +419,7 @@
sget-object v0, Lradiant/MiniPlayerTrackGestures$OffsetLayer;->INSTANCE:Lradiant/MiniPlayerTrackGestures$OffsetLayer;
invoke-static {p0, v0}, Landroidx/compose/ui/graphics/GraphicsLayerModifierKt;->graphicsLayer(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier;
invoke-static {p0, v0}, Landroidx/compose/ui/graphics/GraphicsLayerModifierKt;->graphicsLayer(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier;
move-result-object p0
@@ -431,7 +431,7 @@
sget-object v0, Lradiant/MiniPlayerTrackGestures$TextDraw;->INSTANCE:Lradiant/MiniPlayerTrackGestures$TextDraw; # text clip on right only
invoke-static {p0, v0}, Landroidx/compose/ui/draw/DrawModifierKt;->drawWithContent(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier;
invoke-static {p0, v0}, Landroidx/compose/ui/draw/DrawModifierKt;->drawWithContent(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier;
move-result-object p0
@@ -590,14 +590,14 @@
return-void
.end method
.method public static trackModifier(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier;
.method public static trackModifier(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier;
.locals 1
new-instance v0, Lradiant/MiniPlayerTrackGestures$Gesture;
invoke-direct {v0, p1}, Lradiant/MiniPlayerTrackGestures$Gesture;-><init>(Lyl0/l;)V
invoke-direct {v0, p1}, Lradiant/MiniPlayerTrackGestures$Gesture;-><init>(Lam0/l;)V
invoke-static {p0, v0}, Landroidx/compose/ui/input/pointer/PointerInteropFilter_androidKt;->motionEventSpy(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier;
invoke-static {p0, v0}, Landroidx/compose/ui/input/pointer/PointerInteropFilter_androidKt;->motionEventSpy(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier;
move-result-object p0
@@ -1,7 +1,7 @@
.class public final Lradiant/MiniSeekerFloating;
.super Ljava/lang/Object;
.implements Lyl0/l;
.implements Lam0/l;
# static fields
+13 -13
View File
@@ -5,7 +5,7 @@
# static fields
.field public static progressState:Landroidx/compose/runtime/MutableFloatState;
.field public static volatile vm:Ljh/h;
.field public static volatile vm:Lgh/j;
.field public static volatile sub:Lio/reactivex/disposables/Disposable;
@@ -57,7 +57,7 @@
:start_block
:try_start
sget-object v0, Lradiant/MiniSeekerLine;->vm:Ljh/h; # cached vm
sget-object v0, Lradiant/MiniSeekerLine;->vm:Lgh/j; # cached vm
if-nez v0, :got_vm # reuse if present
@@ -65,32 +65,32 @@
move-result-object v0 # app
invoke-virtual {v0}, Lcom/aspiro/wamp/App;->e()Lf5/c; # dagger component
invoke-virtual {v0}, Lcom/aspiro/wamp/App;->e()Le5/c; # dagger component
move-result-object v0 # component
check-cast v0, Lf5/d0$n2; # narrow type
check-cast v0, Le5/z$n2; # narrow type
iget-object v0, v0, Lf5/d0$n2;->z0:Ldagger/internal/j; # playqueue provider
iget-object v0, v0, Le5/z$n2;->z0:Ldagger/internal/j; # playqueue provider
invoke-interface {v0}, Lol0/a;->get()Ljava/lang/Object; # resolve
invoke-interface {v0}, Lql0/a;->get()Ljava/lang/Object; # resolve
move-result-object v0 # playqueue
check-cast v0, Lcom/aspiro/wamp/playqueue/z0; # narrow type
check-cast v0, Lcom/aspiro/wamp/playqueue/d1; # narrow type
new-instance v1, Ljh/h; # build vm
new-instance v1, Lgh/j; # build vm
invoke-direct {v1, v0}, Ljh/h;-><init>(Lcom/aspiro/wamp/playqueue/z0;)V # ctor
invoke-direct {v1, v0}, Lgh/j;-><init>(Lcom/aspiro/wamp/playqueue/d1;)V # ctor
sput-object v1, Lradiant/MiniSeekerLine;->vm:Ljh/h; # cache
sput-object v1, Lradiant/MiniSeekerLine;->vm:Lgh/j; # cache
:got_vm
sget-object v0, Lradiant/MiniSeekerLine;->vm:Ljh/h; # vm ref
sget-object v0, Lradiant/MiniSeekerLine;->vm:Lgh/j; # vm ref
invoke-virtual {v0}, Ljh/h;->a()V # activate emission
invoke-virtual {v0}, Lgh/j;->a()V # activate emission
iget-object v0, v0, Ljh/h;->d:Lio/reactivex/subjects/BehaviorSubject; # position subject
iget-object v0, v0, Lgh/j;->d:Lio/reactivex/subjects/BehaviorSubject; # position subject
invoke-static {}, Lio/reactivex/android/schedulers/AndroidSchedulers;->mainThread()Lio/reactivex/Scheduler; # main scheduler
+1 -1
View File
@@ -1,6 +1,6 @@
.class public final Lradiant/NoOp;
.super Ljava/lang/Object;
.implements Lyl0/a;
.implements Lam0/a;
# static fields
@@ -0,0 +1,9 @@
.class public final Lradiant/PlayingFrom;
.super Ljava/lang/Object;
.source "PlayingFrom.smali"
# static fields
# puts the "Playing from" source above track title
.field public static a:Ljava/lang/String;
+6 -6
View File
@@ -85,15 +85,15 @@
return-object p0
.end method
.method public static style(ILn20/e2;)Ln20/e2;
.method public static style(ILq20/c2;)Lq20/c2;
.registers 16
invoke-static {p0}, Lradiant/QualityBadge;->textArgb(I)I
move-result v0
new-instance v1, Lc20/a;
invoke-direct {v1, v0}, Lc20/a;-><init>(I)V
new-instance v0, Lc20/d;
new-instance v1, Lf20/a;
invoke-direct {v1, v0}, Lf20/a;-><init>(I)V
new-instance v0, Lf20/d;
const/4 v2, 0x0
const/4 v3, 0x0
const/4 v4, 0x0
@@ -107,7 +107,7 @@
const/4 v12, 0x0
const/16 v13, 0xffe
const/4 v14, 0x0
invoke-direct/range {v0 .. v14}, Lc20/d;-><init>(Lc20/a;Lc20/a;Lc20/a;Lc20/a;Lc20/a;Lc20/a;Lc20/a;Lc20/a;Lc20/a;Lc20/a;Lc20/a;Lc20/a;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
invoke-direct/range {v0 .. v14}, Lf20/d;-><init>(Lf20/a;Lf20/a;Lf20/a;Lf20/a;Lf20/a;Lf20/a;Lf20/a;Lf20/a;Lf20/a;Lf20/a;Lf20/a;Lf20/a;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
move-object v9, v0
move-object/from16 v0, p1
@@ -118,7 +118,7 @@
const/4 v5, 0x0
const/16 v6, 0x1d
const/4 v7, 0x0
invoke-static/range {v0 .. v7}, Ln20/e2;->g(Ln20/e2;Ln20/u4;Lc20/d;Lcom/squareup/ui/market/core/text/MarketTextAlignment;Lcom/squareup/ui/market/core/text/MarketTextTransform;Ln20/t4;ILjava/lang/Object;)Ln20/e2;
invoke-static/range {v0 .. v7}, Lq20/c2;->g(Lq20/c2;Lq20/s4;Lf20/d;Lcom/squareup/ui/market/core/text/MarketTextAlignment;Lcom/squareup/ui/market/core/text/MarketTextTransform;Lq20/r4;ILjava/lang/Object;)Lq20/c2;
move-result-object p0
return-object p0
.end method
+145 -23
View File
@@ -5,8 +5,12 @@
# static fields
.field public static volatile currentKey:Ljava/lang/String;
.field public static volatile currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
.field public static volatile isRlState:Z
.field public static volatile keepOpen:Z
# direct methods
.method static constructor <clinit>()V
@@ -16,8 +20,12 @@
sput-object v0, Lradiant/RLAPILyricsHook;->currentKey:Ljava/lang/String;
sput-object v0, Lradiant/RLAPILyricsHook;->currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
sput-boolean v0, Lradiant/RLAPILyricsHook;->isRlState:Z
sput-boolean v0, Lradiant/RLAPILyricsHook;->keepOpen:Z
return-void
.end method
@@ -60,15 +68,50 @@
return v1
.end method
.method public static isOwner(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;)Z
.locals 2
sget-object v0, Lradiant/RLAPILyricsHook;->currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
if-ne p0, v0, :not_owner
sget-boolean v1, Lradiant/RLAPILyricsHook;->isRlState:Z
return v1
:not_owner
const/4 v1, 0x0
return v1
.end method
.method public static shouldKeepOpen(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;)Z
.locals 2
sget-object v0, Lradiant/RLAPILyricsHook;->currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
if-ne p0, v0, :do_not_keep
sget-boolean v1, Lradiant/RLAPILyricsHook;->keepOpen:Z
if-nez v1, :keep
sget-boolean v1, Lradiant/RLAPILyricsHook;->isRlState:Z
:keep
return v1
:do_not_keep
const/4 v1, 0x0
return v1
.end method
.method public static onWampTrack(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;Lcom/aspiro/wamp/model/Track;)V
.locals 11
invoke-static {p1}, Lradiant/HomeBackdrop;->onTrack(Lcom/aspiro/wamp/model/Track;)V
const/4 v3, 0x0
sput-boolean v3, Lradiant/RLAPILyricsHook;->isRlState:Z
const-string v3, "onWampTrack: hook entered"
invoke-static {v3}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
@@ -84,7 +127,7 @@
invoke-static {v3}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
return-void
goto :invalid_track
:have_track
invoke-virtual {p1}, Lcom/aspiro/wamp/model/MediaItem;->getTitle()Ljava/lang/String;
@@ -97,7 +140,7 @@
invoke-static {v3}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
return-void
goto :invalid_track
:title_present
invoke-static {v1}, Lradiant/RLAPILyricsHook;->isBlank(Ljava/lang/String;)Z
@@ -110,20 +153,34 @@
invoke-static {v3}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
return-void
goto :invalid_track
:title_ok
# match desktop: primary artist name (artist?.name), fall back to the joined list
invoke-virtual {p1}, Lcom/aspiro/wamp/model/MediaItem;->getArtist()Lcom/aspiro/wamp/model/Artist;
move-result-object v3
if-eqz v3, :use_artist_names
invoke-virtual {v3}, Lcom/aspiro/wamp/model/Artist;->getName()Ljava/lang/String;
move-result-object v2
if-nez v2, :artist_present
:use_artist_names
invoke-virtual {p1}, Lcom/aspiro/wamp/model/MediaItem;->getArtistNames()Ljava/lang/String;
move-result-object v2
if-nez v2, :artist_present
const-string v3, "bail: getArtistNames() returned null"
const-string v3, "bail: artist name null"
invoke-static {v3}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
return-void
goto :invalid_track
:artist_present
invoke-static {v2}, Lradiant/RLAPILyricsHook;->isBlank(Ljava/lang/String;)Z
@@ -136,29 +193,81 @@
invoke-static {v3}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
return-void
goto :invalid_track
:artist_ok
const-string v3, ""
invoke-virtual {p1}, Lcom/aspiro/wamp/model/MediaItem;->getId()I
new-instance v4, Ljava/lang/StringBuilder;
move-result v3
invoke-direct {v4}, Ljava/lang/StringBuilder;-><init>()V
invoke-virtual {v4, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
const-string v5, "|"
invoke-virtual {v4, v5}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v4, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v4}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
invoke-static {v3}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v4
sget-object v5, Lradiant/RLAPILyricsHook;->currentKey:Ljava/lang/String;
invoke-virtual {v4, v5}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v5
if-eqz v5, :rl_new_track
sget-object v5, Lradiant/RLAPILyricsHook;->currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
if-ne p0, v5, :rl_new_track
const-string v5, "onWampTrack: same track re-fired, skipping duplicate fetch"
invoke-static {v5}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
return-void
:rl_new_track
iget-object v5, p0, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->P:Lkotlinx/coroutines/flow/MutableStateFlow;
invoke-interface {v5}, Lkotlinx/coroutines/flow/MutableStateFlow;->getValue()Ljava/lang/Object;
move-result-object v5
check-cast v5, Ljava/lang/Boolean;
invoke-virtual {v5}, Ljava/lang/Boolean;->booleanValue()Z
move-result v5
if-nez v5, :store_keep_open
sget-object v6, Lradiant/RLAPILyricsHook;->currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
if-eqz v6, :store_keep_open
if-eq p0, v6, :store_keep_open
iget-object v7, v6, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->P:Lkotlinx/coroutines/flow/MutableStateFlow;
invoke-interface {v7}, Lkotlinx/coroutines/flow/MutableStateFlow;->getValue()Ljava/lang/Object;
move-result-object v7
check-cast v7, Ljava/lang/Boolean;
invoke-virtual {v7}, Ljava/lang/Boolean;->booleanValue()Z
move-result v5
:store_keep_open
sput-boolean v5, Lradiant/RLAPILyricsHook;->keepOpen:Z
const/4 v5, 0x0
sput-boolean v5, Lradiant/RLAPILyricsHook;->isRlState:Z
sput-object v4, Lradiant/RLAPILyricsHook;->currentKey:Ljava/lang/String;
sput-object p0, Lradiant/RLAPILyricsHook;->currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
move-object v3, v4
new-instance v5, Ljava/lang/StringBuilder;
const-string v6, "onWampTrack: fetching for title='"
@@ -207,6 +316,19 @@
invoke-virtual {v6}, Ljava/lang/Thread;->start()V
goto :done
:invalid_track
const/4 v3, 0x0
sput-boolean v3, Lradiant/RLAPILyricsHook;->isRlState:Z
sput-boolean v3, Lradiant/RLAPILyricsHook;->keepOpen:Z
sput-object v3, Lradiant/RLAPILyricsHook;->currentKey:Ljava/lang/String;
sput-object p0, Lradiant/RLAPILyricsHook;->currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
:done
return-void
.end method
+377 -36
View File
@@ -14,6 +14,8 @@
.field public final lyricsId:Ljava/lang/String;
.field public static volatile clientIp:Ljava/lang/String;
# direct methods
.method public constructor <init>(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
@@ -34,6 +36,181 @@
return-void
.end method
.method private failCurrent()V
.locals 4
invoke-direct {p0}, Lradiant/RLAPILyricsWorker;->isCurrent()Z
move-result v0
if-eqz v0, :done
invoke-static {}, Lradiant/WordLyrics;->clear()V
const/4 v0, 0x0
sput-object v0, Lradiant/RLAPILyricsHook;->currentKey:Ljava/lang/String;
sput-boolean v0, Lradiant/RLAPILyricsHook;->isRlState:Z
sget-boolean v0, Lradiant/StickyLyrics;->enabled:Z
if-nez v0, :done
sget-boolean v0, Lradiant/RLAPILyricsHook;->keepOpen:Z
if-nez v0, :done
iget-object v1, p0, Lradiant/RLAPILyricsWorker;->vm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
iget-object v2, v1, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->P:Lkotlinx/coroutines/flow/MutableStateFlow;
sget-object v3, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;
invoke-interface {v2, v3}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
:done
return-void
.end method
.method private isCurrent()Z
.locals 4
iget-object v0, p0, Lradiant/RLAPILyricsWorker;->vm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
sget-object v1, Lradiant/RLAPILyricsHook;->currentVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
if-ne v0, v1, :not_current
iget-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->a:Lbi/e;
invoke-interface {v1}, Lbi/e;->getCurrentItem()Lcom/aspiro/wamp/playqueue/u0;
move-result-object v1
if-eqz v1, :not_current
invoke-interface {v1}, Lcom/aspiro/wamp/playqueue/u0;->getMediaItem()Lcom/aspiro/wamp/model/MediaItem;
move-result-object v1
if-eqz v1, :not_current
invoke-virtual {v1}, Lcom/aspiro/wamp/model/MediaItem;->getId()I
move-result v2
invoke-static {v2}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
move-result-object v1
iget-object v2, p0, Lradiant/RLAPILyricsWorker;->key:Ljava/lang/String;
invoke-virtual {v2, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v3
return v3
:not_current
const/4 v3, 0x0
return v3
.end method
# Public client IP (needed for debugging with ratelimits)
.method static clientIp()Ljava/lang/String;
.locals 6
sget-object v0, Lradiant/RLAPILyricsWorker;->clientIp:Ljava/lang/String;
if-eqz v0, :fetch
return-object v0
:fetch
:try_start
new-instance v0, Ljava/net/URL;
const-string v1, "https://api.ipify.org?format=text"
invoke-direct {v0, v1}, Ljava/net/URL;-><init>(Ljava/lang/String;)V
invoke-virtual {v0}, Ljava/net/URL;->openConnection()Ljava/net/URLConnection;
move-result-object v0
check-cast v0, Ljava/net/HttpURLConnection;
const/16 v1, 0x5dc
invoke-virtual {v0, v1}, Ljava/net/URLConnection;->setConnectTimeout(I)V
invoke-virtual {v0, v1}, Ljava/net/URLConnection;->setReadTimeout(I)V
invoke-virtual {v0}, Ljava/net/HttpURLConnection;->getResponseCode()I
move-result v1
const/16 v2, 0xc8
if-eq v1, v2, :ok
invoke-virtual {v0}, Ljava/net/HttpURLConnection;->disconnect()V
goto :fail
:ok
invoke-virtual {v0}, Ljava/net/HttpURLConnection;->getInputStream()Ljava/io/InputStream;
move-result-object v1
new-instance v2, Ljava/io/InputStreamReader;
const-string v3, "UTF-8"
invoke-direct {v2, v1, v3}, Ljava/io/InputStreamReader;-><init>(Ljava/io/InputStream;Ljava/lang/String;)V
new-instance v3, Ljava/io/BufferedReader;
invoke-direct {v3, v2}, Ljava/io/BufferedReader;-><init>(Ljava/io/Reader;)V
invoke-virtual {v3}, Ljava/io/BufferedReader;->readLine()Ljava/lang/String;
move-result-object v4
invoke-virtual {v3}, Ljava/io/BufferedReader;->close()V
invoke-virtual {v0}, Ljava/net/HttpURLConnection;->disconnect()V
if-eqz v4, :fail
invoke-virtual {v4}, Ljava/lang/String;->trim()Ljava/lang/String;
move-result-object v4
invoke-virtual {v4}, Ljava/lang/String;->isEmpty()Z
move-result v5
if-nez v5, :fail
sput-object v4, Lradiant/RLAPILyricsWorker;->clientIp:Ljava/lang/String;
return-object v4
:try_end
.catchall {:try_start .. :try_end} :catch_all
:catch_all
move-exception v0
:fail
const-string v0, "null"
return-object v0
.end method
.method public static fetch(Ljava/lang/String;Z)Ljava/lang/String;
.locals 7
@@ -56,6 +233,8 @@
invoke-virtual {v0, v1}, Ljava/net/URLConnection;->setConnectTimeout(I)V
const v1, 0xafc8
invoke-virtual {v0, v1}, Ljava/net/URLConnection;->setReadTimeout(I)V
if-eqz p1, :no_auth
@@ -74,7 +253,9 @@
const-string v1, "x-client-ip"
const-string v2, "null"
invoke-static {}, Lradiant/RLAPILyricsWorker;->clientIp()Ljava/lang/String;
move-result-object v2
invoke-virtual {v0, v1, v2}, Ljava/net/URLConnection;->setRequestProperty(Ljava/lang/String;Ljava/lang/String;)V
@@ -313,20 +494,168 @@
return-object v1
.end method
# Returns "&isrc=<enc>" for the current track
.method private isrcParam()Ljava/lang/String;
.locals 6
iget-object v0, p0, Lradiant/RLAPILyricsWorker;->key:Ljava/lang/String;
const/4 v1, 0x0
:loop
invoke-static {v0}, Lradiant/IsrcCache;->get(Ljava/lang/String;)Ljava/lang/String;
move-result-object v2
if-eqz v2, :retry
invoke-virtual {v2}, Ljava/lang/String;->trim()Ljava/lang/String;
move-result-object v2
invoke-virtual {v2}, Ljava/lang/String;->isEmpty()Z
move-result v3
if-nez v3, :retry
:try_enc_start
invoke-static {v2}, Lradiant/RLAPILyricsWorker;->uric(Ljava/lang/String;)Ljava/lang/String;
move-result-object v2
:try_enc_end
.catchall {:try_enc_start .. :try_enc_end} :enc_fail
:enc_done
new-instance v3, Ljava/lang/StringBuilder;
const-string v4, "&isrc="
invoke-direct {v3, v4}, Ljava/lang/StringBuilder;-><init>(Ljava/lang/String;)V
invoke-virtual {v3, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v3}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v2
return-object v2
:enc_fail
move-exception v3
goto :enc_done
:retry
# keep waiting for TIDAL's mapper to cache the ISRC while this track is still current
invoke-direct {p0}, Lradiant/RLAPILyricsWorker;->isCurrent()Z
move-result v3
if-eqz v3, :giveup
const/16 v3, 0x28
if-ge v1, v3, :giveup
:try_sleep_start
const-wide/16 v3, 0x64
invoke-static {v3, v4}, Ljava/lang/Thread;->sleep(J)V
:try_sleep_end
.catchall {:try_sleep_start .. :try_sleep_end} :sleep_catch
:sleep_done
add-int/lit8 v1, v1, 0x1
goto :loop
:sleep_catch
move-exception v3
goto :sleep_done
:giveup
const-string v0, ""
return-object v0
.end method
# URL-encode like JS encodeURIComponent (so requests are byte identical to the desktop plugin)
.method static uric(Ljava/lang/String;)Ljava/lang/String;
.locals 3
const-string v0, "UTF-8"
invoke-static {p0, v0}, Ljava/net/URLEncoder;->encode(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
move-result-object v0
const-string v1, "+"
const-string v2, "%20"
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object v0
const-string v1, "%21"
const-string v2, "!"
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object v0
const-string v1, "%27"
const-string v2, "\'"
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object v0
const-string v1, "%28"
const-string v2, "("
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object v0
const-string v1, "%29"
const-string v2, ")"
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object v0
const-string v1, "%7E"
const-string v2, "~"
invoke-virtual {v0, v1, v2}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object v0
return-object v0
.end method
.method private runImpl()V
.locals 11
.locals 13
iget-object v0, p0, Lradiant/RLAPILyricsWorker;->title:Ljava/lang/String;
const-string v1, "UTF-8"
invoke-static {v0, v1}, Ljava/net/URLEncoder;->encode(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
invoke-static {v0}, Lradiant/RLAPILyricsWorker;->uric(Ljava/lang/String;)Ljava/lang/String;
move-result-object v0
iget-object v2, p0, Lradiant/RLAPILyricsWorker;->artist:Ljava/lang/String;
invoke-static {v2, v1}, Ljava/net/URLEncoder;->encode(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
invoke-static {v2}, Lradiant/RLAPILyricsWorker;->uric(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
@@ -344,6 +673,12 @@
invoke-virtual {v2, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-direct {p0}, Lradiant/RLAPILyricsWorker;->isrcParam()Ljava/lang/String;
move-result-object v0
invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
const-string v0, "&platform=rl-mobile"
invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
@@ -396,22 +731,11 @@
invoke-static {v4}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
sget-boolean v4, Lradiant/StickyLyrics;->enabled:Z
if-nez v4, :no_close
iget-object v4, p0, Lradiant/RLAPILyricsWorker;->vm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
iget-object v5, v4, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->N:Lkotlinx/coroutines/flow/MutableStateFlow;
sget-object v6, Ljava/lang/Boolean;->FALSE:Ljava/lang/Boolean;
invoke-interface {v5, v6}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
:no_close
return-void
goto :request_failed
:got_body
move-object v11, v3
invoke-static {v3}, Lradiant/RLAPILyricsWorker;->parseLines(Ljava/lang/String;)Ljava/util/ArrayList;
move-result-object v3
@@ -422,7 +746,7 @@
invoke-static {v4}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
return-void
goto :request_failed
:parse_ok
invoke-virtual {v3}, Ljava/util/ArrayList;->size()I
@@ -435,7 +759,7 @@
invoke-static {v5}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
return-void
goto :request_failed
:nonempty
new-instance v5, Ljava/lang/StringBuilder;
@@ -456,11 +780,7 @@
invoke-static {v5}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
iget-object v4, p0, Lradiant/RLAPILyricsWorker;->key:Ljava/lang/String;
sget-object v5, Lradiant/RLAPILyricsHook;->currentKey:Ljava/lang/String;
invoke-virtual {v4, v5}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
invoke-direct {p0}, Lradiant/RLAPILyricsWorker;->isCurrent()Z
move-result v4
@@ -473,11 +793,13 @@
return-void
:key_ok
invoke-static {v11}, Lradiant/WordLyrics;->ingest(Ljava/lang/String;)V
iget-object v4, p0, Lradiant/RLAPILyricsWorker;->vm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
iget-object v5, v4, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->M:Lkotlinx/coroutines/flow/MutableStateFlow;
iget-object v5, v4, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->O:Lkotlinx/coroutines/flow/MutableStateFlow;
invoke-static {v3}, Ltn0/a;->c(Ljava/lang/Iterable;)Ltn0/b;
invoke-static {v3}, Lvn0/a;->c(Ljava/lang/Iterable;)Lvn0/b;
move-result-object v6
@@ -494,41 +816,52 @@
const/4 v10, 0x0
invoke-direct {v8, v7, v6, v9, v10}, Lcom/tidal/android/feature/playerscreen/ui/g$c;-><init>(Ljava/lang/String;Ltn0/b;IZ)V
invoke-direct {v8, v7, v6, v9, v10}, Lcom/tidal/android/feature/playerscreen/ui/g$c;-><init>(Ljava/lang/String;Lvn0/b;IZ)V
const-string v6, "publishing g$c -> J=true N=true M=g$c"
const-string v6, "publishing g$c -> K=true (O=true if sticky) N=g$c"
invoke-static {v6}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
const/4 v6, 0x1
invoke-interface {v5, v8}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
sput-boolean v6, Lradiant/RLAPILyricsHook;->isRlState:Z
iget-object v6, v4, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->J:Lkotlinx/coroutines/flow/MutableStateFlow;
iget-object v6, v4, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->K:Lkotlinx/coroutines/flow/MutableStateFlow;
sget-object v7, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean;
invoke-interface {v6, v7}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
sget-boolean v9, Lradiant/RLAPILyricsHook;->keepOpen:Z
if-nez v9, :open_lyrics
sget-boolean v9, Lradiant/StickyLyrics;->enabled:Z
if-eqz v9, :skip_n
iget-object v6, v4, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->N:Lkotlinx/coroutines/flow/MutableStateFlow;
:open_lyrics
iget-object v6, v4, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->P:Lkotlinx/coroutines/flow/MutableStateFlow;
invoke-interface {v6, v7}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
:skip_n
invoke-interface {v5, v8}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
:done
return-void
:request_failed
invoke-direct {p0}, Lradiant/RLAPILyricsWorker;->failCurrent()V
return-void
.end method
# virtual methods
.method public run()V
.locals 1
.locals 2
:try_start
invoke-direct {p0}, Lradiant/RLAPILyricsWorker;->runImpl()V
@@ -541,5 +874,13 @@
:catch_all
move-exception v0
invoke-virtual {v0}, Ljava/lang/Throwable;->toString()Ljava/lang/String;
move-result-object v1
invoke-static {v1}, Lradiant/RLAPILyricsHook;->dlog(Ljava/lang/String;)V
invoke-direct {p0}, Lradiant/RLAPILyricsWorker;->failCurrent()V
return-void
.end method
@@ -20,13 +20,13 @@
if-eqz p1, :ret # null guard
instance-of v0, p1, Ljh/b; # type guard
instance-of v0, p1, Lgh/b; # type guard
if-eqz v0, :ret # skip if wrong type
check-cast p1, Ljh/b; # narrow type
check-cast p1, Lgh/b; # narrow type
iget v0, p1, Ljh/b;->b:F # raw progress
iget v0, p1, Lgh/b;->b:F # raw progress
invoke-static {v0}, Ljava/lang/Float;->isNaN(F)Z # nan check
@@ -4,7 +4,7 @@
# direct methods
.method public static final a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
.method public static final a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lam0/a;)V
.locals 21
.annotation build Landroidx/compose/runtime/Composable;
.end annotation
@@ -98,7 +98,7 @@
const/4 v4, 0x6
invoke-static {v2, v11, v4}, Lcom/squareup/ui/market/core/theme/x;->t(Lcom/squareup/ui/market/core/theme/k$a;Landroidx/compose/runtime/Composer;I)Lcom/squareup/ui/market/core/theme/MarketStylesheet;
invoke-static {v2, v11, v4}, Lcom/squareup/ui/market/core/theme/z;->t(Lcom/squareup/ui/market/core/theme/k$a;Landroidx/compose/runtime/Composer;I)Lcom/squareup/ui/market/core/theme/MarketStylesheet;
move-result-object v15
@@ -131,7 +131,7 @@
const/16 v18, 0x0
invoke-static/range {v15 .. v20}, Lcom/squareup/ui/market/components/MarketIconButtonKt;->P(Lcom/squareup/ui/market/core/theme/MarketStylesheet;Lcom/squareup/ui/market/core/components/properties/IconButton$Size;Lcom/squareup/ui/market/core/components/properties/IconButton$Rank;Lcom/squareup/ui/market/core/components/properties/IconButton$Variant;ILjava/lang/Object;)Ln20/w1;
invoke-static/range {v15 .. v20}, Lcom/squareup/ui/market/components/MarketIconButtonKt;->P(Lcom/squareup/ui/market/core/theme/MarketStylesheet;Lcom/squareup/ui/market/core/components/properties/IconButton$Size;Lcom/squareup/ui/market/core/components/properties/IconButton$Rank;Lcom/squareup/ui/market/core/components/properties/IconButton$Variant;ILjava/lang/Object;)Lq20/u1;
move-result-object v4
@@ -140,7 +140,7 @@
:cond_5
move-object v9, v4
check-cast v9, Ln20/w1;
check-cast v9, Lq20/u1;
sget v2, Lcom/tidal/android/feature/playerscreen/ui/R$string;->lyrics:I
@@ -172,7 +172,7 @@
const/4 v8, 0x0
invoke-static/range {v1 .. v13}, Lcom/squareup/ui/market/components/MarketIconButtonKt;->c(Lyl0/a;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;ZLcom/squareup/ui/market/components/n;Lyl0/a;Ljava/lang/String;Ln20/w1;Lyl0/p;Landroidx/compose/runtime/Composer;II)V
invoke-static/range {v1 .. v13}, Lcom/squareup/ui/market/components/MarketIconButtonKt;->b(Lam0/a;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/interaction/MutableInteractionSource;ZLcom/squareup/ui/market/components/n;Lam0/a;Ljava/lang/String;Lq20/u1;Lam0/p;Landroidx/compose/runtime/Composer;II)V
invoke-static {}, Landroidx/compose/runtime/ComposerKt;->isTraceInProgress()Z
@@ -3,7 +3,7 @@
.source "SourceFile"
# interfaces
.implements Lyl0/p;
.implements Lam0/p;
# virtual methods
@@ -35,7 +35,7 @@
invoke-static {v0, p2, v1, v2}, Landroidx/compose/runtime/ComposerKt;->traceEventStart(IIILjava/lang/String;)V
:cond_0
const p2, 0x7f08051d
const p2, 0x7f080522
const/4 v0, 0x0
+1 -1
View File
@@ -1,6 +1,6 @@
.class public final Lradiant/SpvFactory;
.super Ljava/lang/Object;
.implements Lyl0/l;
.implements Lam0/l;
# static fields
@@ -0,0 +1,87 @@
.class public final Lradiant/WazeInitReceiver;
.super Landroid/content/BroadcastReceiver;
.source "WazeInitReceiver.smali"
# direct methods
.method public constructor <init>()V
.locals 0
invoke-direct {p0}, Landroid/content/BroadcastReceiver;-><init>()V
return-void
.end method
# virtual methods
.method public onReceive(Landroid/content/Context;Landroid/content/Intent;)V
.locals 5
if-eqz p1, :return
if-eqz p2, :return
const-string v0, "com.waze.sdk.audio.ACTION_INIT"
invoke-virtual {p2}, Landroid/content/Intent;->getAction()Ljava/lang/String;
move-result-object v1
invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object;)Z
move-result v0
if-eqz v0, :return
const-string v0, "token"
invoke-virtual {p2, v0}, Landroid/content/Intent;->getStringExtra(Ljava/lang/String;)Ljava/lang/String;
move-result-object v0
if-eqz v0, :return
invoke-virtual {v0}, Ljava/lang/String;->length()I
move-result v1
if-lez v1, :return
invoke-virtual {p1}, Landroid/content/Context;->getApplicationContext()Landroid/content/Context;
move-result-object v1
if-eqz v1, :context_ready
move-object p1, v1
:context_ready
new-instance v1, Landroid/content/Intent;
invoke-direct {v1}, Landroid/content/Intent;-><init>()V
const-string v2, "com.waze"
const-string v3, "com.waze.sdk.SdkService"
invoke-virtual {v1, v2, v3}, Landroid/content/Intent;->setClassName(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;
new-instance v2, Lradiant/WazeServiceConnection;
invoke-direct {v2, p1, v0}, Lradiant/WazeServiceConnection;-><init>(Landroid/content/Context;Ljava/lang/String;)V
:try_start_0
const/4 v3, 0x1
invoke-virtual {p1, v1, v2, v3}, Landroid/content/Context;->bindService(Landroid/content/Intent;Landroid/content/ServiceConnection;I)Z
:try_end_0
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
goto :return
:catch_0
move-exception v4
:return
return-void
.end method
@@ -0,0 +1,228 @@
.class public final Lradiant/WazeServiceConnection;
.super Ljava/lang/Object;
.source "WazeServiceConnection.smali"
# interfaces
.implements Landroid/content/ServiceConnection;
# instance fields
.field private final context:Landroid/content/Context;
.field private final token:Ljava/lang/String;
# direct methods
.method public constructor <init>(Landroid/content/Context;Ljava/lang/String;)V
.locals 0
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
iput-object p1, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
iput-object p2, p0, Lradiant/WazeServiceConnection;->token:Ljava/lang/String;
return-void
.end method
.method private addOpenMeIntent(Landroid/os/Bundle;)V
.locals 4
iget-object v0, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
invoke-virtual {v0}, Landroid/content/Context;->getPackageManager()Landroid/content/pm/PackageManager;
move-result-object v1
invoke-virtual {v0}, Landroid/content/Context;->getPackageName()Ljava/lang/String;
move-result-object v2
invoke-virtual {v1, v2}, Landroid/content/pm/PackageManager;->getLaunchIntentForPackage(Ljava/lang/String;)Landroid/content/Intent;
move-result-object v1
if-eqz v1, :return
const/high16 v2, 0x10000000
invoke-virtual {v1, v2}, Landroid/content/Intent;->addFlags(I)Landroid/content/Intent;
const v2, 0xc000000
const/4 v3, 0x0
invoke-static {v0, v3, v1, v2}, Landroid/app/PendingIntent;->getActivity(Landroid/content/Context;ILandroid/content/Intent;I)Landroid/app/PendingIntent;
move-result-object v1
const-string v2, "openMeIntent"
invoke-virtual {p1, v2, v1}, Landroid/os/Bundle;->putParcelable(Ljava/lang/String;Landroid/os/Parcelable;)V
:return
return-void
.end method
.method private createClientMessenger()Landroid/os/Messenger;
.locals 3
new-instance v0, Landroid/os/Handler;
invoke-static {}, Landroid/os/Looper;->getMainLooper()Landroid/os/Looper;
move-result-object v1
invoke-direct {v0, v1}, Landroid/os/Handler;-><init>(Landroid/os/Looper;)V
new-instance v2, Landroid/os/Messenger;
invoke-direct {v2, v0}, Landroid/os/Messenger;-><init>(Landroid/os/Handler;)V
return-object v2
.end method
.method private createConfigBundle()Landroid/os/Bundle;
.locals 3
new-instance v0, Landroid/os/Bundle;
invoke-direct {v0}, Landroid/os/Bundle;-><init>()V
const-string v1, "versionCode"
const/16 v2, 0xa
invoke-virtual {v0, v1, v2}, Landroid/os/Bundle;->putInt(Ljava/lang/String;I)V
const-string v1, "themeColor"
const v2, __RL_WAZE_THEME_COLOR__ # Waze SDK themeColor
invoke-virtual {v0, v1, v2}, Landroid/os/Bundle;->putInt(Ljava/lang/String;I)V
invoke-direct {p0, v0}, Lradiant/WazeServiceConnection;->addOpenMeIntent(Landroid/os/Bundle;)V
return-object v0
.end method
.method private register(Landroid/os/IBinder;)V
.locals 5
if-eqz p1, :return
invoke-static {}, Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
move-result-object v0
invoke-static {}, Landroid/os/Parcel;->obtain()Landroid/os/Parcel;
move-result-object v1
const-string v2, "com.waze.sdk.ISdkService"
invoke-virtual {v0, v2}, Landroid/os/Parcel;->writeInterfaceToken(Ljava/lang/String;)V
iget-object v2, p0, Lradiant/WazeServiceConnection;->token:Ljava/lang/String;
invoke-virtual {v0, v2}, Landroid/os/Parcel;->writeString(Ljava/lang/String;)V
invoke-direct {p0}, Lradiant/WazeServiceConnection;->createConfigBundle()Landroid/os/Bundle;
move-result-object v2
invoke-static {v0, v2}, Lradiant/WazeServiceConnection;->writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
invoke-direct {p0}, Lradiant/WazeServiceConnection;->createClientMessenger()Landroid/os/Messenger;
move-result-object v2
invoke-static {v0, v2}, Lradiant/WazeServiceConnection;->writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
const/4 v2, 0x1
const/4 v3, 0x0
invoke-interface {p1, v2, v0, v1, v3}, Landroid/os/IBinder;->transact(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z
move-result v4
if-eqz v4, :cleanup
invoke-virtual {v1}, Landroid/os/Parcel;->readException()V
:cleanup
invoke-virtual {v1}, Landroid/os/Parcel;->recycle()V
invoke-virtual {v0}, Landroid/os/Parcel;->recycle()V
:return
return-void
.end method
.method private safeUnbind()V
.locals 1
:try_start_0
iget-object v0, p0, Lradiant/WazeServiceConnection;->context:Landroid/content/Context;
invoke-virtual {v0, p0}, Landroid/content/Context;->unbindService(Landroid/content/ServiceConnection;)V
:try_end_0
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
goto :return
:catch_0
move-exception v0
:return
return-void
.end method
.method private static writeParcelable(Landroid/os/Parcel;Landroid/os/Parcelable;)V
.locals 2
const/4 v0, 0x0
if-eqz p1, :null_value
const/4 v1, 0x1
invoke-virtual {p0, v1}, Landroid/os/Parcel;->writeInt(I)V
invoke-interface {p1, p0, v0}, Landroid/os/Parcelable;->writeToParcel(Landroid/os/Parcel;I)V
return-void
:null_value
invoke-virtual {p0, v0}, Landroid/os/Parcel;->writeInt(I)V
return-void
.end method
# virtual methods
.method public onServiceConnected(Landroid/content/ComponentName;Landroid/os/IBinder;)V
.locals 1
:try_start_0
invoke-direct {p0, p2}, Lradiant/WazeServiceConnection;->register(Landroid/os/IBinder;)V
:try_end_0
.catch Ljava/lang/Throwable; {:try_start_0 .. :try_end_0} :catch_0
goto :unbind
:catch_0
move-exception v0
:unbind
invoke-direct {p0}, Lradiant/WazeServiceConnection;->safeUnbind()V
return-void
.end method
.method public onServiceDisconnected(Landroid/content/ComponentName;)V
.locals 0
return-void
.end method
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,21 @@
.class public final Lradiant/WordLyricsTick;
.super Ljava/lang/Object;
.implements Ljava/lang/Runnable;
# 50ms clock tick driver for word level lyrics highlighting
.method public constructor <init>()V
.locals 0
invoke-direct {p0}, Ljava/lang/Object;-><init>()V
return-void
.end method
.method public run()V
.locals 0
invoke-static {}, Lradiant/WordLyrics;->tick()V
return-void
.end method
+5 -4
View File
@@ -9,8 +9,8 @@
.line 182
const-wide/16 v9, 0x0
--- a/com/tidal/android/feature/home/ui/p.smali
+++ b/com/tidal/android/feature/home/ui/p.smali
--- a/com/tidal/android/feature/home/ui/o.smali
+++ b/com/tidal/android/feature/home/ui/o.smali
@@ -187,6 +187,10 @@
.line 61
.line 62
@@ -22,8 +22,8 @@
invoke-interface {p1}, Landroidx/compose/foundation/layout/PaddingValues;->calculateTopPadding-D9Ej5fM()F
.line 63
--- a/com/tidal/android/feature/home/ui/composables/e.smali
+++ b/com/tidal/android/feature/home/ui/composables/e.smali
--- a/com/tidal/android/feature/home/ui/composables/g.smali
+++ b/com/tidal/android/feature/home/ui/composables/g.smali
@@ -790,6 +790,8 @@
.line 104
move-result-wide v14
@@ -41,3 +41,4 @@
+
.line 135
sget-object v3, Landroidx/compose/ui/graphics/Color;->Companion:Landroidx/compose/ui/graphics/Color$Companion;
+55
View File
@@ -0,0 +1,55 @@
--- a/mb/f.smali
+++ b/mb/f.smali
@@ -613,6 +613,25 @@
.line 236
:goto_8
+ const-string/jumbo v5, "com.waze"
+
+ invoke-static {v3, v5}, Lkotlin/jvm/internal/n;->b(Ljava/lang/Object;Ljava/lang/Object;)Z # package match
+
+ move-result v5
+
+ if-eqz v5, :rl_waze_done
+
+ const-string/jumbo v5, "03:63:7f:6c:5d:8f:60:4e:6f:db:79:a6:ff:bf:a5:78:de:4e:31:8f:8d:a2:2f:c6:10:66:65:24:7f:88:07:d7" # Waze cert
+
+ invoke-static {v2, v5}, Lkotlin/jvm/internal/n;->b(Ljava/lang/Object;Ljava/lang/Object;)Z # cert match
+
+ move-result v5
+
+ if-eqz v5, :rl_waze_done
+
+ goto :goto_9 # trust Waze
+
+ :rl_waze_done
invoke-static {}, Landroid/os/Process;->myUid()I
.line 237
@@ -769,6 +788,26 @@
:goto_b
if-eqz v2, :cond_14
+ const-string/jumbo v1, "com.waze"
+
+ invoke-static {v3, v1}, Lkotlin/jvm/internal/n;->b(Ljava/lang/Object;Ljava/lang/Object;)Z # package match
+
+ move-result v1
+
+ if-eqz v1, :rl_waze_recent_root_done_2
+
+ new-instance v1, Landroidx/media/MediaBrowserServiceCompat$BrowserRoot;
+
+ const-string/jumbo v4, "__RL_WAZE_ROOT_ID__"
+
+ const/4 v5, 0x0
+
+ invoke-direct {v1, v4, v5}, Landroidx/media/MediaBrowserServiceCompat$BrowserRoot;-><init>(Ljava/lang/String;Landroid/os/Bundle;)V
+
+ return-object v1
+
+ :rl_waze_recent_root_done_2
+
.line 306
.line 307
iget-object v1, v0, Lmb/f;->c:Ljava/util/Map;
+5 -5
View File
@@ -1,5 +1,5 @@
--- a/com/tidal/android/feature/playerscreen/ui/h0.smali
+++ b/com/tidal/android/feature/playerscreen/ui/h0.smali
--- a/com/tidal/android/feature/playerscreen/ui/b0.smali
+++ b/com/tidal/android/feature/playerscreen/ui/b0.smali
@@ -669,8 +669,23 @@
move-object v5, v1
@@ -8,15 +8,15 @@
+
+ invoke-interface {v7, v1}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open group around the cover
+
+ iget-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/h0;->b:Lcom/tidal/android/feature/playerscreen/ui/r$a; # player state
+ iget-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/b0;->b:Lcom/tidal/android/feature/playerscreen/ui/s$a; # player state
+
+ iget-object v1, v1, Lcom/tidal/android/feature/playerscreen/ui/r$a;->j:Lcom/tidal/android/feature/playerscreen/ui/g; # current view mode
+ iget-object v1, v1, Lcom/tidal/android/feature/playerscreen/ui/s$a;->j:Lcom/tidal/android/feature/playerscreen/ui/g; # current view mode
+
+ instance-of v1, v1, Lcom/tidal/android/feature/playerscreen/ui/g$a; # cover mode only
+
+ if-eqz v1, :radiant_after_cover # lyrics/credits mode -> skip cover
+
invoke-static/range {v2 .. v9}, Lcom/tidal/android/feature/playerscreen/ui/composables/CoverPagerKt;->c(Lcom/tidal/android/feature/playerscreen/ui/d;Lyl0/l;FLandroidx/compose/ui/Modifier;ZLandroidx/compose/runtime/Composer;II)V
invoke-static/range {v2 .. v9}, Lcom/tidal/android/feature/playerscreen/ui/composables/CoverPagerKt;->c(Lcom/tidal/android/feature/playerscreen/ui/d;Lam0/l;FLandroidx/compose/ui/Modifier;ZLandroidx/compose/runtime/Composer;II)V
+ :radiant_after_cover # skip target
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close group
+4 -5
View File
@@ -1,6 +1,6 @@
--- a/com/tidal/android/feature/playerscreen/ui/composables/o1.smali
+++ b/com/tidal/android/feature/playerscreen/ui/composables/o1.smali
@@ -64,26 +64,29 @@
@@ -64,7 +64,7 @@
.line 16
.line 17
@@ -9,8 +9,7 @@
.line 18
.line 19
invoke-interface {p1, v2}, Landroidx/compose/ui/unit/Density;->toPx-0680j_4(F)F
@@ -73,7 +73,13 @@
.line 20
.line 21
.line 22
@@ -25,8 +24,7 @@
.line 23
const/16 v5, 0x8
.line 24
@@ -82,9 +88,6 @@
.line 25
const/4 v6, 0x0
@@ -35,3 +33,4 @@
-
.line 27
const/4 v4, 0x0
+23 -5
View File
@@ -1,9 +1,6 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt$PlayerScreenPortrait$2$1.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt$PlayerScreenPortrait$2$1.smali
@@ -228,11 +228,11 @@
.line 23
.line 24
iget-boolean p1, p0, Lcom/tidal/android/feature/playerscreen/ui/PlayerScreenKt$PlayerScreenPortrait$2$1;->$isLyricsVisible:Z
@@ -231,7 +231,7 @@
.line 25
.line 26
@@ -12,4 +9,25 @@
.line 27
.line 28
iput v2, p0, Lcom/tidal/android/feature/playerscreen/ui/PlayerScreenKt$PlayerScreenPortrait$2$1;->label:I
--- a/com/tidal/android/feature/playerscreen/ui/PlayerViewModel.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerViewModel.smali
@@ -1382,6 +1382,19 @@
.line 109
.line 110
move-result v1
+ sget v4, Lradiant/LyricsReinitGuard;->lastMediaId:I
+ if-ne v1, v4, :rl_reinit_store
+ sget-object v4, Lradiant/LyricsReinitGuard;->lastVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
+ if-ne v0, v4, :rl_reinit_store
+ goto :rl_skip_reinit # only suppress duplicate initialization on the same ViewModel
+ :rl_reinit_store
+ sput v1, Lradiant/LyricsReinitGuard;->lastMediaId:I
+ sput-object v0, Lradiant/LyricsReinitGuard;->lastVm:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
+ goto :rl_reinit_ok
+ :rl_skip_reinit
+ sget-object v4, Lkotlin/u;->a:Lkotlin/u;
+ return-object v4
+ :rl_reinit_ok
.line 111
invoke-static {v1}, Ljava/lang/String;->valueOf(I)Ljava/lang/String;
+7 -7
View File
@@ -1,6 +1,6 @@
--- a/com/tidal/android/feature/playerscreen/ui/c0.smali
+++ b/com/tidal/android/feature/playerscreen/ui/c0.smali
@@ -47,7 +47,7 @@
--- a/com/tidal/android/feature/playerscreen/ui/m0.smali
+++ b/com/tidal/android/feature/playerscreen/ui/m0.smali
@@ -45,7 +45,7 @@
# virtual methods
.method public final invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
@@ -9,9 +9,9 @@
.line 1
move-object/from16 v0, p0
@@ -461,6 +461,64 @@
@@ -460,6 +460,64 @@
.line 200
invoke-static/range {v2 .. v9}, Lcom/tidal/android/feature/playerscreen/ui/composables/LyricsKt;->a(Lcom/tidal/android/feature/playerscreen/ui/g;Lyl0/l;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/layout/PaddingValues;Lyl0/l;Landroidx/compose/runtime/Composer;II)V
invoke-static/range {v2 .. v9}, Lcom/tidal/android/feature/playerscreen/ui/composables/LyricsKt;->a(Lcom/tidal/android/feature/playerscreen/ui/g;Lam0/l;Landroidx/compose/ui/Modifier;Landroidx/compose/foundation/layout/PaddingValues;Lam0/l;Landroidx/compose/runtime/Composer;II)V
+ sget-object v17, Lradiant/SpvFactory;->a:Lradiant/SpvFactory; # progress view factory
+
@@ -29,7 +29,7 @@
+
+ const/16 v24, 0x0 # synthetic null
+
+ invoke-static/range {v18 .. v24}, Landroidx/compose/foundation/ClickableKt;->clickable-XHw0xAI$default(Landroidx/compose/ui/Modifier;ZLjava/lang/String;Landroidx/compose/ui/semantics/Role;Lyl0/a;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; # apply clickable
+ invoke-static/range {v18 .. v24}, Landroidx/compose/foundation/ClickableKt;->clickable-XHw0xAI$default(Landroidx/compose/ui/Modifier;ZLjava/lang/String;Landroidx/compose/ui/semantics/Role;Lam0/a;ILjava/lang/Object;)Landroidx/compose/ui/Modifier; # apply clickable
+
+ move-result-object v23 # clickable modifier
+
@@ -69,7 +69,7 @@
+
+ const/16 v22, 0x4 # default mask
+
+ invoke-static/range {v17 .. v22}, Landroidx/compose/ui/viewinterop/AndroidView_androidKt;->AndroidView(Lyl0/l;Landroidx/compose/ui/Modifier;Lyl0/l;Landroidx/compose/runtime/Composer;II)V # mount progress pill
+ invoke-static/range {v17 .. v22}, Landroidx/compose/ui/viewinterop/AndroidView_androidKt;->AndroidView(Lam0/l;Landroidx/compose/ui/Modifier;Lam0/l;Landroidx/compose/runtime/Composer;II)V # mount progress pill
+
.line 201
.line 202
+20 -20
View File
@@ -1,34 +1,30 @@
# rl-locals: com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali e( 79
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -4945,7 +4945,11 @@
const/4 v7, 0x0
@@ -5183,7 +5183,11 @@
const/4 v12, 0x0
.line 226
- invoke-static {v7, v9, v4, v2, v10}, Lcom/tidal/android/feature/playerscreen/ui/composables/k1;->a(Landroidx/compose/ui/Modifier;Lyl0/a;ZLandroidx/compose/runtime/Composer;I)V
+ const v10, 0x52414448 # empty group key
.line 259
- invoke-static {v7, v8, v4, v15, v12}, Lcom/tidal/android/feature/playerscreen/ui/composables/k1;->a(Landroidx/compose/ui/Modifier;Lam0/a;ZLandroidx/compose/runtime/Composer;I)V
+ const v7, 0x52414448 # empty group key
+
+ invoke-interface {v2, v10}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
+ invoke-interface {v15, v7}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
+
+ invoke-interface {v2}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close empty
+ invoke-interface {v15}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close empty
.line 227
invoke-interface {v2}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V
@@ -5720,6 +5724,22 @@
:cond_51
check-cast v4, Lyl0/a;
.line 260
invoke-interface {v15}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V
@@ -5967,6 +5971,22 @@
const/4 v2, 0x0
invoke-static {v4, v3, v7, v6}, Lcom/tidal/android/feature/playerscreen/ui/composables/s3;->a(ILam0/a;Landroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;)V
invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/l3;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
+ new-instance v74, Landroidx/window/embedding/a2; # lyrics toggle lambda
+
+ new-instance v74, Lcom/tidal/android/feature/playerscreen/ui/g0; # lyrics toggle lambda
+ move-object/from16 v75, p2 # action dispatcher
+
+ move-object/from16 v75, p5 # action dispatcher
+ const/16 v76, 0x1 # lyrics action disc
+
+ const/16 v76, 0x0 # lyrics action disc
+
+ invoke-direct/range {v74 .. v76}, Lcom/tidal/android/feature/playerscreen/ui/g0;-><init>(Ljava/lang/Object;I)V # build lambda
+ invoke-direct/range {v74 .. v76}, Landroidx/window/embedding/a2;-><init>(Ljava/lang/Object;I)V # build lambda
+
+ const/16 v71, 0x0 # changed flags
+
@@ -36,4 +32,8 @@
+
+ const/16 v73, 0x0 # null modifier
+
+ invoke-static/range {v71 .. v74}, Lradiant/SparkleButton;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V # render sparkle button
+ invoke-static/range {v71 .. v74}, Lradiant/SparkleButton;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lam0/a;)V # render sparkle button
+
.line 365
iget-object v3, v11, Lcom/tidal/android/feature/playerscreen/ui/s$a;->m:Lcom/tidal/android/feature/playerscreen/ui/p;
+38 -42
View File
@@ -1,50 +1,46 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -5094,7 +5094,11 @@
const/4 v13, 0x0
@@ -5328,7 +5328,11 @@
const/4 v12, 0x0
.line 247
- invoke-static {v9, v0, v10, v2, v13}, Lcom/tidal/android/feature/playerscreen/ui/composables/BroadcastButtonKt;->b(Lcom/tidal/android/feature/playerscreen/ui/b;Lyl0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+ const v9, 0x52414244 # empty group key
.line 280
- invoke-static {v8, v6, v12, v15, v3}, Lcom/tidal/android/feature/playerscreen/ui/composables/BroadcastButtonKt;->b(Lcom/tidal/android/feature/playerscreen/ui/b;Lam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V
+ const v3, 0x52414244 # empty group key
+
+ invoke-interface {v2, v9}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
+ invoke-interface {v15, v3}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
+
+ invoke-interface {v2}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close empty
+ invoke-interface {v15}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close empty
.line 248
invoke-interface {v2}, Landroidx/compose/runtime/Composer;->endNode()V
@@ -5770,16 +5774,20 @@
.line 335
:cond_53
- new-instance v4, Lcom/aspiro/wamp/tidalconnect/playback/i;
-
- invoke-direct {v4, v11, v1}, Lcom/aspiro/wamp/tidalconnect/playback/i;-><init>(Ljava/lang/Object;I)V
-
- .line 336
- invoke-interface {v7, v4}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V
-
- .line 337
- :cond_54
- check-cast v4, Lyl0/a;
-
- const/4 v2, 0x0
-
- invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/x4;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
+ new-instance v4, Landroidx/navigation/fragment/k; # connect click lambda factory
.line 281
invoke-interface {v15}, Landroidx/compose/runtime/Composer;->endNode()V
@@ -6156,11 +6160,11 @@
.line 385
:cond_61
:goto_2e
- new-instance v1, Lcom/tidal/android/feature/playerscreen/ui/e0;
+ new-instance v1, Landroidx/window/embedding/b2; # connect click lambda (was share e0)
- const/4 v6, 0x0
+ const/4 v6, 0x1 # connect-clicked disc
- invoke-direct {v1, v10, v6}, Lcom/tidal/android/feature/playerscreen/ui/e0;-><init>(Ljava/lang/Object;I)V
+ invoke-direct {v1, v10, v6}, Landroidx/window/embedding/b2;-><init>(Ljava/lang/Object;I)V # build connect lambda
.line 386
invoke-interface {v7, v1}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V
@@ -6169,9 +6173,13 @@
:goto_2f
check-cast v1, Lam0/a;
- const/4 v3, 0x0
+ iget-object v8, v11, Lcom/tidal/android/feature/playerscreen/ui/s$a;->d:Lcom/tidal/android/feature/playerscreen/ui/b; # broadcast state
+
+ move-object/from16 v6, p5 # action dispatcher
+ const/4 v3, 0x0 # null modifier
+
+ const/4 v8, 0x1 # connect-clicked disc
+
+ invoke-direct {v4, v6, v8}, Landroidx/navigation/fragment/k;-><init>(Ljava/lang/Object;I)V # build lambda
+
+ invoke-interface {v7, v4}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V # cache lambda
+
+ :cond_54 # cache join
+ check-cast v4, Lyl0/a; # cast to Function0
+
+ iget-object v8, v10, Lcom/tidal/android/feature/playerscreen/ui/r$a;->d:Lcom/tidal/android/feature/playerscreen/ui/b; # broadcast state
+
+ const/4 v2, 0x0 # changed flags
+
+ invoke-static {v8, v4, v13, v7, v2}, Lcom/tidal/android/feature/playerscreen/ui/composables/BroadcastButtonKt;->b(Lcom/tidal/android/feature/playerscreen/ui/b;Lyl0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V # render connect button
+ const/4 v6, 0x0 # changed flags
- invoke-static {v6, v1, v7, v3}, Lcom/tidal/android/feature/playerscreen/ui/composables/e5;->a(ILam0/a;Landroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;)V
+ invoke-static {v8, v1, v3, v7, v6}, Lcom/tidal/android/feature/playerscreen/ui/composables/BroadcastButtonKt;->b(Lcom/tidal/android/feature/playerscreen/ui/b;Lam0/a;Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V # render connect button
if-ne v0, v2, :cond_62
+26
View File
@@ -0,0 +1,26 @@
--- a/cg0/h.smali
+++ b/cg0/h.smali
@@ -363,6 +363,23 @@
.method public static final d(Lcom/tidal/sdk/tidalapi/generated/models/TracksResourceObject;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/Map;)Lcom/tidal/android/tidalapi/domain/model/o;
.locals 23
+ invoke-virtual/range {p0 .. p0}, Lcom/tidal/sdk/tidalapi/generated/models/TracksResourceObject;->getAttributes()Lcom/tidal/sdk/tidalapi/generated/models/TracksAttributes;
+
+ move-result-object v1
+
+ if-eqz v1, :rl_isrc_skip
+
+ invoke-virtual/range {p0 .. p0}, Lcom/tidal/sdk/tidalapi/generated/models/TracksResourceObject;->getId()Ljava/lang/String;
+
+ move-result-object v0
+
+ invoke-virtual {v1}, Lcom/tidal/sdk/tidalapi/generated/models/TracksAttributes;->getIsrc()Ljava/lang/String;
+
+ move-result-object v1
+
+ invoke-static {v0, v1}, Lradiant/IsrcCache;->put(Ljava/lang/String;Ljava/lang/String;)V
+
+ :rl_isrc_skip
move-object/from16 v0, p4
move-object/from16 v1, p7
+13 -5
View File
@@ -1,15 +1,23 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerViewModel$observeLyricsProgress$1$a.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerViewModel$observeLyricsProgress$1$a.smali
@@ -190,7 +190,14 @@
goto :goto_0
@@ -58,6 +58,8 @@
.line 5
int-to-long p1, p1
+ invoke-static {p1, p2}, Lradiant/WordLyrics;->onProgress(J)V
+
.line 6
iget-object v0, p0, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel$observeLyricsProgress$1$a;->a:Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;
@@ -191,6 +193,13 @@
.line 67
:cond_3
+ sget-boolean v6, Lradiant/RLAPILyricsHook;->isRlState:Z # read RL flag
+ sget-boolean v6, Lradiant/RLAPILyricsHook;->isRlState:Z
+
+ if-eqz v6, :radiant_skip # skip if not RL
+ if-eqz v6, :radiant_skip
+
+ const/4 v5, -0x1 # RL no-match default = -1
+ const/4 v5, -0x1
+
+ :radiant_skip
if-gez v4, :cond_4
+56
View File
@@ -0,0 +1,56 @@
--- a/com/tidal/android/feature/playerscreen/ui/composables/f2.smali
+++ b/com/tidal/android/feature/playerscreen/ui/composables/f2.smali
@@ -87,7 +87,7 @@
# virtual methods
.method public final invoke(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
- .locals 28
+ .locals 40
.line 1
move-object/from16 v0, p0
@@ -313,6 +313,8 @@
.line 100
check-cast v1, Lcom/tidal/android/feature/playerscreen/ui/f;
+ move/16 v33, v2
+
.line 101
.line 102
const v3, 0x6b82e849
@@ -801,6 +803,26 @@
.line 331
iget-object v3, v1, Lcom/tidal/android/feature/playerscreen/ui/f;->a:Ljava/lang/String;
+ iget v4, v0, Lcom/tidal/android/feature/playerscreen/ui/composables/f2;->b:I
+
+ move/16 v34, v4
+
+ iget-object v4, v1, Lcom/tidal/android/feature/playerscreen/ui/f;->a:Ljava/lang/String;
+
+ move-object/16 v35, v4
+
+ iget-wide v4, v0, Lcom/tidal/android/feature/playerscreen/ui/composables/f2;->d:J
+
+ move-wide/16 v36, v4
+
+ iget-wide v4, v0, Lcom/tidal/android/feature/playerscreen/ui/composables/f2;->e:J
+
+ move-wide/16 v38, v4
+
+ invoke-static/range {v33 .. v39}, Lradiant/WordLyrics;->render(IILjava/lang/String;JJ)Landroidx/compose/ui/text/AnnotatedString;
+
+ move-result-object v3
+
.line 332
.line 333
invoke-interface {v2}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object;
@@ -898,7 +920,7 @@
.line 377
.line 378
- invoke-static/range {v3 .. v27}, Landroidx/compose/material3/TextKt;->Text--4IGK_g(Ljava/lang/String;Landroidx/compose/ui/Modifier;JJLandroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontFamily;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/text/style/TextAlign;JIZIILam0/l;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;III)V
+ invoke-static/range {v3 .. v27}, Landroidx/compose/material3/TextKt;->Text--4IGK_g(Landroidx/compose/ui/text/AnnotatedString;Landroidx/compose/ui/Modifier;JJLandroidx/compose/ui/text/font/FontStyle;Landroidx/compose/ui/text/font/FontWeight;Landroidx/compose/ui/text/font/FontFamily;JLandroidx/compose/ui/text/style/TextDecoration;Landroidx/compose/ui/text/style/TextAlign;JIZILjava/util/Map;Lam0/l;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/runtime/Composer;III)V
.line 379
.line 380
+66 -10
View File
@@ -1,7 +1,6 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerViewModel.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerViewModel.smali
@@ -1277,7 +1277,9 @@
.line 104
@@ -1374,6 +1374,8 @@
.line 105
check-cast v1, Lcom/aspiro/wamp/model/Track;
@@ -10,12 +9,69 @@
.line 106
.line 107
invoke-virtual {v1}, Lcom/aspiro/wamp/model/MediaItem;->getId()I
@@ -1551,7 +1553,7 @@
.line 235
.line 236
.line 237
- if-nez v9, :cond_a
+ goto :cond_a # skip TIDAL N=false setter
.line 238
@@ -1655,7 +1657,11 @@
.line 239
.line 240
.line 241
- if-nez v9, :cond_a
+ invoke-static {v0}, Lradiant/RLAPILyricsHook;->shouldKeepOpen(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;)Z
+ move-result v20
+ if-nez v20, :cond_a # keep visibility only for RL state owned by this ViewModel
+ :rl_native_visibility
+ if-nez v9, :cond_a
.line 242
.line 243
@@ -2347,7 +2353,12 @@
.line 572
:goto_c
+ invoke-static {v0}, Lradiant/RLAPILyricsHook;->isOwner(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;)Z
+ move-result v20
+ if-nez v20, :rl_keep_n2 # only preserve RL content owned by this ViewModel
+ :rl_set_n2
invoke-interface {v9, v1}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
+ :rl_keep_n2
.line 573
.line 574
@@ -2396,7 +2407,12 @@
.line 595
.line 596
+ invoke-static {v0}, Lradiant/RLAPILyricsHook;->shouldKeepOpen(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;)Z
+ move-result v20
+ if-nez v20, :rl_keep_o # only preserve visibility owned by this ViewModel
+ :rl_set_o
invoke-interface {v1, v5}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
+ :rl_keep_o
.line 597
.line 598
@@ -2425,7 +2441,12 @@
.line 610
.line 611
+ invoke-static {v0}, Lradiant/RLAPILyricsHook;->isOwner(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;)Z
+ move-result v20
+ if-nez v20, :rl_keep_n # only preserve RL content owned by this ViewModel
+ :rl_set_n
invoke-interface {v1, v6}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
+ :rl_keep_n
.line 612
.line 613
--- a/com/tidal/android/feature/playerscreen/ui/PlayerViewModel$special$$inlined$mapNotNull$1$2.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerViewModel$special$$inlined$mapNotNull$1$2.smali
@@ -2256,6 +2256,11 @@
.line 1040
.line 1041
move-result v34
+ invoke-static {v1}, Lradiant/RLAPILyricsHook;->isOwner(Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;)Z
+ move-result v4
+ if-eqz v4, :rl_hl_done # ignore non-RL state or state owned by an obsolete ViewModel
+ const/16 v34, 0x1 # RL lyrics active = force hasLyrics so the sparkle stays
+ :rl_hl_done
.line 1042
iget-object v4, v1, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->P:Lkotlinx/coroutines/flow/MutableStateFlow;
@@ -1,41 +1,37 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -5725,17 +5725,38 @@
invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/l3;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
@@ -5971,6 +5971,14 @@
invoke-static {v4, v3, v7, v6}, Lcom/tidal/android/feature/playerscreen/ui/composables/s3;->a(ILam0/a;Landroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;)V
+ iget-boolean v3, v11, Lcom/tidal/android/feature/playerscreen/ui/s$a;->i:Z # hasLyrics flag
+
+ iget-boolean v2, v10, Lcom/tidal/android/feature/playerscreen/ui/r$a;->i:Z # hasLyrics flag
+ if-eqz v3, :cond_sparkle_no_lyrics # branch when no lyrics
+
+ if-eqz v2, :cond_sparkle_no_lyrics # branch when no lyrics
+ const v3, 0x30551b59 # group key (lyrics)
+
+ const v2, 0x30551b59 # group key (lyrics)
+ invoke-interface {v7, v3}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open lyrics branch
+
+ invoke-interface {v7, v2}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open lyrics branch
new-instance v74, Landroidx/window/embedding/a2; # lyrics toggle lambda
new-instance v74, Lcom/tidal/android/feature/playerscreen/ui/g0; # lyrics toggle lambda
move-object/from16 v75, p2 # action dispatcher
@@ -5987,6 +5995,19 @@
move-object/from16 v75, p5 # action dispatcher
invoke-static/range {v71 .. v74}, Lradiant/SparkleButton;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lam0/a;)V # render sparkle button
const/16 v76, 0x0 # lyrics action disc
invoke-direct/range {v74 .. v76}, Lcom/tidal/android/feature/playerscreen/ui/g0;-><init>(Ljava/lang/Object;I)V # build lambda
const/16 v71, 0x0 # changed flags
move-object/from16 v72, v7 # composer
const/16 v73, 0x0 # null modifier
invoke-static/range {v71 .. v74}, Lradiant/SparkleButton;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V # render sparkle button
+
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close lyrics branch
+
+ goto :goto_sparkle_done # skip empty branch
+
+ :cond_sparkle_no_lyrics # no-lyrics branch
+ const v2, 0x3057f75c # group key (no lyrics)
+ const v3, 0x3057f75c # group key (no lyrics)
+
+ invoke-interface {v7, v2}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
+ invoke-interface {v7, v3}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open empty
+
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close empty
+
+ :goto_sparkle_done # join target
+
.line 365
iget-object v3, v11, Lcom/tidal/android/feature/playerscreen/ui/s$a;->m:Lcom/tidal/android/feature/playerscreen/ui/p;
+259 -49
View File
@@ -4,11 +4,15 @@
{
"id": "EnableLegacyUi",
"order": 10,
"fileNames": ["enable-legacy-ui.patch"],
"fileNames": [
"enable-legacy-ui.patch"
],
"title": "Enable Legacy UI",
"description": "[This patch will stop working soon] - Replaces the New Compose based UI with the Legacy UI (disables player-market-ui feature flag)",
"default": false,
"requires": ["DebugMenuUnlock"],
"requires": [
"DebugMenuUnlock"
],
"disables": [
"LyricsDisableCover",
"LyricsReplaceLyricsButton",
@@ -17,75 +21,183 @@
"LyricsKeepControlsVisible",
"PlayerBackdrop",
"QualityBadgeColors",
"PlayerMovePlayingFrom",
"PlayerOneHanded",
"LyricsProgressPill",
"CoverEverywhere",
"MiniPlayerRedesign"
]
},
{
"id": "LyricsRlApi",
"order": 20,
"fileNames": ["lyrics-rl-api.patch", "lyrics-rl-api-observer.patch"],
"fileNames": [
"lyrics-rl-api.patch",
"lyrics-rl-api-observer.patch",
"lyrics-rl-api-isrc.patch"
],
"title": "Radiant Lyrics API - WIP",
"description": "Use Radiant Lyrics API to fetch Lyrics (Higher quality & More providers)",
"default": false
"description": "Use Radiant Lyrics API to fetch Lyrics (Higher quality & More providers). Pick how the highlight moves: whole Line or word-by-word (Word).",
"default": false,
"defaultVariantIndex": 0,
"variants": [
{
"title": "Line",
"fileNames": []
},
{
"title": "Word",
"fileNames": [
"lyrics-rl-api-word.patch"
]
}
]
},
{
"id": "PlayerBackdrop",
"order": 30,
"fileNames": ["player-backdrop.patch"],
"fileNames": [],
"title": "Player Backdrop",
"description": "Restores the legacy translucent backdrop blur behind the player",
"description": "Lets you fully adjust how the player backdrop blur looks and behaves",
"default": true,
"defaultVariantIndex": 2,
"variants": [
{
"title": "Static",
"fileNames": [
"player-backdrop-static.patch"
],
"extensionFiles": [
"radiant/BackdropFx.smali"
]
},
{
"title": "Animated",
"fileNames": [
"player-backdrop-animated.patch"
],
"extensionFiles": [
"radiant/BackdropFx.smali"
]
},
{
"title": "Playback",
"fileNames": [
"player-backdrop-playback.patch"
],
"extensionFiles": [
"radiant/BackdropFx.smali"
]
}
],
"advancedOptions": [
{
"type": "slider",
"key": "blur_strength",
"title": "Blur Strength",
"description": "How strongly the album art behind the player is blurred",
"description": "The value of Blur applied to the backdrop cover",
"default": 50,
"min": 0,
"max": 100,
"steps": 19,
"displayAsPercent": true,
"token": "RL_BLUR_BITS",
"encode": { "kind": "floatBits", "scale": 1.8 }
"token": "RL_BLUR",
"encode": {
"kind": "int",
"scale": 1.0
}
},
{
"type": "slider",
"key": "dimming",
"title": "Backdrop Dimming",
"description": "Darkens the backdrop so the foreground controls stay legible",
"key": "contrast",
"title": "Contrast",
"description": "The value of Contrast applied to the backdrop cover",
"default": 50,
"min": 0,
"max": 100,
"steps": 19,
"displayAsPercent": true,
"token": "RL_SCRIM_ARGB",
"encode": { "kind": "argbAlpha" }
"token": "RL_CONTRAST",
"encode": {
"kind": "floatBits",
"scale": 0.02
}
},
{
"type": "slider",
"key": "saturation",
"title": "Saturation",
"description": "The value of Saturation applied to the backdrop cover",
"default": 50,
"min": 0,
"max": 100,
"steps": 19,
"displayAsPercent": true,
"token": "RL_SATURATION",
"encode": {
"kind": "floatBits",
"scale": 0.02
}
},
{
"type": "slider",
"key": "brightness",
"title": "Brightness",
"description": "The value of Brightness applied to the backdrop cover",
"default": 50,
"min": 0,
"max": 100,
"steps": 19,
"displayAsPercent": true,
"token": "RL_BRIGHTNESS",
"encode": {
"kind": "floatBits",
"scale": 0.02
}
},
{
"type": "toggle",
"key": "cover_everywhere",
"title": "Cover Everywhere - WIP",
"description": "Applies TIDAL's native blurred album-art backdrop to every Compose based page (Home & Collection)",
"default": false,
"inline": true,
"fileNames": [
"home-backdrop.patch",
"collection-backdrop.patch",
"cover-capture.patch"
]
}
]
},
{
"id": "CoverEverywhere",
"order": 35,
"fileNames": ["home-backdrop.patch", "collection-backdrop.patch", "cover-capture.patch"],
"title": "Cover Everywhere - WIP",
"description": "Applies the blurred backdrop to every Compose based page (Home & Collection)",
"default": false
},
{
"id": "QualityBadgeColors",
"order": 36,
"fileNames": ["player-quality-badge-colors.patch"],
"fileNames": [
"player-quality-badge-colors.patch"
],
"title": "Quality Badge Colors",
"description": "Brings color back to the player quality badge.",
"default": true
},
{
"id": "PlayerOneHanded",
"id": "PlayerMovePlayingFrom",
"order": 37,
"fileNames": ["player-one-handed.patch"],
"fileNames": [
"player-move-playing-from.patch"
],
"extensionFiles": [
"radiant/PlayingFrom.smali"
],
"title": "Playing From",
"description": "Shows the source name (playlist/album/mix) above the track title",
"default": true
},
{
"id": "PlayerOneHanded",
"order": 38,
"fileNames": [
"player-one-handed.patch"
],
"title": "One-Handed Mode",
"description": "Mirrors the bottom player buttons left-to-right for easier one-handed reach.",
"default": false
@@ -93,16 +205,25 @@
{
"id": "LyricsProgressPill",
"order": 40,
"fileNames": ["lyrics-progress-pill.patch", "lyrics-fade-region.patch"],
"fileNames": [
"lyrics-progress-pill.patch",
"lyrics-fade-region.patch"
],
"title": "Lyrics Progress Pill",
"description": "Restores the old Track Progress Pill in the top of the Lyrics screen!",
"default": true,
"requires": ["LyricsDisableCover", "LyricsReplaceLyricsButton", "LyricsReplaceShareButton"]
"requires": [
"LyricsDisableCover",
"LyricsReplaceLyricsButton",
"LyricsReplaceShareButton"
]
},
{
"id": "LyricsDisableCover",
"order": 41,
"fileNames": ["lyrics-disable-cover.patch"],
"fileNames": [
"lyrics-disable-cover.patch"
],
"title": "Disable Lyrics Cover",
"description": "Removes the mini track cover from the lyrics screen.",
"default": true
@@ -110,7 +231,10 @@
{
"id": "LyricsReplaceLyricsButton",
"order": 42,
"fileNames": ["lyrics-replace-lyrics-button.patch", "lyrics-sparkle-conditional-visibility.patch"],
"fileNames": [
"lyrics-replace-lyrics-button.patch",
"lyrics-sparkle-conditional-visibility.patch"
],
"title": "Replace Lyrics Button",
"description": "Replaces the Lyrics button with the RL Sparkle!",
"default": true
@@ -118,7 +242,9 @@
{
"id": "LyricsReplaceShareButton",
"order": 43,
"fileNames": ["lyrics-replace-share-button.patch"],
"fileNames": [
"lyrics-replace-share-button.patch"
],
"title": "Replace Share Button",
"description": "Replaces the share button with the Tidal Connect button from the top of the screen. (it's in the menu already)",
"default": true
@@ -132,9 +258,22 @@
"default": false,
"defaultVariantIndex": 2,
"variants": [
{ "title": "Floating", "fileNames": [] },
{ "title": "Grey", "fileNames": ["mini-player-grey.patch"] },
{ "title": "Black", "fileNames": ["mini-player-black.patch"] }
{
"title": "Floating",
"fileNames": []
},
{
"title": "Grey",
"fileNames": [
"mini-player-grey.patch"
]
},
{
"title": "Black",
"fileNames": [
"mini-player-black.patch"
]
}
],
"advancedOptions": [
{
@@ -144,10 +283,18 @@
"description": "Colorizes the Mini-Player depending on the currently playing track.",
"default": false,
"inline": true,
"fileNames": ["mini-player-dynamic-bg.patch"],
"extensionFiles": ["radiant/MiniPlayerBackground.smali"],
"hidesVariants": [2],
"relabelVariants": { "1": "Legacy" }
"fileNames": [
"mini-player-dynamic-bg.patch"
],
"extensionFiles": [
"radiant/MiniPlayerBackground.smali"
],
"hidesVariants": [
2
],
"relabelVariants": {
"1": "Legacy"
}
},
{
"type": "toggle",
@@ -156,8 +303,12 @@
"description": "Draws an animated progress ring around the floating mini-player. Requires the Floating style.",
"default": false,
"requiresVariant": 0,
"fileNames": ["mini-player-floating-border.patch"],
"extensionFiles": ["radiant/MiniSeekerFloating.smali"]
"fileNames": [
"mini-player-floating-border.patch"
],
"extensionFiles": [
"radiant/MiniSeekerFloating.smali"
]
},
{
"type": "toggle",
@@ -165,7 +316,9 @@
"title": "Mini-Player Gestures",
"description": "Adds swipe up gesture to the mini-player to reopen the player",
"default": true,
"fileNames": ["mini-player-gestures.patch"],
"fileNames": [
"mini-player-gestures.patch"
],
"extensionFiles": [
"radiant/MiniPlayerGestures.smali",
"radiant/MiniPlayerGestures$Gesture.smali",
@@ -179,8 +332,14 @@
"type": "choice",
"key": "swipe_up_drag",
"title": "Swipe Up Style",
"entries": ["Static", "Drag"],
"values": ["0x0", "0x1"],
"entries": [
"Static",
"Drag"
],
"values": [
"0x0",
"0x1"
],
"defaultIndex": 1,
"requiresOption": "gestures",
"token": "RL_MINI_PLAYER_SWIPE_UP_DRAG"
@@ -192,14 +351,16 @@
"description": "Swipe left or right on the mini-player to skip tracks.",
"default": false,
"requiresOption": "gestures",
"fileNames": ["mini-player-gestures-left-right.patch"],
"fileNames": [
"mini-player-gestures-left-right.patch"
],
"extensionFiles": [
"radiant/MiniPlayerTrackGestures.smali",
"radiant/MiniPlayerTrackGestures$Gesture.smali",
"radiant/MiniPlayerTrackGestures$OffsetLayer.smali",
"radiant/MiniPlayerTrackGestures$ResetAnimator.smali",
"radiant/MiniPlayerTrackGestures$TextDraw.smali",
"com/tidal/android/feature/appscaffold/ui/q$c.smali"
"com/tidal/android/feature/appscaffold/ui/r$c.smali"
]
}
]
@@ -207,15 +368,64 @@
{
"id": "LyricsKeepControlsVisible",
"order": 60,
"fileNames": ["lyrics-keep-controls-visible.patch"],
"fileNames": [
"lyrics-keep-controls-visible.patch"
],
"extensionFiles": [
"radiant/LyricsReinitGuard.smali"
],
"title": "Keep Controls Visible",
"description": "Inverts the auto-hide behavior on the lyrics screen, playback controls stay visible by default and only hide when you tap them off.",
"description": "Inverts the auto-hide behavior on the lyrics screen, playback controls stay visible by default and only hide when you tap them off. Also stops the open lyrics view from randomly closing when the player re-fetches the same track.",
"default": true
},
{
"id": "WazeIntegration",
"order": 90,
"category": "integration",
"pathLocked": true,
"fileNames": [
"integration-waze-playback.patch"
],
"extensionFiles": [
"radiant/WazeInitReceiver.smali",
"radiant/WazeServiceConnection.smali"
],
"title": "Waze Integration",
"description": "Control TIDAL playback from the Waze app",
"default": true,
"advancedOptions": [
{
"type": "choice",
"key": "browse_root",
"title": "Media Menu",
"entries": [
"Auto Menu",
"Home",
"Recents"
],
"values": [
"ROOT_AUTO",
"HOME_V2::home_page_v2_id",
"RECENTLY_PLAYED::home/pages/CONTINUE_LISTEN_TO/view-all"
],
"defaultIndex": 0,
"token": "RL_WAZE_ROOT_ID"
},
{
"type": "color",
"key": "accent_color",
"title": "Accent Color",
"default": -16747037,
"token": "RL_WAZE_THEME_COLOR"
}
]
},
{
"id": "DebugMenuUnlock",
"order": 100,
"fileNames": ["debug-menu-unlock.patch"],
"fileNames": [
"debug-menu-unlock.patch"
],
"title": "Unlock Debug Menu",
"description": "Reveals TIDAL's hidden Debug Menu in Settings. (Unlocks Feature Flags & the legacy Debug Options)",
"default": false
+31 -32
View File
@@ -20,61 +20,60 @@
.line 71
--- a/com/tidal/android/feature/appscaffold/ui/composable/i.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/i.smali
@@ -2756,12 +2756,7 @@
invoke-static {v0, v8, v11, v12}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxWidth$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
@@ -2275,11 +2275,7 @@
move-result-object v0
move-result-object v2
- .line 143
- invoke-static {v2}, Landroidx/compose/foundation/layout/WindowInsetsPadding_androidKt;->navigationBarsPadding(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
-
- .line 140
- invoke-static {v0}, Landroidx/compose/foundation/layout/WindowInsetsPadding_androidKt;->navigationBarsPadding(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
-
- move-result-object v0
- move-result-object v2
-
+ # flush bottom; skip nav inset
.line 141
invoke-interface/range {v17 .. v17}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object;
.line 144
invoke-interface/range {v21 .. v21}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object;
@@ -2773,6 +2768,8 @@
@@ -2291,6 +2287,8 @@
move-result v10
move-result v4
+ const/4 v10, 0x0 # zero horizontal padding
+ const/4 v4, 0x0 # zero horizontal padding
+
const/4 v11, 0x2
const/4 v6, 0x2
.line 142
@@ -2816,6 +2813,12 @@
.line 145
@@ -2334,6 +2332,12 @@
move-result-wide v10
move-result-wide v3
+ const v8, -0x1000000 # 0xFF000000 opaque black
+ const v5, -0x1000000 # 0xFF000000 opaque black
+
+ invoke-static {v8}, Landroidx/compose/ui/graphics/ColorKt;->Color(I)J # pack to color long
+ invoke-static {v5}, Landroidx/compose/ui/graphics/ColorKt;->Color(I)J # pack to color long
+
+ move-result-wide v10 # override theme color
+ move-result-wide v3 # override theme color
+
.line 147
sget-object v8, Lcom/tidal/android/feature/appscaffold/ui/composable/a;->c:Landroidx/compose/foundation/shape/RoundedCornerShape;
.line 150
sget-object v5, Lcom/tidal/android/feature/appscaffold/ui/composable/a;->c:Landroidx/compose/foundation/shape/RoundedCornerShape;
@@ -2857,6 +2860,10 @@
@@ -2375,6 +2379,10 @@
move-result-object v0
move-result-object v2
+ invoke-static {v0}, Landroidx/compose/foundation/layout/WindowInsetsPadding_androidKt;->navigationBarsPadding(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # inset bar content above nav bar (Prevents Bleeding behind Nav Buttons)
+ invoke-static {v2}, Landroidx/compose/foundation/layout/WindowInsetsPadding_androidKt;->navigationBarsPadding(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # inset bar content above nav bar (Prevents Bleeding behind Nav Buttons)
+
+ move-result-object v0
+ move-result-object v2
+
.line 155
sget-object v8, Landroidx/compose/foundation/layout/Arrangement;->INSTANCE:Landroidx/compose/foundation/layout/Arrangement;
.line 158
sget-object v3, Landroidx/compose/foundation/layout/Arrangement;->INSTANCE:Landroidx/compose/foundation/layout/Arrangement;
@@ -2969,6 +2976,10 @@
@@ -2487,6 +2495,10 @@
invoke-static {v12, v0, v8}, Landroidx/compose/runtime/Updater;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Lyl0/p;)V
invoke-static {v6, v2, v3}, Landroidx/compose/runtime/Updater;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Lam0/p;)V
+ const/4 v8, 0x0 # composer $changed flags
+
+ invoke-static {v15, v8}, Lradiant/MiniSeekerLine;->render(Landroidx/compose/runtime/Composer;I)V # draw top-edge seeker
+ invoke-static {v7, v8}, Lradiant/MiniSeekerLine;->render(Landroidx/compose/runtime/Composer;I)V # draw top-edge seeker
+
.line 172
sget-object v0, Landroidx/compose/foundation/layout/ColumnScopeInstance;->INSTANCE:Landroidx/compose/foundation/layout/ColumnScopeInstance;
.line 175
sget-object v2, Landroidx/compose/foundation/layout/ColumnScopeInstance;->INSTANCE:Landroidx/compose/foundation/layout/ColumnScopeInstance;
+27 -28
View File
@@ -1,56 +1,55 @@
--- a/com/tidal/android/feature/appscaffold/ui/composable/i.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/i.smali
@@ -2819,4 +2819,10 @@
.line 147
+ const/4 v8, 0x0
@@ -2334,6 +2334,12 @@
move-result-wide v3
+ const/4 v5, 0x0
+
+ invoke-static {v10, v11, v15, v8}, Lradiant/MiniPlayerBackground;->color(JLandroidx/compose/runtime/Composer;I)J # dynamic bg or fallback
+ invoke-static {v3, v4, v7, v5}, Lradiant/MiniPlayerBackground;->color(JLandroidx/compose/runtime/Composer;I)J # dynamic bg or fallback
+
+ move-result-wide v10
+ move-result-wide v3
+
sget-object v8, Lcom/tidal/android/feature/appscaffold/ui/composable/a;->c:Landroidx/compose/foundation/shape/RoundedCornerShape;
.line 150
sget-object v5, Lcom/tidal/android/feature/appscaffold/ui/composable/a;->c:Landroidx/compose/foundation/shape/RoundedCornerShape;
.line 148
--- a/com/tidal/android/feature/playerscreen/ui/PlayerViewModel.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerViewModel.smali
@@ -1047,9 +1047,13 @@
invoke-static {v2, v1, v4, v3}, Lkotlinx/coroutines/flow/FlowKt;->stateIn(Lkotlinx/coroutines/flow/Flow;Lkotlinx/coroutines/CoroutineScope;Lkotlinx/coroutines/flow/SharingStarted;Ljava/lang/Object;)Lkotlinx/coroutines/flow/StateFlow;
@@ -1146,6 +1146,10 @@
move-result-object v1
iput-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->W:Lkotlinx/coroutines/flow/StateFlow;
iput-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->U:Lkotlinx/coroutines/flow/StateFlow;
+ iget-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->O:Lkotlin/h;
+ iget-object v1, v0, Lcom/tidal/android/feature/playerscreen/ui/PlayerViewModel;->Q:Lkotlin/i;
+
+ invoke-interface {v1}, Lkotlin/h;->getValue()Ljava/lang/Object; # init player bg color
+ invoke-interface {v1}, Lkotlin/i;->getValue()Ljava/lang/Object; # init player bg color
+
return-void
.end method
@@ -1607,6 +1611,8 @@
@@ -1711,6 +1715,8 @@
:goto_6
invoke-interface {v9, v10}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
+ invoke-static {v10}, Lradiant/MiniPlayerBackground;->setHex(Ljava/lang/String;)V # store player bg hex
+
.line 263
.line 264
.line 265
@@ -2306,6 +2312,8 @@
.line 598
.line 267
.line 268
.line 269
@@ -2410,6 +2416,8 @@
.line 602
invoke-interface {v1, v5}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
+ invoke-static {v5}, Lradiant/MiniPlayerBackground;->setHex(Ljava/lang/String;)V # clear bg color
+
.line 599
.line 600
.line 601
@@ -2523,6 +2531,8 @@
.line 704
.line 603
.line 604
.line 605
@@ -2627,6 +2635,8 @@
.line 708
invoke-interface {v1, v5}, Lkotlinx/coroutines/flow/MutableStateFlow;->setValue(Ljava/lang/Object;)V
+ invoke-static {v5}, Lradiant/MiniPlayerBackground;->setHex(Ljava/lang/String;)V # clear bg color
+
.line 705
.line 706
.line 707
.line 709
.line 710
.line 711
+7 -7
View File
@@ -1,15 +1,15 @@
--- a/com/tidal/android/feature/appscaffold/ui/composable/i.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/i.smali
@@ -2829,6 +2829,12 @@
@@ -2347,6 +2347,12 @@
move-result-object v0
move-result-object v2
+ sget-object v8, Lradiant/MiniSeekerFloating;->INSTANCE:Lradiant/MiniSeekerFloating; # draw lambda
+ sget-object v5, Lradiant/MiniSeekerFloating;->INSTANCE:Lradiant/MiniSeekerFloating; # draw lambda
+
+ invoke-static {v0, v8}, Landroidx/compose/ui/draw/DrawModifierKt;->drawWithContent(Landroidx/compose/ui/Modifier;Lyl0/l;)Landroidx/compose/ui/Modifier; # overlay perimeter stroke
+ invoke-static {v2, v5}, Landroidx/compose/ui/draw/DrawModifierKt;->drawWithContent(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier; # overlay perimeter stroke
+
+ move-result-object v0 # updated modifier
+ move-result-object v2 # updated modifier
+
.line 150
sget-object v8, Lkotlin/u;->a:Lkotlin/u;
.line 153
sget-object v3, Lkotlin/u;->a:Lkotlin/u;
+62 -40
View File
@@ -1,40 +1,53 @@
--- a/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali
@@ -1768,3 +1768,7 @@
@@ -1215,6 +1215,10 @@
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
+ invoke-static {v6, v1}, Lradiant/MiniPlayerTrackGestures;->trackModifier(Landroidx/compose/ui/Modifier;Lam0/l;)Landroidx/compose/ui/Modifier; # attach horizontal swipe listener
+
+ move-result-object v6
+
.line 38
@@ -1884,5 +1888,5 @@
sget-object v21, Landroidx/compose/ui/Alignment;->Companion:Landroidx/compose/ui/Alignment$Companion;
@@ -1352,6 +1356,8 @@
.line 56
iget-object v6, v0, Lcom/tidal/android/feature/appscaffold/ui/s;->b:Lcom/tidal/android/feature/appscaffold/ui/p;
-
+ invoke-static {v6}, Lradiant/MiniPlayerTrackGestures;->onRenderedItem(Ljava/lang/Object;)V # reset stale drag offset if track metadata changes mid-gesture
iget-object v11, v0, Lcom/tidal/android/feature/appscaffold/ui/t;->b:Lcom/tidal/android/feature/appscaffold/ui/q;
+ invoke-static {v11}, Lradiant/MiniPlayerTrackGestures;->onRenderedItem(Ljava/lang/Object;)V # reset stale drag offset if track metadata changes mid-gesture
+
.line 57
invoke-virtual/range {v16 .. v16}, Lcom/squareup/ui/market/core/theme/MarketStylesheet;->getBorderRadii()Lcom/squareup/ui/market/core/theme/MarketStylesheet$b;
@@ -1919,5 +1923,6 @@
invoke-static {v5, v4}, Landroidx/compose/foundation/layout/SizeKt;->size-3ABfNKs(Landroidx/compose/ui/Modifier;F)Landroidx/compose/ui/Modifier;
-
move-result-object v4
-
+ invoke-static {v4}, Lradiant/MiniPlayerTrackGestures;->feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move the whole cover container with horizontal swipe
+ move-result-object v4
@@ -1390,6 +1396,10 @@
move-result-object v6
+ invoke-static {v6}, Lradiant/MiniPlayerTrackGestures;->feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move the whole cover container with horizontal swipe
+
+ move-result-object v6
+
.line 63
@@ -2032,3 +2038,5 @@
move-result-object v4
-
+ invoke-static {v4}, Lradiant/MiniPlayerTrackGestures;->textFeedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move title/artist
+ move-result-object v4
invoke-virtual/range {v22 .. v22}, Lcom/squareup/ui/market/core/theme/MarketStylesheet$c;->p0()Lf20/a;
@@ -1501,6 +1511,10 @@
move-result-object v5
+ invoke-static {v5}, Lradiant/MiniPlayerTrackGestures;->textFeedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move title/artist
+
+ move-result-object v5
+
.line 72
invoke-virtual/range {v32 .. v32}, Landroidx/compose/foundation/layout/Arrangement;->getTop()Landroidx/compose/foundation/layout/Arrangement$Vertical;
--- a/com/tidal/android/feature/appscaffold/ui/MiniPlayerViewModel.smali
+++ b/com/tidal/android/feature/appscaffold/ui/MiniPlayerViewModel.smali
@@ -816,10 +816,10 @@
@@ -512,16 +512,16 @@
.line 110
invoke-virtual {p1, v0}, Ljava/lang/Object;->equals(Ljava/lang/Object;)Z
.line 111
.line 112
.line 113
@@ -47,21 +60,25 @@
.line 115
.line 116
@@ -997,11 +997,32 @@
invoke-interface {v3}, Lbi/e;->i()Z
.line 117
@@ -695,12 +695,34 @@
.line 194
:cond_e
return-void
- .line 195
.line 195
:cond_f
+ sget-object v0, Lcom/tidal/android/feature/appscaffold/ui/q$c;->a:Lcom/tidal/android/feature/appscaffold/ui/q$c;
+ sget-object v0, Lcom/tidal/android/feature/appscaffold/ui/r$c;->a:Lcom/tidal/android/feature/appscaffold/ui/r$c; # our synthetic previous-track event
+
+ invoke-virtual {p1, v0}, Ljava/lang/Object;->equals(Ljava/lang/Object;)Z
+ invoke-virtual {p1, v0}, Ljava/lang/Object;->equals(Ljava/lang/Object;)Z # is this the swipe-previous event?
+
+ move-result p1
+
+ if-eqz p1, :unknown_event
+
+ invoke-interface {v3}, Lei/e;->canSkipToPreviousOrRewind()Z
+ invoke-interface {v3}, Lbi/e;->canSkipToPreviousOrRewind()Z
+
+ move-result p1
+
@@ -69,36 +86,41 @@
+
+ const/4 p1, 0x0
+
+ invoke-interface {v3, p1}, Lei/e;->h(Z)V # false = previous/rewind
+ invoke-interface {v3, p1}, Lbi/e;->h(Z)V # false = previous/rewind
+
+ :previous_done
+ return-void
+
+ :unknown_event
invoke-static {}, Landroidx/compose/ui/graphics/y;->b()V
invoke-static {}, Landroidx/navigation/f0;->a()V
.line 196
.line 197
.line 198
return-void
--- a/com/tidal/android/feature/appscaffold/ui/composable/e.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/e.smali
@@ -75,6 +75,18 @@
.line 22
:pswitch_0
+ invoke-static {}, Lradiant/MiniPlayerTrackGestures;->consumeTapOpenSuppression()Z # prevent tap open after horizontal swipe
--- a/com/tidal/android/feature/appscaffold/ui/composable/g.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/g.smali
@@ -24,12 +24,23 @@
# virtual methods
.method public final invoke()Ljava/lang/Object;
.locals 2
+ invoke-static {}, Lradiant/MiniPlayerTrackGestures;->consumeTapOpenSuppression()Z # skip open-player if a horizontal skip-swipe just happened
+
+ move-result v0
+
+ if-eqz v0, :continue_open
+ if-eqz v0, :rl_continue_open
+
+ sget-object v0, Lkotlin/u;->a:Lkotlin/u;
+
+ return-object v0
+
+ :continue_open
+
iget-object v0, p0, Lcom/tidal/android/feature/appscaffold/ui/composable/e;->b:Ljava/lang/Object;
+ :rl_continue_open
.line 1
iget-object v0, p0, Lcom/tidal/android/feature/appscaffold/ui/composable/g;->a:Lam0/l;
.line 23
.line 24
.line 2
.line 3
sget-object v1, Lcom/tidal/android/feature/appscaffold/ui/b$b;->a:Lcom/tidal/android/feature/appscaffold/ui/b$b;
+67 -48
View File
@@ -1,39 +1,32 @@
# rl-locals: com/tidal/android/feature/appscaffold/ui/composable/i.smali b( 52
--- a/com/tidal/android/feature/appscaffold/ui/composable/i.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/i.smali
@@ -2427,6 +2427,12 @@
move-object/from16 v16, v9
@@ -1691,6 +1691,14 @@
.line 99
+ 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
+
+ move-result-object v5
+
invoke-static {v15, v5}, Landroidx/compose/ui/ComposedModifierKt;->materializeModifier(Landroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
move-result-object v24
move-result-object v9
@@ -2832,2 +2838,8 @@
+ move-object/from16 v8, v25 # SheetState from AppScaffold
+ move-object/from16 v49, p5 # gesture expand lambda (AppScaffold Function1 param)
+
+ const/4 v10, __RL_MINI_PLAYER_SWIPE_UP_DRAG__ # Enable Drag option
+ move-object/from16 v50, v24 # SheetState
+
+ invoke-static {v6, v8, v10}, Lradiant/MiniPlayerGestures;->configure(Lyl0/l;Landroidx/compose/material3/SheetState;Z)V
+ const/16 v51, __RL_MINI_PLAYER_SWIPE_UP_DRAG__ # Enable Drag option
+
.line 150
sget-object v8, Lkotlin/u;->a:Lkotlin/u;
+ invoke-static/range {v49 .. v51}, Lradiant/MiniPlayerGestures;->configure(Lam0/l;Landroidx/compose/material3/SheetState;Z)V # wire swipe-up to expand the sheet
+
.line 69
invoke-static {}, Landroidx/compose/ui/platform/CompositionLocalsKt;->getLocalDensity()Landroidx/compose/runtime/ProvidableCompositionLocal;
--- a/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/MiniPlayerKt.smali
@@ -1243,5 +1243,21 @@
invoke-virtual {v0}, Ljava/lang/Object;->getClass()Ljava/lang/Class;
@@ -712,6 +712,22 @@
iget-object v3, v0, Lcom/tidal/android/feature/appscaffold/ui/s;->c:Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;
iget-object v3, v0, Lcom/tidal/android/feature/appscaffold/ui/t;->c:Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$PlayState;
+ iget-object v5, v0, Lcom/tidal/android/feature/appscaffold/ui/t;->a:Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$ItemType; # currently rendered mini player media type
+
+ iget-object v5, v0, Lcom/tidal/android/feature/appscaffold/ui/s;->a:Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$ItemType; # currently rendered mini player media type
+ sget-object v6, Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$ItemType;->Unknown:Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$ItemType; # Unknown = no media playing
+
+ sget-object v6, Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$ItemType;->Unknown:Lcom/tidal/android/feature/appscaffold/ui/MiniPlayerContract$ItemType; # Unknown = no media playing. other media types : Track, Video.
+
+ if-ne v5, v6, :rl_has_media # used to prevent swipe up when nothing is playing
+ if-ne v5, v6, :rl_has_media # prevent swipe up when nothing playing
+
+ const/4 v5, 0x0
+
@@ -44,69 +37,95 @@
+
+ :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 @@
const v4, -0x571456a1
@@ -1215,6 +1231,10 @@
move-result-object v6
+ 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)
@@ -1390,6 +1410,10 @@
move-result-object v6
+ invoke-static {v6}, Lradiant/MiniPlayerGestures;->feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move cover (swipe up feedback)
+
+ move-result-object v4
+ move-result-object v6
+
.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)
invoke-virtual/range {v22 .. v22}, Lcom/squareup/ui/market/core/theme/MarketStylesheet$c;->p0()Lf20/a;
@@ -1501,6 +1525,10 @@
move-result-object v5
+ invoke-static {v5}, Lradiant/MiniPlayerGestures;->feedbackModifier(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # move title/artist (swipe up feedback)
+
+ move-result-object v4
+ move-result-object v5
+
.line 72
invoke-virtual/range {p2 .. p2}, Landroidx/compose/foundation/layout/Arrangement;->getTop()Landroidx/compose/foundation/layout/Arrangement$Vertical;
invoke-virtual/range {v32 .. v32}, 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 @@
.line 22
.line 23
@@ -212,6 +212,12 @@
.line 24
iget-object p1, p0, Landroidx/compose/material3/ModalBottomSheetKt$ModalBottomSheet$4$1;->$sheetState:Landroidx/compose/material3/SheetState;
-
+ invoke-static {p1}, Lradiant/MiniPlayerGestures;->suppressAutoShow(Landroidx/compose/material3/SheetState;)Z # avoid Material3 show() taking over manual drag
+
+ move-result v1
+
+ if-nez v1, :skip_show
+
.line 25
.line 26
iput v2, p0, Landroidx/compose/material3/ModalBottomSheetKt$ModalBottomSheet$4$1;->label:I
@@ -231,7 +233,7 @@
.line 33
@@ -232,6 +238,7 @@
.line 34
return-object v0
-
+ :skip_show
.line 35
:cond_2
:goto_0
--- a/androidx/compose/material3/ModalBottomSheetKt.smali
+++ b/androidx/compose/material3/ModalBottomSheetKt.smali
@@ -1370,3 +1370,6 @@
@@ -1288,12 +1288,18 @@
.line 33
invoke-interface {v5, v12}, Landroidx/compose/runtime/Composer;->updateRememberedValue(Ljava/lang/Object;)V
.line 34
:cond_47
+ move-object v14, v12
+ check-cast v14, Lyl0/l;
+ invoke-static {v13, v14}, Lradiant/MiniPlayerGestures;->setSettleCallback(Landroidx/compose/material3/SheetState;Lyl0/l;)V # reuse native settle animation on release
+ move-object v14, v12 # settle callback
+
+ check-cast v14, Lam0/l; # to Function1
+
+ invoke-static {v13, v14}, Lradiant/MiniPlayerGestures;->setSettleCallback(Landroidx/compose/material3/SheetState;Lam0/l;)V # reuse native settle animation on release
+
move-object/from16 v32, v12
check-cast v32, Lam0/l;
.line 35
invoke-interface {v5}, Landroidx/compose/runtime/Composer;->rememberedValue()Ljava/lang/Object;
--- a/androidx/compose/material3/SheetDefaultsKt.smali
+++ b/androidx/compose/material3/SheetDefaultsKt.smali
@@ -100,6 +100,5 @@
@@ -98,7 +98,7 @@
const/4 v2, 0x0
.line 16
- const/16 v3, 0x12c
-
+ const/16 v3, 0x64 # 100ms
.line 17
.line 18
const/4 v4, 0x0
+24 -25
View File
@@ -20,48 +20,47 @@
.line 71
--- a/com/tidal/android/feature/appscaffold/ui/composable/i.smali
+++ b/com/tidal/android/feature/appscaffold/ui/composable/i.smali
@@ -2756,12 +2756,7 @@
invoke-static {v0, v8, v11, v12}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxWidth$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
@@ -2275,11 +2275,7 @@
move-result-object v0
move-result-object v2
- .line 143
- invoke-static {v2}, Landroidx/compose/foundation/layout/WindowInsetsPadding_androidKt;->navigationBarsPadding(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
-
- .line 140
- invoke-static {v0}, Landroidx/compose/foundation/layout/WindowInsetsPadding_androidKt;->navigationBarsPadding(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier;
-
- move-result-object v0
- move-result-object v2
-
+ # flush bottom; skip nav inset
.line 141
invoke-interface/range {v17 .. v17}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object;
.line 144
invoke-interface/range {v21 .. v21}, Landroidx/compose/runtime/State;->getValue()Ljava/lang/Object;
@@ -2773,6 +2768,8 @@
@@ -2291,6 +2287,8 @@
move-result v10
move-result v4
+ const/4 v10, 0x0 # zero horizontal padding
+ const/4 v4, 0x0 # zero horizontal padding
+
const/4 v11, 0x2
const/4 v6, 0x2
.line 142
@@ -2857,6 +2854,10 @@
.line 145
@@ -2375,6 +2373,10 @@
move-result-object v0
move-result-object v2
+ invoke-static {v0}, Landroidx/compose/foundation/layout/WindowInsetsPadding_androidKt;->navigationBarsPadding(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # inset bar content above nav bar (Prevents Bleeding behind Nav Buttons)
+ invoke-static {v2}, Landroidx/compose/foundation/layout/WindowInsetsPadding_androidKt;->navigationBarsPadding(Landroidx/compose/ui/Modifier;)Landroidx/compose/ui/Modifier; # inset bar content above nav bar (Prevents Bleeding behind Nav Buttons)
+
+ move-result-object v0
+ move-result-object v2
+
.line 155
sget-object v8, Landroidx/compose/foundation/layout/Arrangement;->INSTANCE:Landroidx/compose/foundation/layout/Arrangement;
.line 158
sget-object v3, Landroidx/compose/foundation/layout/Arrangement;->INSTANCE:Landroidx/compose/foundation/layout/Arrangement;
@@ -2969,6 +2970,10 @@
@@ -2487,6 +2489,10 @@
invoke-static {v12, v0, v8}, Landroidx/compose/runtime/Updater;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Lyl0/p;)V
invoke-static {v6, v2, v3}, Landroidx/compose/runtime/Updater;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Lam0/p;)V
+ const/4 v8, 0x0 # composer $changed flags
+
+ invoke-static {v15, v8}, Lradiant/MiniSeekerLine;->render(Landroidx/compose/runtime/Composer;I)V # draw top-edge seeker
+ invoke-static {v7, v8}, Lradiant/MiniSeekerLine;->render(Landroidx/compose/runtime/Composer;I)V # draw top-edge seeker
+
.line 172
sget-object v0, Landroidx/compose/foundation/layout/ColumnScopeInstance;->INSTANCE:Landroidx/compose/foundation/layout/ColumnScopeInstance;
.line 175
sget-object v2, Landroidx/compose/foundation/layout/ColumnScopeInstance;->INSTANCE:Landroidx/compose/foundation/layout/ColumnScopeInstance;
+121
View File
@@ -0,0 +1,121 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -4433,6 +4433,14 @@
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
+
+ const/16 v21, 0x1 # RL: isPlaying=true (Animated — always rotate)
+
+ const/16 v22, 0x0 # RL: isSeeking=false (Animated — ignore scrub)
+
+ invoke-static {}, Lradiant/HomeBackdrop;->setModeAnimated()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
--- a/com/tidal/android/core/ui/composable/c0.smali
+++ b/com/tidal/android/core/ui/composable/c0.smali
@@ -16,7 +16,9 @@
move-result p0
.line 5
- invoke-virtual {p2, p0}, Landroid/view/Window;->setNavigationBarColor(I)V
+ const/4 v3, 0x0 # RL: force transparent nav bar so the native blur backdrop shows through (was p0 = extracted BG color; luminance below still uses p0 for icon light/dark)
+
+ invoke-virtual {p2, v3}, Landroid/view/Window;->setNavigationBarColor(I)V
.line 6
.line 7
--- a/de0/c.smali
+++ b/de0/c.smali
@@ -26,29 +26,26 @@
.line 2
.line 3
.line 4
- const-string v0, "HeavyBlurTransformation() "
-
- .line 5
- .line 6
- const-string v1, " "
-
- .line 7
- .line 8
- const/4 v2, 0x6
-
- .line 9
- const/16 v3, 0x19
-
- .line 10
- .line 11
- invoke-static {v2, v3, v0, v1}, Landroidx/compose/foundation/text/input/a;->b(IILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-
- .line 12
- .line 13
- .line 14
+ new-instance v0, Ljava/lang/StringBuilder;
+ invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
+ const-string v1, "RLBackdrop_b"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const/16 v1, __RL_BLUR__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "c"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_CONTRAST__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "s"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_SATURATION__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "r"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_BRIGHTNESS__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
-
- .line 15
iput-object v0, p0, Lde0/c;->a:Ljava/lang/String;
.line 16
@@ -59,10 +56,17 @@
# virtual methods
.method public final a(Landroid/graphics/Bitmap;)Landroid/graphics/Bitmap;
- .locals 2
+ .locals 3
.line 1
- const/4 v0, 0x6
+ const/16 v2, __RL_BLUR__
+ mul-int/lit8 v0, v2, 0x6
+ const/16 v1, 0x32
+ div-int v0, v0, v1
+ const/4 v1, 0x1
+ if-ge v0, v1, :rl_ds_ok
+ const/4 v0, 0x1
+ :rl_ds_ok
.line 2
invoke-static {p1, v0}, Lcom/squareup/ui/market/layout/e;->c(Landroid/graphics/Bitmap;I)Landroid/graphics/Bitmap;
@@ -82,7 +86,7 @@
.line 9
.line 10
.line 11
- const/16 v1, 0x19
+ div-int/lit8 v1, v2, 0x2
.line 12
.line 13
@@ -93,6 +97,10 @@
.line 16
move-result-object v1
+ invoke-static {v1}, Lradiant/BackdropFx;->apply(Landroid/graphics/Bitmap;)Landroid/graphics/Bitmap;
+
+ move-result-object v1
+
.line 17
invoke-virtual {v0}, Landroid/graphics/Bitmap;->recycle()V
+117
View File
@@ -0,0 +1,117 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -4433,6 +4433,10 @@
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
--- a/com/tidal/android/core/ui/composable/c0.smali
+++ b/com/tidal/android/core/ui/composable/c0.smali
@@ -16,7 +16,9 @@
move-result p0
.line 5
- invoke-virtual {p2, p0}, Landroid/view/Window;->setNavigationBarColor(I)V
+ const/4 v3, 0x0 # RL: force transparent nav bar so the native blur backdrop shows through (was p0 = extracted BG color; luminance below still uses p0 for icon light/dark)
+
+ invoke-virtual {p2, v3}, Landroid/view/Window;->setNavigationBarColor(I)V
.line 6
.line 7
--- a/de0/c.smali
+++ b/de0/c.smali
@@ -26,29 +26,26 @@
.line 2
.line 3
.line 4
- const-string v0, "HeavyBlurTransformation() "
-
- .line 5
- .line 6
- const-string v1, " "
-
- .line 7
- .line 8
- const/4 v2, 0x6
-
- .line 9
- const/16 v3, 0x19
-
- .line 10
- .line 11
- invoke-static {v2, v3, v0, v1}, Landroidx/compose/foundation/text/input/a;->b(IILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-
- .line 12
- .line 13
- .line 14
+ new-instance v0, Ljava/lang/StringBuilder;
+ invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
+ const-string v1, "RLBackdrop_b"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const/16 v1, __RL_BLUR__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "c"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_CONTRAST__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "s"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_SATURATION__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "r"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_BRIGHTNESS__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
-
- .line 15
iput-object v0, p0, Lde0/c;->a:Ljava/lang/String;
.line 16
@@ -59,10 +56,17 @@
# virtual methods
.method public final a(Landroid/graphics/Bitmap;)Landroid/graphics/Bitmap;
- .locals 2
+ .locals 3
.line 1
- const/4 v0, 0x6
+ const/16 v2, __RL_BLUR__
+ mul-int/lit8 v0, v2, 0x6
+ const/16 v1, 0x32
+ div-int v0, v0, v1
+ const/4 v1, 0x1
+ if-ge v0, v1, :rl_ds_ok
+ const/4 v0, 0x1
+ :rl_ds_ok
.line 2
invoke-static {p1, v0}, Lcom/squareup/ui/market/layout/e;->c(Landroid/graphics/Bitmap;I)Landroid/graphics/Bitmap;
@@ -82,7 +86,7 @@
.line 9
.line 10
.line 11
- const/16 v1, 0x19
+ div-int/lit8 v1, v2, 0x2
.line 12
.line 13
@@ -93,6 +97,10 @@
.line 16
move-result-object v1
+ invoke-static {v1}, Lradiant/BackdropFx;->apply(Landroid/graphics/Bitmap;)Landroid/graphics/Bitmap;
+
+ move-result-object v1
+
.line 17
invoke-virtual {v0}, Landroid/graphics/Bitmap;->recycle()V
+121
View File
@@ -0,0 +1,121 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -4433,6 +4433,14 @@
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
+
+ const/16 v21, 0x0 # RL: isPlaying=false (Static — no rotation)
+
+ const/16 v22, 0x0 # RL: isSeeking=false (Static — no scrub rotation)
+
+ invoke-static {}, Lradiant/HomeBackdrop;->setModeStatic()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
--- a/com/tidal/android/core/ui/composable/c0.smali
+++ b/com/tidal/android/core/ui/composable/c0.smali
@@ -16,7 +16,9 @@
move-result p0
.line 5
- invoke-virtual {p2, p0}, Landroid/view/Window;->setNavigationBarColor(I)V
+ const/4 v3, 0x0 # RL: force transparent nav bar so the native blur backdrop shows through (was p0 = extracted BG color; luminance below still uses p0 for icon light/dark)
+
+ invoke-virtual {p2, v3}, Landroid/view/Window;->setNavigationBarColor(I)V
.line 6
.line 7
--- a/de0/c.smali
+++ b/de0/c.smali
@@ -26,29 +26,26 @@
.line 2
.line 3
.line 4
- const-string v0, "HeavyBlurTransformation() "
-
- .line 5
- .line 6
- const-string v1, " "
-
- .line 7
- .line 8
- const/4 v2, 0x6
-
- .line 9
- const/16 v3, 0x19
-
- .line 10
- .line 11
- invoke-static {v2, v3, v0, v1}, Landroidx/compose/foundation/text/input/a;->b(IILjava/lang/String;Ljava/lang/String;)Ljava/lang/String;
-
- .line 12
- .line 13
- .line 14
+ new-instance v0, Ljava/lang/StringBuilder;
+ invoke-direct {v0}, Ljava/lang/StringBuilder;-><init>()V
+ const-string v1, "RLBackdrop_b"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const/16 v1, __RL_BLUR__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "c"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_CONTRAST__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "s"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_SATURATION__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ const-string v1, "r"
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+ const v1, __RL_BRIGHTNESS__
+ invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
+ invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
-
- .line 15
iput-object v0, p0, Lde0/c;->a:Ljava/lang/String;
.line 16
@@ -59,10 +56,17 @@
# virtual methods
.method public final a(Landroid/graphics/Bitmap;)Landroid/graphics/Bitmap;
- .locals 2
+ .locals 3
.line 1
- const/4 v0, 0x6
+ const/16 v2, __RL_BLUR__
+ mul-int/lit8 v0, v2, 0x6
+ const/16 v1, 0x32
+ div-int v0, v0, v1
+ const/4 v1, 0x1
+ if-ge v0, v1, :rl_ds_ok
+ const/4 v0, 0x1
+ :rl_ds_ok
.line 2
invoke-static {p1, v0}, Lcom/squareup/ui/market/layout/e;->c(Landroid/graphics/Bitmap;I)Landroid/graphics/Bitmap;
@@ -82,7 +86,7 @@
.line 9
.line 10
.line 11
- const/16 v1, 0x19
+ div-int/lit8 v1, v2, 0x2
.line 12
.line 13
@@ -93,6 +97,10 @@
.line 16
move-result-object v1
+ invoke-static {v1}, Lradiant/BackdropFx;->apply(Landroid/graphics/Bitmap;)Landroid/graphics/Bitmap;
+
+ move-result-object v1
+
.line 17
invoke-virtual {v0}, Landroid/graphics/Bitmap;->recycle()V
-152
View File
@@ -1,152 +0,0 @@
# rl-locals: com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali e( 71
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -4172,6 +4172,148 @@
invoke-static {v5, v3, v4}, Landroidx/compose/runtime/Updater;->set-impl(Landroidx/compose/runtime/Composer;Ljava/lang/Object;Lyl0/p;)V
+ const v3, 0x52414449 # slot table key
+
+ invoke-interface {v10, v3}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V # open group
+
+ move-object/from16 v3, p3 # player state
+
+ iget-object v3, v3, Lcom/tidal/android/feature/playerscreen/ui/r$a;->c:Lcom/tidal/android/feature/playerscreen/ui/d; # cover pager
+
+ iget-object v4, v3, Lcom/tidal/android/feature/playerscreen/ui/d;->a:Ltn0/b; # item list
+
+ iget v5, v3, Lcom/tidal/android/feature/playerscreen/ui/d;->b:I # current index
+
+ invoke-interface {v4}, Ljava/util/List;->size()I # list size
+
+ move-result v6 # size value
+
+ if-le v6, v5, :radiant_skip # bounds check
+
+ if-ltz v5, :radiant_skip # negative check
+
+ invoke-interface {v4, v5}, Ljava/util/List;->get(I)Ljava/lang/Object; # current item
+
+ move-result-object v4 # current item
+
+ instance-of v6, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a; # still album cover?
+
+ if-eqz v6, :radiant_try_animated # if not, try animated album cover
+
+ check-cast v4, Lcom/tidal/android/feature/playerscreen/ui/c$a; # narrow type
+
+ iget v5, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a;->b:I # album id
+
+ iget-object v4, v4, Lcom/tidal/android/feature/playerscreen/ui/c$a;->c:Ljava/lang/String; # cover uuid
+
+ goto :radiant_have_cover # cover resolved
+
+ :radiant_try_animated # animated album cover (c$b) shares albumId/cover layout
+ instance-of v6, v4, Lcom/tidal/android/feature/playerscreen/ui/c$b; # animated album cover?
+
+ if-eqz v6, :radiant_skip # neither -> skip (music video / unknown)
+
+ check-cast v4, Lcom/tidal/android/feature/playerscreen/ui/c$b; # narrow type
+
+ iget v5, v4, Lcom/tidal/android/feature/playerscreen/ui/c$b;->b:I # album id
+
+ iget-object v4, v4, Lcom/tidal/android/feature/playerscreen/ui/c$b;->c:Ljava/lang/String; # still cover uuid (blur this)
+
+ :radiant_have_cover # v5 = album id, v4 = cover uuid
+
+ new-instance v6, Lcom/tidal/android/feature/playerscreen/ui/composables/n0; # cover request lambda
+
+ invoke-direct {v6, v5, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/n0;-><init>(ILjava/lang/String;)V # build request
+
+ sget-object v5, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion; # base modifier
+
+ const/4 v7, 0x0 # fraction unused
+
+ const/4 v8, 0x1 # default fraction
+
+ const/4 v3, 0x0 # synthetic null
+
+ invoke-static {v5, v7, v8, v3}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier; # fill the player root
+
+ move-result-object v5 # filled modifier
+
+ const v7, __RL_BLUR_BITS__ # blur dp bits (Advanced Options: Blur Strength)
+
+ invoke-static {v7}, Landroidx/compose/ui/unit/Dp;->constructor-impl(F)F # to Dp
+
+ move-result v7 # blur dp value
+
+ sget-object v8, Landroidx/compose/ui/draw/BlurredEdgeTreatment;->Companion:Landroidx/compose/ui/draw/BlurredEdgeTreatment$Companion; # blur edge companion
+
+ invoke-virtual {v8}, Landroidx/compose/ui/draw/BlurredEdgeTreatment$Companion;->getRectangle---Goahg()Landroidx/compose/ui/graphics/Shape; # rectangle treatment
+
+ move-result-object v8 # edge shape
+
+ invoke-static {v5, v7, v8}, Landroidx/compose/ui/draw/BlurKt;->blur-F8QBwvs(Landroidx/compose/ui/Modifier;FLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier; # apply blur
+
+ move-result-object v5 # blurred modifier
+
+ sget-object v7, Landroidx/compose/ui/layout/ContentScale;->Companion:Landroidx/compose/ui/layout/ContentScale$Companion; # scale companion
+
+ invoke-virtual {v7}, Landroidx/compose/ui/layout/ContentScale$Companion;->getCrop()Landroidx/compose/ui/layout/ContentScale; # cover-crop scaling
+
+ move-result-object v7 # crop scale
+
+ move-object/from16 v61, v6 # request
+
+ const/16 v62, 0x0 # contentDescription
+
+ move-object/from16 v63, v5 # blurred modifier
+
+ const/16 v64, 0x0 # colorFilter
+
+ move-object/from16 v65, v7 # contentScale
+
+ move-object/from16 v66, v4 # cover uuid
+
+ const/16 v67, 0x0 # null onError
+
+ move-object/from16 v68, v10 # composer
+
+ const/16 v69, 0x0 # changed flags
+
+ const/16 v70, 0x48 # default mask
+
+ invoke-static/range {v61 .. v70}, Lxd0/f;->a(Lyl0/l;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/ColorFilter;Landroidx/compose/ui/layout/ContentScale;Ljava/lang/Object;Lyl0/a;Landroidx/compose/runtime/Composer;II)V # render blurred cover
+
+ sget-object v3, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion; # scrim chain start
+
+ const/4 v4, 0x0 # fraction unused
+
+ const/4 v5, 0x1 # default mask
+
+ const/4 v6, 0x0 # null obj
+
+ invoke-static {v3, v4, v5, v6}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxSize$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier; # fill screen
+
+ move-result-object v3 # fullscreen modifier
+
+ const v6, __RL_SCRIM_ARGB__ # scrim ARGB (Advanced Options: Backdrop Dimming)
+
+ invoke-static {v6}, Landroidx/compose/ui/graphics/ColorKt;->Color(I)J # pack color long
+
+ move-result-wide v6 # color long
+
+ invoke-static {}, Landroidx/compose/ui/graphics/RectangleShapeKt;->getRectangleShape()Landroidx/compose/ui/graphics/Shape; # rect shape
+
+ move-result-object v4 # rect shape
+
+ invoke-static {v3, v6, v7, v4}, Landroidx/compose/foundation/BackgroundKt;->background-bw27NRU(Landroidx/compose/ui/Modifier;JLandroidx/compose/ui/graphics/Shape;)Landroidx/compose/ui/Modifier; # tint with scrim
+
+ move-result-object v3 # tinted modifier
+
+ const/4 v4, 0x0 # changed flags
+
+ invoke-static {v3, v10, v4}, Landroidx/compose/foundation/layout/SpacerKt;->Spacer(Landroidx/compose/ui/Modifier;Landroidx/compose/runtime/Composer;I)V # draw scrim
+
+ :radiant_skip # skip target
+ invoke-interface {v10}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V # close group
+
.line 138
sget-object v3, Landroidx/compose/foundation/layout/BoxScopeInstance;->INSTANCE:Landroidx/compose/foundation/layout/BoxScopeInstance;
+16 -16
View File
@@ -1,24 +1,24 @@
--- a/com/tidal/android/feature/playerscreen/ui/composables/c1.smali
+++ b/com/tidal/android/feature/playerscreen/ui/composables/c1.smali
@@ -259,7 +259,7 @@
@@ -300,7 +300,7 @@
.line 109
.line 110
- sget p2, Lcom/tidal/android/feature/playerscreen/ui/R$drawable;->ic_circle_checked:I
+ sget p2, Lcom/tidal/android/feature/playerscreen/ui/R$drawable;->ic_shapes_heart_filled_medium:I # favorited: filled heart (was circle-check)
.line 128
.line 129
- sget v0, Lcom/tidal/android/feature/playerscreen/ui/R$drawable;->ic_circle_checked:I
+ sget v0, Lcom/tidal/android/feature/playerscreen/ui/R$drawable;->ic_shapes_heart_filled_medium:I # favorited: filled heart (was circle-check)
.line 111
.line 112
@@ -267,11 +267,7 @@
.line 130
.line 131
@@ -308,11 +308,7 @@
.line 113
.line 132
:cond_5
- sget-object p2, Lx20/b;->O:Lx20/a;
- sget-object v0, La30/b;->O:La30/a;
-
- .line 114
- .line 115
- iget p2, p2, Lx20/a;->a:I
+ sget p2, Lcom/tidal/android/feature/playerscreen/ui/R$drawable;->ic_shapes_heart_medium:I # not favorited: outline heart (was market plus)
- .line 133
- .line 134
- iget v0, v0, La30/a;->a:I
+ sget v0, Lcom/tidal/android/feature/playerscreen/ui/R$drawable;->ic_shapes_heart_medium:I # not favorited: outline heart (was market plus)
.line 116
.line 117
.line 135
.line 136
+11
View File
@@ -0,0 +1,11 @@
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -5970,6 +5970,8 @@
.line 365
iget-object v3, v11, Lcom/tidal/android/feature/playerscreen/ui/s$a;->m:Lcom/tidal/android/feature/playerscreen/ui/p;
+ const/4 v3, 0x0 # Never show the "Playing from" source at the bottom (relocated above the title, or hidden when off)
+
if-nez v3, :cond_5a
const v3, 0x26ba353b
+68
View File
@@ -0,0 +1,68 @@
# rl-locals: com/tidal/android/feature/playerscreen/ui/composables/n2.smali a( 45
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -5202,6 +5202,20 @@
.line 262
:goto_21
+ iget-object v7, v5, Lcom/tidal/android/feature/playerscreen/ui/s$a;->m:Lcom/tidal/android/feature/playerscreen/ui/p; # RL move-playing-from: SourceLabel — published in BOTH cover & lyrics view (may be null)
+
+ if-eqz v7, :rl_pf_null # no source -> clear
+
+ iget-object v7, v7, Lcom/tidal/android/feature/playerscreen/ui/p;->a:Ljava/lang/String; # sourceName
+
+ goto :rl_pf_set
+
+ :rl_pf_null
+ const/4 v7, 0x0
+
+ :rl_pf_set
+ sput-object v7, Lradiant/PlayingFrom;->a:Ljava/lang/String; # publish for n2 (rendered above the title)
+
iget-object v7, v5, Lcom/tidal/android/feature/playerscreen/ui/s$a;->c:Lcom/tidal/android/feature/playerscreen/ui/d;
.line 263
--- a/com/tidal/android/feature/playerscreen/ui/composables/n2.smali
+++ b/com/tidal/android/feature/playerscreen/ui/composables/n2.smali
@@ -674,6 +674,41 @@
:cond_1e
check-cast v3, Lq20/c2;
+ move-object/from16 v33, v1 # RL: composer held stable for the conditional group
+
+ const v34, 0x52414450 # RL group key
+
+ invoke-interface/range {v33 .. v34}, Landroidx/compose/runtime/Composer;->startReplaceGroup(I)V
+
+ sget-object v34, Lradiant/PlayingFrom;->a:Ljava/lang/String; # RL: published "Playing from" source name
+
+ if-eqz v34, :rl_pf_skip # no source -> render nothing above the title
+
+ sget-object v35, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion;
+
+ const/16 v36, 0x1 # maxLines = 1
+
+ const/16 v37, 0x0
+
+ const/16 v38, 0x0
+
+ const/16 v39, 0x0
+
+ const/16 v40, 0x0
+
+ move-object/from16 v41, v3 # reuse the artist PARAGRAPH_30 style (same colour + size)
+
+ move-object/from16 v42, v1 # composer
+
+ const/16 v43, 0x0
+
+ const/16 v44, 0x78 # default-arg mask (matches the artist MarketLabel.e call)
+
+ invoke-static/range {v34 .. v44}, Lcom/squareup/ui/market/components/MarketLabelKt;->e(Ljava/lang/String;Landroidx/compose/ui/Modifier;IILcom/squareup/ui/market/text/a;Landroidx/compose/foundation/interaction/MutableInteractionSource;Lam0/l;Lq20/c2;Landroidx/compose/runtime/Composer;II)V
+
+ :rl_pf_skip
+ invoke-interface/range {v33 .. v33}, Landroidx/compose/runtime/Composer;->endReplaceGroup()V
+
.line 43
sget-object v17, Landroidx/compose/ui/Modifier;->Companion:Landroidx/compose/ui/Modifier$Companion;
+8 -20
View File
@@ -1,12 +1,9 @@
# rl-locals: com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali e( 80
--- a/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerScreenKt.smali
@@ -5650,12 +5650,26 @@
invoke-static {v2, v15, v7, v9}, Lcom/aspiro/wamp/dynamicpages/ui/compose/f;->a(FLandroidx/compose/ui/Modifier$Companion;Landroidx/compose/runtime/Composer;I)V
@@ -5755,6 +5755,20 @@
const/4 v2, 0x0
const/4 v9, 0x0
const/4 v8, 0x0
+ invoke-static {}, Landroidx/compose/ui/platform/CompositionLocalsKt;->getLocalLayoutDirection()Landroidx/compose/runtime/ProvidableCompositionLocal; # layout-direction local
+
@@ -22,24 +19,15 @@
+
+ invoke-interface/range {v76 .. v77}, Landroidx/compose/runtime/Composer;->startProvider(Landroidx/compose/runtime/ProvidedValue;)V # open Rtl scope (mirror row)
+
.line 302
invoke-static {v15, v9, v1, v2}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxWidth$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
.line 335
invoke-static {v1, v8, v14, v3}, Landroidx/compose/foundation/layout/SizeKt;->fillMaxWidth$default(Landroidx/compose/ui/Modifier;FILjava/lang/Object;)Landroidx/compose/ui/Modifier;
move-result-object v4
move/from16 v5, v58
@@ -6001,12 +6015,14 @@
invoke-static {v13, v7, v2, v4}, Lcom/tidal/android/feature/playerscreen/ui/composables/m0;->a(ILandroidx/compose/runtime/Composer;Landroidx/compose/ui/Modifier;Lyl0/a;)V
.line 343
@@ -6221,6 +6235,8 @@
.line 393
invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endNode()V
+ invoke-interface {v7}, Landroidx/compose/runtime/Composer;->endProvider()V # close Rtl scope (end mirror)
+
.line 344
invoke-static/range {v40 .. v40}, Landroidx/compose/ui/unit/Dp;->constructor-impl(F)F
.line 394
invoke-static/range {v41 .. v41}, Landroidx/compose/ui/unit/Dp;->constructor-impl(F)F
move-result v20
const/16 v21, 0x7
+30 -29
View File
@@ -2,7 +2,7 @@
+++ b/com/tidal/android/feature/playerscreen/ui/composables/SeekbarAndTimeKt.smali
@@ -372,6 +372,10 @@
.line 158
sget v4, Lcom/tidal/android/feature/playerscreen/ui/composables/o4;->g:F
sget v4, Lcom/tidal/android/feature/playerscreen/ui/composables/t4;->g:F
+ const/high16 v11, 0x40000000 # 2.0f
+
@@ -30,7 +30,7 @@
+
+ move-object/from16 v3, p1
+
+ invoke-static {v13, v3}, Lradiant/QualityBadge;->style(ILn20/e2;)Ln20/e2;
+ invoke-static {v13, v3}, Lradiant/QualityBadge;->style(ILq20/c2;)Lq20/c2;
+
+ move-result-object v8
+
@@ -72,45 +72,46 @@
return-void
--- a/com/tidal/android/feature/playerscreen/ui/PlayerViewModel$special$$inlined$mapNotNull$1$2.smali
+++ b/com/tidal/android/feature/playerscreen/ui/PlayerViewModel$special$$inlined$mapNotNull$1$2.smali
@@ -1356,6 +1356,14 @@
.line 617
- move-result v10
+ move-result v10 # isCurrentStreamHiResLosslessQuality() result
@@ -1452,7 +1452,15 @@
.line 662
.line 663
.line 664
- move-result v8
+ move-result v8 # isCurrentStreamHiResLosslessQuality() result
+
+ const/16 v31, 0x0 # LOW / HIGH quality
+
+ if-eqz v10, :radiant_qbc_not_hires
+ if-eqz v8, :radiant_qbc_not_hires
+
+ const/16 v31, 0x2 # HI_RES_LOSSLESS quality
+
+ :radiant_qbc_not_hires
.line 665
if-nez v8, :cond_1f
@@ -1464,7 +1472,13 @@
.line 668
.line 669
.line 670
- move-result v8
+ move-result v8 # isCurrentStreamLossless() result
+
.line 618
if-nez v10, :cond_19
@@ -1368,6 +1376,12 @@
.line 623
- move-result v10
+ move-result v10 # isCurrentStreamLossless() result
+ if-eqz v10, :radiant_qbc_not_lossless
+ if-eqz v8, :radiant_qbc_not_lossless
+
+ const/16 v31, 0x1 # LOSSLESS quality
+
+ :radiant_qbc_not_lossless
+
.line 624
if-eqz v10, :cond_18
@@ -1695,7 +1709,10 @@
.line 671
if-eqz v8, :cond_1e
@@ -1793,7 +1807,9 @@
.line 771
.line 772
- invoke-direct {v8, v5}, Lcom/tidal/android/feature/playerscreen/ui/i$a;-><init>(Ljava/lang/String;)V
+ move/from16 v10, v31 # quality
+
+ invoke-direct {v8, v5, v10}, Lcom/tidal/android/feature/playerscreen/ui/i$a;-><init>(Ljava/lang/String;I)V
.line 818
.line 819
- invoke-direct {v5, v4}, Lcom/tidal/android/feature/playerscreen/ui/i$a;-><init>(Ljava/lang/String;)V
+ move/from16 v9, v31 # quality
+
+ invoke-direct {v5, v4, v9}, Lcom/tidal/android/feature/playerscreen/ui/i$a;-><init>(Ljava/lang/String;I)V
.line 773
.line 774
.line 820
.line 821