Skip to content

Commit

Permalink
Simplify settings tabs (#2875)
Browse files Browse the repository at this point in the history
* Simplify settings tabs

- Move Analytics to Feedback tab
- Rename Developer Settings to Developer Mode and move to Preferences tab
- Clean up Preferences tab
- Only way to see version number is by enabling Developer Mode

* Remove extra label

* Lint

* Lint

* Update locales/en/app.json

Co-authored-by: Robin <[email protected]>

---------

Co-authored-by: Robin <[email protected]>
  • Loading branch information
hughns and robintown authored Dec 11, 2024
1 parent 0087e37 commit 54149a4
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 127 deletions.
11 changes: 4 additions & 7 deletions locales/en/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,27 +150,24 @@
"effect_volume_description": "Adjust the volume at which reactions and hand raised effects play.",
"effect_volume_label": "Sound effect volume"
},
"developer_settings_label": "Developer Settings",
"developer_settings_label_description": "Expose developer settings in the settings window.",
"developer_tab_title": "Developer",
"feedback_tab_body": "If you are experiencing issues or simply would like to provide some feedback, please send us a short description below.",
"feedback_tab_description_label": "Your feedback",
"feedback_tab_h4": "Submit feedback",
"feedback_tab_send_logs_label": "Include debug logs",
"feedback_tab_thank_you": "Thanks, we received your feedback!",
"feedback_tab_title": "Feedback",
"more_tab_title": "More",
"opt_in_description": "<0></0><1></1>You may withdraw consent by unchecking this box. If you are currently in a call, this setting will take effect at the end of the call.",
"preferences_tab": {
"developer_mode_label": "Developer mode",
"developer_mode_label_description": "Enable developer mode and show developer settings tab.",
"reactions_play_sound_description": "Play a sound effect when anyone sends a reaction into a call.",
"reactions_play_sound_label": "Play reaction sounds",
"reactions_show_description": "Show an animation when anyone sends a reaction.",
"reactions_show_label": "Show reactions",
"reactions_title": "Reactions"
"reactions_show_label": "Show reactions"
},
"preferences_tab_body": "Here you can configure extra options for an improved experience.",
"preferences_tab_h4": "Preferences",
"preferences_tab_show_hand_raised_timer_description": "Show a timer when a participant raises their hand.",
"preferences_tab_show_hand_raised_timer_description": "Show a timer when a participant raises their hand",
"preferences_tab_show_hand_raised_timer_label": "Show hand raise duration",
"speaker_device_selection_label": "Speaker"
},
Expand Down
75 changes: 75 additions & 0 deletions src/settings/DeveloperSettingsTab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright 2022-2024 New Vector Ltd.
SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/

import { type ChangeEvent, type FC, useCallback } from "react";
import { useTranslation } from "react-i18next";

import { FieldRow, InputField } from "../input/Input";
import {
useSetting,
duplicateTiles as duplicateTilesSetting,
} from "./settings";
import type { MatrixClient } from "matrix-js-sdk/src/client";

interface Props {
client: MatrixClient;
}

export const DeveloperSettingsTab: FC<Props> = ({ client }) => {
const { t } = useTranslation();
const [duplicateTiles, setDuplicateTiles] = useSetting(duplicateTilesSetting);

return (
<>
<p>
{t("developer_mode.hostname", {
hostname: window.location.hostname || "unknown",
})}
</p>
<p>
{t("version", {
productName: import.meta.env.VITE_PRODUCT_NAME || "Element Call",
version: import.meta.env.VITE_APP_VERSION || "dev",
})}
</p>
<p>
{t("developer_mode.crypto_version", {
version: client.getCrypto()?.getVersion() || "unknown",
})}
</p>
<p>
{t("developer_mode.matrix_id", {
id: client.getUserId() || "unknown",
})}
</p>
<p>
{t("developer_mode.device_id", {
id: client.getDeviceId() || "unknown",
})}
</p>
<FieldRow>
<InputField
id="duplicateTiles"
type="number"
label={t("developer_mode.duplicate_tiles_label")}
value={duplicateTiles.toString()}
min={0}
onChange={useCallback(
(event: ChangeEvent<HTMLInputElement>): void => {
const value = event.target.valueAsNumber;
if (value < 0) {
return;
}
setDuplicateTiles(Number.isNaN(value) ? 0 : value);
},
[setDuplicateTiles],
)}
/>
</FieldRow>
</>
);
};
30 changes: 28 additions & 2 deletions src/settings/FeedbackSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,17 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/

