Skip to content

Commit

Permalink
Refactor settings to use observables
Browse files Browse the repository at this point in the history
Also removing some unused settings along the way.
  • Loading branch information
robintown committed Jun 7, 2024
1 parent dfc1111 commit c6cb839
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 180 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"matrix-js-sdk": "github:matrix-org/matrix-js-sdk#e874468ba3e84819cf4b342d2e66af67ab4cf804",
"matrix-widget-api": "^1.3.1",
"normalize.css": "^8.0.1",
"observable-hooks": "^4.2.3",
"pako": "^2.0.4",
"postcss-preset-env": "^9.0.0",
"posthog-js": "^1.29.0",
Expand Down
1 change: 0 additions & 1 deletion public/locales/en-GB/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@
"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.",
"show_connection_stats_label": "Show connection stats",
"speaker_device_selection_label": "Speaker"
},
"star_rating_input_label_one": "{{count}} stars",
Expand Down
31 changes: 10 additions & 21 deletions src/analytics/PosthogAnalytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { MatrixClient } from "matrix-js-sdk";
import { Buffer } from "buffer";

import { widget } from "../widget";
import { getSetting, setSetting, getSettingKey } from "../settings/useSetting";
import {
CallEndedTracker,
CallStartedTracker,
Expand All @@ -35,7 +34,7 @@ import {
} from "./PosthogEvents";
import { Config } from "../config/Config";
import { getUrlParams } from "../UrlParams";
import { localStorageBus } from "../useLocalStorage";
import { optInAnalytics } from "../settings/settings";

/* Posthog analytics tracking.
*
Expand Down Expand Up @@ -131,7 +130,7 @@ export class PosthogAnalytics {
const { analyticsID } = getUrlParams();
// if the embedding platform (element web) already got approval to communicating with posthog
// element call can also send events to posthog
setSetting("opt-in-analytics", Boolean(analyticsID));
optInAnalytics.setValue(Boolean(analyticsID));
}

this.posthog.init(posthogConfig.project_api_key, {
Expand All @@ -151,9 +150,7 @@ export class PosthogAnalytics {
);
this.enabled = false;
}
this.startListeningToSettingsChanges();
const optInAnalytics = getSetting("opt-in-analytics", false);
this.updateAnonymityAndIdentifyUser(optInAnalytics);
this.startListeningToSettingsChanges(); // Triggers maybeIdentifyUser
}

private sanitizeProperties = (
Expand Down Expand Up @@ -336,8 +333,7 @@ export class PosthogAnalytics {
}

public onLoginStatusChanged(): void {
const optInAnalytics = getSetting("opt-in-analytics", false);
this.updateAnonymityAndIdentifyUser(optInAnalytics);
this.maybeIdentifyUser();
}

private updateSuperProperties(): void {
Expand All @@ -360,20 +356,12 @@ export class PosthogAnalytics {
return this.eventSignup.getSignupEndTime() > new Date(0);
}

private async updateAnonymityAndIdentifyUser(
pseudonymousOptIn: boolean,
): Promise<void> {
// Update this.anonymity based on the user's analytics opt-in settings
const anonymity = pseudonymousOptIn
? Anonymity.Pseudonymous
: Anonymity.Disabled;
this.setAnonymity(anonymity);

private async maybeIdentifyUser(): Promise<void> {
// We may not yet have a Matrix client at this point, if not, bail. This should get
// triggered again by onLoginStatusChanged once we do have a client.
if (!window.matrixclient) return;

if (anonymity === Anonymity.Pseudonymous) {
if (this.anonymity === Anonymity.Pseudonymous) {
this.setRegistrationType(
window.matrixclient.isGuest() || window.passwordlessUser
? RegistrationType.Guest
Expand All @@ -389,7 +377,7 @@ export class PosthogAnalytics {
}
}

if (anonymity !== Anonymity.Disabled) {
if (this.anonymity !== Anonymity.Disabled) {
this.updateSuperProperties();
}
}
Expand Down Expand Up @@ -419,8 +407,9 @@ export class PosthogAnalytics {
// * When the user changes their preferences on this device
// Note that for new accounts, pseudonymousAnalyticsOptIn won't be set, so updateAnonymityFromSettings
// won't be called (i.e. this.anonymity will be left as the default, until the setting changes)
localStorageBus.on(getSettingKey("opt-in-analytics"), (optInAnalytics) => {
this.updateAnonymityAndIdentifyUser(optInAnalytics);
optInAnalytics.value.subscribe((optIn) => {
this.setAnonymity(optIn ? Anonymity.Pseudonymous : Anonymity.Disabled);
this.maybeIdentifyUser();
});
}

Expand Down
7 changes: 5 additions & 2 deletions src/home/RegisteredView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ import { UserMenuContainer } from "../UserMenuContainer";
import { JoinExistingCallModal } from "./JoinExistingCallModal";
import { Caption } from "../typography/Typography";
import { Form } from "../form/Form";
import { useOptInAnalytics } from "../settings/useSetting";
import { AnalyticsNotice } from "../analytics/AnalyticsNotice";
import { E2eeType } from "../e2ee/e2eeType";
import {
useSetting,
optInAnalytics as optInAnalyticsSetting,
} from "../settings/settings";

interface Props {
client: MatrixClient;
Expand All @@ -49,7 +52,7 @@ interface Props {
export const RegisteredView: FC<Props> = ({ client }) => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error>();
const [optInAnalytics] = useOptInAnalytics();
const [optInAnalytics] = useSetting(optInAnalyticsSetting);
const history = useHistory();
const { t } = useTranslation();
const [joinExistingCallModalOpen, setJoinExistingCallModalOpen] =
Expand Down
7 changes: 5 additions & 2 deletions src/home/UnauthenticatedView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,18 @@ import styles from "./UnauthenticatedView.module.css";
import commonStyles from "./common.module.css";
import { generateRandomName } from "../auth/generateRandomName";
import { AnalyticsNotice } from "../analytics/AnalyticsNotice";
import { useOptInAnalytics } from "../settings/useSetting";
import { Config } from "../config/Config";
import { E2eeType } from "../e2ee/e2eeType";
import {
useSetting,
optInAnalytics as optInAnalyticsSetting,
} from "../settings/settings";

export const UnauthenticatedView: FC = () => {
const { setClient } = useClient();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<Error>();
const [optInAnalytics] = useOptInAnalytics();
const [optInAnalytics] = useSetting(optInAnalyticsSetting);
const { recaptchaKey, register } = useInteractiveRegistration();
const { execute, reset, recaptchaId } = useRecaptcha(recaptchaKey);

Expand Down
42 changes: 18 additions & 24 deletions src/livekit/MediaDevicesContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ import { Observable } from "rxjs";
import { logger } from "matrix-js-sdk/src/logger";

import {
useSetting,
audioInput as audioInputSetting,
audioOutput as audioOutputSetting,
videoInput as videoInputSetting,
isFirefox,
useAudioInput,
useAudioOutput,
useVideoInput,
} from "../settings/useSetting";
} from "../settings/settings";

export interface MediaDevice {
available: MediaDeviceInfo[];
Expand Down Expand Up @@ -145,43 +146,36 @@ export const MediaDevicesProvider: FC<Props> = ({ children }) => {
// for ouput devices because the selector wont be shown on FF.
const useOutputNames = usingNames && !isFirefox();

const [audioInputSetting, setAudioInputSetting] = useAudioInput();
const [audioOutputSetting, setAudioOutputSetting] = useAudioOutput();
const [videoInputSetting, setVideoInputSetting] = useVideoInput();
const [storedAudioInput, setStoredAudioInput] = useSetting(audioInputSetting);
const [storedAudioOutput, setStoredAudioOutput] =
useSetting(audioOutputSetting);
const [storedVideoInput, setStoredVideoInput] = useSetting(videoInputSetting);

const audioInput = useMediaDevice(
"audioinput",
audioInputSetting,
usingNames,
);
const audioInput = useMediaDevice("audioinput", storedAudioInput, usingNames);
const audioOutput = useMediaDevice(
"audiooutput",
audioOutputSetting,
storedAudioOutput,
useOutputNames,
alwaysUseDefaultAudio,
);
const videoInput = useMediaDevice(
"videoinput",
videoInputSetting,
usingNames,
);
const videoInput = useMediaDevice("videoinput", storedVideoInput, usingNames);

useEffect(() => {
if (audioInput.selectedId !== undefined)
setAudioInputSetting(audioInput.selectedId);
}, [setAudioInputSetting, audioInput.selectedId]);
setStoredAudioInput(audioInput.selectedId);
}, [setStoredAudioInput, audioInput.selectedId]);

useEffect(() => {
// Skip setting state for ff output. Redundent since it is set to always return 'undefined'
// but makes it clear while debugging that this is not happening on FF. + perf ;)
if (audioOutput.selectedId !== undefined && !isFirefox())
setAudioOutputSetting(audioOutput.selectedId);
}, [setAudioOutputSetting, audioOutput.selectedId]);
setStoredAudioOutput(audioOutput.selectedId);
}, [setStoredAudioOutput, audioOutput.selectedId]);

useEffect(() => {
if (videoInput.selectedId !== undefined)
setVideoInputSetting(videoInput.selectedId);
}, [setVideoInputSetting, videoInput.selectedId]);
setStoredVideoInput(videoInput.selectedId);
}, [setStoredVideoInput, videoInput.selectedId]);

const startUsingDeviceNames = useCallback(
() => setNumCallersUsingNames((n) => n + 1),
Expand Down
7 changes: 5 additions & 2 deletions src/room/RoomPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { GroupCallLoader } from "./GroupCallLoader";
import { GroupCallView } from "./GroupCallView";
import { useRoomIdentifier, useUrlParams } from "../UrlParams";
import { useRegisterPasswordlessUser } from "../auth/useRegisterPasswordlessUser";
import { useOptInAnalytics } from "../settings/useSetting";
import { HomePage } from "../home/HomePage";
import { platform } from "../Platform";
import { AppSelectionModal } from "./AppSelectionModal";
Expand All @@ -36,6 +35,10 @@ import { LobbyView } from "./LobbyView";
import { E2eeType } from "../e2ee/e2eeType";
import { useProfile } from "../profile/useProfile";
import { useMuteStates } from "./MuteStates";
import {
useSetting,
optInAnalytics as optInAnalyticsSetting,
} from "../settings/settings";

export const RoomPage: FC = () => {
const {
Expand Down Expand Up @@ -80,7 +83,7 @@ export const RoomPage: FC = () => {
registerPasswordlessUser,
]);

const [optInAnalytics, setOptInAnalytics] = useOptInAnalytics();
const [optInAnalytics, setOptInAnalytics] = useSetting(optInAnalyticsSetting);
useEffect(() => {
// During the beta, opt into analytics by default
if (optInAnalytics === null && setOptInAnalytics) setOptInAnalytics(true);
Expand Down
33 changes: 10 additions & 23 deletions src/settings/SettingsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ import OverflowIcon from "../icons/Overflow.svg?react";
import UserIcon from "../icons/User.svg?react";
import FeedbackIcon from "../icons/Feedback.svg?react";
import { SelectInput } from "../input/SelectInput";
import {
useOptInAnalytics,
useDeveloperSettingsTab,
useShowConnectionStats,
isFirefox,
} from "./useSetting";
import { FieldRow, InputField } from "../input/Input";
import { Body, Caption } from "../typography/Typography";
import { AnalyticsNotice } from "../analytics/AnalyticsNotice";
Expand All @@ -46,6 +40,12 @@ import {
useMediaDeviceNames,
} from "../livekit/MediaDevicesContext";
import { widget } from "../widget";
import {
useSetting,
optInAnalytics as optInAnalyticsSetting,
developerSettingsTab as developerSettingsTabSetting,
isFirefox,
} from "./settings";

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

const [optInAnalytics, setOptInAnalytics] = useOptInAnalytics();
const [developerSettingsTab, setDeveloperSettingsTab] =
useDeveloperSettingsTab();
const [showConnectionStats, setShowConnectionStats] =
useShowConnectionStats();
const [optInAnalytics, setOptInAnalytics] = useSetting(optInAnalyticsSetting);
const [developerSettingsTab, setDeveloperSettingsTab] = useSetting(
developerSettingsTabSetting,
);

// Generate a `SelectInput` with a list of devices for a given device kind.
const generateDeviceSelection = (
Expand Down Expand Up @@ -245,18 +244,6 @@ export const SettingsModal: FC<Props> = ({
})}
</Body>
</FieldRow>
<FieldRow>
<InputField
id="showConnectionStats"
name="connection-stats"
label={t("settings.show_connection_stats_label")}
type="checkbox"
checked={showConnectionStats}
onChange={(e: ChangeEvent<HTMLInputElement>): void =>
setShowConnectionStats(e.target.checked)
}
/>
</FieldRow>
</TabItem>
);

Expand Down
Loading

0 comments on commit c6cb839

Please sign in to comment.