feat(ui): show per-service login status while accounts are being checked
When the app starts it verifies all three services sequentially, which could leave the other two login controls looking idle or trigger login actions before their real state is known. Track which service is currently being checked and reflect it in the header: - Add a serviceLoggingIn store (plus setServiceLoggingIn and isServiceLoggingIn helpers) to GlobalVariablesAndHelperFunctions. - Have the loginTo* functions and the startup CheckIf* functions toggle their service in the store (seed all three at startup, clear each as it resolves). - In Header, the login buttons show a spinner with 'Checking AniList' / 'Checking MAL' / 'Checking Simkl' and are disabled while that service is being checked, reverting to the normal 'AniList Login' style label once its state is known. - In the avatar menu, the 'Login to X' row shows a spinner with the matching 'Checking X' text while that service is logging in.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
simklPrimary,
|
||||
malWatchList,
|
||||
simklWatchList,
|
||||
serviceLoggingIn,
|
||||
} from "./helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import Router from "svelte-spa-router";
|
||||
@@ -35,6 +36,8 @@
|
||||
malLoggedIn.subscribe((value) => (isMALLoggedIn = value));
|
||||
simklLoggedIn.subscribe((value) => (isSimklLoggedIn = value));
|
||||
|
||||
serviceLoggingIn.set(["anilist", "mal", "simkl"]);
|
||||
|
||||
!isAniListLoggedIn && (await CheckIfAniListLoggedInAndLoadWatchList());
|
||||
!isMALLoggedIn && (await CheckIfMALLoggedInAndSetUser());
|
||||
!isSimklLoggedIn && (await CheckIfSimklLoggedInAndSetUser());
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
logoutOfAniList,
|
||||
logoutOfMAL,
|
||||
logoutOfSimkl,
|
||||
serviceLoggingIn,
|
||||
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import * as runtime from "../../wailsjs/runtime";
|
||||
import type { MyAnimeListUser } from "../mal/types/MALTypes";
|
||||
@@ -26,6 +27,7 @@
|
||||
let isAniListLoggedIn: boolean;
|
||||
let isSimklLoggedIn: boolean;
|
||||
let isMALLoggedIn: boolean;
|
||||
let loggingIn: string[] = [];
|
||||
|
||||
aniListUser.subscribe((value) => (currentAniListUser = value));
|
||||
malUser.subscribe((value) => (currentMALUser = value));
|
||||
@@ -33,6 +35,7 @@
|
||||
aniListLoggedIn.subscribe((value) => (isAniListLoggedIn = value));
|
||||
simklLoggedIn.subscribe((value) => (isSimklLoggedIn = value));
|
||||
malLoggedIn.subscribe((value) => (isMALLoggedIn = value));
|
||||
serviceLoggingIn.subscribe((value) => (loggingIn = value));
|
||||
|
||||
function dropdownUser(): void {
|
||||
let dropdown = document.querySelector("#userDropdown");
|
||||
@@ -98,6 +101,14 @@
|
||||
</li>
|
||||
{:else}
|
||||
<li>
|
||||
{#if loggingIn.includes("anilist")}
|
||||
<span class="flex items-center px-4 py-2 w-full truncate">
|
||||
<span
|
||||
class="inline-block w-4 h-4 mr-4 border-2 border-gray-300 border-t-transparent rounded-full animate-spin"
|
||||
></span>
|
||||
<span class="maple-font text-lg mr-4">A</span>Checking AniList
|
||||
</span>
|
||||
{:else}
|
||||
<button
|
||||
on:click={() => {
|
||||
dropdownUser();
|
||||
@@ -107,6 +118,7 @@
|
||||
>
|
||||
<span class="maple-font text-lg mr-4">A</span>Login to AniList
|
||||
</button>
|
||||
{/if}
|
||||
</li>
|
||||
{/if}
|
||||
{#if isMALLoggedIn}
|
||||
@@ -120,6 +132,14 @@
|
||||
</li>
|
||||
{:else}
|
||||
<li>
|
||||
{#if loggingIn.includes("mal")}
|
||||
<span class="flex items-center px-4 py-2 w-full truncate">
|
||||
<span
|
||||
class="inline-block w-4 h-4 mr-4 border-2 border-gray-300 border-t-transparent rounded-full animate-spin"
|
||||
></span>
|
||||
<span class="maple-font text-lg mr-4">M</span>Checking MyAnimeList
|
||||
</span>
|
||||
{:else}
|
||||
<button
|
||||
on:click={() => {
|
||||
dropdownUser();
|
||||
@@ -129,6 +149,7 @@
|
||||
>
|
||||
<span class="maple-font text-lg mr-4">M</span>Login to MyAnimeList
|
||||
</button>
|
||||
{/if}
|
||||
</li>
|
||||
{/if}
|
||||
{#if isSimklLoggedIn}
|
||||
@@ -143,6 +164,14 @@
|
||||
</li>
|
||||
{:else}
|
||||
<li>
|
||||
{#if loggingIn.includes("simkl")}
|
||||
<span class="flex items-center px-4 py-2 w-full truncate">
|
||||
<span
|
||||
class="inline-block w-4 h-4 mr-4 border-2 border-gray-300 border-t-transparent rounded-full animate-spin"
|
||||
></span>
|
||||
<span class="maple-font text-lg mr-4">S</span>Checking Simkl
|
||||
</span>
|
||||
{:else}
|
||||
<button
|
||||
on:click={() => {
|
||||
dropdownUser();
|
||||
@@ -152,6 +181,7 @@
|
||||
>
|
||||
<span class="maple-font text-lg mr-4">S</span>Login to Simkl
|
||||
</button>
|
||||
{/if}
|
||||
</li>
|
||||
{/if}
|
||||
</ul>
|
||||
@@ -174,4 +204,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
loginToSimkl,
|
||||
malLoggedIn,
|
||||
simklLoggedIn,
|
||||
serviceLoggingIn,
|
||||
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
||||
import AvatarMenu from "./AvatarMenu.svelte";
|
||||
import logo from "../assets/images/AniTrackLogo.svg";
|
||||
@@ -15,10 +16,12 @@
|
||||
let isAniListLoggedIn: boolean;
|
||||
let isSimklLoggedIn: boolean;
|
||||
let isMALLoggedIn: boolean;
|
||||
let loggingIn: string[] = [];
|
||||
|
||||
aniListLoggedIn.subscribe((value) => (isAniListLoggedIn = value));
|
||||
simklLoggedIn.subscribe((value) => (isSimklLoggedIn = value));
|
||||
malLoggedIn.subscribe((value) => (isMALLoggedIn = value));
|
||||
serviceLoggingIn.subscribe((value) => (loggingIn = value));
|
||||
</script>
|
||||
|
||||
<nav class="border-gray-200 bg-gray-900">
|
||||
@@ -74,23 +77,50 @@
|
||||
>
|
||||
<li>
|
||||
{#if !isAniListLoggedIn}
|
||||
<button on:click={loginToAniList}>
|
||||
<!-- class="block py-2 px-3 w-full min-[950px]:w-auto rounded text-gray-300 min-[950px]:hover:text-blue-500 hover:bg-gray-700 hover:text-white min-[950px]:hover:bg-transparent border-gray-700">-->
|
||||
<button
|
||||
disabled={loggingIn.includes("anilist")}
|
||||
on:click={loginToAniList}
|
||||
>
|
||||
{#if loggingIn.includes("anilist")}
|
||||
<span
|
||||
class="inline-block w-4 h-4 mr-2 border-2 border-gray-300 border-t-transparent rounded-full animate-spin align-middle"
|
||||
></span
|
||||
>Checking AniList
|
||||
{:else}
|
||||
AniList Login
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
{#if !isMALLoggedIn}
|
||||
<button on:click={loginToMAL}>
|
||||
<!-- class="block py-2 px-3 w-full min-[950px]:w-auto rounded min-[950px]:p-0 text-gray-300 min-[950px]:hover:text-blue-500 hover:bg-gray-700 hover:text-white min-[950px]:hover:bg-transparent border-gray-700">-->
|
||||
<button
|
||||
disabled={loggingIn.includes("mal")}
|
||||
on:click={loginToMAL}
|
||||
>
|
||||
{#if loggingIn.includes("mal")}
|
||||
<span
|
||||
class="inline-block w-4 h-4 mr-2 border-2 border-gray-300 border-t-transparent rounded-full animate-spin align-middle"
|
||||
></span
|
||||
>Checking MAL
|
||||
{:else}
|
||||
MyAnimeList Login
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
</li>
|
||||
<li>
|
||||
{#if !isSimklLoggedIn}
|
||||
<button on:click={loginToSimkl}>
|
||||
<!-- class="block py-2 px-3 w-full min-[950px]:w-auto rounded min-[950px]:p-0 text-gray-300 min-[950px]:hover:text-blue-500 hover:bg-gray-700 hover:text-white min-[950px]:hover:bg-transparent border-gray-700">-->
|
||||
<button
|
||||
disabled={loggingIn.includes("simkl")}
|
||||
on:click={loginToSimkl}
|
||||
>
|
||||
{#if loggingIn.includes("simkl")}
|
||||
<span
|
||||
class="inline-block w-4 h-4 mr-2 border-2 border-gray-300 border-t-transparent rounded-full animate-spin align-middle"
|
||||
></span
|
||||
>Checking Simkl
|
||||
{:else}
|
||||
Simkl Login
|
||||
{/if}
|
||||
</button>
|
||||
{/if}
|
||||
</li>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
aniListSort,
|
||||
clearApiError,
|
||||
setApiError,
|
||||
serviceLoggingIn,
|
||||
} from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
|
||||
let isAniListPrimary: boolean;
|
||||
@@ -60,6 +61,7 @@
|
||||
}
|
||||
};
|
||||
export const CheckIfAniListLoggedInAndLoadWatchList = async () => {
|
||||
serviceLoggingIn.update((s) => [...s, "anilist"]);
|
||||
try {
|
||||
const loggedIn = await CheckIfAniListLoggedIn();
|
||||
if (loggedIn) {
|
||||
@@ -76,6 +78,8 @@
|
||||
true,
|
||||
);
|
||||
aniListLoggedIn.set(false);
|
||||
} finally {
|
||||
serviceLoggingIn.update((s) => s.filter((item) => item !== "anilist"));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
<script lang="ts" context="module">
|
||||
import {CheckIfMyAnimeListLoggedIn, GetMyAnimeList, GetMyAnimeListLoggedInUser} from "../../wailsjs/go/main/App";
|
||||
import {malUser, malPrimary, malWatchList, malLoggedIn} from "./GlobalVariablesAndHelperFunctions.svelte"
|
||||
import {malUser, malPrimary, malWatchList, malLoggedIn, serviceLoggingIn} from "./GlobalVariablesAndHelperFunctions.svelte"
|
||||
import type { MyAnimeListUser } from "../mal/types/MALTypes";
|
||||
|
||||
let isMalPrimary: boolean
|
||||
malPrimary.subscribe(value => isMalPrimary = value)
|
||||
|
||||
export const CheckIfMALLoggedInAndSetUser = async () => {
|
||||
serviceLoggingIn.update((s) => [...s, "mal"])
|
||||
await CheckIfMyAnimeListLoggedIn().then(loggedIn => {
|
||||
if (loggedIn) {
|
||||
GetMyAnimeListLoggedInUser().then(user => {
|
||||
if (!user.name) {
|
||||
malUser.set({} as MyAnimeListUser)
|
||||
malLoggedIn.set(false)
|
||||
return
|
||||
}
|
||||
malUser.set(user)
|
||||
if (isMalPrimary) {
|
||||
GetMyAnimeList(1000).then(watchList => {
|
||||
@@ -20,6 +27,8 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
}).finally(() => {
|
||||
serviceLoggingIn.update((s) => s.filter(item => item !== "mal"))
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -1,11 +1,12 @@
|
||||
<script lang="ts" context="module">
|
||||
import {CheckIfSimklLoggedIn, GetSimklLoggedInUser, SimklGetUserWatchlist} from "../../wailsjs/go/main/App";
|
||||
import { simklLoggedIn, simklUser, simklPrimary, simklWatchList } from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
import { simklLoggedIn, simklUser, simklPrimary, simklWatchList, serviceLoggingIn } from "./GlobalVariablesAndHelperFunctions.svelte";
|
||||
|
||||
let isSimklPrimary: boolean
|
||||
simklPrimary.subscribe(value => isSimklPrimary = value)
|
||||
|
||||
export const CheckIfSimklLoggedInAndSetUser = async () => {
|
||||
serviceLoggingIn.update((s) => [...s, "simkl"])
|
||||
await CheckIfSimklLoggedIn().then(loggedIn => {
|
||||
if (loggedIn) {
|
||||
GetSimklLoggedInUser().then(user => {
|
||||
@@ -24,6 +25,8 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
}).finally(() => {
|
||||
serviceLoggingIn.update((s) => s.filter(item => item !== "simkl"))
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -39,6 +39,7 @@
|
||||
export let aniListLoggedIn = writable(false);
|
||||
export let simklLoggedIn = writable(false);
|
||||
export let malLoggedIn = writable(false);
|
||||
export const serviceLoggingIn = writable([] as string[]);
|
||||
export let simklWatchList = writable({} as SimklWatchList);
|
||||
export let aniListPrimary = writable(true);
|
||||
export let simklPrimary = writable(false);
|
||||
@@ -148,8 +149,27 @@
|
||||
return "";
|
||||
}
|
||||
|
||||
export function setServiceLoggingIn(service: string, isLoggingIn: boolean): void {
|
||||
serviceLoggingIn.update((services) => {
|
||||
if (isLoggingIn) {
|
||||
return services.includes(service) ? services : [...services, service];
|
||||
}
|
||||
return services.filter((s) => s !== service);
|
||||
});
|
||||
}
|
||||
|
||||
export function isServiceLoggingIn(service: string): boolean {
|
||||
let loggingIn = false;
|
||||
serviceLoggingIn.subscribe((services) => {
|
||||
loggingIn = services.includes(service);
|
||||
})();
|
||||
return loggingIn;
|
||||
}
|
||||
|
||||
export function loginToSimkl(): void {
|
||||
GetSimklLoggedInUser().then((user) => {
|
||||
setServiceLoggingIn("simkl", true);
|
||||
GetSimklLoggedInUser()
|
||||
.then((user) => {
|
||||
if (Object.keys(user).length === 0) {
|
||||
simklLoggedIn.set(false);
|
||||
} else {
|
||||
@@ -159,11 +179,14 @@
|
||||
simklLoggedIn.set(true);
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
.finally(() => setServiceLoggingIn("simkl", false));
|
||||
}
|
||||
|
||||
export function loginToAniList(): void {
|
||||
GetAniListLoggedInUser().then((result) => {
|
||||
setServiceLoggingIn("anilist", true);
|
||||
GetAniListLoggedInUser()
|
||||
.then((result) => {
|
||||
aniListUser.set(result);
|
||||
if (isAniListPrimary) {
|
||||
GetAniListUserWatchingList(page, perPage, sort).then((result) => {
|
||||
@@ -173,14 +196,23 @@
|
||||
} else {
|
||||
aniListLoggedIn.set(true);
|
||||
}
|
||||
});
|
||||
})
|
||||
.finally(() => setServiceLoggingIn("anilist", false));
|
||||
}
|
||||
|
||||
export function loginToMAL(): void {
|
||||
GetMyAnimeListLoggedInUser().then((result) => {
|
||||
setServiceLoggingIn("mal", true);
|
||||
GetMyAnimeListLoggedInUser()
|
||||
.then((result) => {
|
||||
if (!result.name) {
|
||||
malUser.set({} as MyAnimeListUser);
|
||||
malLoggedIn.set(false);
|
||||
return;
|
||||
}
|
||||
malUser.set(result);
|
||||
malLoggedIn.set(true);
|
||||
});
|
||||
})
|
||||
.finally(() => setServiceLoggingIn("mal", false));
|
||||
}
|
||||
|
||||
export function logoutOfAniList(): void {
|
||||
|
||||
Reference in New Issue
Block a user