File size: 3,341 Bytes
ec50620
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ac97894
ec50620
 
 
 
 
 
 
 
 
 
 
 
 
ac97894
ec50620
 
ac97894
 
 
 
 
 
 
ec50620
 
 
ac97894
 
ec50620
 
 
 
 
 
ac97894
ec50620
ac97894
 
 
ec50620
 
ac97894
 
 
ec50620
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
 * Copyright 2024 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { useRef, useState, useEffect } from "react";
import "./App.scss";
import { LiveAPIProvider } from "./contexts/LiveAPIContext";
import SidePanel from "./components/side-panel/SidePanel";
import { P5WithEditor } from "./components/p5/P5WithEditor";
import { P5Sketch } from "./components/p5/P5Sketch";
import ControlTray from "./components/control-tray/ControlTray";
import { IOSModal } from "./components/ios-modal/IOSModal";
import { isIOS } from "./lib/platform";
import cn from "classnames";

function App() {
  // this video reference is used for displaying the active stream, whether that is the webcam or screen capture
  // feel free to style as you see fit
  const videoRef = useRef<HTMLVideoElement>(null);
  // either the screen capture, the video or null, if null we hide it
  const [videoStream, setVideoStream] = useState<MediaStream | null>(null);
  const [showIOSModal, setShowIOSModal] = useState(false);
  const [isMobile, setIsMobile] = useState(window.innerWidth < 768);

  useEffect(() => {
    const handleResize = () => {
      setIsMobile(window.innerWidth < 768);
    };

    window.addEventListener('resize', handleResize);
    
    // Check iOS on mount
    if (isIOS()) {
      setShowIOSModal(true);
    }

    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return (
    <div className="App">
      <LiveAPIProvider>
        <div className="streaming-console">
          <SidePanel initialCollapsed={true} />
          <main>
            <h1 className="app-title">
              LiveCoder <span className="subtitle">Built with <a target="_blank" href="https://ai.google.dev/gemini-api/docs/multimodal-live">Google Live API</a> + <a target="_blank" href="https://p5js.org/reference/">p5.js</a></span>
            </h1>
            <div className="main-app-area">
              {/* APP goes here */}
              <div className="p5-editor-container">
                {isMobile ? <P5Sketch /> : <P5WithEditor />}
              </div>
            </div>

            <video
              style={{ background: "black" }}
              className={cn("stream float minimal", {
                hidden: !videoRef.current || !videoStream,
              })}
              ref={videoRef}
              autoPlay
              playsInline
            />
            <ControlTray
              videoRef={videoRef}
              supportsVideo={false}
              onVideoStreamChange={setVideoStream}
            >
              {/* put your own buttons here */}
            </ControlTray>
          </main>
        </div>
      </LiveAPIProvider>

      <IOSModal 
        isOpen={showIOSModal} 
        onClose={() => setShowIOSModal(false)} 
      />
    </div>
  );
}

export default App;