From 304bd1e77a5442f614aacd2b35f330777118b2cd Mon Sep 17 00:00:00 2001 From: Pinapelz Date: Mon, 19 Oct 2026 15:32:53 -0700 Subject: merge with upstream https://github.com/RblSb/SyncTube --- src/client/Buttons.hx | 203 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 161 insertions(+), 42 deletions(-) (limited to 'src/client/Buttons.hx') diff --git a/src/client/Buttons.hx b/src/client/Buttons.hx index 82054ab..61f0367 100644 --- a/src/client/Buttons.hx +++ b/src/client/Buttons.hx @@ -5,9 +5,11 @@ import haxe.Timer; import js.Browser.document; import js.Browser.window; import js.html.Element; +import js.html.Event; import js.html.ImageElement; import js.html.InputElement; import js.html.KeyboardEvent; +import js.html.MouseEvent; import js.html.TransitionEvent; import js.html.VisualViewport; @@ -23,11 +25,11 @@ class Buttons { split = new Split(settings); split.setSize(settings.chatSize); - initChatInputs(main); + initInputs(main); for (item in settings.checkboxes) { if (item.checked == null) continue; - final checkbox:InputElement = getEl('#${item.id}') ?? continue; + final checkbox = (getEl('#${item.id}') : InputElement) ?? continue; checkbox.checked = item.checked; } @@ -137,20 +139,30 @@ class Buttons { getEl("#userlist-wrap").style.transition = "200ms"; }, 0); + final playlistMenuBtn = getEl("#playlist-menu-btn"); + final playlistMenuDropdown = getEl("#playlist-menu-dropdown"); + + inline function closePlaylistMenu() { + playlistMenuDropdown.style.display = "none"; + playlistMenuBtn.classList.remove("active"); + } + final toggleSynch = getEl("#togglesynch"); toggleSynch.onclick = e -> { + closePlaylistMenu(); final icon = toggleSynch.firstElementChild; if (main.isSyncActive) { if (!window.confirm(Lang.get("toggleSynchConfirm"))) return; main.isSyncActive = false; icon.style.color = "rgba(238, 72, 67, 0.75)"; - icon.setAttribute("name", "pause"); + playlistMenuBtn.classList.add("danger"); } else { main.isSyncActive = true; icon.style.color = ""; - icon.setAttribute("name", "play"); + playlistMenuBtn.classList.remove("danger"); main.send({type: UpdatePlaylist}); } + updateToggleSynchBtn(main); } final mediaRefresh = getEl("#mediarefresh"); mediaRefresh.onclick = e -> { @@ -158,11 +170,18 @@ class Buttons { } final fullscreenBtn = getEl("#fullscreenbtn"); fullscreenBtn.onclick = e -> { - if ((Utils.isTouch() || main.isVerbose()) && !Utils.hasFullscreen()) { - window.scrollTo(0, 0); - Utils.requestFullscreen(document.documentElement); + Utils.toggleFullscreen(getEl("#ytapiplayer")); + } + final chatBtn = getEl("#fullscreen-chat-btn"); + chatBtn.onclick = e -> { + e.stopPropagation(); + e.preventDefault(); + clearUnreadChatMessages(); + + if (settings.pageFullscreen) { + Utils.switchToPageFullscreen(); } else { - Utils.requestFullscreen(getEl("#ytapiplayer")); + Utils.cancelFullscreen(); } } initPageFullscreen(); @@ -176,13 +195,39 @@ class Buttons { icon.setAttribute("name", "link"); }, 2000); } + + playlistMenuBtn.onclick = e -> { + e.stopPropagation(); + final isOpen = playlistMenuDropdown.style.display != "none"; + if (isOpen) { + closePlaylistMenu(); + } else { + main.hasSeenSkipVote = true; + playlistMenuDropdown.style.display = ""; + playlistMenuBtn.classList.add("active"); + getEl("#playlist-menu-indicator").style.display = "none"; + } + } + + document.addEventListener("click", e -> { + final target:Element = cast e.target; + if (!playlistMenuBtn.contains(target) && !playlistMenuDropdown.contains(target)) { + closePlaylistMenu(); + } + }); + + final voteSkip = getEl("#voteskip"); + voteSkip.addEventListener("click", () -> closePlaylistMenu()); + final clearPlaylist = getEl("#clearplaylist"); clearPlaylist.onclick = e -> { + closePlaylistMenu(); if (!window.confirm(Lang.get("clearPlaylistConfirm"))) return; main.send({type: ClearPlaylist}); } final shufflePlaylist = getEl("#shuffleplaylist"); shufflePlaylist.onclick = e -> { + closePlaylistMenu(); if (!window.confirm(Lang.get("shufflePlaylistConfirm"))) return; main.send({type: ShufflePlaylist}); } @@ -200,6 +245,7 @@ class Buttons { final showMediaUrl = getEl("#showmediaurl"); showMediaUrl.onclick = e -> { + closePlaylistMenu(); final isOpen = showPlayerGroup(showMediaUrl); if (isOpen) Timer.delay(() -> { getEl("#addfromurl").scrollIntoView(); @@ -209,6 +255,7 @@ class Buttons { final showCustomEmbed = getEl("#showcustomembed"); showCustomEmbed.onclick = e -> { + closePlaylistMenu(); final isOpen = showPlayerGroup(showCustomEmbed); if (isOpen) Timer.delay(() -> { getEl("#customembed").scrollIntoView(); @@ -343,6 +390,40 @@ class Buttons { } updateHotkeysBtn(); + final pageFullscreenBtn = getEl("#pageFullscreenBtn"); + pageFullscreenBtn.onclick = e -> { + settings.pageFullscreen = !settings.pageFullscreen; + Settings.write(settings); + updatePageFullscreenBtn(); + + if (settings.pageFullscreen) { + Utils.switchToPageFullscreen(); + } else { + Utils.cancelFullscreen(); + } + } + updatePageFullscreenBtn(); + + final fullscreenActionBtn = getEl("#fullscreenActionBtn"); + if (fullscreenActionBtn != null) { + fullscreenActionBtn.onclick = e -> { + settings.fullscreenAction = !settings.fullscreenAction; + Settings.write(settings); + updateFullscreenActionBtn(); + } + updateFullscreenActionBtn(); + } + + document.body.addEventListener("click", e -> { + if (!settings.pageFullscreen) return; + if (Utils.hasFullscreen()) return; + final target:Element = cast e.target; + if (target != null + && target.closest("button, input, a, textarea, select, #optionsPanel, #chatline, #userlist, .queue_sortable, .nav") != null) + return; + Utils.requestFullscreen(document.documentElement); + }); + final removeBtn = getEl("#removePlayerBtn"); removeBtn.onclick = e -> { final isActive = main.toggleVideoElement(); @@ -367,6 +448,7 @@ class Buttons { JsApi.setVideoSrc(url); }); } + updateToggleSynchBtn(main); } public static function initHotkeys(main:Main, player:Player):Void { @@ -385,6 +467,8 @@ class Buttons { switch (key) { case R: getEl("#mediarefresh").onclick(); + case U: + getEl("#togglesynch").onclick(); case S: getEl("#voteskip").onclick(); case C: @@ -417,12 +501,52 @@ class Buttons { } static function updateHotkeysBtn():Void { - final text = Lang.get("hotkeys"); - final state = settings.hotkeysEnabled ? Lang.get("on") : Lang.get("off"); - getEl("#hotkeysBtn").innerText = '$text: $state'; + final btn = getEl("#hotkeysBtn"); + var switchEl = btn.querySelector(".toggle-switch"); + if (switchEl == null) { + final text = Lang.get("hotkeys"); + btn.innerHTML = '$text
'; + switchEl = btn.querySelector(".toggle-switch"); + } + + switchEl.classList.toggle("on", settings.hotkeysEnabled); + document.body.classList.toggle("hotkeys-disabled", !settings.hotkeysEnabled); + } + + static function updatePageFullscreenBtn():Void { + final btn = getEl("#pageFullscreenBtn"); + var switchEl = btn.querySelector(".toggle-switch"); + if (switchEl == null) { + final text = Lang.get("pageFullscreen"); + btn.innerHTML = '$text
'; + switchEl = btn.querySelector(".toggle-switch"); + } + switchEl.classList.toggle("on", settings.pageFullscreen); } - static function initChatInputs(main:Main):Void { + static function updateFullscreenActionBtn():Void { + final btn = getEl("#fullscreenActionBtn"); + var switchEl = btn.querySelector(".toggle-switch"); + if (switchEl == null) { + final text = Lang.get(Utils.isTouch() ? "fullscreenActionTouch" : "fullscreenActionDesktop"); + btn.innerHTML = '$text
'; + switchEl = btn.querySelector(".toggle-switch"); + } + switchEl.classList.toggle("on", settings.fullscreenAction); + } + + public static function updateToggleSynchBtn(main:Main):Void { + final toggleSynch = getEl("#togglesynch"); + final span = toggleSynch.querySelector("span"); + final textKey = main.isSyncActive ? "disableVideoSync" : "enableVideoSync"; + final text = Lang.get(textKey); + toggleSynch.title = '$text (Alt-U)'; + if (span != null) { + span.innerHTML = '$text (Alt-U)'; + } + } + + static function initInputs(main:Main):Void { final guestName:InputElement = getEl("#guestname"); guestName.onkeydown = e -> { if (e.keyCode == KeyCode.Return) { @@ -440,37 +564,12 @@ class Buttons { } } - final chatline:InputElement = getEl("#chatline"); - chatline.onfocus = e -> { - if (Utils.isIOS()) { - // final startY = window.scrollY; - final startY = 0; - Timer.delay(() -> { - window.scrollBy(0, -(window.scrollY - startY)); - getEl("#video").scrollTop = 0; - main.scrollChatToEnd(); - }, 100); - } else if (Utils.isTouch()) { - main.scrollChatToEnd(); - } - } final viewport = getVisualViewport(); if (viewport != null) { viewport.addEventListener("resize", e -> onViewportResize()); onViewportResize(); } - new InputWithHistory(chatline, 50, value -> { - if (main.handleCommands(value)) return true; - main.send({ - type: Message, - message: { - clientName: "", - text: value - } - }); - if (Utils.isTouch()) chatline.blur(); - return true; - }); + final checkboxes:Array = [ getEl("#add-temp"), ]; @@ -498,12 +597,32 @@ class Buttons { return (window : Dynamic).visualViewport; } + public static var hasUnreadChatMessages:Bool = false; + + public static function onNewChatMessage():Void { + hasUnreadChatMessages = true; + updateFullscreenChatBtn(); + } + + public static function clearUnreadChatMessages():Void { + hasUnreadChatMessages = false; + updateFullscreenChatBtn(); + } + + public static function updateFullscreenChatBtn():Void { + final chatBtn = getEl("#fullscreen-chat-btn"); + final isFs = Utils.hasFullscreen(); + if (isFs && hasUnreadChatMessages) { + chatBtn.classList.add("has-unread"); + } else { + chatBtn.classList.remove("has-unread"); + } + } + static function initPageFullscreen():Void { document.onfullscreenchange = e -> { - final el = document.documentElement; - if (Utils.hasFullscreen()) { - if (e.target == el) el.classList.add("mobile-view"); - } else el.classList.remove("mobile-view"); + clearUnreadChatMessages(); + updateFullscreenChatBtn(); } } } -- cgit v1.2.3