"@typescript-eslint/no-unused-vars": "error",
"@typescript-eslint/no-shadow": "error"
},
+ overrides: [
+ {
+ files: ['*.ts'],
+ rules: {
+ 'no-undef': 'off',
+ },
+ },
+ ],
};
+++ /dev/null
-/* eslint-disable import/prefer-default-export */
-
-import { useEffect, useState } from 'react';
-
-export function usePermission(name, initial) {
- const [state, setState] = useState(initial);
-
- useEffect(() => {
- let descriptor;
-
- const update = () => setState(descriptor.state);
-
- if (navigator.permissions?.query) {
- navigator.permissions.query({ name }).then((_descriptor) => {
- descriptor = _descriptor;
-
- update();
- descriptor.addEventListener('change', update);
- });
- }
-
- return () => {
- if (descriptor) descriptor.removeEventListener('change', update);
- };
- }, []);
-
- return [state, setState];
-}
--- /dev/null
+import { useEffect, useState } from "react";
+
+export function usePermissionState(name: PermissionName, initialValue: PermissionState = 'prompt') {
+ const [permissionState, setPermissionState] = useState<PermissionState>(initialValue);
+
+ useEffect(() => {
+ let permissionStatus: PermissionStatus;
+
+ function handlePermissionChange(this: PermissionStatus) {
+ setPermissionState(this.state);
+ }
+
+ navigator.permissions
+ .query({ name })
+ .then((permStatus: PermissionStatus) => {
+ permissionStatus = permStatus;
+ handlePermissionChange.apply(permStatus);
+ permStatus.addEventListener("change", handlePermissionChange);
+ })
+ .catch(() => {
+ // Silence error since FF doesn't support microphone permission
+ });
+
+ return () => {
+ permissionStatus?.removeEventListener("change", handlePermissionChange);
+ };
+ }, [name]);
+
+ return permissionState;
+}
\ No newline at end of file
import navigation from '../../../client/state/navigation';
import {
toggleSystemTheme,
- toggleNotifications, toggleNotificationSounds,
} from '../../../client/action/settings';
-import { usePermission } from '../../hooks/usePermission';
+import { usePermissionState } from '../../hooks/usePermission';
import Text from '../../atoms/text/Text';
import IconButton from '../../atoms/button/IconButton';
}
function NotificationsSection() {
- const [permission, setPermission] = usePermission('notifications', window.Notification?.permission);
-
- const [, updateState] = useState({});
+ const notifPermission = usePermissionState('notifications', window.Notification?.permission ?? "denied");
+ const [showNotifications, setShowNotifications] = useSetting(settingsAtom, 'showNotifications')
+ const [isNotificationSounds, setIsNotificationSounds] = useSetting(settingsAtom, 'isNotificationSounds')
const renderOptions = () => {
if (window.Notification === undefined) {
return <Text className="settings-notifications__not-supported">Not supported in this browser.</Text>;
}
- if (permission === 'granted') {
+ if (notifPermission === 'denied') {
+ return <Text>Permission Denied</Text>
+ }
+
+ if (notifPermission === 'granted') {
return (
<Toggle
- isActive={settings._showNotifications}
+ isActive={showNotifications}
onToggle={() => {
- toggleNotifications();
- setPermission(window.Notification?.permission);
- updateState({});
+ setShowNotifications(!showNotifications);
}}
/>
);
return (
<Button
variant="primary"
- onClick={() => window.Notification.requestPermission().then(setPermission)}
+ onClick={() => window.Notification.requestPermission().then(() => {
+ setShowNotifications(window.Notification?.permission === 'granted');
+ })}
>
Request permission
</Button>
title="Notification Sound"
options={(
<Toggle
- isActive={settings.isNotificationSounds}
- onToggle={() => { toggleNotificationSounds(); updateState({}); }}
+ isActive={isNotificationSounds}
+ onToggle={() => setIsNotificationSounds(!isNotificationSounds)}
/>
)}
content={<Text variant="b3">Play sound when new messages arrive.</Text>}
const mx = useMatrixClient();
const navigate = useNavigate();
+ const [showNotifications] = useSetting(settingsAtom, 'showNotifications');
const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds');
const notify = useCallback(
useEffect(() => {
if (invites.length > perviousInviteLen && mx.getSyncState() === 'SYNCING') {
- if (Notification.permission === 'granted') {
+ if (showNotifications && Notification.permission === 'granted') {
notify(invites.length - perviousInviteLen);
}
playSound();
}
}
- }, [mx, invites, perviousInviteLen, notificationSound, notify, playSound]);
+ }, [mx, invites, perviousInviteLen, showNotifications, notificationSound, notify, playSound]);
return (
// eslint-disable-next-line jsx-a11y/media-has-caption
useSyncState(
mx,
useCallback(
- (state) => {
- if (state === SyncState.Prepared) {
+ (state, prevState) => {
+ if (
+ (state === SyncState.Prepared && prevState === null) ||
+ (state === SyncState.Syncing && prevState !== SyncState.Syncing)
+ ) {
setUnreadAtom({
type: 'RESET',
unreadInfos: getUnreadInfos(mx),
type: cons.actions.settings.TOGGLE_NICKAVATAR_EVENT,
});
}
-
-export function toggleNotifications() {
- appDispatcher.dispatch({
- type: cons.actions.settings.TOGGLE_NOTIFICATIONS,
- });
-}
-
-export function toggleNotificationSounds() {
- appDispatcher.dispatch({
- type: cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS,
- });
-}
TOGGLE_PEOPLE_DRAWER: 'TOGGLE_PEOPLE_DRAWER',
TOGGLE_MEMBERSHIP_EVENT: 'TOGGLE_MEMBERSHIP_EVENT',
TOGGLE_NICKAVATAR_EVENT: 'TOGGLE_NICKAVATAR_EVENT',
- TOGGLE_NOTIFICATIONS: 'TOGGLE_NOTIFICATIONS',
- TOGGLE_NOTIFICATION_SOUNDS: 'TOGGLE_NOTIFICATION_SOUNDS',
},
},
events: {
PEOPLE_DRAWER_TOGGLED: 'PEOPLE_DRAWER_TOGGLED',
MEMBERSHIP_EVENTS_TOGGLED: 'MEMBERSHIP_EVENTS_TOGGLED',
NICKAVATAR_EVENTS_TOGGLED: 'NICKAVATAR_EVENTS_TOGGLED',
- NOTIFICATIONS_TOGGLED: 'NOTIFICATIONS_TOGGLED',
- NOTIFICATION_SOUNDS_TOGGLED: 'NOTIFICATION_SOUNDS_TOGGLED',
},
},
};
this.isPeopleDrawer = this.getIsPeopleDrawer();
this.hideMembershipEvents = this.getHideMembershipEvents();
this.hideNickAvatarEvents = this.getHideNickAvatarEvents();
- this._showNotifications = this.getShowNotifications();
- this.isNotificationSounds = this.getIsNotificationSounds();
this.darkModeQueryList = window.matchMedia('(prefers-color-scheme: dark)');
return settings.isPeopleDrawer;
}
- get showNotifications() {
- if (window.Notification?.permission !== 'granted') return false;
- return this._showNotifications;
- }
-
- getShowNotifications() {
- if (typeof this._showNotifications === 'boolean') return this._showNotifications;
-
- const settings = getSettings();
- if (settings === null) return true;
- if (typeof settings.showNotifications === 'undefined') return true;
- return settings.showNotifications;
- }
-
- getIsNotificationSounds() {
- if (typeof this.isNotificationSounds === 'boolean') return this.isNotificationSounds;
-
- const settings = getSettings();
- if (settings === null) return true;
- if (typeof settings.isNotificationSounds === 'undefined') return true;
- return settings.isNotificationSounds;
- }
-
setter(action) {
const actions = {
[cons.actions.settings.TOGGLE_SYSTEM_THEME]: () => {
setSettings('hideNickAvatarEvents', this.hideNickAvatarEvents);
this.emit(cons.events.settings.NICKAVATAR_EVENTS_TOGGLED, this.hideNickAvatarEvents);
},
- [cons.actions.settings.TOGGLE_NOTIFICATIONS]: async () => {
- if (window.Notification?.permission !== 'granted') {
- this._showNotifications = false;
- } else {
- this._showNotifications = !this._showNotifications;
- }
- setSettings('showNotifications', this._showNotifications);
- this.emit(cons.events.settings.NOTIFICATIONS_TOGGLED, this._showNotifications);
- },
- [cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS]: () => {
- this.isNotificationSounds = !this.isNotificationSounds;
- setSettings('isNotificationSounds', this.isNotificationSounds);
- this.emit(cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED, this.isNotificationSounds);
- },
};
actions[action.type]?.();