Ajout de l'indicateur visuel 'Web Radio' pour les flux continus
Implémentation complète de l'étape 2 : ajout d'un indicateur visuel "Web Radio" dans l'interface web pour signaler la lecture d'un flux continu. Cet indicateur s'affiche à côté de l'indicateur "Attachée à une playlist" dans le composant QueueViewer. Changements principaux : - Ajout du champ `is_stream` dans `FullRendererSnapshot` pour transmettre l'état du flux au frontend - Intégration de l'indicateur visuel dans `QueueViewer.vue` avec l'icône Radio - Gestion de l'événement `stream_state_changed` dans le composant `useRenderers.ts` - Mise à jour des types TypeScript pour inclure le nouveau champ `is_stream` - Refactorisation de `sse.rs` pour éliminer la duplication de code Cette fonctionnalité permet aux utilisateurs de savoir rapidement si la lecture en cours est un flux continu (webradio) ou un fichier audio traditionnel.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import { computed, ref, watch, nextTick, toRef } from "vue";
|
||||
import { useRenderer } from "@/composables/useRenderers";
|
||||
import QueueItem from "./QueueItem.vue";
|
||||
import { Link } from "lucide-vue-next";
|
||||
import { Link, Radio } from "lucide-vue-next";
|
||||
import type { QueueItem as QueueItemType } from "@/services/pmocontrol/types";
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -13,7 +13,7 @@ const emit = defineEmits<{
|
||||
clickItem: [item: QueueItemType];
|
||||
}>();
|
||||
|
||||
const { queue, binding } = useRenderer(toRef(props, "rendererId"));
|
||||
const { queue, binding, isStream } = useRenderer(toRef(props, "rendererId"));
|
||||
|
||||
const isAttached = computed(() => !!binding.value);
|
||||
|
||||
@@ -59,10 +59,19 @@ watch(
|
||||
</span>
|
||||
</h3>
|
||||
|
||||
<!-- Indicateur playlist attachée -->
|
||||
<div v-if="isAttached" class="binding-indicator">
|
||||
<Link :size="16" />
|
||||
<span class="binding-text"> Attachée à une playlist </span>
|
||||
<!-- Indicateurs de status -->
|
||||
<div class="status-indicators">
|
||||
<!-- Indicateur playlist attachée -->
|
||||
<div v-if="isAttached" class="binding-indicator">
|
||||
<Link :size="16" />
|
||||
<span class="binding-text"> Attachée à une playlist </span>
|
||||
</div>
|
||||
|
||||
<!-- Indicateur web radio -->
|
||||
<div v-if="isStream" class="stream-indicator">
|
||||
<Radio :size="16" />
|
||||
<span class="stream-text"> Web Radio </span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -111,6 +120,12 @@ watch(
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.status-indicators {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.binding-indicator {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@@ -129,6 +144,24 @@ watch(
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
|
||||
.stream-indicator {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-xs);
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
background-color: rgba(147, 51, 234, 0.1);
|
||||
color: #9333ea;
|
||||
border-radius: var(--radius-md);
|
||||
font-size: var(--text-sm);
|
||||
font-weight: 500;
|
||||
border: 1px solid #9333ea;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.stream-text {
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
|
||||
.queue-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
|
||||
@@ -190,6 +190,10 @@ function ensureSSEConnected() {
|
||||
}
|
||||
break;
|
||||
|
||||
case "stream_state_changed":
|
||||
snapshot.is_stream = event.is_stream;
|
||||
break;
|
||||
|
||||
case "timer_started":
|
||||
case "timer_updated":
|
||||
case "timer_tick":
|
||||
@@ -467,6 +471,7 @@ export function useRenderer(rendererId: Ref<string>) {
|
||||
const state = computed(() => snapshot.value?.state ?? null);
|
||||
const queue = computed(() => snapshot.value?.queue ?? null);
|
||||
const binding = computed(() => snapshot.value?.binding ?? null);
|
||||
const isStream = computed(() => snapshot.value?.is_stream ?? false);
|
||||
|
||||
async function refresh(force = true) {
|
||||
await Promise.all([
|
||||
@@ -481,6 +486,7 @@ export function useRenderer(rendererId: Ref<string>) {
|
||||
state,
|
||||
queue,
|
||||
binding,
|
||||
isStream,
|
||||
refresh,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ export interface FullRendererSnapshot {
|
||||
state: RendererState;
|
||||
queue: QueueSnapshot;
|
||||
binding: AttachedPlaylistInfo | null;
|
||||
is_stream: boolean;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -200,6 +201,12 @@ export type RendererEventPayload =
|
||||
container_id: string | null;
|
||||
timestamp: string;
|
||||
}
|
||||
| {
|
||||
type: "stream_state_changed";
|
||||
renderer_id: string;
|
||||
is_stream: boolean;
|
||||
timestamp: string;
|
||||
}
|
||||
| {
|
||||
type: "timer_started";
|
||||
renderer_id: string;
|
||||
|
||||
Reference in New Issue
Block a user