Merge pull request #5065 from matrix-org/travis/echo/audit
Add local echo for notifications in the new room list
This commit is contained in:
@@ -17,12 +17,25 @@ limitations under the License.
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { AsyncStore } from "./AsyncStore";
|
||||
import { ActionPayload } from "../dispatcher/payloads";
|
||||
import { Dispatcher } from "flux";
|
||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||
|
||||
export abstract class AsyncStoreWithClient<T extends Object> extends AsyncStore<T> {
|
||||
protected matrixClient: MatrixClient;
|
||||
|
||||
protected abstract async onAction(payload: ActionPayload);
|
||||
|
||||
protected constructor(dispatcher: Dispatcher<ActionPayload>, initialState: T = <T>{}) {
|
||||
super(dispatcher, initialState);
|
||||
|
||||
if (MatrixClientPeg.get()) {
|
||||
this.matrixClient = MatrixClientPeg.get();
|
||||
|
||||
// noinspection JSIgnoredPromiseFromCall
|
||||
this.onReady();
|
||||
}
|
||||
}
|
||||
|
||||
protected async onReady() {
|
||||
// Default implementation is to do nothing.
|
||||
}
|
||||
@@ -42,8 +55,14 @@ export abstract class AsyncStoreWithClient<T extends Object> extends AsyncStore<
|
||||
if (!(payload.prevState === 'PREPARED' && payload.state !== 'PREPARED')) {
|
||||
return;
|
||||
}
|
||||
this.matrixClient = payload.matrixClient;
|
||||
await this.onReady();
|
||||
|
||||
if (this.matrixClient !== payload.matrixClient) {
|
||||
if (this.matrixClient) {
|
||||
await this.onNotReady();
|
||||
}
|
||||
this.matrixClient = payload.matrixClient;
|
||||
await this.onReady();
|
||||
}
|
||||
} else if (payload.action === 'on_client_not_viable' || payload.action === 'on_logged_out') {
|
||||
if (this.matrixClient) {
|
||||
await this.onNotReady();
|
||||
|
||||
50
src/stores/NonUrgentToastStore.ts
Normal file
50
src/stores/NonUrgentToastStore.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import EventEmitter from "events";
|
||||
import { ComponentClass } from "../@types/common";
|
||||
import { UPDATE_EVENT } from "./AsyncStore";
|
||||
|
||||
export type ToastReference = symbol;
|
||||
|
||||
export default class NonUrgentToastStore extends EventEmitter {
|
||||
private static _instance: NonUrgentToastStore;
|
||||
|
||||
private toasts = new Map<ToastReference, ComponentClass>();
|
||||
|
||||
public static get instance(): NonUrgentToastStore {
|
||||
if (!NonUrgentToastStore._instance) {
|
||||
NonUrgentToastStore._instance = new NonUrgentToastStore();
|
||||
}
|
||||
return NonUrgentToastStore._instance;
|
||||
}
|
||||
|
||||
public get components(): ComponentClass[] {
|
||||
return Array.from(this.toasts.values());
|
||||
}
|
||||
|
||||
public addToast(c: ComponentClass): ToastReference {
|
||||
const ref: ToastReference = Symbol();
|
||||
this.toasts.set(ref, c);
|
||||
this.emit(UPDATE_EVENT);
|
||||
return ref;
|
||||
}
|
||||
|
||||
public removeToast(ref: ToastReference) {
|
||||
this.toasts.delete(ref);
|
||||
this.emit(UPDATE_EVENT);
|
||||
}
|
||||
}
|
||||
@@ -15,9 +15,10 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import EventEmitter from "events";
|
||||
import React, {JSXElementConstructor} from "react";
|
||||
import React from "react";
|
||||
import { ComponentClass } from "../@types/common";
|
||||
|
||||
export interface IToast<C extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>> {
|
||||
export interface IToast<C extends ComponentClass> {
|
||||
key: string;
|
||||
// higher priority number will be shown on top of lower priority
|
||||
priority: number;
|
||||
@@ -55,7 +56,7 @@ export default class ToastStore extends EventEmitter {
|
||||
*
|
||||
* @param {object} newToast The new toast
|
||||
*/
|
||||
addOrReplaceToast<C extends keyof JSX.IntrinsicElements | JSXElementConstructor<any>>(newToast: IToast<C>) {
|
||||
addOrReplaceToast<C extends ComponentClass>(newToast: IToast<C>) {
|
||||
const oldIndex = this.toasts.findIndex(t => t.key === newToast.key);
|
||||
if (oldIndex === -1) {
|
||||
let newIndex = this.toasts.length;
|
||||
|
||||
31
src/stores/local-echo/EchoChamber.ts
Normal file
31
src/stores/local-echo/EchoChamber.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { RoomEchoChamber } from "./RoomEchoChamber";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { EchoStore } from "./EchoStore";
|
||||
|
||||
/**
|
||||
* Semantic access to local echo
|
||||
*/
|
||||
export class EchoChamber {
|
||||
private constructor() {
|
||||
}
|
||||
|
||||
public static forRoom(room: Room): RoomEchoChamber {
|
||||
return EchoStore.instance.getOrCreateChamberForRoom(room);
|
||||
}
|
||||
}
|
||||
87
src/stores/local-echo/EchoContext.ts
Normal file
87
src/stores/local-echo/EchoContext.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { EchoTransaction, RunFn, TransactionStatus } from "./EchoTransaction";
|
||||
import { arrayFastClone } from "../../utils/arrays";
|
||||
import { IDestroyable } from "../../utils/IDestroyable";
|
||||
import { Whenable } from "../../utils/Whenable";
|
||||
|
||||
export enum ContextTransactionState {
|
||||
NotStarted,
|
||||
PendingErrors,
|
||||
AllSuccessful
|
||||
}
|
||||
|
||||
export abstract class EchoContext extends Whenable<ContextTransactionState> implements IDestroyable {
|
||||
private _transactions: EchoTransaction[] = [];
|
||||
private _state = ContextTransactionState.NotStarted;
|
||||
|
||||
public get transactions(): EchoTransaction[] {
|
||||
return arrayFastClone(this._transactions);
|
||||
}
|
||||
|
||||
public get state(): ContextTransactionState {
|
||||
return this._state;
|
||||
}
|
||||
|
||||
public get firstFailedTime(): Date {
|
||||
const failedTxn = this.transactions.find(t => t.didPreviouslyFail || t.status === TransactionStatus.DoneError);
|
||||
if (failedTxn) return failedTxn.startTime;
|
||||
return null;
|
||||
}
|
||||
|
||||
public disownTransaction(txn: EchoTransaction) {
|
||||
const idx = this._transactions.indexOf(txn);
|
||||
if (idx >= 0) this._transactions.splice(idx, 1);
|
||||
txn.destroy();
|
||||
this.checkTransactions();
|
||||
}
|
||||
|
||||
public beginTransaction(auditName: string, runFn: RunFn): EchoTransaction {
|
||||
const txn = new EchoTransaction(auditName, runFn);
|
||||
this._transactions.push(txn);
|
||||
txn.whenAnything(this.checkTransactions);
|
||||
|
||||
// We have no intent to call the transaction again if it succeeds (in fact, it'll
|
||||
// be really angry at us if we do), so call that the end of the road for the events.
|
||||
txn.when(TransactionStatus.DoneSuccess, () => txn.destroy());
|
||||
|
||||
return txn;
|
||||
}
|
||||
|
||||
private checkTransactions = () => {
|
||||
let status = ContextTransactionState.AllSuccessful;
|
||||
for (const txn of this.transactions) {
|
||||
if (txn.status === TransactionStatus.DoneError || txn.didPreviouslyFail) {
|
||||
status = ContextTransactionState.PendingErrors;
|
||||
break;
|
||||
} else if (txn.status === TransactionStatus.Pending) {
|
||||
status = ContextTransactionState.NotStarted;
|
||||
// no break as we might hit something which broke
|
||||
}
|
||||
}
|
||||
this._state = status;
|
||||
this.notifyCondition(status);
|
||||
};
|
||||
|
||||
public destroy() {
|
||||
for (const txn of this.transactions) {
|
||||
txn.destroy();
|
||||
}
|
||||
this._transactions = [];
|
||||
super.destroy();
|
||||
}
|
||||
}
|
||||
104
src/stores/local-echo/EchoStore.ts
Normal file
104
src/stores/local-echo/EchoStore.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { GenericEchoChamber } from "./GenericEchoChamber";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { RoomEchoChamber } from "./RoomEchoChamber";
|
||||
import { RoomEchoContext } from "./RoomEchoContext";
|
||||
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
|
||||
import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||
import { ActionPayload } from "../../dispatcher/payloads";
|
||||
import { ContextTransactionState, EchoContext } from "./EchoContext";
|
||||
import NonUrgentToastStore, { ToastReference } from "../NonUrgentToastStore";
|
||||
import NonUrgentEchoFailureToast from "../../components/views/toasts/NonUrgentEchoFailureToast";
|
||||
|
||||
interface IState {
|
||||
toastRef: ToastReference;
|
||||
}
|
||||
|
||||
type ContextKey = string;
|
||||
|
||||
const roomContextKey = (room: Room): ContextKey => `room-${room.roomId}`;
|
||||
|
||||
export class EchoStore extends AsyncStoreWithClient<IState> {
|
||||
private static _instance: EchoStore;
|
||||
|
||||
private caches = new Map<ContextKey, GenericEchoChamber<any, any, any>>();
|
||||
|
||||
constructor() {
|
||||
super(defaultDispatcher);
|
||||
}
|
||||
|
||||
public static get instance(): EchoStore {
|
||||
if (!EchoStore._instance) {
|
||||
EchoStore._instance = new EchoStore();
|
||||
}
|
||||
return EchoStore._instance;
|
||||
}
|
||||
|
||||
public get contexts(): EchoContext[] {
|
||||
return Array.from(this.caches.values()).map(e => e.context);
|
||||
}
|
||||
|
||||
public getOrCreateChamberForRoom(room: Room): RoomEchoChamber {
|
||||
if (this.caches.has(roomContextKey(room))) {
|
||||
return this.caches.get(roomContextKey(room)) as RoomEchoChamber;
|
||||
}
|
||||
|
||||
const context = new RoomEchoContext(room);
|
||||
context.whenAnything(() => this.checkContexts());
|
||||
|
||||
const echo = new RoomEchoChamber(context);
|
||||
echo.setClient(this.matrixClient);
|
||||
this.caches.set(roomContextKey(room), echo);
|
||||
|
||||
return echo;
|
||||
}
|
||||
|
||||
private async checkContexts() {
|
||||
let hasOrHadError = false;
|
||||
for (const echo of this.caches.values()) {
|
||||
hasOrHadError = echo.context.state === ContextTransactionState.PendingErrors;
|
||||
if (hasOrHadError) break;
|
||||
}
|
||||
|
||||
if (hasOrHadError && !this.state.toastRef) {
|
||||
const ref = NonUrgentToastStore.instance.addToast(NonUrgentEchoFailureToast);
|
||||
await this.updateState({toastRef: ref});
|
||||
} else if (!hasOrHadError && this.state.toastRef) {
|
||||
NonUrgentToastStore.instance.removeToast(this.state.toastRef);
|
||||
await this.updateState({toastRef: null});
|
||||
}
|
||||
}
|
||||
|
||||
protected async onReady(): Promise<any> {
|
||||
if (!this.caches) return; // can only happen during initialization
|
||||
for (const echo of this.caches.values()) {
|
||||
echo.setClient(this.matrixClient);
|
||||
}
|
||||
}
|
||||
|
||||
protected async onNotReady(): Promise<any> {
|
||||
for (const echo of this.caches.values()) {
|
||||
echo.setClient(null);
|
||||
}
|
||||
}
|
||||
|
||||
protected async onAction(payload: ActionPayload): Promise<any> {
|
||||
// We have nothing to actually listen for
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
72
src/stores/local-echo/EchoTransaction.ts
Normal file
72
src/stores/local-echo/EchoTransaction.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { Whenable } from "../../utils/Whenable";
|
||||
|
||||
export type RunFn = () => Promise<void>;
|
||||
|
||||
export enum TransactionStatus {
|
||||
Pending,
|
||||
DoneSuccess,
|
||||
DoneError,
|
||||
}
|
||||
|
||||
export class EchoTransaction extends Whenable<TransactionStatus> {
|
||||
private _status = TransactionStatus.Pending;
|
||||
private didFail = false;
|
||||
|
||||
public readonly startTime = new Date();
|
||||
|
||||
public constructor(
|
||||
public readonly auditName,
|
||||
public runFn: RunFn,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
public get didPreviouslyFail(): boolean {
|
||||
return this.didFail;
|
||||
}
|
||||
|
||||
public get status(): TransactionStatus {
|
||||
return this._status;
|
||||
}
|
||||
|
||||
public run() {
|
||||
if (this.status === TransactionStatus.DoneSuccess) {
|
||||
throw new Error("Cannot re-run a successful echo transaction");
|
||||
}
|
||||
this.setStatus(TransactionStatus.Pending);
|
||||
this.runFn()
|
||||
.then(() => this.setStatus(TransactionStatus.DoneSuccess))
|
||||
.catch(() => this.setStatus(TransactionStatus.DoneError));
|
||||
}
|
||||
|
||||
public cancel() {
|
||||
// Success basically means "done"
|
||||
this.setStatus(TransactionStatus.DoneSuccess);
|
||||
}
|
||||
|
||||
private setStatus(status: TransactionStatus) {
|
||||
this._status = status;
|
||||
if (status === TransactionStatus.DoneError) {
|
||||
this.didFail = true;
|
||||
} else if (status === TransactionStatus.DoneSuccess) {
|
||||
this.didFail = false;
|
||||
}
|
||||
this.notifyCondition(status);
|
||||
}
|
||||
}
|
||||
91
src/stores/local-echo/GenericEchoChamber.ts
Normal file
91
src/stores/local-echo/GenericEchoChamber.ts
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { EchoContext } from "./EchoContext";
|
||||
import { EchoTransaction, RunFn, TransactionStatus } from "./EchoTransaction";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { EventEmitter } from "events";
|
||||
|
||||
export async function implicitlyReverted() {
|
||||
// do nothing :D
|
||||
}
|
||||
|
||||
export const PROPERTY_UPDATED = "property_updated";
|
||||
|
||||
export abstract class GenericEchoChamber<C extends EchoContext, K, V> extends EventEmitter {
|
||||
private cache = new Map<K, {txn: EchoTransaction, val: V}>();
|
||||
protected matrixClient: MatrixClient;
|
||||
|
||||
protected constructor(public readonly context: C, private lookupFn: (key: K) => V) {
|
||||
super();
|
||||
}
|
||||
|
||||
public setClient(client: MatrixClient) {
|
||||
const oldClient = this.matrixClient;
|
||||
this.matrixClient = client;
|
||||
this.onClientChanged(oldClient, client);
|
||||
}
|
||||
|
||||
protected abstract onClientChanged(oldClient: MatrixClient, newClient: MatrixClient);
|
||||
|
||||
/**
|
||||
* Gets a value. If the key is in flight, the cached value will be returned. If
|
||||
* the key is not in flight then the lookupFn provided to this class will be
|
||||
* called instead.
|
||||
* @param key The key to look up.
|
||||
* @returns The value for the key.
|
||||
*/
|
||||
public getValue(key: K): V {
|
||||
return this.cache.has(key) ? this.cache.get(key).val : this.lookupFn(key);
|
||||
}
|
||||
|
||||
private cacheVal(key: K, val: V, txn: EchoTransaction) {
|
||||
this.cache.set(key, {txn, val});
|
||||
this.emit(PROPERTY_UPDATED, key);
|
||||
}
|
||||
|
||||
private decacheKey(key: K) {
|
||||
if (this.cache.has(key)) {
|
||||
this.context.disownTransaction(this.cache.get(key).txn);
|
||||
this.cache.delete(key);
|
||||
this.emit(PROPERTY_UPDATED, key);
|
||||
}
|
||||
}
|
||||
|
||||
protected markEchoReceived(key: K) {
|
||||
if (this.cache.has(key)) {
|
||||
const txn = this.cache.get(key).txn;
|
||||
this.context.disownTransaction(txn);
|
||||
txn.cancel();
|
||||
}
|
||||
this.decacheKey(key);
|
||||
}
|
||||
|
||||
public setValue(auditName: string, key: K, targetVal: V, runFn: RunFn, revertFn: RunFn) {
|
||||
// Cancel any pending transactions for the same key
|
||||
if (this.cache.has(key)) {
|
||||
this.cache.get(key).txn.cancel();
|
||||
}
|
||||
|
||||
const txn = this.context.beginTransaction(auditName, runFn);
|
||||
this.cacheVal(key, targetVal, txn); // set the cache now as it won't be updated by the .when() ladder below.
|
||||
|
||||
txn.when(TransactionStatus.Pending, () => this.cacheVal(key, targetVal, txn))
|
||||
.when(TransactionStatus.DoneError, () => revertFn());
|
||||
|
||||
txn.run();
|
||||
}
|
||||
}
|
||||
78
src/stores/local-echo/RoomEchoChamber.ts
Normal file
78
src/stores/local-echo/RoomEchoChamber.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { GenericEchoChamber, implicitlyReverted, PROPERTY_UPDATED } from "./GenericEchoChamber";
|
||||
import { getRoomNotifsState, setRoomNotifsState } from "../../RoomNotifs";
|
||||
import { RoomEchoContext } from "./RoomEchoContext";
|
||||
import { _t } from "../../languageHandler";
|
||||
import { Volume } from "../../RoomNotifsTypes";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
|
||||
export type CachedRoomValues = Volume;
|
||||
|
||||
export enum CachedRoomKey {
|
||||
NotificationVolume,
|
||||
}
|
||||
|
||||
export class RoomEchoChamber extends GenericEchoChamber<RoomEchoContext, CachedRoomKey, CachedRoomValues> {
|
||||
private properties = new Map<CachedRoomKey, CachedRoomValues>();
|
||||
|
||||
public constructor(context: RoomEchoContext) {
|
||||
super(context, (k) => this.properties.get(k));
|
||||
}
|
||||
|
||||
protected onClientChanged(oldClient, newClient) {
|
||||
this.properties.clear();
|
||||
if (oldClient) {
|
||||
oldClient.removeListener("accountData", this.onAccountData);
|
||||
}
|
||||
if (newClient) {
|
||||
// Register the listeners first
|
||||
newClient.on("accountData", this.onAccountData);
|
||||
|
||||
// Then populate the properties map
|
||||
this.updateNotificationVolume();
|
||||
}
|
||||
}
|
||||
|
||||
private onAccountData = (event: MatrixEvent) => {
|
||||
if (event.getType() === "m.push_rules") {
|
||||
const currentVolume = this.properties.get(CachedRoomKey.NotificationVolume) as Volume;
|
||||
const newVolume = getRoomNotifsState(this.context.room.roomId) as Volume;
|
||||
if (currentVolume !== newVolume) {
|
||||
this.updateNotificationVolume();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private updateNotificationVolume() {
|
||||
this.properties.set(CachedRoomKey.NotificationVolume, getRoomNotifsState(this.context.room.roomId));
|
||||
this.markEchoReceived(CachedRoomKey.NotificationVolume);
|
||||
this.emit(PROPERTY_UPDATED, CachedRoomKey.NotificationVolume);
|
||||
}
|
||||
|
||||
// ---- helpers below here ----
|
||||
|
||||
public get notificationVolume(): Volume {
|
||||
return this.getValue(CachedRoomKey.NotificationVolume);
|
||||
}
|
||||
|
||||
public set notificationVolume(v: Volume) {
|
||||
this.setValue(_t("Change notification settings"), CachedRoomKey.NotificationVolume, v, async () => {
|
||||
return setRoomNotifsState(this.context.room.roomId, v);
|
||||
}, implicitlyReverted);
|
||||
}
|
||||
}
|
||||
24
src/stores/local-echo/RoomEchoContext.ts
Normal file
24
src/stores/local-echo/RoomEchoContext.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Copyright 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { EchoContext } from "./EchoContext";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
||||
export class RoomEchoContext extends EchoContext {
|
||||
constructor(public readonly room: Room) {
|
||||
super();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user