diff --git a/res/css/_components.pcss b/res/css/_components.pcss index 808b6b024e1..504dbca5bc6 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -348,7 +348,6 @@ @import "./views/settings/tabs/user/_MjolnirUserSettingsTab.pcss"; @import "./views/settings/tabs/user/_SecurityUserSettingsTab.pcss"; @import "./views/settings/tabs/user/_SidebarUserSettingsTab.pcss"; -@import "./views/settings/tabs/user/_VoiceUserSettingsTab.pcss"; @import "./views/spaces/_SpaceBasicSettings.pcss"; @import "./views/spaces/_SpaceChildrenPicker.pcss"; @import "./views/spaces/_SpaceCreateMenu.pcss"; diff --git a/res/css/structures/_QuickSettingsButton.pcss b/res/css/structures/_QuickSettingsButton.pcss index 128c8e0fbbe..3f26e132504 100644 --- a/res/css/structures/_QuickSettingsButton.pcss +++ b/res/css/structures/_QuickSettingsButton.pcss @@ -113,9 +113,11 @@ limitations under the License. } .mx_QuickSettingsButton_icon { + // TODO remove when all icons have fill=currentColor * { fill: $secondary-content; } + color: $secondary-content; width: 16px; height: 16px; position: absolute; diff --git a/res/css/views/settings/tabs/user/_SidebarUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_SidebarUserSettingsTab.pcss index 5bcb6b16029..cb90c0c15fa 100644 --- a/res/css/views/settings/tabs/user/_SidebarUserSettingsTab.pcss +++ b/res/css/views/settings/tabs/user/_SidebarUserSettingsTab.pcss @@ -14,67 +14,25 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_SidebarUserSettingsTab { - .mx_Checkbox { - margin-top: 12px; - font-size: $font-15px; - line-height: $font-24px; - color: $secondary-content; - } - - .mx_SidebarUserSettingsTab_checkboxMicrocopy { - margin-bottom: 12px; - margin-left: 24px; - font-size: $font-15px; - line-height: $font-24px; - color: $secondary-content; - } - - .mx_SidebarUserSettingsTab_homeAllRoomsCheckbox { - margin-left: 24px; - - & + div { - margin-left: 48px; - } - } +.mx_SidebarUserSettingsTab_homeAllRoomsCheckbox { + margin-left: 24px; - .mx_SidebarUserSettingsTab_homeCheckbox, - .mx_SidebarUserSettingsTab_favouritesCheckbox, - .mx_SidebarUserSettingsTab_peopleCheckbox, - .mx_SidebarUserSettingsTab_orphansCheckbox { - .mx_Checkbox_background + div { - padding-left: 20px; - position: relative; - - &::before { - background-color: $secondary-content; - content: ""; - mask-repeat: no-repeat; - mask-position: center; - mask-size: contain; - width: 16px; - height: 16px; - position: absolute; - left: 0; - top: 50%; - transform: translateY(-50%); - } - } - } - - .mx_SidebarUserSettingsTab_homeCheckbox .mx_Checkbox_background + div::before { - mask-image: url("$(res)/img/element-icons/home.svg"); - } - - .mx_SidebarUserSettingsTab_favouritesCheckbox .mx_Checkbox_background + div::before { - mask-image: url("$(res)/img/element-icons/roomlist/favorite.svg"); + & + div { + margin-left: 48px; } +} - .mx_SidebarUserSettingsTab_peopleCheckbox .mx_Checkbox_background + div::before { - mask-image: url("$(res)/img/element-icons/room/members.svg"); +.mx_SidebarUserSettingsTab_checkbox { + margin-bottom: $spacing-8; + // override checkbox stylesĖš + label { + align-items: flex-start !important; } - .mx_SidebarUserSettingsTab_orphansCheckbox .mx_Checkbox_background + div::before { - mask-image: url("$(res)/img/element-icons/roomlist/hash-circle.svg"); + svg { + height: 16px; + width: 16px; + margin-right: $spacing-8; + margin-bottom: -1px; } } diff --git a/res/css/views/settings/tabs/user/_VoiceUserSettingsTab.pcss b/res/css/views/settings/tabs/user/_VoiceUserSettingsTab.pcss deleted file mode 100644 index 138ca6f9de3..00000000000 --- a/res/css/views/settings/tabs/user/_VoiceUserSettingsTab.pcss +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2019 New Vector Ltd - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -.mx_VoiceUserSettingsTab .mx_Field { - margin-inline-end: var(--SettingsTab_fullWidthField-margin-inline-end); -} - -.mx_VoiceUserSettingsTab_missingMediaPermissions { - margin-bottom: 15px; -} diff --git a/res/img/element-icons/home.svg b/res/img/element-icons/home.svg index 9ca0b827162..ae5aceaec2b 100644 --- a/res/img/element-icons/home.svg +++ b/res/img/element-icons/home.svg @@ -1,3 +1,3 @@ - + diff --git a/res/img/element-icons/room/members.svg b/res/img/element-icons/room/members.svg index 03aba81ad49..50aa0aa466c 100644 --- a/res/img/element-icons/room/members.svg +++ b/res/img/element-icons/room/members.svg @@ -2,6 +2,6 @@ - - + + diff --git a/res/img/element-icons/roomlist/favorite.svg b/res/img/element-icons/roomlist/favorite.svg index 0c33999ea3d..c601b698085 100644 --- a/res/img/element-icons/roomlist/favorite.svg +++ b/res/img/element-icons/roomlist/favorite.svg @@ -1,3 +1,3 @@ - + diff --git a/res/img/element-icons/roomlist/hash-circle.svg b/res/img/element-icons/roomlist/hash-circle.svg index 924b22cf329..a6bf54fb235 100644 --- a/res/img/element-icons/roomlist/hash-circle.svg +++ b/res/img/element-icons/roomlist/hash-circle.svg @@ -2,6 +2,6 @@ - - + + diff --git a/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx b/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx index 1a11e0d5a2a..3ff7afdf49d 100644 --- a/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/SidebarUserSettingsTab.tsx @@ -1,5 +1,5 @@ /* -Copyright 2021 - 2022 The Matrix.org Foundation C.I.C. +Copyright 2021 - 2023 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -16,6 +16,10 @@ limitations under the License. import React, { ChangeEvent } from "react"; +import { Icon as HomeIcon } from "../../../../../../res/img/element-icons/home.svg"; +import { Icon as FavoriteIcon } from "../../../../../../res/img/element-icons/roomlist/favorite.svg"; +import { Icon as MembersIcon } from "../../../../../../res/img/element-icons/room/members.svg"; +import { Icon as HashCircleIcon } from "../../../../../../res/img/element-icons/roomlist/hash-circle.svg"; import { _t } from "../../../../../languageHandler"; import SettingsStore from "../../../../../settings/SettingsStore"; import { SettingLevel } from "../../../../../settings/SettingLevel"; @@ -23,6 +27,9 @@ import StyledCheckbox from "../../../elements/StyledCheckbox"; import { useSettingValue } from "../../../../../hooks/useSettings"; import { MetaSpace } from "../../../../../stores/spaces"; import PosthogTrackers from "../../../../../PosthogTrackers"; +import SettingsTab from "../SettingsTab"; +import { SettingsSection } from "../../shared/SettingsSection"; +import SettingsSubsection, { SettingsSubsectionText } from "../../shared/SettingsSubsection"; type InteractionName = "WebSettingsSidebarTabSpacesCheckbox" | "WebQuickSettingsPinToSidebarCheckbox"; @@ -50,79 +57,91 @@ const SidebarUserSettingsTab: React.FC = () => { } = useSettingValue>("Spaces.enabledMetaSpaces"); const allRoomsInHome = useSettingValue("Spaces.allRoomsInHome"); + const onAllRoomsInHomeToggle = async (event: ChangeEvent): Promise => { + await SettingsStore.setValue("Spaces.allRoomsInHome", null, SettingLevel.ACCOUNT, event.target.checked); + PosthogTrackers.trackInteraction("WebSettingsSidebarTabSpacesCheckbox", event, 1); + }; + return ( -
-
{_t("Sidebar")}
-
-
{_t("Spaces to show")}
-
- {_t( + + + - - - {_t("Home")} - -
- {_t("Home is useful for getting an overview of everything.")} -
- - { - SettingsStore.setValue("Spaces.allRoomsInHome", null, SettingLevel.ACCOUNT, e.target.checked); - PosthogTrackers.trackInteraction("WebSettingsSidebarTabSpacesCheckbox", e, 1); - }} - className="mx_SidebarUserSettingsTab_homeAllRoomsCheckbox" - > - {_t("Show all rooms")} - -
- {_t("Show all your rooms in Home, even if they're in a space.")} -
- - - {_t("Favourites")} - -
- {_t("Group all your favourite rooms and people in one place.")} -
- - - {_t("People")} - -
- {_t("Group all your people in one place.")} -
- - - {_t("Rooms outside of a space")} - -
- {_t("Group all your rooms that aren't part of a space in one place.")} -
-
-
+ + + + {_t("Home")} + + + {_t("Home is useful for getting an overview of everything.")} + + + + + {_t("Show all rooms")} + + {_t("Show all your rooms in Home, even if they're in a space.")} + + + + + + + {_t("Favourites")} + + + {_t("Group all your favourite rooms and people in one place.")} + + + + + + + {_t("People")} + + {_t("Group all your people in one place.")} + + + + + + {_t("Rooms outside of a space")} + + + {_t("Group all your rooms that aren't part of a space in one place.")} + + + + + ); }; diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx index ada24bdf271..28218174664 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.tsx @@ -26,6 +26,9 @@ import { SettingLevel } from "../../../../../settings/SettingLevel"; import SettingsFlag from "../../../elements/SettingsFlag"; import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch"; import { requestMediaPermissions } from "../../../../../utils/media/requestMediaPermissions"; +import SettingsTab from "../SettingsTab"; +import { SettingsSection } from "../../shared/SettingsSection"; +import SettingsSubsection from "../../shared/SettingsSubsection"; interface IState { mediaDevices: IMediaDevices | null; @@ -128,7 +131,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { let webcamDropdown: ReactNode | undefined; if (!this.state.mediaDevices) { requestButton = ( -
+

