feat: Add page transition animations and notification settings for audio playback
This commit is contained in:
@@ -17,6 +17,7 @@ import { CacheManagement } from '@/app/components/CacheManagement';
|
||||
import { OfflineManagement } from '@/app/components/OfflineManagement';
|
||||
import { FaServer, FaUser, FaLock, FaCheck, FaTimes, FaLastfm, FaCog } from 'react-icons/fa';
|
||||
import { Settings, ExternalLink } from 'lucide-react';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
|
||||
const SettingsPage = () => {
|
||||
const { theme, setTheme, mode, setMode } = useTheme();
|
||||
@@ -59,6 +60,7 @@ const SettingsPage = () => {
|
||||
// Sidebar settings
|
||||
const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
||||
const [sidebarVisible, setSidebarVisible] = useState(true);
|
||||
const [notifyNowPlaying, setNotifyNowPlaying] = useState(false);
|
||||
|
||||
// Initialize client-side state after hydration
|
||||
useEffect(() => {
|
||||
@@ -94,6 +96,12 @@ const SettingsPage = () => {
|
||||
setSidebarVisible(true); // Default to visible
|
||||
}
|
||||
|
||||
// Notifications preference
|
||||
const savedNotify = localStorage.getItem('playback-notifications-enabled');
|
||||
if (savedNotify !== null) {
|
||||
setNotifyNowPlaying(savedNotify === 'true');
|
||||
}
|
||||
|
||||
// Load Last.fm credentials
|
||||
const storedCredentials = localStorage.getItem('lastfm-credentials');
|
||||
if (storedCredentials) {
|
||||
@@ -264,6 +272,43 @@ const SettingsPage = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleNotifyToggle = async (enabled: boolean) => {
|
||||
setNotifyNowPlaying(enabled);
|
||||
if (isClient) {
|
||||
localStorage.setItem('playback-notifications-enabled', enabled.toString());
|
||||
}
|
||||
if (enabled && typeof window !== 'undefined' && 'Notification' in window) {
|
||||
try {
|
||||
if (Notification.permission === 'default') {
|
||||
await Notification.requestPermission();
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
toast({
|
||||
title: enabled ? 'Notifications Enabled' : 'Notifications Disabled',
|
||||
description: enabled ? 'You will be notified when a new song starts.' : 'Now playing notifications are off.',
|
||||
});
|
||||
};
|
||||
|
||||
const handleTestNotification = () => {
|
||||
if (typeof window === 'undefined') return;
|
||||
if (!('Notification' in window)) {
|
||||
toast({ title: 'Not supported', description: 'Browser does not support notifications.', variant: 'destructive' });
|
||||
return;
|
||||
}
|
||||
if (Notification.permission === 'denied') {
|
||||
toast({ title: 'Permission denied', description: 'Enable notifications in your browser settings.', variant: 'destructive' });
|
||||
return;
|
||||
}
|
||||
const title = 'mice – Test Notification';
|
||||
const body = 'This is how a now playing notification will look.';
|
||||
try {
|
||||
new Notification(title, { body, icon: '/icon-192.png', badge: '/icon-192.png' });
|
||||
} catch {
|
||||
toast({ title: 'Test Notification', description: body });
|
||||
}
|
||||
};
|
||||
|
||||
const handleLastFmAuth = () => {
|
||||
if (!lastFmCredentials.apiKey) {
|
||||
toast({
|
||||
@@ -470,6 +515,29 @@ const SettingsPage = () => {
|
||||
</Card>
|
||||
)}
|
||||
|
||||
{/* Notifications */}
|
||||
<Card className="mb-6 break-inside-avoid py-5">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Settings className="w-5 h-5" />
|
||||
Notifications
|
||||
</CardTitle>
|
||||
<CardDescription>Control now playing notifications</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="font-medium">Now playing notifications</p>
|
||||
<p className="text-sm text-muted-foreground">Show a notification when a new song starts</p>
|
||||
</div>
|
||||
<Switch checked={notifyNowPlaying} onCheckedChange={handleNotifyToggle} />
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm" onClick={handleTestNotification}>Test notification</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="mb-6 break-inside-avoid py-5">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user