From 228fdfad1ebeed95e423898aad2628d88967374f Mon Sep 17 00:00:00 2001 From: Fuwn Date: Thu, 21 May 2026 13:30:34 +0000 Subject: fix(lists): optimistic increment and snapshot to remove refresh flash Click + on a Due item now bumps progress locally and drops the row if the bump catches the user up, with no upfront refresh. The mutation fires in the background and triggers a single revalidate on response. Also snapshot the resolved media to previousAnimeList on every render, so refreshes from any path (countdown, interval, manual, post-increment) show the prior list during pending instead of a placeholder. --- src/lib/List/Anime/CleanAnimeList.svelte | 46 ++++++++++++++++---------------- 1 file changed, 23 insertions(+), 23 deletions(-) (limited to 'src/lib/List/Anime/CleanAnimeList.svelte') diff --git a/src/lib/List/Anime/CleanAnimeList.svelte b/src/lib/List/Anime/CleanAnimeList.svelte index 23d87a97..3f397c25 100644 --- a/src/lib/List/Anime/CleanAnimeList.svelte +++ b/src/lib/List/Anime/CleanAnimeList.svelte @@ -9,6 +9,7 @@ import type { AniListAuthorisation } from "$lib/Data/AniList/identity"; import ListTitle from "../ListTitle.svelte"; import { onDestroy, onMount } from "svelte"; import AiringTime from "$lib/Media/Anime/Airing/AiringTime.svelte"; +import { hasDueEpisodes } from "$lib/Media/Anime/Airing/classify"; import { browser } from "$app/environment"; import identity from "$stores/identity"; import "../covers.css"; @@ -109,6 +110,9 @@ $: filteredMedia = ? media : media.filter((m) => m.mediaListEntry?.customLists?.[selectedList]); +$: if (browser && !dummy && media && previousAnimeList !== media) + previousAnimeList = media; + const updateSelectedList = (event: Event) => { const nextSelectedList = (event.currentTarget as HTMLSelectElement).value; @@ -206,28 +210,24 @@ $: if (browser && !dummy) { onDestroy(() => clearAiringRefreshTimeout()); const increment = (anime: Media, progress: number) => { - if (!dummy && pendingUpdate !== anime.id) { + if (dummy || pendingUpdate === anime.id) return; + + pendingUpdate = anime.id; + lastUpdatedMedia = anime.id; + + const target = media.find((m) => m.id === anime.id); + + if (target?.mediaListEntry) target.mediaListEntry.progress = progress + 1; + + media = + !completed && target && !hasDueEpisodes(target) + ? media.filter((m) => m.id !== anime.id) + : media; + + incrementMediaProgress(anime.id, anime.mediaListEntry?.progress, user, () => { + pendingUpdate = null; $revalidateAnime = $revalidateAnime + 1; - lastUpdatedMedia = anime.id; - pendingUpdate = anime.id; - - incrementMediaProgress( - anime.id, - anime.mediaListEntry?.progress, - user, - () => { - const mediaListEntry = media.find( - (m) => m.id === anime.id, - )?.mediaListEntry; - - if (mediaListEntry) mediaListEntry.progress = progress + 1; - - previousAnimeList = media; - animeLists = cleanCache(user, $identity); - pendingUpdate = null; - }, - ); - } + }); }; @@ -279,7 +279,7 @@ const increment = (anime: Media, progress: number) => { >
{#if !upcoming && !notYetReleased} - {pendingUpdate === anime.id ? progress + 1 : progress}{@html totalEpisodes(anime)} + {progress}{@html totalEpisodes(anime)}