import { type FC, useCallback } from "react";
import { type ChangeEvent, type FC, useCallback } from "react";
import { randomString } from "matrix-js-sdk/src/randomstring";
import { useTranslation } from "react-i18next";
import { Trans, useTranslation } from "react-i18next";
import { Button, Text } from "@vector-im/compound-web";
import { logger } from "matrix-js-sdk/src/logger";

import { FieldRow, InputField, ErrorMessage } from "../input/Input";
import { useSubmitRageshake, useRageshakeRequest } from "./submit-rageshake";
import feedbackStyles from "../input/FeedbackInput.module.css";
import { AnalyticsNotice } from "../analytics/AnalyticsNotice";
import { useOptInAnalytics } from "./settings";

interface Props {
roomId?: string;
Expand Down Expand Up @@ -52,8 +54,32 @@ export const FeedbackSettingsTab: FC<Props> = ({ roomId }) => {
[submitRageshake, roomId, sendRageshakeRequest],
);

const [optInAnalytics, setOptInAnalytics] = useOptInAnalytics();
const optInDescription = (
<Text size="sm">
<Trans i18nKey="settings.opt_in_description">
<AnalyticsNotice />
<br />
You may withdraw consent by unchecking this box. If you are currently in
a call, this setting will take effect at the end of the call.
</Trans>
</Text>
);

return (
<div>
<h4>{t("common.analytics")}</h4>
<FieldRow>
<InputField
id="optInAnalytics"
type="checkbox"
checked={optInAnalytics ?? undefined}
description={optInDescription}
onChange={(event: ChangeEvent<HTMLInputElement>): void => {
setOptInAnalytics?.(event.target.checked);
}}
/>
</FieldRow>
<h4>{t("settings.feedback_tab_h4")}</h4>
<Text>{t("settings.feedback_tab_body")}</Text>
<form onSubmit={onSubmitFeedback}>
Expand Down
21 changes: 19 additions & 2 deletions src/settings/PreferencesSettingsTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
showHandRaisedTimer as showHandRaisedTimerSetting,
showReactions as showReactionsSetting,
playReactionsSound as playReactionsSoundSetting,
developerSettingsTab as developerSettingsTabSetting,
useSetting,
} from "./settings";

Expand All @@ -36,9 +37,12 @@ export const PreferencesSettingsTab: FC = () => {
fn(e.target.checked);
};

const [developerSettingsTab, setDeveloperSettingsTab] = useSetting(
developerSettingsTabSetting,
);

return (
<div>
<h4>{t("settings.preferences_tab_h4")}</h4>
<Text>{t("settings.preferences_tab_body")}</Text>
<FieldRow>
<InputField
Expand All @@ -52,7 +56,6 @@ export const PreferencesSettingsTab: FC = () => {
onChange={(e) => onChangeSetting(e, setShowHandRaisedTimer)}
/>
</FieldRow>
<h5>{t("settings.preferences_tab.reactions_title")}</h5>
<FieldRow>
<InputField
id="showReactions"
Expand All @@ -75,6 +78,20 @@ export const PreferencesSettingsTab: FC = () => {
onChange={(e) => onChangeSetting(e, setPlayReactionSound)}
/>
</FieldRow>
<FieldRow>
<InputField
id="developerSettingsTab"
type="checkbox"
checked={developerSettingsTab}
label={t("settings.preferences_tab.developer_mode_label")}
description={t(
"settings.preferences_tab.developer_mode_label_description",
)}
onChange={(event: ChangeEvent<HTMLInputElement>): void =>
setDeveloperSettingsTab(event.target.checked)
}
/>
</FieldRow>
</div>
);
};
126 changes: 10 additions & 116 deletions src/settings/SettingsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@ SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
*/

import { type ChangeEvent, type FC, useCallback, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { type FC, useState } from "react";
import { useTranslation } from "react-i18next";
import { type MatrixClient } from "matrix-js-sdk/src/matrix";
import { Root as Form, Text } from "@vector-im/compound-web";
import { Root as Form } from "@vector-im/compound-web";

import { Modal } from "../Modal";
import styles from "./SettingsModal.module.css";
import { type Tab, TabContainer } from "../tabs/Tabs";
import { FieldRow, InputField } from "../input/Input";
import { AnalyticsNotice } from "../analytics/AnalyticsNotice";
import { ProfileSettingsTab } from "./ProfileSettingsTab";
import { FeedbackSettingsTab } from "./FeedbackSettingsTab";
import {
Expand All @@ -24,15 +22,14 @@ import {
import { widget } from "../widget";
import {
useSetting,
developerSettingsTab as developerSettingsTabSetting,
duplicateTiles as duplicateTilesSetting,
useOptInAnalytics,
soundEffectVolumeSetting,
developerSettingsTab,
} from "./settings";
import { isFirefox } from "../Platform";
import { PreferencesSettingsTab } from "./PreferencesSettingsTab";
import { Slider } from "../Slider";
import { DeviceSelection } from "./DeviceSelection";
import { DeveloperSettingsTab } from "./DeveloperSettingsTab";

type SettingsTab =
| "audio"
Expand Down Expand Up @@ -64,28 +61,13 @@ export const SettingsModal: FC<Props> = ({
}) => {
const { t } = useTranslation();

const [optInAnalytics, setOptInAnalytics] = useOptInAnalytics();
const [developerSettingsTab, setDeveloperSettingsTab] = useSetting(
developerSettingsTabSetting,
);
const [duplicateTiles, setDuplicateTiles] = useSetting(duplicateTilesSetting);

const optInDescription = (
<Text size="sm">
<Trans i18nKey="settings.opt_in_description">
<AnalyticsNotice />
<br />
You may withdraw consent by unchecking this box. If you are currently in
a call, this setting will take effect at the end of the call.
</Trans>
</Text>
);

const devices = useMediaDevices();
useMediaDeviceNames(devices, open);
const [soundVolume, setSoundVolume] = useSetting(soundEffectVolumeSetting);
const [soundVolumeRaw, setSoundVolumeRaw] = useState(soundVolume);

const [showDeveloperSettingsTab] = useSetting(developerSettingsTab);

const audioTab: Tab<SettingsTab> = {
key: "audio",
name: t("common.audio"),
Expand Down Expand Up @@ -151,104 +133,16 @@ export const SettingsModal: FC<Props> = ({
content: <FeedbackSettingsTab roomId={roomId} />,
};

const moreTab: Tab<SettingsTab> = {
key: "more",
name: t("settings.more_tab_title"),
content: (
<>
<h4>{t("settings.developer_tab_title")}</h4>
<p>
{t("version", {
productName: import.meta.env.VITE_PRODUCT_NAME || "Element Call",
version: import.meta.env.VITE_APP_VERSION || "dev",
})}
</p>
<FieldRow>
<InputField
id="developerSettingsTab"
type="checkbox"
checked={developerSettingsTab}
label={t("settings.developer_settings_label")}
description={t("settings.developer_settings_label_description")}
onChange={(event: ChangeEvent<HTMLInputElement>): void =>
setDeveloperSettingsTab(event.target.checked)
}
/>
</FieldRow>
<h4>{t("common.analytics")}</h4>
<FieldRow>
<InputField
id="optInAnalytics"
type="checkbox"
checked={optInAnalytics ?? undefined}
description={optInDescription}
onChange={(event: ChangeEvent<HTMLInputElement>): void => {
setOptInAnalytics?.(event.target.checked);
}}
/>
</FieldRow>
</>
),
};

const developerTab: Tab<SettingsTab> = {
key: "developer",
name: t("settings.developer_tab_title"),
content: (
<>
<p>
{t("developer_mode.hostname", {
hostname: window.location.hostname || "unknown",
})}
</p>
<p>
{t("version", {
productName: import.meta.env.VITE_PRODUCT_NAME || "Element Call",
version: import.meta.env.VITE_APP_VERSION || "dev",
})}
</p>
<p>
{t("developer_mode.crypto_version", {
version: client.getCrypto()?.getVersion() || "unknown",
})}
</p>
<p>
{t("developer_mode.matrix_id", {
id: client.getUserId() || "unknown",
})}
</p>
<p>
{t("developer_mode.device_id", {
id: client.getDeviceId() || "unknown",
})}
</p>
<FieldRow>
<InputField
id="duplicateTiles"
type="number"
label={t("developer_mode.duplicate_tiles_label")}
value={duplicateTiles.toString()}
min={0}
onChange={useCallback(
(event: ChangeEvent<HTMLInputElement>): void => {
const value = event.target.valueAsNumber;
if (value < 0) {
return;
}
setDuplicateTiles(Number.isNaN(value) ? 0 : value);
},
[setDuplicateTiles],
)}
/>
</FieldRow>
</>
),
content: <DeveloperSettingsTab client={client} />,
};

const tabs = [audioTab, videoTab];
if (widget === null) tabs.push(profileTab);
tabs.push(preferencesTab, feedbackTab, moreTab);
if (developerSettingsTab) tabs.push(developerTab);
tabs.push(preferencesTab, feedbackTab);
if (showDeveloperSettingsTab) tabs.push(developerTab);

return (
<Modal
Expand Down

0 comments on commit 54149a4

Please sign in to comment.