forked from lavender/watch-party
		
	Implement a viewer list
TODO: - instead of fixing a size make it max-height - when the chat is below the video it would probably be better to put the viewer list next to the chat
This commit is contained in:
		
							parent
							
								
									903fd535ce
								
							
						
					
					
						commit
						98505de0f0
					
				
					 9 changed files with 59 additions and 7 deletions
				
			
		|  | @ -3,7 +3,7 @@ | |||
|   <head> | ||||
|     <meta charset="utf-8" /> | ||||
|     <title>watch party :D</title> | ||||
|     <link rel="stylesheet" href="/styles.css?v=3" /> | ||||
|     <link rel="stylesheet" href="/styles.css?v=4" /> | ||||
|   </head> | ||||
| 
 | ||||
|   <body> | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ | |||
|   <head> | ||||
|     <meta charset="utf-8" /> | ||||
|     <title>watch party :D</title> | ||||
|     <link rel="stylesheet" href="/styles.css?v=3" /> | ||||
|     <link rel="stylesheet" href="/styles.css?v=4" /> | ||||
|   </head> | ||||
| 
 | ||||
|   <body> | ||||
|  | @ -46,12 +46,13 @@ | |||
| 
 | ||||
|     <div id="video-container"></div> | ||||
|     <div id="chatbox-container"> | ||||
|       <div id="viewer-list"></div> | ||||
|       <div id="chatbox"></div> | ||||
|       <form id="chatbox-send"> | ||||
|         <input type="text" placeholder="Message..." /> | ||||
|       </form> | ||||
|     </div> | ||||
| 
 | ||||
|     <script type="module" src="/main.mjs?v=2"></script> | ||||
|     <script type="module" src="/main.mjs?v=3"></script> | ||||
|   </body> | ||||
| </html> | ||||
|  |  | |||
|  | @ -181,3 +181,19 @@ export const logEventToChat = (event) => { | |||
|     } | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| export const updateViewerList = (viewers) => { | ||||
|   const listContainer = document.querySelector("#viewer-list"); | ||||
| 
 | ||||
|   // empty out the current list
 | ||||
|   listContainer.innerHTML = ""; | ||||
| 
 | ||||
|   // display the updated list
 | ||||
|   for (const viewer of viewers) { | ||||
|     const viewerElem = document.createElement("div"); | ||||
|     const content = document.createElement("strong"); | ||||
|     content.appendChild(document.createTextNode(viewer)); | ||||
|     viewerElem.appendChild(content); | ||||
|     listContainer.appendChild(viewerElem); | ||||
|   } | ||||
| }; | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import { joinSession } from "./watch-session.mjs?v=3"; | ||||
| import { joinSession } from "./watch-session.mjs?v=4"; | ||||
| 
 | ||||
| /** | ||||
|  * @param {HTMLInputElement} field | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import { setupVideo } from "./video.mjs?v=2"; | ||||
| import { setupChat, logEventToChat } from "./chat.mjs?v=2"; | ||||
| import { setupChat, logEventToChat, updateViewerList } from "./chat.mjs?v=3"; | ||||
| 
 | ||||
| /** | ||||
|  * @param {string} sessionId | ||||
|  | @ -69,6 +69,9 @@ const setupIncomingEvents = (video, socket) => { | |||
|             setDebounce(); | ||||
|             setVideoTime(event.data); | ||||
|             break; | ||||
|           case "UpdateViewerList": | ||||
|             updateViewerList(event.data); | ||||
|             break; | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import { setupJoinSessionForm } from "./lib/join-session.mjs?v=2"; | ||||
| import { setupJoinSessionForm } from "./lib/join-session.mjs?v=3"; | ||||
| 
 | ||||
| const main = () => { | ||||
|   setupJoinSessionForm(); | ||||
|  |  | |||
|  | @ -156,6 +156,16 @@ button.small-button { | |||
|   overflow-y: scroll; | ||||
| } | ||||
| 
 | ||||
| #viewer-list { | ||||
|   padding: 0.5em 2em; | ||||
|   /* TODO: turn this into max-height instead of fixed height without breaking the chatbox height */ | ||||
|   height: 4em; | ||||
|   overflow-y: scroll; | ||||
|   color: rgb(126, 208, 255); | ||||
|   border-bottom: var(--fg); | ||||
|   border-bottom-style: solid; | ||||
| } | ||||
| 
 | ||||
| #chatbox-container { | ||||
|   background-color: #222; | ||||
| } | ||||
|  | @ -191,6 +201,6 @@ button.small-button { | |||
|   } | ||||
| 
 | ||||
|   #chatbox { | ||||
|     height: calc(100vh - 5em) !important; | ||||
|     height: calc(100vh - 5em - 4em) !important; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -9,6 +9,7 @@ pub enum WatchEventData { | |||
|     UserJoin, | ||||
|     UserLeave, | ||||
|     ChatMessage(String), | ||||
|     UpdateViewerList(Vec<String>), | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Serialize, Deserialize)] | ||||
|  |  | |||
|  | @ -65,6 +65,8 @@ pub async fn ws_subscribe(session_uuid: Uuid, nickname: String, ws: WebSocket) { | |||
|     ) | ||||
|     .await; | ||||
| 
 | ||||
|     update_viewer_list(session_uuid).await; | ||||
| 
 | ||||
|     while let Some(Ok(message)) = viewer_ws_rx.next().await { | ||||
|         let event: WatchEventData = match message | ||||
|             .to_str() | ||||
|  | @ -97,6 +99,7 @@ pub async fn ws_subscribe(session_uuid: Uuid, nickname: String, ws: WebSocket) { | |||
|     .await; | ||||
| 
 | ||||
|     CONNECTED_VIEWERS.write().await.remove(&viewer_id); | ||||
|     update_viewer_list(session_uuid).await; | ||||
| } | ||||
| 
 | ||||
| pub async fn ws_publish(session_uuid: Uuid, skip_viewer_id: Option<usize>, event: WatchEvent) { | ||||
|  | @ -111,3 +114,21 @@ pub async fn ws_publish(session_uuid: Uuid, skip_viewer_id: Option<usize>, event | |||
|         }); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| async fn update_viewer_list(session_uuid: Uuid) { | ||||
|     let mut names = Vec::new(); | ||||
|     for viewer in CONNECTED_VIEWERS.read().await.values() { | ||||
|         if viewer.session == session_uuid && viewer.nickname != None { | ||||
|             names.push(viewer.nickname.clone().unwrap()) | ||||
|         } | ||||
|     } | ||||
|     ws_publish( | ||||
|         session_uuid, | ||||
|         None, | ||||
|         WatchEvent::new( | ||||
|             String::from("server"), | ||||
|             WatchEventData::UpdateViewerList(names), | ||||
|         ), | ||||
|     ) | ||||
|     .await; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue