build(Needs bump)!: Update to ReVanced Patcher v22 (#6542)

Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: Pun Butrach <pun.butrach@gmail.com>
Co-authored-by: Ushie <ushiekane@gmail.com>
Co-authored-by: ILoveOpenSourceApplications <ILoveOpenSourceApplications@users.noreply.github.com>
Co-authored-by: rospino74 <34315725+rospino74@users.noreply.github.com>
Co-authored-by: drobotk <pawwwll@gmail.com>
Co-authored-by: Sayanth <13906889+SayanthD@users.noreply.github.com>
Co-authored-by: kitadai31 <90122968+kitadai31@users.noreply.github.com>

BREAKING CHANGE: Deprecated APIs have been removed, and various APIs now use the updated ReVanced Patcher v22 APIs.
This commit is contained in:
oSumAtrIX 2026-02-27 02:39:17 +01:00 committed by GitHub
parent 376f2af8d8
commit ab2ac36e30
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
842 changed files with 12691 additions and 13203 deletions

View file

@ -6,6 +6,6 @@ dependencies {
android {
defaultConfig {
minSdk = 26
minSdk = 23
}
}

View file

@ -528,14 +528,8 @@ public final class AlternativeThumbnailsPatch {
* Cache used to verify if an alternative thumbnails exists for a given video id.
*/
@GuardedBy("itself")
private static final Map<String, VerifiedQualities> altVideoIdLookup = new LinkedHashMap<>(100) {
private static final int CACHE_LIMIT = 1000;
@Override
protected boolean removeEldestEntry(Entry eldest) {
return size() > CACHE_LIMIT; // Evict the oldest entry if over the cache limit.
}
};
private static final Map<String, VerifiedQualities> altVideoIdLookup =
Utils.createSizeRestrictedMap(1000);
private static VerifiedQualities getVerifiedQualities(@NonNull String videoId, boolean returnNullIfDoesNotExist) {
synchronized (altVideoIdLookup) {

View file

@ -7,6 +7,7 @@ import androidx.annotation.Nullable;
import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;
@ -50,7 +51,7 @@ public class ChangeHeaderPatch {
return null;
}
final int identifier = Utils.getResourceIdentifier(attributeName, "attr");
final int identifier = Utils.getResourceIdentifier(ResourceType.ATTR, attributeName);
if (identifier == 0) {
// Should never happen.
Logger.printException(() -> "Could not find attribute: " + drawableName);
@ -71,7 +72,7 @@ public class ChangeHeaderPatch {
? "_dark"
: "_light");
final int identifier = Utils.getResourceIdentifier(drawableFullName, "drawable");
final int identifier = Utils.getResourceIdentifier(ResourceType.DRAWABLE, drawableFullName);
if (identifier != 0) {
return Utils.getContext().getDrawable(identifier);
}

View file

@ -21,7 +21,7 @@ public final class DownloadsPatch {
/**
* Injection point.
*/
public static void activityCreated(Activity mainActivity) {
public static void setMainActivity(Activity mainActivity) {
activityRef = new WeakReference<>(mainActivity);
}

View file

@ -0,0 +1,24 @@
package app.revanced.extension.youtube.patches;
import java.util.Map;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused")
public class FixContentProviderPatch {
/**
* Injection point.
*/
public static void removeNullMapEntries(Map<?, ?> map) {
map.entrySet().removeIf(entry -> {
Object value = entry.getValue();
if (value == null) {
Logger.printDebug(() -> "Removing content provider key with null value: " + entry.getKey());
return true;
}
return false;
});
}
}

View file

@ -7,6 +7,7 @@ import android.view.ViewGroup;
import android.widget.ImageView;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;
@ -29,6 +30,15 @@ public final class HidePlayerOverlayButtonsPatch {
return Settings.HIDE_CAST_BUTTON.get() ? View.GONE : original;
}
/**
* Injection point.
*/
public static boolean getCastButtonOverrideV2(boolean original) {
if (Settings.HIDE_CAST_BUTTON.get()) return false;
return original;
}
/**
* Injection point.
*/
@ -40,10 +50,10 @@ public final class HidePlayerOverlayButtonsPatch {
= Settings.HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS.get();
private static final int PLAYER_CONTROL_PREVIOUS_BUTTON_TOUCH_AREA_ID = getResourceIdentifierOrThrow(
"player_control_previous_button_touch_area", "id");
ResourceType.ID, "player_control_previous_button_touch_area");
private static final int PLAYER_CONTROL_NEXT_BUTTON_TOUCH_AREA_ID = getResourceIdentifierOrThrow(
"player_control_next_button_touch_area", "id");
ResourceType.ID, "player_control_next_button_touch_area");
/**
* Injection point.

View file

@ -4,7 +4,17 @@ import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public class HideSeekbarPatch {
/**
* Injection point.
*/
public static boolean hideSeekbar() {
return Settings.HIDE_SEEKBAR.get();
}
/**
* Injection point.
*/
public static boolean useFullscreenLargeSeekbar(boolean original) {
return Settings.FULLSCREEN_LARGE_SEEKBAR.get();
}
}

View file

@ -15,6 +15,7 @@ import androidx.annotation.Nullable;
import java.util.List;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.youtube.settings.Settings;
@ -115,7 +116,7 @@ public final class MiniplayerPatch {
* Resource is not present in older targets, and this field will be zero.
*/
private static final int MODERN_OVERLAY_SUBTITLE_TEXT
= Utils.getResourceIdentifier("modern_miniplayer_subtitle_text", "id");
= Utils.getResourceIdentifier(ResourceType.ID, "modern_miniplayer_subtitle_text");
private static final MiniplayerType CURRENT_TYPE = Settings.MINIPLAYER_TYPE.get();
@ -378,6 +379,19 @@ public final class MiniplayerPatch {
return original;
}
/**
* Injection point.
*/
public static boolean allowBoldIcons(boolean original) {
if (CURRENT_TYPE == MINIMAL) {
// Minimal player does not have the correct pause/play icon (it's too large).
// Use the non bold icons instead.
return false;
}
return original;
}
/**
* Injection point.
*/

View file

@ -5,12 +5,11 @@ import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButt
import android.os.Build;
import android.view.View;
import android.widget.TextView;
import java.util.EnumMap;
import java.util.Map;
import android.widget.TextView;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;
@ -30,13 +29,13 @@ public final class NavigationButtonsPatch {
private static final boolean SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON
= Settings.SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON.get();
private static final Boolean DISABLE_TRANSLUCENT_STATUS_BAR
private static final boolean DISABLE_TRANSLUCENT_STATUS_BAR
= Settings.DISABLE_TRANSLUCENT_STATUS_BAR.get();
private static final Boolean DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT
private static final boolean DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT
= Settings.DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT.get();
private static final Boolean DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK
private static final boolean DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK
= Settings.DISABLE_TRANSLUCENT_NAVIGATION_BAR_DARK.get();
/**
@ -62,6 +61,13 @@ public final class NavigationButtonsPatch {
hideViewUnderCondition(Settings.HIDE_NAVIGATION_BUTTON_LABELS, navigationLabelsView);
}
/**
* Injection point.
*/
public static boolean useAnimatedNavigationButtons(boolean original) {
return Settings.NAVIGATION_BAR_ANIMATIONS.get();
}
/**
* Injection point.
*/

View file

@ -20,15 +20,6 @@ public class OpenShortsInRegularPlayerPatch {
REGULAR_PLAYER_FULLSCREEN
}
static {
if (!VersionCheckPatch.IS_19_46_OR_GREATER
&& Settings.SHORTS_PLAYER_TYPE.get() == ShortsPlayerType.REGULAR_PLAYER_FULLSCREEN) {
// User imported newer settings to an older app target.
Logger.printInfo(() -> "Resetting " + Settings.SHORTS_PLAYER_TYPE);
Settings.SHORTS_PLAYER_TYPE.resetToDefault();
}
}
private static WeakReference<Activity> mainActivityRef = new WeakReference<>(null);
private static volatile boolean overrideBackPressToExit;

View file

@ -24,18 +24,20 @@ public class OpenVideosFullscreenHookPatch {
/**
* Injection point.
*
* Returns negated value.
*/
public static boolean openVideoFullscreenPortrait(boolean original) {
public static boolean doNotOpenVideoFullscreenPortrait(boolean original) {
Boolean openFullscreen = openNextVideoFullscreen;
if (openFullscreen != null) {
openNextVideoFullscreen = null;
return openFullscreen;
return !openFullscreen;
}
if (!isFullScreenPatchIncluded()) {
return original;
}
return Settings.OPEN_VIDEOS_FULLSCREEN_PORTRAIT.get();
return !Settings.OPEN_VIDEOS_FULLSCREEN_PORTRAIT.get();
}
}

View file

@ -42,7 +42,7 @@ public class PlayerControlsPatch {
Logger.printDebug(() -> "fullscreen button visibility: "
+ (visibility == View.VISIBLE ? "VISIBLE" :
visibility == View.GONE ? "GONE" : "INVISIBLE"));
visibility == View.GONE ? "GONE" : "INVISIBLE"));
fullscreenButtonVisibilityChanged(visibility == View.VISIBLE);
}

View file

@ -1,19 +1,29 @@
package app.revanced.extension.youtube.patches;
import android.app.AlertDialog;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;
/** @noinspection unused*/
@SuppressWarnings("unused")
public class RemoveViewerDiscretionDialogPatch {
/**
* Injection point.
*/
public static void confirmDialog(AlertDialog dialog) {
if (!Settings.REMOVE_VIEWER_DISCRETION_DIALOG.get()) {
// Since the patch replaces the AlertDialog#show() method, we need to call the original method here.
dialog.show();
if (Settings.REMOVE_VIEWER_DISCRETION_DIALOG.get()) {
Logger.printDebug(() -> "Clicking alert dialog dismiss button");
final var button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
button.setSoundEffectsEnabled(false);
button.performClick();
return;
}
final var button = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
button.setSoundEffectsEnabled(false);
button.performClick();
// Since the patch replaces the AlertDialog#show() method, we need to call the original method here.
Logger.printDebug(() -> "Showing alert dialog");
dialog.show();
}
}

View file

@ -16,7 +16,7 @@ import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.components.ReturnYouTubeDislikeFilter;
import app.revanced.extension.youtube.patches.litho.ReturnYouTubeDislikeFilter;
import app.revanced.extension.youtube.returnyoutubedislike.ReturnYouTubeDislike;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType;
@ -131,6 +131,10 @@ public class ReturnYouTubeDislikePatch {
String conversionContextString = conversionContext.toString();
if (Settings.RYD_ENABLED.get()) { // FIXME: Remove this.
Logger.printDebug(() -> "RYD conversion context: " + conversionContext);
}
if (isRollingNumber && !conversionContextString.contains("video_action_bar.e")) {
return original;
}

View file

@ -2,8 +2,6 @@ package app.revanced.extension.youtube.patches;
import android.app.Activity;
import androidx.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Objects;
@ -78,7 +76,7 @@ public class ShortsAutoplayPatch {
/**
* Injection point.
*/
public static Enum<?> changeShortsRepeatBehavior(@Nullable Enum<?> original) {
public static Enum<?> changeShortsRepeatBehavior(Enum<?> original) {
try {
final boolean autoplay;
@ -95,19 +93,19 @@ public class ShortsAutoplayPatch {
autoplay = Settings.SHORTS_AUTOPLAY.get();
}
final ShortsLoopBehavior behavior = autoplay
Enum<?> overrideBehavior = (autoplay
? ShortsLoopBehavior.SINGLE_PLAY
: ShortsLoopBehavior.REPEAT;
: ShortsLoopBehavior.REPEAT).ytEnumValue;
if (behavior.ytEnumValue != null) {
if (overrideBehavior != null) {
Logger.printDebug(() -> {
String name = (original == null ? "unknown (null)" : original.name());
return behavior == original
return overrideBehavior == original
? "Behavior setting is same as original. Using original: " + name
: "Changing Shorts repeat behavior from: " + name + " to: " + behavior.name();
: "Changing Shorts repeat behavior from: " + name + " to: " + overrideBehavior.name();
});
return behavior.ytEnumValue;
return overrideBehavior;
}
if (original == null) {
@ -118,13 +116,12 @@ public class ShortsAutoplayPatch {
return unknown;
}
} catch (Exception ex) {
Logger.printException(() -> "changeShortsRepeatBehavior failure", ex);
Logger.printException(() -> "changeShortsRepeatState failure", ex);
}
return original;
}
/**
* Injection point.
*/

View file

@ -19,5 +19,12 @@ public class VersionCheckPatch {
public static final boolean IS_19_29_OR_GREATER = isVersionOrGreater("19.29.00");
@Deprecated
public static final boolean IS_19_34_OR_GREATER = isVersionOrGreater("19.34.00");
public static final boolean IS_19_46_OR_GREATER = isVersionOrGreater("19.46.00");
public static final boolean IS_20_21_OR_GREATER = isVersionOrGreater("20.21.00");
public static final boolean IS_20_22_OR_GREATER = isVersionOrGreater("20.22.00");
public static final boolean IS_20_31_OR_GREATER = isVersionOrGreater("20.31.00");
public static final boolean IS_20_37_OR_GREATER = isVersionOrGreater("20.37.00");
}

View file

@ -1,4 +1,4 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import static app.revanced.extension.shared.StringRef.str;
@ -8,10 +8,10 @@ import android.view.View;
import java.util.List;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.ByteArrayFilterGroup;
import app.revanced.extension.shared.patches.litho.FilterGroup.StringFilterGroup;
import app.revanced.extension.youtube.settings.Settings;

View file

@ -1,4 +1,4 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.StringFilterGroup;

View file

@ -1,7 +1,8 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import app.revanced.extension.shared.patches.litho.FilterGroupList.ByteArrayFilterGroupList;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.youtube.patches.VersionCheckPatch;
import app.revanced.extension.shared.patches.litho.FilterGroupList.ByteArrayFilterGroupList;
import app.revanced.extension.shared.patches.litho.FilterGroup.ByteArrayFilterGroup;
import app.revanced.extension.shared.patches.litho.FilterGroup.StringFilterGroup;
import app.revanced.extension.youtube.settings.Settings;
@ -42,7 +43,6 @@ public final class ButtonsFilter extends Filter {
addPathCallbacks(
likeSubscribeGlow,
bufferFilterPathGroup,
new StringFilterGroup(
Settings.HIDE_LIKE_DISLIKE_BUTTON,
"|segmented_like_dislike_button"
@ -61,6 +61,12 @@ public final class ButtonsFilter extends Filter {
)
);
// FIXME: 20.22+ filtering of the action buttons doesn't work because
// the buffer is the same for all buttons.
if (!VersionCheckPatch.IS_20_22_OR_GREATER) {
addPathCallbacks(bufferFilterPathGroup);
}
bufferButtonsGroupList.addAll(
new ByteArrayFilterGroup(
Settings.HIDE_REPORT_BUTTON,
@ -112,11 +118,13 @@ public final class ButtonsFilter extends Filter {
}
private boolean isEveryFilterGroupEnabled() {
for (var group : pathCallbacks)
for (var group : pathCallbacks) {
if (!group.isEnabled()) return false;
}
for (var group : bufferButtonsGroupList)
for (var group : bufferButtonsGroupList) {
if (!group.isEnabled()) return false;
}
return true;
}

View file

@ -1,4 +1,4 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;

View file

@ -1,9 +1,9 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;
import app.revanced.extension.shared.patches.litho.FilterGroupList.*;
import app.revanced.extension.shared.patches.litho.FilterGroupList.ByteArrayFilterGroupList;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType;

View file

@ -1,8 +1,8 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import app.revanced.extension.shared.patches.litho.FilterGroup.StringFilterGroup;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;
@SuppressWarnings("unused")
public final class HideInfoCardsFilter extends Filter {

View file

@ -1,4 +1,4 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;

View file

@ -1,5 +1,6 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import static app.revanced.extension.youtube.patches.VersionCheckPatch.IS_20_21_OR_GREATER;
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
import android.graphics.drawable.Drawable;
@ -7,16 +8,17 @@ import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.StringTrieSearch;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;
import app.revanced.extension.shared.patches.litho.FilterGroupList.*;
import app.revanced.extension.shared.patches.litho.FilterGroup.ByteArrayFilterGroup;
import app.revanced.extension.shared.patches.litho.FilterGroup.StringFilterGroup;
import app.revanced.extension.shared.patches.litho.FilterGroupList.ByteArrayFilterGroupList;
import app.revanced.extension.youtube.patches.ChangeHeaderPatch;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.NavigationBar;
@ -51,7 +53,7 @@ public final class LayoutComponentsFilter extends Filter {
private final StringFilterGroup compactChannelBarInnerButton;
private final ByteArrayFilterGroup joinMembershipButton;
private final StringFilterGroup horizontalShelves;
private final ByteArrayFilterGroup ticketShelf;
private final ByteArrayFilterGroup ticketShelfBuffer;
private final StringFilterGroup chipBar;
private final StringFilterGroup channelProfile;
private final ByteArrayFilterGroupList channelProfileBuffer;
@ -210,7 +212,7 @@ public final class LayoutComponentsFilter extends Filter {
// Playable horizontal shelf header.
playablesBuffer = new ByteArrayFilterGroup(
Settings.HIDE_PLAYABLES,
null,
"FEmini_app_destination"
);
@ -296,15 +298,15 @@ public final class LayoutComponentsFilter extends Filter {
);
horizontalShelves = new StringFilterGroup(
Settings.HIDE_HORIZONTAL_SHELVES,
null, // Setting is checked in isFiltered()
"horizontal_video_shelf.e",
"horizontal_shelf.e",
"horizontal_shelf_inline.e",
"horizontal_tile_shelf.e"
);
ticketShelf = new ByteArrayFilterGroup(
Settings.HIDE_TICKET_SHELF,
ticketShelfBuffer = new ByteArrayFilterGroup(
null,
"ticket_item.e"
);
@ -346,7 +348,7 @@ public final class LayoutComponentsFilter extends Filter {
@Override
public boolean isFiltered(String identifier, String path, byte[] buffer,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
// This identifier is used not only in players but also in search results:
// https://github.com/ReVanced/revanced-patches/issues/3245
// Until 2024, medical information panels such as Covid 19 also used this identifier and were shown in the search results.
@ -386,9 +388,19 @@ public final class LayoutComponentsFilter extends Filter {
}
if (matchedGroup == horizontalShelves) {
return contentIndex == 0 && (hideShelves()
|| ticketShelf.check(buffer).isFiltered()
|| playablesBuffer.check(buffer).isFiltered());
if (contentIndex != 0) return false;
final boolean hideShelves = Settings.HIDE_HORIZONTAL_SHELVES.get();
final boolean hideTickets = Settings.HIDE_TICKET_SHELF.get();
final boolean hidePlayables = Settings.HIDE_PLAYABLES.get();
if (!hideShelves && !hideTickets && !hidePlayables) return false;
// Must always check other buffers first, to prevent incorrectly hiding them
// if they are set to show but hide horizontal shelves is set to hidden.
if (ticketShelfBuffer.check(buffer).isFiltered()) return hideTickets;
if (playablesBuffer.check(buffer).isFiltered()) return hidePlayables;
return hideShelves && hideShelves();
}
if (matchedGroup == chipBar) {
@ -402,20 +414,22 @@ public final class LayoutComponentsFilter extends Filter {
* Injection point.
* Called from a different place then the other filters.
*/
public static boolean filterMixPlaylists(Object conversionContext, @Nullable final byte[] bytes) {
public static boolean filterMixPlaylists(Object conversionContext, @Nullable byte[] buffer) {
// Edit: This hook may no longer be needed, and mix playlist filtering
// might be possible using the existing litho filters.
try {
if (!Settings.HIDE_MIX_PLAYLISTS.get()) {
return false;
}
if (bytes == null) {
Logger.printDebug(() -> "bytes is null");
if (buffer == null) {
Logger.printDebug(() -> "buffer is null");
return false;
}
if (mixPlaylists.check(bytes).isFiltered()
if (mixPlaylists.check(buffer).isFiltered()
// Prevent hiding the description of some videos accidentally.
&& !mixPlaylistsBufferExceptions.check(bytes).isFiltered()
&& !mixPlaylistsBufferExceptions.check(buffer).isFiltered()
// Prevent playlist items being hidden, if a mix playlist is present in it.
// Check last since it requires creating a context string.
//
@ -478,11 +492,23 @@ public final class LayoutComponentsFilter extends Filter {
: height;
}
private static final boolean HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS_ENABLED
= Settings.HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS.get();
/**
* Injection point.
*/
public static void hideInRelatedVideos(View chipView) {
Utils.hideViewBy0dpUnderCondition(Settings.HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS, chipView);
// Cannot use 0dp hide with later targets, otherwise the suggested videos
// can be shown in full screen mode.
// This behavior may also be present in earlier app targets.
if (IS_20_21_OR_GREATER) {
// FIXME: The filter bar is still briefly shown when dragging the suggested videos
// below the video player.
Utils.hideViewUnderCondition(HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS_ENABLED, chipView);
} else {
Utils.hideViewBy0dpUnderCondition(HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS_ENABLED, chipView);
}
}
private static final boolean HIDE_DOODLES_ENABLED = Settings.HIDE_DOODLES.get();
@ -507,6 +533,8 @@ public final class LayoutComponentsFilter extends Filter {
&& NavigationBar.isSearchBarActive()
// Search bar can be active but behind the player.
&& !PlayerType.getCurrent().isMaximizedOrFullscreen()) {
// FIXME: "Show more" button is visible hidden,
// but an empty space remains that can be clicked.
Utils.hideViewByLayoutParams(view);
}
}

View file

@ -1,4 +1,4 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;

View file

@ -1,11 +1,12 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.ByteArrayFilterGroup;
import app.revanced.extension.shared.patches.litho.FilterGroup.StringFilterGroup;
import app.revanced.extension.shared.patches.litho.FilterGroupList.ByteArrayFilterGroupList;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;
import app.revanced.extension.shared.patches.litho.FilterGroupList.*;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.ShortsPlayerState;

View file

@ -1,21 +1,21 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import androidx.annotation.GuardedBy;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.TrieSearch;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;
import app.revanced.extension.shared.patches.litho.FilterGroupList.ByteArrayFilterGroupList;
import app.revanced.extension.youtube.patches.ReturnYouTubeDislikePatch;
import app.revanced.extension.youtube.patches.VideoInformation;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.TrieSearch;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;
import app.revanced.extension.shared.patches.litho.FilterGroupList.*;
/**
* Searches for video id's in the proto buffer of Shorts dislike.
@ -36,18 +36,7 @@ public final class ReturnYouTubeDislikeFilter extends Filter {
* Cannot use {@link LinkedHashSet} because it's missing #removeEldestEntry().
*/
@GuardedBy("itself")
private static final Map<String, Boolean> lastVideoIds = new LinkedHashMap<>() {
/**
* Number of video id's to keep track of for searching thru the buffer.
* A minimum value of 3 should be sufficient, but check a few more just in case.
*/
private static final int NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK = 5;
@Override
protected boolean removeEldestEntry(Entry eldest) {
return size() > NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK;
}
};
private static final Map<String, Boolean> lastVideoIds = Utils.createSizeRestrictedMap(5);
/**
* Injection point.
@ -88,7 +77,7 @@ public final class ReturnYouTubeDislikeFilter extends Filter {
@Override
public boolean isFiltered(String identifier, String path, byte[] buffer,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
if (!Settings.RYD_ENABLED.get() || !Settings.RYD_SHORTS.get()) {
return false;
}

View file

@ -1,19 +1,24 @@
package app.revanced.extension.youtube.patches.components;
package app.revanced.extension.youtube.patches.litho;
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
import android.view.View;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;
import app.revanced.extension.shared.patches.litho.FilterGroup.ByteArrayFilterGroup;
import app.revanced.extension.shared.patches.litho.FilterGroupList.ByteArrayFilterGroupList;
import app.revanced.extension.shared.settings.BooleanSetting;
import com.google.android.libraries.youtube.rendering.ui.pivotbar.PivotBar;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.patches.litho.Filter;
import app.revanced.extension.shared.patches.litho.FilterGroup.*;
import app.revanced.extension.shared.patches.litho.FilterGroupList.*;
import app.revanced.extension.youtube.patches.VersionCheckPatch;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.NavigationBar;
import app.revanced.extension.youtube.shared.PlayerType;
@ -21,12 +26,32 @@ import app.revanced.extension.youtube.shared.PlayerType;
@SuppressWarnings("unused")
public final class ShortsFilter extends Filter {
private static final boolean HIDE_SHORTS_NAVIGATION_BAR = Settings.HIDE_SHORTS_NAVIGATION_BAR.get();
private static final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.e";
private static final String COMPONENT_TYPE = "ComponentType";
private static final String[] REEL_ACTION_BAR_PATHS = {
"reel_action_bar.", // Regular Shorts.
"reels_player_overlay_layout." // Shorts ads.
};
private static final Map<Integer, BooleanSetting> REEL_ACTION_BUTTONS_MAP = new HashMap<>() {
{
// Like button and Dislike button can be hidden with Litho filter.
// put(0, Settings.HIDE_SHORTS_LIKE_BUTTON);
// put(1, Settings.HIDE_SHORTS_DISLIKE_BUTTON);
put(2, Settings.HIDE_SHORTS_COMMENTS_BUTTON);
put(3, Settings.HIDE_SHORTS_SHARE_BUTTON);
put(4, Settings.HIDE_SHORTS_REMIX_BUTTON);
}
};
private final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.e";
/**
* For paid promotion label and subscribe button that appears in the channel bar.
*/
private static final String REEL_METAPANEL_PATH = "reel_metapanel.e";
private final String REEL_METAPANEL_PATH = "reel_metapanel.e";
/**
* For paid promotion label and subscribe button that appears in the channel bar.
*/
private final String REEL_PLAYER_OVERLAY_PATH = "reel_player_overlay.e";
/**
* Tags that appears when opening the Shorts player.
@ -46,6 +71,8 @@ public final class ShortsFilter extends Filter {
private final ByteArrayFilterGroup useSoundButtonBuffer;
private final StringFilterGroup useTemplateButton;
private final ByteArrayFilterGroup useTemplateButtonBuffer;
private final StringFilterGroup reelCarousel;
private final ByteArrayFilterGroup reelCarouselBuffer;
private final StringFilterGroup autoDubbedLabel;
private final StringFilterGroup subscribeButton;
@ -149,13 +176,15 @@ public final class ShortsFilter extends Filter {
StringFilterGroup likeButton = new StringFilterGroup(
Settings.HIDE_SHORTS_LIKE_BUTTON,
"shorts_like_button.e",
"reel_like_button.e"
"reel_like_button.e",
"reel_like_toggled_button.e"
);
StringFilterGroup dislikeButton = new StringFilterGroup(
Settings.HIDE_SHORTS_DISLIKE_BUTTON,
"shorts_dislike_button.e",
"reel_dislike_button.e"
"reel_dislike_button.e",
"reel_dislike_toggled_button.e"
);
StringFilterGroup previewComment = new StringFilterGroup(
@ -174,7 +203,7 @@ public final class ShortsFilter extends Filter {
autoDubbedLabel = new StringFilterGroup(
Settings.HIDE_SHORTS_AUTO_DUBBED_LABEL,
"badge."
"badge.e"
);
joinButton = new StringFilterGroup(
@ -199,6 +228,16 @@ public final class ShortsFilter extends Filter {
"reel_action_bar.e"
);
reelCarousel = new StringFilterGroup(
Settings.HIDE_SHORTS_SOUND_METADATA_LABEL,
"reel_carousel.e"
);
reelCarouselBuffer = new ByteArrayFilterGroup(
null,
"FEsfv_audio_pivot"
);
useSoundButton = new StringFilterGroup(
Settings.HIDE_SHORTS_USE_SOUND_BUTTON,
// First filter needed for "Use this sound" that can appear when viewing Shorts
@ -226,7 +265,11 @@ public final class ShortsFilter extends Filter {
videoActionButton = new StringFilterGroup(
null,
// Can be simply 'button.e', 'shorts_video_action_button.e' or 'reel_action_button.e'
// Can be any of:
// button.eml
// shorts_video_action_button.eml
// reel_action_button.eml
// reel_pivot_button.eml
"button.e"
);
@ -236,32 +279,39 @@ public final class ShortsFilter extends Filter {
);
addPathCallbacks(
shortsCompactFeedVideo, joinButton, subscribeButton, paidPromotionLabel, autoDubbedLabel,
shortsActionBar, suggestedAction, pausedOverlayButtons, channelBar, previewComment,
fullVideoLinkLabel, videoTitle, useSoundButton, reelSoundMetadata, soundButton, infoPanel,
stickers, likeFountain, likeButton, dislikeButton, livePreview
shortsCompactFeedVideo, joinButton, subscribeButton, paidPromotionLabel, livePreview,
suggestedAction, pausedOverlayButtons, channelBar, previewComment, autoDubbedLabel,
fullVideoLinkLabel, videoTitle, useSoundButton, reelSoundMetadata, soundButton, reelCarousel,
infoPanel, stickers, likeFountain, likeButton, dislikeButton
);
//
// All other action buttons.
//
videoActionButtonBuffer.addAll(
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_COMMENTS_BUTTON,
"reel_comment_button",
"youtube_shorts_comment_outline"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_SHARE_BUTTON,
"reel_share_button",
"youtube_shorts_share_outline"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_REMIX_BUTTON,
"reel_remix_button",
"youtube_shorts_remix_outline"
)
);
// Legacy hiding of Shorts action buttons. Because of 20.31+ buffer changes
// it's currently not possible to hide these using buffer filtering.
// See alternative hiding strategy in hideActionButtons().
if (!VersionCheckPatch.IS_20_22_OR_GREATER) {
addPathCallbacks(shortsActionBar);
//
// All other action buttons.
//
videoActionButtonBuffer.addAll(
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_COMMENTS_BUTTON,
"reel_comment_button",
"youtube_shorts_comment_outline"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_SHARE_BUTTON,
"reel_share_button",
"youtube_shorts_share_outline"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_REMIX_BUTTON,
"reel_remix_button",
"youtube_shorts_remix_outline"
)
);
}
//
// Suggested actions.
@ -275,7 +325,8 @@ public final class ShortsFilter extends Filter {
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_SHOP_BUTTON,
"yt_outline_bag_"
"yt_outline_bag_",
"yt_outline_experimental_bag_"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_TAGGED_PRODUCTS,
@ -285,31 +336,38 @@ public final class ShortsFilter extends Filter {
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_LOCATION_LABEL,
"yt_outline_location_point_"
"yt_outline_location_point_",
"yt_outline_experimental_location_point_"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_SAVE_SOUND_BUTTON,
"yt_outline_bookmark_",
// 'Save sound' button. It seems this has been removed and only 'Save music' is used.
// Still hide this in case it's still present.
"yt_outline_list_add_"
"yt_outline_list_add_",
"yt_outline_experimental_list_add_"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_SEARCH_SUGGESTIONS,
"yt_outline_search_"
"yt_outline_search_",
"yt_outline_experimental_search_"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_SUPER_THANKS_BUTTON,
"yt_outline_dollar_sign_heart_"
"yt_outline_dollar_sign_heart_",
"yt_outline_experimental_dollar_sign_heart_"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_USE_TEMPLATE_BUTTON,
// "Use this template" can appear in two different places.
"yt_outline_template_add_"
"yt_outline_template_add_",
"yt_outline_experimental_template_add_"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_UPCOMING_BUTTON,
"yt_outline_bell_"
"yt_outline_bell_",
"yt_outline_experimental_bell_"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_EFFECT_BUTTON,
@ -322,11 +380,13 @@ public final class ShortsFilter extends Filter {
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_NEW_POSTS_BUTTON,
"yt_outline_box_pencil"
"yt_outline_box_pencil",
"yt_outline_experimental_box_pencil"
),
new ByteArrayFilterGroup(
Settings.HIDE_SHORTS_HASHTAG_BUTTON,
"yt_outline_hashtag_"
"yt_outline_hashtag_",
"yt_outline_experimental_hashtag_"
)
);
}
@ -343,12 +403,17 @@ public final class ShortsFilter extends Filter {
@Override
public boolean isFiltered(String identifier, String path, byte[] buffer,
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) {
if (contentType == FilterContentType.PATH) {
if (matchedGroup == subscribeButton || matchedGroup == joinButton
|| matchedGroup == paidPromotionLabel || matchedGroup == autoDubbedLabel) {
// Selectively filter to avoid false positive filtering of other subscribe/join buttons.
return path.startsWith(REEL_CHANNEL_BAR_PATH) || path.startsWith(REEL_METAPANEL_PATH);
return path.startsWith(REEL_CHANNEL_BAR_PATH) || path.startsWith(REEL_METAPANEL_PATH)
|| path.startsWith(REEL_PLAYER_OVERLAY_PATH);
}
if (matchedGroup == reelCarousel) {
return reelCarouselBuffer.check(buffer).isFiltered();
}
if (matchedGroup == useSoundButton) {
@ -444,6 +509,9 @@ public final class ShortsFilter extends Filter {
};
}
/**
* Injection point.
*/
public static int getSoundButtonSize(int original) {
if (Settings.HIDE_SHORTS_SOUND_BUTTON.get()) {
return 0;
@ -452,10 +520,16 @@ public final class ShortsFilter extends Filter {
return original;
}
/**
* Injection point.
*/
public static void setNavigationBar(PivotBar view) {
pivotBarRef = new WeakReference<>(view);
}
/**
* Injection point.
*/
public static void hideNavigationBar(String tag) {
if (HIDE_SHORTS_NAVIGATION_BAR) {
if (REEL_WATCH_FRAGMENT_INIT_PLAYBACK.contains(tag)) {
@ -470,6 +544,9 @@ public final class ShortsFilter extends Filter {
}
}
/**
* Injection point.
*/
public static int getNavigationBarHeight(int original) {
if (HIDE_SHORTS_NAVIGATION_BAR) {
return HIDDEN_NAVIGATION_BAR_VERTICAL_HEIGHT;
@ -477,4 +554,4 @@ public final class ShortsFilter extends Filter {
return original;
}
}
}

View file

@ -8,7 +8,7 @@ import android.widget.ListView;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.components.AdvancedVideoQualityMenuFilter;
import app.revanced.extension.youtube.patches.litho.AdvancedVideoQualityMenuFilter;
import app.revanced.extension.youtube.settings.Settings;
/**

View file

@ -21,7 +21,6 @@ public class RememberVideoQualityPatch {
private static final IntegerSetting shortsQualityWifi = Settings.SHORTS_QUALITY_DEFAULT_WIFI;
private static final IntegerSetting shortsQualityMobile = Settings.SHORTS_QUALITY_DEFAULT_MOBILE;
public static boolean shouldRememberVideoQuality() {
BooleanSetting preference = ShortsPlayerState.isOpen()
? Settings.REMEMBER_SHORTS_QUALITY_LAST_SELECTED

View file

@ -32,7 +32,7 @@ import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.ui.Dim;
import app.revanced.extension.shared.ui.SheetBottomDialog;
import app.revanced.extension.youtube.patches.VideoInformation;
import app.revanced.extension.youtube.patches.components.PlaybackSpeedMenuFilter;
import app.revanced.extension.youtube.patches.litho.PlaybackSpeedMenuFilter;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.shared.PlayerType;
import kotlin.Unit;

View file

@ -0,0 +1,85 @@
package app.revanced.extension.youtube.patches.theme;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
/**
* Dynamic drawable that is either the regular or bolded ReVanced preference icon.
*
* This is needed because the YouTube ReVanced preference intent is an AndroidX preference,
* and AndroidX classes are not built into Android which makes programmatically changing
* the preference thru patching overly complex. This solves the problem by using a drawable
* wrapper to dynamically pick which icon drawable to use at runtime.
*/
@SuppressWarnings("unused")
public class ReVancedSettingsIconDynamicDrawable extends Drawable {
private final Drawable icon;
public ReVancedSettingsIconDynamicDrawable() {
final int resId = Utils.getResourceIdentifier(ResourceType.DRAWABLE,
Utils.appIsUsingBoldIcons()
? "revanced_settings_icon_bold"
: "revanced_settings_icon"
);
icon = Utils.getContext().getDrawable(resId);
}
@Override
public void draw(@NonNull Canvas canvas) {
icon.draw(canvas);
}
@Override
public void setAlpha(int alpha) {
icon.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {
icon.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return icon.getOpacity();
}
@Override
public int getIntrinsicWidth() {
return icon.getIntrinsicWidth();
}
@Override
public int getIntrinsicHeight() {
return icon.getIntrinsicHeight();
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, bottom);
icon.setBounds(left, top, right, bottom);
}
@Override
public void setBounds(@NonNull Rect bounds) {
super.setBounds(bounds);
icon.setBounds(bounds);
}
@Override
public void onBoundsChange(@NonNull Rect bounds) {
super.onBoundsChange(bounds);
icon.setBounds(bounds);
}
}

View file

@ -16,6 +16,7 @@ import java.util.Arrays;
import java.util.Scanner;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.youtube.settings.Settings;
@ -101,16 +102,6 @@ public final class SeekbarColorPatch {
return customSeekbarColor;
}
/**
* injection point.
*/
public static boolean useLotteLaunchSplashScreen(boolean original) {
// This method is only used for development purposes to force the old style launch screen.
// Forcing this off on some devices can cause unexplained startup crashes,
// where the lottie animation is still used even though this condition appears to bypass it.
return original; // false = drawable style, true = lottie style.
}
/**
* Injection point.
* Modern Lottie style animation.

View file

@ -260,7 +260,8 @@ public class ReturnYouTubeDislike {
// middle separator
String middleSeparatorString = compactLayout
? " " + MIDDLE_SEPARATOR_CHARACTER + " "
: " \u2009" + MIDDLE_SEPARATOR_CHARACTER + "\u2009 "; // u2009 = 'narrow space' character
: " \u2009\u2009" + MIDDLE_SEPARATOR_CHARACTER + "\u2009\u2009 "; // u2009 = 'narrow space'
final int shapeInsertionIndex = middleSeparatorString.length() / 2;
Spannable middleSeparatorSpan = new SpannableString(middleSeparatorString);
ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());
@ -555,7 +556,8 @@ public class ReturnYouTubeDislike {
if (originalDislikeSpan != null && replacementLikeDislikeSpan != null
&& spansHaveEqualTextAndColor(original, originalDislikeSpan)) {
Logger.printDebug(() -> "Replacing span with previously created dislike span of data: " + videoId);
Logger.printDebug(() -> "Replacing span: " + original + " with " +
"previously created dislike span of data: " + videoId);
return replacementLikeDislikeSpan;
}

View file

@ -19,7 +19,7 @@ import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerH
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
import static app.revanced.extension.youtube.patches.litho.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
import static app.revanced.extension.youtube.patches.spoof.SpoofVideoStreamsPatch.SpoofClientAv1Availability;
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
import static app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.SponsorBlockDuration;
@ -46,7 +46,7 @@ import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.DeArrow
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillImagesAvailability;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime;
import app.revanced.extension.youtube.patches.MiniplayerPatch;
import app.revanced.extension.youtube.patches.VersionCheckPatch;
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationProvider.SwipeOverlayStyle;
@ -188,7 +188,7 @@ public class Settings extends YouTubeAndMusicSettings {
public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_double_tap_action", TRUE, true, new MiniplayerAnyModernAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_OVERLAY_BUTTONS = new BooleanSetting("revanced_miniplayer_hide_overlay_buttons", FALSE, true, new MiniplayerHideOverlayButtonsAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, new MiniplayerHideSubtextsAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", TRUE, true, new MiniplayerPatch.MiniplayerHideRewindOrOverlayOpacityAvailability());
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", TRUE, true, new MiniplayerHideRewindOrOverlayOpacityAvailability());
public static final IntegerSetting MINIPLAYER_WIDTH_DIP = new IntegerSetting("revanced_miniplayer_width_dip", 192, true, new MiniplayerAnyModernAvailability());
public static final IntegerSetting MINIPLAYER_OPACITY = new IntegerSetting("revanced_miniplayer_opacity", 100, true, new MiniplayerHideRewindOrOverlayOpacityAvailability());
@ -284,6 +284,7 @@ public class Settings extends YouTubeAndMusicSettings {
public static final BooleanSetting HIDE_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_hide_notifications_button", FALSE, true);
public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true,
"revanced_switch_create_with_notifications_button_user_dialog_message");
public static final BooleanSetting NAVIGATION_BAR_ANIMATIONS = new BooleanSetting("revanced_navigation_bar_animations", FALSE);
public static final BooleanSetting DISABLE_TRANSLUCENT_STATUS_BAR = new BooleanSetting("revanced_disable_translucent_status_bar", FALSE, true,
"revanced_disable_translucent_status_bar_user_dialog_message");
public static final BooleanSetting DISABLE_TRANSLUCENT_NAVIGATION_BAR_LIGHT = new BooleanSetting("revanced_disable_translucent_navigation_bar_light", FALSE, true);
@ -337,6 +338,7 @@ public class Settings extends YouTubeAndMusicSettings {
public static final BooleanSetting DISABLE_PRECISE_SEEKING_GESTURE = new BooleanSetting("revanced_disable_precise_seeking_gesture", FALSE);
public static final BooleanSetting HIDE_SEEKBAR = new BooleanSetting("revanced_hide_seekbar", FALSE, true);
public static final BooleanSetting HIDE_SEEKBAR_THUMBNAIL = new BooleanSetting("revanced_hide_seekbar_thumbnail", FALSE, true);
public static final BooleanSetting FULLSCREEN_LARGE_SEEKBAR = new BooleanSetting("revanced_fullscreen_large_seekbar", FALSE);
public static final BooleanSetting HIDE_TIMESTAMP = new BooleanSetting("revanced_hide_timestamp", FALSE);
public static final BooleanSetting RESTORE_OLD_SEEKBAR_THUMBNAILS = new BooleanSetting("revanced_restore_old_seekbar_thumbnails", TRUE);
public static final BooleanSetting SEEKBAR_TAPPING = new BooleanSetting("revanced_seekbar_tapping", FALSE);
@ -472,6 +474,13 @@ public class Settings extends YouTubeAndMusicSettings {
static {
// region Migration
// 20.37+ YT removed parts of the code for the legacy tablet miniplayer.
// This check must remain until the Tablet type is eventually removed.
if (VersionCheckPatch.IS_20_37_OR_GREATER && MINIPLAYER_TYPE.get() == MiniplayerType.TABLET) {
Logger.printInfo(() -> "Resetting miniplayer tablet type");
MINIPLAYER_TYPE.resetToDefault();
}
// Migrate renamed change header enums.
if (HEADER_LOGO.get() == HeaderLogo.REVANCED) {
HEADER_LOGO.save(HeaderLogo.ROUNDED);
@ -514,6 +523,14 @@ public class Settings extends YouTubeAndMusicSettings {
SPOOF_APP_VERSION.resetToDefault();
}
if (!BaseSettings.SETTINGS_DISABLE_BOLD_ICONS.get() && SPOOF_APP_VERSION.get()
&& SPOOF_APP_VERSION_TARGET.get().compareTo("19.35.00") <= 0) {
Logger.printInfo(() -> "Temporarily disabling bold icons that don't work with old spoof targets");
// Don't save and only temporarily overwrite the value so
// if spoofing is turned off the old setting value is used.
BooleanSetting.privateSetValue(BaseSettings.SETTINGS_DISABLE_BOLD_ICONS, false);
}
// VR 1.61 is not selectable in the settings, and it's selected by spoof stream patch if needed.
if (SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_VR_1_61_48) {
SPOOF_VIDEO_STREAMS_CLIENT_TYPE.resetToDefault();

View file

@ -7,6 +7,7 @@ import android.preference.PreferenceFragment;
import android.view.View;
import android.widget.Toolbar;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseActivityHook;
import app.revanced.extension.youtube.patches.VersionCheckPatch;
@ -15,11 +16,28 @@ import app.revanced.extension.youtube.settings.preference.YouTubePreferenceFragm
import app.revanced.extension.youtube.settings.search.YouTubeSearchViewController;
/**
* Hooks LicenseActivity to inject a custom {@link YouTubePreferenceFragment} with a toolbar and search functionality.
* Hooks LicenseActivity to inject a custom {@link YouTubePreferenceFragment}
* with a toolbar and search functionality.
*/
@SuppressWarnings("deprecation")
public class YouTubeActivityHook extends BaseActivityHook {
/**
* How much time has passed since the first launch of the app. Simple check to prevent
* forcing bold icons on first launch where the settings menu is partially broken
* due to missing icon resources the client has not yet received.
*/
private static final long MINIMUM_TIME_AFTER_FIRST_LAUNCH_BEFORE_ALLOWING_BOLD_ICONS = 30 * 1000; // 30 seconds.
private static final boolean USE_BOLD_ICONS = VersionCheckPatch.IS_20_31_OR_GREATER
&& !Settings.SETTINGS_DISABLE_BOLD_ICONS.get()
&& (System.currentTimeMillis() - Settings.FIRST_TIME_APP_LAUNCHED.get())
> MINIMUM_TIME_AFTER_FIRST_LAUNCH_BEFORE_ALLOWING_BOLD_ICONS;
static {
Utils.setAppIsUsingBoldIcons(USE_BOLD_ICONS);
}
private static int currentThemeValueOrdinal = -1; // Must initially be a non-valid enum ordinal value.
/**
@ -44,15 +62,7 @@ public class YouTubeActivityHook extends BaseActivityHook {
final var theme = Utils.isDarkModeEnabled()
? "Theme.YouTube.Settings.Dark"
: "Theme.YouTube.Settings";
activity.setTheme(Utils.getResourceIdentifierOrThrow(theme, "style"));
}
/**
* Returns the resource ID for the YouTube settings layout.
*/
@Override
protected int getContentViewResourceId() {
return LAYOUT_REVANCED_SETTINGS_WITH_TOOLBAR;
activity.setTheme(Utils.getResourceIdentifierOrThrow(ResourceType.STYLE, theme));
}
/**
@ -155,4 +165,12 @@ public class YouTubeActivityHook extends BaseActivityHook {
public static boolean handleBackPress() {
return YouTubeSearchViewController.handleFinish(searchViewController);
}
/**
* Injection point.
*/
@SuppressWarnings("unused")
public static boolean useBoldIcons(boolean original) {
return USE_BOLD_ICONS;
}
}

View file

@ -19,8 +19,10 @@ import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.youtube.patches.VersionCheckPatch;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
@ -72,7 +74,7 @@ public final class NavigationBar {
*/
public static boolean isSearchBarActive() {
View searchbarResults = searchBarResultsRef.get();
return searchbarResults != null && searchbarResults.getParent() != null;
return searchbarResults != null && searchbarResults.isShown();
}
public static boolean isBackButtonVisible() {
@ -277,12 +279,14 @@ public final class NavigationBar {
}
/**
* Use the bundled non cairo filled icon instead of a custom icon.
* Use the old non cairo filled icon, which is almost identical to
* the what would be the filled cairo icon.
* Custom cairo notification filled icon to fix unpatched app missing resource.
*/
private static final int fillBellCairoBlack = Utils.getResourceIdentifier(
"yt_fill_bell_black_24", "drawable");
private static final int fillBellCairoBlack = Utils.getResourceIdentifier(ResourceType.DRAWABLE,
// The bold cairo notification filled icon is present,
// but YT still has not fixed the icon not associated to the enum.
VersionCheckPatch.IS_20_31_OR_GREATER && !Settings.SETTINGS_DISABLE_BOLD_ICONS.get()
? "yt_fill_experimental_bell_vd_theme_24"
: "revanced_fill_bell_cairo_black_24");
/**
* Injection point.
@ -290,13 +294,12 @@ public final class NavigationBar {
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public static void setCairoNotificationFilledIcon(EnumMap enumMap, Enum tabActivityCairo) {
if (fillBellCairoBlack != 0) {
// Show a popup informing this fix is no longer needed to those who might care.
if (BaseSettings.DEBUG.get() && enumMap.containsKey(tabActivityCairo)) {
Logger.printException(() -> "YouTube fixed the cairo notification icons");
}
enumMap.putIfAbsent(tabActivityCairo, fillBellCairoBlack);
// Show a popup informing this fix is no longer needed to those who might care.
if (BaseSettings.DEBUG.get() && enumMap.containsKey(tabActivityCairo)) {
Logger.printException(() -> "YouTube fixed the notification icons");
}
enumMap.putIfAbsent(tabActivityCairo, fillBellCairoBlack);
}
public enum NavigationButton {

View file

@ -3,6 +3,7 @@ package app.revanced.extension.youtube.shared
import android.app.Activity
import android.view.View
import android.view.ViewGroup
import app.revanced.extension.shared.ResourceType
import app.revanced.extension.shared.Utils
import java.lang.ref.WeakReference
@ -19,13 +20,13 @@ class PlayerControlsVisibilityObserverImpl(
* id of the direct parent of controls_layout, R.id.youtube_controls_overlay
*/
private val controlsLayoutParentId =
Utils.getResourceIdentifier(activity, "youtube_controls_overlay", "id")
Utils.getResourceIdentifier(activity, ResourceType.ID, "youtube_controls_overlay")
/**
* id of R.id.controls_layout
*/
private val controlsLayoutId =
Utils.getResourceIdentifier(activity, "controls_layout", "id")
Utils.getResourceIdentifier(activity, ResourceType.ID, "controls_layout")
/**
* reference to the controls layout view

View file

@ -2,7 +2,6 @@ package app.revanced.extension.youtube.shared
import app.revanced.extension.shared.Logger
import app.revanced.extension.youtube.Event
import app.revanced.extension.youtube.patches.VideoInformation
/**
* Regular player type.

View file

@ -24,7 +24,6 @@ import android.widget.TextView;
import androidx.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -150,9 +149,9 @@ public class SegmentPlaybackController {
private static long skipSegmentButtonEndTime;
@Nullable
private static String timeWithoutSegments;
private static int sponsorBarAbsoluteLeft;
private static int sponsorAbsoluteBarRight;
private static int sponsorBarThickness;
private static int seekbarAbsoluteLeft;
private static int seekbarAbsoluteRight;
private static int seekbarThickness;
@Nullable
private static SponsorSegment lastSegmentSkipped;
@ -908,31 +907,13 @@ public class SegmentPlaybackController {
* injection point.
*/
@SuppressWarnings("unused")
public static void setSponsorBarRect(Object self) {
try {
Field field = self.getClass().getDeclaredField("replaceMeWithsetSponsorBarRect");
field.setAccessible(true);
Rect rect = (Rect) Objects.requireNonNull(field.get(self));
setSponsorBarAbsoluteLeft(rect);
setSponsorBarAbsoluteRight(rect);
} catch (Exception ex) {
Logger.printException(() -> "setSponsorBarRect failure", ex);
}
}
private static void setSponsorBarAbsoluteLeft(Rect rect) {
final int left = rect.left;
if (sponsorBarAbsoluteLeft != left) {
Logger.printDebug(() -> "setSponsorBarAbsoluteLeft: " + left);
sponsorBarAbsoluteLeft = left;
}
}
private static void setSponsorBarAbsoluteRight(Rect rect) {
final int right = rect.right;
if (sponsorAbsoluteBarRight != right) {
Logger.printDebug(() -> "setSponsorBarAbsoluteRight: " + right);
sponsorAbsoluteBarRight = right;
public static void setSeekbarRectangle(Rect seekbarRect) {
final int left = seekbarRect.left;
final int right = seekbarRect.right;
if (seekbarAbsoluteLeft != left || seekbarAbsoluteRight != right) {
Logger.printDebug(() -> "setSeekbarRectangle left: " + left + " right: " + right);
seekbarAbsoluteLeft = left;
seekbarAbsoluteRight = right;
}
}
@ -940,8 +921,8 @@ public class SegmentPlaybackController {
* injection point.
*/
@SuppressWarnings("unused")
public static void setSponsorBarThickness(int thickness) {
sponsorBarThickness = thickness;
public static void setSeekbarThickness(int thickness) {
seekbarThickness = thickness;
}
/**
@ -951,8 +932,7 @@ public class SegmentPlaybackController {
public static String appendTimeWithoutSegments(String totalTime) {
try {
if (Settings.SB_ENABLED.get() && Settings.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.get()
&& !TextUtils.isEmpty(totalTime) && !TextUtils.isEmpty(timeWithoutSegments)
&& !isAdProgressTextVisible()) {
&& !TextUtils.isEmpty(totalTime) && !TextUtils.isEmpty(timeWithoutSegments)) {
// Force LTR layout, to match the same LTR video time/length layout YouTube uses for all languages
return "\u202D" + totalTime + timeWithoutSegments; // u202D = left to right override
}
@ -980,6 +960,7 @@ public class SegmentPlaybackController {
continue;
}
foundNonhighlightSegments = true;
long start = segment.start;
final long end = segment.end;
// To prevent nested segments from incorrectly counting additional time,
@ -1011,17 +992,17 @@ public class SegmentPlaybackController {
* Injection point.
*/
@SuppressWarnings("unused")
public static void drawSponsorTimeBars(final Canvas canvas, final float posY) {
public static void drawSegmentTimeBars(final Canvas canvas, final float posY) {
try {
if (segments == null || isAdProgressTextVisible()) return;
if (segments == null) return;
final long videoLength = VideoInformation.getVideoLength();
if (videoLength <= 0) return;
final int thicknessDiv2 = sponsorBarThickness / 2; // rounds down
final float top = posY - (sponsorBarThickness - thicknessDiv2);
final int thicknessDiv2 = seekbarThickness / 2; // Rounds down.
final float top = posY - (seekbarThickness - thicknessDiv2);
final float bottom = posY + thicknessDiv2;
final float videoMillisecondsToPixels = (1f / videoLength) * (sponsorAbsoluteBarRight - sponsorBarAbsoluteLeft);
final float leftPadding = sponsorBarAbsoluteLeft;
final float videoMillisecondsToPixels = (1f / videoLength) * (seekbarAbsoluteRight - seekbarAbsoluteLeft);
final float leftPadding = seekbarAbsoluteLeft;
for (SponsorSegment segment : segments) {
final float left = leftPadding + segment.start * videoMillisecondsToPixels;

View file

@ -1,16 +1,26 @@
package app.revanced.extension.youtube.sponsorblock.ui;
import android.view.View;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController;
import app.revanced.extension.youtube.videoplayer.PlayerControlButton;
@SuppressWarnings("unused")
public class CreateSegmentButton {
private static final int DRAWABLE_SB_LOGO = Utils.getResourceIdentifierOrThrow(
ResourceType.DRAWABLE, Utils.appIsUsingBoldIcons()
? "revanced_sb_logo_bold"
: "revanced_sb_logo"
);
@Nullable
private static PlayerControlButton instance;
@ -31,6 +41,14 @@ public class CreateSegmentButton {
v -> SponsorBlockViewController.toggleNewSegmentLayoutVisibility(),
null
);
// FIXME: Bold YT player icons are currently forced off.
// Enable this logic when the new player icons are not forced off.
ImageView icon = Utils.getChildViewByResourceName(controlsView,
"revanced_sb_create_segment_button");
if (false) {
icon.setImageResource(DRAWABLE_SB_LOGO);
}
} catch (Exception ex) {
Logger.printException(() -> "initialize failure", ex);
}

View file

@ -16,6 +16,7 @@ import android.widget.ImageButton;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ui.Dim;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.youtube.patches.VideoInformation;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.sponsorblock.SponsorBlockUtils;
@ -45,8 +46,8 @@ public final class NewSegmentLayout extends FrameLayout {
final int defStyleAttr, final int defStyleRes) {
super(context, attributeSet, defStyleAttr, defStyleRes);
LayoutInflater.from(context).inflate(
getResourceIdentifierOrThrow(context, "revanced_sb_new_segment", "layout"), this, true
LayoutInflater.from(context).inflate(getResourceIdentifierOrThrow(context,
ResourceType.LAYOUT, "revanced_sb_new_segment"), this, true
);
initializeButton(
@ -105,7 +106,7 @@ public final class NewSegmentLayout extends FrameLayout {
*/
private void initializeButton(final Context context, final String resourceIdentifierName,
final ButtonOnClickHandlerFunction handler, final String debugMessage) {
ImageButton button = findViewById(getResourceIdentifierOrThrow(context, resourceIdentifierName, "id"));
ImageButton button = findViewById(getResourceIdentifierOrThrow(context, ResourceType.ID, resourceIdentifierName));
// Add ripple effect
RippleDrawable rippleDrawable = new RippleDrawable(

View file

@ -21,6 +21,7 @@ import androidx.annotation.NonNull;
import java.util.Objects;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController;
import app.revanced.extension.youtube.sponsorblock.objects.SponsorSegment;
@ -57,11 +58,10 @@ public class SkipSponsorButton extends FrameLayout {
public SkipSponsorButton(Context context, AttributeSet attributeSet, int defStyleAttr, int defStyleRes) {
super(context, attributeSet, defStyleAttr, defStyleRes);
LayoutInflater.from(context).inflate(getResourceIdentifierOrThrow(context,
"revanced_sb_skip_sponsor_button", "layout"), this, true); // layout:skip_ad_button
LayoutInflater.from(context).inflate(getResourceIdentifierOrThrow(context, ResourceType.LAYOUT, "revanced_sb_skip_sponsor_button"), this, true); // layout:skip_ad_button
setMinimumHeight(getResourceDimensionPixelSize("ad_skip_ad_button_min_height")); // dimen:ad_skip_ad_button_min_height
skipSponsorBtnContainer = Objects.requireNonNull(findViewById(getResourceIdentifierOrThrow(
context, "revanced_sb_skip_sponsor_button_container", "id"))); // id:skip_ad_button_container
context, ResourceType.ID, "revanced_sb_skip_sponsor_button_container"))); // id:skip_ad_button_container
background = new Paint();
background.setColor(getResourceColor("skip_ad_button_background_color")); // color:skip_ad_button_background_color);
@ -72,7 +72,7 @@ public class SkipSponsorButton extends FrameLayout {
border.setStrokeWidth(getResourceDimension("ad_skip_ad_button_border_width")); // dimen:ad_skip_ad_button_border_width);
border.setStyle(Paint.Style.STROKE);
skipSponsorTextView = Objects.requireNonNull(findViewById(getResourceIdentifier(context, "revanced_sb_skip_sponsor_button_text", "id"))); // id:skip_ad_button_text;
skipSponsorTextView = Objects.requireNonNull(findViewById(getResourceIdentifier(context, ResourceType.ID, "revanced_sb_skip_sponsor_button_text"))); // id:skip_ad_button_text;
defaultBottomMargin = getResourceDimensionPixelSize("skip_button_default_bottom_margin"); // dimen:skip_button_default_bottom_margin
ctaBottomMargin = getResourceDimensionPixelSize("skip_button_cta_bottom_margin"); // dimen:skip_button_cta_bottom_margin

View file

@ -1,5 +1,6 @@
package app.revanced.extension.youtube.sponsorblock.ui;
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
import static app.revanced.extension.shared.Utils.getResourceIdentifierOrThrow;
import android.content.Context;
@ -15,6 +16,7 @@ import java.lang.ref.WeakReference;
import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.shared.PlayerType;
import app.revanced.extension.youtube.sponsorblock.objects.SponsorSegment;
@ -62,16 +64,17 @@ public class SponsorBlockViewController {
Context context = Utils.getContext();
RelativeLayout layout = new RelativeLayout(context);
layout.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,RelativeLayout.LayoutParams.MATCH_PARENT));
layout.setLayoutParams(new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));
LayoutInflater.from(context).inflate(getResourceIdentifierOrThrow(
"revanced_sb_inline_sponsor_overlay", "layout"), layout);
ResourceType.LAYOUT, "revanced_sb_inline_sponsor_overlay"), layout);
inlineSponsorOverlayRef = new WeakReference<>(layout);
viewGroup.addView(layout);
viewGroup.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override
public void onChildViewAdded(View parent, View child) {
// ensure SB buttons and controls are always on top, otherwise the endscreen cards can cover the skip button
// Ensure SB buttons and controls are always on top, otherwise the end-screen cards can cover the skip button.
RelativeLayout layout = inlineSponsorOverlayRef.get();
if (layout != null) {
layout.bringToFront();
@ -83,14 +86,14 @@ public class SponsorBlockViewController {
});
youtubeOverlaysLayoutRef = new WeakReference<>(viewGroup);
skipHighlightButtonRef = new WeakReference<>(layout.findViewById(getResourceIdentifierOrThrow(
"revanced_sb_skip_highlight_button", "id")));
skipHighlightButtonRef = new WeakReference<>(Objects.requireNonNull(layout.findViewById(
getResourceIdentifier(ResourceType.ID, "revanced_sb_skip_highlight_button"))));
skipSponsorButtonRef = new WeakReference<>(layout.findViewById(getResourceIdentifierOrThrow(
"revanced_sb_skip_sponsor_button", "id")));
skipSponsorButtonRef = new WeakReference<>(Objects.requireNonNull(layout.findViewById(
getResourceIdentifier(ResourceType.ID, "revanced_sb_skip_sponsor_button"))));
NewSegmentLayout newSegmentLayout = layout.findViewById(getResourceIdentifierOrThrow(
"revanced_sb_new_segment_view", "id"));
NewSegmentLayout newSegmentLayout = Objects.requireNonNull(layout.findViewById(
getResourceIdentifier(ResourceType.ID, "revanced_sb_new_segment_view")));
newSegmentLayoutRef = new WeakReference<>(newSegmentLayout);
newSegmentLayout.updateLayout();

View file

@ -8,6 +8,7 @@ import android.view.MotionEvent
import android.view.ViewGroup
import app.revanced.extension.shared.Logger.printDebug
import app.revanced.extension.shared.Logger.printException
import app.revanced.extension.youtube.patches.VersionCheckPatch
import app.revanced.extension.youtube.settings.Settings
import app.revanced.extension.youtube.shared.PlayerType
import app.revanced.extension.youtube.swipecontrols.controller.AudioVolumeController
@ -237,6 +238,8 @@ class SwipeControlsHostActivity : Activity() {
*/
@Suppress("unused")
@JvmStatic
fun allowSwipeChangeVideo(original: Boolean): Boolean = Settings.SWIPE_CHANGE_VIDEO.get()
fun allowSwipeChangeVideo(original: Boolean): Boolean =
// Feature can cause crashing if forced in newer targets.
!VersionCheckPatch.IS_20_22_OR_GREATER && Settings.SWIPE_CHANGE_VIDEO.get()
}
}

View file

@ -3,6 +3,7 @@ package app.revanced.extension.youtube.swipecontrols.controller
import android.app.Activity
import android.util.TypedValue
import android.view.ViewGroup
import app.revanced.extension.shared.ResourceType
import app.revanced.extension.shared.Utils
import app.revanced.extension.youtube.swipecontrols.misc.Rectangle
import app.revanced.extension.youtube.swipecontrols.misc.applyDimension
@ -56,7 +57,8 @@ class SwipeZonesController(
/**
* id for R.id.player_view
*/
private val playerViewId = Utils.getResourceIdentifier(host, "player_view", "id")
private val playerViewId = Utils.getResourceIdentifier(
host, ResourceType.ID, "player_view")
/**
* current bounding rectangle of the player

View file

@ -14,12 +14,13 @@ import android.util.AttributeSet
import android.view.HapticFeedbackConstants
import android.view.View
import android.widget.RelativeLayout
import app.revanced.extension.shared.ResourceType
import app.revanced.extension.shared.StringRef.str
import app.revanced.extension.shared.Utils
import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationProvider
import app.revanced.extension.youtube.swipecontrols.misc.SwipeControlsOverlay
import kotlin.math.min
import kotlin.math.max
import kotlin.math.min
import kotlin.math.round
/**
@ -53,7 +54,7 @@ class SwipeControlsOverlayLayout(
// Function to retrieve drawable resources by name.
private fun getDrawable(name: String): Drawable {
val drawable = resources.getDrawable(
Utils.getResourceIdentifier(context, name, "drawable"),
Utils.getResourceIdentifier(context, ResourceType.DRAWABLE, name),
context.theme,
)
drawable.setTint(config.overlayTextColor)
@ -86,7 +87,7 @@ class SwipeControlsOverlayLayout(
// Initialize horizontal progress bar.
val screenWidth = resources.displayMetrics.widthPixels
val layoutWidth = (screenWidth * 4 / 5).toInt() // Cap at ~360dp.
val layoutWidth = (screenWidth * 4 / 5) // Cap at ~360dp.
horizontalProgressView = HorizontalProgressView(
context,
config.overlayBackgroundOpacity,
@ -630,7 +631,7 @@ class VerticalProgressView(
if (isMinimalStyle) {
canvas.drawText(displayText, textX, textStartY, textPaint)
} else {
val progressStartY = (iconEndY + padding).toFloat()
val progressStartY = (iconEndY + padding)
val progressEndY = textStartY - textPaint.textSize - padding
val progressHeight = progressEndY - progressStartY

View file

@ -3,8 +3,11 @@ package app.revanced.extension.youtube.videoplayer;
import static app.revanced.extension.shared.StringRef.str;
import android.view.View;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;
@ -14,9 +17,9 @@ public class LoopVideoButton {
private static PlayerControlButton instance;
private static final int LOOP_VIDEO_ON = Utils.getResourceIdentifierOrThrow(
"revanced_loop_video_button_on", "drawable");
ResourceType.DRAWABLE, "revanced_loop_video_button_on");
private static final int LOOP_VIDEO_OFF = Utils.getResourceIdentifierOrThrow(
"revanced_loop_video_button_off", "drawable");
ResourceType.DRAWABLE,"revanced_loop_video_button_off");
/**
* Injection point.

View file

@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.List;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.ResourceType;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.VideoInformation;
import app.revanced.extension.youtube.patches.playback.quality.RememberVideoQualityPatch;