feat: backup/restore, user profile popover, image compress, video blur, wake lock
- backup/restore dialog + user profile popover components - image compression, video blur, wake lock utilities - message cache + conversation messages hook refinements - call context, active speakers, screen share dialog tweaks - audio + screen share settings persistence - refreshed app icons (smaller sizes) across all platforms
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { DeviceRestore } from './DeviceRestore';
|
||||
import { AlertIcon, ShieldIcon, XIcon } from './icons';
|
||||
|
||||
interface Props {
|
||||
open: boolean;
|
||||
userId: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
// Modal wrapper around DeviceRestore for the already-signed-in case. A
|
||||
// successful restore swaps the local device-identity for the one embedded
|
||||
// in the backup string — the app then hard-reloads so every hook
|
||||
// re-initialises against the restored keys (simpler than invalidating
|
||||
// supabase-realtime subscriptions, stronghold caches, livekit rooms, etc.
|
||||
// individually).
|
||||
export function BackupRestoreDialog({ open, userId, onClose }: Props) {
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') onClose();
|
||||
};
|
||||
window.addEventListener('keydown', onKey);
|
||||
const prev = document.body.style.overflow;
|
||||
document.body.style.overflow = 'hidden';
|
||||
return () => {
|
||||
window.removeEventListener('keydown', onKey);
|
||||
document.body.style.overflow = prev;
|
||||
};
|
||||
}, [open, onClose]);
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Backup wiederherstellen"
|
||||
className="fixed inset-0 z-50 flex items-start justify-center overflow-y-auto bg-black/60 p-6 backdrop-blur-sm"
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
className="flex w-full max-w-md flex-col gap-4"
|
||||
>
|
||||
<div className="flex items-center justify-between rounded-lg border border-white/10 bg-ink-900/70 p-3 backdrop-blur-xl">
|
||||
<div className="flex items-center gap-2">
|
||||
<ShieldIcon className="h-4 w-4 text-brand-300" />
|
||||
<h3 className="text-sm font-semibold text-white">
|
||||
Gerät aus Backup wiederherstellen
|
||||
</h3>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
aria-label="Schließen"
|
||||
className="flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg text-neutral-400 transition hover:bg-white/10 hover:text-white"
|
||||
>
|
||||
<XIcon className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex items-start gap-2 rounded-lg border border-amber-500/30 bg-amber-500/10 p-3 text-xs text-amber-100">
|
||||
<AlertIcon className="mt-0.5 h-4 w-4 shrink-0 text-amber-300" />
|
||||
<p className="min-w-0 flex-1">
|
||||
Restore ersetzt das aktuelle Gerät durch das aus dem Backup.
|
||||
Die App lädt danach neu. Nachrichten, die auf diesem Gerät seit
|
||||
dem Backup eingegangen sind, sind erst wieder lesbar, nachdem
|
||||
Peer-Geräte den Conversation-Key erneut für die wiederhergestellte
|
||||
Device-ID wrappen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<DeviceRestore
|
||||
userId={userId}
|
||||
onRestored={() => {
|
||||
// Hard reload — cleanest way to reset every hook, supabase
|
||||
// realtime channel, stronghold handle, and cached state.
|
||||
window.location.reload();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user