diff --git a/res/css/views/beta/_BetaCard.scss b/res/css/views/beta/_BetaCard.scss index d54dd4a4c82..642e08f3f41 100644 --- a/res/css/views/beta/_BetaCard.scss +++ b/res/css/views/beta/_BetaCard.scss @@ -20,6 +20,7 @@ limitations under the License. background-color: $system; border-radius: 8px; box-sizing: border-box; + color: $secondary-content; .mx_BetaCard_columns { display: flex; @@ -45,14 +46,13 @@ limitations under the License. .mx_BetaCard_caption { font-size: $font-15px; line-height: $font-20px; - color: $secondary-content; } .mx_BetaCard_buttons { display: flex; flex-wrap: wrap-reverse; - gap: 12px; - margin: 20px auto; + gap: $spacing-12; + margin: $spacing-20 auto 0; .mx_AccessibleButton { padding: 7px 40px; @@ -66,10 +66,16 @@ limitations under the License. } } - .mx_BetaCard_disclaimer { + .mx_BetaCard_refreshWarning { + margin-top: $spacing-8; + font-size: $font-10px; + text-align: center; + } + + .mx_BetaCard_faq { + margin-top: $spacing-20; font-size: $font-12px; line-height: $font-15px; - color: $secondary-content; > h4 { margin: 12px 0 0; @@ -105,7 +111,6 @@ limitations under the License. margin-top: 4px; font-size: $font-12px; line-height: $font-15px; - color: $secondary-content; } } } diff --git a/res/css/views/rooms/_RoomHeader.scss b/res/css/views/rooms/_RoomHeader.scss index d3e5077e449..6ac17732639 100644 --- a/res/css/views/rooms/_RoomHeader.scss +++ b/res/css/views/rooms/_RoomHeader.scss @@ -44,6 +44,10 @@ limitations under the License. .mx_InviteOnlyIcon_large { margin: 0; } + + .mx_BetaCard_betaPill { + margin-right: $spacing-8; + } } .mx_RoomHeader_spinner { diff --git a/res/css/views/rooms/_RoomPreviewCard.scss b/res/css/views/rooms/_RoomPreviewCard.scss index b561bf666df..322a8c4251d 100644 --- a/res/css/views/rooms/_RoomPreviewCard.scss +++ b/res/css/views/rooms/_RoomPreviewCard.scss @@ -105,6 +105,13 @@ limitations under the License. mask-image: url('$(res)/img/element-icons/call/video-call.svg'); } } + + // XXX Remove this when video rooms leave beta + .mx_BetaCard_betaPill { + position: absolute; + right: $spacing-24; + top: $spacing-32; + } } h1.mx_RoomPreviewCard_name { diff --git a/res/img/betas/video_rooms.png b/res/img/betas/video_rooms.png new file mode 100644 index 00000000000..02a9e8c86b7 Binary files /dev/null and b/res/img/betas/video_rooms.png differ diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 4f7c8019241..6ccfe4dd5dd 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -123,7 +123,7 @@ const SpaceLandingAddButton = ({ space }) => { { canCreateRoom && <> { e.preventDefault(); e.stopPropagation(); @@ -135,19 +135,23 @@ const SpaceLandingAddButton = ({ space }) => { } }} /> - { videoRoomsEnabled && { - e.preventDefault(); - e.stopPropagation(); - closeMenu(); - - if (await showCreateNewRoom(space, RoomType.ElementVideo)) { - defaultDispatcher.fire(Action.UpdateSpaceHierarchy); - } - }} - /> } + { videoRoomsEnabled && ( + { + e.preventDefault(); + e.stopPropagation(); + closeMenu(); + + if (await showCreateNewRoom(space, RoomType.ElementVideo)) { + defaultDispatcher.fire(Action.UpdateSpaceHierarchy); + } + }} + > + + + ) } } { const { title, caption, - disclaimer, + faq, image, feedbackLabel, feedbackSubheading, @@ -99,6 +99,14 @@ const BetaCard = ({ title: titleOverride, featureId }: IProps) => { ; } + let refreshWarning: string; + if (requiresRefresh) { + const brand = SdkConfig.get().brand; + refreshWarning = value + ? _t("Leaving the beta will reload %(brand)s.", { brand }) + : _t("Joining the beta will reload %(brand)s.", { brand }); + } + let content: ReactNode; if (busy) { content = ; @@ -137,8 +145,11 @@ const BetaCard = ({ title: titleOverride, featureId }: IProps) => { { content } - { disclaimer &&
- { disclaimer(value) } + { refreshWarning &&
+ { refreshWarning } +
} + { faq &&
+ { faq(value) }
}
diff --git a/src/components/views/context_menus/SpaceContextMenu.tsx b/src/components/views/context_menus/SpaceContextMenu.tsx index 5d045900453..ce28ae32950 100644 --- a/src/components/views/context_menus/SpaceContextMenu.tsx +++ b/src/components/views/context_menus/SpaceContextMenu.tsx @@ -184,7 +184,9 @@ const SpaceContextMenu = ({ space, hideHeader, onFinished, ...props }: IProps) = iconClassName="mx_SpacePanel_iconPlus" label={_t("Video room")} onClick={onNewVideoRoomClick} - /> + > + + } { canAddSubSpaces && { const e2eIcon = this.props.e2eStatus ? : undefined; + const isVideoRoom = SettingsStore.getValue("feature_video_rooms") && this.props.room.isElementVideoRoom(); + const viewLabs = () => defaultDispatcher.dispatch({ + action: Action.ViewUserSettings, + initialTabId: UserTab.Labs, + }); + const betaPill = isVideoRoom ? ( + + ) : null; + return (
@@ -280,6 +293,7 @@ export default class RoomHeader extends React.Component { { name } { searchStatus } { topicElement } + { betaPill } { rightRow }
diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index a0632d763e1..45e0c46bf00 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -41,6 +41,7 @@ import IconizedContextMenu, { IconizedContextMenuOptionList, } from "../context_menus/IconizedContextMenu"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; +import { BetaPill } from "../beta/BetaCard"; import SpaceStore from "../../../stores/spaces/SpaceStore"; import { isMetaSpace, @@ -238,19 +239,23 @@ const UntaggedAuxButton = ({ tabIndex }: IAuxButtonProps) => { tooltip={canAddRooms ? undefined : _t("You do not have permissions to create new rooms in this space")} /> - { SettingsStore.getValue("feature_video_rooms") && { - e.preventDefault(); - e.stopPropagation(); - closeMenu(); - showCreateNewRoom(activeSpace, RoomType.ElementVideo); - }} - disabled={!canAddRooms} - tooltip={canAddRooms ? undefined - : _t("You do not have permissions to create new rooms in this space")} - /> } + { SettingsStore.getValue("feature_video_rooms") && ( + { + e.preventDefault(); + e.stopPropagation(); + closeMenu(); + showCreateNewRoom(activeSpace, RoomType.ElementVideo); + }} + disabled={!canAddRooms} + tooltip={canAddRooms ? undefined + : _t("You do not have permissions to create new rooms in this space")} + > + + + ) } { PosthogTrackers.trackInteraction("WebRoomListRoomsSublistPlusMenuCreateRoomItem", e); }} /> - { SettingsStore.getValue("feature_video_rooms") && { - e.preventDefault(); - e.stopPropagation(); - closeMenu(); - defaultDispatcher.dispatch({ - action: "view_create_room", - type: RoomType.ElementVideo, - }); - }} - /> } + { SettingsStore.getValue("feature_video_rooms") && ( + { + e.preventDefault(); + e.stopPropagation(); + closeMenu(); + defaultDispatcher.dispatch({ + action: "view_create_room", + type: RoomType.ElementVideo, + }); + }} + > + + + ) } } { closePlusMenu(); }} /> - { videoRoomsEnabled && { - e.preventDefault(); - e.stopPropagation(); - showCreateNewRoom(activeSpace, RoomType.ElementVideo); - closePlusMenu(); - }} - /> } + { videoRoomsEnabled && ( + { + e.preventDefault(); + e.stopPropagation(); + showCreateNewRoom(activeSpace, RoomType.ElementVideo); + closePlusMenu(); + }} + > + + + ) } ; } @@ -312,19 +316,23 @@ const RoomListHeader = ({ onVisibilityChange }: IProps) => { closePlusMenu(); }} /> - { videoRoomsEnabled && { - e.preventDefault(); - e.stopPropagation(); - defaultDispatcher.dispatch({ - action: "view_create_room", - type: RoomType.ElementVideo, - }); - closePlusMenu(); - }} - /> } + { videoRoomsEnabled && ( + { + e.preventDefault(); + e.stopPropagation(); + defaultDispatcher.dispatch({ + action: "view_create_room", + type: RoomType.ElementVideo, + }); + closePlusMenu(); + }} + > + + + ) } ; } if (canExploreRooms) { diff --git a/src/components/views/rooms/RoomPreviewCard.tsx b/src/components/views/rooms/RoomPreviewCard.tsx index 71b22765743..65dadc96f6c 100644 --- a/src/components/views/rooms/RoomPreviewCard.tsx +++ b/src/components/views/rooms/RoomPreviewCard.tsx @@ -35,6 +35,7 @@ import RoomTopic from "../elements/RoomTopic"; import RoomFacePile from "../elements/RoomFacePile"; import RoomAvatar from "../avatars/RoomAvatar"; import MemberAvatar from "../avatars/MemberAvatar"; +import { BetaPill } from "../beta/BetaCard"; import RoomInfoLine from "./RoomInfoLine"; interface IProps { @@ -151,6 +152,7 @@ const RoomPreviewCard: FC = ({ room, onJoinButtonClicked, onRejectButton avatarRow = <>
+ ; } else if (room.isSpaceRoom()) { avatarRow = ; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index af9d020df94..f32e1ac6933 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -869,6 +869,14 @@ "Encryption": "Encryption", "Experimental": "Experimental", "Developer": "Developer", + "Video rooms": "Video rooms", + "A new way to chat over voice and video in %(brand)s.": "A new way to chat over voice and video in %(brand)s.", + "Video rooms are always-on VoIP channels embedded within a room in %(brand)s.": "Video rooms are always-on VoIP channels embedded within a room in %(brand)s.", + "How can I create a video room?": "How can I create a video room?", + "Use the “+” button in the room section of the left panel.": "Use the “+” button in the room section of the left panel.", + "Can I use text chat alongside the video call?": "Can I use text chat alongside the video call?", + "Yes, the chat timeline is displayed alongside the video.": "Yes, the chat timeline is displayed alongside the video.", + "Thank you for trying the beta, please go into as much detail as you can so we can improve it.": "Thank you for trying the beta, please go into as much detail as you can so we can improve it.", "Let moderators hide messages pending moderation.": "Let moderators hide messages pending moderation.", "Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators": "Report to moderators prototype. In rooms that support moderation, the `report` button will let you report abuse to room moderators", "Render LaTeX maths in messages": "Render LaTeX maths in messages", @@ -882,8 +890,6 @@ "How can I leave the beta?": "How can I leave the beta?", "To leave, return to this page and use the “%(leaveTheBeta)s” button.": "To leave, return to this page and use the “%(leaveTheBeta)s” button.", "Leave the beta": "Leave the beta", - "Thank you for trying the beta, please go into as much detail as you can so we can improve it.": "Thank you for trying the beta, please go into as much detail as you can so we can improve it.", - "Video rooms (under active development)": "Video rooms (under active development)", "Render simple counters in room header": "Render simple counters in room header", "Try out new ways to ignore people (experimental)": "Try out new ways to ignore people (experimental)", "Support adding custom themes": "Support adding custom themes", @@ -1784,6 +1790,7 @@ "Show Widgets": "Show Widgets", "Search": "Search", "Invite": "Invite", + "Video rooms are a beta feature": "Video rooms are a beta feature", "Video room": "Video room", "Public space": "Public space", "Public room": "Public room", @@ -2954,6 +2961,8 @@ "This is a beta feature": "This is a beta feature", "Click for more info": "Click for more info", "Beta": "Beta", + "Leaving the beta will reload %(brand)s.": "Leaving the beta will reload %(brand)s.", + "Joining the beta will reload %(brand)s.": "Joining the beta will reload %(brand)s.", "Join the beta": "Join the beta", "Updated %(humanizedUpdateTime)s": "Updated %(humanizedUpdateTime)s", "Live until %(expiryTime)s": "Live until %(expiryTime)s", diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 53ff2ceb2de..2cb5a25d8c7 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -165,7 +165,7 @@ export interface IBaseSetting { betaInfo?: { title: string; // _td caption: () => ReactNode; - disclaimer?: (enabled: boolean) => ReactNode; + faq?: (enabled: boolean) => ReactNode; image?: string; // require(...) feedbackSubheading?: string; feedbackLabel?: string; @@ -184,6 +184,42 @@ export interface IFeature extends Omit, "isFeature"> { export type ISetting = IBaseSetting | IFeature; export const SETTINGS: {[setting: string]: ISetting} = { + "feature_video_rooms": { + isFeature: true, + labsGroup: LabGroup.Rooms, + displayName: _td("Video rooms"), + supportedLevels: LEVELS_FEATURE, + default: false, + // Reload to ensure that the left panel etc. get remounted + controller: new ReloadOnChangeController(), + betaInfo: { + title: _td("Video rooms"), + caption: () => <> +

+ { _t("A new way to chat over voice and video in %(brand)s.", { + brand: SdkConfig.get().brand, + }) } +

+

+ { _t("Video rooms are always-on VoIP channels embedded within a room in %(brand)s.", { + brand: SdkConfig.get().brand, + }) } +

+ , + faq: () => + SdkConfig.get().bug_report_endpoint_url && <> +

{ _t("How can I create a video room?") }

+

{ _t("Use the “+” button in the room section of the left panel.") }

+

{ _t("Can I use text chat alongside the video call?") }

+

{ _t("Yes, the chat timeline is displayed alongside the video.") }

+ , + feedbackLabel: "video-room-feedback", + feedbackSubheading: _td("Thank you for trying the beta, " + + "please go into as much detail as you can so we can improve it."), + image: require("../../res/img/betas/video_rooms.png"), + requiresRefresh: true, + }, + }, "feature_msc3531_hide_messages_pending_moderation": { isFeature: true, labsGroup: LabGroup.Moderation, @@ -232,7 +268,7 @@ export const SETTINGS: {[setting: string]: ISetting} = { , }) }

, - disclaimer: () => + faq: () => SdkConfig.get().bug_report_endpoint_url && <>

{ _t("How can I start a thread?") }

@@ -255,15 +291,6 @@ export const SETTINGS: {[setting: string]: ISetting} = { }, }, - "feature_video_rooms": { - isFeature: true, - labsGroup: LabGroup.Rooms, - displayName: _td("Video rooms (under active development)"), - supportedLevels: LEVELS_FEATURE, - default: false, - // Reload to ensure that the left panel etc. get remounted - controller: new ReloadOnChangeController(), - }, "feature_state_counters": { isFeature: true, labsGroup: LabGroup.Rooms, @@ -363,7 +390,7 @@ export const SETTINGS: {[setting: string]: ISetting} = {

{ _t("A new, quick way to search spaces and rooms you're in.") }

{ _t("This feature is a work in progress, we'd love to hear your feedback.") }

, - disclaimer: () => <> + faq: () => <> { SdkConfig.get().bug_report_endpoint_url && <>

{ _t("How can I give feedback?") }

{ _t("To feedback, join the beta, start a search and click on feedback.") }