mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-13 05:37:40 +02:00
feat(YouTube): Support version 19.34.42
This commit is contained in:
@ -26,9 +26,4 @@ public class InitializationPatch {
|
|||||||
showRestartDialog(mActivity, "revanced_extended_restart_first_run", 3000);
|
showRestartDialog(mActivity, "revanced_extended_restart_first_run", 3000);
|
||||||
Utils.runOnMainThreadDelayed(() -> BaseSettings.SETTINGS_INITIALIZED.save(true), 3000);
|
Utils.runOnMainThreadDelayed(() -> BaseSettings.SETTINGS_INITIALIZED.save(true), 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setDeviceInformation(@NonNull Activity mActivity) {
|
|
||||||
ExtendedUtils.setApplicationLabel();
|
|
||||||
ExtendedUtils.setVersionName();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -248,8 +248,8 @@ public class ReVancedPreferenceFragment extends PreferenceFragment {
|
|||||||
@SuppressLint("SimpleDateFormat")
|
@SuppressLint("SimpleDateFormat")
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
|
||||||
var appName = ExtendedUtils.getApplicationLabel();
|
var appName = ExtendedUtils.getAppLabel();
|
||||||
var versionName = ExtendedUtils.getVersionName();
|
var versionName = ExtendedUtils.getAppVersionName();
|
||||||
var formatDate = dateFormat.format(new Date(System.currentTimeMillis()));
|
var formatDate = dateFormat.format(new Date(System.currentTimeMillis()));
|
||||||
var fileName = String.format("%s_v%s_%s.txt", appName, versionName, formatDate);
|
var fileName = String.format("%s_v%s_%s.txt", appName, versionName, formatDate);
|
||||||
|
|
||||||
|
@ -8,16 +8,25 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
public class PackageUtils extends Utils {
|
public class PackageUtils extends Utils {
|
||||||
private static String applicationLabel = "";
|
|
||||||
private static int smallestScreenWidthDp = 0;
|
|
||||||
private static String versionName = "";
|
|
||||||
|
|
||||||
public static String getApplicationLabel() {
|
public static String getAppLabel() {
|
||||||
return applicationLabel;
|
final PackageInfo packageInfo = getPackageInfo();
|
||||||
|
if (packageInfo != null) {
|
||||||
|
final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
|
||||||
|
if (applicationInfo != null && applicationInfo.loadLabel(getPackageManager()) instanceof String applicationLabel) {
|
||||||
|
return applicationLabel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getVersionName() {
|
public static String getAppVersionName() {
|
||||||
return versionName;
|
final PackageInfo packageInfo = getPackageInfo();
|
||||||
|
if (packageInfo != null) {
|
||||||
|
return packageInfo.versionName;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPackageEnabled(@NonNull String packageName) {
|
public static boolean isPackageEnabled(@NonNull String packageName) {
|
||||||
@ -30,32 +39,11 @@ public class PackageUtils extends Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isTablet() {
|
public static boolean isTablet() {
|
||||||
return smallestScreenWidthDp >= 600;
|
return getSmallestScreenWidthDp() >= 600;
|
||||||
}
|
|
||||||
|
|
||||||
public static void setApplicationLabel() {
|
|
||||||
final PackageInfo packageInfo = getPackageInfo();
|
|
||||||
if (packageInfo != null) {
|
|
||||||
final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
|
|
||||||
if (applicationInfo != null) {
|
|
||||||
applicationLabel = (String) applicationInfo.loadLabel(getPackageManager());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setSmallestScreenWidthDp() {
|
|
||||||
smallestScreenWidthDp = context.getResources().getConfiguration().smallestScreenWidthDp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setVersionName() {
|
|
||||||
final PackageInfo packageInfo = getPackageInfo();
|
|
||||||
if (packageInfo != null) {
|
|
||||||
versionName = packageInfo.versionName;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getSmallestScreenWidthDp() {
|
public static int getSmallestScreenWidthDp() {
|
||||||
return smallestScreenWidthDp;
|
return context.getResources().getConfiguration().smallestScreenWidthDp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// utils
|
// utils
|
||||||
|
@ -78,8 +78,8 @@ public class FeedPatch {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hideFloatingButton() {
|
public static String hideFloatingButton(String fab) {
|
||||||
return Settings.HIDE_FLOATING_BUTTON.get();
|
return Settings.HIDE_FLOATING_BUTTON.get() ? null : fab;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void hideLatestVideosButton(View view) {
|
public static void hideLatestVideosButton(View view) {
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package app.revanced.extension.youtube.patches.general;
|
package app.revanced.extension.youtube.patches.general;
|
||||||
|
|
||||||
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_1;
|
import static app.revanced.extension.shared.utils.StringRef.str;
|
||||||
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_2;
|
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.*;
|
||||||
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_3;
|
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_20_OR_GREATER;
|
||||||
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.ORIGINAL;
|
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_21_OR_GREATER;
|
||||||
|
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_26_OR_GREATER;
|
||||||
|
import static app.revanced.extension.youtube.utils.ExtendedUtils.IS_19_29_OR_GREATER;
|
||||||
import static app.revanced.extension.youtube.utils.ExtendedUtils.validateValue;
|
import static app.revanced.extension.youtube.utils.ExtendedUtils.validateValue;
|
||||||
|
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
@ -17,9 +19,10 @@ import androidx.annotation.Nullable;
|
|||||||
import app.revanced.extension.shared.utils.Logger;
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
import app.revanced.extension.shared.utils.ResourceUtils;
|
import app.revanced.extension.shared.utils.ResourceUtils;
|
||||||
import app.revanced.extension.shared.utils.Utils;
|
import app.revanced.extension.shared.utils.Utils;
|
||||||
|
import app.revanced.extension.shared.settings.Setting;
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings({"unused", "SpellCheckingInspection"})
|
||||||
public final class MiniplayerPatch {
|
public final class MiniplayerPatch {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,14 +30,28 @@ public final class MiniplayerPatch {
|
|||||||
*/
|
*/
|
||||||
public enum MiniplayerType {
|
public enum MiniplayerType {
|
||||||
/**
|
/**
|
||||||
* Unmodified type, and same as un-patched.
|
* Disabled. When swiped down the miniplayer is immediately closed.
|
||||||
|
* Only available with 19.43+
|
||||||
*/
|
*/
|
||||||
|
DISABLED(false, null),
|
||||||
|
/** Unmodified type, and same as un-patched. */
|
||||||
ORIGINAL(null, null),
|
ORIGINAL(null, null),
|
||||||
|
/**
|
||||||
|
* Exactly the same as MINIMAL and only here for migration of user settings.
|
||||||
|
* Eventually this should be deleted.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
PHONE(false, null),
|
PHONE(false, null),
|
||||||
|
MINIMAL(false, null),
|
||||||
TABLET(true, null),
|
TABLET(true, null),
|
||||||
MODERN_1(null, 1),
|
MODERN_1(null, 1),
|
||||||
MODERN_2(null, 2),
|
MODERN_2(null, 2),
|
||||||
MODERN_3(null, 3);
|
MODERN_3(null, 3),
|
||||||
|
/**
|
||||||
|
* Half broken miniplayer, that might be work in progress or left over abandoned code.
|
||||||
|
* Can force this type by editing the import/export settings.
|
||||||
|
*/
|
||||||
|
MODERN_4(null, 4);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legacy tablet hook value.
|
* Legacy tablet hook value.
|
||||||
@ -58,6 +75,44 @@ public final class MiniplayerPatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final int MINIPLAYER_SIZE;
|
||||||
|
|
||||||
|
static {
|
||||||
|
// YT appears to use the device screen dip width, plus an unknown fixed horizontal padding size.
|
||||||
|
DisplayMetrics displayMetrics = Utils.getContext().getResources().getDisplayMetrics();
|
||||||
|
final int deviceDipWidth = (int) (displayMetrics.widthPixels / displayMetrics.density);
|
||||||
|
|
||||||
|
// YT seems to use a minimum height to calculate the minimum miniplayer width based on the video.
|
||||||
|
// 170 seems to be the smallest that can be used and using less makes no difference.
|
||||||
|
final int WIDTH_DIP_MIN = 170; // Seems to be the smallest that works.
|
||||||
|
final int HORIZONTAL_PADDING_DIP = 15; // Estimated padding.
|
||||||
|
// Round down to the nearest 5 pixels, to keep any error toasts easier to read.
|
||||||
|
final int WIDTH_DIP_MAX = 5 * ((deviceDipWidth - HORIZONTAL_PADDING_DIP) / 5);
|
||||||
|
Logger.printDebug(() -> "Screen dip width: " + deviceDipWidth + " maxWidth: " + WIDTH_DIP_MAX);
|
||||||
|
|
||||||
|
int dipWidth = Settings.MINIPLAYER_WIDTH_DIP.get();
|
||||||
|
|
||||||
|
if (dipWidth < WIDTH_DIP_MIN || dipWidth > WIDTH_DIP_MAX) {
|
||||||
|
Utils.showToastLong(str("revanced_miniplayer_width_dip_invalid_toast",
|
||||||
|
WIDTH_DIP_MIN, WIDTH_DIP_MAX));
|
||||||
|
|
||||||
|
// Instead of resetting, clamp the size at the bounds.
|
||||||
|
dipWidth = Math.max(WIDTH_DIP_MIN, Math.min(dipWidth, WIDTH_DIP_MAX));
|
||||||
|
Settings.MINIPLAYER_WIDTH_DIP.save(dipWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
MINIPLAYER_SIZE = dipWidth;
|
||||||
|
|
||||||
|
final int opacity = validateValue(
|
||||||
|
Settings.MINIPLAYER_OPACITY,
|
||||||
|
0,
|
||||||
|
100,
|
||||||
|
"revanced_miniplayer_opacity_invalid_toast"
|
||||||
|
);
|
||||||
|
|
||||||
|
OPACITY_LEVEL = (opacity * 255) / 100;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modern subtitle overlay for {@link MiniplayerType#MODERN_2}.
|
* Modern subtitle overlay for {@link MiniplayerType#MODERN_2}.
|
||||||
* Resource is not present in older targets, and this field will be zero.
|
* Resource is not present in older targets, and this field will be zero.
|
||||||
@ -67,19 +122,21 @@ public final class MiniplayerPatch {
|
|||||||
|
|
||||||
private static final MiniplayerType CURRENT_TYPE = Settings.MINIPLAYER_TYPE.get();
|
private static final MiniplayerType CURRENT_TYPE = Settings.MINIPLAYER_TYPE.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cannot turn off double tap with modern 2 or 3 with later targets,
|
||||||
|
* as forcing it off breakings tapping the miniplayer.
|
||||||
|
*/
|
||||||
private static final boolean DOUBLE_TAP_ACTION_ENABLED =
|
private static final boolean DOUBLE_TAP_ACTION_ENABLED =
|
||||||
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_2 || CURRENT_TYPE == MODERN_3) && Settings.MINIPLAYER_DOUBLE_TAP_ACTION.get();
|
// 19.29+ is very broken if double tap is not enabled.
|
||||||
|
IS_19_29_OR_GREATER ||
|
||||||
|
(CURRENT_TYPE.isModern() && Settings.MINIPLAYER_DOUBLE_TAP_ACTION.get());
|
||||||
|
|
||||||
private static final boolean DRAG_AND_DROP_ENABLED =
|
private static final boolean DRAG_AND_DROP_ENABLED =
|
||||||
CURRENT_TYPE == MODERN_1 && Settings.MINIPLAYER_DRAG_AND_DROP.get();
|
CURRENT_TYPE.isModern() && Settings.MINIPLAYER_DRAG_AND_DROP.get();
|
||||||
|
|
||||||
private static final boolean HIDE_EXPAND_CLOSE_AVAILABLE =
|
|
||||||
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3) &&
|
|
||||||
!DOUBLE_TAP_ACTION_ENABLED &&
|
|
||||||
!DRAG_AND_DROP_ENABLED;
|
|
||||||
|
|
||||||
private static final boolean HIDE_EXPAND_CLOSE_ENABLED =
|
private static final boolean HIDE_EXPAND_CLOSE_ENABLED =
|
||||||
HIDE_EXPAND_CLOSE_AVAILABLE && Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.get();
|
Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.get()
|
||||||
|
&& Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.isAvailable();
|
||||||
|
|
||||||
private static final boolean HIDE_SUBTEXT_ENABLED =
|
private static final boolean HIDE_SUBTEXT_ENABLED =
|
||||||
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3) && Settings.MINIPLAYER_HIDE_SUBTEXT.get();
|
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3) && Settings.MINIPLAYER_HIDE_SUBTEXT.get();
|
||||||
@ -87,17 +144,49 @@ public final class MiniplayerPatch {
|
|||||||
private static final boolean HIDE_REWIND_FORWARD_ENABLED =
|
private static final boolean HIDE_REWIND_FORWARD_ENABLED =
|
||||||
CURRENT_TYPE == MODERN_1 && Settings.MINIPLAYER_HIDE_REWIND_FORWARD.get();
|
CURRENT_TYPE == MODERN_1 && Settings.MINIPLAYER_HIDE_REWIND_FORWARD.get();
|
||||||
|
|
||||||
|
private static final boolean MINIPLAYER_ROUNDED_CORNERS_ENABLED =
|
||||||
|
Settings.MINIPLAYER_ROUNDED_CORNERS.get();
|
||||||
|
|
||||||
|
private static final boolean MINIPLAYER_HORIZONTAL_DRAG_ENABLED =
|
||||||
|
DRAG_AND_DROP_ENABLED && Settings.MINIPLAYER_HORIZONTAL_DRAG.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a broken and always present subtitle text that is only
|
||||||
|
* present with {@link MiniplayerType#MODERN_2}. Bug was fixed in 19.21.
|
||||||
|
*/
|
||||||
|
private static final boolean HIDE_BROKEN_MODERN_2_SUBTITLE =
|
||||||
|
CURRENT_TYPE == MODERN_2 && !IS_19_21_OR_GREATER;
|
||||||
|
|
||||||
private static final int OPACITY_LEVEL;
|
private static final int OPACITY_LEVEL;
|
||||||
|
|
||||||
static {
|
public static final class MiniplayerHorizontalDragAvailability implements Setting.Availability {
|
||||||
final int opacity = validateValue(
|
@Override
|
||||||
Settings.MINIPLAYER_OPACITY,
|
public boolean isAvailable() {
|
||||||
0,
|
return Settings.MINIPLAYER_TYPE.get().isModern() && Settings.MINIPLAYER_DRAG_AND_DROP.get();
|
||||||
100,
|
}
|
||||||
"revanced_miniplayer_opacity_invalid_toast"
|
}
|
||||||
);
|
|
||||||
|
|
||||||
OPACITY_LEVEL = (opacity * 255) / 100;
|
public static final class MiniplayerHideExpandCloseAvailability implements Setting.Availability {
|
||||||
|
@Override
|
||||||
|
public boolean isAvailable() {
|
||||||
|
MiniplayerType type = Settings.MINIPLAYER_TYPE.get();
|
||||||
|
return (!IS_19_20_OR_GREATER && (type == MODERN_1 || type == MODERN_3))
|
||||||
|
|| (!IS_19_26_OR_GREATER && type == MODERN_1
|
||||||
|
&& !Settings.MINIPLAYER_DOUBLE_TAP_ACTION.get() && !Settings.MINIPLAYER_DRAG_AND_DROP.get())
|
||||||
|
|| (IS_19_29_OR_GREATER && type == MODERN_3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
* <p>
|
||||||
|
* Enables a handler that immediately closes the miniplayer when the video is minimized,
|
||||||
|
* effectively disabling the miniplayer.
|
||||||
|
*/
|
||||||
|
public static boolean getMiniplayerOnCloseHandler(boolean original) {
|
||||||
|
return CURRENT_TYPE == ORIGINAL
|
||||||
|
? original
|
||||||
|
: CURRENT_TYPE == DISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -141,17 +230,71 @@ public final class MiniplayerPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static boolean enableMiniplayerDoubleTapAction() {
|
public static boolean getModernFeatureFlagsActiveOverride(boolean original) {
|
||||||
|
if (CURRENT_TYPE == ORIGINAL) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CURRENT_TYPE.isModern();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean enableMiniplayerDoubleTapAction(boolean original) {
|
||||||
|
if (CURRENT_TYPE == ORIGINAL) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
return DOUBLE_TAP_ACTION_ENABLED;
|
return DOUBLE_TAP_ACTION_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static boolean enableMiniplayerDragAndDrop() {
|
public static boolean enableMiniplayerDragAndDrop(boolean original) {
|
||||||
|
if (CURRENT_TYPE == ORIGINAL) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
return DRAG_AND_DROP_ENABLED;
|
return DRAG_AND_DROP_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean setRoundedCorners(boolean original) {
|
||||||
|
if (CURRENT_TYPE.isModern()) {
|
||||||
|
return MINIPLAYER_ROUNDED_CORNERS_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static int setMiniplayerDefaultSize(int original) {
|
||||||
|
if (CURRENT_TYPE.isModern()) {
|
||||||
|
return MINIPLAYER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static boolean setHorizontalDrag(boolean original) {
|
||||||
|
if (CURRENT_TYPE.isModern()) {
|
||||||
|
return MINIPLAYER_HORIZONTAL_DRAG_ENABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
@ -169,29 +312,36 @@ public final class MiniplayerPatch {
|
|||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static boolean hideMiniplayerSubTexts(View view) {
|
public static void hideMiniplayerSubTexts(View view) {
|
||||||
// Different subviews are passed in, but only TextView and layouts are of interest here.
|
try {
|
||||||
final boolean hideView = HIDE_SUBTEXT_ENABLED && (view instanceof TextView || view instanceof LinearLayout);
|
// Different subviews are passed in, but only TextView is of interest here.
|
||||||
Utils.hideViewByRemovingFromParentUnderCondition(hideView, view);
|
if (HIDE_SUBTEXT_ENABLED && view instanceof TextView) {
|
||||||
return hideView || view == null;
|
Logger.printDebug(() -> "Hiding subtext view");
|
||||||
|
Utils.hideViewByRemovingFromParentUnderCondition(true, view);
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "hideMiniplayerSubTexts failure", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static void playerOverlayGroupCreated(View group) {
|
public static void playerOverlayGroupCreated(View group) {
|
||||||
// Modern 2 has an half broken subtitle that is always present.
|
try {
|
||||||
// Always hide it to make the miniplayer mostly usable.
|
if (HIDE_BROKEN_MODERN_2_SUBTITLE && MODERN_OVERLAY_SUBTITLE_TEXT != 0) {
|
||||||
if (CURRENT_TYPE == MODERN_2 && MODERN_OVERLAY_SUBTITLE_TEXT != 0) {
|
if (group instanceof ViewGroup) {
|
||||||
if (group instanceof ViewGroup viewGroup) {
|
View subtitleText = Utils.getChildView((ViewGroup) group, true,
|
||||||
View subtitleText = Utils.getChildView(viewGroup, true,
|
view -> view.getId() == MODERN_OVERLAY_SUBTITLE_TEXT);
|
||||||
view -> view.getId() == MODERN_OVERLAY_SUBTITLE_TEXT);
|
|
||||||
|
|
||||||
if (subtitleText != null) {
|
if (subtitleText != null) {
|
||||||
subtitleText.setVisibility(View.GONE);
|
subtitleText.setVisibility(View.GONE);
|
||||||
Logger.printDebug(() -> "Modern overlay subtitle view set to hidden");
|
Logger.printDebug(() -> "Modern overlay subtitle view set to hidden");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "playerOverlayGroupCreated failure", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -31,9 +31,6 @@ public class InitializationPatch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void setExtendedUtils(@NonNull Activity mActivity) {
|
public static void setExtendedUtils(@NonNull Activity mActivity) {
|
||||||
ExtendedUtils.setApplicationLabel();
|
|
||||||
ExtendedUtils.setSmallestScreenWidthDp();
|
|
||||||
ExtendedUtils.setVersionName();
|
|
||||||
ExtendedUtils.setPlayerFlyoutMenuAdditionalSettings();
|
ExtendedUtils.setPlayerFlyoutMenuAdditionalSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,6 +10,7 @@ import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.Min
|
|||||||
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_1;
|
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_1;
|
||||||
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_2;
|
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_2;
|
||||||
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_3;
|
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_3;
|
||||||
|
import static app.revanced.extension.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_4;
|
||||||
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP;
|
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP;
|
||||||
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY;
|
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY;
|
||||||
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE;
|
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE;
|
||||||
@ -34,6 +35,7 @@ import app.revanced.extension.youtube.patches.alternativethumbnails.AlternativeT
|
|||||||
import app.revanced.extension.youtube.patches.general.ChangeStartPagePatch;
|
import app.revanced.extension.youtube.patches.general.ChangeStartPagePatch;
|
||||||
import app.revanced.extension.youtube.patches.general.ChangeStartPagePatch.StartPage;
|
import app.revanced.extension.youtube.patches.general.ChangeStartPagePatch.StartPage;
|
||||||
import app.revanced.extension.youtube.patches.general.LayoutSwitchPatch.FormFactor;
|
import app.revanced.extension.youtube.patches.general.LayoutSwitchPatch.FormFactor;
|
||||||
|
import app.revanced.extension.youtube.patches.general.MiniplayerPatch;
|
||||||
import app.revanced.extension.youtube.patches.general.YouTubeMusicActionsPatch;
|
import app.revanced.extension.youtube.patches.general.YouTubeMusicActionsPatch;
|
||||||
import app.revanced.extension.youtube.patches.misc.SpoofStreamingDataPatch;
|
import app.revanced.extension.youtube.patches.misc.SpoofStreamingDataPatch;
|
||||||
import app.revanced.extension.youtube.patches.misc.WatchHistoryPatch.WatchHistoryType;
|
import app.revanced.extension.youtube.patches.misc.WatchHistoryPatch.WatchHistoryType;
|
||||||
@ -167,11 +169,15 @@ public class Settings extends BaseSettings {
|
|||||||
|
|
||||||
// PreferenceScreen: General - Miniplayer
|
// PreferenceScreen: General - Miniplayer
|
||||||
public static final EnumSetting<MiniplayerType> MINIPLAYER_TYPE = new EnumSetting<>("revanced_miniplayer_type", MiniplayerType.ORIGINAL, true);
|
public static final EnumSetting<MiniplayerType> MINIPLAYER_TYPE = new EnumSetting<>("revanced_miniplayer_type", MiniplayerType.ORIGINAL, true);
|
||||||
public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_enable_double_tap_action", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_2, MODERN_3));
|
private static final Setting.Availability MINIPLAYER_ANY_MODERN = MINIPLAYER_TYPE.availability(MODERN_1, MODERN_2, MODERN_3, MODERN_4);
|
||||||
public static final BooleanSetting MINIPLAYER_DRAG_AND_DROP = new BooleanSetting("revanced_miniplayer_enable_drag_and_drop", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1));
|
public static final BooleanSetting MINIPLAYER_DOUBLE_TAP_ACTION = new BooleanSetting("revanced_miniplayer_double_tap_action", TRUE, true, MINIPLAYER_ANY_MODERN);
|
||||||
public static final BooleanSetting MINIPLAYER_HIDE_EXPAND_CLOSE = new BooleanSetting("revanced_miniplayer_hide_expand_close", FALSE, true);
|
public static final BooleanSetting MINIPLAYER_DRAG_AND_DROP = new BooleanSetting("revanced_miniplayer_drag_and_drop", TRUE, true, MINIPLAYER_ANY_MODERN);
|
||||||
|
public static final BooleanSetting MINIPLAYER_HORIZONTAL_DRAG = new BooleanSetting("revanced_miniplayer_horizontal_drag", FALSE, true, new MiniplayerPatch.MiniplayerHorizontalDragAvailability());
|
||||||
|
public static final BooleanSetting MINIPLAYER_HIDE_EXPAND_CLOSE = new BooleanSetting("revanced_miniplayer_hide_expand_close", FALSE, true, new MiniplayerPatch.MiniplayerHideExpandCloseAvailability());
|
||||||
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3));
|
public static final BooleanSetting MINIPLAYER_HIDE_SUBTEXT = new BooleanSetting("revanced_miniplayer_hide_subtext", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1, MODERN_3));
|
||||||
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1));
|
public static final BooleanSetting MINIPLAYER_HIDE_REWIND_FORWARD = new BooleanSetting("revanced_miniplayer_hide_rewind_forward", FALSE, true, MINIPLAYER_TYPE.availability(MODERN_1));
|
||||||
|
public static final BooleanSetting MINIPLAYER_ROUNDED_CORNERS = new BooleanSetting("revanced_miniplayer_rounded_corners", TRUE, true, MINIPLAYER_ANY_MODERN);
|
||||||
|
public static final IntegerSetting MINIPLAYER_WIDTH_DIP = new IntegerSetting("revanced_miniplayer_width_dip", 192, true, MINIPLAYER_ANY_MODERN);
|
||||||
public static final IntegerSetting MINIPLAYER_OPACITY = new IntegerSetting("revanced_miniplayer_opacity", 100, true, MINIPLAYER_TYPE.availability(MODERN_1));
|
public static final IntegerSetting MINIPLAYER_OPACITY = new IntegerSetting("revanced_miniplayer_opacity", 100, true, MINIPLAYER_TYPE.availability(MODERN_1));
|
||||||
|
|
||||||
// PreferenceScreen: General - Navigation bar
|
// PreferenceScreen: General - Navigation bar
|
||||||
|
@ -593,8 +593,8 @@ public class ReVancedPreferenceFragment extends PreferenceFragment {
|
|||||||
private void exportActivity() {
|
private void exportActivity() {
|
||||||
@SuppressLint("SimpleDateFormat") final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
@SuppressLint("SimpleDateFormat") final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
|
||||||
final String appName = ExtendedUtils.getApplicationLabel();
|
final String appName = ExtendedUtils.getAppLabel();
|
||||||
final String versionName = ExtendedUtils.getVersionName();
|
final String versionName = ExtendedUtils.getAppVersionName();
|
||||||
final String formatDate = dateFormat.format(new Date(System.currentTimeMillis()));
|
final String formatDate = dateFormat.format(new Date(System.currentTimeMillis()));
|
||||||
final String fileName = String.format("%s_v%s_%s.txt", appName, versionName, formatDate);
|
final String fileName = String.format("%s_v%s_%s.txt", appName, versionName, formatDate);
|
||||||
|
|
||||||
|
@ -12,6 +12,12 @@ import app.revanced.extension.shared.utils.PackageUtils;
|
|||||||
import app.revanced.extension.youtube.settings.Settings;
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
|
||||||
public class ExtendedUtils extends PackageUtils {
|
public class ExtendedUtils extends PackageUtils {
|
||||||
|
public static final boolean IS_19_17_OR_GREATER = getAppVersionName().compareTo("19.17.00") >= 0;
|
||||||
|
public static final boolean IS_19_20_OR_GREATER = getAppVersionName().compareTo("19.20.00") >= 0;
|
||||||
|
public static final boolean IS_19_21_OR_GREATER = getAppVersionName().compareTo("19.21.00") >= 0;
|
||||||
|
public static final boolean IS_19_26_OR_GREATER = getAppVersionName().compareTo("19.26.00") >= 0;
|
||||||
|
public static final boolean IS_19_29_OR_GREATER = getAppVersionName().compareTo("19.29.00") >= 0;
|
||||||
|
public static final boolean IS_19_34_OR_GREATER = getAppVersionName().compareTo("19.34.00") >= 0;
|
||||||
|
|
||||||
public static int validateValue(IntegerSetting settings, int min, int max, String message) {
|
public static int validateValue(IntegerSetting settings, int min, int max, String message) {
|
||||||
int value = settings.get();
|
int value = settings.get();
|
||||||
|
@ -14,6 +14,7 @@ import app.revanced.patches.music.utils.settings.settingsPatch
|
|||||||
import app.revanced.util.ResourceGroup
|
import app.revanced.util.ResourceGroup
|
||||||
import app.revanced.util.Utils.trimIndentMultiline
|
import app.revanced.util.Utils.trimIndentMultiline
|
||||||
import app.revanced.util.copyResources
|
import app.revanced.util.copyResources
|
||||||
|
import app.revanced.util.getAdaptiveIconResourceFile
|
||||||
import app.revanced.util.getResourceGroup
|
import app.revanced.util.getResourceGroup
|
||||||
import app.revanced.util.underBarOrThrow
|
import app.revanced.util.underBarOrThrow
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
@ -248,38 +249,23 @@ val customBrandingIconPatch = resourcePatch(
|
|||||||
return@execute
|
return@execute
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getAdaptiveIconResourceFile(tag: String): String {
|
|
||||||
document("res/mipmap-anydpi/ic_launcher_release.xml").use { document ->
|
|
||||||
val adaptiveIcon = document
|
|
||||||
.getElementsByTagName("adaptive-icon")
|
|
||||||
.item(0) as Element
|
|
||||||
|
|
||||||
val childNodes = adaptiveIcon.childNodes
|
|
||||||
for (i in 0 until childNodes.length) {
|
|
||||||
val node = childNodes.item(i)
|
|
||||||
if (node is Element && node.tagName == tag && node.hasAttribute("android:drawable")) {
|
|
||||||
return node.getAttribute("android:drawable").split("/")[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw PatchException("Element not found: $tag")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mapOf(
|
mapOf(
|
||||||
ADAPTIVE_ICON_BACKGROUND_FILE_NAME to getAdaptiveIconResourceFile("background"),
|
ADAPTIVE_ICON_BACKGROUND_FILE_NAME to getAdaptiveIconResourceFile("res/mipmap-anydpi/ic_launcher_release.xml", "background"),
|
||||||
ADAPTIVE_ICON_FOREGROUND_FILE_NAME to getAdaptiveIconResourceFile("foreground")
|
ADAPTIVE_ICON_FOREGROUND_FILE_NAME to getAdaptiveIconResourceFile("res/mipmap-anydpi/ic_launcher_release.xml", "foreground")
|
||||||
).forEach { (oldIconResourceFile, newIconResourceFile) ->
|
).forEach { (oldIconResourceFile, newIconResourceFile) ->
|
||||||
mipmapDirectories.forEach {
|
if (oldIconResourceFile != newIconResourceFile) {
|
||||||
val mipmapDirectory = resourceDirectory.resolve(it)
|
mipmapDirectories.forEach {
|
||||||
Files.move(
|
val mipmapDirectory = resourceDirectory.resolve(it)
|
||||||
mipmapDirectory
|
Files.move(
|
||||||
.resolve("$oldIconResourceFile.png")
|
mipmapDirectory
|
||||||
.toPath(),
|
.resolve("$oldIconResourceFile.png")
|
||||||
mipmapDirectory
|
.toPath(),
|
||||||
.resolve("$newIconResourceFile.png")
|
mipmapDirectory
|
||||||
.toPath(),
|
.resolve("$newIconResourceFile.png")
|
||||||
StandardCopyOption.REPLACE_EXISTING
|
.toPath(),
|
||||||
)
|
StandardCopyOption.REPLACE_EXISTING
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,10 +112,6 @@ private val settingsBytecodePatch = bytecodePatch(
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
injectOnCreateMethodCall(
|
|
||||||
EXTENSION_INITIALIZATION_CLASS_DESCRIPTOR,
|
|
||||||
"setDeviceInformation"
|
|
||||||
)
|
|
||||||
injectOnCreateMethodCall(
|
injectOnCreateMethodCall(
|
||||||
EXTENSION_INITIALIZATION_CLASS_DESCRIPTOR,
|
EXTENSION_INITIALIZATION_CLASS_DESCRIPTOR,
|
||||||
"onCreate"
|
"onCreate"
|
||||||
|
@ -147,18 +147,22 @@ val feedComponentsPatch = bytecodePatch(
|
|||||||
// region patch for hide floating button
|
// region patch for hide floating button
|
||||||
|
|
||||||
onCreateMethod.apply {
|
onCreateMethod.apply {
|
||||||
val fabIndex = indexOfFirstInstructionOrThrow {
|
val stringIndex = indexOfFirstInstructionOrThrow {
|
||||||
opcode == Opcode.CONST_STRING &&
|
opcode == Opcode.CONST_STRING &&
|
||||||
getReference<StringReference>()?.string == "fab"
|
getReference<StringReference>()?.string == "fab"
|
||||||
}
|
}
|
||||||
val fabRegister = getInstruction<OneRegisterInstruction>(fabIndex).registerA
|
val stringRegister = getInstruction<OneRegisterInstruction>(stringIndex).registerA
|
||||||
val jumpIndex = indexOfFirstInstructionOrThrow(fabIndex + 1, Opcode.CONST_STRING)
|
val insertIndex = indexOfFirstInstructionOrThrow(stringIndex) {
|
||||||
|
opcode == Opcode.INVOKE_DIRECT &&
|
||||||
|
getReference<MethodReference>()?.name == "<init>"
|
||||||
|
}
|
||||||
|
val jumpIndex = indexOfFirstInstructionOrThrow(insertIndex, Opcode.CONST_STRING)
|
||||||
|
|
||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
fabIndex, """
|
insertIndex, """
|
||||||
invoke-static {}, $FEED_CLASS_DESCRIPTOR->hideFloatingButton()Z
|
invoke-static {v$stringRegister}, $FEED_CLASS_DESCRIPTOR->hideFloatingButton(Ljava/lang/String;)Ljava/lang/String;
|
||||||
move-result v$fabRegister
|
move-result-object v$stringRegister
|
||||||
if-nez v$fabRegister, :hide
|
if-eqz v$stringRegister, :hide
|
||||||
""", ExternalLabel("hide", getInstruction(jumpIndex))
|
""", ExternalLabel("hide", getInstruction(jumpIndex))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -2,20 +2,18 @@
|
|||||||
|
|
||||||
package app.revanced.patches.youtube.general.miniplayer
|
package app.revanced.patches.youtube.general.miniplayer
|
||||||
|
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
|
|
||||||
import app.revanced.patches.youtube.utils.resourceid.floatyBarTopMargin
|
import app.revanced.patches.youtube.utils.resourceid.floatyBarTopMargin
|
||||||
|
import app.revanced.patches.youtube.utils.resourceid.miniplayerMaxSize
|
||||||
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerClose
|
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerClose
|
||||||
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerExpand
|
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerExpand
|
||||||
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerForwardButton
|
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerForwardButton
|
||||||
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerRewindButton
|
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerRewindButton
|
||||||
import app.revanced.patches.youtube.utils.resourceid.scrimOverlay
|
import app.revanced.patches.youtube.utils.resourceid.scrimOverlay
|
||||||
import app.revanced.patches.youtube.utils.resourceid.ytOutlinePictureInPictureWhite
|
import app.revanced.patches.youtube.utils.resourceid.ytOutlinePictureInPictureWhite
|
||||||
import app.revanced.util.containsLiteralInstruction
|
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
import app.revanced.util.or
|
import app.revanced.util.or
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
|
||||||
|
|
||||||
internal val miniplayerDimensionsCalculatorParentFingerprint = legacyFingerprint(
|
internal val miniplayerDimensionsCalculatorParentFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerDimensionsCalculatorParentFingerprint",
|
name = "miniplayerDimensionsCalculatorParentFingerprint",
|
||||||
@ -25,6 +23,9 @@ internal val miniplayerDimensionsCalculatorParentFingerprint = legacyFingerprint
|
|||||||
literals = listOf(floatyBarTopMargin),
|
literals = listOf(floatyBarTopMargin),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches using the class found in [miniplayerModernViewParentFingerprint].
|
||||||
|
*/
|
||||||
internal val miniplayerModernAddViewListenerFingerprint = legacyFingerprint(
|
internal val miniplayerModernAddViewListenerFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernAddViewListenerFingerprint",
|
name = "miniplayerModernAddViewListenerFingerprint",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
@ -32,6 +33,9 @@ internal val miniplayerModernAddViewListenerFingerprint = legacyFingerprint(
|
|||||||
parameters = listOf("Landroid/view/View;")
|
parameters = listOf("Landroid/view/View;")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches using the class found in [miniplayerModernViewParentFingerprint].
|
||||||
|
*/
|
||||||
internal val miniplayerModernCloseButtonFingerprint = legacyFingerprint(
|
internal val miniplayerModernCloseButtonFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernCloseButtonFingerprint",
|
name = "miniplayerModernCloseButtonFingerprint",
|
||||||
returnType = "Landroid/widget/ImageView;",
|
returnType = "Landroid/widget/ImageView;",
|
||||||
@ -40,41 +44,33 @@ internal val miniplayerModernCloseButtonFingerprint = legacyFingerprint(
|
|||||||
literals = listOf(modernMiniPlayerClose),
|
literals = listOf(modernMiniPlayerClose),
|
||||||
)
|
)
|
||||||
|
|
||||||
private var constructorMethodCount = 0
|
internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L
|
||||||
|
// In later targets this feature flag does nothing and is dead code.
|
||||||
internal fun isMultiConstructorMethod() = constructorMethodCount > 1
|
internal const val MINIPLAYER_MODERN_FEATURE_LEGACY_KEY = 45630429L
|
||||||
|
internal const val MINIPLAYER_DOUBLE_TAP_FEATURE_KEY = 45628823L
|
||||||
|
internal const val MINIPLAYER_DRAG_DROP_FEATURE_KEY = 45628752L
|
||||||
|
internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L
|
||||||
|
internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L
|
||||||
|
internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L
|
||||||
|
internal const val MINIPLAYER_DISABLED_FEATURE_KEY = 45657015L
|
||||||
|
|
||||||
internal val miniplayerModernConstructorFingerprint = legacyFingerprint(
|
internal val miniplayerModernConstructorFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernConstructorFingerprint",
|
name = "miniplayerModernConstructorFingerprint",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
parameters = listOf("L"),
|
parameters = listOf("L"),
|
||||||
literals = listOf(45623000L),
|
literals = listOf(45623000L),
|
||||||
customFingerprint = custom@{ method, classDef ->
|
|
||||||
classDef.methods.forEach {
|
|
||||||
if (MethodUtil.isConstructor(it)) constructorMethodCount += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_19_25_or_greater)
|
|
||||||
return@custom true
|
|
||||||
|
|
||||||
// Double tap action (Used in YouTube 19.25.39+).
|
|
||||||
method.containsLiteralInstruction(45628823L)
|
|
||||||
&& method.containsLiteralInstruction(45630429L)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val miniplayerModernDragAndDropFingerprint = legacyFingerprint(
|
internal val miniplayerOnCloseHandlerFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernDragAndDropFingerprint",
|
name = "miniplayerOnCloseHandlerFingerprint",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("L"),
|
returnType = "Z",
|
||||||
literals = listOf(45628752L),
|
literals = listOf(MINIPLAYER_DISABLED_FEATURE_KEY),
|
||||||
)
|
|
||||||
|
|
||||||
internal val miniplayerModernEnabledFingerprint = legacyFingerprint(
|
|
||||||
name = "miniplayerModernEnabledFingerprint",
|
|
||||||
literals = listOf(45622882L),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches using the class found in [miniplayerModernViewParentFingerprint].
|
||||||
|
*/
|
||||||
internal val miniplayerModernExpandButtonFingerprint = legacyFingerprint(
|
internal val miniplayerModernExpandButtonFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernExpandButtonFingerprint",
|
name = "miniplayerModernExpandButtonFingerprint",
|
||||||
returnType = "Landroid/widget/ImageView;",
|
returnType = "Landroid/widget/ImageView;",
|
||||||
@ -83,6 +79,9 @@ internal val miniplayerModernExpandButtonFingerprint = legacyFingerprint(
|
|||||||
literals = listOf(modernMiniPlayerExpand),
|
literals = listOf(modernMiniPlayerExpand),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches using the class found in [miniplayerModernViewParentFingerprint].
|
||||||
|
*/
|
||||||
internal val miniplayerModernExpandCloseDrawablesFingerprint = legacyFingerprint(
|
internal val miniplayerModernExpandCloseDrawablesFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernExpandCloseDrawablesFingerprint",
|
name = "miniplayerModernExpandCloseDrawablesFingerprint",
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
@ -91,6 +90,9 @@ internal val miniplayerModernExpandCloseDrawablesFingerprint = legacyFingerprint
|
|||||||
literals = listOf(ytOutlinePictureInPictureWhite),
|
literals = listOf(ytOutlinePictureInPictureWhite),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches using the class found in [miniplayerModernViewParentFingerprint].
|
||||||
|
*/
|
||||||
internal val miniplayerModernForwardButtonFingerprint = legacyFingerprint(
|
internal val miniplayerModernForwardButtonFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernForwardButtonFingerprint",
|
name = "miniplayerModernForwardButtonFingerprint",
|
||||||
returnType = "Landroid/widget/ImageView;",
|
returnType = "Landroid/widget/ImageView;",
|
||||||
@ -99,6 +101,9 @@ internal val miniplayerModernForwardButtonFingerprint = legacyFingerprint(
|
|||||||
literals = listOf(modernMiniPlayerForwardButton),
|
literals = listOf(modernMiniPlayerForwardButton),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches using the class found in [miniplayerModernViewParentFingerprint].
|
||||||
|
*/
|
||||||
internal val miniplayerModernOverlayViewFingerprint = legacyFingerprint(
|
internal val miniplayerModernOverlayViewFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernOverlayViewFingerprint",
|
name = "miniplayerModernOverlayViewFingerprint",
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
@ -107,6 +112,9 @@ internal val miniplayerModernOverlayViewFingerprint = legacyFingerprint(
|
|||||||
literals = listOf(scrimOverlay),
|
literals = listOf(scrimOverlay),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches using the class found in [miniplayerModernViewParentFingerprint].
|
||||||
|
*/
|
||||||
internal val miniplayerModernRewindButtonFingerprint = legacyFingerprint(
|
internal val miniplayerModernRewindButtonFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerModernRewindButtonFingerprint",
|
name = "miniplayerModernRewindButtonFingerprint",
|
||||||
returnType = "Landroid/widget/ImageView;",
|
returnType = "Landroid/widget/ImageView;",
|
||||||
@ -123,11 +131,16 @@ internal val miniplayerModernViewParentFingerprint = legacyFingerprint(
|
|||||||
strings = listOf("player_overlay_modern_mini_player_controls")
|
strings = listOf("player_overlay_modern_mini_player_controls")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal val miniplayerMinimumSizeFingerprint = legacyFingerprint(
|
||||||
|
name = "miniplayerMinimumSizeFingerprint",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
literals = listOf(192L, 128L, miniplayerMaxSize),
|
||||||
|
)
|
||||||
|
|
||||||
internal val miniplayerOverrideFingerprint = legacyFingerprint(
|
internal val miniplayerOverrideFingerprint = legacyFingerprint(
|
||||||
name = "miniplayerOverrideFingerprint",
|
name = "miniplayerOverrideFingerprint",
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("L"),
|
|
||||||
strings = listOf("appName")
|
strings = listOf("appName")
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -144,6 +157,7 @@ internal val miniplayerResponseModelSizeCheckFingerprint = legacyFingerprint(
|
|||||||
returnType = "L",
|
returnType = "L",
|
||||||
parameters = listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
|
parameters = listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
|
Opcode.RETURN_OBJECT,
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
@ -152,12 +166,12 @@ internal val miniplayerResponseModelSizeCheckFingerprint = legacyFingerprint(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME =
|
||||||
|
"Lcom/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout;"
|
||||||
|
|
||||||
internal val youTubePlayerOverlaysLayoutFingerprint = legacyFingerprint(
|
internal val youTubePlayerOverlaysLayoutFingerprint = legacyFingerprint(
|
||||||
name = "youTubePlayerOverlaysLayoutFingerprint",
|
name = "youTubePlayerOverlaysLayoutFingerprint",
|
||||||
customFingerprint = { _, classDef ->
|
customFingerprint = { _, classDef ->
|
||||||
classDef.type == YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
|
classDef.type == YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
internal const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME =
|
|
||||||
"Lcom/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout;"
|
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
package app.revanced.patches.youtube.general.miniplayer
|
package app.revanced.patches.youtube.general.miniplayer
|
||||||
|
|
||||||
import app.revanced.patcher.Fingerprint
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
|
||||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
|
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
|
||||||
import app.revanced.patches.youtube.utils.patch.PatchList.MINIPLAYER
|
import app.revanced.patches.youtube.utils.patch.PatchList.MINIPLAYER
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_15_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_15_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_19_26_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_19_29_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_19_36_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_19_43_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerClose
|
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerClose
|
||||||
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerExpand
|
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerExpand
|
||||||
@ -28,6 +28,7 @@ import app.revanced.patches.youtube.utils.resourceid.ytOutlinePictureInPictureWh
|
|||||||
import app.revanced.patches.youtube.utils.resourceid.ytOutlineXWhite
|
import app.revanced.patches.youtube.utils.resourceid.ytOutlineXWhite
|
||||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||||
|
import app.revanced.util.addInstructionsAtControlFlowLabel
|
||||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||||
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
|
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
|
||||||
import app.revanced.util.fingerprint.matchOrThrow
|
import app.revanced.util.fingerprint.matchOrThrow
|
||||||
@ -41,14 +42,13 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
|||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
|
||||||
|
|
||||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
"$GENERAL_PATH/MiniplayerPatch;"
|
"$GENERAL_PATH/MiniplayerPatch;"
|
||||||
@ -83,7 +83,7 @@ val miniplayerPatch = bytecodePatch(
|
|||||||
"""
|
"""
|
||||||
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Z)Z
|
invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Z)Z
|
||||||
move-result v$register
|
move-result v$register
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,39 +105,34 @@ val miniplayerPatch = bytecodePatch(
|
|||||||
* Adds an override to specify which modern miniplayer is used.
|
* Adds an override to specify which modern miniplayer is used.
|
||||||
*/
|
*/
|
||||||
fun MutableMethod.insertModernMiniplayerTypeOverride(iPutIndex: Int) {
|
fun MutableMethod.insertModernMiniplayerTypeOverride(iPutIndex: Int) {
|
||||||
val targetInstruction = getInstruction<TwoRegisterInstruction>(iPutIndex)
|
val register = getInstruction<TwoRegisterInstruction>(iPutIndex).registerA
|
||||||
val targetReference = (targetInstruction as ReferenceInstruction).reference
|
|
||||||
|
|
||||||
addInstructions(
|
addInstructionsAtControlFlowLabel(
|
||||||
iPutIndex + 1, """
|
iPutIndex,
|
||||||
invoke-static { v${targetInstruction.registerA} }, $EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
|
"""
|
||||||
move-result v${targetInstruction.registerA}
|
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
|
||||||
# Original instruction
|
move-result v$register
|
||||||
iput v${targetInstruction.registerA}, v${targetInstruction.registerB}, $targetReference
|
""",
|
||||||
"""
|
|
||||||
)
|
)
|
||||||
removeInstruction(iPutIndex)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Pair<String, Fingerprint>.hookInflatedView(
|
fun MutableMethod.hookInflatedView(
|
||||||
literalValue: Long,
|
literalValue: Long,
|
||||||
hookedClassType: String,
|
hookedClassType: String,
|
||||||
extensionMethodName: String,
|
extensionMethodName: String,
|
||||||
) {
|
) {
|
||||||
methodOrThrow(miniplayerModernViewParentFingerprint).apply {
|
val imageViewIndex = indexOfFirstInstructionOrThrow(
|
||||||
val imageViewIndex = indexOfFirstInstructionOrThrow(
|
indexOfFirstLiteralInstructionOrThrow(literalValue)
|
||||||
indexOfFirstLiteralInstructionOrThrow(literalValue)
|
) {
|
||||||
) {
|
opcode == Opcode.CHECK_CAST &&
|
||||||
opcode == Opcode.CHECK_CAST &&
|
getReference<TypeReference>()?.type == hookedClassType
|
||||||
getReference<TypeReference>()?.type == hookedClassType
|
|
||||||
}
|
|
||||||
|
|
||||||
val register = getInstruction<OneRegisterInstruction>(imageViewIndex).registerA
|
|
||||||
addInstruction(
|
|
||||||
imageViewIndex + 1,
|
|
||||||
"invoke-static { v$register }, $extensionMethodName"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(imageViewIndex).registerA
|
||||||
|
addInstruction(
|
||||||
|
imageViewIndex + 1,
|
||||||
|
"invoke-static { v$register }, $extensionMethodName"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modern mini player is only present and functional in 19.15+.
|
// Modern mini player is only present and functional in 19.15+.
|
||||||
@ -184,7 +179,7 @@ val miniplayerPatch = bytecodePatch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPatchingOldVersion) {
|
if (isPatchingOldVersion) {
|
||||||
settingArray += "SETTINGS: MINIPLAYER_TYPE_LEGACY"
|
settingArray += "SETTINGS: MINIPLAYER_TYPE_19_14"
|
||||||
addPreference(settingArray, MINIPLAYER)
|
addPreference(settingArray, MINIPLAYER)
|
||||||
|
|
||||||
// Return here, as patch below is only intended for new versions of the app.
|
// Return here, as patch below is only intended for new versions of the app.
|
||||||
@ -197,14 +192,14 @@ val miniplayerPatch = bytecodePatch(
|
|||||||
|
|
||||||
miniplayerModernConstructorFingerprint.mutableClassOrThrow().methods.forEach {
|
miniplayerModernConstructorFingerprint.mutableClassOrThrow().methods.forEach {
|
||||||
it.apply {
|
it.apply {
|
||||||
if (MethodUtil.isConstructor(it)) {
|
if (AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
||||||
val iPutIndex = indexOfFirstInstructionOrThrow {
|
val iPutIndex = indexOfFirstInstructionOrThrow {
|
||||||
opcode == Opcode.IPUT &&
|
this.opcode == Opcode.IPUT &&
|
||||||
getReference<FieldReference>()?.type == "I"
|
this.getReference<FieldReference>()?.type == "I"
|
||||||
}
|
}
|
||||||
|
|
||||||
insertModernMiniplayerTypeOverride(iPutIndex)
|
insertModernMiniplayerTypeOverride(iPutIndex)
|
||||||
} else if (isMultiConstructorMethod()) {
|
} else {
|
||||||
findReturnIndicesReversed().forEach { index ->
|
findReturnIndicesReversed().forEach { index ->
|
||||||
insertModernMiniplayerOverride(
|
insertModernMiniplayerOverride(
|
||||||
index
|
index
|
||||||
@ -214,27 +209,96 @@ val miniplayerPatch = bytecodePatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_19_25_or_greater) {
|
if (is_19_23_or_greater) {
|
||||||
miniplayerModernEnabledFingerprint.injectLiteralInstructionBooleanCall(
|
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
45622882L,
|
MINIPLAYER_DRAG_DROP_FEATURE_KEY,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z"
|
"$EXTENSION_CLASS_DESCRIPTOR->enableMiniplayerDragAndDrop(Z)Z"
|
||||||
)
|
)
|
||||||
|
settingArray += "SETTINGS: MINIPLAYER_DRAG_AND_DROP"
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
// region Enable double tap action.
|
|
||||||
|
|
||||||
if (is_19_25_or_greater) {
|
if (is_19_25_or_greater) {
|
||||||
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
45628823L,
|
MINIPLAYER_MODERN_FEATURE_LEGACY_KEY,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->enableMiniplayerDoubleTapAction()Z"
|
|
||||||
)
|
|
||||||
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
|
||||||
45630429L,
|
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z"
|
"$EXTENSION_CLASS_DESCRIPTOR->getModernMiniplayerOverride(Z)Z"
|
||||||
)
|
)
|
||||||
settingArray += "SETTINGS: MINIPLAYER_DOUBLE_TAP_ACTION"
|
|
||||||
|
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
|
MINIPLAYER_MODERN_FEATURE_KEY,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->getModernFeatureFlagsActiveOverride(Z)Z"
|
||||||
|
)
|
||||||
|
|
||||||
|
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
|
MINIPLAYER_DOUBLE_TAP_FEATURE_KEY,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->enableMiniplayerDoubleTapAction(Z)Z"
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!is_19_29_or_greater) {
|
||||||
|
settingArray += "SETTINGS: MINIPLAYER_DOUBLE_TAP_ACTION"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_19_26_or_greater) {
|
||||||
|
miniplayerModernConstructorFingerprint.methodOrThrow().apply {
|
||||||
|
val literalIndex = indexOfFirstLiteralInstructionOrThrow(
|
||||||
|
MINIPLAYER_INITIAL_SIZE_FEATURE_KEY,
|
||||||
|
)
|
||||||
|
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.LONG_TO_INT)
|
||||||
|
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
targetIndex + 1,
|
||||||
|
"""
|
||||||
|
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setMiniplayerDefaultSize(I)I
|
||||||
|
move-result v$register
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override a minimum size constant.
|
||||||
|
miniplayerMinimumSizeFingerprint.methodOrThrow().apply {
|
||||||
|
val index = indexOfFirstInstructionOrThrow {
|
||||||
|
opcode == Opcode.CONST_16 &&
|
||||||
|
(this as NarrowLiteralInstruction).narrowLiteral == 192
|
||||||
|
}
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
|
||||||
|
// Smaller sizes can be used, but the miniplayer will always start in size 170 if set any smaller.
|
||||||
|
// The 170 initial limit probably could be patched to allow even smaller initial sizes,
|
||||||
|
// but 170 is already half the horizontal space and smaller does not seem useful.
|
||||||
|
replaceInstruction(index, "const/16 v$register, 170")
|
||||||
|
}
|
||||||
|
|
||||||
|
settingArray += "SETTINGS: MINIPLAYER_WIDTH_DIP"
|
||||||
|
} else {
|
||||||
|
settingArray += "SETTINGS: MINIPLAYER_REWIND_FORWARD"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_19_36_or_greater) {
|
||||||
|
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
|
MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->setRoundedCorners(Z)Z"
|
||||||
|
)
|
||||||
|
|
||||||
|
settingArray += "SETTINGS: MINIPLAYER_ROUNDED_CONERS"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_19_43_or_greater) {
|
||||||
|
miniplayerOnCloseHandlerFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
|
MINIPLAYER_DISABLED_FEATURE_KEY,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->getMiniplayerOnCloseHandler(Z)Z"
|
||||||
|
)
|
||||||
|
|
||||||
|
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
|
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->setHorizontalDrag(Z)Z"
|
||||||
|
)
|
||||||
|
|
||||||
|
settingArray += "SETTINGS: MINIPLAYER_HORIZONTAL_DRAG"
|
||||||
|
settingArray += "SETTINGS: MINIPLAYER_TYPE_19_43"
|
||||||
|
} else {
|
||||||
|
settingArray += "SETTINGS: MINIPLAYER_TYPE_19_16"
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@ -291,7 +355,7 @@ val miniplayerPatch = bytecodePatch(
|
|||||||
"adjustMiniplayerOpacity"
|
"adjustMiniplayerOpacity"
|
||||||
)
|
)
|
||||||
).forEach { (fingerprint, literalValue, methodName) ->
|
).forEach { (fingerprint, literalValue, methodName) ->
|
||||||
fingerprint.hookInflatedView(
|
fingerprint.methodOrThrow(miniplayerModernViewParentFingerprint).hookInflatedView(
|
||||||
literalValue,
|
literalValue,
|
||||||
"Landroid/widget/ImageView;",
|
"Landroid/widget/ImageView;",
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V"
|
"$EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V"
|
||||||
@ -300,23 +364,19 @@ val miniplayerPatch = bytecodePatch(
|
|||||||
|
|
||||||
miniplayerModernAddViewListenerFingerprint.methodOrThrow(
|
miniplayerModernAddViewListenerFingerprint.methodOrThrow(
|
||||||
miniplayerModernViewParentFingerprint
|
miniplayerModernViewParentFingerprint
|
||||||
).apply {
|
).addInstruction(
|
||||||
addInstructionsWithLabels(
|
0,
|
||||||
0,
|
"invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||||
"""
|
"hideMiniplayerSubTexts(Landroid/view/View;)V",
|
||||||
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->hideMiniplayerSubTexts(Landroid/view/View;)Z
|
)
|
||||||
move-result v0
|
|
||||||
if-nez v0, :hidden
|
|
||||||
""",
|
|
||||||
ExternalLabel("hidden", getInstruction(implementation!!.instructions.lastIndex))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Modern 2 has a broken overlay subtitle view that is always present.
|
// Modern 2 has a broken overlay subtitle view that is always present.
|
||||||
// Modern 2 uses the same overlay controls as the regular video player,
|
// Modern 2 uses the same overlay controls as the regular video player,
|
||||||
// and the overlay views are added at runtime.
|
// and the overlay views are added at runtime.
|
||||||
// Add a hook to the overlay class, and pass the added views to extension.
|
// Add a hook to the overlay class, and pass the added views to extension.
|
||||||
|
//
|
||||||
|
// NOTE: Modern 2 uses the same video UI as the regular player except resized to smaller.
|
||||||
|
// This patch code could be used to hide other player overlays that do not use Litho.
|
||||||
youTubePlayerOverlaysLayoutFingerprint.matchOrThrow().let {
|
youTubePlayerOverlaysLayoutFingerprint.matchOrThrow().let {
|
||||||
it.method.apply {
|
it.method.apply {
|
||||||
it.classDef.methods.add(
|
it.classDef.methods.add(
|
||||||
@ -352,18 +412,6 @@ val miniplayerPatch = bytecodePatch(
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Enable drag and drop.
|
|
||||||
|
|
||||||
if (is_19_23_or_greater) {
|
|
||||||
miniplayerModernDragAndDropFingerprint.injectLiteralInstructionBooleanCall(
|
|
||||||
45628752L,
|
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->enableMiniplayerDragAndDrop()Z"
|
|
||||||
)
|
|
||||||
settingArray += "SETTINGS: MINIPLAYER_DRAG_AND_DROP"
|
|
||||||
}
|
|
||||||
|
|
||||||
// endregion
|
|
||||||
|
|
||||||
settingArray += "SETTINGS: MINIPLAYER_TYPE_MODERN"
|
settingArray += "SETTINGS: MINIPLAYER_TYPE_MODERN"
|
||||||
|
|
||||||
// region add settings
|
// region add settings
|
||||||
|
@ -1,17 +1,69 @@
|
|||||||
package app.revanced.patches.youtube.general.spoofappversion
|
package app.revanced.patches.youtube.general.spoofappversion
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.patch.resourcePatch
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.shared.spoof.appversion.baseSpoofAppVersionPatch
|
import app.revanced.patches.shared.spoof.appversion.baseSpoofAppVersionPatch
|
||||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR
|
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||||
|
import app.revanced.patches.youtube.utils.indexOfGetDrawableInstruction
|
||||||
import app.revanced.patches.youtube.utils.patch.PatchList.SPOOF_APP_VERSION
|
import app.revanced.patches.youtube.utils.patch.PatchList.SPOOF_APP_VERSION
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_18_34_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_18_34_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_18_39_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_18_39_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_18_49_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_18_49_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||||
|
import app.revanced.patches.youtube.utils.toolBarButtonFingerprint
|
||||||
import app.revanced.util.appendAppVersion
|
import app.revanced.util.appendAppVersion
|
||||||
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
private val spoofAppVersionBytecodePatch = bytecodePatch(
|
||||||
|
description = "spoofAppVersionBytecodePatch"
|
||||||
|
) {
|
||||||
|
|
||||||
|
dependsOn(versionCheckPatch)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
if (!is_19_23_or_greater) {
|
||||||
|
return@execute
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When spoofing the app version to YouTube 19.20.xx or earlier via Spoof app version on YouTube 19.23.xx+, the Library tab will crash.
|
||||||
|
* As a temporary workaround, do not set an image in the toolbar when the enum name is UNKNOWN.
|
||||||
|
*/
|
||||||
|
toolBarButtonFingerprint.methodOrThrow().apply {
|
||||||
|
val getDrawableIndex = indexOfGetDrawableInstruction(this)
|
||||||
|
val enumOrdinalIndex = indexOfFirstInstructionReversedOrThrow(getDrawableIndex) {
|
||||||
|
opcode == Opcode.INVOKE_INTERFACE &&
|
||||||
|
getReference<MethodReference>()?.returnType == "I"
|
||||||
|
}
|
||||||
|
val insertIndex = enumOrdinalIndex + 2
|
||||||
|
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex - 1).registerA
|
||||||
|
val jumpIndex = indexOfFirstInstructionOrThrow(insertIndex) {
|
||||||
|
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
|
getReference<MethodReference>()?.name == "setImageDrawable"
|
||||||
|
} + 1
|
||||||
|
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
insertIndex, """
|
||||||
|
if-eqz v$insertRegister, :ignore
|
||||||
|
""", ExternalLabel("ignore", getInstruction(jumpIndex))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val spoofAppVersionPatch = resourcePatch(
|
val spoofAppVersionPatch = resourcePatch(
|
||||||
@ -22,6 +74,7 @@ val spoofAppVersionPatch = resourcePatch(
|
|||||||
|
|
||||||
dependsOn(
|
dependsOn(
|
||||||
baseSpoofAppVersionPatch("$GENERAL_CLASS_DESCRIPTOR->getVersionOverride(Ljava/lang/String;)Ljava/lang/String;"),
|
baseSpoofAppVersionPatch("$GENERAL_CLASS_DESCRIPTOR->getVersionOverride(Ljava/lang/String;)Ljava/lang/String;"),
|
||||||
|
spoofAppVersionBytecodePatch,
|
||||||
settingsPatch,
|
settingsPatch,
|
||||||
versionCheckPatch,
|
versionCheckPatch,
|
||||||
)
|
)
|
||||||
|
@ -297,6 +297,7 @@ val toolBarComponentsPatch = bytecodePatch(
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
/*
|
||||||
// region patch for hide voice search button
|
// region patch for hide voice search button
|
||||||
|
|
||||||
if (is_19_28_or_greater) {
|
if (is_19_28_or_greater) {
|
||||||
@ -311,6 +312,7 @@ val toolBarComponentsPatch = bytecodePatch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
*/
|
||||||
|
|
||||||
// region patch for hide voice search button
|
// region patch for hide voice search button
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ import app.revanced.patcher.patch.resourcePatch
|
|||||||
import app.revanced.patcher.patch.stringOption
|
import app.revanced.patcher.patch.stringOption
|
||||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.patch.PatchList.CUSTOM_BRANDING_ICON_FOR_YOUTUBE
|
import app.revanced.patches.youtube.utils.patch.PatchList.CUSTOM_BRANDING_ICON_FOR_YOUTUBE
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusIcon
|
import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusIcon
|
||||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||||
import app.revanced.util.ResourceGroup
|
import app.revanced.util.ResourceGroup
|
||||||
@ -12,9 +14,16 @@ import app.revanced.util.Utils.trimIndentMultiline
|
|||||||
import app.revanced.util.copyFile
|
import app.revanced.util.copyFile
|
||||||
import app.revanced.util.copyResources
|
import app.revanced.util.copyResources
|
||||||
import app.revanced.util.copyXmlNode
|
import app.revanced.util.copyXmlNode
|
||||||
|
import app.revanced.util.getAdaptiveIconResourceFile
|
||||||
import app.revanced.util.getResourceGroup
|
import app.revanced.util.getResourceGroup
|
||||||
import app.revanced.util.underBarOrThrow
|
import app.revanced.util.underBarOrThrow
|
||||||
|
import java.nio.file.Files
|
||||||
|
import java.nio.file.StandardCopyOption
|
||||||
|
|
||||||
|
private const val ADAPTIVE_ICON_BACKGROUND_FILE_NAME =
|
||||||
|
"adaptiveproduct_youtube_background_color_108"
|
||||||
|
private const val ADAPTIVE_ICON_FOREGROUND_FILE_NAME =
|
||||||
|
"adaptiveproduct_youtube_foreground_color_108"
|
||||||
private const val DEFAULT_ICON = "revancify_blue"
|
private const val DEFAULT_ICON = "revancify_blue"
|
||||||
|
|
||||||
private val availableIcon = mapOf(
|
private val availableIcon = mapOf(
|
||||||
@ -39,8 +48,8 @@ private val drawableDirectories = sizeArray.map { "drawable-$it" }
|
|||||||
private val mipmapDirectories = sizeArray.map { "mipmap-$it" }
|
private val mipmapDirectories = sizeArray.map { "mipmap-$it" }
|
||||||
|
|
||||||
private val launcherIconResourceFileNames = arrayOf(
|
private val launcherIconResourceFileNames = arrayOf(
|
||||||
"adaptiveproduct_youtube_background_color_108",
|
ADAPTIVE_ICON_BACKGROUND_FILE_NAME,
|
||||||
"adaptiveproduct_youtube_foreground_color_108",
|
ADAPTIVE_ICON_FOREGROUND_FILE_NAME,
|
||||||
"ic_launcher",
|
"ic_launcher",
|
||||||
"ic_launcher_round"
|
"ic_launcher_round"
|
||||||
).map { "$it.png" }.toTypedArray()
|
).map { "$it.png" }.toTypedArray()
|
||||||
@ -83,7 +92,10 @@ val customBrandingIconPatch = resourcePatch(
|
|||||||
) {
|
) {
|
||||||
compatibleWith(COMPATIBLE_PACKAGE)
|
compatibleWith(COMPATIBLE_PACKAGE)
|
||||||
|
|
||||||
dependsOn(settingsPatch)
|
dependsOn(
|
||||||
|
settingsPatch,
|
||||||
|
versionCheckPatch,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
val appIconOption = stringOption(
|
val appIconOption = stringOption(
|
||||||
@ -181,5 +193,32 @@ val customBrandingIconPatch = resourcePatch(
|
|||||||
|
|
||||||
updatePatchStatusIcon(appIcon)
|
updatePatchStatusIcon(appIcon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!is_19_34_or_greater) {
|
||||||
|
return@execute
|
||||||
|
}
|
||||||
|
if (appIcon == "youtube") {
|
||||||
|
return@execute
|
||||||
|
}
|
||||||
|
|
||||||
|
mapOf(
|
||||||
|
ADAPTIVE_ICON_BACKGROUND_FILE_NAME to getAdaptiveIconResourceFile("res/mipmap-anydpi/ic_launcher.xml", "background"),
|
||||||
|
ADAPTIVE_ICON_FOREGROUND_FILE_NAME to getAdaptiveIconResourceFile("res/mipmap-anydpi/ic_launcher.xml", "foreground")
|
||||||
|
).forEach { (oldIconResourceFile, newIconResourceFile) ->
|
||||||
|
if (oldIconResourceFile != newIconResourceFile) {
|
||||||
|
mipmapDirectories.forEach {
|
||||||
|
val mipmapDirectory = get("res").resolve(it)
|
||||||
|
Files.copy(
|
||||||
|
mipmapDirectory
|
||||||
|
.resolve("$oldIconResourceFile.png")
|
||||||
|
.toPath(),
|
||||||
|
mipmapDirectory
|
||||||
|
.resolve("$newIconResourceFile.png")
|
||||||
|
.toPath(),
|
||||||
|
StandardCopyOption.REPLACE_EXISTING
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -386,6 +386,8 @@ val playerComponentsPatch = bytecodePatch(
|
|||||||
findMethodOrThrow(syntheticReference) {
|
findMethodOrThrow(syntheticReference) {
|
||||||
name == "onClick"
|
name == "onClick"
|
||||||
}.hookInitVideoPanel(0)
|
}.hookInitVideoPanel(0)
|
||||||
|
} else {
|
||||||
|
println("WARNING: target Opcode not found in ${fingerprint.first}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import app.revanced.patches.youtube.utils.resourceid.fadeDurationFast
|
|||||||
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarColorizedBarPlayedColorDark
|
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarColorizedBarPlayedColorDark
|
||||||
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarPlayedNotHighlightedColor
|
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarPlayedNotHighlightedColor
|
||||||
import app.revanced.patches.youtube.utils.resourceid.insetOverlayViewLayout
|
import app.revanced.patches.youtube.utils.resourceid.insetOverlayViewLayout
|
||||||
|
import app.revanced.patches.youtube.utils.resourceid.menuItemView
|
||||||
import app.revanced.patches.youtube.utils.resourceid.scrimOverlay
|
import app.revanced.patches.youtube.utils.resourceid.scrimOverlay
|
||||||
import app.revanced.patches.youtube.utils.resourceid.seekUndoEduOverlayStub
|
import app.revanced.patches.youtube.utils.resourceid.seekUndoEduOverlayStub
|
||||||
import app.revanced.patches.youtube.utils.resourceid.totalTime
|
import app.revanced.patches.youtube.utils.resourceid.totalTime
|
||||||
@ -12,9 +13,13 @@ import app.revanced.patches.youtube.utils.resourceid.varispeedUnavailableTitle
|
|||||||
import app.revanced.patches.youtube.utils.resourceid.videoQualityBottomSheet
|
import app.revanced.patches.youtube.utils.resourceid.videoQualityBottomSheet
|
||||||
import app.revanced.patches.youtube.utils.sponsorblock.sponsorBlockBytecodePatch
|
import app.revanced.patches.youtube.utils.sponsorblock.sponsorBlockBytecodePatch
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
import app.revanced.util.or
|
import app.revanced.util.or
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
internal val engagementPanelBuilderFingerprint = legacyFingerprint(
|
internal val engagementPanelBuilderFingerprint = legacyFingerprint(
|
||||||
name = "engagementPanelBuilderFingerprint",
|
name = "engagementPanelBuilderFingerprint",
|
||||||
@ -164,6 +169,23 @@ internal val seekbarOnDrawFingerprint = legacyFingerprint(
|
|||||||
customFingerprint = { method, _ -> method.name == "onDraw" }
|
customFingerprint = { method, _ -> method.name == "onDraw" }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal fun indexOfGetDrawableInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
|
getReference<MethodReference>()?.toString() == "Landroid/content/res/Resources;->getDrawable(I)Landroid/graphics/drawable/Drawable;"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val toolBarButtonFingerprint = legacyFingerprint(
|
||||||
|
name = "toolBarButtonFingerprint",
|
||||||
|
returnType = "V",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("Landroid/view/MenuItem;"),
|
||||||
|
literals = listOf(menuItemView),
|
||||||
|
customFingerprint = { method, _ ->
|
||||||
|
indexOfGetDrawableInstruction(method) >= 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
internal val totalTimeFingerprint = legacyFingerprint(
|
internal val totalTimeFingerprint = legacyFingerprint(
|
||||||
name = "totalTimeFingerprint",
|
name = "totalTimeFingerprint",
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
|
@ -14,7 +14,8 @@ internal object Constants {
|
|||||||
"18.38.44", // This is the last version with no delay in applying video quality on the server side.
|
"18.38.44", // This is the last version with no delay in applying video quality on the server side.
|
||||||
"18.48.39", // This is the last version that do not use Rolling Number.
|
"18.48.39", // This is the last version that do not use Rolling Number.
|
||||||
"19.05.36", // This is the last version with the least YouTube experimental flag.
|
"19.05.36", // This is the last version with the least YouTube experimental flag.
|
||||||
"19.16.39", // This is the latest version supported by the RVX patch.
|
"19.16.39", // This is the last version where the 'Restore old seekbar thumbnails' setting works.
|
||||||
|
"19.34.42", // This is the latest version supported by the RVX patch.
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -134,8 +134,8 @@ private val playerControlsBytecodePatch = bytecodePatch(
|
|||||||
|
|
||||||
changeVisibilityMethod =
|
changeVisibilityMethod =
|
||||||
findMethodOrThrow(EXTENSION_PLAYER_CONTROLS_CLASS_DESCRIPTOR) {
|
findMethodOrThrow(EXTENSION_PLAYER_CONTROLS_CLASS_DESCRIPTOR) {
|
||||||
name == "changeVisibility"
|
name == "changeVisibility" &&
|
||||||
&& parameters == listOf("Z", "Z")
|
parameters == listOf("Z", "Z")
|
||||||
}
|
}
|
||||||
|
|
||||||
changeVisibilityNegatedImmediatelyMethod =
|
changeVisibilityNegatedImmediatelyMethod =
|
||||||
|
@ -10,12 +10,6 @@ import com.android.tools.smali.dexlib2.Opcode
|
|||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
internal fun indexOfLayoutDirectionInstruction(method: Method) =
|
|
||||||
method.indexOfFirstInstruction {
|
|
||||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
|
||||||
getReference<MethodReference>().toString() == "Landroid/view/View;->setLayoutDirection(I)V"
|
|
||||||
}
|
|
||||||
|
|
||||||
internal val browseIdClassFingerprint = legacyFingerprint(
|
internal val browseIdClassFingerprint = legacyFingerprint(
|
||||||
name = "browseIdClassFingerprint",
|
name = "browseIdClassFingerprint",
|
||||||
returnType = "Ljava/lang/Object;",
|
returnType = "Ljava/lang/Object;",
|
||||||
@ -45,18 +39,26 @@ internal val reelWatchPagerFingerprint = legacyFingerprint(
|
|||||||
literals = listOf(reelWatchPlayer),
|
literals = listOf(reelWatchPlayer),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal fun indexOfStringIsEmptyInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
|
getReference<MethodReference>().toString() == "Ljava/lang/String;->isEmpty()Z"
|
||||||
|
}
|
||||||
|
|
||||||
internal val searchQueryClassFingerprint = legacyFingerprint(
|
internal val searchQueryClassFingerprint = legacyFingerprint(
|
||||||
name = "searchQueryClassFingerprint",
|
name = "searchQueryClassFingerprint",
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("L", "Ljava/util/Map;"),
|
parameters = listOf("L", "Ljava/util/Map;"),
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.CHECK_CAST,
|
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT,
|
Opcode.MOVE_RESULT,
|
||||||
),
|
),
|
||||||
strings = listOf("force_enable_sticky_browsy_bars"),
|
strings = listOf("force_enable_sticky_browsy_bars"),
|
||||||
|
customFingerprint = { method, _ ->
|
||||||
|
indexOfStringIsEmptyInstruction(method) >= 0
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val videoStateFingerprint = legacyFingerprint(
|
internal val videoStateFingerprint = legacyFingerprint(
|
||||||
|
@ -135,32 +135,30 @@ val playerTypeHookPatch = bytecodePatch(
|
|||||||
|
|
||||||
// region patch for hook search bar
|
// region patch for hook search bar
|
||||||
|
|
||||||
searchQueryClassFingerprint.matchOrThrow().let {
|
searchQueryClassFingerprint.methodOrThrow().apply {
|
||||||
it.method.apply {
|
val searchQueryIndex = indexOfStringIsEmptyInstruction(this) - 1
|
||||||
val searchQueryIndex = it.patternMatch!!.startIndex + 1
|
val searchQueryFieldReference = getInstruction<ReferenceInstruction>(searchQueryIndex).reference
|
||||||
val searchQueryFieldReference = getInstruction<ReferenceInstruction>(searchQueryIndex).reference
|
val searchQueryClass = (searchQueryFieldReference as FieldReference).definingClass
|
||||||
val searchQueryClass = (searchQueryFieldReference as FieldReference).definingClass
|
|
||||||
|
|
||||||
findMethodOrThrow(searchQueryClass).apply {
|
findMethodOrThrow(searchQueryClass).apply {
|
||||||
val smaliInstructions =
|
val smaliInstructions =
|
||||||
|
"""
|
||||||
|
if-eqz v0, :ignore
|
||||||
|
iget-object v0, v0, $searchQueryFieldReference
|
||||||
|
if-eqz v0, :ignore
|
||||||
|
return-object v0
|
||||||
|
:ignore
|
||||||
|
const-string v0, ""
|
||||||
|
return-object v0
|
||||||
"""
|
"""
|
||||||
if-eqz v0, :ignore
|
|
||||||
iget-object v0, v0, $searchQueryFieldReference
|
|
||||||
if-eqz v0, :ignore
|
|
||||||
return-object v0
|
|
||||||
:ignore
|
|
||||||
const-string v0, ""
|
|
||||||
return-object v0
|
|
||||||
"""
|
|
||||||
|
|
||||||
addStaticFieldToExtension(
|
addStaticFieldToExtension(
|
||||||
EXTENSION_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR,
|
EXTENSION_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR,
|
||||||
"getSearchQuery",
|
"getSearchQuery",
|
||||||
"searchQueryClass",
|
"searchQueryClass",
|
||||||
definingClass,
|
definingClass,
|
||||||
smaliInstructions
|
smaliInstructions
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,10 +23,22 @@ var is_19_23_or_greater = false
|
|||||||
private set
|
private set
|
||||||
var is_19_25_or_greater = false
|
var is_19_25_or_greater = false
|
||||||
private set
|
private set
|
||||||
|
var is_19_26_or_greater = false
|
||||||
|
private set
|
||||||
var is_19_28_or_greater = false
|
var is_19_28_or_greater = false
|
||||||
private set
|
private set
|
||||||
|
var is_19_29_or_greater = false
|
||||||
|
private set
|
||||||
var is_19_32_or_greater = false
|
var is_19_32_or_greater = false
|
||||||
private set
|
private set
|
||||||
|
var is_19_34_or_greater = false
|
||||||
|
private set
|
||||||
|
var is_19_36_or_greater = false
|
||||||
|
private set
|
||||||
|
var is_19_41_or_greater = false
|
||||||
|
private set
|
||||||
|
var is_19_43_or_greater = false
|
||||||
|
private set
|
||||||
var is_19_44_or_greater = false
|
var is_19_44_or_greater = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@ -53,8 +65,14 @@ val versionCheckPatch = resourcePatch(
|
|||||||
is_19_15_or_greater = 241602000 <= playStoreServicesVersion
|
is_19_15_or_greater = 241602000 <= playStoreServicesVersion
|
||||||
is_19_23_or_greater = 242402000 <= playStoreServicesVersion
|
is_19_23_or_greater = 242402000 <= playStoreServicesVersion
|
||||||
is_19_25_or_greater = 242599000 <= playStoreServicesVersion
|
is_19_25_or_greater = 242599000 <= playStoreServicesVersion
|
||||||
|
is_19_26_or_greater = 242705000 <= playStoreServicesVersion
|
||||||
is_19_28_or_greater = 242905000 <= playStoreServicesVersion
|
is_19_28_or_greater = 242905000 <= playStoreServicesVersion
|
||||||
|
is_19_29_or_greater = 243005000 <= playStoreServicesVersion
|
||||||
is_19_32_or_greater = 243305000 <= playStoreServicesVersion
|
is_19_32_or_greater = 243305000 <= playStoreServicesVersion
|
||||||
|
is_19_34_or_greater = 243499000 <= playStoreServicesVersion
|
||||||
|
is_19_36_or_greater = 243705000 <= playStoreServicesVersion
|
||||||
|
is_19_41_or_greater = 244305000 <= playStoreServicesVersion
|
||||||
|
is_19_43_or_greater = 244405000 <= playStoreServicesVersion
|
||||||
is_19_44_or_greater = 244505000 <= playStoreServicesVersion
|
is_19_44_or_greater = 244505000 <= playStoreServicesVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,8 @@ var menuItemView = -1L
|
|||||||
private set
|
private set
|
||||||
var metaPanel = -1L
|
var metaPanel = -1L
|
||||||
private set
|
private set
|
||||||
|
var miniplayerMaxSize = -1L
|
||||||
|
private set
|
||||||
var modernMiniPlayerClose = -1L
|
var modernMiniPlayerClose = -1L
|
||||||
private set
|
private set
|
||||||
var modernMiniPlayerExpand = -1L
|
var modernMiniPlayerExpand = -1L
|
||||||
@ -444,6 +446,10 @@ internal val sharedResourceIdPatch = resourcePatch(
|
|||||||
ID,
|
ID,
|
||||||
"metapanel"
|
"metapanel"
|
||||||
]
|
]
|
||||||
|
miniplayerMaxSize = resourceMappings[
|
||||||
|
DIMEN,
|
||||||
|
"miniplayer_max_size",
|
||||||
|
]
|
||||||
modernMiniPlayerClose = resourceMappings[
|
modernMiniPlayerClose = resourceMappings[
|
||||||
ID,
|
ID,
|
||||||
"modern_miniplayer_close"
|
"modern_miniplayer_close"
|
||||||
|
@ -1,26 +1,10 @@
|
|||||||
package app.revanced.patches.youtube.utils.toolbar
|
package app.revanced.patches.youtube.utils.toolbar
|
||||||
|
|
||||||
import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH
|
import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH
|
||||||
import app.revanced.patches.youtube.utils.resourceid.menuItemView
|
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
import app.revanced.util.or
|
import app.revanced.util.or
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
|
||||||
|
|
||||||
internal val toolBarButtonFingerprint = legacyFingerprint(
|
|
||||||
name = "toolBarButtonFingerprint",
|
|
||||||
returnType = "V",
|
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
parameters = listOf("Landroid/view/MenuItem;"),
|
|
||||||
opcodes = listOf(
|
|
||||||
Opcode.INVOKE_INTERFACE,
|
|
||||||
Opcode.MOVE_RESULT,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.INVOKE_VIRTUAL
|
|
||||||
),
|
|
||||||
literals = listOf(menuItemView),
|
|
||||||
)
|
|
||||||
internal val toolBarPatchFingerprint = legacyFingerprint(
|
internal val toolBarPatchFingerprint = legacyFingerprint(
|
||||||
name = "toolBarPatchFingerprint",
|
name = "toolBarPatchFingerprint",
|
||||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.STATIC,
|
accessFlags = AccessFlags.PRIVATE or AccessFlags.STATIC,
|
||||||
|
@ -6,12 +6,18 @@ import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
|||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH
|
import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH
|
||||||
|
import app.revanced.patches.youtube.utils.indexOfGetDrawableInstruction
|
||||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||||
import app.revanced.util.fingerprint.matchOrThrow
|
import app.revanced.patches.youtube.utils.toolBarButtonFingerprint
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
"$UTILS_PATH/ToolBarPatch;"
|
"$UTILS_PATH/ToolBarPatch;"
|
||||||
@ -24,30 +30,35 @@ val toolBarHookPatch = bytecodePatch(
|
|||||||
dependsOn(sharedResourceIdPatch)
|
dependsOn(sharedResourceIdPatch)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
toolBarButtonFingerprint.matchOrThrow().let {
|
toolBarButtonFingerprint.methodOrThrow().apply {
|
||||||
it.method.apply {
|
val getDrawableIndex = indexOfGetDrawableInstruction(this)
|
||||||
val replaceIndex = it.patternMatch!!.startIndex
|
val enumOrdinalIndex = indexOfFirstInstructionReversedOrThrow(getDrawableIndex) {
|
||||||
val freeIndex = it.patternMatch!!.endIndex - 1
|
opcode == Opcode.INVOKE_INTERFACE &&
|
||||||
|
getReference<MethodReference>()?.returnType == "I"
|
||||||
val replaceReference = getInstruction<ReferenceInstruction>(replaceIndex).reference
|
|
||||||
val replaceRegister =
|
|
||||||
getInstruction<FiveRegisterInstruction>(replaceIndex).registerC
|
|
||||||
val enumRegister = getInstruction<FiveRegisterInstruction>(replaceIndex).registerD
|
|
||||||
val freeRegister = getInstruction<TwoRegisterInstruction>(freeIndex).registerA
|
|
||||||
|
|
||||||
val imageViewIndex = replaceIndex + 2
|
|
||||||
val imageViewReference =
|
|
||||||
getInstruction<ReferenceInstruction>(imageViewIndex).reference
|
|
||||||
|
|
||||||
addInstructions(
|
|
||||||
replaceIndex + 1, """
|
|
||||||
iget-object v$freeRegister, p0, $imageViewReference
|
|
||||||
invoke-static {v$enumRegister, v$freeRegister}, $EXTENSION_CLASS_DESCRIPTOR->hookToolBar(Ljava/lang/Enum;Landroid/widget/ImageView;)V
|
|
||||||
invoke-interface {v$replaceRegister, v$enumRegister}, $replaceReference
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
removeInstruction(replaceIndex)
|
|
||||||
}
|
}
|
||||||
|
val freeIndex = getDrawableIndex - 1
|
||||||
|
|
||||||
|
val replaceReference = getInstruction<ReferenceInstruction>(enumOrdinalIndex).reference
|
||||||
|
val replaceRegister =
|
||||||
|
getInstruction<FiveRegisterInstruction>(enumOrdinalIndex).registerC
|
||||||
|
val enumRegister = getInstruction<FiveRegisterInstruction>(enumOrdinalIndex).registerD
|
||||||
|
val freeRegister = getInstruction<TwoRegisterInstruction>(freeIndex).registerA
|
||||||
|
|
||||||
|
val imageViewIndex = indexOfFirstInstructionReversedOrThrow(enumOrdinalIndex) {
|
||||||
|
opcode == Opcode.IGET_OBJECT &&
|
||||||
|
getReference<FieldReference>()?.type == "Landroid/widget/ImageView;"
|
||||||
|
}
|
||||||
|
val imageViewReference =
|
||||||
|
getInstruction<ReferenceInstruction>(imageViewIndex).reference
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
enumOrdinalIndex + 1, """
|
||||||
|
iget-object v$freeRegister, p0, $imageViewReference
|
||||||
|
invoke-static {v$enumRegister, v$freeRegister}, $EXTENSION_CLASS_DESCRIPTOR->hookToolBar(Ljava/lang/Enum;Landroid/widget/ImageView;)V
|
||||||
|
invoke-interface {v$replaceRegister, v$enumRegister}, $replaceReference
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
removeInstruction(enumOrdinalIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
toolbarMethod = toolBarPatchFingerprint.methodOrThrow()
|
toolbarMethod = toolBarPatchFingerprint.methodOrThrow()
|
||||||
|
@ -5,7 +5,6 @@ import app.revanced.patcher.patch.Patch
|
|||||||
import app.revanced.patcher.patch.PatchException
|
import app.revanced.patcher.patch.PatchException
|
||||||
import app.revanced.patcher.patch.ResourcePatchContext
|
import app.revanced.patcher.patch.ResourcePatchContext
|
||||||
import app.revanced.patcher.util.Document
|
import app.revanced.patcher.util.Document
|
||||||
import org.w3c.dom.Attr
|
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
import org.w3c.dom.Node
|
import org.w3c.dom.Node
|
||||||
import org.w3c.dom.NodeList
|
import org.w3c.dom.NodeList
|
||||||
@ -44,26 +43,6 @@ fun Node.cloneNodes(parent: Node) {
|
|||||||
parent.removeChild(this)
|
parent.removeChild(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a sequence for all child nodes.
|
|
||||||
*/
|
|
||||||
fun NodeList.asSequence() = (0 until this.length).asSequence().map { this.item(it) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a sequence for all child nodes.
|
|
||||||
*/
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
fun Node.childElementsSequence() =
|
|
||||||
this.childNodes.asSequence().filter { it.nodeType == Node.ELEMENT_NODE } as Sequence<Element>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the given [action] on each child element.
|
|
||||||
*/
|
|
||||||
inline fun Node.forEachChildElement(action: (Element) -> Unit) =
|
|
||||||
childElementsSequence().forEach {
|
|
||||||
action(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively traverse the DOM tree starting from the given root node.
|
* Recursively traverse the DOM tree starting from the given root node.
|
||||||
*
|
*
|
||||||
@ -74,20 +53,29 @@ fun Node.doRecursively(action: (Node) -> Unit) {
|
|||||||
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String.startsWithAny(vararg prefixes: String): Boolean {
|
|
||||||
for (prefix in prefixes)
|
|
||||||
if (this.startsWith(prefix))
|
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun List<String>.getResourceGroup(fileNames: Array<String>) = map { directory ->
|
fun List<String>.getResourceGroup(fileNames: Array<String>) = map { directory ->
|
||||||
ResourceGroup(
|
ResourceGroup(
|
||||||
directory, *fileNames
|
directory, *fileNames
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ResourcePatchContext.getAdaptiveIconResourceFile(path: String, tag: String): String {
|
||||||
|
document(path).use { document ->
|
||||||
|
val adaptiveIcon = document
|
||||||
|
.getElementsByTagName("adaptive-icon")
|
||||||
|
.item(0) as Element
|
||||||
|
|
||||||
|
val childNodes = adaptiveIcon.childNodes
|
||||||
|
for (i in 0 until childNodes.length) {
|
||||||
|
val node = childNodes.item(i)
|
||||||
|
if (node is Element && node.tagName == tag && node.hasAttribute("android:drawable")) {
|
||||||
|
return node.getAttribute("android:drawable").split("/")[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw PatchException("Element not found: $tag")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun ResourcePatchContext.appendAppVersion(appVersion: String) {
|
fun ResourcePatchContext.appendAppVersion(appVersion: String) {
|
||||||
addEntryValues(
|
addEntryValues(
|
||||||
"revanced_spoof_app_version_target_entries",
|
"revanced_spoof_app_version_target_entries",
|
||||||
@ -227,14 +215,6 @@ fun ResourcePatchContext.removeStringsElements(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Node.insertFirst(node: Node) {
|
|
||||||
if (hasChildNodes()) {
|
|
||||||
insertBefore(node, firstChild)
|
|
||||||
} else {
|
|
||||||
appendChild(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Node.insertNode(tagName: String, targetNode: Node, block: Element.() -> Unit) {
|
fun Node.insertNode(tagName: String, targetNode: Node, block: Element.() -> Unit) {
|
||||||
val child = ownerDocument.createElement(tagName)
|
val child = ownerDocument.createElement(tagName)
|
||||||
child.block()
|
child.block()
|
||||||
@ -294,21 +274,6 @@ internal fun inputStreamFromBundledResource(
|
|||||||
*/
|
*/
|
||||||
class ResourceGroup(val resourceDirectoryName: String, vararg val resources: String)
|
class ResourceGroup(val resourceDirectoryName: String, vararg val resources: String)
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate through the children of a node by its tag.
|
|
||||||
* @param resource The xml resource.
|
|
||||||
* @param targetTag The target xml node.
|
|
||||||
* @param callback The callback to call when iterating over the nodes.
|
|
||||||
*/
|
|
||||||
fun ResourcePatchContext.iterateXmlNodeChildren(
|
|
||||||
resource: String,
|
|
||||||
targetTag: String,
|
|
||||||
callback: (node: Node) -> Unit,
|
|
||||||
) = document(classLoader.getResourceAsStream(resource)!!).use { document ->
|
|
||||||
val stringsNode = document.getElementsByTagName(targetTag).item(0).childNodes
|
|
||||||
for (i in 1 until stringsNode.length - 1) callback(stringsNode.item(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy resources from the current class loader to the resource directory.
|
* Copy resources from the current class loader to the resource directory.
|
||||||
* @param resourceDirectory The directory of the resource.
|
* @param resourceDirectory The directory of the resource.
|
||||||
@ -383,12 +348,3 @@ internal fun NodeList.findElementByAttributeValue(attributeName: String, value:
|
|||||||
internal fun NodeList.findElementByAttributeValueOrThrow(attributeName: String, value: String) =
|
internal fun NodeList.findElementByAttributeValueOrThrow(attributeName: String, value: String) =
|
||||||
findElementByAttributeValue(attributeName, value)
|
findElementByAttributeValue(attributeName, value)
|
||||||
?: throw PatchException("Could not find: $attributeName $value")
|
?: throw PatchException("Could not find: $attributeName $value")
|
||||||
|
|
||||||
internal fun Element.copyAttributesFrom(oldContainer: Element) {
|
|
||||||
// Copy attributes from the old element to the new element
|
|
||||||
val attributes = oldContainer.attributes
|
|
||||||
for (i in 0 until attributes.length) {
|
|
||||||
val attr = attributes.item(i) as Attr
|
|
||||||
setAttribute(attr.name, attr.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -163,7 +163,8 @@
|
|||||||
<item>MEMBERSHIPS_SHORTS_ONLY</item>
|
<item>MEMBERSHIPS_SHORTS_ONLY</item>
|
||||||
<item>MEMBERSHIPS_LIVESTREAMS_ONLY</item>
|
<item>MEMBERSHIPS_LIVESTREAMS_ONLY</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_miniplayer_type_19_15_entries">
|
<string-array name="revanced_miniplayer_type_19_43_entries">
|
||||||
|
<item>@string/revanced_miniplayer_type_entry_0</item>
|
||||||
<item>@string/revanced_miniplayer_type_entry_1</item>
|
<item>@string/revanced_miniplayer_type_entry_1</item>
|
||||||
<item>@string/revanced_miniplayer_type_entry_2</item>
|
<item>@string/revanced_miniplayer_type_entry_2</item>
|
||||||
<item>@string/revanced_miniplayer_type_entry_3</item>
|
<item>@string/revanced_miniplayer_type_entry_3</item>
|
||||||
@ -171,22 +172,39 @@
|
|||||||
<item>@string/revanced_miniplayer_type_entry_5</item>
|
<item>@string/revanced_miniplayer_type_entry_5</item>
|
||||||
<item>@string/revanced_miniplayer_type_entry_6</item>
|
<item>@string/revanced_miniplayer_type_entry_6</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_miniplayer_type_19_15_entry_values">
|
<string-array name="revanced_miniplayer_type_19_43_entry_values">
|
||||||
|
<item>DISABLED</item>
|
||||||
<item>ORIGINAL</item>
|
<item>ORIGINAL</item>
|
||||||
<item>PHONE</item>
|
<item>MINIMAL</item>
|
||||||
<item>TABLET</item>
|
<item>TABLET</item>
|
||||||
<item>MODERN_1</item>
|
<item>MODERN_1</item>
|
||||||
<item>MODERN_2</item>
|
<item>MODERN_2</item>
|
||||||
<item>MODERN_3</item>
|
<item>MODERN_3</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_miniplayer_type_legacy_entries">
|
<string-array name="revanced_miniplayer_type_19_16_entries">
|
||||||
|
<item>@string/revanced_miniplayer_type_entry_1</item>
|
||||||
|
<item>@string/revanced_miniplayer_type_entry_2</item>
|
||||||
|
<item>@string/revanced_miniplayer_type_entry_3</item>
|
||||||
|
<item>@string/revanced_miniplayer_type_entry_4</item>
|
||||||
|
<item>@string/revanced_miniplayer_type_entry_5</item>
|
||||||
|
<item>@string/revanced_miniplayer_type_entry_6</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="revanced_miniplayer_type_19_16_entry_values">
|
||||||
|
<item>ORIGINAL</item>
|
||||||
|
<item>MINIMAL</item>
|
||||||
|
<item>TABLET</item>
|
||||||
|
<item>MODERN_1</item>
|
||||||
|
<item>MODERN_2</item>
|
||||||
|
<item>MODERN_3</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="revanced_miniplayer_type_19_14_entries">
|
||||||
<item>@string/revanced_miniplayer_type_entry_1</item>
|
<item>@string/revanced_miniplayer_type_entry_1</item>
|
||||||
<item>@string/revanced_miniplayer_type_entry_2</item>
|
<item>@string/revanced_miniplayer_type_entry_2</item>
|
||||||
<item>@string/revanced_miniplayer_type_entry_3</item>
|
<item>@string/revanced_miniplayer_type_entry_3</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_miniplayer_type_legacy_entry_values">
|
<string-array name="revanced_miniplayer_type_19_14_entry_values">
|
||||||
<item>ORIGINAL</item>
|
<item>ORIGINAL</item>
|
||||||
<item>PHONE</item>
|
<item>MINIMAL</item>
|
||||||
<item>TABLET</item>
|
<item>TABLET</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_return_youtube_username_display_format_entries">
|
<string-array name="revanced_return_youtube_username_display_format_entries">
|
||||||
|
@ -449,30 +449,49 @@ Some components may not be hidden."</string>
|
|||||||
<string name="revanced_preference_screen_miniplayer_summary">Change the style of the in app minimized player.</string>
|
<string name="revanced_preference_screen_miniplayer_summary">Change the style of the in app minimized player.</string>
|
||||||
|
|
||||||
<string name="revanced_miniplayer_type_title">Miniplayer type</string>
|
<string name="revanced_miniplayer_type_title">Miniplayer type</string>
|
||||||
|
<string name="revanced_miniplayer_type_entry_0">Disabled</string>
|
||||||
<string name="revanced_miniplayer_type_entry_1">Original</string>
|
<string name="revanced_miniplayer_type_entry_1">Original</string>
|
||||||
<string name="revanced_miniplayer_type_entry_2">Phone</string>
|
<string name="revanced_miniplayer_type_entry_2">Minimal</string>
|
||||||
<string name="revanced_miniplayer_type_entry_3">Tablet</string>
|
<string name="revanced_miniplayer_type_entry_3">Tablet</string>
|
||||||
<string name="revanced_miniplayer_type_entry_4">Modern 1</string>
|
<string name="revanced_miniplayer_type_entry_4">Modern 1</string>
|
||||||
<string name="revanced_miniplayer_type_entry_5">Modern 2</string>
|
<string name="revanced_miniplayer_type_entry_5">Modern 2</string>
|
||||||
<string name="revanced_miniplayer_type_entry_6">Modern 3</string>
|
<string name="revanced_miniplayer_type_entry_6">Modern 3</string>
|
||||||
<string name="revanced_miniplayer_enable_double_tap_action_title">Enable double-tap action</string>
|
<string name="revanced_miniplayer_rounded_corners_title">Enable rounded corners</string>
|
||||||
<string name="revanced_miniplayer_enable_double_tap_action_summary_on">"Double-tap action is enabled.
|
<string name="revanced_miniplayer_rounded_corners_summary_on">Corners are rounded.</string>
|
||||||
|
<string name="revanced_miniplayer_rounded_corners_summary_off">Corners are square.</string>
|
||||||
|
<string name="revanced_miniplayer_double_tap_action_title">Enable double-tap and pinch to resize</string>
|
||||||
|
<string name="revanced_miniplayer_double_tap_action_summary_on">"Double-tap action and pinch to resize is enabled.
|
||||||
|
|
||||||
• Double-tap to change the minimized video to a larger size.
|
• Double tap to increase miniplayer size.
|
||||||
• Double-tap once more to change to the original size."</string>
|
• Double tap again to restore original size."</string>
|
||||||
<string name="revanced_miniplayer_enable_double_tap_action_summary_off">Double-tap action is disabled.</string>
|
<string name="revanced_miniplayer_double_tap_action_summary_off">Double-tap action and pinch to resize is disabled.</string>
|
||||||
<string name="revanced_miniplayer_enable_drag_and_drop_title">Enable drag and drop</string>
|
<string name="revanced_miniplayer_drag_and_drop_title">Enable drag and drop</string>
|
||||||
<string name="revanced_miniplayer_enable_drag_and_drop_summary_on">Drag and drop is enabled.</string>
|
<string name="revanced_miniplayer_drag_and_drop_summary_on">"Drag and drop is enabled.
|
||||||
<string name="revanced_miniplayer_enable_drag_and_drop_summary_off">Drag and drop is disabled.</string>
|
|
||||||
<string name="revanced_miniplayer_hide_expand_close_title">Hide expand and close buttons</string>
|
Miniplayer can be dragged to any corner of the screen."</string>
|
||||||
<string name="revanced_miniplayer_hide_expand_close_summary_on">Buttons are hidden.\n(swipe miniplayer to expand or close)</string>
|
<string name="revanced_miniplayer_drag_and_drop_summary_off">Drag and drop is disabled.</string>
|
||||||
<string name="revanced_miniplayer_hide_expand_close_summary_off">Expand and close buttons are shown.</string>
|
<string name="revanced_miniplayer_horizontal_drag_title">Enable horizontal drag gesture.</string>
|
||||||
|
<string name="revanced_miniplayer_horizontal_drag_summary_on">"Horizontal drag gesture enabled.
|
||||||
|
|
||||||
|
Miniplayer can be dragged off screen to the left or right."</string>
|
||||||
|
<string name="revanced_miniplayer_horizontal_drag_summary_off">Horizontal drag gesture disabled.</string>
|
||||||
|
<string name="revanced_miniplayer_hide_expand_close_title">Hide close button</string>
|
||||||
|
<string name="revanced_miniplayer_hide_expand_close_summary_on">Close button is hidden.</string>
|
||||||
|
<string name="revanced_miniplayer_hide_expand_close_summary_off">Close button is shown.</string>
|
||||||
|
<string name="revanced_miniplayer_hide_expand_close_legacy_title">Hide expand and close buttons</string>
|
||||||
|
<string name="revanced_miniplayer_hide_expand_close_legacy_summary_on">"Buttons are hidden.
|
||||||
|
|
||||||
|
Swipe to expand or close."</string>
|
||||||
|
<string name="revanced_miniplayer_hide_expand_close_legacy_summary_off">Expand and close buttons are shown.</string>
|
||||||
<string name="revanced_miniplayer_hide_subtext_title">Hide subtexts</string>
|
<string name="revanced_miniplayer_hide_subtext_title">Hide subtexts</string>
|
||||||
<string name="revanced_miniplayer_hide_subtext_summary_on">Subtexts are hidden.</string>
|
<string name="revanced_miniplayer_hide_subtext_summary_on">Subtexts are hidden.</string>
|
||||||
<string name="revanced_miniplayer_hide_subtext_summary_off">Subtexts are shown.</string>
|
<string name="revanced_miniplayer_hide_subtext_summary_off">Subtexts are shown.</string>
|
||||||
<string name="revanced_miniplayer_hide_rewind_forward_title">Hide skip forward and back buttons</string>
|
<string name="revanced_miniplayer_hide_rewind_forward_title">Hide skip forward and back buttons</string>
|
||||||
<string name="revanced_miniplayer_hide_rewind_forward_summary_on">Skip forward and back are hidden.</string>
|
<string name="revanced_miniplayer_hide_rewind_forward_summary_on">Skip forward and back are hidden.</string>
|
||||||
<string name="revanced_miniplayer_hide_rewind_forward_summary_off">Skip forward and back are shown.</string>
|
<string name="revanced_miniplayer_hide_rewind_forward_summary_off">Skip forward and back are shown.</string>
|
||||||
|
<string name="revanced_miniplayer_width_dip_title">Initial size</string>
|
||||||
|
<string name="revanced_miniplayer_width_dip_summary">Initial on screen size, in pixels.</string>
|
||||||
|
<string name="revanced_miniplayer_width_dip_invalid_toast">Pixel size must be between %1$s and %2$s.</string>
|
||||||
<string name="revanced_miniplayer_opacity_title">Overlay opacity</string>
|
<string name="revanced_miniplayer_opacity_title">Overlay opacity</string>
|
||||||
<string name="revanced_miniplayer_opacity_summary">Opacity value between 0-100, where 0 is transparent.</string>
|
<string name="revanced_miniplayer_opacity_summary">Opacity value between 0-100, where 0 is transparent.</string>
|
||||||
<string name="revanced_miniplayer_opacity_invalid_toast">Miniplayer overlay opacity must be between 0-100.</string>
|
<string name="revanced_miniplayer_opacity_invalid_toast">Miniplayer overlay opacity must be between 0-100.</string>
|
||||||
|
@ -160,19 +160,42 @@
|
|||||||
</PreferenceScreen>SETTINGS: HOOK_BUTTONS -->
|
</PreferenceScreen>SETTINGS: HOOK_BUTTONS -->
|
||||||
|
|
||||||
<!-- SETTINGS: MINIPLAYER_TYPE_MODERN
|
<!-- SETTINGS: MINIPLAYER_TYPE_MODERN
|
||||||
<PreferenceScreen android:title="@string/revanced_preference_screen_miniplayer_title" android:key="revanced_preference_screen_miniplayer" android:summary="@string/revanced_preference_screen_miniplayer_summary">
|
<PreferenceScreen android:title="@string/revanced_preference_screen_miniplayer_title" android:key="revanced_preference_screen_miniplayer" android:summary="@string/revanced_preference_screen_miniplayer_summary">SETTINGS: MINIPLAYER_TYPE_MODERN -->
|
||||||
<ListPreference android:entries="@array/revanced_miniplayer_type_19_15_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_19_15_entry_values" />SETTINGS: MINIPLAYER_TYPE_MODERN -->
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_TYPE_19_16
|
||||||
|
<ListPreference android:entries="@array/revanced_miniplayer_type_19_16_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_19_16_entry_values" />SETTINGS: MINIPLAYER_TYPE_19_16 -->
|
||||||
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_TYPE_19_43
|
||||||
|
<ListPreference android:entries="@array/revanced_miniplayer_type_19_43_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_19_43_entry_values" />SETTINGS: MINIPLAYER_TYPE_19_43 -->
|
||||||
|
|
||||||
<!-- SETTINGS: MINIPLAYER_DOUBLE_TAP_ACTION
|
<!-- SETTINGS: MINIPLAYER_DOUBLE_TAP_ACTION
|
||||||
<SwitchPreference android:title="@string/revanced_miniplayer_enable_double_tap_action_title" android:key="revanced_miniplayer_enable_double_tap_action" android:summaryOn="@string/revanced_miniplayer_enable_double_tap_action_summary_on" android:summaryOff="@string/revanced_miniplayer_enable_double_tap_action_summary_off" />SETTINGS: MINIPLAYER_DOUBLE_TAP_ACTION -->
|
<SwitchPreference android:title="@string/revanced_miniplayer_double_tap_action_title" android:key="revanced_miniplayer_double_tap_action" android:summaryOn="@string/revanced_miniplayer_double_tap_action_summary_on" android:summaryOff="@string/revanced_miniplayer_double_tap_action_summary_off" />SETTINGS: MINIPLAYER_DOUBLE_TAP_ACTION -->
|
||||||
|
|
||||||
<!-- SETTINGS: MINIPLAYER_DRAG_AND_DROP
|
<!-- SETTINGS: MINIPLAYER_DRAG_AND_DROP
|
||||||
<SwitchPreference android:title="@string/revanced_miniplayer_enable_drag_and_drop_title" android:key="revanced_miniplayer_enable_drag_and_drop" android:summaryOn="@string/revanced_miniplayer_enable_drag_and_drop_summary_on" android:summaryOff="@string/revanced_miniplayer_enable_drag_and_drop_summary_off" />SETTINGS: MINIPLAYER_DRAG_AND_DROP -->
|
<SwitchPreference android:title="@string/revanced_miniplayer_drag_and_drop_title" android:key="revanced_miniplayer_drag_and_drop" android:summaryOn="@string/revanced_miniplayer_drag_and_drop_summary_on" android:summaryOff="@string/revanced_miniplayer_drag_and_drop_summary_off" />SETTINGS: MINIPLAYER_DRAG_AND_DROP -->
|
||||||
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_HORIZONTAL_DRAG
|
||||||
|
<SwitchPreference android:title="@string/revanced_miniplayer_horizontal_drag_title" android:key="revanced_miniplayer_horizontal_drag" android:summaryOn="@string/revanced_miniplayer_horizontal_drag_summary_on" android:summaryOff="@string/revanced_miniplayer_horizontal_drag_summary_off" />SETTINGS: MINIPLAYER_HORIZONTAL_DRAG -->
|
||||||
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_ROUNDED_CONERS
|
||||||
|
<SwitchPreference android:title="@string/revanced_miniplayer_rounded_corners_title" android:key="revanced_miniplayer_rounded_corners" android:summaryOn="@string/revanced_miniplayer_rounded_corners_summary_on" android:summaryOff="@string/revanced_miniplayer_rounded_corners_summary_off" />SETTINGS: MINIPLAYER_ROUNDED_CONERS -->
|
||||||
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_TYPE_MODERN
|
||||||
|
<SwitchPreference android:title="@string/revanced_miniplayer_hide_subtext_title" android:key="revanced_miniplayer_hide_subtext" android:summaryOn="@string/revanced_miniplayer_hide_subtext_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_subtext_summary_off" />SETTINGS: MINIPLAYER_TYPE_MODERN -->
|
||||||
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_EXPAND_CLOSE_19_25
|
||||||
|
<SwitchPreference android:title="@string/revanced_miniplayer_hide_expand_close_title" android:key="revanced_miniplayer_hide_expand_close" android:summaryOn="@string/revanced_miniplayer_hide_expand_close_legacy_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_expand_close_legacy_summary_off" />SETTINGS: MINIPLAYER_EXPAND_CLOSE_19_25 -->
|
||||||
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_EXPAND_CLOSE_19_26
|
||||||
|
<SwitchPreference android:title="@string/revanced_miniplayer_hide_expand_close_title" android:key="revanced_miniplayer_hide_expand_close" android:summaryOn="@string/revanced_miniplayer_hide_expand_close_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_expand_close_summary_off" />SETTINGS: MINIPLAYER_EXPAND_CLOSE_19_26 -->
|
||||||
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_REWIND_FORWARD
|
||||||
|
<SwitchPreference android:title="@string/revanced_miniplayer_hide_rewind_forward_title" android:key="revanced_miniplayer_hide_rewind_forward" android:summaryOn="@string/revanced_miniplayer_hide_rewind_forward_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_rewind_forward_summary_off" />SETTINGS: MINIPLAYER_REWIND_FORWARD -->
|
||||||
|
|
||||||
|
<!-- SETTINGS: MINIPLAYER_WIDTH_DIP
|
||||||
|
<app.revanced.extension.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_miniplayer_width_dip_title" android:key="revanced_miniplayer_width_dip" android:summary="@string/revanced_miniplayer_width_dip_summary" android:inputType="number" />SETTINGS: MINIPLAYER_WIDTH_DIP -->
|
||||||
|
|
||||||
<!-- SETTINGS: MINIPLAYER_TYPE_MODERN
|
<!-- SETTINGS: MINIPLAYER_TYPE_MODERN
|
||||||
<SwitchPreference android:title="@string/revanced_miniplayer_hide_expand_close_title" android:key="revanced_miniplayer_hide_expand_close" android:summaryOn="@string/revanced_miniplayer_hide_expand_close_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_expand_close_summary_off" />
|
|
||||||
<SwitchPreference android:title="@string/revanced_miniplayer_hide_subtext_title" android:key="revanced_miniplayer_hide_subtext" android:summaryOn="@string/revanced_miniplayer_hide_subtext_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_subtext_summary_off" />
|
|
||||||
<SwitchPreference android:title="@string/revanced_miniplayer_hide_rewind_forward_title" android:key="revanced_miniplayer_hide_rewind_forward" android:summaryOn="@string/revanced_miniplayer_hide_rewind_forward_summary_on" android:summaryOff="@string/revanced_miniplayer_hide_rewind_forward_summary_off" />
|
|
||||||
<app.revanced.extension.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_miniplayer_opacity_title" android:key="revanced_miniplayer_opacity" android:summary="@string/revanced_miniplayer_opacity_summary" android:inputType="number" />
|
<app.revanced.extension.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_miniplayer_opacity_title" android:key="revanced_miniplayer_opacity" android:summary="@string/revanced_miniplayer_opacity_summary" android:inputType="number" />
|
||||||
</PreferenceScreen>SETTINGS: MINIPLAYER_TYPE_MODERN -->
|
</PreferenceScreen>SETTINGS: MINIPLAYER_TYPE_MODERN -->
|
||||||
|
|
||||||
@ -266,8 +289,8 @@
|
|||||||
<SwitchPreference android:title="@string/revanced_hide_gray_separator_title" android:key="revanced_hide_gray_separator" android:summaryOn="@string/revanced_hide_gray_separator_summary_on" android:summaryOff="@string/revanced_hide_gray_separator_summary_off" />
|
<SwitchPreference android:title="@string/revanced_hide_gray_separator_title" android:key="revanced_hide_gray_separator" android:summaryOn="@string/revanced_hide_gray_separator_summary_on" android:summaryOff="@string/revanced_hide_gray_separator_summary_off" />
|
||||||
<SwitchPreference android:title="@string/revanced_hide_snack_bar_title" android:key="revanced_hide_snack_bar" android:summaryOn="@string/revanced_hide_snack_bar_summary_on" android:summaryOff="@string/revanced_hide_snack_bar_summary_off" />SETTINGS: HIDE_LAYOUT_COMPONENTS -->
|
<SwitchPreference android:title="@string/revanced_hide_snack_bar_title" android:key="revanced_hide_snack_bar" android:summaryOn="@string/revanced_hide_snack_bar_summary_on" android:summaryOff="@string/revanced_hide_snack_bar_summary_off" />SETTINGS: HIDE_LAYOUT_COMPONENTS -->
|
||||||
|
|
||||||
<!-- SETTINGS: MINIPLAYER_TYPE_LEGACY
|
<!-- SETTINGS: MINIPLAYER_TYPE_19_14
|
||||||
<ListPreference android:entries="@array/revanced_miniplayer_type_legacy_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_legacy_entry_values" />SETTINGS: MINIPLAYER_TYPE_LEGACY -->
|
<ListPreference android:entries="@array/revanced_miniplayer_type_19_14_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_19_14_entry_values" />SETTINGS: MINIPLAYER_TYPE_19_14 -->
|
||||||
|
|
||||||
<!-- SETTINGS: REMOVE_VIEWER_DISCRETION_DIALOG
|
<!-- SETTINGS: REMOVE_VIEWER_DISCRETION_DIALOG
|
||||||
<SwitchPreference android:title="@string/revanced_remove_viewer_discretion_dialog_title" android:key="revanced_remove_viewer_discretion_dialog" android:summary="@string/revanced_remove_viewer_discretion_dialog_summary" />SETTINGS: REMOVE_VIEWER_DISCRETION_DIALOG -->
|
<SwitchPreference android:title="@string/revanced_remove_viewer_discretion_dialog_title" android:key="revanced_remove_viewer_discretion_dialog" android:summary="@string/revanced_remove_viewer_discretion_dialog_summary" />SETTINGS: REMOVE_VIEWER_DISCRETION_DIALOG -->
|
||||||
|
Reference in New Issue
Block a user