{_t("Missing media permissions, click the button below to request.")}

{_t("Request media permissions")} @@ -148,33 +151,30 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { } return ( -
-
{_t("Voice & Video")}
- {requestButton} -
- {_t("Voice settings")} - {speakerDropdown} - {microphoneDropdown} - => { - await MediaDeviceHandler.setAudioAutoGainControl(v); - this.setState({ audioAutoGainControl: MediaDeviceHandler.getAudioAutoGainControl() }); - }} - label={_t("Automatically adjust the microphone volume")} - data-testid="voice-auto-gain" - /> -
-
- {_t("Video settings")} - {webcamDropdown} - -
- -
{_t("Advanced")}
-
- {_t("Voice processing")} -
+ + + {requestButton} + + {speakerDropdown} + {microphoneDropdown} + => { + await MediaDeviceHandler.setAudioAutoGainControl(v); + this.setState({ audioAutoGainControl: MediaDeviceHandler.getAudioAutoGainControl() }); + }} + label={_t("Automatically adjust the microphone volume")} + data-testid="voice-auto-gain" + /> + + + {webcamDropdown} + + + + + + => { @@ -193,9 +193,8 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> { label={_t("Echo cancellation")} data-testid="voice-echo-cancellation" /> -
-
- {_t("Connection")} + + { level={SettingLevel.DEVICE} onChange={this.changeFallbackICEServerAllowed} /> -
-
-
+ + + ); } } diff --git a/test/components/views/settings/tabs/user/SidebarUserSettingsTab-test.tsx b/test/components/views/settings/tabs/user/SidebarUserSettingsTab-test.tsx new file mode 100644 index 00000000000..fc0c2a12643 --- /dev/null +++ b/test/components/views/settings/tabs/user/SidebarUserSettingsTab-test.tsx @@ -0,0 +1,88 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { fireEvent, render, screen } from "@testing-library/react"; + +import SidebarUserSettingsTab from "../../../../../../src/components/views/settings/tabs/user/SidebarUserSettingsTab"; +import PosthogTrackers from "../../../../../../src/PosthogTrackers"; +import SettingsStore from "../../../../../../src/settings/SettingsStore"; +import { MetaSpace } from "../../../../../../src/stores/spaces"; +import { SettingLevel } from "../../../../../../src/settings/SettingLevel"; +import { flushPromises } from "../../../../../test-utils"; + +// used by checkbox to relate labels to inputs +// make it stable for snapshot testing +jest.mock("matrix-js-sdk/src/randomstring", () => ({ + randomString: jest.fn().mockReturnValue("abcd"), +})); + +describe("", () => { + beforeEach(() => { + jest.spyOn(PosthogTrackers, "trackInteraction").mockClear(); + jest.spyOn(SettingsStore, "getValue").mockRestore(); + jest.spyOn(SettingsStore, "setValue").mockReset(); + }); + + it("renders sidebar settings", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it("toggles all rooms in home setting", async () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => { + if (settingName === "Spaces.enabledMetaSpaces") { + return { + [MetaSpace.Home]: true, + [MetaSpace.Favourites]: true, + [MetaSpace.People]: true, + [MetaSpace.Orphans]: true, + }; + } + return false; + }); + render(); + + fireEvent.click(screen.getByTestId("mx_SidebarUserSettingsTab_homeAllRoomsCheckbox")); + + await flushPromises(); + expect(SettingsStore.setValue).toHaveBeenCalledWith("Spaces.allRoomsInHome", null, SettingLevel.ACCOUNT, true); + + expect(PosthogTrackers.trackInteraction).toHaveBeenCalledWith( + "WebSettingsSidebarTabSpacesCheckbox", + // synthetic event from checkbox + expect.objectContaining({ type: "change" }), + 1, + ); + }); + + it("disables all rooms in home setting when home space is disabled", () => { + jest.spyOn(SettingsStore, "getValue").mockImplementation((settingName) => { + if (settingName === "Spaces.enabledMetaSpaces") { + return { + [MetaSpace.Home]: false, + [MetaSpace.Favourites]: true, + [MetaSpace.People]: true, + [MetaSpace.Orphans]: true, + }; + } + return false; + }); + render(); + + expect(screen.getByTestId("mx_SidebarUserSettingsTab_homeAllRoomsCheckbox")).toBeDisabled(); + }); +}); diff --git a/test/components/views/settings/tabs/user/__snapshots__/SidebarUserSettingsTab-test.tsx.snap b/test/components/views/settings/tabs/user/__snapshots__/SidebarUserSettingsTab-test.tsx.snap new file mode 100644 index 00000000000..c1933d6dcad --- /dev/null +++ b/test/components/views/settings/tabs/user/__snapshots__/SidebarUserSettingsTab-test.tsx.snap @@ -0,0 +1,215 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[` renders sidebar settings 1`] = ` +
+
+
+
+

+ Sidebar +

+
+
+
+

+ Spaces to show +

+
+
+
+ Spaces are ways to group rooms and people. Alongside the spaces you're in, you can use some pre-built ones too. +
+
+
+ + +