Skip to content
This repository has been archived by the owner on Dec 11, 2024. It is now read-only.

Commit

Permalink
feat(YouTube): add Miniplayer patch (Replaces `Enable tablet mini p…
Browse files Browse the repository at this point in the history
…layer` patch)
  • Loading branch information
inotia00 authored and anddea committed Jun 14, 2024
1 parent a3ce453 commit 465a638
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,18 @@ public void save(@NonNull T newValue) {
public T get() {
return value;
}

/**
* Availability based on if this setting is currently set to any of the provided types.
*/
@SafeVarargs
public final Setting.Availability availability(@NonNull T... types) {
return () -> {
T currentEnumType = get();
for (T enumType : types) {
if (currentEnumType == enumType) return true;
}
return false;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import android.preference.PreferenceScreen;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
Expand Down Expand Up @@ -88,12 +89,31 @@ public static void hideViewUnderCondition(BooleanSetting condition, View view) {
hideViewUnderCondition(condition.get(), view);
}

public static void hideViewUnderCondition(boolean enabled, View view) {
if (!enabled) return;
/**
* Hide a view by setting its visibility to GONE.
*
* @param condition The setting to check for hiding the view.
* @param view The view to hide.
*/
public static void hideViewUnderCondition(boolean condition, View view) {
if (!condition) return;

view.setVisibility(View.GONE);
}

@SuppressWarnings("unused")
public static void hideViewByRemovingFromParentUnderCondition(BooleanSetting condition, View view) {
hideViewByRemovingFromParentUnderCondition(condition.get(), view);
}

public static void hideViewByRemovingFromParentUnderCondition(boolean condition, View view) {
if (!condition) return;
if (!(view.getParent() instanceof ViewGroup viewGroup))
return;

viewGroup.removeView(view);
}

/**
* General purpose pool for network calls and other background tasks.
* All tasks run at max thread priority.
Expand Down Expand Up @@ -193,6 +213,25 @@ public static <T extends View> T getChildView(@NonNull ViewGroup viewGroup, @Non
return null;
}

@Nullable
public static ViewParent getParentView(@NonNull View view, int nthParent) {
ViewParent parent = view.getParent();

int currentDepth = 0;
while (++currentDepth < nthParent && parent != null) {
parent = parent.getParent();
}

if (currentDepth == nthParent) {
return parent;
}

final int currentDepthLog = currentDepth;
Logger.printDebug(() -> "Could not find parent view of depth: " + nthParent
+ " and instead found at: " + currentDepthLog + " view: " + view);
return null;
}

public static void restartApp(@NonNull Context mContext) {
String packageName = mContext.getPackageName();
Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(packageName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,54 +193,6 @@ public static boolean enableGradientLoadingScreen() {

// endregion

// region [Enable tablet mini player] patch

private static boolean tabletMiniPlayerEnabled = Settings.ENABLE_TABLET_MINI_PLAYER.get();
private static boolean modernMiniPlayerEnabled = tabletMiniPlayerEnabled && Settings.ENABLE_MODERN_MINI_PLAYER.get();

public static boolean enableTabletMiniPlayer(boolean original) {
return tabletMiniPlayerEnabled || original;
}

/**
* In ModernMiniPlayer, the drawables of the close button and expand button are reversed.
* OnClickListener appears to be applied normally, so this appears to be a bug in YouTube.
* To solve this, swap the drawables of the close and expand buttons.
*/
private static final int closeButtonDrawableId =
ResourceUtils.getDrawableIdentifier("yt_outline_x_white_24");
private static final int expandButtonDrawableId =
ResourceUtils.getDrawableIdentifier("yt_outline_picture_in_picture_white_24");

public static boolean enableModernMiniPlayer(boolean original) {
return modernMiniPlayerEnabled || original;
}

public static int enableModernMiniPlayer(int original) {
return modernMiniPlayerEnabled ? 1 : original;
}

public static int replaceCloseButtonDrawableId(int original) {
return modernMiniPlayerEnabled ? expandButtonDrawableId : original;
}

public static int replaceExpandButtonDrawableId(int original) {
return modernMiniPlayerEnabled ? closeButtonDrawableId : original;
}

public static void hideRewindAndForwardButton(View view) {
if (!Settings.HIDE_MINI_PLAYER_REWIND_FORWARD_BUTTON.get())
return;

view.setVisibility(View.GONE);

if (view.getParent() instanceof ViewGroup viewGroup) {
viewGroup.removeView(view);
}
}

// endregion

// region [Hide layout components] patch

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
package app.revanced.integrations.youtube.patches.general;

import static app.revanced.integrations.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_1;
import static app.revanced.integrations.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_2;
import static app.revanced.integrations.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_3;
import static app.revanced.integrations.youtube.patches.general.MiniplayerPatch.MiniplayerType.ORIGINAL;
import static app.revanced.integrations.youtube.utils.ExtendedUtils.validateValue;

import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import androidx.annotation.Nullable;

import app.revanced.integrations.shared.utils.Logger;
import app.revanced.integrations.shared.utils.ResourceUtils;
import app.revanced.integrations.shared.utils.Utils;
import app.revanced.integrations.youtube.settings.Settings;

@SuppressWarnings("unused")
public final class MiniplayerPatch {

/**
* Mini player type. Null fields indicates to use the original un-patched value.
*/
public enum MiniplayerType {
/** Unmodified type, and same as un-patched. */
ORIGINAL(null, null),
PHONE(false, null),
TABLET(true, null),
MODERN_1(null, 1),
MODERN_2(null, 2),
MODERN_3(null, 3);

/**
* Legacy tablet hook value.
*/
@Nullable
final Boolean legacyTabletOverride;

/**
* Modern player type used by YT.
*/
@Nullable
final Integer modernPlayerType;

MiniplayerType(@Nullable Boolean legacyTabletOverride, @Nullable Integer modernPlayerType) {
this.legacyTabletOverride = legacyTabletOverride;
this.modernPlayerType = modernPlayerType;
}

public boolean isModern() {
return modernPlayerType != null;
}
}

/**
* Modern subtitle overlay for {@link MiniplayerType#MODERN_2}.
* Resource is not present in older targets, and this field will be zero.
*/
private static final int MODERN_OVERLAY_SUBTITLE_TEXT
= ResourceUtils.getIdIdentifier("modern_miniplayer_subtitle_text");

private static final MiniplayerType CURRENT_TYPE = Settings.MINIPLAYER_TYPE.get();

private static final boolean HIDE_EXPAND_CLOSE_ENABLED =
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3) && Settings.MINIPLAYER_HIDE_EXPAND_CLOSE.get();

private static final boolean HIDE_SUBTEXT_ENABLED =
(CURRENT_TYPE == MODERN_1 || CURRENT_TYPE == MODERN_3) && Settings.MINIPLAYER_HIDE_SUBTEXT.get();

private static final boolean HIDE_REWIND_FORWARD_ENABLED =
CURRENT_TYPE == MODERN_1 && Settings.MINIPLAYER_HIDE_REWIND_FORWARD.get();

private static final int OPACITY_LEVEL;

static {
final int opacity = validateValue(
Settings.MINIPLAYER_OPACITY,
0,
100,
"revanced_miniplayer_opacity_invalid_toast"
);

OPACITY_LEVEL = (opacity * 255) / 100;
}

/**
* Injection point.
*/
public static boolean getLegacyTabletMiniplayerOverride(boolean original) {
Boolean isTablet = CURRENT_TYPE.legacyTabletOverride;
return isTablet == null
? original
: isTablet;
}

/**
* Injection point.
*/
public static boolean getModernMiniplayerOverride(boolean original) {
return CURRENT_TYPE == ORIGINAL
? original
: CURRENT_TYPE.isModern();
}

/**
* Injection point.
*/
public static int getModernMiniplayerOverrideType(int original) {
Integer modernValue = CURRENT_TYPE.modernPlayerType;
return modernValue == null
? original
: modernValue;
}

/**
* Injection point.
*/
public static void adjustMiniplayerOpacity(ImageView view) {
if (CURRENT_TYPE == MODERN_1) {
view.setImageAlpha(OPACITY_LEVEL);
}
}

/**
* Injection point.
*/
public static void hideMiniplayerExpandClose(ImageView view) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_EXPAND_CLOSE_ENABLED, view);
}

/**
* Injection point.
*/
public static void hideMiniplayerRewindForward(ImageView view) {
Utils.hideViewByRemovingFromParentUnderCondition(HIDE_REWIND_FORWARD_ENABLED, view);
}

/**
* Injection point.
*/
public static void hideMiniplayerSubTexts(View view) {
// Different subviews are passed in, but only TextView and layouts are of interest here.
final boolean hideView = HIDE_SUBTEXT_ENABLED && (view instanceof TextView || view instanceof LinearLayout);
Utils.hideViewByRemovingFromParentUnderCondition(hideView, view);
}

/**
* Injection point.
*/
public static void playerOverlayGroupCreated(View group) {
// Modern 2 has an half broken subtitle that is always present.
// Always hide it to make the miniplayer mostly usable.
if (CURRENT_TYPE == MODERN_2 && MODERN_OVERLAY_SUBTITLE_TEXT != 0) {
if (group instanceof ViewGroup viewGroup) {
View subtitleText = Utils.getChildView(viewGroup, true,
view -> view.getId() == MODERN_OVERLAY_SUBTITLE_TEXT);

if (subtitleText != null) {
subtitleText.setVisibility(View.GONE);
Logger.printDebug(() -> "Modern overlay subtitle view set to hidden");
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
import static app.revanced.integrations.shared.settings.Setting.parent;
import static app.revanced.integrations.shared.settings.Setting.parentsAny;
import static app.revanced.integrations.shared.utils.StringRef.str;
import static app.revanced.integrations.youtube.patches.general.MiniplayerPatch.MiniplayerType;
import static app.revanced.integrations.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_1;
import static app.revanced.integrations.youtube.patches.general.MiniplayerPatch.MiniplayerType.MODERN_3;
import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.MANUAL_SKIP;
import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY;
import static app.revanced.integrations.youtube.sponsorblock.objects.CategoryBehaviour.SKIP_AUTOMATICALLY_ONCE;
Expand Down Expand Up @@ -125,9 +128,6 @@ public class Settings extends BaseSettings {
public static final BooleanSetting DISABLE_AUTO_CAPTIONS = new BooleanSetting("revanced_disable_auto_captions", FALSE, true);
public static final BooleanSetting DISABLE_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_splash_animation", FALSE, true);
public static final BooleanSetting ENABLE_GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_enable_gradient_loading_screen", FALSE, true);
public static final BooleanSetting ENABLE_TABLET_MINI_PLAYER = new BooleanSetting("revanced_enable_tablet_mini_player", FALSE, true);
public static final BooleanSetting ENABLE_MODERN_MINI_PLAYER = new BooleanSetting("revanced_enable_modern_mini_player", FALSE, true, parent(ENABLE_TABLET_MINI_PLAYER));
public static final BooleanSetting HIDE_MINI_PLAYER_REWIND_FORWARD_BUTTON = new BooleanSetting("revanced_hide_mini_player_rewind_forward_button", FALSE, true, parent(ENABLE_MODERN_MINI_PLAYER));
public static final BooleanSetting HIDE_FLOATING_MICROPHONE = new BooleanSetting("revanced_hide_floating_microphone", TRUE, true);
public static final BooleanSetting HIDE_GRAY_SEPARATOR = new BooleanSetting("revanced_hide_gray_separator", TRUE);
public static final BooleanSetting HIDE_SNACK_BAR = new BooleanSetting("revanced_hide_snack_bar", FALSE);
Expand All @@ -147,6 +147,24 @@ public class Settings extends BaseSettings {
public static final BooleanSetting CUSTOM_FILTER = new BooleanSetting("revanced_custom_filter", FALSE);
public static final StringSetting CUSTOM_FILTER_STRINGS = new StringSetting("revanced_custom_filter_strings", "", true, parent(CUSTOM_FILTER));

// PreferenceScreen: General - Miniplayer
public static final EnumSetting<MiniplayerType> MINIPLAYER_TYPE = new EnumSetting<>("revanced_miniplayer_type", MiniplayerType.ORIGINAL, true);
public static final BooleanSetting MINIPLAYER_HIDE_EXPAND_CLOSE = new BooleanSetting("revanced_miniplayer_hide_expand_close", 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 IntegerSetting MINIPLAYER_OPACITY = new IntegerSetting("revanced_miniplayer_opacity", 100, true, MINIPLAYER_TYPE.availability(MODERN_1));

// PreferenceScreen: General - Navigation buttons
public static final BooleanSetting ENABLE_NARROW_NAVIGATION_BUTTONS = new BooleanSetting("revanced_enable_narrow_navigation_buttons", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_CREATE_BUTTON = new BooleanSetting("revanced_hide_navigation_create_button", TRUE, true);
public static final BooleanSetting HIDE_NAVIGATION_HOME_BUTTON = new BooleanSetting("revanced_hide_navigation_home_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_LIBRARY_BUTTON = new BooleanSetting("revanced_hide_navigation_library_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_hide_navigation_notifications_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_SHORTS_BUTTON = new BooleanSetting("revanced_hide_navigation_shorts_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_SUBSCRIPTIONS_BUTTON = new BooleanSetting("revanced_hide_navigation_subscriptions_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_LABEL = new BooleanSetting("revanced_hide_navigation_label", FALSE, true);
public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true);

// PreferenceScreen: General - Settings menu
public static final BooleanSetting HIDE_SETTINGS_MENU = new BooleanSetting("revanced_hide_settings_menu", FALSE);
public static final StringSetting HIDE_SETTINGS_MENU_FILTER_STRINGS = new StringSetting("revanced_hide_settings_menu_filter_strings", "", true, parent(HIDE_SETTINGS_MENU));
Expand All @@ -165,17 +183,6 @@ public class Settings extends BaseSettings {
public static final BooleanSetting REPLACE_TOOLBAR_CREATE_BUTTON_TYPE = new BooleanSetting("revanced_replace_toolbar_create_button_type", FALSE, true);


// PreferenceScreen: General - Navigation buttons
public static final BooleanSetting ENABLE_NARROW_NAVIGATION_BUTTONS = new BooleanSetting("revanced_enable_narrow_navigation_buttons", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_CREATE_BUTTON = new BooleanSetting("revanced_hide_navigation_create_button", TRUE, true);
public static final BooleanSetting HIDE_NAVIGATION_HOME_BUTTON = new BooleanSetting("revanced_hide_navigation_home_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_LIBRARY_BUTTON = new BooleanSetting("revanced_hide_navigation_library_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_hide_navigation_notifications_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_SHORTS_BUTTON = new BooleanSetting("revanced_hide_navigation_shorts_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_SUBSCRIPTIONS_BUTTON = new BooleanSetting("revanced_hide_navigation_subscriptions_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_LABEL = new BooleanSetting("revanced_hide_navigation_label", TRUE, true);
public static final BooleanSetting SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON = new BooleanSetting("revanced_switch_create_with_notifications_button", TRUE, true);

// PreferenceScreen: Player
public static final IntegerSetting CUSTOM_PLAYER_OVERLAY_OPACITY = new IntegerSetting("revanced_custom_player_overlay_opacity", 100, true);
public static final BooleanSetting DISABLE_AUTO_PLAYER_POPUP_PANELS = new BooleanSetting("revanced_disable_auto_player_popup_panels", TRUE, true);
Expand Down

0 comments on commit 465a638

Please sign in to comment.