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.
207 lines
6.8 KiB
Svelte
207 lines
6.8 KiB
Svelte
<script lang="ts">
|
|
import { Avatar } from "flowbite-svelte";
|
|
import type { AniListUser } from "../anilist/types/AniListTypes";
|
|
import {
|
|
aniListLoggedIn,
|
|
aniListUser,
|
|
malUser,
|
|
simklUser,
|
|
malLoggedIn,
|
|
simklLoggedIn,
|
|
loginToAniList,
|
|
loginToMAL,
|
|
loginToSimkl,
|
|
logoutOfAniList,
|
|
logoutOfMAL,
|
|
logoutOfSimkl,
|
|
serviceLoggingIn,
|
|
} from "../helperModules/GlobalVariablesAndHelperFunctions.svelte";
|
|
import * as runtime from "../../wailsjs/runtime";
|
|
import type { MyAnimeListUser } from "../mal/types/MALTypes";
|
|
import type { SimklUser } from "../simkl/types/simklTypes";
|
|
import { ShowVersion } from "../../wailsjs/go/main/App";
|
|
|
|
let currentAniListUser: AniListUser;
|
|
let currentMALUser: MyAnimeListUser;
|
|
let currentSimklUser: SimklUser;
|
|
let isAniListLoggedIn: boolean;
|
|
let isSimklLoggedIn: boolean;
|
|
let isMALLoggedIn: boolean;
|
|
let loggingIn: string[] = [];
|
|
|
|
aniListUser.subscribe((value) => (currentAniListUser = value));
|
|
malUser.subscribe((value) => (currentMALUser = value));
|
|
simklUser.subscribe((value) => (currentSimklUser = value));
|
|
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");
|
|
dropdown.classList.toggle("hidden");
|
|
|
|
if (!dropdown.classList.contains("hidden")) {
|
|
document.addEventListener("click", clickOutside);
|
|
}
|
|
}
|
|
|
|
function clickOutside(event: Event): void {
|
|
let dropdown = document.querySelector("#userDropdown");
|
|
let toggleBtn = document.querySelector("#userDropdownButton");
|
|
|
|
if (
|
|
!dropdown.contains(event.target as Node) &&
|
|
!toggleBtn.contains(event.target as Node)
|
|
) {
|
|
dropdown.classList.add("hidden");
|
|
document.removeEventListener("click", clickOutside);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<div class="relative">
|
|
<button id="userDropdownButton" on:click={dropdownUser}>
|
|
{#if isAniListLoggedIn}
|
|
<Avatar
|
|
src={currentAniListUser.data.Viewer.avatar.medium}
|
|
class="cursor-pointer"
|
|
dot={isAniListLoggedIn && isMALLoggedIn && isSimklLoggedIn
|
|
? { color: "green" }
|
|
: { color: "yellow" }}
|
|
/>
|
|
{:else}
|
|
<Avatar class="cursor-pointer" dot={{ color: "red" }} />
|
|
{/if}
|
|
</button>
|
|
<div
|
|
id="userDropdown"
|
|
class="absolute hidden right-0 2xl:left-1/2 2xl:-translate-x-1/2 z-10 divide-y rounded-lg shadow w-44 bg-gray-700 divide-gray-600"
|
|
>
|
|
<div class="px-4 py-3 text-sm text-white">
|
|
{#if isAniListLoggedIn}
|
|
<div>{currentAniListUser.data.Viewer.name}</div>
|
|
{:else}
|
|
<div>You are not logged into AniList</div>
|
|
{/if}
|
|
</div>
|
|
<ul
|
|
class="py-2 text-sm text-gray-200"
|
|
aria-labelledby="dropdownUserAvatarButton"
|
|
>
|
|
{#if isAniListLoggedIn}
|
|
<li>
|
|
<button
|
|
on:click={logoutOfAniList}
|
|
class="block px-4 py-2 w-full hover:bg-gray-600 truncate bg-green-800 hover:text-white"
|
|
>
|
|
<span class="maple-font text-lg text-green-200 mr-4">A</span>Logout {currentAniListUser
|
|
.data.Viewer.name}
|
|
</button>
|
|
</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();
|
|
loginToAniList();
|
|
}}
|
|
class="block px-4 py-2 w-full hover:bg-gray-600 truncate hover:text-white"
|
|
>
|
|
<span class="maple-font text-lg mr-4">A</span>Login to AniList
|
|
</button>
|
|
{/if}
|
|
</li>
|
|
{/if}
|
|
{#if isMALLoggedIn}
|
|
<li>
|
|
<button
|
|
on:click={logoutOfMAL}
|
|
class="block px-4 py-2 w-full hover:bg-gray-600 truncate bg-blue-800 hover:text-white"
|
|
>
|
|
<span class="maple-font text-lg text-blue-200 mr-4">M</span>Logout {currentMALUser.name}
|
|
</button>
|
|
</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();
|
|
loginToMAL();
|
|
}}
|
|
class="block px-4 py-2 w-full hover:bg-gray-600 truncate hover:text-white"
|
|
>
|
|
<span class="maple-font text-lg mr-4">M</span>Login to MyAnimeList
|
|
</button>
|
|
{/if}
|
|
</li>
|
|
{/if}
|
|
{#if isSimklLoggedIn}
|
|
<li>
|
|
<button
|
|
on:click={logoutOfSimkl}
|
|
class="block px-4 py-2 w-full hover:bg-gray-600 truncate bg-indigo-800 hover:text-white"
|
|
>
|
|
<span class="maple-font text-lg text-indigo-200 mr-4">S</span>Logout {currentSimklUser
|
|
.user.name}
|
|
</button>
|
|
</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();
|
|
loginToSimkl();
|
|
}}
|
|
class="block px-4 py-2 w-full hover:bg-gray-600 truncate hover:text-white"
|
|
>
|
|
<span class="maple-font text-lg mr-4">S</span>Login to Simkl
|
|
</button>
|
|
{/if}
|
|
</li>
|
|
{/if}
|
|
</ul>
|
|
<div class="py-2">
|
|
<button
|
|
on:click={() => {
|
|
dropdownUser();
|
|
ShowVersion();
|
|
}}
|
|
class="block px-4 py-2 w-full text-sm hover:bg-gray-600 text-gray-200 over:text-white"
|
|
>
|
|
Version
|
|
</button>
|
|
<button
|
|
on:click={() => runtime.Quit()}
|
|
class="block px-4 py-2 w-full text-sm hover:bg-gray-600 text-gray-200 over:text-white"
|
|
>
|
|
Exit Application
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|