VancedIntegrations/app/src/main/java/fi/vanced/libraries/youtube/ryd/ReturnYouTubeDislikes.java

319 lines
10 KiB
Java

package fi.vanced.libraries.youtube.ryd;
import static fi.razerman.youtube.XGlobals.debug;
import static fi.vanced.libraries.youtube.player.VideoInformation.currentVideoId;
import static fi.vanced.libraries.youtube.player.VideoInformation.dislikeCount;
import static fi.vanced.libraries.youtube.ryd.RYDSettings.PREFERENCES_KEY_RYD_ENABLED;
import static fi.vanced.libraries.youtube.ryd.RYDSettings.PREFERENCES_NAME;
import static fi.vanced.utils.VancedUtils.getIdentifier;
import android.content.Context;
import android.icu.text.CompactDecimalFormat;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.google.android.apps.youtube.app.YouTubeTikTokRoot_Application;
import java.util.Locale;
import java.util.Objects;
import fi.vanced.libraries.youtube.ryd.requests.RYDRequester;
import fi.vanced.utils.SharedPrefUtils;
public class ReturnYouTubeDislikes {
public static boolean isEnabled;
public static final String TAG = "VI - RYD";
private static View _dislikeView = null;
private static Thread _dislikeFetchThread = null;
private static Thread _votingThread = null;
private static Registration registration;
private static Voting voting;
private static boolean likeActive;
private static boolean dislikeActive;
private static int votingValue = 0; // 1 = like, -1 = dislike, 0 = no vote
private static CompactDecimalFormat compactNumberFormatter;
static {
Context context = YouTubeTikTokRoot_Application.getAppContext();
isEnabled = SharedPrefUtils.getBoolean(Objects.requireNonNull(context), PREFERENCES_NAME, PREFERENCES_KEY_RYD_ENABLED, false);
if (isEnabled) {
registration = new Registration(context);
voting = new Voting(context, registration);
}
Locale locale = context.getResources().getConfiguration().locale;
if (debug) {
Log.d(TAG, "locale - " + locale);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
compactNumberFormatter = CompactDecimalFormat.getInstance(
locale,
CompactDecimalFormat.CompactStyle.SHORT
);
}
}
public static void onEnabledChange(boolean enabled) {
isEnabled = enabled;
if (registration == null) {
registration = new Registration(YouTubeTikTokRoot_Application.getAppContext());
}
if (voting == null) {
voting = new Voting(YouTubeTikTokRoot_Application.getAppContext(), registration);
}
}
public static void newVideoLoaded(String videoId) {
if (debug) {
Log.d(TAG, "newVideoLoaded - " + videoId);
}
dislikeCount = null;
if (!isEnabled) return;
try {
if (_dislikeFetchThread != null && _dislikeFetchThread.getState() != Thread.State.TERMINATED) {
if (debug) {
Log.d(TAG, "Interrupting the thread. Current state " + _dislikeFetchThread.getState());
}
_dislikeFetchThread.interrupt();
}
}
catch (Exception ex) {
Log.e(TAG, "Error in the dislike fetch thread", ex);
}
_dislikeFetchThread = new Thread(() -> RYDRequester.fetchDislikes(videoId));
_dislikeFetchThread.start();
}
// Call to this needs to be injected in YT code
public static void setLikeTag(View view) {
if (!isEnabled) return;
setTag(view, "like");
}
public static void setLikeTag(View view, boolean active) {
if (!isEnabled) return;
likeActive = active;
if (likeActive) {
votingValue = 1;
}
if (debug) {
Log.d(TAG, "Like tag active " + likeActive);
}
setTag(view, "like");
}
// Call to this needs to be injected in YT code
public static void setDislikeTag(View view) {
if (!isEnabled) return;
_dislikeView = view;
setTag(view, "dislike");
}
public static void setDislikeTag(View view, boolean active) {
if (!isEnabled) return;
dislikeActive = active;
if (dislikeActive) {
votingValue = -1;
}
_dislikeView = view;
if (debug) {
Log.d(TAG, "Dislike tag active " + dislikeActive);
}
setTag(view, "dislike");
}
// Call to this needs to be injected in YT code
public static CharSequence onSetText(View view, CharSequence originalText) {
if (!isEnabled) return originalText;
return handleOnSetText(view, originalText);
}
// Call to this needs to be injected in YT code
public static void onClick(View view, boolean inactive) {
if (!isEnabled) return;
handleOnClick(view, inactive);
}
private static CharSequence handleOnSetText(View view, CharSequence originalText) {
if (!isEnabled) return originalText;
try {
CharSequence tag = (CharSequence) view.getTag();
if (debug) {
Log.d(TAG, "handleOnSetText - " + tag + " - original text - " + originalText);
}
if (tag == null) return originalText;
if (tag == "like") {
return originalText;
}
else if (tag == "dislike") {
return dislikeCount != null ? formatDislikes(dislikeCount) : originalText;
}
}
catch (Exception ex) {
Log.e(TAG, "Error while handling the setText", ex);
}
return originalText;
}
public static void trySetDislikes(String dislikeCount) {
if (!isEnabled) return;
try {
// Try to set normal video dislike count
if (_dislikeView == null) {
if (debug) { Log.d(TAG, "_dislikeView was null"); }
return;
}
View buttonView = _dislikeView.findViewById(getIdentifier("button_text", "id"));
if (buttonView == null) {
if (debug) { Log.d(TAG, "buttonView was null"); }
return;
}
TextView button = (TextView) buttonView;
button.setText(dislikeCount);
if (debug) {
Log.d(TAG, "trySetDislikes - " + dislikeCount);
}
}
catch (Exception ex) {
if (debug) {
Log.e(TAG, "Error while trying to set dislikes text", ex);
}
}
}
private static void handleOnClick(View view, boolean previousState) {
Context context = YouTubeTikTokRoot_Application.getAppContext();
if (!isEnabled || SharedPrefUtils.getBoolean(Objects.requireNonNull(context),"youtube","user_signed_out",true)) return;
try {
String tag = (String) view.getTag();
if (debug) {
Log.d(TAG, "handleOnClick - " + tag + " - previousState - " + previousState);
}
if (tag == null) return;
// If active status was removed, vote should be none
if (previousState) { votingValue = 0; }
if (tag.equals("like")) {
dislikeActive = false;
// Like was activated
if (!previousState) { votingValue = 1; likeActive = true; }
else { likeActive = false; }
// Like was activated and dislike was previously activated
if (!previousState) { dislikeCount--; trySetDislikes(formatDislikes(dislikeCount)); }
}
else if (tag.equals("dislike")) {
likeActive = false;
// Dislike was activated
if (!previousState) { votingValue = -1; dislikeActive = true; dislikeCount++; }
// Dislike was removed
else { dislikeActive = false; dislikeCount--; }
trySetDislikes(formatDislikes(dislikeCount));
}
else {
// Unknown tag
return;
}
if (debug) {
Log.d(TAG, "New vote status - " + votingValue);
Log.d(TAG, "Like button " + likeActive + " | Dislike button " + dislikeActive);
}
sendVote(votingValue);
}
catch (Exception ex) {
Log.e(TAG, "Error while handling the onClick", ex);
}
}
private static void sendVote(int vote) {
if (!isEnabled) return;
if (debug) {
Log.d(TAG, "sending vote - " + vote + " for video " + currentVideoId);
}
try {
if (_votingThread != null && _votingThread.getState() != Thread.State.TERMINATED) {
if (debug) {
Log.d(TAG, "Interrupting the thread. Current state " + _votingThread.getState());
}
_votingThread.interrupt();
}
}
catch (Exception ex) {
Log.e(TAG, "Error in the voting thread", ex);
}
_votingThread = new Thread(() -> {
try {
boolean result = voting.sendVote(currentVideoId, vote);
if (debug) {
Log.d(TAG, "sendVote status " + result);
}
}
catch (Exception ex) {
Log.e(TAG, "Failed to send vote", ex);
}
});
_votingThread.start();
}
private static void setTag(View view, String tag) {
if (!isEnabled) return;
try {
if (view == null) {
if (debug) {
Log.d(TAG, "View was empty");
}
return;
}
if (debug) {
Log.d(TAG, "setTag - " + tag);
}
view.setTag(tag);
}
catch (Exception ex) {
Log.e(TAG, "Error while trying to set tag to view", ex);
}
}
public static String formatDislikes(int dislikes) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && compactNumberFormatter != null) {
final String formatted = compactNumberFormatter.format(dislikes);
if (debug) {
Log.d(TAG, "Formatting dislikes - " + dislikes + " - " + formatted);
}
return formatted;
}
if (debug) {
Log.d(TAG, "Couldn't format dislikes, using the unformatted count - " + dislikes);
}
return String.valueOf(dislikes);
}
}