mirror of
https://github.com/revanced/revanced-integrations.git
synced 2024-09-12 09:16:28 +02:00
fix(youtube/return-youtube-dislike): support old UI layouts (#378)
This commit is contained in:
parent
ff0d64287c
commit
d3f8fb9739
@ -2,23 +2,114 @@ package app.revanced.integrations.patches;
|
|||||||
|
|
||||||
import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
import static app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
||||||
|
|
||||||
|
import android.text.Editable;
|
||||||
import android.text.SpannableString;
|
import android.text.SpannableString;
|
||||||
import android.text.Spanned;
|
import android.text.Spanned;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike;
|
import app.revanced.integrations.returnyoutubedislike.ReturnYouTubeDislike;
|
||||||
import app.revanced.integrations.settings.SettingsEnum;
|
import app.revanced.integrations.settings.SettingsEnum;
|
||||||
import app.revanced.integrations.utils.LogHelper;
|
import app.revanced.integrations.utils.LogHelper;
|
||||||
|
import app.revanced.integrations.utils.ReVancedUtils;
|
||||||
|
|
||||||
public class ReturnYouTubeDislikePatch {
|
public class ReturnYouTubeDislikePatch {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resource identifier of old UI dislike button.
|
||||||
|
*/
|
||||||
|
private static final int OLD_UI_DISLIKE_BUTTON_RESOURCE_ID
|
||||||
|
= ReVancedUtils.getResourceIdentifier("dislike_button", "id");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dislikes text label used by old UI.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private static WeakReference<TextView> oldUITextViewRef = new WeakReference<>(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Original old UI 'Dislikes' text before patch modifications.
|
||||||
|
* Required to reset the dislikes when changing videos and RYD is not available.
|
||||||
|
* Set only once during the first load.
|
||||||
|
*/
|
||||||
|
private static Spanned oldUIOriginalSpan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replacement span that contains dislike value. Used by {@link #oldUiTextWatcher}.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
private static Spanned oldUIReplacementSpan;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Old UI dislikes can be set multiple times by YouTube.
|
||||||
|
* To prevent it from reverting changes made here, this listener overrides any future changes YouTube makes.
|
||||||
|
*/
|
||||||
|
private static final TextWatcher oldUiTextWatcher = new TextWatcher() {
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
if (oldUIReplacementSpan == null || oldUIReplacementSpan.toString().equals(s.toString())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
s.replace(0, s.length(), oldUIReplacementSpan);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private static void updateOldUIDislikesTextView() {
|
||||||
|
TextView oldUITextView = oldUITextViewRef.get();
|
||||||
|
if (oldUITextView == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Spanned dislikes = ReturnYouTubeDislike.getDislikesSpanForRegularVideo(oldUIOriginalSpan, false);
|
||||||
|
if (dislikes == null) { // Dislikes not available.
|
||||||
|
// Must reset text back to original as the TextView may contain dislikes of a prior video.
|
||||||
|
dislikes = oldUIOriginalSpan;
|
||||||
|
}
|
||||||
|
oldUIReplacementSpan = dislikes;
|
||||||
|
if (!dislikes.equals(oldUITextView.getText())) {
|
||||||
|
oldUITextView.setText(dislikes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point. Called on main thread.
|
||||||
|
*
|
||||||
|
* Used when spoofing the older app versions of {@link SpoofAppVersionPatch}.
|
||||||
|
*/
|
||||||
|
public static void setOldUILayoutDislikes(int buttonViewResourceId, @NonNull TextView textView) {
|
||||||
|
try {
|
||||||
|
if (!SettingsEnum.RYD_ENABLED.getBoolean()
|
||||||
|
|| buttonViewResourceId != OLD_UI_DISLIKE_BUTTON_RESOURCE_ID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (oldUIOriginalSpan == null) {
|
||||||
|
// Use value of the first instance, as it appears TextViews can be recycled
|
||||||
|
// and might contain dislikes previously added by the patch.
|
||||||
|
oldUIOriginalSpan = (Spanned) textView.getText();
|
||||||
|
}
|
||||||
|
oldUITextViewRef = new WeakReference<>(textView);
|
||||||
|
// No way to check if a listener is already attached, so remove and add again.
|
||||||
|
textView.removeTextChangedListener(oldUiTextWatcher);
|
||||||
|
textView.addTextChangedListener(oldUiTextWatcher);
|
||||||
|
|
||||||
|
updateOldUIDislikesTextView();
|
||||||
|
} catch (Exception ex) {
|
||||||
|
LogHelper.printException(() -> "setOldUILayoutDislikes failure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection point.
|
* Injection point.
|
||||||
*/
|
*/
|
||||||
public static void newVideoLoaded(String videoId) {
|
public static void newVideoLoaded(@NonNull String videoId) {
|
||||||
try {
|
try {
|
||||||
if (!SettingsEnum.RYD_ENABLED.getBoolean()) return;
|
if (!SettingsEnum.RYD_ENABLED.getBoolean()) return;
|
||||||
ReturnYouTubeDislike.newVideoLoaded(videoId);
|
ReturnYouTubeDislike.newVideoLoaded(videoId);
|
||||||
@ -97,6 +188,7 @@ public class ReturnYouTubeDislikePatch {
|
|||||||
for (Vote v : Vote.values()) {
|
for (Vote v : Vote.values()) {
|
||||||
if (v.value == vote) {
|
if (v.value == vote) {
|
||||||
ReturnYouTubeDislike.sendVote(v);
|
ReturnYouTubeDislike.sendVote(v);
|
||||||
|
updateOldUIDislikesTextView();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ public class ReturnYouTubeDislike {
|
|||||||
/**
|
/**
|
||||||
* If {@link #currentVideoId} and the RYD data is for the last shorts loaded.
|
* If {@link #currentVideoId} and the RYD data is for the last shorts loaded.
|
||||||
*/
|
*/
|
||||||
private static volatile boolean lastVideoLoadedWasShort;
|
private static volatile boolean dislikeDataIsShort;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores the results of the vote api fetch, and used as a barrier to wait until fetch completes.
|
* Stores the results of the vote api fetch, and used as a barrier to wait until fetch completes.
|
||||||
@ -141,7 +141,7 @@ public class ReturnYouTubeDislike {
|
|||||||
LogHelper.printDebug(() -> "Clearing data");
|
LogHelper.printDebug(() -> "Clearing data");
|
||||||
}
|
}
|
||||||
currentVideoId = videoId;
|
currentVideoId = videoId;
|
||||||
lastVideoLoadedWasShort = false;
|
dislikeDataIsShort = false;
|
||||||
voteFetchFuture = null;
|
voteFetchFuture = null;
|
||||||
originalDislikeSpan = null;
|
originalDislikeSpan = null;
|
||||||
replacementLikeDislikeSpan = null;
|
replacementLikeDislikeSpan = null;
|
||||||
@ -198,7 +198,7 @@ public class ReturnYouTubeDislike {
|
|||||||
// If a Short is opened while a regular video is on screen, this will incorrectly set this as false.
|
// If a Short is opened while a regular video is on screen, this will incorrectly set this as false.
|
||||||
// But this check is needed to fix unusual situations of opening/closing the app
|
// But this check is needed to fix unusual situations of opening/closing the app
|
||||||
// while both a regular video and a short are on screen.
|
// while both a regular video and a short are on screen.
|
||||||
lastVideoLoadedWasShort = PlayerType.getCurrent().isNoneOrHidden();
|
dislikeDataIsShort = PlayerType.getCurrent().isNoneOrHidden();
|
||||||
|
|
||||||
// No need to wrap the call in a try/catch,
|
// No need to wrap the call in a try/catch,
|
||||||
// as any exceptions are propagated out in the later Future#Get call.
|
// as any exceptions are propagated out in the later Future#Get call.
|
||||||
@ -224,7 +224,15 @@ public class ReturnYouTubeDislike {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastVideoLoadedWasShort) {
|
return getDislikesSpanForRegularVideo((Spannable) original, isSegmentedButton);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return NULL if the span does not need changing or if RYD is not available.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static SpannableString getDislikesSpanForRegularVideo(@NonNull Spanned original, boolean isSegmentedButton) {
|
||||||
|
if (dislikeDataIsShort) {
|
||||||
// user:
|
// user:
|
||||||
// 1, opened a video
|
// 1, opened a video
|
||||||
// 2. opened a short (without closing the regular video)
|
// 2. opened a short (without closing the regular video)
|
||||||
@ -234,14 +242,14 @@ public class ReturnYouTubeDislike {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return waitForFetchAndUpdateReplacementSpan((Spannable) original, isSegmentedButton);
|
return waitForFetchAndUpdateReplacementSpan(original, isSegmentedButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a Shorts dislike Spannable is created.
|
* Called when a Shorts dislike Spannable is created.
|
||||||
*/
|
*/
|
||||||
public static SpannableString getDislikeSpanForShort(@NonNull Spanned original) {
|
public static SpannableString getDislikeSpanForShort(@NonNull Spanned original) {
|
||||||
lastVideoLoadedWasShort = true; // it's now certain the video and data are a short
|
dislikeDataIsShort = true; // it's now certain the video and data are a short
|
||||||
return waitForFetchAndUpdateReplacementSpan(original, false);
|
return waitForFetchAndUpdateReplacementSpan(original, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +321,7 @@ public class ReturnYouTubeDislike {
|
|||||||
try {
|
try {
|
||||||
// Must make a local copy of videoId, since it may change between now and when the vote thread runs.
|
// Must make a local copy of videoId, since it may change between now and when the vote thread runs.
|
||||||
String videoIdToVoteFor = getCurrentVideoId();
|
String videoIdToVoteFor = getCurrentVideoId();
|
||||||
if (videoIdToVoteFor == null || lastVideoLoadedWasShort != PlayerType.getCurrent().isNoneOrHidden()) {
|
if (videoIdToVoteFor == null || dislikeDataIsShort != PlayerType.getCurrent().isNoneOrHidden()) {
|
||||||
// User enabled RYD after starting playback of a video.
|
// User enabled RYD after starting playback of a video.
|
||||||
// Or shorts was loaded with regular video present, then shorts was closed,
|
// Or shorts was loaded with regular video present, then shorts was closed,
|
||||||
// and then user voted on the now visible original video.
|
// and then user voted on the now visible original video.
|
||||||
|
@ -20,33 +20,17 @@ import app.revanced.integrations.settings.SharedPrefCategory;
|
|||||||
public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
|
public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If ReturnYouTubeDislike is enabled
|
* If dislikes are shown as percentage.
|
||||||
*/
|
|
||||||
private SwitchPreference enabledPreference;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If dislikes are shown as percentage
|
|
||||||
*/
|
*/
|
||||||
private SwitchPreference percentagePreference;
|
private SwitchPreference percentagePreference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If segmented like/dislike button uses smaller compact layout
|
* If segmented like/dislike button uses smaller compact layout.
|
||||||
*/
|
*/
|
||||||
private SwitchPreference compactLayoutPreference;
|
private SwitchPreference compactLayoutPreference;
|
||||||
|
|
||||||
private void updateUIState() {
|
private void updateUIState() {
|
||||||
enabledPreference.setSummary(SettingsEnum.RYD_ENABLED.getBoolean()
|
|
||||||
? str("revanced_ryd_enable_summary_on")
|
|
||||||
: str("revanced_ryd_enable_summary_off"));
|
|
||||||
|
|
||||||
percentagePreference.setSummary(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.getBoolean()
|
|
||||||
? str("revanced_ryd_dislike_percentage_summary_on")
|
|
||||||
: str("revanced_ryd_dislike_percentage_summary_off"));
|
|
||||||
percentagePreference.setEnabled(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.isAvailable());
|
percentagePreference.setEnabled(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.isAvailable());
|
||||||
|
|
||||||
compactLayoutPreference.setSummary(SettingsEnum.RYD_USE_COMPACT_LAYOUT.getBoolean()
|
|
||||||
? str("revanced_ryd_compact_layout_summary_on")
|
|
||||||
: str("revanced_ryd_compact_layout_summary_off"));
|
|
||||||
compactLayoutPreference.setEnabled(SettingsEnum.RYD_USE_COMPACT_LAYOUT.isAvailable());
|
compactLayoutPreference.setEnabled(SettingsEnum.RYD_USE_COMPACT_LAYOUT.isAvailable());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,9 +43,11 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
|
|||||||
PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(context);
|
PreferenceScreen preferenceScreen = getPreferenceManager().createPreferenceScreen(context);
|
||||||
setPreferenceScreen(preferenceScreen);
|
setPreferenceScreen(preferenceScreen);
|
||||||
|
|
||||||
enabledPreference = new SwitchPreference(context);
|
SwitchPreference enabledPreference = new SwitchPreference(context);
|
||||||
enabledPreference.setChecked(SettingsEnum.RYD_ENABLED.getBoolean());
|
enabledPreference.setChecked(SettingsEnum.RYD_ENABLED.getBoolean());
|
||||||
enabledPreference.setTitle(str("revanced_ryd_enable_title"));
|
enabledPreference.setTitle(str("revanced_ryd_enable_title"));
|
||||||
|
enabledPreference.setSummaryOn(str("revanced_ryd_enable_summary_on"));
|
||||||
|
enabledPreference.setSummaryOff(str("revanced_ryd_enable_summary_off"));
|
||||||
enabledPreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
enabledPreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
final boolean rydIsEnabled = (Boolean) newValue;
|
final boolean rydIsEnabled = (Boolean) newValue;
|
||||||
SettingsEnum.RYD_ENABLED.saveValue(rydIsEnabled);
|
SettingsEnum.RYD_ENABLED.saveValue(rydIsEnabled);
|
||||||
@ -75,6 +61,8 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
|
|||||||
percentagePreference = new SwitchPreference(context);
|
percentagePreference = new SwitchPreference(context);
|
||||||
percentagePreference.setChecked(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.getBoolean());
|
percentagePreference.setChecked(SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.getBoolean());
|
||||||
percentagePreference.setTitle(str("revanced_ryd_dislike_percentage_title"));
|
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) -> {
|
percentagePreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.saveValue(newValue);
|
SettingsEnum.RYD_SHOW_DISLIKE_PERCENTAGE.saveValue(newValue);
|
||||||
ReturnYouTubeDislike.clearCache();
|
ReturnYouTubeDislike.clearCache();
|
||||||
@ -86,6 +74,8 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
|
|||||||
compactLayoutPreference = new SwitchPreference(context);
|
compactLayoutPreference = new SwitchPreference(context);
|
||||||
compactLayoutPreference.setChecked(SettingsEnum.RYD_USE_COMPACT_LAYOUT.getBoolean());
|
compactLayoutPreference.setChecked(SettingsEnum.RYD_USE_COMPACT_LAYOUT.getBoolean());
|
||||||
compactLayoutPreference.setTitle(str("revanced_ryd_compact_layout_title"));
|
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) -> {
|
compactLayoutPreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||||
SettingsEnum.RYD_USE_COMPACT_LAYOUT.saveValue(newValue);
|
SettingsEnum.RYD_USE_COMPACT_LAYOUT.saveValue(newValue);
|
||||||
ReturnYouTubeDislike.clearCache();
|
ReturnYouTubeDislike.clearCache();
|
||||||
@ -185,7 +175,7 @@ public class ReturnYouTubeDislikeSettingsFragment extends PreferenceFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createSummaryText(int value, String summaryStringZeroKey, String summaryStringOneOrMoreKey) {
|
private static String createSummaryText(int value, String summaryStringZeroKey, String summaryStringOneOrMoreKey) {
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
return str(summaryStringZeroKey);
|
return str(summaryStringZeroKey);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user