fix(Spotify): Hide Create button patch failing in edge cases (#5131)

This commit is contained in:
Nuckyz
2025-06-06 18:11:32 -03:00
committed by GitHub
parent 966a78bd81
commit 7a432e5741
2 changed files with 105 additions and 29 deletions

View File

@@ -3,23 +3,29 @@ package app.revanced.extension.spotify.layout.hide.createbutton;
import java.util.List; import java.util.List;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.spotify.shared.ComponentFilters.*;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class HideCreateButtonPatch { public final class HideCreateButtonPatch {
/** /**
* A list of ids of resources which contain the Create button title. * A list of component filters that match whether a navigation bar item is the Create button.
* The main approach used is matching the resource id for the Create button title.
*/ */
private static final List<String> CREATE_BUTTON_TITLE_RES_ID_LIST = List.of( private static final List<ComponentFilter> CREATE_BUTTON_COMPONENT_FILTERS = List.of(
Integer.toString(Utils.getResourceIdentifier("navigationbar_musicappitems_create_title", "string")) new ResourceIdComponentFilter("navigationbar_musicappitems_create_title", "string"),
// Temporary fallback and fix for APKs merged with AntiSplit-M not having resources properly encoded,
// and thus getting the resource identifier for the Create button title always return 0.
// FIXME: Remove this once the above issue is no longer relevant.
new StringComponentFilter("spotify:create-menu")
); );
/** /**
* The old id of the resource which contained the Create button title. Used in older versions of the app. * A component filter for the old id of the resource which contained the Create button title.
* Used in older versions of the app.
*/ */
private static final int OLD_CREATE_BUTTON_TITLE_RES_ID = private static final ResourceIdComponentFilter OLD_CREATE_BUTTON_COMPONENT_FILTER =
Utils.getResourceIdentifier("bottom_navigation_bar_create_tab_title", "string"); new ResourceIdComponentFilter("bottom_navigation_bar_create_tab_title", "string");
/** /**
* Injection point. This method is called on every navigation bar item to check whether it is the Create button. * Injection point. This method is called on every navigation bar item to check whether it is the Create button.
@@ -33,28 +39,20 @@ public final class HideCreateButtonPatch {
String stringifiedNavigationBarItem = navigationBarItem.toString(); String stringifiedNavigationBarItem = navigationBarItem.toString();
boolean isCreateButton = false; for (ComponentFilter componentFilter : CREATE_BUTTON_COMPONENT_FILTERS) {
String matchedTitleResId = null; if (componentFilter.filterUnavailable()) {
Logger.printInfo(() -> "returnNullIfIsCreateButton: Filter " +
for (String titleResId : CREATE_BUTTON_TITLE_RES_ID_LIST) { componentFilter.getFilterRepresentation() + " not available, skipping");
// In case the resource id has not been found.
if (titleResId.equals("0")) {
continue; continue;
} }
if (stringifiedNavigationBarItem.contains(titleResId)) { if (stringifiedNavigationBarItem.contains(componentFilter.getFilterValue())) {
isCreateButton = true; Logger.printInfo(() -> "Hiding Create button because the navigation bar item " + navigationBarItem +
matchedTitleResId = titleResId; " matched the filter " + componentFilter.getFilterRepresentation());
return null;
} }
} }
if (isCreateButton) {
String finalMatchedTitleResId = matchedTitleResId;
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " + navigationBarItem +
" matched the title resource id " + finalMatchedTitleResId);
return null;
}
return navigationBarItem; return navigationBarItem;
} }
@@ -63,16 +61,15 @@ public final class HideCreateButtonPatch {
* Create button. * Create button.
*/ */
public static boolean isOldCreateButton(int oldNavigationBarItemTitleResId) { public static boolean isOldCreateButton(int oldNavigationBarItemTitleResId) {
// In case the resource id has not been found. if (OLD_CREATE_BUTTON_COMPONENT_FILTER.filterUnavailable()) {
if (OLD_CREATE_BUTTON_TITLE_RES_ID == 0) { Logger.printInfo(() -> "Skipping hiding old Create button because the resource id for " +
OLD_CREATE_BUTTON_COMPONENT_FILTER.resourceName + " is not available");
return false; return false;
} }
boolean isCreateButton = oldNavigationBarItemTitleResId == OLD_CREATE_BUTTON_TITLE_RES_ID; if (oldNavigationBarItemTitleResId == OLD_CREATE_BUTTON_COMPONENT_FILTER.getResourceId()) {
if (isCreateButton) {
Logger.printInfo(() -> "Hiding old Create button because the navigation bar item title resource id" + Logger.printInfo(() -> "Hiding old Create button because the navigation bar item title resource id" +
" matched " + OLD_CREATE_BUTTON_TITLE_RES_ID); " matched " + OLD_CREATE_BUTTON_COMPONENT_FILTER.getFilterRepresentation());
return true; return true;
} }

View File

@@ -0,0 +1,79 @@
package app.revanced.extension.spotify.shared;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
public final class ComponentFilters {
public interface ComponentFilter {
String getFilterValue();
String getFilterRepresentation();
default boolean filterUnavailable() {
return false;
}
}
public static final class ResourceIdComponentFilter implements ComponentFilter {
public final String resourceName;
public final String resourceType;
// Android resources are always positive, so -1 is a valid sentinel value to indicate it has not been loaded.
// 0 is returned when a resource has not been found.
private int resourceId = -1;
private String stringfiedResourceId = null;
public ResourceIdComponentFilter(String resourceName, String resourceType) {
this.resourceName = resourceName;
this.resourceType = resourceType;
}
public int getResourceId() {
if (resourceId == -1) {
resourceId = Utils.getResourceIdentifier(resourceName, resourceType);
}
return resourceId;
}
@Override
public String getFilterValue() {
if (stringfiedResourceId == null) {
stringfiedResourceId = Integer.toString(getResourceId());
}
return stringfiedResourceId;
}
@Override
public String getFilterRepresentation() {
boolean resourceFound = getResourceId() != 0;
return (resourceFound ? getFilterValue() + " (" : "") + resourceName + (resourceFound ? ")" : "");
}
@Override
public boolean filterUnavailable() {
boolean resourceNotFound = getResourceId() == 0;
if (resourceNotFound) {
Logger.printInfo(() -> "Resource id for " + resourceName + " was not found");
}
return resourceNotFound;
}
}
public static final class StringComponentFilter implements ComponentFilter {
public final String string;
public StringComponentFilter(String string) {
this.string = string;
}
@Override
public String getFilterValue() {
return string;
}
@Override
public String getFilterRepresentation() {
return string;
}
}
}