feat: allow toggling eavesdropping
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
import { WindowControls } from "@/components/window-controls";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Outlet, useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import { Home, Settings } from "lucide-react";
|
||||
import { useNavigate, useParams } from "react-router-dom";
|
||||
import { Home, Settings, Volume2, VolumeOff } from "lucide-react";
|
||||
import { Toggle } from "@/components/ui/toggle";
|
||||
import { useAutoplayStore } from "@/stores/autoplay-store";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
@@ -53,6 +55,23 @@ function NetworkBreadcrumbContent({ networkId }: { networkId: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
function AutoplayToggle() {
|
||||
const muted = useAutoplayStore((s) => s.muted);
|
||||
const toggleMuted = useAutoplayStore((s) => s.toggleMuted);
|
||||
|
||||
return (
|
||||
<Toggle
|
||||
size="sm"
|
||||
pressed={!muted}
|
||||
onPressedChange={toggleMuted}
|
||||
className="no-drag"
|
||||
aria-label={muted ? "Unmute autoplay" : "Mute autoplay"}
|
||||
>
|
||||
{muted ? <VolumeOff className="size-3.5" /> : <Volume2 className="size-3.5" />}
|
||||
</Toggle>
|
||||
);
|
||||
}
|
||||
|
||||
function TopBar() {
|
||||
const navigate = useNavigate();
|
||||
const { networkId, "*": rest } = useParams();
|
||||
@@ -116,6 +135,8 @@ function TopBar() {
|
||||
|
||||
<div className="flex-1" />
|
||||
|
||||
<AutoplayToggle />
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { X, Mic, Video } from "lucide-react";
|
||||
import { X, Mic } from "lucide-react";
|
||||
import { useAutoplayStore } from "@/stores/autoplay-store";
|
||||
import { useDownloadUrl } from "@/hooks/use-download-url";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
|
||||
import { Small } from "@/components/ui/typography";
|
||||
import { getInitials } from "@/lib/utils";
|
||||
|
||||
interface AutoplayOverlayProps {
|
||||
networkId: string;
|
||||
@@ -19,7 +20,9 @@ export function AutoplayOverlay({ networkId }: AutoplayOverlayProps) {
|
||||
if (!activeParticle || !url) return null;
|
||||
|
||||
const isVideo = activeParticle.properties.mime_type?.startsWith("video/");
|
||||
const Icon = isVideo ? Video : Mic;
|
||||
const senderEmail = activeParticle.created_by_email;
|
||||
const senderInitials = getInitials(senderEmail);
|
||||
const senderName = senderEmail.split("@")[0];
|
||||
|
||||
const handleClick = () => {
|
||||
stop();
|
||||
@@ -28,42 +31,63 @@ export function AutoplayOverlay({ networkId }: AutoplayOverlayProps) {
|
||||
}
|
||||
};
|
||||
|
||||
const closeButton = (
|
||||
<button
|
||||
className="absolute top-1 right-1 z-10 rounded-full bg-black/50 p-0.5 text-white hover:bg-black/70"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
stop();
|
||||
}}
|
||||
>
|
||||
<X className="size-3.5" />
|
||||
</button>
|
||||
);
|
||||
|
||||
const senderBar = (
|
||||
<div className="flex items-center gap-2 px-3 py-2">
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback className="bg-primary/10 text-primary text-[10px] font-medium">
|
||||
{senderInitials}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<Small className="truncate text-muted-foreground">{senderName}</Small>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Card
|
||||
size="sm"
|
||||
className="absolute bottom-4 right-4 z-40 w-52 cursor-pointer shadow-lg"
|
||||
<div
|
||||
className="absolute bottom-4 right-4 z-40 w-52 cursor-pointer overflow-hidden rounded-xl bg-card text-card-foreground shadow-lg ring-1 ring-foreground/10"
|
||||
onClick={handleClick}
|
||||
>
|
||||
<div className="relative">
|
||||
{/* Close button */}
|
||||
<button
|
||||
className="absolute top-1 right-1 z-10 rounded-full bg-black/50 p-0.5 text-white hover:bg-black/70"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
stop();
|
||||
}}
|
||||
>
|
||||
<X className="size-3.5" />
|
||||
</button>
|
||||
|
||||
{isVideo ? (
|
||||
{isVideo ? (
|
||||
<div className="relative">
|
||||
{closeButton}
|
||||
<video
|
||||
src={url}
|
||||
autoPlay
|
||||
playsInline
|
||||
onEnded={stop}
|
||||
className="w-full rounded-t-xl object-cover"
|
||||
className="w-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
{senderBar}
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative">
|
||||
{closeButton}
|
||||
<div className="flex items-center gap-2 px-3 py-3">
|
||||
<Icon className="size-4 shrink-0 text-muted-foreground" />
|
||||
<Small className="truncate text-muted-foreground">
|
||||
Playing voice note...
|
||||
</Small>
|
||||
<audio src={url} autoPlay onEnded={stop} />
|
||||
<Avatar size="sm">
|
||||
<AvatarFallback className="bg-primary/10 text-primary text-[10px] font-medium">
|
||||
{senderInitials}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="min-w-0 flex-1">
|
||||
<Small className="truncate font-medium">{senderName}</Small>
|
||||
</div>
|
||||
<Mic />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
<audio src={url} autoPlay onEnded={stop} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user