Split software arch desc for easier manintenance. Many fixes related to next video playing and remote playback
This commit is contained in:
@@ -31,11 +31,9 @@
|
||||
import { formatTime, calculateProgress } from "$lib/utils/playbackUnits";
|
||||
import { haptics } from "$lib/utils/haptics";
|
||||
import { toast } from "$lib/stores/toast";
|
||||
import { sleepTimerActive } from "$lib/stores/sleepTimer";
|
||||
import Controls from "./Controls.svelte";
|
||||
import FavoriteButton from "$lib/components/FavoriteButton.svelte";
|
||||
import CastButton from "$lib/components/sessions/CastButton.svelte";
|
||||
import SleepTimerIndicator from "./SleepTimerIndicator.svelte";
|
||||
import VolumeControl from "./VolumeControl.svelte";
|
||||
import CachedImage from "../common/CachedImage.svelte";
|
||||
|
||||
@@ -289,14 +287,14 @@
|
||||
|
||||
<div
|
||||
role="region"
|
||||
class="px-4 py-3 flex items-center gap-4 touch-pan-y relative"
|
||||
class="px-4 py-2 touch-pan-y relative"
|
||||
ontouchstart={handleTouchStart}
|
||||
ontouchmove={handleTouchMove}
|
||||
ontouchend={handleTouchEnd}
|
||||
style="transform: translateX({swipeTransform}px); transition: {isSwiping ? 'none' : 'transform 0.3s ease-out'}"
|
||||
>
|
||||
<!-- Media info -->
|
||||
<div class="flex items-center gap-3 flex-1 min-w-0">
|
||||
<!-- Row 1: Media info, like, cast, overflow -->
|
||||
<div class="flex items-center gap-3">
|
||||
<!-- Artwork -->
|
||||
<div
|
||||
class="w-12 h-12 rounded bg-gray-800 flex-shrink-0 overflow-hidden"
|
||||
@@ -354,146 +352,127 @@
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Favorite Button -->
|
||||
{#if displayMedia}
|
||||
<div class="hidden sm:block">
|
||||
<!-- Like Button -->
|
||||
{#if displayMedia}
|
||||
<FavoriteButton
|
||||
itemId={displayMedia?.id ?? ""}
|
||||
isFavorite={displayMedia?.userData?.isFavorite ?? false}
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Cast Button (visible on all screen sizes) -->
|
||||
<CastButton size="sm" />
|
||||
|
||||
<!-- Sleep Timer Button (always visible on larger screens) -->
|
||||
{#if !$sleepTimerActive}
|
||||
<button
|
||||
onclick={(e) => {
|
||||
e.stopPropagation();
|
||||
onSleepTimerClick?.();
|
||||
}}
|
||||
ontouchstart={(e) => e.stopPropagation()}
|
||||
ontouchmove={(e) => e.stopPropagation()}
|
||||
ontouchend={(e) => e.stopPropagation()}
|
||||
class="p-2 rounded-full hover:bg-white/10 transition-colors hidden sm:block"
|
||||
title="Sleep timer"
|
||||
aria-label="Sleep timer"
|
||||
>
|
||||
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
<!-- Sleep Timer Indicator (shows when active) -->
|
||||
<SleepTimerIndicator onClick={onSleepTimerClick} />
|
||||
|
||||
<!-- Volume Control (Linux only) -->
|
||||
<div class="hidden sm:block">
|
||||
<VolumeControl size="sm" />
|
||||
</div>
|
||||
|
||||
<!-- Time -->
|
||||
<div class="text-xs text-gray-400 hidden sm:block">
|
||||
{formatTime(displayPosition)} / {formatTime(displayDuration)}
|
||||
</div>
|
||||
|
||||
<!-- Controls -->
|
||||
<Controls
|
||||
isPlaying={displayIsPlaying}
|
||||
{hasPrevious}
|
||||
{hasNext}
|
||||
{shuffle}
|
||||
{repeat}
|
||||
onPlayPause={handlePlayPause}
|
||||
onPrevious={handlePrevious}
|
||||
onNext={handleNext}
|
||||
onToggleShuffle={handleToggleShuffle}
|
||||
onCycleRepeat={handleCycleRepeat}
|
||||
{onSleepTimerClick}
|
||||
/>
|
||||
|
||||
<!-- Overflow Menu Button -->
|
||||
<div class="relative">
|
||||
<button
|
||||
onclick={() => {
|
||||
showOverflowMenu = !showOverflowMenu;
|
||||
haptics.tap();
|
||||
}}
|
||||
class="p-2 hover:bg-white/10 rounded-full transition-colors"
|
||||
aria-label="More options"
|
||||
>
|
||||
<svg class="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Overflow Menu Dropdown -->
|
||||
{#if showOverflowMenu}
|
||||
<div
|
||||
class="absolute bottom-full right-0 mb-2 w-56 bg-[var(--color-surface)] border border-gray-700 rounded-lg shadow-2xl overflow-hidden z-[70]"
|
||||
role="menu"
|
||||
>
|
||||
<button
|
||||
onclick={handleViewQueue}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
||||
</svg>
|
||||
View Queue
|
||||
</button>
|
||||
|
||||
{#if displayMedia?.albumId}
|
||||
<button
|
||||
onclick={handleGoToAlbum}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 14.5v-9l6 4.5-6 4.5z"/>
|
||||
</svg>
|
||||
Go to Album
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if displayMedia?.artistItems?.length}
|
||||
<button
|
||||
onclick={handleGoToArtist}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
|
||||
</svg>
|
||||
Go to Artist
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
onclick={handleAddToPlaylist}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
Add to Playlist
|
||||
</button>
|
||||
|
||||
<button
|
||||
onclick={handleShare}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
|
||||
</svg>
|
||||
Share
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Cast Button -->
|
||||
<CastButton size="sm" />
|
||||
|
||||
<!-- Overflow Menu Button -->
|
||||
<div class="relative">
|
||||
<button
|
||||
onclick={() => {
|
||||
showOverflowMenu = !showOverflowMenu;
|
||||
haptics.tap();
|
||||
}}
|
||||
class="p-2 hover:bg-white/10 rounded-full transition-colors"
|
||||
aria-label="More options"
|
||||
>
|
||||
<svg class="w-5 h-5 text-gray-400" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<!-- Overflow Menu Dropdown -->
|
||||
{#if showOverflowMenu}
|
||||
<div
|
||||
class="absolute bottom-full right-0 mb-2 w-56 bg-[var(--color-surface)] border border-gray-700 rounded-lg shadow-2xl overflow-hidden z-[70]"
|
||||
role="menu"
|
||||
>
|
||||
<button
|
||||
onclick={handleViewQueue}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 10h16M4 14h16M4 18h16" />
|
||||
</svg>
|
||||
View Queue
|
||||
</button>
|
||||
|
||||
{#if displayMedia?.albumId}
|
||||
<button
|
||||
onclick={handleGoToAlbum}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 14.5v-9l6 4.5-6 4.5z"/>
|
||||
</svg>
|
||||
Go to Album
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
{#if displayMedia?.artistItems?.length}
|
||||
<button
|
||||
onclick={handleGoToArtist}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
|
||||
</svg>
|
||||
Go to Artist
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<button
|
||||
onclick={handleAddToPlaylist}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
||||
</svg>
|
||||
Add to Playlist
|
||||
</button>
|
||||
|
||||
<button
|
||||
onclick={handleShare}
|
||||
class="w-full px-4 py-3 text-left text-sm text-white hover:bg-white/10 transition-colors flex items-center gap-3"
|
||||
>
|
||||
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
|
||||
</svg>
|
||||
Share
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row 2: Playback controls (play/pause centered) -->
|
||||
<div class="flex items-center mt-1">
|
||||
<div class="flex-1"></div>
|
||||
|
||||
<Controls
|
||||
isPlaying={displayIsPlaying}
|
||||
{hasPrevious}
|
||||
{hasNext}
|
||||
{shuffle}
|
||||
{repeat}
|
||||
onPlayPause={handlePlayPause}
|
||||
onPrevious={handlePrevious}
|
||||
onNext={handleNext}
|
||||
onToggleShuffle={handleToggleShuffle}
|
||||
onCycleRepeat={handleCycleRepeat}
|
||||
{onSleepTimerClick}
|
||||
/>
|
||||
|
||||
<div class="flex-1 flex items-center justify-end gap-2">
|
||||
<!-- Volume Control (desktop only) -->
|
||||
<div class="hidden sm:block">
|
||||
<VolumeControl size="sm" />
|
||||
</div>
|
||||
|
||||
<!-- Time (desktop only) -->
|
||||
<div class="text-xs text-gray-400 hidden sm:block">
|
||||
{formatTime(displayPosition)} / {formatTime(displayDuration)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user