mirror of
https://github.com/revanced/revanced-integrations
synced 2024-11-22 05:02:19 +01:00
fix(YouTube): Show video chapter titles without clipping when overlay buttons are enabled (#699)
This commit is contained in:
parent
f49d634bc2
commit
325cc17900
@ -0,0 +1,44 @@
|
||||
package app.revanced.integrations.youtube.patches;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class PlayerControlsPatch {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void setFullscreenCloseButton(ImageView imageButton) {
|
||||
// Add a global listener, since the protected method
|
||||
// View#onVisibilityChanged() does not have any call backs.
|
||||
imageButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
int lastVisibility = View.VISIBLE;
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
try {
|
||||
final int visibility = imageButton.getVisibility();
|
||||
if (lastVisibility != visibility) {
|
||||
lastVisibility = visibility;
|
||||
|
||||
Logger.printDebug(() -> "fullscreen button visibility: "
|
||||
+ (visibility == View.VISIBLE ? "VISIBLE" :
|
||||
visibility == View.GONE ? "GONE" : "INVISIBLE"));
|
||||
|
||||
fullscreenButtonVisibilityChanged(visibility == View.VISIBLE);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printDebug(() -> "OnGlobalLayoutListener failure", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// noinspection EmptyMethod
|
||||
public static void fullscreenButtonVisibilityChanged(boolean isVisible) {
|
||||
// Code added during patching.
|
||||
}
|
||||
}
|
@ -145,10 +145,8 @@ public final class LayoutComponentsFilter extends Filter {
|
||||
);
|
||||
|
||||
// The player audio track button does the exact same function as the audio track flyout menu option.
|
||||
// But if the copy url button is shown, these button clashes and the the audio button does not work.
|
||||
// Previously this was a setting to show/hide the player button.
|
||||
// But it was decided it's simpler to always hide this button because:
|
||||
// - it doesn't work with copy video url feature
|
||||
// - the button is rare
|
||||
// - always hiding makes the ReVanced settings simpler and easier to understand
|
||||
// - nobody is going to notice the redundant button is always hidden
|
||||
|
@ -12,8 +12,9 @@ import app.revanced.integrations.youtube.patches.VideoInformation;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import app.revanced.integrations.youtube.videoplayer.BottomControlButton;
|
||||
import app.revanced.integrations.youtube.videoplayer.PlayerControlButton;
|
||||
|
||||
// Edit: This should be a subclass of PlayerControlButton
|
||||
public class CreateSegmentButtonController {
|
||||
private static WeakReference<ImageView> buttonReference = new WeakReference<>(null);
|
||||
private static boolean isShowing;
|
||||
@ -27,9 +28,7 @@ public class CreateSegmentButtonController {
|
||||
ImageView imageView = Objects.requireNonNull(youtubeControlsLayout.findViewById(
|
||||
getResourceIdentifier("revanced_sb_create_segment_button", "id")));
|
||||
imageView.setVisibility(View.GONE);
|
||||
imageView.setOnClickListener(v -> {
|
||||
SponsorBlockViewController.toggleNewSegmentLayoutVisibility();
|
||||
});
|
||||
imageView.setOnClickListener(v -> SponsorBlockViewController.toggleNewSegmentLayoutVisibility());
|
||||
|
||||
buttonReference = new WeakReference<>(imageView);
|
||||
} catch (Exception ex) {
|
||||
@ -37,25 +36,30 @@ public class CreateSegmentButtonController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibilityImmediate(boolean visible) {
|
||||
changeVisibility(visible, true);
|
||||
if (visible) {
|
||||
// Fix button flickering, by pushing this call to the back of
|
||||
// the main thread and letting other layout code run first.
|
||||
Utils.runOnMainThread(() -> setVisibility(true, false));
|
||||
} else {
|
||||
setVisibility(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibilityNegatedImmediate(boolean visible) {
|
||||
changeVisibility(!visible, true);
|
||||
public static void changeVisibility(boolean visible, boolean animated) {
|
||||
// Ignore this call, otherwise with full screen thumbnails the buttons are visible while seeking.
|
||||
if (visible && !animated) return;
|
||||
|
||||
setVisibility(visible, animated);
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean visible) {
|
||||
changeVisibility(visible, false);
|
||||
}
|
||||
|
||||
public static void changeVisibility(boolean visible, boolean immediate) {
|
||||
private static void setVisibility(boolean visible, boolean animated) {
|
||||
try {
|
||||
if (isShowing == visible) return;
|
||||
isShowing = visible;
|
||||
@ -68,8 +72,8 @@ public class CreateSegmentButtonController {
|
||||
if (!shouldBeShown()) {
|
||||
return;
|
||||
}
|
||||
if (!immediate) {
|
||||
iView.startAnimation(BottomControlButton.getButtonFadeIn());
|
||||
if (animated) {
|
||||
iView.startAnimation(PlayerControlButton.getButtonFadeIn());
|
||||
}
|
||||
iView.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
@ -77,8 +81,8 @@ public class CreateSegmentButtonController {
|
||||
|
||||
if (iView.getVisibility() == View.VISIBLE) {
|
||||
iView.clearAnimation();
|
||||
if (!immediate) {
|
||||
iView.startAnimation(BottomControlButton.getButtonFadeOut());
|
||||
if (animated) {
|
||||
iView.startAnimation(PlayerControlButton.getButtonFadeOut());
|
||||
}
|
||||
iView.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -14,8 +14,9 @@ import app.revanced.integrations.youtube.sponsorblock.SegmentPlaybackController;
|
||||
import app.revanced.integrations.youtube.sponsorblock.SponsorBlockUtils;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import app.revanced.integrations.youtube.videoplayer.BottomControlButton;
|
||||
import app.revanced.integrations.youtube.videoplayer.PlayerControlButton;
|
||||
|
||||
// Edit: This should be a subclass of PlayerControlButton
|
||||
public class VotingButtonController {
|
||||
private static WeakReference<ImageView> buttonReference = new WeakReference<>(null);
|
||||
private static boolean isShowing;
|
||||
@ -29,35 +30,41 @@ public class VotingButtonController {
|
||||
ImageView imageView = Objects.requireNonNull(youtubeControlsLayout.findViewById(
|
||||
getResourceIdentifier("revanced_sb_voting_button", "id")));
|
||||
imageView.setVisibility(View.GONE);
|
||||
imageView.setOnClickListener(v -> {
|
||||
SponsorBlockUtils.onVotingClicked(v.getContext());
|
||||
});
|
||||
imageView.setOnClickListener(v -> SponsorBlockUtils.onVotingClicked(v.getContext()));
|
||||
|
||||
buttonReference = new WeakReference<>(imageView);
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "Unable to set RelativeLayout", ex);
|
||||
Logger.printException(() -> "initialize failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibilityImmediate(boolean visible) {
|
||||
changeVisibility(visible, true);
|
||||
if (visible) {
|
||||
// Fix button flickering, by pushing this call to the back of
|
||||
// the main thread and letting other layout code run first.
|
||||
Utils.runOnMainThread(() -> setVisibility(true, false));
|
||||
} else {
|
||||
setVisibility(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibilityNegatedImmediate(boolean visible) {
|
||||
changeVisibility(!visible, true);
|
||||
public static void changeVisibility(boolean visible, boolean animated) {
|
||||
// Ignore this call, otherwise with full screen thumbnails the buttons are visible while seeking.
|
||||
if (visible && !animated) return;
|
||||
|
||||
setVisibility(visible, animated);
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean visible) {
|
||||
changeVisibility(visible, false);
|
||||
}
|
||||
|
||||
public static void changeVisibility(boolean visible, boolean immediate) {
|
||||
private static void setVisibility(boolean visible, boolean animated) {
|
||||
try {
|
||||
if (isShowing == visible) return;
|
||||
isShowing = visible;
|
||||
@ -70,8 +77,8 @@ public class VotingButtonController {
|
||||
if (!shouldBeShown()) {
|
||||
return;
|
||||
}
|
||||
if (!immediate) {
|
||||
iView.startAnimation(BottomControlButton.getButtonFadeIn());
|
||||
if (animated) {
|
||||
iView.startAnimation(PlayerControlButton.getButtonFadeIn());
|
||||
}
|
||||
iView.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
@ -79,8 +86,8 @@ public class VotingButtonController {
|
||||
|
||||
if (iView.getVisibility() == View.VISIBLE) {
|
||||
iView.clearAnimation();
|
||||
if (!immediate) {
|
||||
iView.startAnimation(BottomControlButton.getButtonFadeOut());
|
||||
if (animated) {
|
||||
iView.startAnimation(PlayerControlButton.getButtonFadeOut());
|
||||
}
|
||||
iView.setVisibility(View.GONE);
|
||||
}
|
||||
|
@ -1,83 +0,0 @@
|
||||
package app.revanced.integrations.youtube.videoplayer;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import app.revanced.integrations.shared.settings.BooleanSetting;
|
||||
|
||||
public abstract class BottomControlButton {
|
||||
private static final Animation fadeIn;
|
||||
private static final Animation fadeOut;
|
||||
|
||||
private final WeakReference<ImageView> buttonRef;
|
||||
private final BooleanSetting setting;
|
||||
protected boolean isVisible;
|
||||
|
||||
static {
|
||||
// TODO: check if these durations are correct.
|
||||
fadeIn = Utils.getResourceAnimation("fade_in");
|
||||
fadeIn.setDuration(Utils.getResourceInteger("fade_duration_fast"));
|
||||
|
||||
fadeOut = Utils.getResourceAnimation("fade_out");
|
||||
fadeOut.setDuration(Utils.getResourceInteger("fade_duration_scheduled"));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Animation getButtonFadeIn() {
|
||||
return fadeIn;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Animation getButtonFadeOut() {
|
||||
return fadeOut;
|
||||
}
|
||||
|
||||
public BottomControlButton(@NonNull ViewGroup bottomControlsViewGroup, @NonNull String imageViewButtonId,
|
||||
@NonNull BooleanSetting booleanSetting, @NonNull View.OnClickListener onClickListener,
|
||||
@Nullable View.OnLongClickListener longClickListener) {
|
||||
Logger.printDebug(() -> "Initializing button: " + imageViewButtonId);
|
||||
|
||||
setting = booleanSetting;
|
||||
|
||||
// Create the button.
|
||||
ImageView imageView = Objects.requireNonNull(bottomControlsViewGroup.findViewById(
|
||||
Utils.getResourceIdentifier(imageViewButtonId, "id")
|
||||
));
|
||||
imageView.setOnClickListener(onClickListener);
|
||||
if (longClickListener != null) {
|
||||
imageView.setOnLongClickListener(longClickListener);
|
||||
}
|
||||
imageView.setVisibility(View.GONE);
|
||||
|
||||
buttonRef = new WeakReference<>(imageView);
|
||||
}
|
||||
|
||||
public void setVisibility(boolean visible) {
|
||||
if (isVisible == visible) return;
|
||||
isVisible = visible;
|
||||
|
||||
ImageView imageView = buttonRef.get();
|
||||
if (imageView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
imageView.clearAnimation();
|
||||
if (visible && setting.get()) {
|
||||
imageView.startAnimation(fadeIn);
|
||||
imageView.setVisibility(View.VISIBLE);
|
||||
} else if (imageView.getVisibility() == View.VISIBLE) {
|
||||
imageView.startAnimation(fadeOut);
|
||||
imageView.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,8 @@ import app.revanced.integrations.youtube.patches.CopyVideoUrlPatch;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
|
||||
public class CopyVideoUrlButton extends BottomControlButton {
|
||||
@SuppressWarnings("unused")
|
||||
public class CopyVideoUrlButton extends PlayerControlButton {
|
||||
@Nullable
|
||||
private static CopyVideoUrlButton instance;
|
||||
|
||||
@ -38,9 +39,16 @@ public class CopyVideoUrlButton extends BottomControlButton {
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean showing) {
|
||||
if (instance != null) instance.setVisibility(showing);
|
||||
public static void changeVisibilityImmediate(boolean visible) {
|
||||
if (instance != null) instance.setVisibilityImmediate(visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean visible, boolean animated) {
|
||||
if (instance != null) instance.setVisibility(visible, animated);
|
||||
}
|
||||
}
|
@ -9,7 +9,8 @@ import app.revanced.integrations.youtube.patches.CopyVideoUrlPatch;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
|
||||
public class CopyVideoUrlTimestampButton extends BottomControlButton {
|
||||
@SuppressWarnings("unused")
|
||||
public class CopyVideoUrlTimestampButton extends PlayerControlButton {
|
||||
@Nullable
|
||||
private static CopyVideoUrlTimestampButton instance;
|
||||
|
||||
@ -38,10 +39,16 @@ public class CopyVideoUrlTimestampButton extends BottomControlButton {
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean showing) {
|
||||
if (instance != null) instance.setVisibility(showing);
|
||||
public static void changeVisibilityImmediate(boolean visible) {
|
||||
if (instance != null) instance.setVisibilityImmediate(visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean visible, boolean animated) {
|
||||
if (instance != null) instance.setVisibility(visible, animated);
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@ import app.revanced.integrations.youtube.patches.VideoInformation;
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class ExternalDownloadButton extends BottomControlButton {
|
||||
public class ExternalDownloadButton extends PlayerControlButton {
|
||||
@Nullable
|
||||
private static ExternalDownloadButton instance;
|
||||
|
||||
@ -37,10 +37,17 @@ public class ExternalDownloadButton extends BottomControlButton {
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean showing) {
|
||||
if (instance != null) instance.setVisibility(showing);
|
||||
public static void changeVisibilityImmediate(boolean visible) {
|
||||
if (instance != null) instance.setVisibilityImmediate(visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean visible, boolean animated) {
|
||||
if (instance != null) instance.setVisibility(visible, animated);
|
||||
}
|
||||
|
||||
private static void onDownloadClick(View view) {
|
||||
|
@ -9,7 +9,8 @@ import app.revanced.integrations.youtube.patches.playback.speed.CustomPlaybackSp
|
||||
import app.revanced.integrations.youtube.settings.Settings;
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
|
||||
public class PlaybackSpeedDialogButton extends BottomControlButton {
|
||||
@SuppressWarnings("unused")
|
||||
public class PlaybackSpeedDialogButton extends PlayerControlButton {
|
||||
@Nullable
|
||||
private static PlaybackSpeedDialogButton instance;
|
||||
|
||||
@ -35,9 +36,16 @@ public class PlaybackSpeedDialogButton extends BottomControlButton {
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean showing) {
|
||||
if (instance != null) instance.setVisibility(showing);
|
||||
public static void changeVisibilityImmediate(boolean visible) {
|
||||
if (instance != null) instance.setVisibilityImmediate(visible);
|
||||
}
|
||||
|
||||
/**
|
||||
* injection point
|
||||
*/
|
||||
public static void changeVisibility(boolean visible, boolean animated) {
|
||||
if (instance != null) instance.setVisibility(visible, animated);
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
package app.revanced.integrations.youtube.videoplayer;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Objects;
|
||||
|
||||
import app.revanced.integrations.shared.Logger;
|
||||
import app.revanced.integrations.shared.Utils;
|
||||
import app.revanced.integrations.shared.settings.BooleanSetting;
|
||||
|
||||
public abstract class PlayerControlButton {
|
||||
private static final Animation fadeIn;
|
||||
private static final Animation fadeOut;
|
||||
private static final Animation fadeOutImmediate;
|
||||
|
||||
private final WeakReference<ImageView> buttonRef;
|
||||
protected final BooleanSetting setting;
|
||||
protected boolean isVisible;
|
||||
|
||||
static {
|
||||
// TODO: check if these durations are correct.
|
||||
fadeIn = Utils.getResourceAnimation("fade_in");
|
||||
fadeIn.setDuration(Utils.getResourceInteger("fade_duration_fast"));
|
||||
|
||||
fadeOut = Utils.getResourceAnimation("fade_out");
|
||||
fadeOut.setDuration(Utils.getResourceInteger("fade_duration_scheduled"));
|
||||
|
||||
fadeOutImmediate = Utils.getResourceAnimation("abc_fade_out");
|
||||
fadeOutImmediate.setDuration(Utils.getResourceInteger("fade_duration_fast"));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Animation getButtonFadeIn() {
|
||||
return fadeIn;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Animation getButtonFadeOut() {
|
||||
return fadeOut;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static Animation getButtonFadeOutImmediately() {
|
||||
return fadeOutImmediate;
|
||||
}
|
||||
|
||||
public PlayerControlButton(@NonNull ViewGroup bottomControlsViewGroup, @NonNull String imageViewButtonId,
|
||||
@NonNull BooleanSetting booleanSetting, @NonNull View.OnClickListener onClickListener,
|
||||
@Nullable View.OnLongClickListener longClickListener) {
|
||||
Logger.printDebug(() -> "Initializing button: " + imageViewButtonId);
|
||||
|
||||
ImageView imageView = Objects.requireNonNull(bottomControlsViewGroup.findViewById(
|
||||
Utils.getResourceIdentifier(imageViewButtonId, "id")
|
||||
));
|
||||
imageView.setVisibility(View.GONE);
|
||||
|
||||
imageView.setOnClickListener(onClickListener);
|
||||
if (longClickListener != null) {
|
||||
imageView.setOnLongClickListener(longClickListener);
|
||||
}
|
||||
|
||||
setting = booleanSetting;
|
||||
buttonRef = new WeakReference<>(imageView);
|
||||
}
|
||||
|
||||
public void setVisibilityImmediate(boolean visible) {
|
||||
if (visible) {
|
||||
// Fix button flickering, by pushing this call to the back of
|
||||
// the main thread and letting other layout code run first.
|
||||
Utils.runOnMainThread(() -> private_setVisibility(true, false));
|
||||
} else {
|
||||
private_setVisibility(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVisibility(boolean visible, boolean animated) {
|
||||
// Ignore this call, otherwise with full screen thumbnails the buttons are visible while seeking.
|
||||
if (visible && !animated) return;
|
||||
|
||||
private_setVisibility(visible, animated);
|
||||
}
|
||||
|
||||
private void private_setVisibility(boolean visible, boolean animated) {
|
||||
try {
|
||||
if (isVisible == visible) return;
|
||||
isVisible = visible;
|
||||
|
||||
ImageView iView = buttonRef.get();
|
||||
if (iView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible && setting.get()) {
|
||||
iView.clearAnimation();
|
||||
if (animated) {
|
||||
iView.startAnimation(PlayerControlButton.getButtonFadeIn());
|
||||
}
|
||||
iView.setVisibility(View.VISIBLE);
|
||||
} else if (iView.getVisibility() == View.VISIBLE) {
|
||||
iView.clearAnimation();
|
||||
if (animated) {
|
||||
iView.startAnimation(PlayerControlButton.getButtonFadeOut());
|
||||
}
|
||||
iView.setVisibility(View.GONE);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "setVisibility failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user