Active private receipt support

This commit is contained in:
greentore 2023-02-06 19:15:04 +01:00
parent a6fb44e1ab
commit 373d3c9e59
5 changed files with 75 additions and 2 deletions

View file

@ -7,7 +7,7 @@ import settings from '../../../client/state/settings';
import navigation from '../../../client/state/navigation'; import navigation from '../../../client/state/navigation';
import { import {
toggleSystemTheme, toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents, toggleSystemTheme, toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents,
toggleNotifications, toggleNotificationSounds, toggleNotifications, toggleNotificationSounds, toggleReadReceipts,
} from '../../../client/action/settings'; } from '../../../client/action/settings';
import { usePermission } from '../../hooks/usePermission'; import { usePermission } from '../../hooks/usePermission';
@ -44,6 +44,10 @@ import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
import CinnySVG from '../../../../public/res/svg/cinny.svg'; import CinnySVG from '../../../../public/res/svg/cinny.svg';
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog'; import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
let capabilities = {
privateReadReceipts: false,
};
function AppearanceSection() { function AppearanceSection() {
const [, updateState] = useState({}); const [, updateState] = useState({});
@ -188,6 +192,7 @@ function EmojiSection() {
} }
function SecuritySection() { function SecuritySection() {
const [, updateState] = useState({});
return ( return (
<div className="settings-security"> <div className="settings-security">
<div className="settings-security__card"> <div className="settings-security__card">
@ -217,6 +222,33 @@ function SecuritySection() {
)} )}
/> />
</div> </div>
<div className="settings-security__card">
<MenuHeader>Presence</MenuHeader>
<SettingTile
title="Send read receipts"
options={(
<Toggle
/** Always allow to switch receipts on. */
disabled={!capabilities.privateReadReceipts && settings.sendReadReceipts}
isActive={settings.sendReadReceipts}
onToggle={() => { toggleReadReceipts(); updateState({}); }}
/>
)}
content={(
<>
<Text variant="b3">
Let other people know what messages you read.
</Text>
{!capabilities.privateReadReceipts
&& (
<Text variant="b3">
Making your read receipts private requires a compatible homeserver.
</Text>
)}
</>
)}
/>
</div>
</div> </div>
); );
} }
@ -320,9 +352,20 @@ function useWindowToggle(setSelectedTab) {
return [isOpen, requestClose]; return [isOpen, requestClose];
} }
async function getCapabilities() {
const mx = initMatrix.matrixClient;
capabilities = {
privateReadReceipts: (await (Promise.all([
mx.doesServerSupportUnstableFeature('org.matrix.msc2285.stable'),
mx.isVersionSupported('v1.4')])
)).some((res) => res === true),
};
}
function Settings() { function Settings() {
const [selectedTab, setSelectedTab] = useState(tabItems[0]); const [selectedTab, setSelectedTab] = useState(tabItems[0]);
const [isOpen, requestClose] = useWindowToggle(setSelectedTab); const [isOpen, requestClose] = useWindowToggle(setSelectedTab);
useEffect(getCapabilities, []);
const handleTabChange = (tabItem) => setSelectedTab(tabItem); const handleTabChange = (tabItem) => setSelectedTab(tabItem);
const handleLogout = async () => { const handleLogout = async () => {

View file

@ -1,4 +1,10 @@
import initMatrix from '../initMatrix'; import initMatrix from '../initMatrix';
import settings from '../state/settings';
const ReceiptType = {
Read: 'm.read',
ReadPrivate: 'm.read.private',
};
// eslint-disable-next-line import/prefer-default-export // eslint-disable-next-line import/prefer-default-export
export async function markAsRead(roomId) { export async function markAsRead(roomId) {
@ -22,5 +28,6 @@ export async function markAsRead(roomId) {
const latestEvent = getLatestValidEvent(); const latestEvent = getLatestValidEvent();
if (latestEvent === null) return; if (latestEvent === null) return;
await mx.sendReadReceipt(latestEvent); const receiptType = settings.sendReadReceipts ? ReceiptType.Read : ReceiptType.ReadPrivate;
await mx.sendReadReceipt(latestEvent, receiptType);
} }

View file

@ -42,3 +42,9 @@ export function toggleNotificationSounds() {
type: cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS, type: cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS,
}); });
} }
export function toggleReadReceipts() {
appDispatcher.dispatch({
type: cons.actions.settings.TOGGLE_READ_RECEIPTS,
});
}

