@@ -35,6 +35,8 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
3535 const [ roomNameError , setRoomNameError ] = useState ( '' ) ;
3636 const [ searchQuery , setSearchQuery ] = useState ( '' ) ;
3737 const [ activeFilter , setActiveFilter ] = useState ( 'All' ) ;
38+ const [ statusMessage , setStatusMessage ] = useState ( '' ) ;
39+ const [ statusTone , setStatusTone ] = useState ( 'info' ) ;
3840 const [ toast , setToast ] = useState ( { visible : false , message : '' , type : 'info' } ) ;
3941 const [ roomFetchError , setRoomFetchError ] = useState ( null ) ;
4042 const [ loadingAction , setLoadingAction ] = useState ( 'idle' ) ;
@@ -111,6 +113,11 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
111113 return activeRoom . ownerDisplayName . trim ( ) . toLowerCase ( ) === userName . trim ( ) . toLowerCase ( ) ;
112114 } , [ activeRoom , userName ] ) ;
113115 const canShareScreen = isHost || meetingSettings . allowGuestScreenShare ;
116+
117+ function showStatus ( message , tone = 'info' ) {
118+ setStatusTone ( tone ) ;
119+ setStatusMessage ( message ) ;
120+ }
114121
115122 const filteredRooms = useMemo ( ( ) => {
116123 let result = rooms || [ ] ;
@@ -200,6 +207,7 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
200207 setActiveRoom ( result . room ) ;
201208 setJoinInput ( result . room . joinLink ) ;
202209 seedMeetingRoom ( result . room ) ;
210+ showStatus ( `${ result . room . roomName } is ready to join.` , 'success' ) ;
203211 setToast ( { visible : true , message : `Room ${ result . room . roomCode } is live.` , type : 'success' } ) ;
204212 await refreshRooms ( ) ;
205213 }
@@ -226,6 +234,7 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
226234 setActiveRoom ( result . room ) ;
227235 setJoinInput ( result . room . roomCode ) ;
228236 seedMeetingRoom ( result . room ) ;
237+ showStatus ( `${ result . room . roomName } is ready to join.` , 'success' ) ;
229238 setToast ( { visible : true , message : `Joined ${ result . room . roomName } .` , type : 'success' } ) ;
230239 await refreshRooms ( ) ;
231240 if ( fromIncomingLink ) {
@@ -237,20 +246,17 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
237246 const result = await getRoom ( roomCode ) ;
238247 setLoadingAction ( 'idle' ) ;
239248 if ( ! result . ok ) {
240- setStatusTone ( 'error' ) ;
241- setStatusMessage ( result . message ) ;
249+ showStatus ( result . message , 'error' ) ;
242250 return ;
243251 }
244252 setActiveRoom ( result . room ) ;
245253 setJoinInput ( result . room . roomCode ) ;
246254 seedMeetingRoom ( result . room ) ;
247- setStatusTone ( 'info' ) ;
248- setStatusMessage ( `${ result . room . roomName } is ready.` ) ;
255+ showStatus ( `${ result . room . roomName } is ready.` , 'info' ) ;
249256 }
250257 async function handleShareRoom ( friendName ) {
251258 if ( ! activeRoom ) {
252- setStatusTone ( 'error' ) ;
253- setStatusMessage ( 'Create or join a room before sharing it.' ) ;
259+ showStatus ( 'Create or join a room before sharing it.' , 'error' ) ;
254260 return ;
255261 }
256262 const message = friendName
@@ -262,30 +268,26 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
262268 message,
263269 } ) ;
264270 setLoadingAction ( 'idle' ) ;
265- setStatusTone ( 'success' ) ;
266- setStatusMessage ( friendName ? `Share sheet opened for ${ friendName } .` : 'Share sheet opened.' ) ;
271+ showStatus ( friendName ? `Share sheet opened for ${ friendName } .` : 'Share sheet opened.' , 'success' ) ;
267272 }
268273 function handleEnterMeeting ( ) {
269274 if ( ! activeRoom ) {
270- setStatusTone ( 'error' ) ;
271- setStatusMessage ( 'Open a room first.' ) ;
275+ showStatus ( 'Open a room first.' , 'error' ) ;
272276 return ;
273277 }
274278 if ( ! meetingParticipants . length ) {
275279 seedMeetingRoom ( activeRoom ) ;
276280 }
277281 setMeetingOpen ( true ) ;
278- setStatusTone ( 'info' ) ;
279- setStatusMessage ( `Inside ${ activeRoom . roomName } .` ) ;
282+ showStatus ( `Inside ${ activeRoom . roomName } .` , 'info' ) ;
280283 }
281284 function handleLeaveMeeting ( ) {
282285 setMeetingOpen ( false ) ;
283286 setMeetingPanel ( 'none' ) ;
284287 setShareScreenOn ( false ) ;
285288 setRecordingOn ( false ) ;
286289 setFocusedParticipantId ( meetingParticipants [ 1 ] ?. id ?? meetingParticipants [ 0 ] ?. id ?? null ) ;
287- setStatusTone ( 'info' ) ;
288- setStatusMessage ( activeRoom ? `Left ${ activeRoom . roomName } . Room is still active.` : 'Left the meeting.' ) ;
290+ showStatus ( activeRoom ? `Left ${ activeRoom . roomName } . Room is still active.` : 'Left the meeting.' , 'info' ) ;
289291 }
290292 function updateSelfParticipant ( updater ) {
291293 setMeetingParticipants ( ( current ) => current . map ( ( participant , index ) => ( index === 0 ? updater ( participant ) : participant ) ) ) ;
@@ -446,6 +448,15 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
446448 { activeRoom . roomType } • { activeRoom . ownerDisplayName } • { activeRoom . participantCount } in room
447449 </ Text >
448450 < Text style = { styles . joinLinkText } > { activeRoom . joinLink } </ Text >
451+ { statusMessage ? ( < View style = { [
452+ styles . statusBanner ,
453+ statusTone === 'success' && styles . statusBannerSuccess ,
454+ statusTone === 'error' && styles . statusBannerError ,
455+ statusTone === 'info' && styles . statusBannerInfo ,
456+ ] } >
457+ < Ionicons name = { statusTone === 'error' ? 'warning' : statusTone === 'success' ? 'checkmark-circle' : 'information-circle' } size = { 18 } color = { statusTone === 'error' ? '#B3261E' : theme . colors . accentStrong } />
458+ < Text style = { styles . statusBannerText } > { statusMessage } </ Text >
459+ </ View > ) : null }
449460 < View style = { styles . previewCard } >
450461 < View style = { styles . previewVisual } >
451462 < Text style = { styles . previewInitials } > { getInitials ( userName ) } </ Text >
@@ -629,8 +640,8 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
629640 < Text style = { styles . captionText } > Prof. Deshmukh: Let's revise normalization before we solve the next DBMS problem.</ Text >
630641 </ View > ) : null }
631642
632- { reactionBurst ? ( < View style = { styles . reactionBubble } >
633- < Text style = { styles . reactionEmoji } > { reactionBurst . icon } </ Text >
643+ { reactionBurst ? ( < View style = { styles . reactionBubble } >
644+ < Ionicons name = { reactionBurst . icon } size = { 24 } color = "#FFFFFF" / >
634645 < Text style = { styles . reactionLabel } > { reactionBurst . label } </ Text >
635646 </ View > ) : null }
636647 </ View >
@@ -661,12 +672,12 @@ export default function HangoutScreen({ onOpenDrawer, avatarLabel, sessionToken,
661672
662673 < View style = { styles . reactionRow } >
663674 { [
664- { icon : '👏 ' , label : 'Clap ' } ,
665- { icon : '🔥 ' , label : 'Fire ' } ,
666- { icon : '👍 ' , label : 'Thumbs up ' } ,
667- { icon : '🙌 ' , label : 'Celebrate ' } ,
675+ { icon : 'hand-left ' , label : 'Raise hand ' } ,
676+ { icon : 'checkmark-circle ' , label : 'Agree ' } ,
677+ { icon : 'help-circle ' , label : 'Question ' } ,
678+ { icon : 'bulb ' , label : 'Idea ' } ,
668679 ] . map ( ( reaction ) => ( < Pressable key = { reaction . label } style = { styles . reactionChip } onPress = { ( ) => sendReaction ( reaction . icon , reaction . label ) } >
669- < Text style = { styles . reactionChipEmoji } > { reaction . icon } </ Text >
680+ < Ionicons name = { reaction . icon } size = { 16 } color = { theme . colors . darkText } / >
670681 < Text style = { styles . reactionChipText } > { reaction . label } </ Text >
671682 </ Pressable > ) ) }
672683 </ View >
@@ -838,12 +849,15 @@ function MeetingPanelSheet({ visible, panel, participants, messages, activityFee
838849 </ ScrollView > ) : null }
839850
840851 { panel === 'settings' ? ( < ScrollView style = { styles . panelScroll } showsVerticalScrollIndicator = { false } >
852+ { ! isHost ? ( < View style = { styles . guestNotice } >
853+ < Text style = { styles . guestNoticeText } > Only the host can change room-wide settings.</ Text >
854+ </ View > ) : null }
841855 < SettingsRow label = "Noise cancellation" value = { settings . noiseCancellation } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , noiseCancellation : value } ) } />
842856 < SettingsRow label = "Low light mode" value = { settings . lowLightMode } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , lowLightMode : value } ) } />
843857 < SettingsRow label = "Mirror self view" value = { settings . mirrorSelfView } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , mirrorSelfView : value } ) } />
844- < SettingsRow label = "Allow in-call chat" value = { settings . allowChat } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , allowChat : value } ) } />
845- < SettingsRow label = "Allow guest screen share" value = { settings . allowGuestScreenShare } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , allowGuestScreenShare : value } ) } />
846- < SettingsRow label = "Waiting room" value = { settings . waitingRoomEnabled } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , waitingRoomEnabled : value } ) } />
858+ < SettingsRow label = "Allow in-call chat" value = { settings . allowChat } disabled = { ! isHost } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , allowChat : value } ) } />
859+ < SettingsRow label = "Allow guest screen share" value = { settings . allowGuestScreenShare } disabled = { ! isHost } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , allowGuestScreenShare : value } ) } />
860+ < SettingsRow label = "Waiting room" value = { settings . waitingRoomEnabled } disabled = { ! isHost } onValueChange = { ( value ) => onUpdateSettings ( { ...settings , waitingRoomEnabled : value } ) } />
847861
848862 < Text style = { styles . settingsLabel } > Layout</ Text >
849863 < View style = { styles . settingsChipRow } >
@@ -881,10 +895,10 @@ function MeetingPanelSheet({ visible, panel, participants, messages, activityFee
881895 </ View >
882896 </ Modal > ) ;
883897}
884- function SettingsRow ( { label, value, onValueChange, } ) {
885- return ( < View style = { styles . settingsRow } >
898+ function SettingsRow ( { label, value, disabled = false , onValueChange, } ) {
899+ return ( < View style = { [ styles . settingsRow , disabled && styles . settingsRowDisabled ] } >
886900 < Text style = { styles . settingsText } > { label } </ Text >
887- < Switch value = { value } onValueChange = { onValueChange } trackColor = { { false : '#DADCE0' , true : theme . colors . accentSoft } } thumbColor = { value ? theme . colors . accentStrong : '#FFFFFF' } />
901+ < Switch value = { value } disabled = { disabled } onValueChange = { onValueChange } trackColor = { { false : '#DADCE0' , true : theme . colors . accentSoft } } thumbColor = { value ? theme . colors . accentStrong : '#FFFFFF' } />
888902 </ View > ) ;
889903}
890904const panelTitleMap = {
@@ -1923,6 +1937,9 @@ const styles = StyleSheet.create({
19231937 borderBottomWidth : 1 ,
19241938 borderBottomColor : theme . colors . line ,
19251939 } ,
1940+ settingsRowDisabled : {
1941+ opacity : 0.55 ,
1942+ } ,
19261943 settingsText : {
19271944 color : theme . colors . text ,
19281945 fontSize : 15 ,
0 commit comments