diff --git a/src/app/components/create-room/CreateRoomKindSelector.tsx b/src/app/components/create-room/CreateRoomKindSelector.tsx index 096954fb..ebc55e7f 100644 --- a/src/app/components/create-room/CreateRoomKindSelector.tsx +++ b/src/app/components/create-room/CreateRoomKindSelector.tsx @@ -2,12 +2,8 @@ import React from 'react'; import { Box, Text, Icon, Icons, config, IconSrc } from 'folds'; import { SequenceCard } from '../sequence-card'; import { SettingTile } from '../setting-tile'; +import { CreateRoomKind } from './types'; -export enum CreateRoomKind { - Private = 'private', - Restricted = 'restricted', - Public = 'public', -} type CreateRoomKindSelectorProps = { value?: CreateRoomKind; onSelect: (value: CreateRoomKind) => void; diff --git a/src/app/components/create-room/CreateRoomVoiceSelector.tsx b/src/app/components/create-room/CreateRoomVoiceSelector.tsx new file mode 100644 index 00000000..f3862db2 --- /dev/null +++ b/src/app/components/create-room/CreateRoomVoiceSelector.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { Box, Text, Icon, Icons, config, IconSrc } from 'folds'; +import { SequenceCard } from '../sequence-card'; +import { SettingTile } from '../setting-tile'; +import { CreateRoomVoice } from './types'; + +type CreateRoomVoiceSelectorProps = { + value?: CreateRoomVoice; + onSelect: (value: CreateRoomVoice) => void; + disabled?: boolean; + getIcon: (kind: CreateRoomVoice) => IconSrc; +}; +export function CreateRoomVoiceSelector({ + value, + onSelect, + disabled, + getIcon, +}: CreateRoomVoiceSelectorProps) { + return ( + + onSelect(CreateRoomVoice.TextRoom)} + disabled={disabled} + > + } + after={value === CreateRoomVoice.TextRoom && } + > + Text + + Send text messages, videos and GIFs. + + + + onSelect(CreateRoomVoice.VoiceRoom)} + disabled={disabled} + > + } + after={value === CreateRoomVoice.VoiceRoom && } + > + Voice + + A room optimized for voice calls. + + + + + ); +} diff --git a/src/app/components/create-room/index.ts b/src/app/components/create-room/index.ts index ffd9cb3d..a9c603b2 100644 --- a/src/app/components/create-room/index.ts +++ b/src/app/components/create-room/index.ts @@ -3,3 +3,4 @@ export * from './CreateRoomAliasInput'; export * from './RoomVersionSelector'; export * from './utils'; export * from './AdditionalCreatorInput'; +export * from './types'; diff --git a/src/app/components/create-room/types.ts b/src/app/components/create-room/types.ts new file mode 100644 index 00000000..e35af47a --- /dev/null +++ b/src/app/components/create-room/types.ts @@ -0,0 +1,10 @@ +export enum CreateRoomVoice { + TextRoom = 'text', + VoiceRoom = 'voice', +} + +export enum CreateRoomKind { + Private = 'private', + Restricted = 'restricted', + Public = 'public', +} diff --git a/src/app/components/create-room/utils.ts b/src/app/components/create-room/utils.ts index f10adf21..3d702f2a 100644 --- a/src/app/components/create-room/utils.ts +++ b/src/app/components/create-room/utils.ts @@ -7,11 +7,11 @@ import { Room, } from 'matrix-js-sdk'; import { RoomJoinRulesEventContent } from 'matrix-js-sdk/lib/types'; -import { CreateRoomKind } from './CreateRoomKindSelector'; import { RoomType, StateEvent } from '../../../types/matrix/room'; import { getViaServers } from '../../plugins/via-servers'; import { getMxIdServer } from '../../utils/matrix'; import { IPowerLevels } from '../../hooks/usePowerLevels'; +import { CreateRoomKind } from './types'; export const createRoomCreationContent = ( type: RoomType | undefined, diff --git a/src/app/features/create-room/CreateRoom.tsx b/src/app/features/create-room/CreateRoom.tsx index ef8e67be..9cc8bee8 100644 --- a/src/app/features/create-room/CreateRoom.tsx +++ b/src/app/features/create-room/CreateRoom.tsx @@ -1,5 +1,5 @@ import React, { FormEventHandler, useCallback, useEffect, useState } from 'react'; -import { MatrixError, Room } from 'matrix-js-sdk'; +import { MatrixError, Room, JoinRule } from 'matrix-js-sdk'; import { Box, Button, @@ -37,22 +37,40 @@ import { CreateRoomKindSelector, RoomVersionSelector, useAdditionalCreators, + CreateRoomVoice, } from '../../components/create-room'; import { RoomType, StateEvent } from '../../../types/matrix/room'; import { IPowerLevels } from '../../hooks/usePowerLevels'; +import { CreateRoomVoiceSelector } from '../../components/create-room/CreateRoomVoiceSelector'; +import { getRoomIconSrc } from '../../utils/room'; -const getCreateRoomKindToIcon = (kind: CreateRoomKind) => { - if (kind === CreateRoomKind.Private) return Icons.HashLock; - if (kind === CreateRoomKind.Restricted) return Icons.Hash; - return Icons.HashGlobe; +const getCreateRoomKindToIcon = (kind: CreateRoomKind, voice?: CreateRoomVoice) => { + const isVoiceRoom = voice === CreateRoomVoice.VoiceRoom; + + let joinRule: JoinRule = JoinRule.Public; + if (kind === CreateRoomKind.Restricted) joinRule = JoinRule.Restricted; + if (kind === CreateRoomKind.Private) joinRule = JoinRule.Knock; + + return getRoomIconSrc(Icons, isVoiceRoom ? RoomType.Call : undefined, joinRule); +}; + +const getCreateRoomVoiceToIcon = (kind: CreateRoomVoice) => { + if (kind === CreateRoomVoice.VoiceRoom) return Icons.VolumeHigh; + return Icons.Hash; }; type CreateRoomFormProps = { defaultKind?: CreateRoomKind; + defaultVoice?: CreateRoomVoice; space?: Room; onCreate?: (roomId: string) => void; }; -export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormProps) { +export function CreateRoomForm({ + defaultKind, + defaultVoice, + space, + onCreate, +}: CreateRoomFormProps) { const mx = useMatrixClient(); const alive = useAlive(); @@ -66,6 +84,7 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP const allowRestricted = space && restrictedSupported(selectedRoomVersion); + const [voice, setVoice] = useState(defaultVoice ?? CreateRoomVoice.TextRoom); const [kind, setKind] = useState( defaultKind ?? allowRestricted ? CreateRoomKind.Restricted : CreateRoomKind.Private ); @@ -74,7 +93,6 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP useAdditionalCreators(); const [federation, setFederation] = useState(true); const [encryption, setEncryption] = useState(false); - const [callRoom, setCallRoom] = useState(false); const [knock, setKnock] = useState(false); const [advance, setAdvance] = useState(false); @@ -123,7 +141,7 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP const powerOverrides: IPowerLevels = { events: {}, }; - if (callRoom) { + if (voice === CreateRoomVoice.VoiceRoom) { roomType = RoomType.Call; powerOverrides.events![StateEvent.GroupCallMemberPrefix] = 0; } @@ -150,6 +168,17 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP return ( + {!space && ( + + Type + + + )} Access getCreateRoomKindToIcon(roomKind, voice)} /> Name } + before={} name="nameInput" autoFocus size="500" @@ -184,20 +213,6 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP disabled={disabled} /> - - - } - /> - {kind === CreateRoomKind.Public && } diff --git a/src/app/features/create-room/CreateRoomModal.tsx b/src/app/features/create-room/CreateRoomModal.tsx index c9919ba9..5fa9b6ca 100644 --- a/src/app/features/create-room/CreateRoomModal.tsx +++ b/src/app/features/create-room/CreateRoomModal.tsx @@ -23,12 +23,13 @@ import { } from '../../state/hooks/createRoomModal'; import { CreateRoomModalState } from '../../state/createRoomModal'; import { stopPropagation } from '../../utils/keyboard'; +import { CreateRoomVoice } from '../../components/create-room/types'; type CreateRoomModalProps = { state: CreateRoomModalState; }; function CreateRoomModal({ state }: CreateRoomModalProps) { - const { spaceId } = state; + const { spaceId, voice } = state; const closeDialog = useCloseCreateRoomModal(); const allJoinedRooms = useAllJoinedRoomsSet(); @@ -57,7 +58,7 @@ function CreateRoomModal({ state }: CreateRoomModalProps) { }} > - New Room + New {voice === CreateRoomVoice.VoiceRoom && 'Voice '}Room @@ -74,7 +75,7 @@ function CreateRoomModal({ state }: CreateRoomModalProps) { direction="Column" gap="500" > - + diff --git a/src/app/features/lobby/SpaceItem.tsx b/src/app/features/lobby/SpaceItem.tsx index 64a97900..3dfbbdea 100644 --- a/src/app/features/lobby/SpaceItem.tsx +++ b/src/app/features/lobby/SpaceItem.tsx @@ -36,6 +36,7 @@ import { useMediaAuthentication } from '../../hooks/useMediaAuthentication'; import { useOpenCreateRoomModal } from '../../state/hooks/createRoomModal'; import { useOpenCreateSpaceModal } from '../../state/hooks/createSpaceModal'; import { AddExistingModal } from '../add-existing'; +import { CreateRoomVoice } from '../../components/create-room/types'; function SpaceProfileLoading() { return ( @@ -249,8 +250,8 @@ function AddRoomButton({ item }: { item: HierarchyItem }) { setCords(evt.currentTarget.getBoundingClientRect()); }; - const handleCreateRoom = () => { - openCreateRoomModal(item.roomId); + const handleCreateRoom = (voice?: CreateRoomVoice) => { + openCreateRoomModal(item.roomId, voice); setCords(undefined); }; @@ -281,10 +282,19 @@ function AddRoomButton({ item }: { item: HierarchyItem }) { radii="300" variant="Primary" fill="None" - onClick={handleCreateRoom} + onClick={() => handleCreateRoom(CreateRoomVoice.TextRoom)} > New Room + handleCreateRoom(CreateRoomVoice.VoiceRoom)} + > + New Voice Room + Existing Room diff --git a/src/app/state/createRoomModal.ts b/src/app/state/createRoomModal.ts index 81af5d5b..3d1a6803 100644 --- a/src/app/state/createRoomModal.ts +++ b/src/app/state/createRoomModal.ts @@ -1,7 +1,9 @@ import { atom } from 'jotai'; +import { CreateRoomVoice } from '../components/create-room/types'; export type CreateRoomModalState = { spaceId?: string; + voice?: CreateRoomVoice; }; export const createRoomModalAtom = atom(undefined); diff --git a/src/app/state/hooks/createRoomModal.ts b/src/app/state/hooks/createRoomModal.ts index 15db7289..dfb15017 100644 --- a/src/app/state/hooks/createRoomModal.ts +++ b/src/app/state/hooks/createRoomModal.ts @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import { useAtomValue, useSetAtom } from 'jotai'; import { createRoomModalAtom, CreateRoomModalState } from '../createRoomModal'; +import { CreateRoomVoice } from '../../components/create-room/types'; export const useCreateRoomModalState = (): CreateRoomModalState | undefined => { const data = useAtomValue(createRoomModalAtom); @@ -19,13 +20,13 @@ export const useCloseCreateRoomModal = (): CloseCallback => { return close; }; -type OpenCallback = (space?: string) => void; +type OpenCallback = (space?: string, voice?: CreateRoomVoice) => void; export const useOpenCreateRoomModal = (): OpenCallback => { const setSettings = useSetAtom(createRoomModalAtom); const open: OpenCallback = useCallback( - (spaceId) => { - setSettings({ spaceId }); + (spaceId, voice) => { + setSettings({ spaceId, voice }); }, [setSettings] );