mirror of
https://github.com/revoltchat/revite.git
synced 2025-01-06 12:44:46 -05:00
127 lines
3.9 KiB
TypeScript
127 lines
3.9 KiB
TypeScript
/**
|
|
* This file monitors changes to settings and syncs them to the server.
|
|
*/
|
|
|
|
import isEqual from "lodash.isequal";
|
|
import { Language } from "../Locale";
|
|
import { Sync } from "revolt.js/dist/api/objects";
|
|
import { useContext, useEffect } from "preact/hooks";
|
|
import { connectState } from "../../redux/connector";
|
|
import { WithDispatcher } from "../../redux/reducers";
|
|
import { Settings } from "../../redux/reducers/settings";
|
|
import { Notifications } from "../../redux/reducers/notifications";
|
|
import { AppContext, ClientStatus, StatusContext } from "./RevoltClient";
|
|
import { ClientboundNotification } from "revolt.js/dist/websocket/notifications";
|
|
import { DEFAULT_ENABLED_SYNC, SyncData, SyncKeys, SyncOptions } from "../../redux/reducers/sync";
|
|
|
|
type Props = WithDispatcher & {
|
|
settings: Settings,
|
|
locale: Language,
|
|
sync: SyncOptions,
|
|
notifications: Notifications
|
|
};
|
|
|
|
var lastValues: { [key in SyncKeys]?: any } = { };
|
|
|
|
export function mapSync(packet: Sync.UserSettings, revision?: Record<string, number>) {
|
|
let update: { [key in SyncKeys]?: [ number, SyncData[key] ] } = {};
|
|
for (let key of Object.keys(packet)) {
|
|
let [ timestamp, obj ] = packet[key];
|
|
if (timestamp < (revision ?? {})[key] ?? 0) {
|
|
continue;
|
|
}
|
|
|
|
let object;
|
|
if (obj[0] === '{') {
|
|
object = JSON.parse(obj)
|
|
} else {
|
|
object = obj;
|
|
}
|
|
|
|
lastValues[key as SyncKeys] = object;
|
|
update[key as SyncKeys] = [ timestamp, object ];
|
|
}
|
|
|
|
return update;
|
|
}
|
|
|
|
function SyncManager(props: Props) {
|
|
const client = useContext(AppContext);
|
|
const status = useContext(StatusContext);
|
|
|
|
useEffect(() => {
|
|
if (status === ClientStatus.ONLINE) {
|
|
client
|
|
.syncFetchSettings(DEFAULT_ENABLED_SYNC.filter(x => !props.sync?.disabled?.includes(x)))
|
|
.then(data => {
|
|
props.dispatcher({
|
|
type: 'SYNC_UPDATE',
|
|
update: mapSync(data)
|
|
});
|
|
});
|
|
|
|
client
|
|
.syncFetchUnreads()
|
|
.then(unreads => props.dispatcher({ type: 'UNREADS_SET', unreads }));
|
|
}
|
|
}, [ status ]);
|
|
|
|
function syncChange(key: SyncKeys, data: any) {
|
|
let timestamp = + new Date();
|
|
props.dispatcher({
|
|
type: 'SYNC_SET_REVISION',
|
|
key,
|
|
timestamp
|
|
});
|
|
|
|
client.syncSetSettings({
|
|
[key]: data
|
|
}, timestamp);
|
|
}
|
|
|
|
let disabled = props.sync.disabled ?? [];
|
|
for (let [key, object] of [ ['appearance', props.settings.appearance], ['theme', props.settings.theme], ['locale', props.locale], ['notifications', props.notifications] ] as [SyncKeys, any][]) {
|
|
useEffect(() => {
|
|
if (disabled.indexOf(key) === -1) {
|
|
if (typeof lastValues[key] !== 'undefined') {
|
|
if (!isEqual(lastValues[key], object)) {
|
|
syncChange(key, object);
|
|
}
|
|
}
|
|
}
|
|
|
|
lastValues[key] = object;
|
|
}, [ disabled, object ]);
|
|
}
|
|
|
|
useEffect(() => {
|
|
function onPacket(packet: ClientboundNotification) {
|
|
if (packet.type === 'UserSettingsUpdate') {
|
|
let update: { [key in SyncKeys]?: [ number, SyncData[key] ] } = mapSync(packet.update, props.sync.revision);
|
|
|
|
props.dispatcher({
|
|
type: 'SYNC_UPDATE',
|
|
update
|
|
});
|
|
}
|
|
}
|
|
|
|
client.addListener('packet', onPacket);
|
|
return () => client.removeListener('packet', onPacket);
|
|
}, [ disabled, props.sync ]);
|
|
|
|
return null;
|
|
}
|
|
|
|
export default connectState(
|
|
SyncManager,
|
|
state => {
|
|
return {
|
|
settings: state.settings,
|
|
locale: state.locale,
|
|
sync: state.sync,
|
|
notifications: state.notifications
|
|
};
|
|
},
|
|
true
|
|
);
|