Jon Taylor commited on
Commit
35f4179
1 Parent(s): 24d8b3c

call state implemented

Browse files
frontend/app/components/App.js ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+
3
+ import {
4
+ DailyVideo,
5
+ useAppMessage,
6
+ useLocalSessionId,
7
+ useParticipantIds,
8
+ } from "@daily-co/daily-react";
9
+ import { ActionIcon, LoadingOverlay } from "@mantine/core";
10
+ import {
11
+ IconDoorExit,
12
+ IconInfoSquareRoundedFilled,
13
+ IconLayoutSidebarRightCollapse,
14
+ IconLayoutSidebarRightExpand,
15
+ } from "@tabler/icons-react";
16
+ import { useCallback, useState } from "react";
17
+ import Card from "./Card";
18
+ import Controls from "./Controls";
19
+ import { HUDItem } from "./HUDItem";
20
+ import { TrayButton } from "./TrayButton";
21
+
22
+ export default function App({ onLeave }) {
23
+ const [panelHidden, setPanelHidden] = useState(false);
24
+ const localSessionId = useLocalSessionId();
25
+ const participantIds = useParticipantIds({ filter: "remote" });
26
+ const [params, setParams] = useState();
27
+ const sendAppMessage = useAppMessage({
28
+ onAppMessage: useCallback((ev) => setParams(ev.data), []),
29
+ });
30
+
31
+ return (
32
+ <div className="flex flex-col min-h-screen">
33
+ <div
34
+ className={`flex-1 grid ${
35
+ panelHidden ? "grid-cols-[0px_1fr]" : "grid-cols-[460px_1fr]"
36
+ }`}
37
+ >
38
+ <aside className="overflow-y-auto max-h-screen border-r border-zinc-200 bg-white">
39
+ <Controls
40
+ remoteParams={params}
41
+ onData={(data) => sendAppMessage(data, "*")}
42
+ />
43
+ </aside>
44
+ <div className="max-h-screen bg-zinc-100 flex items-center justify-center relative">
45
+ <header className="flex flex-row justify-between px-3 absolute top-3 w-full">
46
+ <ActionIcon
47
+ size="lg"
48
+ className="rounded-md bg-zinc-200 hover:bg-indigo-500 hover:text-indigo-50 text-zinc-500 transition-colors duration-300"
49
+ onClick={() => setPanelHidden(!panelHidden)}
50
+ >
51
+ {panelHidden ? (
52
+ <IconLayoutSidebarRightCollapse size={20} stroke={2} />
53
+ ) : (
54
+ <IconLayoutSidebarRightExpand size={20} stroke={2} />
55
+ )}
56
+ </ActionIcon>
57
+ <div className="flex flex-row gap-2">
58
+ <HUDItem label="Expiry" value="3:00" />
59
+ <HUDItem label="FPS" value="0" />
60
+ </div>
61
+ </header>
62
+
63
+ <main className="w-full h-full flex flex-col max-w-lg xl:max-w-2xl 2xl:max-w-full 2xl:flex-row items-center justify-center p-6 gap-3">
64
+ <Card>
65
+ <DailyVideo automirror sessionId={localSessionId} />
66
+ </Card>
67
+ <Card>
68
+ {participantIds.length ? (
69
+ <DailyVideo sessionId={participantIds[0]} />
70
+ ) : (
71
+ <LoadingOverlay
72
+ visible={true}
73
+ zIndex={1000}
74
+ className="bg-zinc-300"
75
+ />
76
+ )}
77
+ </Card>
78
+ </main>
79
+
80
+ <footer className="absolute flex flex-row gap-2 bottom-3 right-3">
81
+ <TrayButton Icon={IconInfoSquareRoundedFilled}>About</TrayButton>
82
+ <TrayButton red Icon={IconDoorExit} onClick={() => onLeave()}>
83
+ Leave
84
+ </TrayButton>
85
+ </footer>
86
+ </div>
87
+ </div>
88
+ </div>
89
+ );
90
+ }
frontend/app/components/Call.js CHANGED
@@ -1,17 +1,11 @@
1
  "use client";
2
 
3
- import {
4
- DailyVideo,
5
- useAppMessage,
6
- useLocalSessionId,
7
- useParticipantIds,
8
- } from "@daily-co/daily-react";
9
  import { useCallback, useEffect, useState } from "react";
10
- import Avatar from "../components/Avatar";
11
- import Card from "../components/Card";
12
  import CreateRoom from "../components/CreateRoom";
13
  import Join from "../components/Joining";
14
  import { apiUrl } from "../utils";
 
15
 
16
  const STATE_IDLE = "idle";
17
  const STATE_JOINING = "joining";
@@ -21,16 +15,14 @@ const BOT_STATE_STARTING = "bot_starting";
21
  const BOT_STATE_STARTED = "bot_started";
