From b8823e0a7cf98adef65121b23ca99fc30f5a9b47 Mon Sep 17 00:00:00 2001 From: WardPearce Date: Sat, 14 Feb 2026 21:42:22 +1300 Subject: [PATCH] Update pages on authStore set --- .../lib/components/settings/Interface.svelte | 38 +++++++++--- materialious/src/lib/i18n/locales/en.json | 2 + materialious/src/lib/misc.ts | 35 +++++++++++ materialious/src/routes/(app)/+layout.svelte | 62 ++++++------------- 4 files changed, 84 insertions(+), 53 deletions(-) diff --git a/materialious/src/lib/components/settings/Interface.svelte b/materialious/src/lib/components/settings/Interface.svelte index 3ec993e7..d17cc812 100644 --- a/materialious/src/lib/components/settings/Interface.svelte +++ b/materialious/src/lib/components/settings/Interface.svelte @@ -11,7 +11,13 @@ import type { RgbaColor, HsvaColor, Colord } from 'colord'; import { _ } from '$lib/i18n'; import { get } from 'svelte/store'; - import { isMobile, clearCaches, isUnrestrictedPlatform, setInvidiousInstance } from '../../misc'; + import { + isMobile, + clearCaches, + isUnrestrictedPlatform, + setInvidiousInstance, + goToInvidiousLogin + } from '../../misc'; import { getPages, type Pages } from '../../navPages'; import ColorPicker from 'svelte-awesome-color-picker'; import { @@ -91,11 +97,6 @@ } async function setBackend(event: Event) { - if (isOwnBackend()?.internalAuth) { - rawMasterKeyStore.set(undefined); - fetch('/api/user/logout', { method: 'DELETE' }); - } - const select = event.target as HTMLSelectElement; backendInUseStore.set(select.value as 'ivg' | 'yt'); reloadState(); @@ -165,14 +166,31 @@ + {#if isOwnBackend()?.internalAuth} + {#if !$authStore} + + {:else} + + {/if} +
+ {/if} {:else}
{/if} - {#if isMobile()} - {#if invalidInstance} -
- {/if} + {#if isMobile() && invalidInstance} +
{/if} {#if Capacitor.isNativePlatform() && (invalidInstance || $interfaceAllowInsecureRequests)} diff --git a/materialious/src/lib/i18n/locales/en.json b/materialious/src/lib/i18n/locales/en.json index 51e447a3..b8080665 100644 --- a/materialious/src/lib/i18n/locales/en.json +++ b/materialious/src/lib/i18n/locales/en.json @@ -11,6 +11,8 @@ "password": "Password", "invalidPassword": "Invalid password", "usernameTaken": "Username taken", + "linkInvidious": "Link Invidious account", + "unlinkInvidious": "Unlink Invidious account", "createAccount": "Create account", "needRegister": "I need to register", "registrationDisabled": "Registration currently disabled, contact instance owner.", diff --git a/materialious/src/lib/misc.ts b/materialious/src/lib/misc.ts index 6a999fc9..ddd2a671 100644 --- a/materialious/src/lib/misc.ts +++ b/materialious/src/lib/misc.ts @@ -13,6 +13,7 @@ import { interfaceAndroidUseNativeShare, isAndroidTvStore, playlistCacheStore, + rawMasterKeyStore, searchCacheStore } from './store'; import type { @@ -29,6 +30,8 @@ import { Capacitor } from '@capacitor/core'; import { Share } from '@capacitor/share'; import { Clipboard } from '@capacitor/clipboard'; import { isOwnBackend } from './shared'; +import { Browser } from '@capacitor/browser'; +import { clearFeedYTjs } from './api/youtubejs/subscriptions'; export function isMobile(): boolean { const userAgent = navigator.userAgent; @@ -289,3 +292,35 @@ export async function setInvidiousInstance( return true; } + +export async function goToInvidiousLogin() { + if (!get(instanceStore)) return; + const path = new URL(`${get(instanceStore)}/authorize_token`); + const searchParams = new URLSearchParams({ + scopes: ':feed,:subscriptions*,:playlists*,:history*,:notifications*' + }); + if (Capacitor.getPlatform() === 'android') { + searchParams.set('callback_url', 'materialious-auth://'); + path.search = searchParams.toString(); + await Browser.open({ url: path.toString() }); + } else { + searchParams.set('callback_url', `${location.origin}${resolve('/auth', {})}`); + path.search = searchParams.toString(); + document.location.href = path.toString(); + } +} + +export async function logout() { + if (isYTBackend()) { + await clearFeedYTjs(); + } + + if (isOwnBackend()?.internalAuth) { + fetch('/api/user/logout', { method: 'DELETE' }); + rawMasterKeyStore.set(undefined); + } else { + authStore.set(null); + } + + goto(resolve('/', {})); +} diff --git a/materialious/src/routes/(app)/+layout.svelte b/materialious/src/routes/(app)/+layout.svelte index 2aefed80..5a1dadf7 100644 --- a/materialious/src/routes/(app)/+layout.svelte +++ b/materialious/src/routes/(app)/+layout.svelte @@ -40,11 +40,10 @@ import { _ } from '$lib/i18n'; import { get } from 'svelte/store'; import { pwaInfo } from 'virtual:pwa-info'; - import { isYTBackend, truncate } from '$lib/misc'; + import { goToInvidiousLogin, isYTBackend, logout, truncate } from '$lib/misc'; import Author from '$lib/components/Author.svelte'; import Toast from '$lib/components/Toast.svelte'; import { isOwnBackend } from '$lib/shared'; - import { clearFeedYTjs } from '$lib/api/youtubejs/subscriptions'; let { children } = $props(); @@ -52,15 +51,20 @@ let mobileSearchShow = $state(false); - let isLoggedIn = $state(false); - authStore.subscribe((value) => { - isLoggedIn = value !== null; - }); - let notifications: Notification[] = $state([]); let playerIsPip: boolean = $state(false); + let pages = $state(getPages()); + + authStore.subscribe(() => { + pages = getPages(); + }); + + rawMasterKeyStore.subscribe(() => { + pages = getPages(); + }); + page.subscribe((pageData) => { playerIsPip = !pageData.url.pathname.includes('/watch'); requestAnimationFrame(() => resetScroll()); @@ -117,27 +121,13 @@ }); async function login() { - if (isOwnBackend()?.internalAuth && isYTBackend()) { + if (isOwnBackend()?.internalAuth) { goto(resolve('/internal/login', {})); return; } if (!$isAndroidTvStore) { - // eslint-disable-next-line svelte/prefer-svelte-reactivity - const path = new URL(`${get(instanceStore)}/authorize_token`); - // eslint-disable-next-line svelte/prefer-svelte-reactivity - const searchParams = new URLSearchParams({ - scopes: ':feed,:subscriptions*,:playlists*,:history*,:notifications*' - }); - if (Capacitor.getPlatform() === 'android') { - searchParams.set('callback_url', 'materialious-auth://'); - path.search = searchParams.toString(); - await Browser.open({ url: path.toString() }); - } else { - searchParams.set('callback_url', `${location.origin}${resolve('/auth', {})}`); - path.search = searchParams.toString(); - document.location.href = path.toString(); - } + await goToInvidiousLogin(); } else { await ui('#tv-login'); document.getElementById('username')?.focus(); @@ -188,20 +178,6 @@ loginError = true; } - async function logout() { - if (isYTBackend()) { - await clearFeedYTjs(); - } - - if (isOwnBackend()?.internalAuth) { - fetch('/api/user/logout', { method: 'DELETE' }); - } - - rawMasterKeyStore.set(undefined); - authStore.set(null); - goto(resolve('/', {})); - } - async function loadNotifications() { const feed = await getFeed(100, 1); notifications = feed.notifications; @@ -255,7 +231,7 @@ setTheme(); setAmoledTheme(); - if (isLoggedIn && !isYTBackend()) { + if ($authStore && !isYTBackend()) { loadNotifications().catch(() => logout()); } @@ -295,7 +271,7 @@
{$_('searchPlaceholder')}
{/if} - {#each getPages() as navPage (navPage)} + {#each pages as navPage (navPage)} {navPage.icon}
{navPage.name}
@@ -308,7 +284,7 @@
{$_('layout.settings')}
{#if showLogin} - {#if !isLoggedIn} + {#if (!$authStore && !isOwnBackend()?.internalAuth) || !$rawMasterKeyStore} login
{$_('layout.login')}
@@ -370,7 +346,7 @@ group
{$_('layout.syncParty')}
- {#if isLoggedIn && !isYTBackend()} + {#if (!$authStore && !isOwnBackend()?.internalAuth) || !$rawMasterKeyStore} {#if showLogin} - {#if !isLoggedIn && !$rawMasterKeyStore} + {#if (!$authStore && !isOwnBackend()?.internalAuth) || (!$rawMasterKeyStore && isOwnBackend()?.internalAuth)}