From 7723d0c86cee4e776319c327fe81fa10d0bf68e1 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 20 Jul 2021 15:10:48 +0100 Subject: [PATCH] added recording and streaming --- dailyjs/basic-call/components/Room/Header.js | 50 ++------------ dailyjs/basic-call/components/Room/Room.js | 2 +- .../components/Room/RoomContainer.js | 3 +- dailyjs/basic-call/pages/api/createRoom.js | 1 + .../FlyingEmojis/FlyingEmojisOverlay.js | 4 +- dailyjs/live-fitness/components/App/App.js | 24 ++++--- .../live-fitness/components/Room/Header.js | 44 +++++++++++++ dailyjs/live-fitness/components/Room/Room.js | 4 +- dailyjs/live-fitness/components/Tray/Tray.js | 30 +++++++-- dailyjs/live-fitness/next.config.js | 2 + dailyjs/live-fitness/package.json | 2 + dailyjs/live-fitness/pages/[room].js | 8 ++- dailyjs/live-fitness/pages/_app.js | 3 + dailyjs/live-streaming/index.js | 1 + dailyjs/recording/index.js | 1 + dailyjs/shared/components/Button/Button.js | 18 ++++- .../components/ExpiryTimer/ExpiryTimer.js | 7 ++ .../components/HeaderCapsule/HeaderCapsule.js | 65 +++++++++++++++++++ .../shared/components/HeaderCapsule/index.js | 1 + .../shared/contexts/ParticipantsProvider.js | 5 +- dailyjs/shared/contexts/UIStateProvider.js | 10 ++- dailyjs/shared/hooks/useCallUI.js | 8 ++- 22 files changed, 223 insertions(+), 70 deletions(-) create mode 100644 dailyjs/live-fitness/components/Room/Header.js create mode 100644 dailyjs/live-streaming/index.js create mode 100644 dailyjs/recording/index.js create mode 100644 dailyjs/shared/components/HeaderCapsule/HeaderCapsule.js create mode 100644 dailyjs/shared/components/HeaderCapsule/index.js diff --git a/dailyjs/basic-call/components/Room/Header.js b/dailyjs/basic-call/components/Room/Header.js index e1f05ac..7491b1e 100644 --- a/dailyjs/basic-call/components/Room/Header.js +++ b/dailyjs/basic-call/components/Room/Header.js @@ -1,4 +1,5 @@ import React, { useMemo } from 'react'; +import HeaderCapsule from '@dailyjs/shared/components/HeaderCapsule'; import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider'; import { useUIState } from '@dailyjs/shared/contexts/UIStateProvider'; @@ -10,17 +11,18 @@ export const Header = () => { () => (
Daily -
Basic call demo
-
+ + Basic call demo + {`${participantCount} ${ participantCount === 1 ? 'participant' : 'participants' }`} -
+ {customCapsule && ( -
+ {customCapsule.variant === 'recording' && } {customCapsule.label} -
+ )}
), diff --git a/dailyjs/basic-call/components/Room/Room.js b/dailyjs/basic-call/components/Room/Room.js index 45210db..a21247f 100644 --- a/dailyjs/basic-call/components/Room/Room.js +++ b/dailyjs/basic-call/components/Room/Room.js @@ -2,7 +2,7 @@ import React from 'react'; import { VideoGrid } from '../VideoGrid'; import { Header } from './Header'; -import RoomContainer from './RoomContainer'; +import { RoomContainer } from './RoomContainer'; export const Room = () => ( diff --git a/dailyjs/basic-call/components/Room/RoomContainer.js b/dailyjs/basic-call/components/Room/RoomContainer.js index e3e674d..998ecaf 100644 --- a/dailyjs/basic-call/components/Room/RoomContainer.js +++ b/dailyjs/basic-call/components/Room/RoomContainer.js @@ -7,8 +7,7 @@ import PropTypes from 'prop-types'; import WaitingRoom from '../WaitingRoom'; export const RoomContainer = ({ children }) => { - const { localParticipant } = useParticipants(); - const isOwner = !!localParticipant?.isOwner; + const { isOwner } = useParticipants(); useJoinSound(); diff --git a/dailyjs/basic-call/pages/api/createRoom.js b/dailyjs/basic-call/pages/api/createRoom.js index 04a61c8..1a67932 100644 --- a/dailyjs/basic-call/pages/api/createRoom.js +++ b/dailyjs/basic-call/pages/api/createRoom.js @@ -16,6 +16,7 @@ export default async function handler(req, res) { exp: Math.round(Date.now() / 1000) + (expiryMinutes || 5) * 60, // expire in x minutes eject_at_room_exp: true, enable_knocking: privacy !== 'public', + enable_recording: 'local', }, }), }; diff --git a/dailyjs/flying-emojis/components/FlyingEmojis/FlyingEmojisOverlay.js b/dailyjs/flying-emojis/components/FlyingEmojis/FlyingEmojisOverlay.js index 51426a9..68f0ff9 100644 --- a/dailyjs/flying-emojis/components/FlyingEmojis/FlyingEmojisOverlay.js +++ b/dailyjs/flying-emojis/components/FlyingEmojis/FlyingEmojisOverlay.js @@ -94,8 +94,8 @@ export const FlyingEmojisOverlay = () => { position: fixed; top: 0px; bottom: 0px; - left: 24px; - right: 24px; + left: 0px; + right: 0px; overflow: hidden; pointer-events: none; user-select: none; diff --git a/dailyjs/live-fitness/components/App/App.js b/dailyjs/live-fitness/components/App/App.js index 21ba2ae..5bce06e 100644 --- a/dailyjs/live-fitness/components/App/App.js +++ b/dailyjs/live-fitness/components/App/App.js @@ -2,6 +2,8 @@ import React from 'react'; import App from '@dailyjs/basic-call/components/App'; import FlyingEmojiOverlay from '@dailyjs/flying-emojis/components/FlyingEmojis'; +import { LiveStreamingProvider } from '@dailyjs/live-streaming/contexts/LiveStreamingProvider'; +import { RecordingProvider } from '@dailyjs/recording/contexts/RecordingProvider'; import { ChatProvider } from '@dailyjs/text-chat/contexts/ChatProvider'; import Room from '../Room'; @@ -10,16 +12,18 @@ import Room from '../Room'; * as the layout logic changes considerably for the basic demo */ export const LiveFitnessApp = () => ( - <> - - - , - }} - /> - - + + + + + , + }} + /> + + + ); export default LiveFitnessApp; diff --git a/dailyjs/live-fitness/components/Room/Header.js b/dailyjs/live-fitness/components/Room/Header.js new file mode 100644 index 0000000..1d14da8 --- /dev/null +++ b/dailyjs/live-fitness/components/Room/Header.js @@ -0,0 +1,44 @@ +import React, { useMemo } from 'react'; +import Button from '@dailyjs/shared/components/Button'; +import HeaderCapsule from '@dailyjs/shared/components/HeaderCapsule'; +import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider'; + +export const Header = () => { + const { participantCount } = useParticipants(); + + return useMemo( + () => ( +
+ Daily + + + {`${participantCount} ${ + participantCount === 1 ? 'participant' : 'participants' + }`} + + + + +
+ ), + [participantCount] + ); +}; + +export default Header; diff --git a/dailyjs/live-fitness/components/Room/Room.js b/dailyjs/live-fitness/components/Room/Room.js index 8d2a1e8..43960af 100644 --- a/dailyjs/live-fitness/components/Room/Room.js +++ b/dailyjs/live-fitness/components/Room/Room.js @@ -1,9 +1,11 @@ import React from 'react'; -import RoomContainer from '@dailyjs/basic-call/components/Room/RoomContainer'; +import { RoomContainer } from '@dailyjs/basic-call/components/Room/RoomContainer'; +import { Header } from './Header'; export const Room = () => ( +
Hello
); diff --git a/dailyjs/live-fitness/components/Tray/Tray.js b/dailyjs/live-fitness/components/Tray/Tray.js index abf18ba..565eb14 100644 --- a/dailyjs/live-fitness/components/Tray/Tray.js +++ b/dailyjs/live-fitness/components/Tray/Tray.js @@ -1,12 +1,30 @@ import React from 'react'; import FlyingEmojiTrayButton from '@dailyjs/flying-emojis/components/Tray'; +import LiveStreamingButton from '@dailyjs/live-streaming/components/Tray'; +import RecordingButton from '@dailyjs/recording/components/Tray'; +import { useParticipants } from '@dailyjs/shared/contexts/ParticipantsProvider'; import ChatTrayButton from '@dailyjs/text-chat/components/Tray'; -export const Tray = () => ( - <> - - - -); +export const Tray = () => { + const { isOwner } = useParticipants(); + + if (isOwner) { + return ( + <> + + + + + + ); + } + + return ( + <> + + + + ); +}; export default Tray; diff --git a/dailyjs/live-fitness/next.config.js b/dailyjs/live-fitness/next.config.js index 889e818..ad6010a 100644 --- a/dailyjs/live-fitness/next.config.js +++ b/dailyjs/live-fitness/next.config.js @@ -4,6 +4,8 @@ const withTM = require('next-transpile-modules')([ '@dailyjs/basic-call', '@dailyjs/flying-emojis', '@dailyjs/text-chat', + '@dailyjs/live-streaming', + '@dailyjs/recording', ]); const packageJson = require('./package.json'); diff --git a/dailyjs/live-fitness/package.json b/dailyjs/live-fitness/package.json index 8432623..df8999e 100644 --- a/dailyjs/live-fitness/package.json +++ b/dailyjs/live-fitness/package.json @@ -14,6 +14,8 @@ "@dailyjs/basic-call": "*", "@dailyjs/flying-emojis": "*", "@dailyjs/text-chat": "*", + "@dailyjs/live-streaming": "*", + "@dailyjs/recording": "*", "next": "^11.0.0", "pluralize": "^8.0.0", "react": "^17.0.2", diff --git a/dailyjs/live-fitness/pages/[room].js b/dailyjs/live-fitness/pages/[room].js index 726c882..22cea5b 100644 --- a/dailyjs/live-fitness/pages/[room].js +++ b/dailyjs/live-fitness/pages/[room].js @@ -20,6 +20,7 @@ export default function Room({ domain, customTrayComponent, asides, + modals, }) { const [token, setToken] = useState(); const [tokenError, setTokenError] = useState(); @@ -78,7 +79,11 @@ export default function Room({ * Main call UI */ return ( - + @@ -100,6 +105,7 @@ Room.propTypes = { instructor: PropTypes.bool, customTrayComponent: PropTypes.node, asides: PropTypes.arrayOf(PropTypes.func), + modals: PropTypes.arrayOf(PropTypes.func), }; export async function getServerSideProps(context) { diff --git a/dailyjs/live-fitness/pages/_app.js b/dailyjs/live-fitness/pages/_app.js index 60bb86c..b9ba6b0 100644 --- a/dailyjs/live-fitness/pages/_app.js +++ b/dailyjs/live-fitness/pages/_app.js @@ -1,9 +1,12 @@ import React from 'react'; import App from '@dailyjs/basic-call/pages/_app'; +import LiveStreamingModal from '@dailyjs/live-streaming/components/LiveStreamingModal'; +import RecordingModal from '@dailyjs/recording/components/RecordingModal'; import ChatAside from '@dailyjs/text-chat/components/ChatAside'; import Tray from '../components/Tray'; App.customTrayComponent = ; App.asides = [ChatAside]; +App.modals = [LiveStreamingModal, RecordingModal]; export default App; diff --git a/dailyjs/live-streaming/index.js b/dailyjs/live-streaming/index.js new file mode 100644 index 0000000..9044efc --- /dev/null +++ b/dailyjs/live-streaming/index.js @@ -0,0 +1 @@ +// Note: I am here because next-transpile-modules requires a mainfile diff --git a/dailyjs/recording/index.js b/dailyjs/recording/index.js new file mode 100644 index 0000000..9044efc --- /dev/null +++ b/dailyjs/recording/index.js @@ -0,0 +1 @@ +// Note: I am here because next-transpile-modules requires a mainfile diff --git a/dailyjs/shared/components/Button/Button.js b/dailyjs/shared/components/Button/Button.js index ff36a25..05c06af 100644 --- a/dailyjs/shared/components/Button/Button.js +++ b/dailyjs/shared/components/Button/Button.js @@ -195,7 +195,7 @@ export const Button = forwardRef( } .button.tiny { - height: 32px; + height: 28px; font-size: 11px; border-radius: var(--radius-xs); text-transform: uppercase; @@ -320,6 +320,22 @@ export const Button = forwardRef( box-shadow: 0 0 0px 3px rgba(0, 0, 0, 0.05); } + .button.outline-dark { + background: transparent; + border: 1px solid var(--blue-light); + color: var(--text-light); + } + + .button.outline-dark:hover, + .button.outline-dark:focus, + .button.outline-dark:active { + border: 1px solid var(--primary-default); + box-shadow: none; + } + .button.outline-dark:focus { + box-shadow: 0 0 0px 3px ${hexa(theme.primary.default, 0.35)}; + } + .button.muted { color: var(--red-default); } diff --git a/dailyjs/shared/components/ExpiryTimer/ExpiryTimer.js b/dailyjs/shared/components/ExpiryTimer/ExpiryTimer.js index f5f2aa6..477bad9 100644 --- a/dailyjs/shared/components/ExpiryTimer/ExpiryTimer.js +++ b/dailyjs/shared/components/ExpiryTimer/ExpiryTimer.js @@ -11,12 +11,19 @@ export const ExpiryTimer = ({ expiry }) => { } const i = setInterval(() => { const timeLeft = Math.round((expiry - Date.now()) / 1000); + if (timeLeft < 0) { + return setSecs(null); + } setSecs(`${Math.floor(timeLeft / 60)}:${`0${timeLeft % 60}`.slice(-2)}`); }, 1000); return () => clearInterval(i); }, [expiry]); + if (!secs) { + return null; + } + return (
{secs} diff --git a/dailyjs/shared/components/HeaderCapsule/HeaderCapsule.js b/dailyjs/shared/components/HeaderCapsule/HeaderCapsule.js new file mode 100644 index 0000000..4be0c78 --- /dev/null +++ b/dailyjs/shared/components/HeaderCapsule/HeaderCapsule.js @@ -0,0 +1,65 @@ +import React from 'react'; + +import classNames from 'classnames'; +import PropTypes from 'prop-types'; + +export const HeaderCapsule = ({ children, variant }) => { + const cx = classNames('capsule', variant); + + return ( +
+ {children} + +
+ ); +}; + +HeaderCapsule.propTypes = { + children: PropTypes.node, + variant: PropTypes.string, +}; + +export default HeaderCapsule; diff --git a/dailyjs/shared/components/HeaderCapsule/index.js b/dailyjs/shared/components/HeaderCapsule/index.js new file mode 100644 index 0000000..4f6c752 --- /dev/null +++ b/dailyjs/shared/components/HeaderCapsule/index.js @@ -0,0 +1 @@ +export { HeaderCapsule as default } from './HeaderCapsule'; diff --git a/dailyjs/shared/contexts/ParticipantsProvider.js b/dailyjs/shared/contexts/ParticipantsProvider.js index 6fc344c..3e31b45 100644 --- a/dailyjs/shared/contexts/ParticipantsProvider.js +++ b/dailyjs/shared/contexts/ParticipantsProvider.js @@ -75,7 +75,10 @@ export const ParticipantsProvider = ({ children }) => { [allParticipants] ); - const isOwner = useMemo(() => localParticipant?.isOwner, [localParticipant]); + const isOwner = useMemo( + () => !!localParticipant?.isOwner, + [localParticipant] + ); /** * The participant who should be rendered prominently right now diff --git a/dailyjs/shared/contexts/UIStateProvider.js b/dailyjs/shared/contexts/UIStateProvider.js index fe36416..bb6d2a8 100644 --- a/dailyjs/shared/contexts/UIStateProvider.js +++ b/dailyjs/shared/contexts/UIStateProvider.js @@ -22,6 +22,10 @@ export const UIStateProvider = ({ }, []); const closeModal = useCallback((modalName) => { + if (!modalName) { + setActiveModals({}); + } + setActiveModals((prevState) => ({ ...prevState, [modalName]: false, @@ -34,6 +38,10 @@ export const UIStateProvider = ({ setShowAside((p) => (p === newAside ? null : newAside)); }, []); + const closeAside = useCallback(() => { + setShowAside(null); + }, []); + return ( { const router = useRouter(); + const { closeAside, closeModal } = useUIState(); useEffect(() => { console.log(`%c🔀 App state changed: ${state}`, `color: gray;`); @@ -36,6 +38,10 @@ export const useCallUI = ({ return ; } + // Make sure we hide any active asides or modals when the state changes + closeAside(); + closeModal(); + // Update the UI based on the state of our call switch (state) { case CALL_STATE_NOT_FOUND: @@ -80,7 +86,7 @@ export const useCallUI = ({ return callEnded ? ( callEnded() ) : ( - window.location.reload()}> + You have left the call. We hope you had fun! );