mirror of
				https://github.com/cinnyapp/cinny.git
				synced 2025-11-04 06:20:28 +03:00 
			
		
		
		
	Fix unread reset and notification settings (#1824)
* reset unread with client sync state change * fix notification toggle setting not working * revert formatOnSave vscode setting
This commit is contained in:
		
							parent
							
								
									e2228a18c1
								
							
						
					
					
						commit
						e6d6b0349e
					
				
					 9 changed files with 62 additions and 100 deletions
				
			
		| 
						 | 
				
			
			@ -61,4 +61,12 @@ module.exports = {
 | 
			
		|||
    "@typescript-eslint/no-unused-vars": "error",
 | 
			
		||||
    "@typescript-eslint/no-shadow": "error"
 | 
			
		||||
  },
 | 
			
		||||
  overrides: [
 | 
			
		||||
    {
 | 
			
		||||
      files: ['*.ts'],
 | 
			
		||||
      rules: {
 | 
			
		||||
        'no-undef': 'off',
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,28 +0,0 @@
 | 
			
		|||
/* 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];
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								src/app/hooks/usePermission.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/app/hooks/usePermission.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,30 @@
 | 
			
		|||
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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -7,9 +7,8 @@ import settings from '../../../client/state/settings';
 | 
			
		|||
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';
 | 
			
		||||
| 
						 | 
				
			
			@ -230,23 +229,25 @@ function AppearanceSection() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
          }}
 | 
			
		||||
        />
 | 
			
		||||
      );
 | 
			
		||||
| 
						 | 
				
			
			@ -255,7 +256,9 @@ function NotificationsSection() {
 | 
			
		|||
    return (
 | 
			
		||||
      <Button
 | 
			
		||||
        variant="primary"
 | 
			
		||||
        onClick={() => window.Notification.requestPermission().then(setPermission)}
 | 
			
		||||
        onClick={() => window.Notification.requestPermission().then(() => {
 | 
			
		||||
          setShowNotifications(window.Notification?.permission === 'granted');
 | 
			
		||||
        })}
 | 
			
		||||
      >
 | 
			
		||||
        Request permission
 | 
			
		||||
      </Button>
 | 
			
		||||
| 
						 | 
				
			
			@ -275,8 +278,8 @@ function NotificationsSection() {
 | 
			
		|||
          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>}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,6 +58,7 @@ function InviteNotifications() {
 | 
			
		|||
  const mx = useMatrixClient();
 | 
			
		||||
 | 
			
		||||
  const navigate = useNavigate();
 | 
			
		||||
  const [showNotifications] = useSetting(settingsAtom, 'showNotifications');
 | 
			
		||||
  const [notificationSound] = useSetting(settingsAtom, 'isNotificationSounds');
 | 
			
		||||
 | 
			
		||||
  const notify = useCallback(
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +85,7 @@ function InviteNotifications() {
 | 
			
		|||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    if (invites.length > perviousInviteLen && mx.getSyncState() === 'SYNCING') {
 | 
			
		||||
      if (Notification.permission === 'granted') {
 | 
			
		||||
      if (showNotifications && Notification.permission === 'granted') {
 | 
			
		||||
        notify(invites.length - perviousInviteLen);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -92,7 +93,7 @@ function InviteNotifications() {
 | 
			
		|||
        playSound();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }, [mx, invites, perviousInviteLen, notificationSound, notify, playSound]);
 | 
			
		||||
  }, [mx, invites, perviousInviteLen, showNotifications, notificationSound, notify, playSound]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    // eslint-disable-next-line jsx-a11y/media-has-caption
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -185,8 +185,11 @@ export const useBindRoomToUnreadAtom = (
 | 
			
		|||
  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),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,15 +30,3 @@ export function toggleNickAvatarEvents() {
 | 
			
		|||
    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,
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,8 +52,6 @@ const cons = {
 | 
			
		|||
      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: {
 | 
			
		||||
| 
						 | 
				
			
			@ -81,8 +79,6 @@ const cons = {
 | 
			
		|||
      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',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,8 +33,6 @@ class Settings extends EventEmitter {
 | 
			
		|||
    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)');
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -137,29 +135,6 @@ class Settings extends EventEmitter {
 | 
			
		|||
    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]: () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -185,20 +160,6 @@ class Settings extends EventEmitter {
 | 
			
		|||
        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]?.();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue