-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #57 from SolidLabResearch/master
Deploy
- Loading branch information
Showing
32 changed files
with
9,694 additions
and
2,155 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,8 +4,16 @@ | |
|
||
# Solid Watchparty | ||
|
||
[solidlabresearch.github.io/solid-watch-party/](https://solidlabresearch.github.io/solid-watch-party/) | ||
|
||
Welcome to Solid Watchparty, a platform designed for shared media viewing experiences with a focus on decentralized data management using SOLID Pods. This project leverages the latest web technologies to offer a responsive and user-centric interface. | ||
|
||
|
||
|
||
https://github.com/SolidLabResearch/solid-watch-party/assets/37975937/e78ec297-3538-44c7-ad32-14ea310a35e7 | ||
|
||
|
||
|
||
## :zap: Quick Start | ||
|
||
|
||
|
@@ -14,6 +22,10 @@ Welcome to Solid Watchparty, a platform designed for shared media viewing experi | |
``` | ||
git clone [email protected]:SolidLabResearch/solid-watch-party.git | ||
``` | ||
2. **Navigate to directory** | ||
``` | ||
cd solid-watch-party/solid-watchparty/ | ||
``` | ||
2. **Install Dependencies** | ||
``` | ||
npm install | ||
|
@@ -36,7 +48,8 @@ This project is in active development. This in an overview of the progress: | |
- [x] Creating new rooms and joining rooms | ||
- [x] Sending, retrieving and displaying messages | ||
- [x] Watching a video stream | ||
- [ ] Video stream syncing and controls | ||
- [x] Video stream syncing and controls | ||
- [ ] Privacy | ||
- [ ] Polishing | ||
2. **Statistics dashboard:** | ||
- *details to be determined* | ||
|
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,233 @@ | ||
/* library imports */ | ||
import { useEffect, useState, useContext } from 'react'; | ||
import { useSession, } from "@inrupt/solid-ui-react"; | ||
import { FaUserCircle, FaCheck } from "react-icons/fa"; | ||
import propTypes from 'prop-types'; | ||
|
||
/* component imports */ | ||
import SWModal from '../components/SWModal'; | ||
import SWLoadingIcon from '../components/SWLoadingIcon'; | ||
import { MenuBar, MenuItem } from '../components/SWMenu'; | ||
import SWSwitch from '../components/SWSwitch'; | ||
|
||
/* context imports */ | ||
import { MessageBoxContext } from '../contexts'; | ||
|
||
/* service imports */ | ||
import RoomSolidService from '../services/room.solidservice.js'; | ||
import MessageSolidService from '../services/message.solidservice.js'; | ||
|
||
/* util imports */ | ||
import { inSession } from '../utils/solidUtils'; | ||
|
||
/* TODO(Elias): Add validations and error handling everywhere */ | ||
|
||
function LoadingCard() { | ||
return ( | ||
<div className="flex w-full h-full items-center justify-center"> | ||
<SWLoadingIcon className="w-8 h-8"/> | ||
</div> | ||
); | ||
} | ||
|
||
function PersonCard({person}) { | ||
const [enabled, setEnabled] = useState(false); | ||
const [messageBoxUrl, setMessageBoxUrl] = useContext(MessageBoxContext); | ||
const [isLoading, setIsLoading] = useState(true); | ||
const sessionContext = useSession(); | ||
const isMyCard = (person.webId === sessionContext.session.info.webId); | ||
|
||
useEffect(() => { | ||
const fetch = async () => { | ||
setIsLoading(true); | ||
const accessModes = await MessageSolidService.checkAccess(sessionContext, messageBoxUrl, person.webId); | ||
if (accessModes.error) { | ||
return; | ||
} | ||
setEnabled(accessModes.read); | ||
setIsLoading(false); | ||
} | ||
fetch(); | ||
}, []); | ||
|
||
const onSwitch = async () => { | ||
setIsLoading(true); | ||
const result = await MessageSolidService.setAccess(sessionContext, messageBoxUrl, person.webId, | ||
{read: !enabled}); | ||
setIsLoading(false); | ||
if (result.error) { | ||
return; | ||
} | ||
setEnabled(result.read); | ||
} | ||
|
||
return ( | ||
<div className="rgb-bg-1 sw-border flex justify-between p-4 items-center"> | ||
<div className="flex gap-3"> | ||
<FaUserCircle className="rgb-1 sw-fw-1 w-6 h-6"/> | ||
<p>{person.name}</p> | ||
</div> | ||
<div className="flex gap-3 items-center"> | ||
<p className="rgb-1">Allow seeing my messages:</p> | ||
<SWSwitch enabled={enabled} onSwitch={onSwitch} disabled={isMyCard} isLoading={isLoading}/> | ||
</div> | ||
</div> | ||
); | ||
} | ||
PersonCard.propTypes = { | ||
person: propTypes.object.isRequired, | ||
} | ||
|
||
function RequestingPersonCard({person, roomUrl, removeFromPeople}) { | ||
const sessionContext = useSession(); | ||
const [isLoading, setIsLoading] = useState(false); | ||
|
||
const onAccept = async (person) => { | ||
setIsLoading(true); | ||
const result = await RoomSolidService.addPerson(sessionContext, roomUrl, person.messageBoxUrl, person.webId); | ||
setIsLoading(false); | ||
if (result.error) { | ||
console.error(result.error); | ||
return; | ||
} | ||
removeFromPeople(person); | ||
} | ||
|
||
return ( | ||
<div className="rgb-bg-1 sw-border flex justify-between p-4 h-fit"> | ||
<div className="flex gap-3 justify-between w-full items-center"> | ||
<div className="flex gap-3"> | ||
<FaUserCircle className="rgb-1 sw-fw-1 w-6 h-6"/> | ||
<p className="rgb-on">{person.name}</p> | ||
</div> | ||
{isLoading ? ( | ||
<div className="p-1"> | ||
<SWLoadingIcon className={`w-5`}/> | ||
</div> | ||
) : ( | ||
<button onClick={() => onAccept(person)} | ||
className="p-2 rounded items-center rgb-bg-active-1 hover:rgb-bg-1 | ||
active:rgb-bg-active-2 rgb-active-1 active:rgb-1"> | ||
<FaCheck/> | ||
</button> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
} | ||
RequestingPersonCard.propTypes = { | ||
person: propTypes.object.isRequired, | ||
roomUrl: propTypes.string.isRequired, | ||
removeFromPeople: propTypes.func.isRequired, | ||
} | ||
|
||
function InRoomPeople({roomUrl}) { | ||
const sessionContext = useSession(); | ||
const [isLoading, setIsLoading] = useState(true); | ||
const [people, setPeople] = useState([]); | ||
|
||
useEffect(() => { | ||
const getPeople = async () => { | ||
let peopleResult = await RoomSolidService.getPeople(sessionContext, roomUrl); | ||
if (peopleResult.error) { | ||
console.error(peopleResult.error); | ||
return; | ||
} | ||
peopleResult = peopleResult.map((person, index) => ({...person, key: index})); | ||
setIsLoading(false); | ||
setPeople(peopleResult); | ||
}; | ||
if (inSession(sessionContext)) { | ||
getPeople(); | ||
} | ||
}, []); | ||
|
||
if (isLoading) { | ||
return (<LoadingCard/>); | ||
} | ||
return ( | ||
<div className="overflow-auto grid grid-cols-2 auto-rows-min gap-4 h-[90%]"> | ||
{people.map((person, index) => <PersonCard person={person} key={index}/>)} | ||
</div> | ||
); | ||
} | ||
InRoomPeople.propTypes = { | ||
roomUrl: propTypes.string.isRequired, | ||
} | ||
|
||
function RequestingPeople({roomUrl}) { | ||
const sessionContext = useSession(); | ||
const [isLoading, setIsLoading] = useState(true); | ||
const [people, setPeople] = useState([]); | ||
|
||
useEffect(() => { | ||
const getPeople = async () => { | ||
let peopleResult = await RoomSolidService.getActiveRegisterPeople(sessionContext, roomUrl); | ||
if (peopleResult.error) { | ||
console.error(peopleResult.error); | ||
return; | ||
} | ||
peopleResult = peopleResult.map((person, index) => ({...person, key: index})); | ||
setIsLoading(false); | ||
setPeople(peopleResult); | ||
}; | ||
if (inSession(sessionContext)) { | ||
getPeople(); | ||
} | ||
}, []); | ||
|
||
const removeFromPeople = (person) => { | ||
setPeople(people.filter((p) => (p.webId !== person.webId))); | ||
} | ||
|
||
if (isLoading) { | ||
return (<LoadingCard/>); | ||
} | ||
return ( | ||
<div className="overflow-auto grid grid-cols-2 auto-rows-min gap-4 h-[90%]"> | ||
{people.map((person, index) => ( | ||
<RequestingPersonCard person={person} key={index} roomUrl={roomUrl} | ||
removeFromPeople={removeFromPeople}/> | ||
))} | ||
</div> | ||
); | ||
} | ||
RequestingPeople.propTypes = { | ||
roomUrl: propTypes.string.isRequired, | ||
} | ||
|
||
function PeopleMenuModal({setModalIsShown, roomUrl}) { | ||
/* NOTE(Elias): Uses strings for pages, valid options are: | ||
* 1. in-room | ||
* 2. requesting */ | ||
const [tab, setTab] = useState("in-room"); | ||
|
||
let body = <></> | ||
switch (tab) { | ||
case "in-room": | ||
body = <InRoomPeople roomUrl={roomUrl}/>; | ||
break; | ||
case "requesting": | ||
body = <RequestingPeople roomUrl={roomUrl}/>; | ||
break; | ||
} | ||
|
||
return ( | ||
<SWModal className="rgb-bg-2 h-2/3 p-12 z-10 w-1/2 sw-border" setIsShown={setModalIsShown}> | ||
<div className="mb-6 flex items-center justify-between"> | ||
<p className="sw-fs-2 sw-fw-1">People</p> | ||
<MenuBar> | ||
<MenuItem onClick={() => setTab("in-room")}>In Room</MenuItem> | ||
<MenuItem onClick={() => setTab("requesting")}>Requesting</MenuItem> | ||
</MenuBar> | ||
</div> | ||
{body} | ||
</SWModal> | ||
); | ||
} | ||
PeopleMenuModal.propTypes = { | ||
setModalIsShown: propTypes.func.isRequired, | ||
roomUrl: propTypes.string.isRequired, | ||
} | ||
|
||
export default PeopleMenuModal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.