Skip to content

Commit

Permalink
feat(YouTube): Add Change form factor patch (#4217)
Browse files Browse the repository at this point in the history
  • Loading branch information
LisoUseInAIKyrios authored Dec 27, 2024
1 parent da4aeac commit 644ac5b
Show file tree
Hide file tree
Showing 18 changed files with 365 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,6 @@ private static List<Setting<?>> allLoadedSettingsSorted() {

/**
* Confirmation message to display, if the user tries to change the setting from the default value.
* Currently this works only for Boolean setting types.
*/
@Nullable
public final StringRef userDialogMessage;
Expand Down Expand Up @@ -244,6 +243,7 @@ public static <T> void migrateOldSettingToNew(@NonNull Setting<T> oldSetting, @N
*
* This method will be deleted in the future.
*/
@SuppressWarnings("rawtypes")
public static void migrateFromOldPreferences(@NonNull SharedPrefCategory oldPrefs, @NonNull Setting setting, String settingKey) {
if (!oldPrefs.preferences.contains(settingKey)) {
return; // Nothing to do.
Expand Down Expand Up @@ -419,6 +419,7 @@ public static boolean importFromJSON(@NonNull Context alertDialogContext, @NonNu

boolean rebootSettingChanged = false;
int numberOfSettingsImported = 0;
//noinspection rawtypes
for (Setting setting : SETTINGS) {
String key = setting.getImportExportKey();
if (json.has(key)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {

private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
try {
Setting<?> setting = Setting.getSettingFromPath(str);
Setting<?> setting = Setting.getSettingFromPath(Objects.requireNonNull(str));
if (setting == null) {
return;
}
Expand All @@ -52,23 +52,21 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
}
Logger.printDebug(() -> "Preference changed: " + setting.key);

// Apply 'Setting <- Preference', unless during importing when it needs to be 'Setting -> Preference'.
updatePreference(pref, setting, true, settingImportInProgress);
// Update any other preference availability that may now be different.
updateUIAvailability();

if (settingImportInProgress) {
return;
}

if (!showingUserDialogMessage) {
if (setting.userDialogMessage != null && ((SwitchPreference) pref).isChecked() != (Boolean) setting.defaultValue) {
showSettingUserDialogConfirmation((SwitchPreference) pref, (BooleanSetting) setting);
if (!settingImportInProgress && !showingUserDialogMessage) {
if (setting.userDialogMessage != null && !prefIsSetToDefault(pref, setting)) {
// Do not change the setting yet, to allow preserving whatever
// list/text value was previously set if it needs to be reverted.
showSettingUserDialogConfirmation(pref, setting);
return;
} else if (setting.rebootApp) {
showRestartDialog(getContext());
}
}

// Apply 'Setting <- Preference', unless during importing when it needs to be 'Setting -> Preference'.
updatePreference(pref, setting, true, settingImportInProgress);
// Update any other preference availability that may now be different.
updateUIAvailability();
} catch (Exception ex) {
Logger.printException(() -> "OnSharedPreferenceChangeListener failure", ex);
}
Expand All @@ -92,7 +90,7 @@ protected void initialize() {
Utils.setPreferenceTitlesToMultiLineIfNeeded(screen);
}

private void showSettingUserDialogConfirmation(SwitchPreference switchPref, BooleanSetting setting) {
private void showSettingUserDialogConfirmation(Preference pref, Setting<?> setting) {
Utils.verifyOnMainThread();

final var context = getContext();
Expand All @@ -104,12 +102,19 @@ private void showSettingUserDialogConfirmation(SwitchPreference switchPref, Bool
.setTitle(confirmDialogTitle)
.setMessage(Objects.requireNonNull(setting.userDialogMessage).toString())
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
// User confirmed, save to the Setting.
updatePreference(pref, setting, true, false);

// Update availability of other preferences that may be changed.
updateUIAvailability();

if (setting.rebootApp) {
showRestartDialog(context);
}
})
.setNegativeButton(android.R.string.cancel, (dialog, id) -> {
switchPref.setChecked(setting.defaultValue); // Recursive call that resets the Setting value.
// Restore whatever the setting was before the change.
updatePreference(pref, setting, true, true);
})
.setOnDismissListener(dialog -> {
showingUserDialogMessage = false;
Expand All @@ -132,6 +137,24 @@ protected void updateUIAvailability() {
updatePreferenceScreen(getPreferenceScreen(), false, false);
}

/**
* @return If the preference is currently set to the default value of the Setting.
*/
protected boolean prefIsSetToDefault(Preference pref, Setting<?> setting) {
if (pref instanceof SwitchPreference switchPref) {
return switchPref.isChecked() == (Boolean) setting.defaultValue;
}
if (pref instanceof EditTextPreference editPreference) {
return editPreference.getText().equals(setting.defaultValue.toString());
}
if (pref instanceof ListPreference listPref) {
return listPref.getValue().equals(setting.defaultValue.toString());
}

throw new IllegalStateException("Must override method to handle "
+ "preference type: " + pref.getClass());
}

/**
* Syncs all UI Preferences to any {@link Setting} they represent.
*/
Expand Down Expand Up @@ -170,23 +193,20 @@ private void updatePreferenceScreen(@NonNull PreferenceScreen screen,
protected void syncSettingWithPreference(@NonNull Preference pref,
@NonNull Setting<?> setting,
boolean applySettingToPreference) {
if (pref instanceof SwitchPreference) {
SwitchPreference switchPref = (SwitchPreference) pref;
if (pref instanceof SwitchPreference switchPref) {
BooleanSetting boolSetting = (BooleanSetting) setting;
if (applySettingToPreference) {
switchPref.setChecked(boolSetting.get());
} else {
BooleanSetting.privateSetValue(boolSetting, switchPref.isChecked());
}
} else if (pref instanceof EditTextPreference) {
EditTextPreference editPreference = (EditTextPreference) pref;
} else if (pref instanceof EditTextPreference editPreference) {
if (applySettingToPreference) {
editPreference.setText(setting.get().toString());
} else {
Setting.privateSetValueFromString(setting, editPreference.getText());
}
} else if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
} else if (pref instanceof ListPreference listPref) {
if (applySettingToPreference) {
listPref.setValue(setting.get().toString());
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,13 @@ private static ThumbnailOption optionSettingForCurrentNavigation() {
// Unknown tab, treat as the home tab;
return homeOption;
}
if (selectedNavButton == NavigationButton.HOME) {
return homeOption;
}
if (selectedNavButton == NavigationButton.SUBSCRIPTIONS || selectedNavButton == NavigationButton.NOTIFICATIONS) {
return subscriptionsOption;
}
// A library tab variant is active.
return libraryOption;

return switch (selectedNavButton) {
case SUBSCRIPTIONS, NOTIFICATIONS -> subscriptionsOption;
case LIBRARY -> libraryOption;
// Home or explore tab.
default -> homeOption;
};
}

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

import androidx.annotation.Nullable;

import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.settings.Settings;

@SuppressWarnings("unused")
public class ChangeFormFactorPatch {

public enum FormFactor {
/**
* Unmodified, and same as un-patched.
*/
DEFAULT(null),
/**
* <pre>
* Some changes include:
* - Explore tab is present.
* - watch history is missing.
* - feed thumbnails fade in.
*/
UNKNOWN(0),
SMALL(1),
LARGE(2),
/**
* Cars with 'Google built-in'.
* Layout seems identical to {@link #UNKNOWN}
* even when using an Android Automotive device.
*/
AUTOMOTIVE(3),
WEARABLE(4);

@Nullable
final Integer formFactorType;

FormFactor(@Nullable Integer formFactorType) {
this.formFactorType = formFactorType;
}
}

@Nullable
private static final Integer FORM_FACTOR_TYPE = Settings.CHANGE_FORM_FACTOR.get().formFactorType;

/**
* Injection point.
*/
public static int getFormFactor(int original) {
return FORM_FACTOR_TYPE == null
? original
: FORM_FACTOR_TYPE;
}

}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -528,14 +528,13 @@ private boolean hideKeywordSettingIsActive() {
if (selectedNavButton == null) {
return hideHome; // Unknown tab, treat the same as home.
}
if (selectedNavButton == NavigationButton.HOME) {
return hideHome;
}
if (selectedNavButton == NavigationButton.SUBSCRIPTIONS) {
return hideSubscriptions;
}
// User is in the Library or Notifications tab.
return false;

return switch (selectedNavButton) {
case HOME, EXPLORE -> hideHome;
case SUBSCRIPTIONS -> hideSubscriptions;
// User is in the Library or notifications.
default -> false;
};
}

private void updateStats(boolean videoWasHidden, @Nullable String keyword) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ private static boolean shouldHideShortsFeedItems() {
}

return switch (selectedNavButton) {
case HOME -> hideHome;
case HOME, EXPLORE -> hideHome;
case SUBSCRIPTIONS -> hideSubscriptions;
case LIBRARY -> hideHistory;
default -> false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import static app.revanced.extension.shared.settings.Setting.migrateOldSettingToNew;
import static app.revanced.extension.shared.settings.Setting.parent;
import static app.revanced.extension.shared.settings.Setting.parentsAny;
import static app.revanced.extension.youtube.patches.ChangeFormFactorPatch.FormFactor;
import static app.revanced.extension.youtube.patches.ChangeStartPagePatch.StartPage;
import static app.revanced.extension.youtube.patches.ExitFullscreenPatch.FullscreenMode;
import static app.revanced.extension.youtube.patches.ForceOriginalAudioPatch.ForceOriginalAudioAvailability;
Expand Down Expand Up @@ -202,12 +203,12 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_PLAYER_FLYOUT_WATCH_IN_VR = new BooleanSetting("revanced_hide_player_flyout_watch_in_vr", TRUE);

// General layout
public static final EnumSetting<FormFactor> CHANGE_FORM_FACTOR = new EnumSetting<>("revanced_change_form_factor", FormFactor.DEFAULT, true, "revanced_change_form_factor_user_dialog_message");
public static final BooleanSetting BYPASS_IMAGE_REGION_RESTRICTIONS = new BooleanSetting("revanced_bypass_image_region_restrictions", FALSE, true);
public static final BooleanSetting GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_gradient_loading_screen", FALSE, true);
public static final BooleanSetting REMOVE_VIEWER_DISCRETION_DIALOG = new BooleanSetting("revanced_remove_viewer_discretion_dialog", FALSE,
"revanced_remove_viewer_discretion_dialog_user_dialog_message");
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message");
public static final BooleanSetting TABLET_LAYOUT = new BooleanSetting("revanced_tablet_layout", FALSE, true, "revanced_tablet_layout_user_dialog_message");
public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true);
public static final EnumSetting<StartPage> CHANGE_START_PAGE = new EnumSetting<>("revanced_change_start_page", StartPage.DEFAULT, true);
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", IS_19_17_OR_GREATER ? "19.26.42" : "17.33.42", true, parent(SPOOF_APP_VERSION));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton.CREATE;

import android.app.Activity;
import android.os.Build;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
Expand Down Expand Up @@ -242,6 +245,30 @@ private static void navigationTabCreatedCallback(NavigationButton button, View t
// Code is added during patching.
}

/**
* Use the bundled non cairo filled icon instead of a custom icon.
* Use the old non cairo filled icon, which is almost identical to
* the what would be the filled cairo icon.
*/
private static final int fillBellCairoBlack = Utils.getResourceIdentifier(
"yt_fill_bell_black_24", "drawable");

/**
* Injection point.
* Fixes missing drawable.
*/
@RequiresApi(api = Build.VERSION_CODES.N)
@SuppressWarnings({"unchecked", "rawtypes"})
public static void setCairoNotificationFilledIcon(EnumMap enumMap, Enum tabActivityCairo) {
if (fillBellCairoBlack != 0) {
// Show a popup informing this fix is no longer needed to those who might care.
if (BaseSettings.DEBUG.get() && enumMap.containsKey(tabActivityCairo)) {
Logger.printException(() -> "YouTube fixed the cairo notification icons");
}
enumMap.putIfAbsent(tabActivityCairo, fillBellCairoBlack);
}
}

public enum NavigationButton {
HOME("PIVOT_HOME", "TAB_HOME_CAIRO"),
SHORTS("TAB_SHORTS", "TAB_SHORTS_CAIRO"),
Expand All @@ -250,6 +277,10 @@ public enum NavigationButton {
* This tab will never be in a selected state, even if the create video UI is on screen.
*/
CREATE("CREATION_TAB_LARGE", "CREATION_TAB_LARGE_CAIRO"),
/**
* Only shown to automotive layout.
*/
EXPLORE("TAB_EXPLORE"),
SUBSCRIPTIONS("PIVOT_SUBSCRIPTIONS", "TAB_SUBSCRIPTIONS_CAIRO"),
/**
* Notifications tab. Only present when
Expand Down
5 changes: 4 additions & 1 deletion patches/api/patches.api
Original file line number Diff line number Diff line change
Expand Up @@ -1101,6 +1101,10 @@ public final class app/revanced/patches/youtube/layout/buttons/overlay/HidePlaye
public static final fun getHidePlayerOverlayButtonsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

public final class app/revanced/patches/youtube/layout/formfactor/ChangeFormFactorPatchKt {
public static final fun getChangeFormFactorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

public final class app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatchKt {
public static final fun getHideEndscreenCardsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
Expand Down Expand Up @@ -1230,7 +1234,6 @@ public final class app/revanced/patches/youtube/layout/startupshortsreset/Disabl
}

public final class app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatchKt {
public static final field EXTENSION_CLASS_DESCRIPTOR Ljava/lang/String;
public static final fun getEnableTabletLayoutPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

Expand Down
Loading

0 comments on commit 644ac5b

Please sign in to comment.