feat(youtube): import / export of revanced settings (#388)

This commit is contained in:
LisoUseInAIKyrios 2023-05-15 11:51:15 +04:00 committed by GitHub
parent 224221cd80
commit c3f08d8d7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1088 additions and 330 deletions

View File

@ -5,6 +5,6 @@ import app.revanced.integrations.settings.SettingsEnum;
public class AutoRepeatPatch {
//Used by app.revanced.patches.youtube.layout.autorepeat.patch.AutoRepeatPatch
public static boolean shouldAutoRepeat() {
return SettingsEnum.PREFERRED_AUTO_REPEAT.getBoolean();
return SettingsEnum.AUTO_REPEAT.getBoolean();
}
}

View File

@ -4,10 +4,13 @@ import app.revanced.integrations.settings.SettingsEnum;
public class DisableAutoCaptionsPatch {
/**
* Used by injected code. Do not delete.
*/
public static boolean captionsButtonDisabled;
public static boolean autoCaptionsEnabled() {
return SettingsEnum.CAPTIONS_ENABLED.getBoolean();
return SettingsEnum.AUTO_CAPTIONS.getBoolean();
}
}

View File

@ -5,6 +5,6 @@ import app.revanced.integrations.settings.SettingsEnum;
public class DisableStartupShortsPlayerPatch {
//Used by app.revanced.patches.youtube.layout.startupshortsreset.patch.DisableShortsOnStartupPatch
public static boolean disableStartupShortsPlayer() {
return SettingsEnum.DISABLE_STARTUP_SHORTS_PLAYER.getBoolean();
return SettingsEnum.DISABLE_RESUMING_SHORTS_PLAYER.getBoolean();
}
}

View File

@ -15,37 +15,37 @@ public final class GeneralAdsPatch extends Filter {
};
private final BlockRule custom = new CustomBlockRule(
SettingsEnum.ADREMOVER_CUSTOM_ENABLED,
SettingsEnum.ADREMOVER_CUSTOM_REMOVAL
SettingsEnum.CUSTOM_FILTER,
SettingsEnum.CUSTOM_FILTER_STRINGS
);
public GeneralAdsPatch() {
var communityPosts = new BlockRule(SettingsEnum.ADREMOVER_COMMUNITY_POSTS_REMOVAL, "post_base_wrapper");
var communityGuidelines = new BlockRule(SettingsEnum.ADREMOVER_COMMUNITY_GUIDELINES_REMOVAL, "community_guidelines");
var subscribersCommunityGuidelines = new BlockRule(SettingsEnum.ADREMOVER_SUBSCRIBERS_COMMUNITY_GUIDELINES_REMOVAL, "sponsorships_comments_upsell");
var channelMemberShelf = new BlockRule(SettingsEnum.ADREMOVER_CHANNEL_MEMBER_SHELF_REMOVAL, "member_recognition_shelf");
var compactBanner = new BlockRule(SettingsEnum.ADREMOVER_COMPACT_BANNER_REMOVAL, "compact_banner");
var inFeedSurvey = new BlockRule(SettingsEnum.ADREMOVER_FEED_SURVEY_REMOVAL, "in_feed_survey", "slimline_survey");
var medicalPanel = new BlockRule(SettingsEnum.ADREMOVER_MEDICAL_PANEL_REMOVAL, "medical_panel");
var paidContent = new BlockRule(SettingsEnum.ADREMOVER_PAID_CONTENT_REMOVAL, "paid_content_overlay");
var merchandise = new BlockRule(SettingsEnum.ADREMOVER_MERCHANDISE_REMOVAL, "product_carousel");
var infoPanel = new BlockRule(SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL, "publisher_transparency_panel", "single_item_information_panel");
var latestPosts = new BlockRule(SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS, "post_shelf");
var channelGuidelines = new BlockRule(SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES, "channel_guidelines_entry_banner");
var communityPosts = new BlockRule(SettingsEnum.HIDE_COMMUNITY_POSTS, "post_base_wrapper");
var communityGuidelines = new BlockRule(SettingsEnum.HIDE_COMMUNITY_GUIDELINES, "community_guidelines");
var subscribersCommunityGuidelines = new BlockRule(SettingsEnum.HIDE_SUBSCRIBERS_COMMUNITY_GUIDELINES, "sponsorships_comments_upsell");
var channelMemberShelf = new BlockRule(SettingsEnum.HIDE_CHANNEL_MEMBER_SHELF, "member_recognition_shelf");
var compactBanner = new BlockRule(SettingsEnum.HIDE_COMPACT_BANNER, "compact_banner");
var inFeedSurvey = new BlockRule(SettingsEnum.HIDE_FEED_SURVEY, "in_feed_survey", "slimline_survey");
var medicalPanel = new BlockRule(SettingsEnum.HIDE_MEDICAL_PANELS, "medical_panel");
var merchandise = new BlockRule(SettingsEnum.HIDE_MERCHANDISE_BANNERS, "product_carousel");
var infoPanel = new BlockRule(SettingsEnum.HIDE_HIDE_INFO_PANELS, "publisher_transparency_panel", "single_item_information_panel");
var channelGuidelines = new BlockRule(SettingsEnum.HIDE_HIDE_CHANNEL_GUIDELINES, "channel_guidelines_entry_banner");
var audioTrackButton = new BlockRule(SettingsEnum.HIDE_AUDIO_TRACK_BUTTON, "multi_feed_icon_button");
var artistCard = new BlockRule(SettingsEnum.HIDE_ARTIST_CARDS, "official_card");
var selfSponsor = new BlockRule(SettingsEnum.ADREMOVER_SELF_SPONSOR_REMOVAL, "cta_shelf_card");
var chapterTeaser = new BlockRule(SettingsEnum.ADREMOVER_CHAPTER_TEASER_REMOVAL, "expandable_metadata", "macro_markers_carousel");
var viewProducts = new BlockRule(SettingsEnum.ADREMOVER_VIEW_PRODUCTS, "product_item", "products_in_video");
var webLinkPanel = new BlockRule(SettingsEnum.ADREMOVER_WEB_SEARCH_RESULTS, "web_link_panel");
var channelBar = new BlockRule(SettingsEnum.ADREMOVER_CHANNEL_BAR, "channel_bar");
var relatedVideos = new BlockRule(SettingsEnum.ADREMOVER_RELATED_VIDEOS, "fullscreen_related_videos");
var quickActions = new BlockRule(SettingsEnum.ADREMOVER_QUICK_ACTIONS, "quick_actions");
var imageShelf = new BlockRule(SettingsEnum.ADREMOVER_IMAGE_SHELF, "image_shelf");
var graySeparator = new BlockRule(SettingsEnum.ADREMOVER_GRAY_SEPARATOR,
var chapterTeaser = new BlockRule(SettingsEnum.HIDE_CHAPTER_TEASER, "expandable_metadata", "macro_markers_carousel");
var viewProducts = new BlockRule(SettingsEnum.HIDE_PRODUCTS_BANNER, "product_item", "products_in_video");
var webLinkPanel = new BlockRule(SettingsEnum.HIDE_WEB_SEARCH_RESULTS, "web_link_panel");
var channelBar = new BlockRule(SettingsEnum.HIDE_CHANNEL_BAR, "channel_bar");
var relatedVideos = new BlockRule(SettingsEnum.HIDE_RELATED_VIDEOS, "fullscreen_related_videos");
var quickActions = new BlockRule(SettingsEnum.HIDE_QUICK_ACTIONS, "quick_actions");
var imageShelf = new BlockRule(SettingsEnum.HIDE_IMAGE_SHELF, "image_shelf");
var graySeparator = new BlockRule(SettingsEnum.HIDE_GRAY_SEPARATOR,
"cell_divider" // layout residue (gray line above the buttoned ad),
);
var buttonedAd = new BlockRule(SettingsEnum.ADREMOVER_BUTTONED_REMOVAL,
var paidContent = new BlockRule(SettingsEnum.HIDE_PAID_CONTENT, "paid_content_overlay");
var latestPosts = new BlockRule(SettingsEnum.HIDE_HIDE_LATEST_POSTS, "post_shelf");
var selfSponsor = new BlockRule(SettingsEnum.HIDE_SELF_SPONSOR, "cta_shelf_card");
var buttonedAd = new BlockRule(SettingsEnum.HIDE_BUTTONED_ADS,
"_buttoned_layout",
"full_width_square_image_layout",
"_ad_with",
@ -53,7 +53,7 @@ public final class GeneralAdsPatch extends Filter {
"landscape_image_wide_button_layout"
);
var generalAds = new BlockRule(
SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL,
SettingsEnum.HIDE_GENERAL_ADS,
"ads_video_with_context",
"banner_text_icon",
"square_image_layout",
@ -69,7 +69,7 @@ public final class GeneralAdsPatch extends Filter {
"brand_video_shelf"
);
var movieAds = new BlockRule(
SettingsEnum.ADREMOVER_MOVIE_REMOVAL,
SettingsEnum.HIDE_MOVIES_SECTION,
"browsy_bar",
"compact_movie",
"horizontal_movie_shelf",
@ -106,10 +106,10 @@ public final class GeneralAdsPatch extends Filter {
channelMemberShelf
);
var carouselAd = new BlockRule(SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL,
var carouselAd = new BlockRule(SettingsEnum.HIDE_GENERAL_ADS,
"carousel_ad"
);
var shorts = new BlockRule(SettingsEnum.ADREMOVER_SHORTS_REMOVAL,
var shorts = new BlockRule(SettingsEnum.HIDE_SHORTS,
"shorts_shelf",
"inline_shorts",
"shorts_grid"
@ -174,7 +174,7 @@ public final class GeneralAdsPatch extends Filter {
* @param view The view, which shows ads.
*/
public static void hideAdAttributionView(View view) {
hideView(SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL, view);
hideView(SettingsEnum.HIDE_GENERAL_ADS, view);
}
/**
@ -183,7 +183,7 @@ public final class GeneralAdsPatch extends Filter {
* @param view The view, which shows reels.
*/
public static void hideReelView(View view) {
hideView(SettingsEnum.ADREMOVER_SHORTS_REMOVAL, view);
hideView(SettingsEnum.HIDE_SHORTS, view);
}
}

View File

@ -21,7 +21,7 @@ public class HDRAutoBrightnessPatch {
*/
public static float getHDRBrightness(float original) {
// do nothing if disabled
if (!SettingsEnum.USE_HDR_AUTO_BRIGHTNESS.getBoolean()) {
if (!SettingsEnum.HDR_AUTO_BRIGHTNESS.getBoolean()) {
return original;
}

View File

@ -13,7 +13,7 @@ public class OpenLinksExternallyPatch {
* @return The new, default service to open links with or the original service.
*/
public static String enableExternalBrowser(String original) {
if (SettingsEnum.ENABLE_EXTERNAL_BROWSER.getBoolean()) original = "";
if (SettingsEnum.EXTERNAL_BROWSER.getBoolean()) original = "";
return original;
}
}

View File

@ -6,7 +6,7 @@ public class SeekbarTappingPatch {
//Used by app.revanced.patches.youtube.interaction.seekbar.patch.EnableSeekbarTappingPatch
public static boolean isTapSeekingEnabled() {
return SettingsEnum.TAP_SEEKING_ENABLED.getBoolean();
return SettingsEnum.TAP_SEEKING.getBoolean();
}
}

View File

@ -60,7 +60,7 @@ public class SpoofSignatureVerificationPatch {
*/
public static String overrideProtobufParameter(String originalValue) {
try {
if (!SettingsEnum.SIGNATURE_SPOOFING.getBoolean()) {
if (!SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean()) {
return originalValue;
}
@ -101,11 +101,11 @@ public class SpoofSignatureVerificationPatch {
}
LogHelper.printDebug(() -> "YouTube HTTP status code: " + responseCode);
if (SettingsEnum.SIGNATURE_SPOOFING.getBoolean()) {
if (SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean()) {
return; // already enabled
}
SettingsEnum.SIGNATURE_SPOOFING.saveValue(true);
SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.saveValue(true);
ReVancedUtils.showToastLong("Spoofing app signature to prevent playback issues");
// it would be great if the video could be forcefully reloaded, but currently there is no code to do this
@ -130,7 +130,7 @@ public class SpoofSignatureVerificationPatch {
* @param sd function is not entirely clear
*/
public static int[] getSubtitleWindowSettingsOverride(int ap, int ah, int av, boolean vs, boolean sd) {
final boolean signatureSpoofing = SettingsEnum.SIGNATURE_SPOOFING.getBoolean();
final boolean signatureSpoofing = SettingsEnum.SPOOF_SIGNATURE_VERIFICATION.getBoolean();
if (SettingsEnum.DEBUG.getBoolean()) {
if (ap != lastAp || ah != lastAh || av != lastAv || vs != lastVs || sd != lastSd) {
LogHelper.printDebug(() -> "video: " + VideoInformation.getVideoId() + " spoof: " + signatureSpoofing

View File

@ -7,8 +7,7 @@ public class VideoAdsPatch {
// Used by app.revanced.patches.youtube.ad.general.video.patch.VideoAdsPatch
// depends on Whitelist patch (still needs to be written)
public static boolean shouldShowAds() {
return !SettingsEnum.VIDEO_ADS_REMOVAL.getBoolean(); // TODO && Whitelist.shouldShowAds();
return !SettingsEnum.HIDE_VIDEO_ADS.getBoolean(); // TODO && Whitelist.shouldShowAds();
}
}

View File

@ -10,7 +10,7 @@ import app.revanced.integrations.utils.LogHelper;
public class OldQualityLayoutPatch {
public static void showOldQualityMenu(ListView listView)
{
if (!SettingsEnum.OLD_STYLE_VIDEO_QUALITY_PLAYER_SETTINGS.getBoolean()) return;
if (!SettingsEnum.SHOW_OLD_VIDEO_MENU.getBoolean()) return;
listView.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
@Override

View File

@ -22,7 +22,7 @@ public class RememberVideoQualityPatch {
/**
* If the user selected a new quality from the flyout menu,
* and {@link SettingsEnum#VIDEO_QUALITY_REMEMBER_LAST_SELECTED} is enabled.
* and {@link SettingsEnum#REMEMBER_VIDEO_QUALITY_LAST_SELECTED} is enabled.
*/
private static boolean userChangedDefaultQuality;
@ -142,7 +142,7 @@ public class RememberVideoQualityPatch {
* Injection point.
*/
public static void userChangedQuality(int selectedQuality) {
if (!SettingsEnum.VIDEO_QUALITY_REMEMBER_LAST_SELECTED.getBoolean()) return;
if (!SettingsEnum.REMEMBER_VIDEO_QUALITY_LAST_SELECTED.getBoolean()) return;
userSelectedQualityIndex = selectedQuality;
userChangedDefaultQuality = true;

View File

@ -42,12 +42,12 @@ public class CustomVideoSpeedPatch {
private static void resetCustomSpeeds(@NonNull String toastMessage) {
ReVancedUtils.showToastLong(toastMessage);
SettingsEnum.PLAYBACK_SPEED_AVAILABLE.saveValue(SettingsEnum.PLAYBACK_SPEED_AVAILABLE.defaultValue);
SettingsEnum.CUSTOM_PLAYBACK_SPEEDS.saveValue(SettingsEnum.CUSTOM_PLAYBACK_SPEEDS.defaultValue);
}
private static void loadSpeeds() {
try {
String[] speedStrings = SettingsEnum.PLAYBACK_SPEED_AVAILABLE.getString().split("\\s+");
String[] speedStrings = SettingsEnum.CUSTOM_PLAYBACK_SPEEDS.getString().split("\\s+");
Arrays.sort(speedStrings);
if (speedStrings.length == 0) {
throw new IllegalArgumentException();

View File

@ -22,7 +22,7 @@ public final class RememberPlaybackSpeedPatch {
* @param playbackSpeed The playback speed the user selected
*/
public static void userSelectedPlaybackSpeed(float playbackSpeed) {
if (SettingsEnum.PLAYBACK_SPEED_REMEMBER_LAST_SELECTED.getBoolean()) {
if (SettingsEnum.REMEMBER_PLAYBACK_SPEED_LAST_SELECTED.getBoolean()) {
SettingsEnum.PLAYBACK_SPEED_DEFAULT.saveValue(playbackSpeed);
ReVancedUtils.showToastLong("Changed default speed to: " + playbackSpeed + "x");
}

View File

@ -494,7 +494,7 @@ public class ReturnYouTubeDislike {
}
SpannableStringBuilder builder = new SpannableStringBuilder();
final boolean compactLayout = SettingsEnum.RYD_USE_COMPACT_LAYOUT.getBoolean();
final boolean compactLayout = SettingsEnum.RYD_COMPACT_LAYOUT.getBoolean();
final int separatorColor = ThemeHelper.isDarkTheme()
? 0x29AAAAAA // transparent dark gray
: 0xFFD9D9D9; // light gray
@ -578,7 +578,7 @@ public class ReturnYouTubeDislike {
private static SpannableString newSpannableWithDislikes(@NonNull Spanned sourceStyling, @NonNull RYDVoteData voteData) {
return newSpanUsingStylingOfAnotherSpan(sourceStyling,
SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.getBoolean()
SettingsEnum.RYD_DISLIKE_PERCENTAGE.getBoolean()
? formatDislikePercentage(voteData.getDislikePercentage())
: formatDislikeCount(voteData.getDislikeCount()));
}

View File

@ -1,70 +1,90 @@
package app.revanced.integrations.settings;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static app.revanced.integrations.settings.SettingsEnum.ReturnType.BOOLEAN;
import static app.revanced.integrations.settings.SettingsEnum.ReturnType.FLOAT;
import static app.revanced.integrations.settings.SettingsEnum.ReturnType.INTEGER;
import static app.revanced.integrations.settings.SettingsEnum.ReturnType.LONG;
import static app.revanced.integrations.settings.SettingsEnum.ReturnType.STRING;
import static app.revanced.integrations.settings.SharedPrefCategory.RETURN_YOUTUBE_DISLIKE;
import static app.revanced.integrations.settings.SharedPrefCategory.SPONSOR_BLOCK;
import static app.revanced.integrations.utils.StringRef.str;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.integrations.utils.StringRef;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static app.revanced.integrations.settings.SettingsEnum.ReturnType.*;
import static app.revanced.integrations.settings.SharedPrefCategory.RETURN_YOUTUBE_DISLIKE;
import static app.revanced.integrations.settings.SharedPrefCategory.SPONSOR_BLOCK;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import app.revanced.integrations.sponsorblock.SponsorBlockSettings;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
import app.revanced.integrations.utils.StringRef;
public enum SettingsEnum {
//Download Settings
DOWNLOADS_BUTTON_SHOWN("revanced_downloads_enabled", BOOLEAN, TRUE),
DOWNLOADS_PACKAGE_NAME("revanced_downloads_package_name", STRING, "org.schabi.newpipe" /* NewPipe */, parents(DOWNLOADS_BUTTON_SHOWN)),
// External downloader
EXTERNAL_DOWNLOADER("revanced_external_downloader", BOOLEAN, TRUE),
EXTERNAL_DOWNLOADER_PACKAGE_NAME("revanced_external_downloader_name", STRING,
"org.schabi.newpipe" /* NewPipe */, parents(EXTERNAL_DOWNLOADER)),
// Copy video URL settings
COPY_VIDEO_URL_BUTTON_SHOWN("revanced_copy_video_url_enabled", BOOLEAN, TRUE),
COPY_VIDEO_URL_TIMESTAMP_BUTTON_SHOWN("revanced_copy_video_url_timestamp_enabled", BOOLEAN, TRUE),
// Copy video URL
COPY_VIDEO_URL("revanced_copy_video_url", BOOLEAN, TRUE),
COPY_VIDEO_URL_TIMESTAMP("revanced_copy_video_url_timestamp", BOOLEAN, TRUE),
// Video settings
OLD_STYLE_VIDEO_QUALITY_PLAYER_SETTINGS("revanced_use_old_style_quality_settings", BOOLEAN, TRUE),
VIDEO_QUALITY_REMEMBER_LAST_SELECTED("revanced_remember_video_quality_last_selected", BOOLEAN, TRUE),
VIDEO_QUALITY_DEFAULT_WIFI("revanced_default_video_quality_wifi", INTEGER, -2),
VIDEO_QUALITY_DEFAULT_MOBILE("revanced_default_video_quality_mobile", INTEGER, -2),
PLAYBACK_SPEED_REMEMBER_LAST_SELECTED("revanced_remember_playback_speed_last_selected", BOOLEAN, TRUE),
PLAYBACK_SPEED_DEFAULT("revanced_default_playback_speed", FLOAT, 1.0f),
PLAYBACK_SPEED_AVAILABLE("revanced_custom_video_speeds", STRING,
// Video
HDR_AUTO_BRIGHTNESS("revanced_hdr_auto_brightness", BOOLEAN, TRUE),
SHOW_OLD_VIDEO_MENU("revanced_show_old_video_menu", BOOLEAN, TRUE),
REMEMBER_VIDEO_QUALITY_LAST_SELECTED("revanced_remember_video_quality_last_selected", BOOLEAN, TRUE),
VIDEO_QUALITY_DEFAULT_WIFI("revanced_video_quality_default_wifi", INTEGER, -2),
VIDEO_QUALITY_DEFAULT_MOBILE("revanced_video_quality_default_mobile", INTEGER, -2),
REMEMBER_PLAYBACK_SPEED_LAST_SELECTED("revanced_remember_playback_speed_last_selected", BOOLEAN, TRUE),
PLAYBACK_SPEED_DEFAULT("revanced_playback_speed_default", FLOAT, 1.0f),
CUSTOM_PLAYBACK_SPEEDS("revanced_custom_playback_speeds", STRING,
"0.25\n0.5\n0.75\n0.9\n0.95\n1.0\n1.05\n1.1\n1.25\n1.5\n1.75\n2.0\n3.0\n4.0\n5.0", true),
// TODO: Unused currently
// Whitelist settings
//ENABLE_WHITELIST("revanced_whitelist_ads_enabled", BOOLEAN, FALSE),
// Whitelist
//WHITELIST("revanced_whitelist_ads", BOOLEAN, FALSE), // TODO: Unused currently
// Ad settings
ADREMOVER_BUTTONED_REMOVAL("revanced_adremover_buttoned", BOOLEAN, TRUE),
ADREMOVER_CHANNEL_BAR("revanced_hide_channel_bar", BOOLEAN, FALSE),
ADREMOVER_CHANNEL_MEMBER_SHELF_REMOVAL("revanced_adremover_channel_member_shelf_removal", BOOLEAN, TRUE),
ADREMOVER_CHAPTER_TEASER_REMOVAL("revanced_adremover_chapter_teaser", BOOLEAN, TRUE),
ADREMOVER_COMMUNITY_GUIDELINES_REMOVAL("revanced_adremover_community_guidelines", BOOLEAN, TRUE),
ADREMOVER_COMMUNITY_POSTS_REMOVAL("revanced_adremover_community_posts_removal", BOOLEAN, FALSE),
ADREMOVER_COMPACT_BANNER_REMOVAL("revanced_adremover_compact_banner_removal", BOOLEAN, TRUE),
ADREMOVER_CUSTOM_ENABLED("revanced_adremover_custom_enabled", BOOLEAN, FALSE),
ADREMOVER_CUSTOM_REMOVAL("revanced_adremover_custom_strings", STRING, "", true, parents(ADREMOVER_CUSTOM_ENABLED)),
ADREMOVER_EMERGENCY_BOX_REMOVAL("revanced_adremover_emergency_box_removal", BOOLEAN, TRUE),
ADREMOVER_FEED_SURVEY_REMOVAL("revanced_adremover_feed_survey", BOOLEAN, TRUE),
ADREMOVER_GENERAL_ADS_REMOVAL("revanced_adremover_ad_removal", BOOLEAN, TRUE),
ADREMOVER_GRAY_SEPARATOR("revanced_adremover_separator", BOOLEAN, TRUE),
ADREMOVER_HIDE_CHANNEL_GUIDELINES("revanced_adremover_hide_channel_guidelines", BOOLEAN, TRUE),
ADREMOVER_HIDE_LATEST_POSTS("revanced_adremover_hide_latest_posts", BOOLEAN, TRUE),
ADREMOVER_IMAGE_SHELF("revanced_hide_image_shelf", BOOLEAN, TRUE),
ADREMOVER_INFO_PANEL_REMOVAL("revanced_adremover_info_panel", BOOLEAN, TRUE),
ADREMOVER_MEDICAL_PANEL_REMOVAL("revanced_adremover_medical_panel", BOOLEAN, TRUE),
ADREMOVER_MERCHANDISE_REMOVAL("revanced_adremover_merchandise", BOOLEAN, TRUE),
ADREMOVER_MOVIE_REMOVAL("revanced_adremover_movie", BOOLEAN, TRUE),
ADREMOVER_PAID_CONTENT_REMOVAL("revanced_adremover_paid_content", BOOLEAN, TRUE),
ADREMOVER_QUICK_ACTIONS("revanced_hide_quick_actions", BOOLEAN, FALSE),
ADREMOVER_RELATED_VIDEOS("revanced_hide_related_videos", BOOLEAN, FALSE),
ADREMOVER_SELF_SPONSOR_REMOVAL("revanced_adremover_self_sponsor", BOOLEAN, TRUE),
ADREMOVER_SHORTS_REMOVAL("revanced_adremover_shorts", BOOLEAN, TRUE, true),
ADREMOVER_SUBSCRIBERS_COMMUNITY_GUIDELINES_REMOVAL("revanced_adremover_subscribers_community_guidelines_removal", BOOLEAN, TRUE),
ADREMOVER_VIEW_PRODUCTS("revanced_adremover_view_products", BOOLEAN, TRUE),
ADREMOVER_WEB_SEARCH_RESULTS("revanced_adremover_web_search_result", BOOLEAN, TRUE),
VIDEO_ADS_REMOVAL("revanced_video_ads_removal", BOOLEAN, TRUE, true),
// Ads
HIDE_BUTTONED_ADS("revanced_hide_buttoned_ads", BOOLEAN, TRUE),
HIDE_GENERAL_ADS("revanced_hide_general_ads", BOOLEAN, TRUE),
HIDE_HIDE_LATEST_POSTS("revanced_hide_latest_posts_ads", BOOLEAN, TRUE),
HIDE_PAID_CONTENT("revanced_hide_paid_content_ads", BOOLEAN, TRUE),
HIDE_SELF_SPONSOR("revanced_hide_self_sponsor_ads", BOOLEAN, TRUE),
HIDE_VIDEO_ADS("revanced_hide_video_ads", BOOLEAN, TRUE, true),
CUSTOM_FILTER("revanced_custom_filter", BOOLEAN, FALSE),
CUSTOM_FILTER_STRINGS("revanced_custom_filter_strings", STRING, "", true, parents(CUSTOM_FILTER)),
// Layout
HIDE_CHANNEL_BAR("revanced_hide_channel_bar", BOOLEAN, FALSE),
HIDE_CHANNEL_MEMBER_SHELF("revanced_hide_channel_member_shelf", BOOLEAN, TRUE),
HIDE_CHAPTER_TEASER("revanced_hide_chapter_teaser", BOOLEAN, TRUE),
HIDE_COMMUNITY_GUIDELINES("revanced_hide_community_guidelines", BOOLEAN, TRUE),
HIDE_COMMUNITY_POSTS("revanced_hide_community_posts", BOOLEAN, FALSE),
HIDE_COMPACT_BANNER("revanced_hide_compact_banner", BOOLEAN, TRUE),
HIDE_EMERGENCY_BOX("revanced_hide_emergency_box", BOOLEAN, TRUE),
HIDE_FEED_SURVEY("revanced_hide_feed_survey", BOOLEAN, TRUE),
HIDE_GRAY_SEPARATOR("revanced_hide_gray_separator", BOOLEAN, TRUE),
HIDE_HIDE_CHANNEL_GUIDELINES("revanced_hide_channel_guidelines", BOOLEAN, TRUE),
HIDE_IMAGE_SHELF("revanced_hide_image_shelf", BOOLEAN, TRUE),
HIDE_HIDE_INFO_PANELS("revanced_hide_info_panels", BOOLEAN, TRUE),
HIDE_MEDICAL_PANELS("revanced_hide_medical_panels", BOOLEAN, TRUE),
HIDE_MERCHANDISE_BANNERS("revanced_hide_merchandise_banners", BOOLEAN, TRUE),
HIDE_MOVIES_SECTION("revanced_hide_movies_section", BOOLEAN, TRUE),
HIDE_SUBSCRIBERS_COMMUNITY_GUIDELINES("revanced_hide_subscribers_community_guidelines", BOOLEAN, TRUE),
HIDE_PRODUCTS_BANNER("revanced_hide_products_banner", BOOLEAN, TRUE),
HIDE_WEB_SEARCH_RESULTS("revanced_hide_web_search_results", BOOLEAN, TRUE),
HIDE_SHORTS("revanced_hide_shorts", BOOLEAN, TRUE, true),
HIDE_QUICK_ACTIONS("revanced_hide_quick_actions", BOOLEAN, FALSE),
HIDE_RELATED_VIDEOS("revanced_hide_related_videos", BOOLEAN, FALSE),
// Action buttons
HIDE_LIKE_DISLIKE_BUTTON("revanced_hide_like_dislike_button", BOOLEAN, FALSE),
@ -73,8 +93,8 @@ public enum SettingsEnum {
HIDE_CLIP_BUTTON("revanced_hide_clip_button", BOOLEAN, FALSE, "revanced_hide_clip_button_user_dialog_message"),
HIDE_ACTION_BUTTONS("revanced_hide_action_buttons", BOOLEAN, FALSE),
// Layout settings
DISABLE_STARTUP_SHORTS_PLAYER("revanced_startup_shorts_player_enabled", BOOLEAN, FALSE),
// Layout
DISABLE_RESUMING_SHORTS_PLAYER("revanced_disable_resuming_shorts_player", BOOLEAN, FALSE),
HIDE_ALBUM_CARDS("revanced_hide_album_cards", BOOLEAN, FALSE, true),
HIDE_ARTIST_CARDS("revanced_hide_artist_cards", BOOLEAN, FALSE),
HIDE_AUDIO_TRACK_BUTTON("revanced_hide_audio_track_button", BOOLEAN, FALSE),
@ -84,14 +104,13 @@ public enum SettingsEnum {
HIDE_CAST_BUTTON("revanced_hide_cast_button", BOOLEAN, TRUE, true),
HIDE_COMMENTS_SECTION("revanced_hide_comments_section", BOOLEAN, FALSE, true),
HIDE_CREATE_BUTTON("revanced_hide_create_button", BOOLEAN, TRUE, true),
SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON("revanced_switch_create_with_notifications_button", BOOLEAN, TRUE, true),
HIDE_CROWDFUNDING_BOX("revanced_hide_crowdfunding_box", BOOLEAN, FALSE, true),
HIDE_EMAIL_ADDRESS("revanced_hide_email_address", BOOLEAN, FALSE),
HIDE_ENDSCREEN_CARDS("revanced_hide_endscreen_cards", BOOLEAN, TRUE),
HIDE_FLOATING_MICROPHONE_BUTTON("revanced_hide_floating_microphone_button", BOOLEAN, TRUE, true),
HIDE_FULLSCREEN_PANELS("revanced_hide_fullscreen_panels", BOOLEAN, TRUE),
HIDE_GET_PREMIUM("revanced_hide_get_premium", BOOLEAN, TRUE),
HIDE_INFO_CARDS("revanced_hide_infocards", BOOLEAN, TRUE),
HIDE_INFO_CARDS("revanced_hide_info_cards", BOOLEAN, TRUE),
HIDE_LOAD_MORE_BUTTON("revanced_hide_load_more_button", BOOLEAN, TRUE, true),
HIDE_PLAYER_BUTTONS("revanced_hide_player_buttons", BOOLEAN, FALSE),
HIDE_PLAYER_OVERLAY("revanced_hide_player_overlay", BOOLEAN, FALSE, true),
@ -104,7 +123,8 @@ public enum SettingsEnum {
HIDE_TIMESTAMP("revanced_hide_timestamp", BOOLEAN, FALSE),
HIDE_VIDEO_WATERMARK("revanced_hide_video_watermark", BOOLEAN, TRUE),
HIDE_WATCH_IN_VR("revanced_hide_watch_in_vr", BOOLEAN, FALSE, true),
PLAYER_POPUP_PANELS("revanced_player_popup_panels_enabled", BOOLEAN, FALSE),
PLAYER_POPUP_PANELS("revanced_hide_player_popup_panels", BOOLEAN, FALSE),
SWITCH_CREATE_WITH_NOTIFICATIONS_BUTTON("revanced_switch_create_with_notifications_button", BOOLEAN, TRUE, true),
SPOOF_APP_VERSION("revanced_spoof_app_version", BOOLEAN, FALSE, true, "revanced_spoof_app_version_user_dialog_message"),
SPOOF_APP_VERSION_TARGET("revanced_spoof_app_version_target", STRING, "17.30.35", true, parents(SPOOF_APP_VERSION)),
USE_TABLET_MINIPLAYER("revanced_tablet_miniplayer", BOOLEAN, FALSE, true),
@ -114,61 +134,212 @@ public enum SettingsEnum {
HIDE_FILTER_BAR_FEED_IN_SEARCH("revanced_hide_filter_bar_feed_in_search", BOOLEAN, FALSE, true),
HIDE_FILTER_BAR_FEED_IN_RELATED_VIDEOS("revanced_hide_filter_bar_feed_in_related_videos", BOOLEAN, FALSE, true),
// Misc. Settings
SIGNATURE_SPOOFING("revanced_spoof_signature_verification", BOOLEAN, TRUE, "revanced_spoof_signature_verification_user_dialog_message"),
CAPTIONS_ENABLED("revanced_autocaptions_enabled", BOOLEAN, FALSE),
// Misc
AUTO_CAPTIONS("revanced_auto_captions", BOOLEAN, FALSE),
DISABLE_ZOOM_HAPTICS("revanced_disable_zoom_haptics", BOOLEAN, TRUE),
ENABLE_EXTERNAL_BROWSER("revanced_enable_external_browser", BOOLEAN, TRUE, true),
PREFERRED_AUTO_REPEAT("revanced_pref_auto_repeat", BOOLEAN, FALSE),
TAP_SEEKING_ENABLED("revanced_enable_tap_seeking", BOOLEAN, TRUE),
USE_HDR_AUTO_BRIGHTNESS("revanced_pref_hdr_autobrightness", BOOLEAN, TRUE),
EXTERNAL_BROWSER("revanced_external_browser", BOOLEAN, TRUE, true),
AUTO_REPEAT("revanced_auto_repeat", BOOLEAN, FALSE),
TAP_SEEKING("revanced_tap_seeking", BOOLEAN, TRUE),
SPOOF_SIGNATURE_VERIFICATION("revanced_spoof_signature_verification", BOOLEAN, TRUE, "revanced_spoof_signature_verification_user_dialog_message"),
// Swipe controls
ENABLE_SWIPE_BRIGHTNESS("revanced_enable_swipe_brightness", BOOLEAN, TRUE),
ENABLE_SWIPE_VOLUME("revanced_enable_swipe_volume", BOOLEAN, TRUE),
ENABLE_PRESS_TO_SWIPE("revanced_enable_press_to_swipe", BOOLEAN, FALSE, true,
parents(ENABLE_SWIPE_BRIGHTNESS, ENABLE_SWIPE_VOLUME)),
ENABLE_SWIPE_HAPTIC_FEEDBACK("revanced_enable_swipe_haptic_feedback", BOOLEAN, TRUE,
parents(ENABLE_SWIPE_BRIGHTNESS, ENABLE_SWIPE_VOLUME)),
SWIPE_MAGNITUDE_THRESHOLD("revanced_swipe_magnitude_threshold", FLOAT, 30f, // edit: why is this a float and not an Integer?
parents(ENABLE_SWIPE_BRIGHTNESS, ENABLE_SWIPE_VOLUME)),
SWIPE_BRIGHTNESS("revanced_swipe_brightness", BOOLEAN, TRUE),
SWIPE_VOLUME("revanced_swipe_volume", BOOLEAN, TRUE),
SWIPE_PRESS_TO_ENGAGE("revanced_swipe_press_to_engage", BOOLEAN, FALSE, true,
parents(SWIPE_BRIGHTNESS, SWIPE_VOLUME)),
SWIPE_HAPTIC_FEEDBACK("revanced_swipe_haptic_feedback", BOOLEAN, TRUE,
parents(SWIPE_BRIGHTNESS, SWIPE_VOLUME)),
SWIPE_MAGNITUDE_THRESHOLD("revanced_swipe_threshold", INTEGER, 30,
parents(SWIPE_BRIGHTNESS, SWIPE_VOLUME)),
SWIPE_OVERLAY_BACKGROUND_ALPHA("revanced_swipe_overlay_background_alpha", INTEGER, 127,
parents(ENABLE_SWIPE_BRIGHTNESS, ENABLE_SWIPE_VOLUME)),
SWIPE_OVERLAY_TEXT_SIZE("revanced_swipe_overlay_text_size", FLOAT, 22f, // edit: why is this a float and not an Integer?
parents(ENABLE_SWIPE_BRIGHTNESS, ENABLE_SWIPE_VOLUME)),
parents(SWIPE_BRIGHTNESS, SWIPE_VOLUME)),
SWIPE_OVERLAY_TEXT_SIZE("revanced_swipe_text_overlay_size", INTEGER, 22,
parents(SWIPE_BRIGHTNESS, SWIPE_VOLUME)),
SWIPE_OVERLAY_TIMEOUT("revanced_swipe_overlay_timeout", LONG, 500L,
parents(ENABLE_SWIPE_BRIGHTNESS, ENABLE_SWIPE_VOLUME)),
parents(SWIPE_BRIGHTNESS, SWIPE_VOLUME)),
// Debug settings
DEBUG("revanced_debug_enabled", BOOLEAN, FALSE),
DEBUG_STACKTRACE("revanced_debug_stacktrace_enabled", BOOLEAN, FALSE, parents(DEBUG)),
DEBUG_SHOW_TOAST_ON_ERROR("revanced_debug_toast_on_error_enabled", BOOLEAN, TRUE, "revanced_debug_toast_on_error_user_dialog_message"),
// Debugging
DEBUG("revanced_debug", BOOLEAN, FALSE),
DEBUG_STACKTRACE("revanced_debug_stacktrace", BOOLEAN, FALSE, parents(DEBUG)),
DEBUG_TOAST_ON_ERROR("revanced_debug_toast_on_error", BOOLEAN, TRUE, "revanced_debug_toast_on_error_user_dialog_message"),
// ReturnYoutubeDislike settings
// ReturnYoutubeDislike
RYD_ENABLED("ryd_enabled", BOOLEAN, TRUE, RETURN_YOUTUBE_DISLIKE),
RYD_USER_ID("ryd_userId", STRING, "", RETURN_YOUTUBE_DISLIKE),
RYD_SHOW_DISLIKE_PERCENTAGE("ryd_show_dislike_percentage", BOOLEAN, FALSE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)),
RYD_USER_ID("ryd_user_id", STRING, "", RETURN_YOUTUBE_DISLIKE),
RYD_SHORTS("ryd_shorts", BOOLEAN, TRUE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)),
RYD_USE_COMPACT_LAYOUT("ryd_use_compact_layout", BOOLEAN, FALSE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)),
RYD_DISLIKE_PERCENTAGE("ryd_dislike_percentage", BOOLEAN, FALSE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)),
RYD_COMPACT_LAYOUT("ryd_compact_layout", BOOLEAN, FALSE, RETURN_YOUTUBE_DISLIKE, parents(RYD_ENABLED)),
// SponsorBlock settings
SB_ENABLED("sb-enabled", BOOLEAN, TRUE, SPONSOR_BLOCK),
SB_VOTING_ENABLED("sb-voting-enabled", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_CREATE_NEW_SEGMENT_ENABLED("sb-new-segment-enabled", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_USE_COMPACT_SKIP_BUTTON("sb-use-compact-skip-button", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_AUTO_HIDE_SKIP_BUTTON("sb-auto-hide-skip-segment-button", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_SHOW_TOAST_ON_SKIP("show-toast", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_TRACK_SKIP_COUNT("count-skips", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_UUID("uuid", STRING, "", SPONSOR_BLOCK),
SB_ADJUST_NEW_SEGMENT_STEP("new-segment-step-accuracy", INTEGER, 150, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_MIN_DURATION("sb-min-duration", FLOAT, 0F, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_SEEN_GUIDELINES("sb-seen-gl", BOOLEAN, FALSE, SPONSOR_BLOCK),
SB_SKIPPED_SEGMENTS_NUMBER_SKIPPED("sb-skipped-segments", INTEGER, 0, SPONSOR_BLOCK),
SB_SKIPPED_SEGMENTS_TIME_SAVED("sb-skipped-segments-time", LONG, 0L, SPONSOR_BLOCK),
SB_SHOW_TIME_WITHOUT_SEGMENTS("sb-length-without-segments", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_IS_VIP("sb-is-vip", BOOLEAN, FALSE, SPONSOR_BLOCK),
SB_LAST_VIP_CHECK("sb-last-vip-check", LONG, 0L, SPONSOR_BLOCK),
SB_API_URL("sb-api-host-url", STRING, "https://sponsor.ajay.app", SPONSOR_BLOCK);
// SponsorBlock
SB_ENABLED("sb_enabled", BOOLEAN, TRUE, SPONSOR_BLOCK),
SB_PRIVATE_USER_ID("sb_private_user_id_Do_Not_Share", STRING, "", SPONSOR_BLOCK), /** Do not use directly, instead use {@link SponsorBlockSettings} */
DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING("uuid", STRING, "", SPONSOR_BLOCK), // Delete sometime in 2024
SB_CREATE_NEW_SEGMENT_STEP("sb_create_new_segment_step", INTEGER, 150, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_VOTING_BUTTON("sb_voting_button", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_CREATE_NEW_SEGMENT("sb_create_new_segment", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_COMPACT_SKIP_BUTTON("sb_compact_skip_button", BOOLEAN, FALSE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_AUTO_HIDE_SKIP_BUTTON("sb_auto_hide_skip_button", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_TOAST_ON_SKIP("sb_toast_on_skip", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_TRACK_SKIP_COUNT("sb_track_skip_count", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_SEGMENT_MIN_DURATION("sb_min_segment_duration", FLOAT, 0F, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_VIDEO_LENGTH_WITHOUT_SEGMENTS("sb_video_length_without_segments", BOOLEAN, TRUE, SPONSOR_BLOCK, parents(SB_ENABLED)),
SB_API_URL("sb_api_url", STRING, "https://sponsor.ajay.app", SPONSOR_BLOCK),
SB_USER_IS_VIP("sb_user_is_vip", BOOLEAN, FALSE, SPONSOR_BLOCK),
// SB settings not exported
SB_LAST_VIP_CHECK("sb_last_vip_check", LONG, 0L, SPONSOR_BLOCK),
SB_HIDE_EXPORT_WARNING("sb_hide_export_warning", BOOLEAN, FALSE, SPONSOR_BLOCK),
SB_SEEN_GUIDELINES("sb_seen_guidelines", BOOLEAN, FALSE, SPONSOR_BLOCK),
SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS("sb_local_time_saved_number_segments", INTEGER, 0, SPONSOR_BLOCK),
SB_LOCAL_TIME_SAVED_MILLISECONDS("sb_local_time_saved_milliseconds", LONG, 0L, SPONSOR_BLOCK),
//
// TODO: eventually, delete these
//
@Deprecated
DEPRECATED_ADREMOVER_BUTTONED_REMOVAL("revanced_adremover_buttoned", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_ADREMOVER_GENERAL_ADS_REMOVAL("revanced_adremover_ad_removal", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_ADREMOVER_PAID_CONTENT("revanced_adremover_paid_content", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_ADREMOVER_HIDE_LATEST_POSTS("revanced_adremover_hide_latest_posts", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_ADREMOVER_SELF_SPONSOR("revanced_adremover_self_sponsor", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_ADREMOVER_CUSTOM_ENABLED("revanced_adremover_custom_enabled", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_ADREMOVER_CUSTOM_REMOVAL("revanced_adremover_custom_strings", STRING, "", true),
@Deprecated
DEPRECATED_REMOVE_VIDEO_ADS("revanced_video_ads_removal", BOOLEAN, TRUE, true),
@Deprecated
DEPRECATED_HIDE_CHANNEL_MEMBER_SHELF("revanced_adremover_channel_member_shelf_removal", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_CHAPTER_TEASER("revanced_adremover_chapter_teaser", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_COMMUNITY_GUIDELINES("revanced_adremover_community_guidelines", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_COMMUNITY_POSTS("revanced_adremover_community_posts_removal", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_HIDE_COMPACT_BANNER("revanced_adremover_compact_banner_removal", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_EMERGENCY_BOX("revanced_adremover_emergency_box_removal", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_FEED_SURVEY_REMOVAL("revanced_adremover_feed_survey", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_GRAY_SEPARATOR("revanced_adremover_separator", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_HIDE_CHANNEL_GUIDELINES("revanced_adremover_hide_channel_guidelines", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_INFO_PANEL_REMOVAL("revanced_adremover_info_panel", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_MEDICAL_PANEL_REMOVAL("revanced_adremover_medical_panel", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_MERCHANDISE_REMOVAL("revanced_adremover_merchandise", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_MOVIE_REMOVAL("revanced_adremover_movie", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_SUBSCRIBERS_COMMUNITY_GUIDELINES_REMOVAL("revanced_adremover_subscribers_community_guidelines_removal", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_VIEW_PRODUCTS("revanced_adremover_view_products", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_WEB_SEARCH_RESULTS("revanced_adremover_web_search_result", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HIDE_SHORTS("revanced_adremover_shorts", BOOLEAN, TRUE, true),
@Deprecated
DEPRECATED_HIDE_INFO_CARDS("revanced_hide_infocards", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_DISABLE_RESUMING_SHORTS_PLAYER("revanced_disable_startup_shorts_player", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_ETERNAL_DOWNLOADER("revanced_downloads_enabled", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_EXTERNAL_DOWNLOADER_PACKAGE_NAME("revanced_downloads_package_name", STRING, "org.schabi.newpipe"),
@Deprecated
DEPRECATED_SHOW_OLD_VIDEO_MENU("revanced_use_old_style_quality_settings", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_VIDEO_QUALITY_DEFAULT_WIFI("revanced_default_video_quality_wifi", INTEGER, -2),
@Deprecated
DEPRECATED_VIDEO_QUALITY_DEFAULT_MOBILE("revanced_default_video_quality_mobile", INTEGER, -2),
@Deprecated
DEPRECATED_PLAYBACK_SPEED_DEFAULT("revanced_default_playback_speed", FLOAT, 1.0f),
@Deprecated
DEPRECATED_COPY_VIDEO_URL("revanced_copy_video_url_enabled", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_COPY_VIDEO_URL_TIMESTAMP("revanced_copy_video_url_timestamp_enabled", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_AUTO_CAPTIONS("revanced_autocaptions_enabled", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_PLAYER_POPUP_PANELS("revanced_player_popup_panels_enabled", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_SWIPE_BRIGHTNESS("revanced_enable_swipe_brightness", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_SWIPE_VOLUME("revanced_enable_swipe_volume", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_PRESS_TO_SWIPE("revanced_enable_press_to_swipe", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_SWIPE_HAPTIC_FEEDBACK("revanced_enable_swipe_haptic_feedback", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_DEBUG("revanced_debug_enabled", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_DEBUG_STACKTRACE("revanced_debug_stacktrace_enabled", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_DEBUG_TOAST_ON_ERROR("revanced_debug_toast_on_error_enabled", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_EXTERNAL_BROWSER("revanced_enable_external_browser", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_AUTO_REPEAT("revanced_pref_auto_repeat", BOOLEAN, FALSE),
@Deprecated
DEPRECATED_TAP_SEEKING("revanced_enable_tap_seeking", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_HDR_AUTO_BRIGHTNESS("revanced_pref_hdr_autobrightness", BOOLEAN, TRUE),
@Deprecated
DEPRECATED_RYD_USER_ID("ryd_userId", STRING, "", RETURN_YOUTUBE_DISLIKE),
@Deprecated
DEPRECATED_RYD_DISLIKE_PERCENTAGE("ryd_show_dislike_percentage", BOOLEAN, FALSE, RETURN_YOUTUBE_DISLIKE),
@Deprecated
DEPRECATED_RYD_COMPACT_LAYOUT("ryd_use_compact_layout", BOOLEAN, FALSE, RETURN_YOUTUBE_DISLIKE),
@Deprecated
DEPRECATED_SB_ENABLED("sb-enabled", BOOLEAN, TRUE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_VOTING_BUTTON("sb-voting-enabled", BOOLEAN, FALSE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_CREATE_NEW_SEGMENT("sb-new-segment-enabled", BOOLEAN, FALSE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_COMPACT_SKIP_BUTTON("sb-use-compact-skip-button", BOOLEAN, FALSE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_MIN_DURATION("sb-min-duration", FLOAT, 0F, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_VIDEO_LENGTH_WITHOUT_SEGMENTS("sb-length-without-segments", BOOLEAN, TRUE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_API_URL("sb-api-host-url", STRING, "https://sponsor.ajay.app", SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_TOAST_ON_SKIP("show-toast", BOOLEAN, TRUE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_AUTO_HIDE_SKIP_BUTTON("sb-auto-hide-skip-segment-button", BOOLEAN, TRUE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_TRACK_SKIP_COUNT("count-skips", BOOLEAN, TRUE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_ADJUST_NEW_SEGMENT_STEP("new-segment-step-accuracy", INTEGER, 150, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_LAST_VIP_CHECK("sb-last-vip-check", LONG, 0L, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_IS_VIP("sb-is-vip", BOOLEAN, FALSE, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS("sb-skipped-segments", INTEGER, 0, SPONSOR_BLOCK),
@Deprecated
DEPRECATED_SB_LOCAL_TIME_SAVED_MILLISECONDS("sb-skipped-segments-time", LONG, 0L, SPONSOR_BLOCK);
//
// TODO END
//
private static SettingsEnum[] parents(SettingsEnum ... parents) {
return parents;
@ -280,22 +451,126 @@ public enum SettingsEnum {
}
}
private static final Map<String, SettingsEnum> pathToSetting = new HashMap<>(2* values().length);
static {
loadAllSettings();
for (SettingsEnum setting : values()) {
pathToSetting.put(setting.path, setting);
}
}
@Nullable
public static SettingsEnum settingFromPath(@NonNull String str) {
for (SettingsEnum setting : values()) {
if (setting.path.equals(str)) return setting;
}
return null;
return pathToSetting.get(str);
}
private static void loadAllSettings() {
for (SettingsEnum setting : values()) {
setting.load();
}
//
// TODO: eventually delete this
// renamed settings with new path names, but otherwise the new and old settings are identical
//
SettingsEnum[][] renamedSettings = {
// TODO: do _not_ delete this SB private user id migration property until sometime in 2024.
// This is the only setting that cannot be reconfigured if lost,
// and more time should be given for users who rarely upgrade.
{DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING, SB_PRIVATE_USER_ID},
// TODO: delete the rest of these migration settings. When to delete? Anytime.
{DEPRECATED_ADREMOVER_BUTTONED_REMOVAL, HIDE_BUTTONED_ADS},
{DEPRECATED_ADREMOVER_GENERAL_ADS_REMOVAL, HIDE_GENERAL_ADS},
{DEPRECATED_ADREMOVER_HIDE_LATEST_POSTS, HIDE_HIDE_LATEST_POSTS},
{DEPRECATED_ADREMOVER_PAID_CONTENT, HIDE_PAID_CONTENT},
{DEPRECATED_ADREMOVER_SELF_SPONSOR, HIDE_SELF_SPONSOR},
{DEPRECATED_REMOVE_VIDEO_ADS, HIDE_VIDEO_ADS},
{DEPRECATED_ADREMOVER_CUSTOM_ENABLED, CUSTOM_FILTER},
{DEPRECATED_ADREMOVER_CUSTOM_REMOVAL, CUSTOM_FILTER_STRINGS},
{DEPRECATED_HIDE_CHANNEL_MEMBER_SHELF, HIDE_CHANNEL_MEMBER_SHELF},
{DEPRECATED_HIDE_CHAPTER_TEASER, HIDE_CHAPTER_TEASER},
{DEPRECATED_HIDE_COMMUNITY_GUIDELINES, HIDE_COMMUNITY_GUIDELINES},
{DEPRECATED_HIDE_COMMUNITY_POSTS, HIDE_COMMUNITY_POSTS},
{DEPRECATED_HIDE_COMPACT_BANNER, HIDE_COMPACT_BANNER},
{DEPRECATED_HIDE_EMERGENCY_BOX, HIDE_EMERGENCY_BOX},
{DEPRECATED_HIDE_FEED_SURVEY_REMOVAL, HIDE_FEED_SURVEY},
{DEPRECATED_HIDE_GRAY_SEPARATOR, HIDE_GRAY_SEPARATOR},
{DEPRECATED_HIDE_HIDE_CHANNEL_GUIDELINES, HIDE_HIDE_CHANNEL_GUIDELINES},
{DEPRECATED_HIDE_INFO_PANEL_REMOVAL, HIDE_HIDE_INFO_PANELS},
{DEPRECATED_HIDE_MEDICAL_PANEL_REMOVAL, HIDE_MEDICAL_PANELS},
{DEPRECATED_HIDE_MERCHANDISE_REMOVAL, HIDE_MERCHANDISE_BANNERS},
{DEPRECATED_HIDE_MOVIE_REMOVAL, HIDE_MOVIES_SECTION},
{DEPRECATED_HIDE_SUBSCRIBERS_COMMUNITY_GUIDELINES_REMOVAL, HIDE_SUBSCRIBERS_COMMUNITY_GUIDELINES},
{DEPRECATED_HIDE_VIEW_PRODUCTS, HIDE_PRODUCTS_BANNER},
{DEPRECATED_HIDE_WEB_SEARCH_RESULTS, HIDE_WEB_SEARCH_RESULTS},
{DEPRECATED_HIDE_SHORTS, HIDE_SHORTS},
{DEPRECATED_DISABLE_RESUMING_SHORTS_PLAYER, DISABLE_RESUMING_SHORTS_PLAYER},
{DEPRECATED_HIDE_INFO_CARDS, HIDE_INFO_CARDS},
{DEPRECATED_ETERNAL_DOWNLOADER, EXTERNAL_DOWNLOADER},
{DEPRECATED_EXTERNAL_DOWNLOADER_PACKAGE_NAME, EXTERNAL_DOWNLOADER_PACKAGE_NAME},
{DEPRECATED_COPY_VIDEO_URL, COPY_VIDEO_URL},
{DEPRECATED_COPY_VIDEO_URL_TIMESTAMP, COPY_VIDEO_URL_TIMESTAMP},
{DEPRECATED_SHOW_OLD_VIDEO_MENU, SHOW_OLD_VIDEO_MENU},
{DEPRECATED_VIDEO_QUALITY_DEFAULT_WIFI, VIDEO_QUALITY_DEFAULT_WIFI},
{DEPRECATED_VIDEO_QUALITY_DEFAULT_MOBILE, VIDEO_QUALITY_DEFAULT_MOBILE},
{DEPRECATED_PLAYBACK_SPEED_DEFAULT, PLAYBACK_SPEED_DEFAULT},
{DEPRECATED_AUTO_CAPTIONS, AUTO_CAPTIONS},
{DEPRECATED_PLAYER_POPUP_PANELS, PLAYER_POPUP_PANELS},
{DEPRECATED_SWIPE_BRIGHTNESS, SWIPE_BRIGHTNESS},
{DEPRECATED_SWIPE_VOLUME, SWIPE_VOLUME},
{DEPRECATED_PRESS_TO_SWIPE, SWIPE_PRESS_TO_ENGAGE},
{DEPRECATED_SWIPE_HAPTIC_FEEDBACK, SWIPE_HAPTIC_FEEDBACK},
{DEPRECATED_DEBUG, DEBUG},
{DEPRECATED_DEBUG_STACKTRACE, DEBUG_STACKTRACE},
{DEPRECATED_DEBUG_TOAST_ON_ERROR, DEBUG_TOAST_ON_ERROR},
{DEPRECATED_EXTERNAL_BROWSER, EXTERNAL_BROWSER},
{DEPRECATED_AUTO_REPEAT, AUTO_REPEAT},
{DEPRECATED_TAP_SEEKING, TAP_SEEKING},
{DEPRECATED_HDR_AUTO_BRIGHTNESS, HDR_AUTO_BRIGHTNESS},
{DEPRECATED_RYD_USER_ID, RYD_USER_ID},
{DEPRECATED_RYD_DISLIKE_PERCENTAGE, RYD_DISLIKE_PERCENTAGE},
{DEPRECATED_RYD_COMPACT_LAYOUT, RYD_COMPACT_LAYOUT},
{DEPRECATED_SB_ENABLED, SB_ENABLED},
{DEPRECATED_SB_VOTING_BUTTON, SB_VOTING_BUTTON},
{DEPRECATED_SB_CREATE_NEW_SEGMENT, SB_CREATE_NEW_SEGMENT},
{DEPRECATED_SB_COMPACT_SKIP_BUTTON, SB_COMPACT_SKIP_BUTTON},
{DEPRECATED_SB_MIN_DURATION, SB_SEGMENT_MIN_DURATION},
{DEPRECATED_SB_VIDEO_LENGTH_WITHOUT_SEGMENTS, SB_VIDEO_LENGTH_WITHOUT_SEGMENTS},
{DEPRECATED_SB_API_URL, SB_API_URL},
{DEPRECATED_SB_TOAST_ON_SKIP, SB_TOAST_ON_SKIP},
{DEPRECATED_SB_AUTO_HIDE_SKIP_BUTTON, SB_AUTO_HIDE_SKIP_BUTTON},
{DEPRECATED_SB_TRACK_SKIP_COUNT, SB_TRACK_SKIP_COUNT},
{DEPRECATED_SB_ADJUST_NEW_SEGMENT_STEP, SB_CREATE_NEW_SEGMENT_STEP},
{DEPRECATED_SB_LAST_VIP_CHECK, SB_LAST_VIP_CHECK},
{DEPRECATED_SB_IS_VIP, SB_USER_IS_VIP},
{DEPRECATED_SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS, SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS},
{DEPRECATED_SB_LOCAL_TIME_SAVED_MILLISECONDS, SB_LOCAL_TIME_SAVED_MILLISECONDS},
};
for (SettingsEnum[] oldNewSetting : renamedSettings) {
SettingsEnum oldSetting = oldNewSetting[0];
SettingsEnum newSetting = oldNewSetting[1];
if (!oldSetting.isSetToDefault()) {
LogHelper.printInfo(() -> "Migrating old setting of '" + oldSetting.value
+ "' from: " + oldSetting + " into replacement setting: " + newSetting);
newSetting.saveValue(oldSetting.value);
oldSetting.saveValue(oldSetting.defaultValue); // reset old value
}
}
//
// TODO end
//
}
private void load() {
@ -354,7 +629,7 @@ public enum SettingsEnum {
* This method is only to be used by the Settings preference code.
*/
public static void setValue(@NonNull SettingsEnum setting, @NonNull Boolean newValue) {
Objects.requireNonNull(newValue);
setting.returnType.validate(newValue);
setting.value = newValue;
}
@ -362,7 +637,8 @@ public enum SettingsEnum {
* Sets the value, and persistently saves it.
*/
public void saveValue(@NonNull Object newValue) {
Objects.requireNonNull(newValue);
returnType.validate(newValue);
value = newValue; // Must set before saving to preferences (otherwise importing fails to update UI correctly).
switch (returnType) {
case BOOLEAN:
sharedPref.saveBoolean(path, (boolean) newValue);
@ -382,7 +658,6 @@ public enum SettingsEnum {
default:
throw new IllegalStateException(name());
}
value = newValue;
}
/**
@ -400,6 +675,13 @@ public enum SettingsEnum {
return false;
}
/**
* @return if the currently set value is the same as {@link #defaultValue}
*/
public boolean isSetToDefault() {
return value.equals(defaultValue);
}
public boolean getBoolean() {
return (Boolean) value;
}
@ -429,11 +711,174 @@ public enum SettingsEnum {
return value;
}
/**
* This could be yet another field,
* for now use a simple switch statement since this method is not used outside this class.
*/
private boolean includeWithImportExport() {
switch (this) {
case RYD_USER_ID: // Not useful to export, no reason to include it.
case SB_LAST_VIP_CHECK:
case SB_HIDE_EXPORT_WARNING:
case SB_SEEN_GUIDELINES:
case SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS:
case SB_LOCAL_TIME_SAVED_MILLISECONDS:
return false;
}
return true;
}
// Begin import / export
/**
* If a setting path has this prefix, then remove it before importing/exporting.
*/
private static final String OPTIONAL_REVANCED_SETTINGS_PREFIX = "revanced_";
/**
* The path, minus any 'revanced' prefix to keep json concise.
*/
private String getImportExportKey() {
if (path.startsWith(OPTIONAL_REVANCED_SETTINGS_PREFIX)) {
return path.substring(OPTIONAL_REVANCED_SETTINGS_PREFIX.length());
}
return path;
}
private static SettingsEnum[] valuesSortedForExport() {
SettingsEnum[] sorted = values();
Arrays.sort(sorted, (SettingsEnum o1, SettingsEnum o2) -> {
// Organize SponsorBlock settings last.
final boolean o1IsSb = o1.sharedPref == SPONSOR_BLOCK;
final boolean o2IsSb = o2.sharedPref == SPONSOR_BLOCK;
if (o1IsSb != o2IsSb) {
return o1IsSb ? 1 : -1;
}
return o1.path.compareTo(o2.path);
});
return sorted;
}
@NonNull
public static String exportJSON(@Nullable Context alertDialogContext) {
try {
JSONObject json = new JSONObject();
for (SettingsEnum setting : valuesSortedForExport()) {
String importExportKey = setting.getImportExportKey();
if (json.has(importExportKey)) {
throw new IllegalArgumentException("duplicate key found: " + importExportKey);
}
final boolean exportDefaultValues = false; // Enable to see what all settings looks like in the UI.
if (setting.includeWithImportExport() && (!setting.isSetToDefault() | exportDefaultValues)) {
json.put(importExportKey, setting.getObjectValue());
}
}
SponsorBlockSettings.exportCategoriesToFlatJson(alertDialogContext, json);
if (json.length() == 0) {
return "";
}
String export = json.toString(0);
// Remove the outer JSON braces to make the output more compact,
// and leave less chance of the user forgetting to copy it
return export.substring(2, export.length() - 2);
} catch (JSONException e) {
LogHelper.printException(() -> "Export failure", e); // should never happen
return "";
}
}
/**
* @return if any settings that require a reboot were changed.
*/
public static boolean importJSON(@NonNull String settingsJsonString) {
try {
if (!settingsJsonString.matches("[\\s\\S]*\\{")) {
settingsJsonString = '{' + settingsJsonString + '}'; // Restore outer JSON braces
}
JSONObject json = new JSONObject(settingsJsonString);
boolean rebootSettingChanged = false;
int numberOfSettingsImported = 0;
for (SettingsEnum setting : values()) {
String key = setting.getImportExportKey();
if (json.has(key)) {
Object value;
switch (setting.returnType) {
case BOOLEAN:
value = json.getBoolean(key);
break;
case INTEGER:
value = json.getInt(key);
break;
case LONG:
value = json.getLong(key);
break;
case FLOAT:
value = (float) json.getDouble(key);
break;
case STRING:
value = json.getString(key);
break;
default:
throw new IllegalStateException();
}
if (!setting.getObjectValue().equals(value)) {
rebootSettingChanged |= setting.rebootApp;
setting.saveValue(value);
}
numberOfSettingsImported++;
} else if (setting.includeWithImportExport() && !setting.isSetToDefault()) {
LogHelper.printDebug(() -> "Resetting to default: " + setting);
rebootSettingChanged |= setting.rebootApp;
setting.saveValue(setting.defaultValue);
}
}
numberOfSettingsImported += SponsorBlockSettings.importCategoriesFromFlatJson(json);
ReVancedUtils.showToastLong(numberOfSettingsImported == 0
? str("revanced_settings_import_reset")
: str("revanced_settings_import_success", numberOfSettingsImported));
return rebootSettingChanged;
} catch (JSONException | IllegalArgumentException ex) {
ReVancedUtils.showToastLong(str("revanced_settings_import_failure_parse", ex.getMessage()));
LogHelper.printInfo(() -> "", ex);
} catch (Exception ex) {
LogHelper.printException(() -> "Import failure: " + ex.getMessage(), ex); // should never happen
}
return false;
}
// End import / export
public enum ReturnType {
BOOLEAN,
INTEGER,
STRING,
LONG,
FLOAT,
STRING;
public void validate(@Nullable Object obj) throws IllegalArgumentException {
if (!matches(obj)) {
throw new IllegalArgumentException("'" + obj + "' does not match:" + this);
}
}
public boolean matches(@Nullable Object obj) {
switch (this) {
case BOOLEAN:
return obj instanceof Boolean;
case INTEGER:
return obj instanceof Integer;
case LONG:
return obj instanceof Long;
case FLOAT:
return obj instanceof Float;
case STRING:
return obj instanceof String;
}
return false;
}
}
}

View File

@ -0,0 +1,97 @@
package app.revanced.integrations.settingsmenu;
import static app.revanced.integrations.utils.StringRef.str;
import android.app.AlertDialog;
import android.content.Context;
import android.os.Build;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.text.InputType;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.EditText;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
public class ImportExportPreference extends EditTextPreference implements Preference.OnPreferenceClickListener {
private String existingSettings;
private void init() {
setSelectable(true);
EditText editText = getEditText();
editText.setTextIsSelectable(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
editText.setAutofillHints((String) null);
}
editText.setInputType(editText.getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
editText.setTextSize(TypedValue.COMPLEX_UNIT_PT, 7); // Use a smaller font to reduce text wrap.
setOnPreferenceClickListener(this);
}
public ImportExportPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
public ImportExportPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public ImportExportPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ImportExportPreference(Context context) {
super(context);
init();
}
@Override
public boolean onPreferenceClick(Preference preference) {
try {
// Must set text before preparing dialog, otherwise text is non selectable if this preference is later reopened.
existingSettings = SettingsEnum.exportJSON(getContext());
getEditText().setText(existingSettings);
} catch (Exception ex) {
LogHelper.printException(() -> "showDialog failure", ex);
}
return true;
}
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
try {
// Show the user the settings in JSON format.
builder.setNeutralButton(str("revanced_settings_import_copy"), (dialog, which) -> {
ReVancedUtils.setClipboard(getEditText().getText().toString());
}).setPositiveButton(str("revanced_settings_import"), (dialog, which) -> {
importSettings(getEditText().getText().toString());
});
} catch (Exception ex) {
LogHelper.printException(() -> "onPrepareDialogBuilder failure", ex);
}
}
private void importSettings(String replacementSettings) {
try {
if (replacementSettings.equals(existingSettings)) {
return;
}
ReVancedSettingsFragment.settingImportInProgress = true;
final boolean rebootNeeded = SettingsEnum.importJSON(replacementSettings);
if (rebootNeeded) {
ReVancedSettingsFragment.showRebootDialog(getContext());
}
} catch (Exception ex) {
LogHelper.printException(() -> "importSettings failure", ex);
} finally {
ReVancedSettingsFragment.settingImportInProgress = false;
}
}
}

View File

@ -31,6 +31,33 @@ import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
public class ReVancedSettingsFragment extends PreferenceFragment {
/**
* Indicates that if a preference changes,
* to apply the change from the Setting to the UI component.
*/
static boolean settingImportInProgress;
private static void reboot(@NonNull Context activity) {
final int intentFlags = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE;
PendingIntent intent = PendingIntent.getActivity(activity, 0,
new Intent(activity, Shell_HomeActivity.class), intentFlags);
AlarmManager systemService = (AlarmManager) activity.getSystemService(Context.ALARM_SERVICE);
systemService.setExact(AlarmManager.ELAPSED_REALTIME, 1500L, intent);
Process.killProcess(Process.myPid());
}
static void showRebootDialog(@NonNull Context activity) {
String positiveButton = str("in_app_update_restart_button");
String negativeButton = str("sign_in_cancel");
new AlertDialog.Builder(activity).setMessage(str("pref_refresh_config"))
.setPositiveButton(positiveButton, (dialog, id) -> {
reboot(activity);
})
.setNegativeButton(negativeButton, null)
.setCancelable(false)
.show();
}
/**
* Used to prevent showing reboot dialog, if user cancels a setting user dialog.
*/
@ -42,33 +69,53 @@ public class ReVancedSettingsFragment extends PreferenceFragment {
if (setting == null) {
return;
}
Preference pref = this.findPreference(str);
LogHelper.printDebug(() -> "Setting " + setting.name() + " was changed. Preference " + str + ": " + pref);
Preference pref = findPreference(str);
LogHelper.printDebug(() -> setting.name() + ": " + " setting value:" + setting.getObjectValue() + " pref:" + pref);
if (pref == null) {
return;
}
if (pref instanceof SwitchPreference) {
SwitchPreference switchPref = (SwitchPreference) pref;
SettingsEnum.setValue(setting, switchPref.isChecked());
if (settingImportInProgress) {
switchPref.setChecked(setting.getBoolean());
} else {
SettingsEnum.setValue(setting, switchPref.isChecked());
}
} else if (pref instanceof EditTextPreference) {
String editText = ((EditTextPreference) pref).getText();
SettingsEnum.setValue(setting, editText);
EditTextPreference editPreference = (EditTextPreference) pref;
if (settingImportInProgress) {
editPreference.getEditText().setText(setting.getObjectValue().toString());
} else {
SettingsEnum.setValue(setting, editPreference.getText());
}
} else if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
SettingsEnum.setValue(setting, listPref.getValue());
if (settingImportInProgress) {
listPref.setValue(setting.getObjectValue().toString());
} else {
SettingsEnum.setValue(setting, listPref.getValue());
}
updateListPreferenceSummary((ListPreference) pref, setting);
} else {
LogHelper.printException(() -> "Setting cannot be handled: " + pref.getClass() + " " + pref);
return;
}
enableDisablePreferences();
if (settingImportInProgress) {
return;
}
if (!showingUserDialogMessage) {
if (setting.userDialogMessage != null && ((SwitchPreference) pref).isChecked() != (Boolean) setting.defaultValue) {
showSettingUserDialogConfirmation(getActivity(), (SwitchPreference) pref, setting);
} else if (setting.rebootApp) {
rebootDialog(getActivity());
showRebootDialog(getActivity());
}
}
enableDisablePreferences();
} catch (Exception ex) {
LogHelper.printException(() -> "OnSharedPreferenceChangeListener failure", ex);
}
@ -91,17 +138,21 @@ public class ReVancedSettingsFragment extends PreferenceFragment {
CustomVideoSpeedPatch.initializeListPreference((ListPreference) defaultSpeedPreference);
}
// set the summary text for any ListPreferences
// Set current value from SettingsEnum
for (SettingsEnum setting : SettingsEnum.values()) {
Preference preference = findPreference(setting.path);
if (preference instanceof ListPreference) {
if (preference instanceof SwitchPreference) {
((SwitchPreference) preference).setChecked(setting.getBoolean());
} else if (preference instanceof EditTextPreference) {
((EditTextPreference) preference).setText(setting.getObjectValue().toString());
} else if (preference instanceof ListPreference) {
updateListPreferenceSummary((ListPreference) preference, setting);
}
}
preferenceManager.getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
} catch (Exception ex) {
LogHelper.printException(() -> "onActivityCreated() error", ex);
LogHelper.printException(() -> "onActivityCreated() failure", ex);
}
}
@ -124,33 +175,14 @@ public class ReVancedSettingsFragment extends PreferenceFragment {
* Sets summary text to the currently selected list option.
*/
private void updateListPreferenceSummary(ListPreference listPreference, SettingsEnum setting) {
final int entryIndex = listPreference.findIndexOfValue(setting.getObjectValue().toString());
String objectStringValue = setting.getObjectValue().toString();
final int entryIndex = listPreference.findIndexOfValue(objectStringValue);
if (entryIndex >= 0) {
listPreference.setSummary(listPreference.getEntries()[entryIndex]);
listPreference.setValue(objectStringValue);
}
}
private void reboot(@NonNull Activity activity) {
final int intentFlags = PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE;
PendingIntent intent = PendingIntent.getActivity(activity, 0,
new Intent(activity, Shell_HomeActivity.class), intentFlags);
AlarmManager systemService = (AlarmManager) activity.getSystemService(Context.ALARM_SERVICE);
systemService.setExact(AlarmManager.ELAPSED_REALTIME, 1500L, intent);
Process.killProcess(Process.myPid());
}
private void rebootDialog(@NonNull Activity activity) {
String positiveButton = str("in_app_update_restart_button");
String negativeButton = str("sign_in_cancel");
new AlertDialog.Builder(activity).setMessage(str("pref_refresh_config"))
.setPositiveButton(positiveButton, (dialog, id) -> {
reboot(activity);
})
.setNegativeButton(negativeButton, null)
.setCancelable(false)
.show();
}
private void showSettingUserDialogConfirmation(@NonNull Activity activity, SwitchPreference switchPref, SettingsEnum setting) {
showingUserDialogMessage = true;
new AlertDialog.Builder(activity)
@ -158,7 +190,7 @@ public class ReVancedSettingsFragment extends PreferenceFragment {
.setMessage(setting.userDialogMessage.toString())
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
if (setting.rebootApp) {
rebootDialog(activity);
showRebootDialog(activity);
}
})
.setNegativeButton(android.R.string.cancel, (dialog, id) -> {

View File

@ -36,8 +36,8 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
private void updateUIState() {
shortsPreference.setEnabled(SettingsEnum.RYD_SHORTS.isAvailable());
percentagePreference.setEnabled(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.isAvailable());
compactLayoutPreference.setEnabled(SettingsEnum.RYD_USE_COMPACT_LAYOUT.isAvailable());
percentagePreference.setEnabled(SettingsEnum.RYD_DISLIKE_PERCENTAGE.isAvailable());
compactLayoutPreference.setEnabled(SettingsEnum.RYD_COMPACT_LAYOUT.isAvailable());
}
@Override
@ -77,12 +77,12 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
preferenceScreen.addPreference(shortsPreference);
percentagePreference = new SwitchPreference(context);
percentagePreference.setChecked(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.getBoolean());
percentagePreference.setChecked(SettingsEnum.RYD_DISLIKE_PERCENTAGE.getBoolean());
percentagePreference.setTitle(str("revanced_ryd_dislike_percentage_title"));
percentagePreference.setSummaryOn(str("revanced_ryd_dislike_percentage_summary_on"));
percentagePreference.setSummaryOff(str("revanced_ryd_dislike_percentage_summary_off"));
percentagePreference.setOnPreferenceChangeListener((pref, newValue) -> {
SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.saveValue(newValue);
SettingsEnum.RYD_DISLIKE_PERCENTAGE.saveValue(newValue);
ReturnYouTubeDislike.clearCache();
updateUIState();
return true;
@ -90,12 +90,12 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
preferenceScreen.addPreference(percentagePreference);
compactLayoutPreference = new SwitchPreference(context);
compactLayoutPreference.setChecked(SettingsEnum.RYD_USE_COMPACT_LAYOUT.getBoolean());
compactLayoutPreference.setChecked(SettingsEnum.RYD_COMPACT_LAYOUT.getBoolean());
compactLayoutPreference.setTitle(str("revanced_ryd_compact_layout_title"));
compactLayoutPreference.setSummaryOn(str("revanced_ryd_compact_layout_summary_on"));
compactLayoutPreference.setSummaryOff(str("revanced_ryd_compact_layout_summary_off"));
compactLayoutPreference.setOnPreferenceChangeListener((pref, newValue) -> {
SettingsEnum.RYD_USE_COMPACT_LAYOUT.saveValue(newValue);
SettingsEnum.RYD_COMPACT_LAYOUT.saveValue(newValue);
ReturnYouTubeDislike.clearCache();
updateUIState();
return true;

View File

@ -20,6 +20,7 @@ import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
import android.text.Html;
import android.text.InputType;
import android.util.TypedValue;
import android.widget.EditText;
import androidx.annotation.NonNull;
@ -67,41 +68,41 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
if (!enabled) {
SponsorBlockViewController.hideAll();
SegmentPlaybackController.setCurrentVideoId(null);
} else if (!SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.getBoolean()) {
} else if (!SettingsEnum.SB_CREATE_NEW_SEGMENT.getBoolean()) {
SponsorBlockViewController.hideNewSegmentLayout();
}
// voting and add new segment buttons automatically shows/hides themselves
sbEnabled.setChecked(enabled);
addNewSegment.setChecked(SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.getBoolean());
addNewSegment.setChecked(SettingsEnum.SB_CREATE_NEW_SEGMENT.getBoolean());
addNewSegment.setEnabled(enabled);
votingEnabled.setChecked(SettingsEnum.SB_VOTING_ENABLED.getBoolean());
votingEnabled.setChecked(SettingsEnum.SB_VOTING_BUTTON.getBoolean());
votingEnabled.setEnabled(enabled);
compactSkipButton.setChecked(SettingsEnum.SB_USE_COMPACT_SKIP_BUTTON.getBoolean());
compactSkipButton.setChecked(SettingsEnum.SB_COMPACT_SKIP_BUTTON.getBoolean());
compactSkipButton.setEnabled(enabled);
autoHideSkipSegmentButton.setChecked(SettingsEnum.SB_AUTO_HIDE_SKIP_BUTTON.getBoolean());
autoHideSkipSegmentButton.setEnabled(enabled);
showSkipToast.setChecked(SettingsEnum.SB_SHOW_TOAST_ON_SKIP.getBoolean());
showSkipToast.setChecked(SettingsEnum.SB_TOAST_ON_SKIP.getBoolean());
showSkipToast.setEnabled(enabled);
trackSkips.setChecked(SettingsEnum.SB_TRACK_SKIP_COUNT.getBoolean());
trackSkips.setEnabled(enabled);
showTimeWithoutSegments.setChecked(SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.getBoolean());
showTimeWithoutSegments.setChecked(SettingsEnum.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.getBoolean());
showTimeWithoutSegments.setEnabled(enabled);
newSegmentStep.setText(SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getObjectValue().toString());
newSegmentStep.setText(SettingsEnum.SB_CREATE_NEW_SEGMENT_STEP.getObjectValue().toString());
newSegmentStep.setEnabled(enabled);
minSegmentDuration.setText(SettingsEnum.SB_MIN_DURATION.getObjectValue().toString());
minSegmentDuration.setText(SettingsEnum.SB_SEGMENT_MIN_DURATION.getObjectValue().toString());
minSegmentDuration.setEnabled(enabled);
privateUserId.setText(SettingsEnum.SB_UUID.getString());
privateUserId.setText(SettingsEnum.SB_PRIVATE_USER_ID.getString());
privateUserId.setEnabled(enabled);
apiUrl.setEnabled(enabled);
@ -171,7 +172,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
votingEnabled.setSummaryOff(str("sb_enable_voting_sum_off"));
category.addPreference(votingEnabled);
votingEnabled.setOnPreferenceChangeListener((preference1, newValue) -> {
SettingsEnum.SB_VOTING_ENABLED.saveValue(newValue);
SettingsEnum.SB_VOTING_BUTTON.saveValue(newValue);
updateUI();
return true;
});
@ -182,7 +183,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
compactSkipButton.setSummaryOff(str("sb_enable_compact_skip_button_sum_off"));
category.addPreference(compactSkipButton);
compactSkipButton.setOnPreferenceChangeListener((preference1, newValue) -> {
SettingsEnum.SB_USE_COMPACT_SKIP_BUTTON.saveValue(newValue);
SettingsEnum.SB_COMPACT_SKIP_BUTTON.saveValue(newValue);
updateUI();
return true;
});
@ -207,7 +208,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
return false;
});
showSkipToast.setOnPreferenceChangeListener((preference1, newValue) -> {
SettingsEnum.SB_SHOW_TOAST_ON_SKIP.saveValue(newValue);
SettingsEnum.SB_TOAST_ON_SKIP.saveValue(newValue);
updateUI();
return true;
});
@ -218,7 +219,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
showTimeWithoutSegments.setSummaryOn(str("sb_general_time_without_sum_on"));
showTimeWithoutSegments.setSummaryOff(str("sb_general_time_without_sum_off"));
showTimeWithoutSegments.setOnPreferenceChangeListener((preference1, newValue) -> {
SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.saveValue(newValue);
SettingsEnum.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.saveValue(newValue);
updateUI();
return true;
});
@ -247,7 +248,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
.setCancelable(false)
.show();
}
SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.saveValue(newValue);
SettingsEnum.SB_CREATE_NEW_SEGMENT.saveValue(newValue);
updateUI();
return true;
});
@ -262,7 +263,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
ReVancedUtils.showToastLong(str("sb_general_adjusting_invalid"));
return false;
}
SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.saveValue(newAdjustmentValue);
SettingsEnum.SB_CREATE_NEW_SEGMENT_STEP.saveValue(newAdjustmentValue);
return true;
});
category.addPreference(newSegmentStep);
@ -298,7 +299,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
minSegmentDuration.setSummary(str("sb_general_min_duration_sum"));
minSegmentDuration.getEditText().setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
minSegmentDuration.setOnPreferenceChangeListener((preference1, newValue) -> {
SettingsEnum.SB_MIN_DURATION.saveValue(Float.valueOf(newValue.toString()));
SettingsEnum.SB_SEGMENT_MIN_DURATION.saveValue(Float.valueOf(newValue.toString()));
return true;
});
category.addPreference(minSegmentDuration);
@ -312,7 +313,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
ReVancedUtils.showToastLong(str("sb_general_uuid_invalid"));
return false;
}
SettingsEnum.SB_UUID.saveValue(newUUID);
SettingsEnum.SB_PRIVATE_USER_ID.saveValue(newUUID);
fetchAndDisplayStats();
return true;
});
@ -351,9 +352,22 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
});
category.addPreference(apiUrl);
importExport = new EditTextPreference(context);
importExport = new EditTextPreference(context) {
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
builder.setNeutralButton(str("sb_settings_copy"), (dialog, which) -> {
ReVancedUtils.setClipboard(getEditText().getText().toString());
});
}
};
importExport.setTitle(str("sb_settings_ie"));
importExport.setSummary(str("sb_settings_ie_sum"));
importExport.getEditText().setInputType(InputType.TYPE_CLASS_TEXT
| InputType.TYPE_TEXT_FLAG_MULTI_LINE
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
importExport.getEditText().setAutofillHints((String) null);
}
importExport.getEditText().setTextSize(TypedValue.COMPLEX_UNIT_PT, 8);
importExport.setOnPreferenceClickListener(preference1 -> {
importExport.getEditText().setText(SponsorBlockSettings.exportSettings());
return true;
@ -419,6 +433,12 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
private void fetchAndDisplayStats() {
try {
statsCategory.removeAll();
if (!SponsorBlockSettings.userHasSBPrivateId()) {
// User has never voted or created any segments. No stats to show.
addLocalUserStats();
return;
}
Preference loadingPlaceholderPreference = new Preference(this.getActivity());
loadingPlaceholderPreference.setEnabled(false);
statsCategory.addPreference(loadingPlaceholderPreference);
@ -428,6 +448,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
UserStats stats = SBRequester.retrieveUserStats();
ReVancedUtils.runOnMainThread(() -> { // get back on main thread to modify UI elements
addUserStats(loadingPlaceholderPreference, stats);
addLocalUserStats();
});
});
} else {
@ -450,7 +471,8 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
statsCategory.removeAll();
Context context = statsCategory.getContext();
{
if (stats.totalSegmentCountIncludingIgnored > 0) {
// If user has not created any segments, there's no reason to set a username.
EditTextPreference preference = new EditTextPreference(context);
statsCategory.addPreference(preference);
String userName = stats.userName;
@ -482,7 +504,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
statsCategory.addPreference(preference);
String formatted = statsNumberOfSegmentsSkippedFormatter.format(stats.segmentCount);
preference.setTitle(fromHtml(str("sb_stats_submissions", formatted)));
if (stats.segmentCount == 0) {
if (stats.totalSegmentCountIncludingIgnored == 0) {
preference.setSelectable(false);
} else {
preference.setOnPreferenceClickListener(preference1 -> {
@ -512,7 +534,7 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
String stats_saved;
String stats_saved_sum;
if (stats.segmentCount == 0) {
if (stats.totalSegmentCountIncludingIgnored == 0) {
stats_saved = str("sb_stats_saved_zero");
stats_saved_sum = str("sb_stats_saved_sum_zero");
} else {
@ -528,34 +550,34 @@ public class SponsorBlockSettingsFragment extends PreferenceFragment {
return false;
});
}
{
// time the user saved by using SB
Preference preference = new Preference(context);
statsCategory.addPreference(preference);
Runnable updateStatsSelfSaved = () -> {
String formatted = statsNumberOfSegmentsSkippedFormatter.format(SettingsEnum.SB_SKIPPED_SEGMENTS_NUMBER_SKIPPED.getInt());
preference.setTitle(fromHtml(str("sb_stats_self_saved", formatted)));
String formattedSaved = SponsorBlockUtils.getTimeSavedString(SettingsEnum.SB_SKIPPED_SEGMENTS_TIME_SAVED.getLong() / 1000);
preference.setSummary(fromHtml(str("sb_stats_self_saved_sum", formattedSaved)));
};
updateStatsSelfSaved.run();
preference.setOnPreferenceClickListener(preference1 -> {
new AlertDialog.Builder(preference1.getContext())
.setTitle(str("sb_stats_self_saved_reset_title"))
.setPositiveButton(android.R.string.yes, (dialog, whichButton) -> {
SettingsEnum.SB_SKIPPED_SEGMENTS_NUMBER_SKIPPED.saveValue(SettingsEnum.SB_SKIPPED_SEGMENTS_NUMBER_SKIPPED.defaultValue);
SettingsEnum.SB_SKIPPED_SEGMENTS_TIME_SAVED.saveValue(SettingsEnum.SB_SKIPPED_SEGMENTS_TIME_SAVED.defaultValue);
updateStatsSelfSaved.run();
})
.setNegativeButton(android.R.string.no, null).show();
return true;
});
}
} catch (Exception ex) {
LogHelper.printException(() -> "fetchAndDisplayStats failure", ex);
LogHelper.printException(() -> "addUserStats failure", ex);
}
}
private void addLocalUserStats() {
// time the user saved by using SB
Preference preference = new Preference(statsCategory.getContext());
statsCategory.addPreference(preference);
Runnable updateStatsSelfSaved = () -> {
String formatted = statsNumberOfSegmentsSkippedFormatter.format(SettingsEnum.SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS.getInt());
preference.setTitle(fromHtml(str("sb_stats_self_saved", formatted)));
String formattedSaved = SponsorBlockUtils.getTimeSavedString(SettingsEnum.SB_LOCAL_TIME_SAVED_MILLISECONDS.getLong() / 1000);
preference.setSummary(fromHtml(str("sb_stats_self_saved_sum", formattedSaved)));
};
updateStatsSelfSaved.run();
preference.setOnPreferenceClickListener(preference1 -> {
new AlertDialog.Builder(preference1.getContext())
.setTitle(str("sb_stats_self_saved_reset_title"))
.setPositiveButton(android.R.string.yes, (dialog, whichButton) -> {
SettingsEnum.SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS.saveValue(SettingsEnum.SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS.defaultValue);
SettingsEnum.SB_LOCAL_TIME_SAVED_MILLISECONDS.saveValue(SettingsEnum.SB_LOCAL_TIME_SAVED_MILLISECONDS.defaultValue);
updateStatsSelfSaved.run();
})
.setNegativeButton(android.R.string.no, null).show();
return true;
});
}
}

View File

@ -38,12 +38,12 @@ public class SegmentPlaybackController {
* Length of time to show a skip button for a highlight segment,
* or a regular segment if {@link SettingsEnum#SB_AUTO_HIDE_SKIP_BUTTON} is enabled.
*
* Because Effectively, this value is rounded up to the next second.
* Effectively this value is rounded up to the next second.
*/
private static final long DURATION_TO_SHOW_SKIP_BUTTON = 3800;
/*
* Highlight segments have zero length, as they are a point in time.
* Highlight segments have zero length as they are a point in time.
* Draw them on screen using a fixed width bar.
* Value is independent of device dpi.
*/
@ -524,7 +524,7 @@ public class SegmentPlaybackController {
if (!userManuallySkipped) {
// check for any smaller embedded segments, and count those as autoskipped
final boolean showSkipToast = SettingsEnum.SB_SHOW_TOAST_ON_SKIP.getBoolean();
final boolean showSkipToast = SettingsEnum.SB_TOAST_ON_SKIP.getBoolean();
for (final SponsorSegment otherSegment : Objects.requireNonNull(segments)) {
if (segmentToSkip.end < otherSegment.start) {
break; // no other segments can be contained
@ -651,7 +651,7 @@ public class SegmentPlaybackController {
*/
public static String appendTimeWithoutSegments(String totalTime) {
try {
if (SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.getBoolean()
if (SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.getBoolean()
&& !TextUtils.isEmpty(totalTime) && !TextUtils.isEmpty(timeWithoutSegments)) {
// Force LTR layout, to match the same LTR video time/length layout YouTube uses for all languages
return "\u202D" + totalTime + timeWithoutSegments; // u202D = left to right override
@ -665,7 +665,7 @@ public class SegmentPlaybackController {
private static void calculateTimeWithoutSegments() {
final long currentVideoLength = VideoInformation.getVideoLength();
if (!SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.getBoolean() || currentVideoLength <= 0
if (!SettingsEnum.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.getBoolean() || currentVideoLength <= 0
|| segments == null || segments.length == 0) {
timeWithoutSegments = null;
return;

View File

@ -2,10 +2,13 @@ package app.revanced.integrations.sponsorblock;
import static app.revanced.integrations.utils.StringRef.str;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Patterns;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.json.JSONArray;
import org.json.JSONException;
@ -21,6 +24,10 @@ import app.revanced.integrations.utils.LogHelper;
import app.revanced.integrations.utils.ReVancedUtils;
public class SponsorBlockSettings {
/**
* Minimum length a SB user id must be, as set by SB API.
*/
private static final int SB_PRIVATE_USER_ID_MINIMUM_LENGTH = 30;
public static void importSettings(@NonNull String json) {
ReVancedUtils.verifyOnMainThread();
@ -66,43 +73,43 @@ public class SponsorBlockSettings {
}
editor.apply();
String userID = settingsJson.getString("userID");
if (!isValidSBUserId(userID)) {
throw new IllegalArgumentException("userId is blank");
if (settingsJson.has("userID")) {
// User id does not exist if user never voted or created any segments.
String userID = settingsJson.getString("userID");
if (isValidSBUserId(userID)) {
SettingsEnum.SB_PRIVATE_USER_ID.saveValue(userID);
}
}
SettingsEnum.SB_UUID.saveValue(userID);
SettingsEnum.SB_IS_VIP.saveValue(settingsJson.getBoolean("isVip"));
SettingsEnum.SB_SHOW_TOAST_ON_SKIP.saveValue(!settingsJson.getBoolean("dontShowNotice"));
SettingsEnum.SB_USER_IS_VIP.saveValue(settingsJson.getBoolean("isVip"));
SettingsEnum.SB_TOAST_ON_SKIP.saveValue(!settingsJson.getBoolean("dontShowNotice"));
SettingsEnum.SB_TRACK_SKIP_COUNT.saveValue(settingsJson.getBoolean("trackViewCount"));
SettingsEnum.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.saveValue(settingsJson.getBoolean("showTimeWithSkips"));
String serverAddress = settingsJson.getString("serverAddress");
if (!isValidSBServerAddress(serverAddress)) {
throw new IllegalArgumentException(str("sb_api_url_invalid"));
if (isValidSBServerAddress(serverAddress)) { // Old versions of ReVanced exported wrong url format
SettingsEnum.SB_API_URL.saveValue(serverAddress);
}
SettingsEnum.SB_API_URL.saveValue(serverAddress);
SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.saveValue(settingsJson.getBoolean("showTimeWithSkips"));
final float minDuration = (float)settingsJson.getDouble("minDuration");
final float minDuration = (float) settingsJson.getDouble("minDuration");
if (minDuration < 0) {
throw new IllegalArgumentException("invalid minDuration: " + minDuration);
}
SettingsEnum.SB_MIN_DURATION.saveValue(minDuration);
SettingsEnum.SB_SEGMENT_MIN_DURATION.saveValue(minDuration);
try {
if (settingsJson.has("skipCount")) { // Value not exported in old versions of ReVanced
int skipCount = settingsJson.getInt("skipCount");
if (skipCount < 0) {
throw new IllegalArgumentException("invalid skipCount: " + skipCount);
}
SettingsEnum.SB_SKIPPED_SEGMENTS_NUMBER_SKIPPED.saveValue(skipCount);
SettingsEnum.SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS.saveValue(skipCount);
}
if (settingsJson.has("minutesSaved")) {
final double minutesSaved = settingsJson.getDouble("minutesSaved");
if (minutesSaved < 0) {
throw new IllegalArgumentException("invalid minutesSaved: " + minutesSaved);
}
SettingsEnum.SB_SKIPPED_SEGMENTS_TIME_SAVED.saveValue((long)(minutesSaved * 60 * 1000));
} catch (JSONException ex) {
// ignore. values were not exported in prior versions of ReVanced
SettingsEnum.SB_LOCAL_TIME_SAVED_MILLISECONDS.saveValue((long) (minutesSaved * 60 * 1000));
}
ReVancedUtils.showToastLong(str("sb_settings_import_successful"));
@ -136,15 +143,17 @@ public class SponsorBlockSettings {
categorySelectionsArray.put(behaviorObject);
}
}
json.put("userID", SettingsEnum.SB_UUID.getString());
json.put("isVip", SettingsEnum.SB_IS_VIP.getBoolean());
if (SponsorBlockSettings.userHasSBPrivateId()) {
json.put("userID", SettingsEnum.SB_PRIVATE_USER_ID.getString());
}
json.put("isVip", SettingsEnum.SB_USER_IS_VIP.getBoolean());
json.put("serverAddress", SettingsEnum.SB_API_URL.getString());
json.put("dontShowNotice", !SettingsEnum.SB_SHOW_TOAST_ON_SKIP.getBoolean());
json.put("showTimeWithSkips", SettingsEnum.SB_SHOW_TIME_WITHOUT_SEGMENTS.getBoolean());
json.put("minDuration", SettingsEnum.SB_MIN_DURATION.getFloat());
json.put("dontShowNotice", !SettingsEnum.SB_TOAST_ON_SKIP.getBoolean());
json.put("showTimeWithSkips", SettingsEnum.SB_VIDEO_LENGTH_WITHOUT_SEGMENTS.getBoolean());
json.put("minDuration", SettingsEnum.SB_SEGMENT_MIN_DURATION.getFloat());
json.put("trackViewCount", SettingsEnum.SB_TRACK_SKIP_COUNT.getBoolean());
json.put("skipCount", SettingsEnum.SB_SKIPPED_SEGMENTS_NUMBER_SKIPPED.getInt());
json.put("minutesSaved", SettingsEnum.SB_SKIPPED_SEGMENTS_TIME_SAVED.getLong() / (60f * 1000));
json.put("skipCount", SettingsEnum.SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS.getInt());
json.put("minutesSaved", SettingsEnum.SB_LOCAL_TIME_SAVED_MILLISECONDS.getLong() / (60f * 1000));
json.put("categorySelections", categorySelectionsArray);
json.put("barTypes", barTypesObject);
@ -152,13 +161,59 @@ public class SponsorBlockSettings {
return json.toString(2);
} catch (Exception ex) {
LogHelper.printInfo(() -> "failed to export settings", ex); // use info level, as we are showing our own toast
ReVancedUtils.showToastLong(str("sb_settings_export_failed"));
ReVancedUtils.showToastLong(str("sb_settings_export_failed", ex));
return "";
}
}
/**
* Export the categories using flatten json (no embedded dictionaries or arrays).
*/
public static void exportCategoriesToFlatJson(@Nullable Context dialogContext,
@NonNull JSONObject json) throws JSONException {
ReVancedUtils.verifyOnMainThread();
initialize();
// If user has a SponsorBlock user id then show a warning.
if (dialogContext != null && SponsorBlockSettings.userHasSBPrivateId()
&& !SettingsEnum.SB_HIDE_EXPORT_WARNING.getBoolean()) {
new AlertDialog.Builder(dialogContext)
.setMessage(str("sb_settings_revanced_export_user_id_warning"))
.setNeutralButton(str("sb_settings_revanced_export_user_id_warning_dismiss"),
(dialog, which) -> SettingsEnum.SB_HIDE_EXPORT_WARNING.saveValue(true))
.setPositiveButton(android.R.string.ok, null)
.setCancelable(false)
.show();
}
for (SegmentCategory category : SegmentCategory.categoriesWithoutUnsubmitted()) {
category.exportToFlatJSON(json);
}
}
/**
* Import the categories using flatten json (no embedded dictionaries or arrays).
*
* @return the number of settings imported
*/
public static int importCategoriesFromFlatJson(JSONObject json) throws JSONException {
ReVancedUtils.verifyOnMainThread();
initialize();
int numberOfImportedSettings = 0;
SharedPreferences.Editor editor = SharedPrefCategory.SPONSOR_BLOCK.preferences.edit();
for (SegmentCategory category : SegmentCategory.categoriesWithoutUnsubmitted()) {
numberOfImportedSettings += category.importFromFlatJSON(json, editor);
}
editor.apply();
SegmentCategory.updateEnabledCategories();
return numberOfImportedSettings;
}
public static boolean isValidSBUserId(@NonNull String userId) {
return !userId.isEmpty();
return !userId.isEmpty() && userId.length() >= SB_PRIVATE_USER_ID_MINIMUM_LENGTH;
}
/**
@ -180,6 +235,29 @@ public class SponsorBlockSettings {
return true;
}
/**
* @return if the user has ever voted, created a segment, or imported existing SB settings.
*/
public static boolean userHasSBPrivateId() {
return !SettingsEnum.SB_PRIVATE_USER_ID.getString().isEmpty();
}
/**
* Use this only if a user id is required (creating segments, voting).
*/
@NonNull
public static String getSBPrivateUserID() {
String uuid = SettingsEnum.SB_PRIVATE_USER_ID.getString();
if (uuid.isEmpty()) {
uuid = (UUID.randomUUID().toString() +
UUID.randomUUID().toString() +
UUID.randomUUID().toString())
.replace("-", "");
SettingsEnum.SB_PRIVATE_USER_ID.saveValue(uuid);
}
return uuid;
}
private static boolean initialized;
public static void initialize() {
@ -188,15 +266,6 @@ public class SponsorBlockSettings {
}
initialized = true;
String uuid = SettingsEnum.SB_UUID.getString();
if (uuid.isEmpty()) {
uuid = (UUID.randomUUID().toString() +
UUID.randomUUID().toString() +
UUID.randomUUID().toString())
.replace("-", "");
SettingsEnum.SB_UUID.saveValue(uuid);
}
SegmentCategory.loadFromPreferences();
}
}

View File

@ -172,7 +172,7 @@ public class SponsorBlockUtils {
for (int i = 0; i < voteOptions.length; i++) {
SegmentVote voteOption = voteOptions[i];
String title = voteOption.title.toString();
if (SettingsEnum.SB_IS_VIP.getBoolean() && segment.isLocked && voteOption.shouldHighlight) {
if (SettingsEnum.SB_USER_IS_VIP.getBoolean() && segment.isLocked && voteOption.shouldHighlight) {
items[i] = Html.fromHtml(String.format("<font color=\"%s\">%s</font>", LOCKED_COLOR, title));
} else {
items[i] = title;
@ -214,20 +214,18 @@ public class SponsorBlockUtils {
private static void submitNewSegment() {
try {
ReVancedUtils.verifyOnMainThread();
final String uuid = SettingsEnum.SB_UUID.getString();
final long start = newSponsorSegmentStartMillis;
final long end = newSponsorSegmentEndMillis;
final String videoId = VideoInformation.getVideoId();
final long videoLength = VideoInformation.getVideoLength();
final SegmentCategory segmentCategory = newUserCreatedSegmentCategory;
if (start < 0 || end < 0 || start >= end || videoLength <= 0 || videoId.isEmpty()
|| segmentCategory == null || uuid.isEmpty()) {
if (start < 0 || end < 0 || start >= end || videoLength <= 0 || videoId.isEmpty() || segmentCategory == null) {
LogHelper.printException(() -> "invalid parameters");
return;
}
clearUnsubmittedSegmentTimes();
ReVancedUtils.runOnBackgroundThread(() -> {
SBRequester.submitSegments(uuid, videoId, segmentCategory.key, start, end, videoLength);
SBRequester.submitSegments(videoId, segmentCategory.key, start, end, videoLength);
SegmentPlaybackController.executeDownloadSegments(videoId);
});
} catch (Exception e) {
@ -380,9 +378,9 @@ public class SponsorBlockUtils {
return;
}
segment.recordedAsSkipped = true;
final long totalTimeSkipped = SettingsEnum.SB_SKIPPED_SEGMENTS_TIME_SAVED.getLong() + segment.length();
SettingsEnum.SB_SKIPPED_SEGMENTS_TIME_SAVED.saveValue(totalTimeSkipped);
SettingsEnum.SB_SKIPPED_SEGMENTS_NUMBER_SKIPPED.saveValue(SettingsEnum.SB_SKIPPED_SEGMENTS_NUMBER_SKIPPED.getInt() + 1);
final long totalTimeSkipped = SettingsEnum.SB_LOCAL_TIME_SAVED_MILLISECONDS.getLong() + segment.length();
SettingsEnum.SB_LOCAL_TIME_SAVED_MILLISECONDS.saveValue(totalTimeSkipped);
SettingsEnum.SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS.saveValue(SettingsEnum.SB_LOCAL_TIME_SAVED_NUMBER_SEGMENTS.getInt() + 1);
if (SettingsEnum.SB_TRACK_SKIP_COUNT.getBoolean()) {
ReVancedUtils.runOnBackgroundThread(() -> SBRequester.sendSegmentSkippedViewedRequest(segment));

View File

@ -16,6 +16,9 @@ import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -59,6 +62,11 @@ public enum SegmentCategory {
private static final StringRef skipSponsorTextCompact = sf("sb_skip_button_compact");
private static final StringRef skipSponsorTextCompactHighlight = sf("sb_skip_button_compact_highlight");
/**
* Prefix to use when serializing to flat JSON layout used with ReVanced import/export.
*/
private static final String FLAT_JSON_IMPORT_EXPORT_PREFIX = "sb_";
private static final SegmentCategory[] categoriesWithoutHighlights = new SegmentCategory[]{
SPONSOR,
SELF_PROMO,
@ -189,6 +197,8 @@ public enum SegmentCategory {
*/
@NonNull
public CategoryBehaviour behaviour;
@NonNull
public final CategoryBehaviour defaultBehaviour;
SegmentCategory(String key, StringRef title, StringRef description,
StringRef skipButtonText,
@ -213,7 +223,7 @@ public enum SegmentCategory {
this.skippedToastBeginning = Objects.requireNonNull(skippedToastBeginning);
this.skippedToastMiddle = Objects.requireNonNull(skippedToastMiddle);
this.skippedToastEnd = Objects.requireNonNull(skippedToastEnd);
this.behaviour = Objects.requireNonNull(defaultBehavior);
this.behaviour = this.defaultBehaviour = Objects.requireNonNull(defaultBehavior);
this.color = this.defaultColor = defaultColor;
this.paint = new Paint();
setColor(defaultColor);
@ -231,10 +241,13 @@ public enum SegmentCategory {
}
String behaviorString = preferences.getString(key, null);
if (behaviorString != null) {
if (behaviorString == null) {
behaviour = defaultBehaviour;
} else {
CategoryBehaviour preferenceBehavior = CategoryBehaviour.byStringKey(behaviorString);
if (preferenceBehavior == null) {
LogHelper.printException(() -> "Unknown behavior: " + behaviorString); // should never happen
behaviour = defaultBehaviour;
} else {
behaviour = preferenceBehavior;
}
@ -253,6 +266,50 @@ public enum SegmentCategory {
editor.putString(key, behaviour.key);
}
private String getFlatJsonBehaviorKey() {
return FLAT_JSON_IMPORT_EXPORT_PREFIX + key;
}
private String getFlatJsonColorKey() {
return FLAT_JSON_IMPORT_EXPORT_PREFIX + key + COLOR_PREFERENCE_KEY_SUFFIX;
}
public void exportToFlatJSON(JSONObject json) throws JSONException {
if (behaviour != defaultBehaviour) {
json.put(getFlatJsonBehaviorKey(), behaviour.key);
}
if (color != defaultColor) {
json.put(getFlatJsonColorKey(), colorString());
}
}
/**
* Calling code is responsible for calling {@link #updateEnabledCategories()} and {@link SharedPreferences.Editor#apply()}
*/
public int importFromFlatJSON(JSONObject json, SharedPreferences.Editor editor) throws JSONException {
int numberOfSettingsImported = 0;
String behaviorKey = getFlatJsonBehaviorKey();
if (json.has(behaviorKey)) {
String behaviorString = json.getString(behaviorKey);
CategoryBehaviour importedBehavior = CategoryBehaviour.byStringKey(behaviorString);
if (importedBehavior == null) {
throw new IllegalArgumentException("unknown behavior: " + behaviorString);
}
behaviour = importedBehavior;
numberOfSettingsImported++;
} else {
behaviour = defaultBehaviour;
}
String colorKey = getFlatJsonColorKey();
if (json.has(colorKey)) {
setColor(json.getString(colorKey));
numberOfSettingsImported++;
} else {
color = defaultColor;
}
save(editor);
return numberOfSettingsImported;
}
/**
* @return HTML color format string
*/
@ -300,7 +357,7 @@ public enum SegmentCategory {
*/
@NonNull
StringRef getSkipButtonText(long segmentStartTime, long videoLength) {
if (SettingsEnum.SB_USE_COMPACT_SKIP_BUTTON.getBoolean()) {
if (SettingsEnum.SB_COMPACT_SKIP_BUTTON.getBoolean()) {
return (this == SegmentCategory.HIGHLIGHT)
? skipSponsorTextCompactHighlight
: skipSponsorTextCompact;

View File

@ -17,7 +17,12 @@ public class UserStats {
* "User reputation". Unclear how SB determines this value.
*/
public final float reputation;
/**
* {@link #segmentCount} plus {@link #ignoredSegmentCount}
*/
public final int totalSegmentCountIncludingIgnored;
public final int segmentCount;
public final int ignoredSegmentCount;
public final int viewCount;
public final double minutesSaved;
@ -26,6 +31,8 @@ public class UserStats {
userName = json.getString("userName");
reputation = (float)json.getDouble("reputation");
segmentCount = json.getInt("segmentCount");
ignoredSegmentCount = json.getInt("ignoredSegmentCount");
totalSegmentCountIncludingIgnored = segmentCount + ignoredSegmentCount;
viewCount = json.getInt("viewCount");
minutesSaved = json.getDouble("minutesSaved");
}
@ -38,6 +45,7 @@ public class UserStats {
+ ", userName='" + userName + '\''
+ ", reputation=" + reputation
+ ", segmentCount=" + segmentCount
+ ", ignoredSegmentCount=" + ignoredSegmentCount
+ ", viewCount=" + viewCount
+ ", minutesSaved=" + minutesSaved
+ '}';

View File

@ -20,7 +20,7 @@ import java.util.concurrent.TimeUnit;
import app.revanced.integrations.requests.Requester;
import app.revanced.integrations.requests.Route;
import app.revanced.integrations.settings.SettingsEnum;
import app.revanced.integrations.sponsorblock.objects.CategoryBehaviour;
import app.revanced.integrations.sponsorblock.SponsorBlockSettings;
import app.revanced.integrations.sponsorblock.objects.SegmentCategory;
import app.revanced.integrations.sponsorblock.objects.SponsorSegment;
import app.revanced.integrations.sponsorblock.objects.SponsorSegment.SegmentVote;
@ -59,7 +59,7 @@ public class SBRequester {
if (responseCode == HTTP_STATUS_CODE_SUCCESS) {
JSONArray responseArray = Requester.parseJSONArray(connection);
final long minSegmentDuration = (long) (SettingsEnum.SB_MIN_DURATION.getFloat() * 1000);
final long minSegmentDuration = (long) (SettingsEnum.SB_SEGMENT_MIN_DURATION.getFloat() * 1000);
for (int i = 0, length = responseArray.length(); i < length; i++) {
JSONObject obj = (JSONObject) responseArray.get(i);
JSONArray segment = obj.getJSONArray("segment");
@ -127,15 +127,16 @@ public class SBRequester {
return segments.toArray(new SponsorSegment[0]);
}
public static void submitSegments(@NonNull String userPrivateId, @NonNull String videoId, @NonNull String category,
public static void submitSegments(@NonNull String videoId, @NonNull String category,
long startTime, long endTime, long videoLength) {
ReVancedUtils.verifyOffMainThread();
try {
String privateUserId = SponsorBlockSettings.getSBPrivateUserID();
String start = String.format(Locale.US, TIME_TEMPLATE, startTime / 1000f);
String end = String.format(Locale.US, TIME_TEMPLATE, endTime / 1000f);
String duration = String.format(Locale.US, TIME_TEMPLATE, videoLength / 1000f);
HttpURLConnection connection = getConnectionFromRoute(SBRoutes.SUBMIT_SEGMENTS, userPrivateId, videoId, category, start, end, duration);
HttpURLConnection connection = getConnectionFromRoute(SBRoutes.SUBMIT_SEGMENTS, privateUserId, videoId, category, start, end, duration);
final int responseCode = connection.getResponseCode();
final String messageToToast;
@ -196,7 +197,7 @@ public class SBRequester {
ReVancedUtils.runOnBackgroundThread(() -> {
try {
String segmentUuid = segment.UUID;
String uuid = SettingsEnum.SB_UUID.getString();
String uuid = SponsorBlockSettings.getSBPrivateUserID();
HttpURLConnection connection = (voteOption == SegmentVote.CATEGORY_CHANGE)
? getConnectionFromRoute(SBRoutes.VOTE_ON_SEGMENT_CATEGORY, uuid, segmentUuid, categoryToVoteFor.key)
: getConnectionFromRoute(SBRoutes.VOTE_ON_SEGMENT_QUALITY, uuid, segmentUuid, String.valueOf(voteOption.apiVoteType));
@ -230,7 +231,7 @@ public class SBRequester {
public static UserStats retrieveUserStats() {
ReVancedUtils.verifyOffMainThread();
try {
UserStats stats = new UserStats(getJSONObject(SBRoutes.GET_USER_STATS, SettingsEnum.SB_UUID.getString()));
UserStats stats = new UserStats(getJSONObject(SBRoutes.GET_USER_STATS, SponsorBlockSettings.getSBPrivateUserID()));
LogHelper.printDebug(() -> "user stats: " + stats);
return stats;
} catch (IOException ex) {
@ -248,7 +249,7 @@ public class SBRequester {
public static String setUsername(@NonNull String username) {
ReVancedUtils.verifyOffMainThread();
try {
HttpURLConnection connection = getConnectionFromRoute(SBRoutes.CHANGE_USERNAME, SettingsEnum.SB_UUID.getString(), username);
HttpURLConnection connection = getConnectionFromRoute(SBRoutes.CHANGE_USERNAME, SponsorBlockSettings.getSBPrivateUserID(), username);
final int responseCode = connection.getResponseCode();
String responseMessage = connection.getResponseMessage();
if (responseCode == HTTP_STATUS_CODE_SUCCESS) {
@ -262,15 +263,18 @@ public class SBRequester {
}
public static void runVipCheckInBackgroundIfNeeded() {
if (!SponsorBlockSettings.userHasSBPrivateId()) {
return; // User cannot be a VIP. User has never voted, created any segments, and has not import any SB settings.
}
long now = System.currentTimeMillis();
if (now < (SettingsEnum.SB_LAST_VIP_CHECK.getLong() + TimeUnit.DAYS.toMillis(3))) {
return;
}
ReVancedUtils.runOnBackgroundThread(() -> {
try {
JSONObject json = getJSONObject(SBRoutes.IS_USER_VIP, SettingsEnum.SB_UUID.getString());
JSONObject json = getJSONObject(SBRoutes.IS_USER_VIP, SponsorBlockSettings.getSBPrivateUserID());
boolean vip = json.getBoolean("vip");
SettingsEnum.SB_IS_VIP.saveValue(vip);
SettingsEnum.SB_USER_IS_VIP.saveValue(vip);
SettingsEnum.SB_LAST_VIP_CHECK.saveValue(now);
} catch (IOException ex) {
LogHelper.printInfo(() -> "Failed to check VIP (network error)", ex); // info, so no error toast is shown

View File

@ -9,7 +9,7 @@ class SBRoutes {
static final Route IS_USER_VIP = new Route(GET, "/api/isUserVIP?userID={user_id}");
static final Route GET_SEGMENTS = new Route(GET, "/api/skipSegments?videoID={video_id}&categories={categories}");
static final Route VIEWED_SEGMENT = new Route(POST, "/api/viewedVideoSponsorTime?UUID={segment_id}");
static final Route GET_USER_STATS = new Route(GET, "/api/userInfo?userID={user_id}&values=[\"userID\",\"userName\",\"reputation\",\"segmentCount\",\"viewCount\",\"minutesSaved\"]");
static final Route GET_USER_STATS = new Route(GET, "/api/userInfo?userID={user_id}&values=[\"userID\",\"userName\",\"reputation\",\"segmentCount\",\"ignoredSegmentCount\",\"viewCount\",\"minutesSaved\"]");
static final Route CHANGE_USERNAME = new Route(POST, "/api/setUsername?userID={user_id}&username={username}");
static final Route SUBMIT_SEGMENTS = new Route(POST, "/api/skipSegments?userID={user_id}&videoID={video_id}&category={category}&startTime={start_time}&endTime={end_time}&videoDuration={duration}");
static final Route VOTE_ON_SEGMENT_QUALITY = new Route(POST, "/api/voteOnSponsorTime?userID={user_id}&UUID={segment_id}&type={type}");

View File

@ -88,7 +88,7 @@ public class CreateSegmentButtonController {
}
private static boolean shouldBeShown() {
return SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_CREATE_NEW_SEGMENT_ENABLED.getBoolean()
return SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_CREATE_NEW_SEGMENT.getBoolean()
&& !VideoInformation.isAtEndOfVideo();
}

View File

@ -53,14 +53,14 @@ public final class NewSegmentLayout extends FrameLayout {
initializeButton(
context,
"sb_new_segment_rewind",
() -> VideoInformation.seekToRelative(-SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getInt()),
() -> VideoInformation.seekToRelative(-SettingsEnum.SB_CREATE_NEW_SEGMENT_STEP.getInt()),
"Rewind button clicked"
);
initializeButton(
context,
"sb_new_segment_forward",
() -> VideoInformation.seekToRelative(SettingsEnum.SB_ADJUST_NEW_SEGMENT_STEP.getInt()),
() -> VideoInformation.seekToRelative(SettingsEnum.SB_CREATE_NEW_SEGMENT_STEP.getInt()),
"Forward button clicked"
);

View File

@ -213,7 +213,7 @@ public class SponsorBlockViewController {
// the buttons automatically set themselves to visible when appropriate,
// but if buttons are showing when the end of the video is reached then they need
// to be forcefully hidden
if (!SettingsEnum.PREFERRED_AUTO_REPEAT.getBoolean()) {
if (!SettingsEnum.AUTO_REPEAT.getBoolean()) {
CreateSegmentButtonController.hide();
VotingButtonController.hide();
}

View File

@ -90,7 +90,7 @@ public class VotingButtonController {
}
private static boolean shouldBeShown() {
return SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_VOTING_ENABLED.getBoolean()
return SettingsEnum.SB_ENABLED.getBoolean() && SettingsEnum.SB_VOTING_BUTTON.getBoolean()
&& SegmentPlaybackController.videoHasSegments() && !VideoInformation.isAtEndOfVideo();
}

View File

@ -24,13 +24,13 @@ class SwipeControlsConfigurationProvider(
* should swipe controls for volume be enabled?
*/
val enableVolumeControls: Boolean
get() = SettingsEnum.ENABLE_SWIPE_VOLUME.boolean
get() = SettingsEnum.SWIPE_VOLUME.boolean
/**
* should swipe controls for volume be enabled?
*/
val enableBrightnessControl: Boolean
get() = SettingsEnum.ENABLE_SWIPE_BRIGHTNESS.boolean
get() = SettingsEnum.SWIPE_BRIGHTNESS.boolean
/**
* is the video player currently in fullscreen mode?
@ -52,14 +52,14 @@ class SwipeControlsConfigurationProvider(
* should press-to-swipe be enabled?
*/
val shouldEnablePressToSwipe: Boolean
get() = SettingsEnum.ENABLE_PRESS_TO_SWIPE.boolean
get() = SettingsEnum.SWIPE_PRESS_TO_ENGAGE.boolean
/**
* threshold for swipe detection
* this may be called rapidly in onScroll, so we have to load it once and then leave it constant
*/
val swipeMagnitudeThreshold: Float
get() = SettingsEnum.SWIPE_MAGNITUDE_THRESHOLD.float
val swipeMagnitudeThreshold: Int
get() = SettingsEnum.SWIPE_MAGNITUDE_THRESHOLD.int
//endregion
//region overlay adjustments
@ -68,7 +68,7 @@ class SwipeControlsConfigurationProvider(
* should the overlay enable haptic feedback?
*/
val shouldEnableHapticFeedback: Boolean
get() = SettingsEnum.ENABLE_SWIPE_HAPTIC_FEEDBACK.boolean
get() = SettingsEnum.SWIPE_HAPTIC_FEEDBACK.boolean
/**
* how long the overlay should be shown on changes
@ -79,8 +79,8 @@ class SwipeControlsConfigurationProvider(
/**
* text size for the overlay, in sp
*/
val overlayTextSize: Float
get() = SettingsEnum.SWIPE_OVERLAY_TEXT_SIZE.float
val overlayTextSize: Int
get() = SettingsEnum.SWIPE_OVERLAY_TEXT_SIZE.int
/**
* get the background color for text on the overlay, as a color int

View File

@ -74,7 +74,7 @@ class SwipeControlsOverlayLayout(
setColor(config.overlayTextBackgroundColor)
}
setTextColor(config.overlayForegroundColor)
setTextSize(TypedValue.COMPLEX_UNIT_SP, config.overlayTextSize)
setTextSize(TypedValue.COMPLEX_UNIT_SP, config.overlayTextSize.toFloat())
compoundDrawablePadding = compoundIconPadding
visibility = GONE
}

View File

@ -125,7 +125,7 @@ public class LogHelper {
} else {
Log.e(logMessage, messageString, ex);
}
if (SettingsEnum.DEBUG_SHOW_TOAST_ON_ERROR.getBoolean()) {
if (SettingsEnum.DEBUG_TOAST_ON_ERROR.getBoolean()) {
String toastMessageToDisplay = (userToastMessage != null)
? userToastMessage
: outerClassSimpleName + ": " + messageString;

View File

@ -16,7 +16,7 @@ public class CopyVideoUrlButton extends BottomControlButton {
super(
viewGroup,
"copy_video_url_button",
SettingsEnum.COPY_VIDEO_URL_BUTTON_SHOWN,
SettingsEnum.COPY_VIDEO_URL,
view -> CopyVideoUrlPatch.copyUrl(false)
);
}

View File

@ -16,7 +16,7 @@ public class CopyVideoUrlTimestampButton extends BottomControlButton {
super(
bottomControlsViewGroup,
"copy_video_url_timestamp_button",
SettingsEnum.COPY_VIDEO_URL_TIMESTAMP_BUTTON_SHOWN,
SettingsEnum.COPY_VIDEO_URL_TIMESTAMP,
view -> CopyVideoUrlPatch.copyUrl(true)
);
}

View File

@ -21,7 +21,7 @@ public class DownloadButton extends BottomControlButton {
super(
viewGroup,
"download_button",
SettingsEnum.DOWNLOADS_BUTTON_SHOWN,
SettingsEnum.EXTERNAL_DOWNLOADER,
DownloadButton::onDownloadClick
);
}
@ -48,7 +48,7 @@ public class DownloadButton extends BottomControlButton {
LogHelper.printDebug(() -> "Download button clicked");
final var context = view.getContext();
var downloaderPackageName = SettingsEnum.DOWNLOADS_PACKAGE_NAME.getString();
var downloaderPackageName = SettingsEnum.EXTERNAL_DOWNLOADER_PACKAGE_NAME.getString();
boolean packageEnabled = false;
try {

View File

@ -154,6 +154,14 @@ public enum SettingsEnum {
return (String) value;
}
/**
* @return the value of this setting as as generic object type.
*/
@NonNull
public Object getObjectValue() {
return value;
}
public enum ReturnType {
BOOLEAN,
INTEGER,

View File

@ -88,7 +88,23 @@ public class ReVancedSettingsFragment extends PreferenceFragment {
)
);
// Sync all preferences with UI
// TODO: for a developer that uses Twitch: remove duplicated settings data
// 1. remove all default values from the Patches Setting preferences (SwitchPreference, TextPreference, ListPreference)
// 2. enable this code and verify the default is applied
if (false) {
for (SettingsEnum setting : SettingsEnum.values()) {
Preference pref = this.findPreference(setting.path);
if (pref instanceof SwitchPreference) {
((SwitchPreference) pref).setChecked(setting.getBoolean());
} else if (pref instanceof EditTextPreference) {
((EditTextPreference) pref).setText(setting.getObjectValue().toString());
} else if (pref instanceof ListPreference) {
((ListPreference) pref).setValue(setting.getObjectValue().toString());
}
}
}
// TODO: remove this line. On load the UI should apply the values from Settings using the code above.
// It should not apply the UI values to the Settings here
syncPreference(null);
this.registered = true;