diff --git a/src/app/features/room/RoomViewHeader.tsx b/src/app/features/room/RoomViewHeader.tsx index 08f4e95d7..41be23fa9 100644 --- a/src/app/features/room/RoomViewHeader.tsx +++ b/src/app/features/room/RoomViewHeader.tsx @@ -27,6 +27,8 @@ import { import { useAtom } from 'jotai'; import { useNavigate } from 'react-router-dom'; import { Room } from 'matrix-js-sdk'; +import { useVoiceChannelFull } from '../../hooks/useVoiceChannelFull'; +import { useRoomCallPolicy } from '../../hooks/useRoomCallPolicy'; import { useStateEvent } from '../../hooks/useStateEvent'; import { PageHeader } from '../../components/page'; import { RoomAvatar, RoomIcon } from '../../components/room-avatar'; @@ -415,6 +417,54 @@ const CallMenu = forwardRef( }, ); +/** + * [Gitea #134] One small chip that tells members a room's call rules before + * they hit the server-side guard: "8/10" when a voice limit is set, a muted + * camera glyph when the room is audio-only. Nothing when no rule exists; the + * tooltip carries the words. Desktop only (the mobile header is tight). + */ +function CallRulesChip({ room }: { room: Room }) { + const { current, max } = useVoiceChannelFull(room); + const { allowCamera, allowScreenshare } = useRoomCallPolicy(room); + const audioOnly = !allowCamera && !allowScreenshare; + if (max <= 0 && !audioOnly) return null; + const words = [ + max > 0 ? `Voice limit ${max} (${current} in call)` : undefined, + audioOnly ? 'Audio-only room' : undefined, + ] + .filter(Boolean) + .join(' ยท '); + return ( + + {words} + + } + > + {(triggerRef) => ( + : undefined} + > + {max > 0 && ( + + {current}/{max} + + )} + + )} + + ); +} + function CallButton() { const room = useRoom(); const direct = useIsDirectRoom(); @@ -731,6 +781,7 @@ export function RoomViewHeader({ callView }: { callView?: boolean }) { } /> + {screenSize === ScreenSize.Desktop && } {!room.isCallRoom() && livekitSupported && rtcSupported &&