Commit 7eb720cd authored by Gemini's avatar Gemini Committed by Jakob Moser
Browse files

fix(FavoritesView): Correctly display filtered songs and ensure clear search link

This commit fixes two issues in the favorites tab:

- SongList.mjs:
    - Ensures that filtered favorite songs are displayed alongside the "showing X of Y favorites" message, instead of being hidden by it.
    - The "clear search" link now also appears when a search term filters out all favorites (showing 0 of Y), allowing users to easily return to the full list.
    - Refined message display logic to correctly handle various filter and no-content scenarios.
parent 627f068e
Loading
Loading
Loading
Loading
+75 −68
Original line number Diff line number Diff line
@@ -57,10 +57,9 @@ const SongList = {
    },

    getProcessedSongsForView: function(viewFilter, searchTerm) {
        let initialSongsForView = []; // Songs nach initialer Tab-Filterung
        let messageFromTabFilter = null; // Nachricht, die sich nur aus dem Tab-Filter ergibt
        let initialSongsForView = [];
        let messageFromTabFilter = null;

        // 1. Songs basierend auf dem aktiven Tab vorfiltern
        switch (viewFilter) {
            case 'favorites':
                initialSongsForView = this.allSongs.filter(song => song.isFavorite);
@@ -81,43 +80,38 @@ const SongList = {
                break;
        }

        let songsToProcess = initialSongsForView.slice(); // Kopie für weitere Verarbeitung
        let finalMessage = messageFromTabFilter; // Standardnachricht ist die vom Tab-Filter
        let songsToProcess = initialSongsForView.slice();
        let finalMessage = messageFromTabFilter;

        // 2. Suchbegriff anwenden, falls vorhanden
        if (searchTerm && searchTerm.trim() !== '') {
            const lowerSearchTerm = searchTerm.trim().toLowerCase();
            const searchedSongs = initialSongsForView.filter(song => // Wichtig: auf initialSongsForView filtern
            const searchedSongsResult = initialSongsForView.filter(song =>
                (song.title && song.title.toLowerCase().includes(lowerSearchTerm)) ||
                (song.artist && song.artist.toLowerCase().includes(lowerSearchTerm))
            );

            // Spezielle Logik für Nachrichten im Favoriten-Tab bei aktiver Suche
            if (viewFilter === 'favorites') {
                const totalFavoritesInView = initialSongsForView.length; // Anzahl Favoriten *bevor* Suchfilter angewendet wurde
                if (totalFavoritesInView > 0 && searchedSongs.length < totalFavoritesInView) {
                    if (searchedSongs.length > 0) {
                        // Suche aktiv, einige Favoriten sind sichtbar, aber nicht alle
                const totalFavoritesOverall = initialSongsForView.length; // Alle Favoriten, bevor Suchfilter angewendet wird
                
                if (totalFavoritesOverall > 0) { // Nur wenn es überhaupt Favoriten gibt
                    if (searchedSongsResult.length < totalFavoritesOverall) {
                        // Suche hat Favoriten reduziert ODER alle Favoriten ausgeblendet
                        finalMessage = {
                            type: 'filtered_favorites',
                            total: totalFavoritesInView,
                            showing: searchedSongs.length
                            total: totalFavoritesOverall,
                            showing: searchedSongsResult.length // Kann 0 sein
                        };
                    } else {
                        // Suche aktiv, aber KEINE Favoriten passen zur Suche (obwohl es welche gab)
                        finalMessage = "Deine Suche ergab keine Treffer unter deinen Favoriten.";
                    }
                    // Wenn searchedSongsResult.length == totalFavoritesOverall, hat die Suche nichts ausgeblendet,
                    // also keine spezielle Nachricht nötig, außer der Standard-Tab-Filter-Nachricht.
                }
                // Wenn totalFavoritesInView == 0, ist finalMessage bereits "Du hast noch keine Favoriten..."
                // Wenn searchedSongs.length == totalFavoritesInView, hat die Suche nichts ausgeblendet, keine spezielle Nachricht nötig.
            } else if (searchedSongs.length === 0 && initialSongsForView.length > 0) {
                // Suche auf 'Alle' oder 'Beliebt' ergab 0 Treffer, obwohl Songs zum Durchsuchen da waren
                // Wenn totalFavoritesOverall == 0, ist finalMessage bereits "Du hast noch keine Favoriten..."
            } else if (searchedSongsResult.length === 0 && initialSongsForView.length > 0) {
                finalMessage = "Keine Songs für deine Suche gefunden.";
            }
            songsToProcess = searchedSongs; // Ergebnis der Suche wird zur Liste der anzuzeigenden Songs
            songsToProcess = searchedSongsResult;
        }
        
        // Gruppieren und Sortieren
        const groups = {};
        songsToProcess.forEach(song => {
            groups[song.artist] = groups[song.artist] || [];
@@ -131,7 +125,7 @@ const SongList = {

        return {
            groupedSongs: finalGroupedSongs,
            message: finalMessage, // Kann String oder Objekt sein
            message: finalMessage,
            hasContent: songsToProcess.length > 0
        };
    },
@@ -151,7 +145,7 @@ const SongList = {
    },

    view: function(vnode) {
        const { currentView, searchTerm, onSearchTermChange } = vnode.attrs; // onSearchTermChange hier empfangen
        const { currentView, searchTerm, onSearchTermChange } = vnode.attrs;

        if (this.isLoading && (!this.allSongs || this.allSongs.length === 0)) {
            return m("div.song-list-outer-container", m("div.loading-placeholder", "Lade Songs vom Server..."));
@@ -160,42 +154,48 @@ const SongList = {
        const { groupedSongs, message, hasContent } = this.getProcessedSongsForView(currentView, searchTerm);
        const artists = Object.keys(groupedSongs);
        
        // Spezielle Nachricht für gefilterte Favoriten
        let messageElement = null; // Variable für das Nachrichten-Element

        // Logik für die Nachrichtenanzeige
        if (message && typeof message === 'object' && message.type === 'filtered_favorites') {
            return m("div.song-list-outer-container",
                m("p.view-message", [
                    `Deine Suche zeigt gerade ${message.showing} von deinen insgesamt ${message.total} Favoriten. `,
                    `Suchst du etwas Bestimmtes oder möchtest du `,
                    m("a.clear-search-link", {
                        onclick: (e) => {
                            e.preventDefault(); // Verhindert Standard-Linkverhalten
                            if (onSearchTermChange) {
                                onSearchTermChange(''); // Rufe Callback auf, um Suche zu leeren
            let messageTextIntro = `Deine Suche zeigt gerade ${message.showing} von deinen insgesamt ${message.total} Favoriten. `;
            if (message.showing === 0) {
                messageTextIntro = `Deine Suche ergab keine Treffer unter deinen ${message.total} Favoriten. `;
            }
            
            messageElement = m("p.view-message", [
                messageTextIntro,
                message.total > 0 ? `Möchtest du ` : '', // Nur anzeigen, wenn es Favoriten gibt
                message.total > 0 ? m("a.clear-search-link", {
                    onclick: (e) => {
                        e.preventDefault();
                        if (onSearchTermChange) { onSearchTermChange(''); }
                    },
                        href: "#", // Für Link-Semantik und Tastaturfokus
                        role: "button", // Für Barrierefreiheit
                        tabindex: 0,    // Macht es fokussierbar
                        onkeypress: (e) => { // Für Tastaturbedienung (Enter/Space)
                    href: "#", role: "button", tabindex: 0,
                    onkeypress: (e) => {
                        if ((e.key === 'Enter' || e.key === ' ') && onSearchTermChange) {
                                e.preventDefault();
                                onSearchTermChange('');
                            e.preventDefault(); onSearchTermChange('');
                        }
                    }
                    }, `alle ${message.total} Favoriten anzeigen`),
                    "?"
                ])
            );
                }, `alle ${message.total} Favoriten anzeigen`) : '',
                message.total > 0 ? "?" : ''
            ]);
        } else if (message && typeof message === 'string' && !hasContent) {
            // Standardnachrichten (String), wenn keine Songs angezeigt werden
            return m("div.song-list-outer-container", m("p.view-message", message));
            messageElement = m("p.view-message", message);
        } else if (!message && !hasContent && artists.length === 0 ) {
            // Fall: Keine spezielle Nachricht, aber auch keine Inhalte und keine Künstlergruppen
            // Dies kann passieren, wenn die Filterung (z.B. Suche auf "Alle") alle Songs entfernt hat.
             messageElement = m("p.view-message", "Keine Songs entsprechen den aktuellen Kriterien.");
        }

        if (artists.length === 0 && !message) {
             return m("div.song-list-outer-container", m("p.view-message", "Keine Songs entsprechen den aktuellen Kriterien."));
        // Erstelle die Liste der zu rendernden Elemente
        const elementsToRender = [];
        if (messageElement) {
            elementsToRender.push(messageElement);
        }

        return m("div.song-list-outer-container",
        if (hasContent) {
            elementsToRender.push(
                artists.map(artist =>
                    m("div.artist-group", { key: `${currentView}-${searchTerm || 'all'}-${artist}` }, [
                        m("h2.artist-name", artist),
@@ -210,6 +210,13 @@ const SongList = {
                )
            );
        }
        
        // Wenn es nur eine Nachricht gibt und keine Inhalte, und diese Nachricht schon oben behandelt wurde,
        // dann muss hier nichts mehr für den Fall "!hasContent && !messageElement" getan werden,
        // da der Container dann leer bleibt, was korrekt ist.

        return m("div.song-list-outer-container", elementsToRender);
    }
};

export default SongList;