diff --git a/src/plugins/touchbar/index.ts b/src/plugins/touchbar/index.ts index 7b5ce5f79a..f393f99a5b 100644 --- a/src/plugins/touchbar/index.ts +++ b/src/plugins/touchbar/index.ts @@ -1,11 +1,12 @@ import { nativeImage, type NativeImage, TouchBar } from 'electron'; +import youtubeMusicIcon from '@assets/youtube-music.png?asset&asarUnpack'; + import { createPlugin } from '@/utils'; import { getSongControls } from '@/providers/song-controls'; import { registerCallback, SongInfoEvent } from '@/providers/song-info'; import { t } from '@/i18n'; -import youtubeMusicIcon from '@assets/youtube-music.png?asset&asarUnpack'; import { Platform } from '@/types/plugins'; export default createPlugin({ diff --git a/src/plugins/video-toggle/button-switcher.css b/src/plugins/video-toggle/button-switcher.css index 3a9796888e..86a4000280 100644 --- a/src/plugins/video-toggle/button-switcher.css +++ b/src/plugins/video-toggle/button-switcher.css @@ -9,84 +9,56 @@ .video-toggle-custom-mode .video-switch-button { z-index: 999; box-sizing: border-box; - padding: 0; - margin-top: 20px; - margin-left: 10px; - background: rgba(33, 33, 33, 0.4); - border-radius: 30px; + padding: 12px; + margin: 20px 10px 0px 10px; + background: rgba(33, 33, 33, 0.7); + border-radius: 50%; overflow: hidden; - width: 20rem; + width: 48px; + height: 48px; text-align: center; - font-size: 18px; - letter-spacing: 1px; color: #fff; - padding-right: 10rem; position: absolute; -} - -.video-toggle-custom-mode .video-switch-button:before { - content: attr(data-video-button-text); - position: absolute; - top: 0; - bottom: 0; - right: 0; - width: 10rem; + cursor: pointer; display: flex; align-items: center; justify-content: center; - z-index: 3; - pointer-events: none; + transition: all 0.2s ease; } -.video-toggle-custom-mode .video-switch-button-checkbox { - cursor: pointer; - position: absolute; - top: 0; - left: 0; - bottom: 0; - width: 100%; - height: 100%; - opacity: 0; - z-index: 2; +.video-toggle-custom-mode .video-switch-button:hover { + background: rgba(33, 33, 33, 0.9); + transform: scale(1.1); } -.video-toggle-custom-mode .video-switch-button-label-span { - position: relative; +.video-toggle-custom-mode .video-toggle-icon { + width: 20px; + height: 20px; + color: #fff; + stroke: currentColor; + fill: none; + pointer-events: none; } -.video-toggle-custom-mode - .video-switch-button-checkbox:checked - + .video-switch-button-label:before { - transform: translateX(10rem); - transition: transform 300ms linear; +.video-toggle-custom-mode #av-id { + display: none; } -.video-toggle-custom-mode - .video-switch-button-checkbox - + .video-switch-button-label { - position: relative; - padding: 15px 0; - display: block; - user-select: none; - pointer-events: none; +.video-toggle-custom-mode #song-video.ytmusic-player, +.video-toggle-custom-mode #song-image { + position: relative !important; + margin: auto !important; + transition: none !important; } -.video-toggle-custom-mode - .video-switch-button-checkbox - + .video-switch-button-label:before { - content: ''; - background: rgba(60, 60, 60, 0.4); - height: 100%; - width: 100%; - position: absolute; - left: 0; - top: 0; - border-radius: 30px; - transform: translateX(0); - transition: transform 300ms; +.video-toggle-custom-mode ytmusic-player { + margin: auto 0px !important; } -/* disable the native toggler */ -.video-toggle-custom-mode #av-id { - display: none; +.video-toggle-custom-mode #song-image img { + max-width: 100% !important; + max-height: 100% !important; + object-fit: cover !important; + display: block !important; + margin: auto !important; } diff --git a/src/plugins/video-toggle/index.tsx b/src/plugins/video-toggle/index.tsx index 4ca9eeb199..c2cf8d424a 100644 --- a/src/plugins/video-toggle/index.tsx +++ b/src/plugins/video-toggle/index.tsx @@ -1,5 +1,4 @@ import { render } from 'solid-js/web'; - import { createSignal, Show } from 'solid-js'; import forceHideStyle from './force-hide.css?inline'; @@ -108,6 +107,7 @@ export default createPlugin({ renderer: { config: null as VideoTogglePluginConfig | null, + setVideoVisible: null as ((visible: boolean) => void) | null, applyStyleClass: (config: VideoTogglePluginConfig) => { if (config.forceHide) { document.body.classList.add('video-toggle-force-hide'); @@ -119,6 +119,7 @@ export default createPlugin({ }, async start({ getConfig }) { const config = await getConfig(); + this.config = config; this.applyStyleClass(config); if (config.forceHide) { @@ -155,10 +156,15 @@ export default createPlugin({ }, async onPlayerApiReady(api, { getConfig }) { const [showButton, setShowButton] = createSignal(true); + const [videoVisible, setVideoVisible] = createSignal(true); const config = await getConfig(); this.config = config; + setVideoVisible(!config.hideVideo); + + this.setVideoVisible = setVideoVisible; + const moveVolumeHud = (await window.mainConfig.plugins.isEnabled( 'precise-volume', )) @@ -177,14 +183,11 @@ export default createPlugin({ () => ( { - const target = e.target as HTMLInputElement; - - setVideoState(target.checked); + initialVideoVisible={videoVisible()} + onVideoToggle={(showVideo) => { + setVideoVisible(showVideo); + setVideoState(showVideo); }} - onClick={(e) => e.stopPropagation()} - songButtonText={t('plugins.video-toggle.templates.button-song')} - videoButtonText={t('plugins.video-toggle.templates.button-video')} /> ), @@ -206,28 +209,35 @@ export default createPlugin({ } window.mainConfig.plugins.setOptions('video-toggle', this.config); - const checkbox = document.querySelector( - '.video-switch-button-checkbox', - ); // custom mode - if (checkbox) checkbox.checked = !this.config?.hideVideo; - if (player) { - player.style.margin = showVideo ? '' : 'auto 0px'; player.setAttribute( 'playback-mode', showVideo ? 'OMV_PREFERRED' : 'ATV_PREFERRED', ); - document.querySelector( + const videoElement = document.querySelector( '#song-video.ytmusic-player', - )!.style.display = showVideo ? 'block' : 'none'; - document.querySelector('#song-image')!.style.display = - showVideo ? 'none' : 'block'; - - if (showVideo && video && !video.style.top) { - video.style.top = `${ - (player.clientHeight - video.clientHeight) / 2 - }px`; + ); + const imageElement = + document.querySelector('#song-image'); + + if (videoElement && imageElement) { + if (showVideo) { + videoElement.style.display = 'block'; + imageElement.style.display = 'none'; + + if (video && !video.style.top) { + video.style.top = `${(player.clientHeight - video.clientHeight) / 2}px`; + } + } else { + videoElement.style.display = 'none'; + imageElement.style.display = 'block'; + + imageElement.style.position = 'relative'; + imageElement.style.width = '100%'; + imageElement.style.height = '100%'; + imageElement.style.margin = 'auto'; + } } moveVolumeHud(showVideo); @@ -314,42 +324,70 @@ export default createPlugin({ }; if (config.mode !== 'native' && config.mode != 'disabled') { - setTimeout(() => { - const playerSelector = - document.querySelector('#player'); - if (!playerSelector) return; - - playerSelector.prepend(switchButtonContainer); - setVideoState(!config.hideVideo); - forcePlaybackMode(); - if (video) { - video.style.height = 'auto'; - } - video?.addEventListener('ytmd:src-changed', videoStarted); - observeThumbnail(); - videoStarted(); - switch (config.align) { - case 'right': { - switchButtonContainer.style.justifyContent = 'flex-end'; - return; - } + const playerSelector = + document.querySelector('#player'); + if (!playerSelector) return; - case 'middle': { - switchButtonContainer.style.justifyContent = 'center'; - return; - } + const initializeConsistentStyling = () => { + const videoElement = document.querySelector( + '#song-video.ytmusic-player', + ); + const imageElement = + document.querySelector('#song-image'); + + if (videoElement && imageElement) { + videoElement.style.position = 'relative'; + videoElement.style.margin = 'auto'; + imageElement.style.position = 'relative'; + imageElement.style.margin = 'auto'; + } + }; + + playerSelector.prepend(switchButtonContainer); + initializeConsistentStyling(); + setVideoState(!config.hideVideo); + forcePlaybackMode(); + if (video) { + video.style.height = 'auto'; + } + video?.addEventListener('ytmd:src-changed', videoStarted); + observeThumbnail(); + videoStarted(); - default: - case 'left': { - switchButtonContainer.style.justifyContent = 'flex-start'; - } + if (this.config) { + const container = document.getElementById( + 'ytmd-video-toggle-switch-button-container', + ); + if (container) { + const alignmentMap = { + right: 'flex-end', + middle: 'center', + left: 'flex-start', + }; + container.style.justifyContent = alignmentMap[this.config.align]; } - }, 0); + } } }, onConfigChange(newConfig) { this.config = newConfig; this.applyStyleClass(newConfig); + + const container = document.getElementById( + 'ytmd-video-toggle-switch-button-container', + ); + if (container) { + const alignmentMap = { + right: 'flex-end', + middle: 'center', + left: 'flex-start', + }; + container.style.justifyContent = alignmentMap[newConfig.align]; + } + + if (this.setVideoVisible) { + this.setVideoVisible(!newConfig.hideVideo); + } }, }, }); diff --git a/src/plugins/video-toggle/templates/video-switch-button.tsx b/src/plugins/video-toggle/templates/video-switch-button.tsx index c996bb9c3f..16009a7651 100644 --- a/src/plugins/video-toggle/templates/video-switch-button.tsx +++ b/src/plugins/video-toggle/templates/video-switch-button.tsx @@ -1,28 +1,71 @@ -export interface VideoSwitchButtonProps { - onClick?: (event: MouseEvent) => void; - onChange?: (event: Event) => void; - songButtonText: string; - videoButtonText: string; +import { createSignal, createEffect } from 'solid-js'; + +interface VideoSwitchButtonProps { + initialVideoVisible?: boolean; + onVideoToggle?: (showVideo: boolean) => void; } -export const VideoSwitchButton = (props: VideoSwitchButtonProps) => ( -
props.onClick?.(e)} - onChange={(e) => props.onChange?.(e)} - > - - -
-); +export const VideoSwitchButton = (props: VideoSwitchButtonProps) => { + const [isVideoVisible, setIsVideoVisible] = createSignal( + props.initialVideoVisible ?? true, + ); + + createEffect(() => { + if (props.initialVideoVisible !== undefined) { + setIsVideoVisible(props.initialVideoVisible); + } + }); + + const toggleVideo = (e: MouseEvent) => { + const newState = !isVideoVisible(); + setIsVideoVisible(newState); + props.onVideoToggle?.(newState); + e.stopPropagation(); + }; + + return ( +
+ + + + + + + +
+ ); +};