View file

@ -78,6 +78,7 @@ const cons = {
TOGGLE_NICKAVATAR_EVENT: 'TOGGLE_NICKAVATAR_EVENT', TOGGLE_NICKAVATAR_EVENT: 'TOGGLE_NICKAVATAR_EVENT',
TOGGLE_NOTIFICATIONS: 'TOGGLE_NOTIFICATIONS', TOGGLE_NOTIFICATIONS: 'TOGGLE_NOTIFICATIONS',
TOGGLE_NOTIFICATION_SOUNDS: 'TOGGLE_NOTIFICATION_SOUNDS', TOGGLE_NOTIFICATION_SOUNDS: 'TOGGLE_NOTIFICATION_SOUNDS',
TOGGLE_READ_RECEIPTS: 'TOGGLE_READ_RECEIPTS',
}, },
}, },
events: { events: {
@ -150,6 +151,7 @@ const cons = {
NICKAVATAR_EVENTS_TOGGLED: 'NICKAVATAR_EVENTS_TOGGLED', NICKAVATAR_EVENTS_TOGGLED: 'NICKAVATAR_EVENTS_TOGGLED',
NOTIFICATIONS_TOGGLED: 'NOTIFICATIONS_TOGGLED', NOTIFICATIONS_TOGGLED: 'NOTIFICATIONS_TOGGLED',
NOTIFICATION_SOUNDS_TOGGLED: 'NOTIFICATION_SOUNDS_TOGGLED', NOTIFICATION_SOUNDS_TOGGLED: 'NOTIFICATION_SOUNDS_TOGGLED',
READ_RECEIPTS_TOGGLED: 'READ_RECEIPTS_TOGGLED',
}, },
}, },
}; };

View file

@ -30,6 +30,7 @@ class Settings extends EventEmitter {
this.hideNickAvatarEvents = this.getHideNickAvatarEvents(); this.hideNickAvatarEvents = this.getHideNickAvatarEvents();
this._showNotifications = this.getShowNotifications(); this._showNotifications = this.getShowNotifications();
this.isNotificationSounds = this.getIsNotificationSounds(); this.isNotificationSounds = this.getIsNotificationSounds();
this.sendReadReceipts = this.getSendReadReceipts();
this.isTouchScreenDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0); this.isTouchScreenDevice = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0);
} }
@ -147,6 +148,15 @@ class Settings extends EventEmitter {
return settings.isNotificationSounds; return settings.isNotificationSounds;
} }
getSendReadReceipts() {
if (typeof this.sendReadReceipts === 'boolean') return this.sendReadReceipts;
const settings = getSettings();
if (settings === null) return true;
if (typeof settings.sendReadReceipts === 'undefined') return true;
return settings.sendReadReceipts;
}
setter(action) { setter(action) {
const actions = { const actions = {
[cons.actions.settings.TOGGLE_SYSTEM_THEME]: () => { [cons.actions.settings.TOGGLE_SYSTEM_THEME]: () => {
@ -186,6 +196,11 @@ class Settings extends EventEmitter {
setSettings('isNotificationSounds', this.isNotificationSounds); setSettings('isNotificationSounds', this.isNotificationSounds);
this.emit(cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED, this.isNotificationSounds); this.emit(cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED, this.isNotificationSounds);
}, },
[cons.actions.settings.TOGGLE_READ_RECEIPTS]: () => {
this.sendReadReceipts = !this.sendReadReceipts;
setSettings('sendReadReceipts', this.sendReadReceipts);
this.emit(cons.events.settings.READ_RECEIPTS_TOGGLED, this.sendReadReceipts);
},
}; };
actions[action.type]?.(); actions[action.type]?.();