mirror of
https://lavaforge.org/spotizerr/spotizerr.git
synced 2025-12-24 02:39:14 -05:00
Fix config fallback checking logic and PWA scrolling
This commit is contained in:
@@ -23,6 +23,9 @@ from routes.utils.watch.manager import (
|
||||
from routes.auth.middleware import require_admin_from_state, User
|
||||
from routes.auth import AUTH_ENABLED, DISABLE_REGISTRATION
|
||||
|
||||
# Import credential utilities (DB-backed)
|
||||
from routes.utils.credentials import list_credentials, _get_global_spotify_api_creds
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
router = APIRouter()
|
||||
@@ -45,13 +48,18 @@ NOTIFY_PARAMETERS = [
|
||||
def has_credentials(service: str) -> bool:
|
||||
"""Check if credentials exist for the specified service (spotify or deezer)."""
|
||||
try:
|
||||
credentials_path = Path(f"./data/credentials/{service}")
|
||||
if not credentials_path.exists():
|
||||
if service not in ("spotify", "deezer"):
|
||||
return False
|
||||
|
||||
# Check if there are any credential files in the directory
|
||||
credential_files = list(credentials_path.glob("*.json"))
|
||||
return len(credential_files) > 0
|
||||
|
||||
account_names = list_credentials(service)
|
||||
has_any_accounts = bool(account_names)
|
||||
|
||||
if service == "spotify":
|
||||
client_id, client_secret = _get_global_spotify_api_creds()
|
||||
has_global_api_creds = bool(client_id) and bool(client_secret)
|
||||
return has_any_accounts and has_global_api_creds
|
||||
|
||||
return has_any_accounts
|
||||
except Exception as e:
|
||||
logger.warning(f"Error checking credentials for {service}: {e}")
|
||||
return False
|
||||
|
||||
@@ -185,23 +185,21 @@
|
||||
/* PWA specific body styling */
|
||||
body {
|
||||
background: var(--color-surface);
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
.dark body {
|
||||
background: var(--color-surface-dark);
|
||||
}
|
||||
|
||||
/* PWA viewport fixes */
|
||||
html {
|
||||
height: 100vh;
|
||||
height: 100dvh; /* Dynamic viewport height for mobile */
|
||||
html, body {
|
||||
height: 100%;
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -232,6 +230,8 @@
|
||||
.pwa-main {
|
||||
padding-left: var(--safe-area-inset-left);
|
||||
padding-right: var(--safe-area-inset-right);
|
||||
overscroll-behavior-y: contain;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ class AuthApiClient {
|
||||
// Request interceptor to add auth token
|
||||
this.apiClient.interceptors.request.use(
|
||||
(config) => {
|
||||
// Only add auth header if auth is enabled and we have a token
|
||||
if (this.authEnabled && this.token) {
|
||||
// Add auth header whenever we have a token so startup validation works before authEnabled is known
|
||||
if (this.token) {
|
||||
config.headers.Authorization = `Bearer ${this.token}`;
|
||||
}
|
||||
return config;
|
||||
|
||||
@@ -40,40 +40,7 @@ export const Home = () => {
|
||||
const context = useContext(QueueContext);
|
||||
const loaderRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// Prevent scrolling on mobile only when there are no results (empty state)
|
||||
useEffect(() => {
|
||||
const isMobile = window.innerWidth < 768; // md breakpoint
|
||||
if (!isMobile) return;
|
||||
|
||||
// Only prevent scrolling when there are no results to show
|
||||
const shouldPreventScroll = !isLoading && displayedResults.length === 0 && !query.trim();
|
||||
|
||||
if (!shouldPreventScroll) return;
|
||||
|
||||
// Store original styles
|
||||
const originalOverflow = document.body.style.overflow;
|
||||
const originalHeight = document.body.style.height;
|
||||
|
||||
// Find the mobile main content container
|
||||
const mobileMain = document.querySelector('.pwa-main') as HTMLElement;
|
||||
const originalMainOverflow = mobileMain?.style.overflow;
|
||||
|
||||
// Prevent body and main container scrolling on mobile when empty
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.body.style.height = '100vh';
|
||||
if (mobileMain) {
|
||||
mobileMain.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
// Cleanup function
|
||||
return () => {
|
||||
document.body.style.overflow = originalOverflow;
|
||||
document.body.style.height = originalHeight;
|
||||
if (mobileMain) {
|
||||
mobileMain.style.overflow = originalMainOverflow;
|
||||
}
|
||||
};
|
||||
}, [isLoading, displayedResults.length, query]);
|
||||
// Removed scroll locking on mobile empty state to avoid blocking scroll globally
|
||||
|
||||
useEffect(() => {
|
||||
navigate({ search: (prev) => ({ ...prev, q: debouncedQuery, type: searchType }) });
|
||||
|
||||
@@ -82,9 +82,9 @@ function AppLayout() {
|
||||
const { toggleVisibility, totalTasks } = useContext(QueueContext) || {};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-surface-secondary via-surface-muted to-surface-accent dark:from-surface-dark dark:via-surface-muted-dark dark:to-surface-secondary-dark text-content-primary dark:text-content-primary-dark flex flex-col">
|
||||
<div className="min-h-screen bg-gradient-to-br from-surface-secondary via-surface-muted to-surface-accent dark:from-surface-dark dark:via-surface-muted-dark dark:to-surface-secondary-dark text-content-primary dark:text-content-primary-dark flex flex-col overflow-hidden">
|
||||
{/* Desktop Header */}
|
||||
<header className="hidden md:block sticky top-0 z-40 w-full border-b border-border dark:border-border-dark bg-surface-overlay dark:bg-surface-overlay-dark backdrop-blur-sm">
|
||||
<header className="hidden md:block sticky top-0 z-50 w-full border-b border-border dark:border-border-dark bg-surface dark:bg-surface-dark">
|
||||
<div className="container mx-auto h-14 flex items-center justify-between">
|
||||
<Link to="/" className="flex items-center">
|
||||
<img src="/spotizerr.svg" alt="Spotizerr" className="h-8 w-auto logo" />
|
||||
@@ -119,9 +119,9 @@ function AppLayout() {
|
||||
</main>
|
||||
|
||||
{/* Mobile Layout Container */}
|
||||
<div className="md:hidden flex flex-col h-screen">
|
||||
<div className="md:hidden flex flex-col min-h-screen overflow-hidden">
|
||||
{/* Mobile Header - Fixed */}
|
||||
<header className="fixed top-0 left-0 right-0 z-40 border-b border-border dark:border-border-dark bg-surface-overlay dark:bg-surface-overlay-dark backdrop-blur-sm pwa-header">
|
||||
<header className="fixed top-0 left-0 right-0 z-50 border-b border-border dark:border-border-dark bg-surface dark:bg-surface-dark pwa-header">
|
||||
<div className="container mx-auto h-14 flex items-center justify-between px-4">
|
||||
<Link to="/" className="flex items-center">
|
||||
<img src="/spotizerr.svg" alt="Spotizerr" className="h-8 w-auto logo" />
|
||||
@@ -131,12 +131,12 @@ function AppLayout() {
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Mobile Main Content - Scrollable container */}
|
||||
<main className="flex-1 overflow-y-auto mt-14 mb-16 pwa-main">
|
||||
{/* Mobile Main Content - Constrained scroll area between headers */}
|
||||
<div className="fixed top-14 bottom-16 left-0 right-0 overflow-y-auto pwa-main bg-gradient-to-br from-surface-secondary via-surface-muted to-surface-accent dark:from-surface-dark dark:via-surface-muted-dark dark:to-surface-secondary-dark">
|
||||
<div className="container mx-auto p-4">
|
||||
<Outlet />
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{/* Mobile Bottom Navigation - Fixed */}
|
||||
<nav className="fixed bottom-0 left-0 right-0 z-40 border-t border-border dark:border-border-dark bg-surface-overlay dark:bg-surface-overlay-dark backdrop-blur-md pwa-footer">
|
||||
|
||||
Reference in New Issue
Block a user