Merge pull request #958 from FlorianZahn/PersistantHighlight

Highlight Button now persists; Implements issue #953
This commit is contained in:
Ajay Ramachandran
2021-09-30 19:33:39 -04:00
committed by GitHub
7 changed files with 112 additions and 51 deletions

View File

@@ -182,15 +182,15 @@
"hideButtonsDescription": { "hideButtonsDescription": {
"message": "This hides the buttons that appear on the YouTube player to submit skip segments." "message": "This hides the buttons that appear on the YouTube player to submit skip segments."
}, },
"showSkipButton": {
"message": "Keep Skip to Highlight Button on Player"
},
"showInfoButton": { "showInfoButton": {
"message": "Show Info Button On YouTube Player" "message": "Show Info Button On YouTube Player"
}, },
"hideInfoButton": { "hideInfoButton": {
"message": "Hide Info Button On YouTube Player" "message": "Hide Info Button On YouTube Player"
}, },
"whatInfoButton": {
"message": "This is the button that opens up a popup in the YouTube page."
},
"autoHideInfoButton": { "autoHideInfoButton": {
"message": "Auto-hide Info Button" "message": "Auto-hide Info Button"
}, },
@@ -200,9 +200,6 @@
"showDeleteButton": { "showDeleteButton": {
"message": "Show Delete Button On YouTube Player" "message": "Show Delete Button On YouTube Player"
}, },
"whatDeleteButton": {
"message": "This is the button on the YouTube player that will clear all your un-submitted segments for the current video."
},
"enableViewTracking": { "enableViewTracking": {
"message": "Enable Skip Count Tracking" "message": "Enable Skip Count Tracking"
}, },
@@ -442,9 +439,6 @@
"showUploadButton": { "showUploadButton": {
"message": "Show Upload Button" "message": "Show Upload Button"
}, },
"whatUploadButton": {
"message": "This button appears on the YouTube player after you have selected a timestamp and are ready to submit."
},
"customServerAddress": { "customServerAddress": {
"message": "SponsorBlock Server Address" "message": "SponsorBlock Server Address"
}, },

View File

