feat(Strava): Add Hide distractions patch (#6479)

Co-authored-by: Pun Butrach <pun.butrach@gmail.com>
Co-authored-by: ekaunt <62402760+ekaunt@users.noreply.github.com>
Co-authored-by: bengross <bengross@vecta.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
This commit is contained in:
xehpuk 2026-01-22 19:29:33 +01:00 committed by oSumAtrIX
parent 421cb2899e
commit 66b0852f8f
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
16 changed files with 601 additions and 56 deletions

View file

@ -0,0 +1,227 @@
package app.revanced.extension.strava;
import android.annotation.SuppressLint;
import com.strava.modularframework.data.Destination;
import com.strava.modularframework.data.GenericLayoutModule;
import com.strava.modularframework.data.GenericModuleField;
import com.strava.modularframework.data.ListField;
import com.strava.modularframework.data.ListProperties;
import com.strava.modularframework.data.ModularComponent;
import com.strava.modularframework.data.ModularEntry;
import com.strava.modularframework.data.ModularEntryContainer;
import com.strava.modularframework.data.ModularMenuItem;
import com.strava.modularframework.data.Module;
import com.strava.modularframework.data.MultiStateFieldDescriptor;
import com.strava.modularframeworknetwork.ModularEntryNetworkContainer;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@SuppressLint("NewApi")
public class HideDistractionsPatch {
public static boolean upselling;
public static boolean promo;
public static boolean followSuggestions;
public static boolean challengeSuggestions;
public static boolean joinChallenge;
public static boolean joinClub;
public static boolean activityLookback;
public static List<ModularEntry> filterChildrenEntries(ModularEntry modularEntry) {
if (hideModularEntry(modularEntry)) {
return Collections.emptyList();
}
return modularEntry.getChildrenEntries$original().stream()
.filter(childrenEntry -> !hideModularEntry(childrenEntry))
.collect(Collectors.toList());
}
public static List<ModularEntry> filterEntries(ModularEntryContainer modularEntryContainer) {
if (hideModularEntryContainer(modularEntryContainer)) {
return Collections.emptyList();
}
return modularEntryContainer.getEntries$original().stream()
.filter(entry -> !hideModularEntry(entry))
.collect(Collectors.toList());
}
public static List<ModularEntry> filterEntries(ModularEntryNetworkContainer modularEntryNetworkContainer) {
if (hideModularEntryNetworkContainer(modularEntryNetworkContainer)) {
return Collections.emptyList();
}
return modularEntryNetworkContainer.getEntries$original().stream()
.filter(entry -> !hideModularEntry(entry))
.collect(Collectors.toList());
}
public static List<ModularMenuItem> filterMenuItems(ModularEntryContainer modularEntryContainer) {
if (hideModularEntryContainer(modularEntryContainer)) {
return Collections.emptyList();
}
return modularEntryContainer.getMenuItems$original().stream()
.filter(menuItem -> !hideModularMenuItem(menuItem))
.collect(Collectors.toList());
}
public static ListProperties filterProperties(ModularEntryContainer modularEntryContainer) {
if (hideModularEntryContainer(modularEntryContainer)) {
return null;
}
return modularEntryContainer.getProperties$original();
}
public static ListProperties filterProperties(ModularEntryNetworkContainer modularEntryNetworkContainer) {
if (hideModularEntryNetworkContainer(modularEntryNetworkContainer)) {
return null;
}
return modularEntryNetworkContainer.getProperties$original();
}
public static ListField filterField(ListProperties listProperties, String key) {
ListField listField = listProperties.getField$original(key);
if (hideListField(listField)) {
return null;
}
return listField;
}
public static List<ListField> filterFields(ListField listField) {
if (hideListField(listField)) {
return null;
}
return listField.getFields$original().stream()
.filter(field -> !hideListField(field))
.collect(Collectors.toList());
}
public static List<Module> filterModules(ModularEntry modularEntry) {
if (hideModularEntry(modularEntry)) {
return Collections.emptyList();
}
return modularEntry.getModules$original().stream()
.filter(module -> !hideModule(module))
.collect(Collectors.toList());
}
public static GenericModuleField filterField(GenericLayoutModule genericLayoutModule, String key) {
if (hideGenericLayoutModule(genericLayoutModule)) {
return null;
}
GenericModuleField field = genericLayoutModule.getField$original(key);
if (hideGenericModuleField(field)) {
return null;
}
return field;
}
public static GenericModuleField[] filterFields(GenericLayoutModule genericLayoutModule) {
if (hideGenericLayoutModule(genericLayoutModule)) {
return new GenericModuleField[0];
}
return Arrays.stream(genericLayoutModule.getFields$original())
.filter(field -> !hideGenericModuleField(field))
.toArray(GenericModuleField[]::new);
}
public static GenericLayoutModule[] filterSubmodules(GenericLayoutModule genericLayoutModule) {
if (hideGenericLayoutModule(genericLayoutModule)) {
return new GenericLayoutModule[0];
}
return Arrays.stream(genericLayoutModule.getSubmodules$original())
.filter(submodule -> !hideGenericLayoutModule(submodule))
.toArray(GenericLayoutModule[]::new);
}
public static List<Module> filterSubmodules(ModularComponent modularComponent) {
if (hideByName(modularComponent.getPage()) || hideByName(modularComponent.getElement())) {
return Collections.emptyList();
}
return modularComponent.getSubmodules$original().stream()
.filter(submodule -> !hideModule(submodule))
.collect(Collectors.toList());
}
public static Map<String, GenericModuleField> filterStateMap(MultiStateFieldDescriptor multiStateFieldDescriptor) {
return multiStateFieldDescriptor.getStateMap$original().entrySet().stream()
.filter(entry -> !hideGenericModuleField(entry.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private static boolean hideModule(Module module) {
return module == null ||
hideByName(module.getPage()) ||
hideByName(module.getElement());
}
private static boolean hideModularEntry(ModularEntry modularEntry) {
return modularEntry == null ||
hideByName(modularEntry.getPage()) ||
hideByName(modularEntry.getElement()) ||
hideByDestination(modularEntry.getDestination());
}
private static boolean hideGenericLayoutModule(GenericLayoutModule genericLayoutModule) {
try {
return genericLayoutModule == null ||
hideByName(genericLayoutModule.getPage()) ||
hideByName(genericLayoutModule.getElement()) ||
hideByDestination(genericLayoutModule.getDestination());
} catch (RuntimeException getParentEntryOrThrowException) {
return false;
}
}
private static boolean hideListField(ListField listField) {
return listField == null ||
hideByName(listField.getElement()) ||
hideByDestination(listField.getDestination());
}
private static boolean hideGenericModuleField(GenericModuleField genericModuleField) {
return genericModuleField == null ||
hideByName(genericModuleField.getElement()) ||
hideByDestination(genericModuleField.getDestination());
}
private static boolean hideModularEntryContainer(ModularEntryContainer modularEntryContainer) {
return modularEntryContainer == null ||
hideByName(modularEntryContainer.getPage());
}
private static boolean hideModularEntryNetworkContainer(ModularEntryNetworkContainer modularEntryNetworkContainer) {
return modularEntryNetworkContainer == null ||
hideByName(modularEntryNetworkContainer.getPage());
}
private static boolean hideModularMenuItem(ModularMenuItem modularMenuItem) {
return modularMenuItem == null ||
hideByName(modularMenuItem.getElementName()) ||
hideByDestination(modularMenuItem.getDestination());
}
private static boolean hideByName(String name) {
return name != null && (
upselling && name.contains("_upsell") ||
promo && (name.equals("promo") || name.equals("top_of_tab_promo")) ||
followSuggestions && name.equals("suggested_follows") ||
challengeSuggestions && name.equals("suggested_challenges") ||
joinChallenge && name.equals("challenge") ||
joinClub && name.equals("club") ||
activityLookback && name.equals("highlighted_activity_lookback")
);
}
private static boolean hideByDestination(Destination destination) {
if (destination == null) {
return false;
}
String url = destination.getUrl();
return url != null && (
upselling && url.startsWith("strava://subscription/checkout")
);
}
}

View file

@ -0,0 +1,7 @@
package com.strava.modularframework.data;
import java.io.Serializable;
public abstract class Destination implements Serializable {
public abstract String getUrl();
}

View file

@ -0,0 +1,28 @@
package com.strava.modularframework.data;
import java.io.Serializable;
public abstract class GenericLayoutModule implements Serializable, Module {
public abstract Destination getDestination();
@Override
public abstract String getElement();
public abstract GenericModuleField getField(String key);
// Added by patch.
public abstract GenericModuleField getField$original(String key);
public abstract GenericModuleField[] getFields();
// Added by patch.
public abstract GenericModuleField[] getFields$original();
@Override
public abstract String getPage();
public abstract GenericLayoutModule[] getSubmodules();
// Added by patch.
public abstract GenericLayoutModule[] getSubmodules$original();
}

View file

@ -0,0 +1,9 @@
package com.strava.modularframework.data;
import java.io.Serializable;
public abstract class GenericModuleField implements Serializable {
public abstract Destination getDestination();
public abstract String getElement();
}

View file

@ -0,0 +1,14 @@
package com.strava.modularframework.data;
import java.util.List;
public abstract class ListField {
public abstract Destination getDestination();
public abstract String getElement();
public abstract List<ListField> getFields();
// Added by patch.
public abstract List<ListField> getFields$original();
}

View file

@ -0,0 +1,8 @@
package com.strava.modularframework.data;
public abstract class ListProperties {
public abstract ListField getField(String key);
// Added by patch.
public abstract ListField getField$original(String key);
}

View file

@ -0,0 +1,16 @@
package com.strava.modularframework.data;
import java.util.List;
public abstract class ModularComponent implements Module {
@Override
public abstract String getElement();
@Override
public abstract String getPage();
public abstract List<Module> getSubmodules();
// Added by patch.
public abstract List<Module> getSubmodules$original();
}

View file

@ -0,0 +1,21 @@
package com.strava.modularframework.data;
import java.util.List;
public interface ModularEntry {
List<ModularEntry> getChildrenEntries();
// Added by patch.
List<ModularEntry> getChildrenEntries$original();
Destination getDestination();
String getElement();
List<Module> getModules();
// Added by patch.
List<Module> getModules$original();
String getPage();
}

View file

@ -0,0 +1,22 @@
package com.strava.modularframework.data;
import java.util.List;
public abstract class ModularEntryContainer {
public abstract List<ModularEntry> getEntries();
// Added by patch.
public abstract List<ModularEntry> getEntries$original();
public abstract List<ModularMenuItem> getMenuItems();
// Added by patch.
public abstract List<ModularMenuItem> getMenuItems$original();
public abstract String getPage();
public abstract ListProperties getProperties();
// Added by patch.
public abstract ListProperties getProperties$original();
}

View file

@ -0,0 +1,7 @@
package com.strava.modularframework.data;
public abstract class ModularMenuItem {
public abstract Destination getDestination();
public abstract String getElementName();
}

View file

@ -0,0 +1,7 @@
package com.strava.modularframework.data;
public interface Module {
String getElement();
String getPage();
}

View file

@ -0,0 +1,10 @@
package com.strava.modularframework.data;
import java.util.Map;
public abstract class MultiStateFieldDescriptor {
public abstract Map<String, GenericModuleField> getStateMap();
// Added by patch.
public abstract Map<String, GenericModuleField> getStateMap$original();
}

View file

@ -0,0 +1,19 @@
package com.strava.modularframeworknetwork;
import com.strava.modularframework.data.ListProperties;
import com.strava.modularframework.data.ModularEntry;
import java.util.List;
public abstract class ModularEntryNetworkContainer {
public abstract List<ModularEntry> getEntries();
// Added by patch.
public abstract List<ModularEntry> getEntries$original();
public abstract String getPage();
public abstract ListProperties getProperties();
// Added by patch.
public abstract ListProperties getProperties$original();
}