22
 
23
  export default function Call() {
 
24
  const [callState, setCallState] = useState(STATE_IDLE);
25
  const [roomUrl, setRoomUrl] = useState();
26
  const [botState, setBotState] = useState(BOT_STATE_STARTING);
27
- const [params, setParams] = useState({});
28
 
29
- const localSessionId = useLocalSessionId();
30
- const participantIds = useParticipantIds({ filter: "remote" });
31
- const sendAppMessage = useAppMessage({
32
- onAppMessage: useCallback((ev) => setParams(ev.data), []),
33
- });
34
 
35
  const start = useCallback(async () => {
36
  if (!process.env.NEXT_PUBLIC_DISABLE_LOCAL_AGENT) return;
@@ -70,58 +62,9 @@ export default function Call() {
70
  return <Join roomUrl={roomUrl} onJoin={() => setCallState(STATE_JOINED)} />;
71
  }
72
 
 
 
 
73
  // Main call loop
74
- return (
75
- <main className="container py-12">
76
- <div className="grid grid-cols-2 grid-flow-col gap-12">
77
- <div>
78
- <Card headerText="Local Webcam">
79
- <div className="overflow-hidden bg-gray-50 sm:rounded-lg">
80
- <div className="aspect-video flex items-center justify-center">
81
- <DailyVideo automirror sessionId={localSessionId} />
82
- </div>
83
- </div>
84
- </Card>
85
- <div className="relative">
86
- <div>
87
- <label
88
- htmlFor="comment"
89
- className="block text-sm font-medium leading-6 text-gray-900"
90
- >
91
- Add your comment
92
- </label>
93
- <div className="mt-2">
94
- <textarea
95
- rows={4}
96
- name="comment"
97
- id="comment"
98
- className="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
99
- defaultValue={params.prompt || ""}
100
- />
101
- </div>
102
- </div>
103
- Config - Resolution, Mbps, FPS
104
- <button
105
- onClick={() => sendAppMessage({ prompt: "Big ol' car" }, "*")}
106
- >
107
- Send test app message
108
- </button>
109
- </div>
110
- </div>
111
- <div>
112
- <Card headerText="Inference">
113
- <div className="overflow-hidden bg-gray-50 sm:rounded-lg">
114
- <div className="aspect-video flex items-center justify-center">
115
- {participantIds.length ? (
116
- <DailyVideo sessionId={participantIds[0]} />
117
- ) : (
118
- <Avatar />
119
- )}
120
- </div>
121
- </div>
122
- </Card>
123
- </div>
124
- </div>
125
- </main>
126
- );
127
  }
 
1
  "use client";
2
 
3
+ import { useDaily } from "@daily-co/daily-react";
 
 
 
 
 
4
  import { useCallback, useEffect, useState } from "react";
 
 
5
  import CreateRoom from "../components/CreateRoom";
6
  import Join from "../components/Joining";
7
  import { apiUrl } from "../utils";
8
+ import App from "./App";
9
 
10
  const STATE_IDLE = "idle";
11
  const STATE_JOINING = "joining";
 
15
  const BOT_STATE_STARTED = "bot_started";
16
 
17
  export default function Call() {
18
+ const daily = useDaily();
19
  const [callState, setCallState] = useState(STATE_IDLE);
20
  const [roomUrl, setRoomUrl] = useState();
21
  const [botState, setBotState] = useState(BOT_STATE_STARTING);
 
22
 
23
+ function leave() {
24
+ setCallState(STATE_LEFT), daily.leave();
25
+ }
 
 
26
 
27
  const start = useCallback(async () => {
28
  if (!process.env.NEXT_PUBLIC_DISABLE_LOCAL_AGENT) return;
 
62
  return <Join roomUrl={roomUrl} onJoin={() => setCallState(STATE_JOINED)} />;
63
  }
64
 
65
+ if (callState === STATE_LEFT) {
66
+ return <div>Left</div>;
67
+ }
68
  // Main call loop
69
+ return <App onLeave={() => leave()} />;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
frontend/app/components/Controls.js CHANGED
@@ -3,6 +3,7 @@
3
  import {
4
  Accordion,
5
  ActionIcon,
 
6
  SegmentedControl,
7
  Textarea,
8
  } from "@mantine/core";
@@ -21,7 +22,7 @@ import SelectInput from "./SelectInput";
21
  import SlideInput from "./SliderInput";
22
  import TextInput from "./TextInput";
23
 
24
- export const Controls = React.memo(() => {
25
  const form = useForm({
26
  initialValues: {
27
  positivePrompt: "some kind of prompt",
@@ -35,17 +36,36 @@ export const Controls = React.memo(() => {
35
 
36
  const debounce = useDebounce();
37
 
38
- const handleChange = (event) => {
39
- console.log(event);
40
  };
41
 
 
 
 
 
42
  useEffect(() => {
43
  if (!form) return;
44
  form.isDirty() && debounce(() => handleChange(form.values), 500);
45
  }, [form, debounce]);
46
 
47
  return (
48
- <div className="flex flex-col gap-4">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  <Accordion
50
  defaultValue="prompt"
51
  classNames={{
 
3
  import {
4
  Accordion,
5
  ActionIcon,
6
+ LoadingOverlay,
7
  SegmentedControl,
8
  Textarea,
9
  } from "@mantine/core";
 
22
  import SlideInput from "./SliderInput";
23
  import TextInput from "./TextInput";
24
 
25
+ export const Controls = React.memo(({ remoteParams, onData }) => {
26
  const form = useForm({
27
  initialValues: {
28
  positivePrompt: "some kind of prompt",
 
36
 
37
  const debounce = useDebounce();
38
 
39
+ const handleChange = (v) => {
40
+ onData(v);
41
  };
42
 
43
+ useEffect(() => {
44
+ if (remoteParams) return;
45
+ }, [remoteParams]);
46
+
47
  useEffect(() => {
48
  if (!form) return;
49
  form.isDirty() && debounce(() => handleChange(form.values), 500);
50
  }, [form, debounce]);
51
 
52
  return (
53
+ <div className="relative flex flex-col gap-4">
54
+ {!remoteParams && (
55
+ <LoadingOverlay
56
+ visible={true}
57
+ zIndex={1000}
58
+ overlayProps={{ blur: 2 }}
59
+ loaderProps={{
60
+ children: (
61
+ <div className="animate-pulse font-medium">
62
+ Waiting for bot to join...
63
+ </div>
64
+ ),
65
+ }}
66
+ className="h-screen"
67
+ />
68
+ )}
69
  <Accordion
70
  defaultValue="prompt"
71
  classNames={{
frontend/app/components/TrayButton.js CHANGED
@@ -8,7 +8,7 @@ const RED_COLORS =
8
  "bg-rose-700 text-rose-100 hover:text-rose-50 hover:bg-rose-600";
9
  const RED_ICON_COLORS = "text-rose-300 group-hover:text-rose-200";
10
 
11
- export const TrayButton = ({ Icon, red = false, children }) => (
12
  <Button
13
  size="md"
14
  radius="xl"
@@ -24,6 +24,7 @@ export const TrayButton = ({ Icon, red = false, children }) => (
24
  } transition-colors duration-300`}
25
  />
26
  }
 
27
  >
28
  {children}
29
  </Button>
 
8
  "bg-rose-700 text-rose-100 hover:text-rose-50 hover:bg-rose-600";
9
  const RED_ICON_COLORS = "text-rose-300 group-hover:text-rose-200";
10
 
11
+ export const TrayButton = ({ Icon, red = false, children, ...other }) => (
12
  <Button
13
  size="md"
14
  radius="xl"
 
24
  } transition-colors duration-300`}
25
  />
26
  }
27
+ {...other}
28
  >
29
  {children}
30
  </Button>
frontend/app/page.js CHANGED
@@ -4,6 +4,7 @@ import Daily from "@daily-co/daily-js";
4
  import { DailyProvider } from "@daily-co/daily-react";
5
 
6
  import { useEffect, useState } from "react";
 
7
  import Call from "./components/Call";
8
 
9
  export default function Home() {
@@ -17,11 +18,7 @@ export default function Home() {
17
 
18
  return (
19
  <DailyProvider callObject={daily}>
20
- <div className="container flex align-center min-h-screen">
21
- <div className="self-center w-full">
22
- <Call />
23
- </div>
24
- </div>
25
  </DailyProvider>
26
  );
27
  }
 
4
  import { DailyProvider } from "@daily-co/daily-react";
5
 
6
  import { useEffect, useState } from "react";
7
+
8
  import Call from "./components/Call";
9
 
10
  export default function Home() {
 
18
 
19
  return (
20
  <DailyProvider callObject={daily}>
21
+ <Call />
 
 
 
 
22
  </DailyProvider>
23
  );
24
  }
frontend/app/utils.js CHANGED
@@ -5,17 +5,3 @@ export const apiUrl =
5
  `${window.location.protocol === "https:" ? "https" : "http"}://${
6
  window.location.host
7
  }`;
8
-
9
- export function debounce(func, wait) {
10
- let timeout;
11
-
12
- return function executedFunction(...args) {
13
- const later = () => {
14
- clearTimeout(timeout);
15
- func(...args);
16
- };
17
-
18
- clearTimeout(timeout);
19
- timeout = setTimeout(later, wait);
20
- };
21
- }
 
5
  `${window.location.protocol === "https:" ? "https" : "http"}://${
6
  window.location.host
7
  }`;