@@ -75,16 +75,26 @@
vertical-align: top; vertical-align: top;
} }
#infoButton.playerButton:not(.hidden) { .autoHiding {
transform: translateX(0%) scale(1); overflow: visible !important;
/* opacity is from YouTube page */
transition: transform 0.2s, opacity .1s cubic-bezier(0.4,0.0,1,1) !important;
} }
#infoButton.playerButton.hidden { .autoHiding:not(.hidden) {
transform: translateX(0%) scale(1);
/* opacity is from YouTube page */
transition: transform 0.25s, width 0.25s, opacity .1s cubic-bezier(0.4,0.0,1,1) !important;
}
.autoHiding.hidden {
transform: translateX(100%) scale(0); transform: translateX(100%) scale(0);
/* opacity is from YouTube page */ /* opacity is from YouTube page */
transition: transform 0.2s, opacity .1s cubic-bezier(0.4,0.0,1,1) !important; transition: transform 0.25s, width 0.25s, opacity .1s cubic-bezier(0.4,0.0,1,1) !important;
width: 0px !important;
}
.autoHiding.hidden.autoHideLeft {
transform: translateX(-100%) scale(0);
} }
.playerButton.hidden { .playerButton.hidden {

View File

@@ -288,6 +288,21 @@
<div class="small-description">__MSG_hideButtonsDescription__</div> <div class="small-description">__MSG_hideButtonsDescription__</div>
</div> </div>
<br/>
<div option-type="toggle" toggle-type="reverse" sync-option="hideSkipButtonPlayerControls">
<label class="switch-container">
<label class="switch">
<input type="checkbox" checked>
<span class="slider round"></span>
</label>
<div class="switch-label">
__MSG_showSkipButton__
</div>
</label>
</div>
<br/>
<br/> <br/>
<br/> <br/>
@@ -301,14 +316,9 @@
__MSG_showInfoButton__ __MSG_showInfoButton__
</div> </div>
</label> </label>
<br/>
<br/>
<br/>
<div class="small-description">__MSG_whatInfoButton__</div>
</div> </div>
<br/>
<br/> <br/>
<br/> <br/>
@@ -322,14 +332,12 @@
__MSG_autoHideInfoButton__ __MSG_autoHideInfoButton__
</div> </div>
</label> </label>
<br/>
<br/>
<br/>
<br/>
</div> </div>
<br/>
<br/>
<br/>
<div option-type="toggle" toggle-type="reverse" sync-option="hideDeleteButtonPlayerControls"> <div option-type="toggle" toggle-type="reverse" sync-option="hideDeleteButtonPlayerControls">
<label class="switch-container"> <label class="switch-container">
<label class="switch"> <label class="switch">
@@ -340,14 +348,9 @@
__MSG_showDeleteButton__ __MSG_showDeleteButton__
</div> </div>
</label> </label>
<br/>
<br/>
<br/>
<div class="small-description">__MSG_whatDeleteButton__</div>
</div> </div>
<br/>
<br/> <br/>
<br/> <br/>
@@ -361,14 +364,10 @@
__MSG_showUploadButton__ __MSG_showUploadButton__
</div> </div>
</label> </label>
<br/>
<br/>
<br/>
<div class="small-description">__MSG_whatUploadButton__</div>
</div> </div>
<br/>
<br/>
<br/> <br/>
<br/> <br/>

View File

@@ -26,6 +26,7 @@ interface SBConfig {
hideInfoButtonPlayerControls: boolean, hideInfoButtonPlayerControls: boolean,
hideDeleteButtonPlayerControls: boolean, hideDeleteButtonPlayerControls: boolean,
hideUploadButtonPlayerControls: boolean, hideUploadButtonPlayerControls: boolean,
hideSkipButtonPlayerControls: boolean,
hideDiscordLaunches: number, hideDiscordLaunches: number,
hideDiscordLink: boolean, hideDiscordLink: boolean,
invidiousInstances: string[], invidiousInstances: string[],
@@ -172,6 +173,7 @@ const Config: SBObject = {
hideInfoButtonPlayerControls: false, hideInfoButtonPlayerControls: false,
hideDeleteButtonPlayerControls: false, hideDeleteButtonPlayerControls: false,
hideUploadButtonPlayerControls: false, hideUploadButtonPlayerControls: false,
hideSkipButtonPlayerControls: false,
hideDiscordLaunches: 0, hideDiscordLaunches: 0,
hideDiscordLink: false, hideDiscordLink: false,
invidiousInstances: ["invidious.snopyta.org"], invidiousInstances: ["invidious.snopyta.org"],

View File

@@ -1307,15 +1307,8 @@ async function createButtons(): Promise<void> {
if (Config.config.autoHideInfoButton && !onInvidious && controlsContainer if (Config.config.autoHideInfoButton && !onInvidious && controlsContainer
&& playerButtons["info"]?.button && !controlsWithEventListeners.includes(controlsContainer)) { && playerButtons["info"]?.button && !controlsWithEventListeners.includes(controlsContainer)) {
controlsWithEventListeners.push(controlsContainer); controlsWithEventListeners.push(controlsContainer);
playerButtons["info"].button.classList.add("hidden");
controlsContainer.addEventListener("mouseenter", () => { utils.setupAutoHideAnimation(playerButtons["info"].button, controlsContainer);
playerButtons["info"].button.classList.remove("hidden");
});
controlsContainer.addEventListener("mouseleave", () => {
playerButtons["info"].button.classList.add("hidden");
});
} }
} }

View File

@@ -2,6 +2,8 @@ import Config from "../config";
import { SponsorTime } from "../types"; import { SponsorTime } from "../types";
import { getSkippingText } from "../utils/categoryUtils"; import { getSkippingText } from "../utils/categoryUtils";
import Utils from "../utils";
const utils = new Utils();
export interface SkipButtonControlBarProps { export interface SkipButtonControlBarProps {
skip: (segment: SponsorTime) => void; skip: (segment: SponsorTime) => void;
@@ -53,13 +55,20 @@ export class SkipButtonControlBar {
if (leftControlsContainer && !leftControlsContainer.contains(this.container)) { if (leftControlsContainer && !leftControlsContainer.contains(this.container)) {
leftControlsContainer.insertBefore(this.container, this.chapterText); leftControlsContainer.insertBefore(this.container, this.chapterText);
if (Config.config.autoHideInfoButton) {
utils.setupAutoHideAnimation(this.skipIcon, leftControlsContainer, false, false);
}
} }
} }
enable(segment: SponsorTime, duration?: number): void { enable(segment: SponsorTime, duration?: number): void {
if (duration) this.duration = duration; if (duration) this.duration = duration;
this.segment = segment; this.segment = segment;
this.refreshText(); this.refreshText();
this.textContainer?.classList?.remove("hidden");
utils.disableAutoHideAnimation(this.skipIcon);
this.startTimer(); this.startTimer();
} }
@@ -68,7 +77,8 @@ export class SkipButtonControlBar {
if (this.segment) { if (this.segment) {
this.chapterText?.classList?.add("hidden"); this.chapterText?.classList?.add("hidden");
this.container.classList.remove("hidden"); this.container.classList.remove("hidden");
this.textContainer.innerText = getSkippingText([this.segment], false) + (this.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : ""); this.textContainer.innerText = this.getTitle();
this.skipIcon.setAttribute("title", this.getTitle());
} }
} }
@@ -84,17 +94,42 @@ export class SkipButtonControlBar {
startTimer(): void { startTimer(): void {
this.stopTimer(); this.stopTimer();
this.timeout = setTimeout(() => this.disable(), Math.max(Config.config.skipNoticeDuration, this.duration) * 1000); this.timeout = setTimeout(() => this.disableText(), Math.max(Config.config.skipNoticeDuration, this.duration) * 1000);
} }
disable(): void { disable(): void {
this.container.classList.add("hidden"); this.container.classList.add("hidden");
this.textContainer?.classList?.remove("hidden");
this.chapterText?.classList?.remove("hidden"); this.chapterText?.classList?.remove("hidden");
this.getChapterPrefix()?.classList?.remove("hidden");
} }
toggleSkip(): void { toggleSkip(): void {
this.skip(this.segment); this.skip(this.segment);
this.disable(); this.disableText();
}
disableText(): void {
if (Config.config.hideVideoPlayerControls || Config.config.hideSkipButtonPlayerControls) {
this.disable();
return;
}
this.textContainer?.classList?.add("hidden");
this.chapterText?.classList?.remove("hidden");
this.getChapterPrefix()?.classList?.add("hidden");
utils.enableAutoHideAnimation(this.skipIcon);
}
private getTitle(): string {
return getSkippingText([this.segment], false) + (this.showKeybindHint ? " (" + Config.config.skipKeybind + ")" : "");
}
private getChapterPrefix(): HTMLElement {
return document.querySelector(".ytp-chapter-title-prefix");
} }
} }

View File

@@ -183,6 +183,34 @@ export default class Utils {
} }
} }
setupAutoHideAnimation(element: Element, container: Element, enabled = true, rightSlide = true): void {
if (enabled) element.classList.add("autoHiding");
element.classList.add("hidden");
element.classList.add("animationDone");
if (!rightSlide) element.classList.add("autoHideLeft");
container.addEventListener("mouseenter", () => {
element.classList.remove("animationDone");
// Wait for next event loop
setTimeout(() => element.classList.remove("hidden"), 10);
});
container.addEventListener("mouseleave", () => {
if (element.classList.contains("autoHiding")) {
element.classList.add("hidden");
}
});
}
enableAutoHideAnimation(element: Element): void {
element.classList.add("autoHiding");
}
disableAutoHideAnimation(element: Element): void {
element.classList.remove("autoHiding");
}
/** /**
* Merges any overlapping timestamp ranges into single segments and returns them as a new array. * Merges any overlapping timestamp ranges into single segments and returns them as a new array.
*/ */