From 6e8ffbade9e03658f725622631e44dabf2995861 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Wed, 19 Mar 2025 18:02:06 +0100 Subject: [PATCH] feat(YouTube - SponsorBlock): Add opacity setting to category segment colors (#4582) --- .../ResettableEditTextPreference.java | 31 ++- .../extension/youtube/settings/Settings.java | 10 + ...eturnYouTubeDislikePreferenceFragment.java | 3 + .../SponsorBlockPreferenceFragment.java | 25 ++- .../sponsorblock/SponsorBlockSettings.java | 2 +- .../sponsorblock/SponsorBlockUtils.java | 91 ++++---- .../sponsorblock/objects/SegmentCategory.java | 171 +++++++++------ .../SegmentCategoryListPreference.java | 204 ++++++++++++++---- .../sponsorblock/objects/SponsorSegment.java | 9 +- .../resources/addresources/values/strings.xml | 3 + 10 files changed, 382 insertions(+), 167 deletions(-) diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ResettableEditTextPreference.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ResettableEditTextPreference.java index 3e9a96961..98f4a715f 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ResettableEditTextPreference.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ResettableEditTextPreference.java @@ -1,5 +1,7 @@ package app.revanced.extension.shared.settings.preference; +import static app.revanced.extension.shared.StringRef.str; + import android.app.AlertDialog; import android.content.Context; import android.os.Bundle; @@ -8,17 +10,23 @@ import android.util.AttributeSet; import android.widget.Button; import android.widget.EditText; -import app.revanced.extension.shared.Utils; -import app.revanced.extension.shared.settings.Setting; -import app.revanced.extension.shared.Logger; +import androidx.annotation.Nullable; import java.util.Objects; -import static app.revanced.extension.shared.StringRef.str; +import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.Utils; +import app.revanced.extension.shared.settings.Setting; @SuppressWarnings({"unused", "deprecation"}) public class ResettableEditTextPreference extends EditTextPreference { + /** + * Setting to reset. + */ + @Nullable + private Setting setting; + public ResettableEditTextPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } @@ -32,12 +40,22 @@ public class ResettableEditTextPreference extends EditTextPreference { super(context); } + public void setSetting(@Nullable Setting setting) { + this.setting = setting; + } + @Override protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { super.onPrepareDialogBuilder(builder); Utils.setEditTextDialogTheme(builder); - Setting setting = Setting.getSettingFromPath(getKey()); + if (setting == null) { + String key = getKey(); + if (key != null) { + setting = Setting.getSettingFromPath(key); + } + } + if (setting != null) { builder.setNeutralButton(str("revanced_settings_reset"), null); } @@ -54,8 +72,7 @@ public class ResettableEditTextPreference extends EditTextPreference { } button.setOnClickListener(v -> { try { - Setting setting = Objects.requireNonNull(Setting.getSettingFromPath(getKey())); - String defaultStringValue = setting.defaultValue.toString(); + String defaultStringValue = Objects.requireNonNull(setting).defaultValue.toString(); EditText editText = getEditText(); editText.setText(defaultStringValue); editText.setSelection(defaultStringValue.length()); // move cursor to end of text diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 954d75bb6..c0c20842b 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -365,24 +365,34 @@ public class Settings extends BaseSettings { public static final BooleanSetting SB_SEEN_GUIDELINES = new BooleanSetting("sb_seen_guidelines", FALSE, false, false); public static final StringSetting SB_CATEGORY_SPONSOR = new StringSetting("sb_sponsor", SKIP_AUTOMATICALLY_ONCE.reVancedKeyValue); public static final StringSetting SB_CATEGORY_SPONSOR_COLOR = new StringSetting("sb_sponsor_color", "#00D400"); + public static final FloatSetting SB_CATEGORY_SPONSOR_OPACITY = new FloatSetting("sb_sponsor_opacity", 0.8f); public static final StringSetting SB_CATEGORY_SELF_PROMO = new StringSetting("sb_selfpromo", MANUAL_SKIP.reVancedKeyValue); public static final StringSetting SB_CATEGORY_SELF_PROMO_COLOR = new StringSetting("sb_selfpromo_color", "#FFFF00"); + public static final FloatSetting SB_CATEGORY_SELF_PROMO_OPACITY = new FloatSetting("sb_selfpromo_opacity", 0.8f); public static final StringSetting SB_CATEGORY_INTERACTION = new StringSetting("sb_interaction", MANUAL_SKIP.reVancedKeyValue); public static final StringSetting SB_CATEGORY_INTERACTION_COLOR = new StringSetting("sb_interaction_color", "#CC00FF"); + public static final FloatSetting SB_CATEGORY_INTERACTION_OPACITY = new FloatSetting("sb_interaction_opacity", 0.8f); public static final StringSetting SB_CATEGORY_HIGHLIGHT = new StringSetting("sb_highlight", MANUAL_SKIP.reVancedKeyValue); public static final StringSetting SB_CATEGORY_HIGHLIGHT_COLOR = new StringSetting("sb_highlight_color", "#FF1684"); + public static final FloatSetting SB_CATEGORY_HIGHLIGHT_OPACITY = new FloatSetting("sb_highlight_opacity", 0.8f); public static final StringSetting SB_CATEGORY_INTRO = new StringSetting("sb_intro", MANUAL_SKIP.reVancedKeyValue); public static final StringSetting SB_CATEGORY_INTRO_COLOR = new StringSetting("sb_intro_color", "#00FFFF"); + public static final FloatSetting SB_CATEGORY_INTRO_OPACITY = new FloatSetting("sb_intro_opacity", 0.8f); public static final StringSetting SB_CATEGORY_OUTRO = new StringSetting("sb_outro", MANUAL_SKIP.reVancedKeyValue); public static final StringSetting SB_CATEGORY_OUTRO_COLOR = new StringSetting("sb_outro_color", "#0202ED"); + public static final FloatSetting SB_CATEGORY_OUTRO_OPACITY = new FloatSetting("sb_outro_opacity", 0.8f); public static final StringSetting SB_CATEGORY_PREVIEW = new StringSetting("sb_preview", IGNORE.reVancedKeyValue); public static final StringSetting SB_CATEGORY_PREVIEW_COLOR = new StringSetting("sb_preview_color", "#008FD6"); + public static final FloatSetting SB_CATEGORY_PREVIEW_OPACITY = new FloatSetting("sb_preview_opacity", 0.8f); public static final StringSetting SB_CATEGORY_FILLER = new StringSetting("sb_filler", IGNORE.reVancedKeyValue); public static final StringSetting SB_CATEGORY_FILLER_COLOR = new StringSetting("sb_filler_color", "#7300FF"); + public static final FloatSetting SB_CATEGORY_FILLER_OPACITY = new FloatSetting("sb_filler_opacity", 0.8f); public static final StringSetting SB_CATEGORY_MUSIC_OFFTOPIC = new StringSetting("sb_music_offtopic", MANUAL_SKIP.reVancedKeyValue); public static final StringSetting SB_CATEGORY_MUSIC_OFFTOPIC_COLOR = new StringSetting("sb_music_offtopic_color", "#FF9900"); + public static final FloatSetting SB_CATEGORY_MUSIC_OFFTOPIC_OPACITY = new FloatSetting("sb_music_offtopic_opacity", 0.8f); public static final StringSetting SB_CATEGORY_UNSUBMITTED = new StringSetting("sb_unsubmitted", SKIP_AUTOMATICALLY.reVancedKeyValue); public static final StringSetting SB_CATEGORY_UNSUBMITTED_COLOR = new StringSetting("sb_unsubmitted_color", "#FFFFFF"); + public static final FloatSetting SB_CATEGORY_UNSUBMITTED_OPACITY = new FloatSetting("sb_unsubmitted_opacity", 1.0f); // Deprecated migrations private static final StringSetting DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING = new StringSetting("uuid", ""); // Delete sometime in 2024 diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReturnYouTubeDislikePreferenceFragment.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReturnYouTubeDislikePreferenceFragment.java index 5e234ec28..7c367f87b 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReturnYouTubeDislikePreferenceFragment.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/ReturnYouTubeDislikePreferenceFragment.java @@ -14,6 +14,7 @@ import android.preference.PreferenceScreen; import android.preference.SwitchPreference; import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.youtube.patches.ReturnYouTubeDislikePatch; @@ -237,6 +238,8 @@ public class ReturnYouTubeDislikePreferenceFragment extends PreferenceFragment { "revanced_ryd_statistics_getNumberOfRateLimitRequestsEncountered_non_zero_summary")); preferenceScreen.addPreference(statisticPreference); } + + Utils.setPreferenceTitlesToMultiLineIfNeeded(preferenceScreen); } catch (Exception ex) { Logger.printException(() -> "onCreate failure", ex); } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SponsorBlockPreferenceFragment.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SponsorBlockPreferenceFragment.java index 18cf149dc..751125274 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SponsorBlockPreferenceFragment.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SponsorBlockPreferenceFragment.java @@ -17,6 +17,7 @@ import androidx.annotation.Nullable; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.Setting; +import app.revanced.extension.shared.settings.preference.ResettableEditTextPreference; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController; import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings; @@ -44,8 +45,8 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment { private SwitchPreference showTimeWithoutSegments; private SwitchPreference toastOnConnectionError; - private EditTextPreference newSegmentStep; - private EditTextPreference minSegmentDuration; + private ResettableEditTextPreference newSegmentStep; + private ResettableEditTextPreference minSegmentDuration; private EditTextPreference privateUserId; private EditTextPreference importExport; private Preference apiUrl; @@ -159,6 +160,8 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment { addAboutCategory(context, preferenceScreen); + Utils.setPreferenceTitlesToMultiLineIfNeeded(preferenceScreen); + updateUI(); } catch (Exception ex) { Logger.printException(() -> "onCreate failure", ex); @@ -268,7 +271,8 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment { return true; }); - newSegmentStep = new EditTextPreference(context); + newSegmentStep = new ResettableEditTextPreference(context); + newSegmentStep.setSetting(Settings.SB_CREATE_NEW_SEGMENT_STEP); newSegmentStep.setTitle(str("revanced_sb_general_adjusting")); newSegmentStep.setSummary(str("revanced_sb_general_adjusting_sum")); newSegmentStep.getEditText().setInputType(InputType.TYPE_CLASS_NUMBER); @@ -326,7 +330,8 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment { }); category.addPreference(trackSkips); - minSegmentDuration = new EditTextPreference(context); + minSegmentDuration = new ResettableEditTextPreference(context); + minSegmentDuration.setSetting(Settings.SB_SEGMENT_MIN_DURATION); minSegmentDuration.setTitle(str("revanced_sb_general_min_duration")); minSegmentDuration.setSummary(str("revanced_sb_general_min_duration_sum")); minSegmentDuration.getEditText().setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); @@ -345,7 +350,15 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment { }); category.addPreference(minSegmentDuration); - privateUserId = new EditTextPreference(context); + privateUserId = new EditTextPreference(context) { + protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { + Utils.setEditTextDialogTheme(builder); + + builder.setNeutralButton(str("revanced_sb_settings_copy"), (dialog, which) -> { + Utils.setClipboard(getEditText().getText().toString()); + }); + } + }; privateUserId.setTitle(str("revanced_sb_general_uuid")); privateUserId.setSummary(str("revanced_sb_general_uuid_sum")); privateUserId.setOnPreferenceChangeListener((preference1, newValue) -> { @@ -504,7 +517,7 @@ public class SponsorBlockPreferenceFragment extends PreferenceFragment { if (stats.totalSegmentCountIncludingIgnored > 0) { // If user has not created any segments, there's no reason to set a username. - EditTextPreference preference = new EditTextPreference(context); + EditTextPreference preference = new ResettableEditTextPreference(context); statsCategory.addPreference(preference); String userName = stats.userName; preference.setTitle(fromHtml(str("revanced_sb_stats_username", userName))); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockSettings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockSettings.java index 45739f267..e8d64fb50 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockSettings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockSettings.java @@ -136,7 +136,7 @@ public class SponsorBlockSettings { for (SegmentCategory category : categories) { JSONObject categoryObject = new JSONObject(); String categoryKey = category.keyValue; - categoryObject.put("color", category.colorString()); + categoryObject.put("color", category.getColorString()); barTypesObject.put(categoryKey, categoryObject); if (category.behaviour != CategoryBehaviour.IGNORE) { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockUtils.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockUtils.java index 3fdfe1f9f..5edccbacd 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockUtils.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/SponsorBlockUtils.java @@ -5,7 +5,12 @@ import static app.revanced.extension.shared.StringRef.str; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; -import android.text.Html; +import android.graphics.Color; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.style.ForegroundColorSpan; +import android.text.style.StyleSpan; import android.widget.EditText; import androidx.annotation.NonNull; @@ -33,7 +38,7 @@ import app.revanced.extension.youtube.sponsorblock.ui.SponsorBlockViewController * Not thread safe. All fields/methods must be accessed from the main thread. */ public class SponsorBlockUtils { - private static final String LOCKED_COLOR = "#FFC83D"; + private static final int LOCKED_COLOR = Color.parseColor("#FFC83D"); private static final String MANUAL_EDIT_TIME_TEXT_HINT = "hh:mm:ss.sss"; private static final Pattern manualEditTimePattern = Pattern.compile("((\\d{1,2}):)?(\\d{1,2}):(\\d{2})(\\.(\\d{1,3}))?"); @@ -160,32 +165,34 @@ public class SponsorBlockUtils { SegmentVote[] voteOptions = (segment.category == SegmentCategory.HIGHLIGHT) ? SegmentVote.voteTypesWithoutCategoryChange // highlight segments cannot change category : SegmentVote.values(); - CharSequence[] items = new CharSequence[voteOptions.length]; + final int voteOptionsLength = voteOptions.length; + final boolean userIsVip = Settings.SB_USER_IS_VIP.get(); + CharSequence[] items = new CharSequence[voteOptionsLength]; - for (int i = 0; i < voteOptions.length; i++) { + for (int i = 0; i < voteOptionsLength; i++) { SegmentVote voteOption = voteOptions[i]; - String title = voteOption.title.toString(); - if (Settings.SB_USER_IS_VIP.get() && segment.isLocked && voteOption.shouldHighlight) { - items[i] = Html.fromHtml(String.format("%s", LOCKED_COLOR, title)); - } else { - items[i] = title; + CharSequence title = voteOption.title.toString(); + if (userIsVip && segment.isLocked && voteOption.highlightIfVipAndVideoIsLocked) { + SpannableString coloredTitle = new SpannableString(title); + coloredTitle.setSpan(new ForegroundColorSpan(LOCKED_COLOR), + 0, title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + title = coloredTitle; } + items[i] = title; } - new AlertDialog.Builder(context) - .setItems(items, (dialog1, which1) -> { - SegmentVote voteOption = voteOptions[which1]; - switch (voteOption) { - case UPVOTE: - case DOWNVOTE: - SBRequester.voteForSegmentOnBackgroundThread(segment, voteOption); - break; - case CATEGORY_CHANGE: - onNewCategorySelect(segment, context); - break; - } - }) - .show(); + new AlertDialog.Builder(context).setItems(items, (dialog1, which1) -> { + SegmentVote voteOption = voteOptions[which1]; + switch (voteOption) { + case UPVOTE: + case DOWNVOTE: + SBRequester.voteForSegmentOnBackgroundThread(segment, voteOption); + break; + case CATEGORY_CHANGE: + onNewCategorySelect(segment, context); + break; + } + }).show(); } catch (Exception ex) { Logger.printException(() -> "segmentVoteClickListener failure", ex); } @@ -282,7 +289,6 @@ public class SponsorBlockUtils { return; } - final int numberOfSegments = segments.length; CharSequence[] titles = new CharSequence[numberOfSegments]; for (int i = 0; i < numberOfSegments; i++) { @@ -290,22 +296,33 @@ public class SponsorBlockUtils { if (segment.category == SegmentCategory.UNSUBMITTED) { continue; } - StringBuilder htmlBuilder = new StringBuilder(); - htmlBuilder.append(String.format(" %s
", - segment.category.color, segment.category.title)); - htmlBuilder.append(formatSegmentTime(segment.start)); - if (segment.category != SegmentCategory.HIGHLIGHT) { - htmlBuilder.append(" to ").append(formatSegmentTime(segment.end)); + + SpannableStringBuilder spannableBuilder = new SpannableStringBuilder(); + + spannableBuilder.append(segment.category.getTitleWithColorDot()); + spannableBuilder.append('\n'); + + String startTime = formatSegmentTime(segment.start); + if (segment.category == SegmentCategory.HIGHLIGHT) { + spannableBuilder.append(startTime); + } else { + String toFromString = str("revanced_sb_vote_segment_time_to_from", + startTime, formatSegmentTime(segment.end)); + spannableBuilder.append(toFromString); } - htmlBuilder.append("
"); - if (i + 1 != numberOfSegments) // prevents trailing new line after last segment - htmlBuilder.append("
"); - titles[i] = Html.fromHtml(htmlBuilder.toString()); + + if (i + 1 != numberOfSegments) { + // prevents trailing new line after last segment + spannableBuilder.append('\n'); + } + + spannableBuilder.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), + 0, spannableBuilder.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + + titles[i] = spannableBuilder; } - new AlertDialog.Builder(context) - .setItems(titles, segmentVoteClickListener) - .show(); + new AlertDialog.Builder(context).setItems(titles, segmentVoteClickListener).show(); } catch (Exception ex) { Logger.printException(() -> "onVotingClicked failure", ex); } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategory.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategory.java index 5be3755ae..ec1b1fca5 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategory.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategory.java @@ -1,13 +1,14 @@ package app.revanced.extension.youtube.sponsorblock.objects; -import static app.revanced.extension.youtube.settings.Settings.*; import static app.revanced.extension.shared.StringRef.sf; +import static app.revanced.extension.youtube.settings.Settings.*; import android.graphics.Color; import android.graphics.Paint; -import android.text.Html; -import android.text.Spanned; +import android.text.Spannable; +import android.text.SpannableString; import android.text.TextUtils; +import android.text.style.ForegroundColorSpan; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -15,43 +16,45 @@ import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; -import app.revanced.extension.shared.Utils; -import app.revanced.extension.shared.settings.StringSetting; -import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.StringRef; +import app.revanced.extension.shared.Utils; +import app.revanced.extension.shared.settings.FloatSetting; +import app.revanced.extension.shared.settings.StringSetting; +import app.revanced.extension.youtube.settings.Settings; public enum SegmentCategory { SPONSOR("sponsor", sf("revanced_sb_segments_sponsor"), sf("revanced_sb_segments_sponsor_sum"), sf("revanced_sb_skip_button_sponsor"), sf("revanced_sb_skipped_sponsor"), - SB_CATEGORY_SPONSOR, SB_CATEGORY_SPONSOR_COLOR), + SB_CATEGORY_SPONSOR, SB_CATEGORY_SPONSOR_COLOR, SB_CATEGORY_SPONSOR_OPACITY), SELF_PROMO("selfpromo", sf("revanced_sb_segments_selfpromo"), sf("revanced_sb_segments_selfpromo_sum"), sf("revanced_sb_skip_button_selfpromo"), sf("revanced_sb_skipped_selfpromo"), - SB_CATEGORY_SELF_PROMO, SB_CATEGORY_SELF_PROMO_COLOR), + SB_CATEGORY_SELF_PROMO, SB_CATEGORY_SELF_PROMO_COLOR, SB_CATEGORY_SELF_PROMO_OPACITY), INTERACTION("interaction", sf("revanced_sb_segments_interaction"), sf("revanced_sb_segments_interaction_sum"), sf("revanced_sb_skip_button_interaction"), sf("revanced_sb_skipped_interaction"), - SB_CATEGORY_INTERACTION, SB_CATEGORY_INTERACTION_COLOR), + SB_CATEGORY_INTERACTION, SB_CATEGORY_INTERACTION_COLOR, SB_CATEGORY_INTERACTION_OPACITY), /** * Unique category that is treated differently than the rest. */ HIGHLIGHT("poi_highlight", sf("revanced_sb_segments_highlight"), sf("revanced_sb_segments_highlight_sum"), sf("revanced_sb_skip_button_highlight"), sf("revanced_sb_skipped_highlight"), - SB_CATEGORY_HIGHLIGHT, SB_CATEGORY_HIGHLIGHT_COLOR), + SB_CATEGORY_HIGHLIGHT, SB_CATEGORY_HIGHLIGHT_COLOR, SB_CATEGORY_HIGHLIGHT_OPACITY), INTRO("intro", sf("revanced_sb_segments_intro"), sf("revanced_sb_segments_intro_sum"), sf("revanced_sb_skip_button_intro_beginning"), sf("revanced_sb_skip_button_intro_middle"), sf("revanced_sb_skip_button_intro_end"), sf("revanced_sb_skipped_intro_beginning"), sf("revanced_sb_skipped_intro_middle"), sf("revanced_sb_skipped_intro_end"), - SB_CATEGORY_INTRO, SB_CATEGORY_INTRO_COLOR), + SB_CATEGORY_INTRO, SB_CATEGORY_INTRO_COLOR, SB_CATEGORY_INTRO_OPACITY), OUTRO("outro", sf("revanced_sb_segments_outro"), sf("revanced_sb_segments_outro_sum"), sf("revanced_sb_skip_button_outro"), sf("revanced_sb_skipped_outro"), - SB_CATEGORY_OUTRO, SB_CATEGORY_OUTRO_COLOR), + SB_CATEGORY_OUTRO, SB_CATEGORY_OUTRO_COLOR, SB_CATEGORY_OUTRO_OPACITY), PREVIEW("preview", sf("revanced_sb_segments_preview"), sf("revanced_sb_segments_preview_sum"), sf("revanced_sb_skip_button_preview_beginning"), sf("revanced_sb_skip_button_preview_middle"), sf("revanced_sb_skip_button_preview_end"), sf("revanced_sb_skipped_preview_beginning"), sf("revanced_sb_skipped_preview_middle"), sf("revanced_sb_skipped_preview_end"), - SB_CATEGORY_PREVIEW, SB_CATEGORY_PREVIEW_COLOR), + SB_CATEGORY_PREVIEW, SB_CATEGORY_PREVIEW_COLOR, SB_CATEGORY_PREVIEW_OPACITY), FILLER("filler", sf("revanced_sb_segments_filler"), sf("revanced_sb_segments_filler_sum"), sf("revanced_sb_skip_button_filler"), sf("revanced_sb_skipped_filler"), - SB_CATEGORY_FILLER, SB_CATEGORY_FILLER_COLOR), + SB_CATEGORY_FILLER, SB_CATEGORY_FILLER_COLOR, SB_CATEGORY_FILLER_OPACITY), MUSIC_OFFTOPIC("music_offtopic", sf("revanced_sb_segments_nomusic"), sf("revanced_sb_segments_nomusic_sum"), sf("revanced_sb_skip_button_nomusic"), sf("revanced_sb_skipped_nomusic"), - SB_CATEGORY_MUSIC_OFFTOPIC, SB_CATEGORY_MUSIC_OFFTOPIC_COLOR), + SB_CATEGORY_MUSIC_OFFTOPIC, SB_CATEGORY_MUSIC_OFFTOPIC_COLOR, SB_CATEGORY_MUSIC_OFFTOPIC_OPACITY), UNSUBMITTED("unsubmitted", StringRef.empty, StringRef.empty, sf("revanced_sb_skip_button_unsubmitted"), sf("revanced_sb_skipped_unsubmitted"), - SB_CATEGORY_UNSUBMITTED, SB_CATEGORY_UNSUBMITTED_COLOR),; + SB_CATEGORY_UNSUBMITTED, SB_CATEGORY_UNSUBMITTED_COLOR, SB_CATEGORY_UNSUBMITTED_OPACITY); private static final StringRef skipSponsorTextCompact = sf("revanced_sb_skip_button_compact"); private static final StringRef skipSponsorTextCompactHighlight = sf("revanced_sb_skip_button_compact_highlight"); @@ -90,12 +93,10 @@ public enum SegmentCategory { mValuesMap.put(value.keyValue, value); } - @NonNull public static SegmentCategory[] categoriesWithoutUnsubmitted() { return categoriesWithoutUnsubmitted; } - @NonNull public static SegmentCategory[] categoriesWithoutHighlights() { return categoriesWithoutHighlights; } @@ -106,7 +107,7 @@ public enum SegmentCategory { } /** - * Must be called if behavior of any category is changed + * Must be called if behavior of any category is changed. */ public static void updateEnabledCategories() { Utils.verifyOnMainThread(); @@ -133,32 +134,33 @@ public enum SegmentCategory { updateEnabledCategories(); } - @NonNull - public final String keyValue; - @NonNull - public final StringSetting behaviorSetting; - @NonNull - private final StringSetting colorSetting; + public static int applyOpacityToColor(int color, float opacity) { + if (opacity < 0 || opacity > 1.0f) { + throw new IllegalArgumentException("Invalid opacity: " + opacity); + } + final int opacityInt = (int) (255 * opacity); + return (color & 0x00FFFFFF) | (opacityInt << 24); + } + + public final String keyValue; + public final StringSetting behaviorSetting; // TODO: Replace with EnumSetting. + private final StringSetting colorSetting; + private final FloatSetting opacitySetting; - @NonNull public final StringRef title; - @NonNull public final StringRef description; /** * Skip button text, if the skip occurs in the first quarter of the video */ - @NonNull public final StringRef skipButtonTextBeginning; /** * Skip button text, if the skip occurs in the middle half of the video */ - @NonNull public final StringRef skipButtonTextMiddle; /** * Skip button text, if the skip occurs in the last quarter of the video */ - @NonNull public final StringRef skipButtonTextEnd; /** * Skipped segment toast, if the skip occurred in the first quarter of the video @@ -179,10 +181,7 @@ public enum SegmentCategory { @NonNull public final Paint paint; - /** - * Value must be changed using {@link #setColor(String)}. - */ - public int color; + private int color; /** * Value must be changed using {@link #setBehaviour(CategoryBehaviour)}. @@ -194,17 +193,20 @@ public enum SegmentCategory { SegmentCategory(String keyValue, StringRef title, StringRef description, StringRef skipButtonText, StringRef skippedToastText, - StringSetting behavior, StringSetting color) { + StringSetting behavior, + StringSetting color, FloatSetting opacity) { this(keyValue, title, description, skipButtonText, skipButtonText, skipButtonText, skippedToastText, skippedToastText, skippedToastText, - behavior, color); + behavior, + color, opacity); } SegmentCategory(String keyValue, StringRef title, StringRef description, StringRef skipButtonTextBeginning, StringRef skipButtonTextMiddle, StringRef skipButtonTextEnd, StringRef skippedToastBeginning, StringRef skippedToastMiddle, StringRef skippedToastEnd, - StringSetting behavior, StringSetting color) { + StringSetting behavior, + StringSetting color, FloatSetting opacity) { this.keyValue = Objects.requireNonNull(keyValue); this.title = Objects.requireNonNull(title); this.description = Objects.requireNonNull(description); @@ -216,6 +218,7 @@ public enum SegmentCategory { this.skippedToastEnd = Objects.requireNonNull(skippedToastEnd); this.behaviorSetting = Objects.requireNonNull(behavior); this.colorSetting = Objects.requireNonNull(color); + this.opacitySetting = Objects.requireNonNull(opacity); this.paint = new Paint(); loadFromSettings(); } @@ -232,11 +235,14 @@ public enum SegmentCategory { this.behaviour = savedBehavior; String colorString = colorSetting.get(); + final float opacity = opacitySetting.get(); try { setColor(colorString); + setOpacity(opacity); } catch (Exception ex) { - Logger.printException(() -> "Invalid color: " + colorString, ex); + Logger.printException(() -> "Invalid color: " + colorString + " opacity: " + opacity, ex); colorSetting.resetToDefault(); + opacitySetting.resetToDefault(); loadFromSettings(); } } @@ -245,45 +251,78 @@ public enum SegmentCategory { this.behaviour = Objects.requireNonNull(behaviour); this.behaviorSetting.save(behaviour.reVancedKeyValue); } - /** - * @return HTML color format string - */ - @NonNull - public String colorString() { - return String.format("#%06X", color); - } - public void setColor(@NonNull String colorString) throws IllegalArgumentException { - final int color = Color.parseColor(colorString) & 0xFFFFFF; - this.color = color; + private void updateColor() { + color = applyOpacityToColor(color, opacitySetting.get()); paint.setColor(color); - paint.setAlpha(255); - colorSetting.save(colorString); // Save after parsing. } - public void resetColor() { + /** + * @param opacity Segment color opacity between [0, 1]. + */ + public void setOpacity(float opacity) throws IllegalArgumentException { + if (opacity < 0 || opacity > 1) { + throw new IllegalArgumentException("Invalid opacity: " + opacity); + } + + opacitySetting.save(opacity); + updateColor(); + } + + public float getOpacity() { + return opacitySetting.get(); + } + + public void resetColorAndOpacity() { setColor(colorSetting.defaultValue); + setOpacity(opacitySetting.defaultValue); } - @NonNull - private static String getCategoryColorDotHTML(int color) { - color &= 0xFFFFFF; - return String.format("", color); + /** + * @param colorString Segment color with #RRGGBB format. + */ + public void setColor(String colorString) throws IllegalArgumentException { + color = Color.parseColor(colorString); + colorSetting.save(colorString); + + updateColor(); } - @NonNull - public static Spanned getCategoryColorDot(int color) { - return Html.fromHtml(getCategoryColorDotHTML(color)); + /** + * @return Integer color of #RRGGBB format. + */ + public int getColorNoOpacity() { + return color & 0x00FFFFFF; } - @NonNull - public Spanned getCategoryColorDot() { + /** + * @return Hex color string of #RRGGBB format with no opacity level. + */ + public String getColorString() { + return String.format(Locale.US, "#%06X", getColorNoOpacity()); + } + + private static SpannableString getCategoryColorDotSpan(String text, int color) { + SpannableString dotSpan = new SpannableString('⬤' + text); + dotSpan.setSpan(new ForegroundColorSpan(color), 0, 1, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + return dotSpan; + } + + public static SpannableString getCategoryColorDot(int color) { + return getCategoryColorDotSpan("", color); + } + + public SpannableString getCategoryColorDot() { return getCategoryColorDot(color); } - @NonNull - public Spanned getTitleWithColorDot() { - return Html.fromHtml(getCategoryColorDotHTML(color) + " " + title); + public SpannableString getTitleWithColorDot(int categoryColor) { + return getCategoryColorDotSpan(" " + title, categoryColor); + } + + public SpannableString getTitleWithColorDot() { + return getTitleWithColorDot(color); } /** @@ -291,7 +330,6 @@ public enum SegmentCategory { * @param videoLength length of the video * @return the skip button text */ - @NonNull StringRef getSkipButtonText(long segmentStartTime, long videoLength) { if (Settings.SB_COMPACT_SKIP_BUTTON.get()) { return (this == SegmentCategory.HIGHLIGHT) @@ -300,7 +338,7 @@ public enum SegmentCategory { } if (videoLength == 0) { - return skipButtonTextBeginning; // video is still loading. Assume it's the beginning + return skipButtonTextBeginning; // Video is still loading. Assume it's the beginning. } final float position = segmentStartTime / (float) videoLength; if (position < 0.25f) { @@ -316,10 +354,9 @@ public enum SegmentCategory { * @param videoLength length of the video * @return 'skipped segment' toast message */ - @NonNull StringRef getSkippedToastText(long segmentStartTime, long videoLength) { if (videoLength == 0) { - return skippedToastBeginning; // video is still loading. Assume it's the beginning + return skippedToastBeginning; // Video is still loading. Assume it's the beginning. } final float position = segmentStartTime / (float) videoLength; if (position < 0.25f) { diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategoryListPreference.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategoryListPreference.java index ec83d9122..ae92caaff 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategoryListPreference.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SegmentCategoryListPreference.java @@ -1,6 +1,7 @@ package app.revanced.extension.youtube.sponsorblock.objects; import static app.revanced.extension.shared.StringRef.str; +import static app.revanced.extension.youtube.sponsorblock.objects.SegmentCategory.applyOpacityToColor; import android.app.AlertDialog; import android.content.Context; @@ -11,11 +12,10 @@ import android.text.Editable; import android.text.InputType; import android.text.TextWatcher; import android.widget.EditText; -import android.widget.LinearLayout; -import android.widget.TableLayout; -import android.widget.TableRow; +import android.widget.GridLayout; import android.widget.TextView; +import java.util.Locale; import java.util.Objects; import app.revanced.extension.shared.Logger; @@ -24,27 +24,38 @@ import app.revanced.extension.shared.Utils; @SuppressWarnings("deprecation") public class SegmentCategoryListPreference extends ListPreference { private final SegmentCategory category; - private EditText mEditText; - private int mClickedDialogEntryIndex; + private TextView colorDotView; + private EditText colorEditText; + private EditText opacityEditText; + /** + * #RRGGBB + */ + private int categoryColor; + /** + * [0, 1] + */ + private float categoryOpacity; + private int selectedDialogEntryIndex; public SegmentCategoryListPreference(Context context, SegmentCategory category) { super(context); - final boolean isHighlightCategory = category == SegmentCategory.HIGHLIGHT; this.category = Objects.requireNonNull(category); // Edit: Using preferences to sync together multiple pieces - // of code together is messy and should be rethought. + // of code is messy and should be rethought. setKey(category.behaviorSetting.key); setDefaultValue(category.behaviorSetting.defaultValue); + + final boolean isHighlightCategory = category == SegmentCategory.HIGHLIGHT; setEntries(isHighlightCategory ? CategoryBehaviour.getBehaviorDescriptionsWithoutSkipOnce() : CategoryBehaviour.getBehaviorDescriptions()); setEntryValues(isHighlightCategory ? CategoryBehaviour.getBehaviorKeyValuesWithoutSkipOnce() : CategoryBehaviour.getBehaviorKeyValues()); - setSummary(category.description.toString()); - updateTitle(); + + updateTitleFromCategory(); } @Override @@ -52,26 +63,40 @@ public class SegmentCategoryListPreference extends ListPreference { try { Utils.setEditTextDialogTheme(builder); + categoryColor = category.getColorNoOpacity(); + categoryOpacity = category.getOpacity(); + Context context = builder.getContext(); - TableLayout table = new TableLayout(context); - table.setOrientation(LinearLayout.HORIZONTAL); - table.setPadding(70, 0, 150, 0); - - TableRow row = new TableRow(context); + GridLayout gridLayout = new GridLayout(context); + gridLayout.setPadding(70, 0, 150, 0); // Padding for the entire layout. + gridLayout.setColumnCount(3); + gridLayout.setRowCount(2); + GridLayout.LayoutParams gridParams = new GridLayout.LayoutParams(); + gridParams.rowSpec = GridLayout.spec(0); // First row. + gridParams.columnSpec = GridLayout.spec(0); // First column. TextView colorTextLabel = new TextView(context); colorTextLabel.setText(str("revanced_sb_color_dot_label")); - row.addView(colorTextLabel); + colorTextLabel.setLayoutParams(gridParams); + gridLayout.addView(colorTextLabel); - TextView colorDotView = new TextView(context); - colorDotView.setText(category.getCategoryColorDot()); - colorDotView.setPadding(30, 0, 30, 0); - row.addView(colorDotView); + gridParams = new GridLayout.LayoutParams(); + gridParams.rowSpec = GridLayout.spec(0); // First row. + gridParams.columnSpec = GridLayout.spec(1); // Second column. + gridParams.setMargins(0, 0, 10, 0); + colorDotView = new TextView(context); + colorDotView.setLayoutParams(gridParams); + gridLayout.addView(colorDotView); + updateCategoryColorDot(); - mEditText = new EditText(context); - mEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS); - mEditText.setText(category.colorString()); - mEditText.addTextChangedListener(new TextWatcher() { + gridParams = new GridLayout.LayoutParams(); + gridParams.rowSpec = GridLayout.spec(0); // First row. + gridParams.columnSpec = GridLayout.spec(2); // Third column. + colorEditText = new EditText(context); + colorEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS); + colorEditText.setTextLocale(Locale.US); + colorEditText.setText(category.getColorString()); + colorEditText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @@ -81,29 +106,94 @@ public class SegmentCategoryListPreference extends ListPreference { } @Override - public void afterTextChanged(Editable s) { + public void afterTextChanged(Editable edit) { try { - String colorString = s.toString(); + String colorString = edit.toString(); + final int colorStringLength = colorString.length(); + if (!colorString.startsWith("#")) { - s.insert(0, "#"); // recursively calls back into this method + edit.insert(0, "#"); // Recursively calls back into this method. return; } - if (colorString.length() > 7) { - s.delete(7, colorString.length()); + + final int maxColorStringLength = 7; // #RRGGBB + if (colorStringLength > maxColorStringLength) { + edit.delete(maxColorStringLength, colorStringLength); return; } - final int color = Color.parseColor(colorString); - colorDotView.setText(SegmentCategory.getCategoryColorDot(color)); + + categoryColor = Color.parseColor(colorString); + updateCategoryColorDot(); } catch (IllegalArgumentException ex) { - // ignore + // Ignore. } } }); - mEditText.setLayoutParams(new TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 1f)); - row.addView(mEditText); + colorEditText.setLayoutParams(gridParams); + gridLayout.addView(colorEditText); - table.addView(row); - builder.setView(table); + gridParams = new GridLayout.LayoutParams(); + gridParams.rowSpec = GridLayout.spec(1); // Second row. + gridParams.columnSpec = GridLayout.spec(0, 1); // First and second column. + TextView opacityLabel = new TextView(context); + opacityLabel.setText(str("revanced_sb_color_opacity_label")); + opacityLabel.setLayoutParams(gridParams); + gridLayout.addView(opacityLabel); + + gridParams = new GridLayout.LayoutParams(); + gridParams.rowSpec = GridLayout.spec(1); // Second row. + gridParams.columnSpec = GridLayout.spec(2); // Third column. + opacityEditText = new EditText(context); + opacityEditText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL); + opacityEditText.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + } + + @Override + public void afterTextChanged(Editable edit) { + try { + String editString = edit.toString(); + final int opacityStringLength = editString.length(); + + final int maxOpacityStringLength = 4; // [0.00, 1.00] + if (opacityStringLength > maxOpacityStringLength) { + edit.delete(maxOpacityStringLength, opacityStringLength); + return; + } + + final float opacity = opacityStringLength == 0 + ? 0 + : Float.parseFloat(editString); + if (opacity < 0) { + categoryOpacity = 0; + edit.replace(0, opacityStringLength, "0"); + return; + } else if (opacity > 1.0f) { + categoryOpacity = 1; + edit.replace(0, opacityStringLength, "1.0"); + return; + } else if (!editString.endsWith(".")) { + // Ignore "0." and "1." until the user finishes entering a valid number. + categoryOpacity = opacity; + } + + updateCategoryColorDot(); + } catch (NumberFormatException ex) { + // Should never happen. + Logger.printException(() -> "Could not parse opacity string", ex); + } + } + }); + opacityEditText.setLayoutParams(gridParams); + gridLayout.addView(opacityEditText); + updateOpacityText(); + + builder.setView(gridLayout); builder.setTitle(category.title.toString()); builder.setPositiveButton(android.R.string.ok, (dialog, which) -> { @@ -111,8 +201,8 @@ public class SegmentCategoryListPreference extends ListPreference { }); builder.setNeutralButton(str("revanced_sb_reset_color"), (dialog, which) -> { try { - category.resetColor(); - updateTitle(); + category.resetColorAndOpacity(); + updateTitleFromCategory(); Utils.showToastShort(str("revanced_sb_color_reset")); } catch (Exception ex) { Logger.printException(() -> "setNeutralButton failure", ex); @@ -120,8 +210,9 @@ public class SegmentCategoryListPreference extends ListPreference { }); builder.setNegativeButton(android.R.string.cancel, null); - mClickedDialogEntryIndex = findIndexOfValue(getValue()); - builder.setSingleChoiceItems(getEntries(), mClickedDialogEntryIndex, (dialog, which) -> mClickedDialogEntryIndex = which); + selectedDialogEntryIndex = findIndexOfValue(getValue()); + builder.setSingleChoiceItems(getEntries(), selectedDialogEntryIndex, + (dialog, which) -> selectedDialogEntryIndex = which); } catch (Exception ex) { Logger.printException(() -> "onPrepareDialogBuilder failure", ex); } @@ -130,30 +221,51 @@ public class SegmentCategoryListPreference extends ListPreference { @Override protected void onDialogClosed(boolean positiveResult) { try { - if (positiveResult && mClickedDialogEntryIndex >= 0 && getEntryValues() != null) { - String value = getEntryValues()[mClickedDialogEntryIndex].toString(); + if (positiveResult && selectedDialogEntryIndex >= 0 && getEntryValues() != null) { + String value = getEntryValues()[selectedDialogEntryIndex].toString(); if (callChangeListener(value)) { setValue(value); category.setBehaviour(Objects.requireNonNull(CategoryBehaviour.byReVancedKeyValue(value))); SegmentCategory.updateEnabledCategories(); } - String colorString = mEditText.getText().toString(); + try { - if (!colorString.equals(category.colorString())) { + String colorString = colorEditText.getText().toString(); + if (!colorString.equals(category.getColorString()) || categoryOpacity != category.getOpacity()) { category.setColor(colorString); + category.setOpacity(categoryOpacity); Utils.showToastShort(str("revanced_sb_color_changed")); } } catch (IllegalArgumentException ex) { Utils.showToastShort(str("revanced_sb_color_invalid")); } - updateTitle(); + + updateTitleFromCategory(); } } catch (Exception ex) { Logger.printException(() -> "onDialogClosed failure", ex); } } - private void updateTitle() { - setTitle(category.getTitleWithColorDot()); + private void applyOpacityToCategoryColor() { + categoryColor = applyOpacityToColor(categoryColor, categoryOpacity); + } + + private void updateTitleFromCategory() { + categoryColor = category.getColorNoOpacity(); + categoryOpacity = category.getOpacity(); + applyOpacityToCategoryColor(); + + setTitle(category.getTitleWithColorDot(categoryColor)); + } + + private void updateCategoryColorDot() { + applyOpacityToCategoryColor(); + + colorDotView.setText(SegmentCategory.getCategoryColorDot(categoryColor)); + } + + private void updateOpacityText() { + opacityEditText.setText(String.format(Locale.US, "%.2f", categoryOpacity)); } } \ No newline at end of file diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SponsorSegment.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SponsorSegment.java index 811cb87c4..375de16b5 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SponsorSegment.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/sponsorblock/objects/SponsorSegment.java @@ -23,12 +23,15 @@ public class SponsorSegment implements Comparable { @NonNull public final StringRef title; public final int apiVoteType; - public final boolean shouldHighlight; + /** + * If the option should be highlighted for VIP users. + */ + public final boolean highlightIfVipAndVideoIsLocked; - SegmentVote(@NonNull StringRef title, int apiVoteType, boolean shouldHighlight) { + SegmentVote(@NonNull StringRef title, int apiVoteType, boolean highlightIfVipAndVideoIsLocked) { this.title = title; this.apiVoteType = apiVoteType; - this.shouldHighlight = shouldHighlight; + this.highlightIfVipAndVideoIsLocked = highlightIfVipAndVideoIsLocked; } } diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 7e015ef08..41648df70 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -1068,6 +1068,8 @@ Already exists" Downvote Change category There are no segments to vote for + + %1$s to %2$s Choose the segment category Category is disabled in settings. Enable category to submit. New SponsorBlock segment @@ -1115,6 +1117,7 @@ Ready to submit?" %1$s hours %2$s minutes %1$s minutes %2$s seconds %s seconds + Opacity: Color: Color changed Color reset