Merge pull request #4835 from matrix-org/t3chguy/notifications0

More small tweaks in preparation for Notifications rework
This commit is contained in:
Michael Telatynski 2020-06-25 23:34:28 +01:00 committed by GitHub
commit 85c5bb3bc3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 139 additions and 15 deletions

View file

@ -0,0 +1,61 @@
/*
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 React from "react";
import classNames from "classnames";
import StyledRadioButton from "./StyledRadioButton";
interface IDefinition<T extends string> {
value: T;
className?: string;
disabled?: boolean;
label: React.ReactChild;
description?: React.ReactChild;
}
interface IProps<T extends string> {
name: string;
className?: string;
definitions: IDefinition<T>[];
value?: T; // if not provided no options will be selected
onChange(newValue: T);
}
function StyledRadioGroup<T extends string>({name, definitions, value, className, onChange}: IProps<T>) {
const _onChange = e => {
onChange(e.target.value);
};
return <React.Fragment>
{definitions.map(d => <React.Fragment>
<StyledRadioButton
key={d.value}
className={classNames(className, d.className)}
onChange={_onChange}
checked={d.value === value}
name={name}
value={d.value}
disabled={d.disabled}
>
{d.label}
</StyledRadioButton>
{d.description}
</React.Fragment>)}
</React.Fragment>;
}
export default StyledRadioGroup;

View file

@ -141,6 +141,20 @@ export default class NotificationBadge extends React.PureComponent<IProps, IStat
} }
} }
export class StaticNotificationState extends EventEmitter implements INotificationState {
constructor(public symbol: string, public count: number, public color: NotificationColor) {
super();
}
public static forCount(count: number, color: NotificationColor): StaticNotificationState {
return new StaticNotificationState(null, count, color);
}
public static forSymbol(symbol: string, color: NotificationColor): StaticNotificationState {
return new StaticNotificationState(symbol, 0, color);
}
}
export class RoomNotificationState extends EventEmitter implements IDestroyable, INotificationState { export class RoomNotificationState extends EventEmitter implements IDestroyable, INotificationState {
private _symbol: string; private _symbol: string;
private _count: number; private _count: number;

View file

@ -33,6 +33,7 @@ import StyledCheckbox from '../../../elements/StyledCheckbox';
import SettingsFlag from '../../../elements/SettingsFlag'; import SettingsFlag from '../../../elements/SettingsFlag';
import Field from '../../../elements/Field'; import Field from '../../../elements/Field';
import EventTilePreview from '../../../elements/EventTilePreview'; import EventTilePreview from '../../../elements/EventTilePreview';
import StyledRadioGroup from "../../../elements/StyledRadioGroup";
interface IProps { interface IProps {
} }
@ -116,8 +117,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
}; };
} }
private onThemeChange = (e: React.ChangeEvent<HTMLInputElement>): void => { private onThemeChange = (newTheme: string): void => {
const newTheme = e.target.value;
if (this.state.theme === newTheme) return; if (this.state.theme === newTheme) return;
// doing getValue in the .catch will still return the value we failed to set, // doing getValue in the .catch will still return the value we failed to set,
@ -277,19 +277,18 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
<div className="mx_SettingsTab_section mx_AppearanceUserSettingsTab_themeSection"> <div className="mx_SettingsTab_section mx_AppearanceUserSettingsTab_themeSection">
<span className="mx_SettingsTab_subheading">{_t("Theme")}</span> <span className="mx_SettingsTab_subheading">{_t("Theme")}</span>
{systemThemeSection} {systemThemeSection}
<div className="mx_ThemeSelectors" onChange={this.onThemeChange}> <div className="mx_ThemeSelectors">
{orderedThemes.map(theme => { <StyledRadioGroup
return <StyledRadioButton
key={theme.id}
value={theme.id}
name="theme" name="theme"
disabled={this.state.useSystemTheme} definitions={orderedThemes.map(t => ({
checked={!this.state.useSystemTheme && theme.id === this.state.theme} value: t.id,
className={"mx_ThemeSelector_" + theme.id} label: t.name,
> disabled: this.state.useSystemTheme,
{theme.name} className: "mx_ThemeSelector_" + t.id,
</StyledRadioButton>; }))}
})} onChange={this.onThemeChange}
value={this.state.useSystemTheme ? undefined : this.state.theme}
/>
</div> </div>
{customThemeForm} {customThemeForm}
<SettingsFlag name="useCompactLayout" level={SettingLevel.ACCOUNT} useCheckbox={true} /> <SettingsFlag name="useCompactLayout" level={SettingLevel.ACCOUNT} useCheckbox={true} />

View 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 {useCallback, useState} from "react";
import {MatrixClient} from "matrix-js-sdk/src/client";
import {MatrixEvent} from "matrix-js-sdk/src/models/event";
import {Room} from "matrix-js-sdk/src/models/room";
import {useEventEmitter} from "./useEventEmitter";
const tryGetContent = (ev?: MatrixEvent) => ev ? ev.getContent() : undefined;
// Hook to simplify listening to Matrix account data
export const useAccountData = <T extends {}>(cli: MatrixClient, eventType: string) => {
const [value, setValue] = useState<T>(() => tryGetContent(cli.getAccountData(eventType)));
const handler = useCallback((event) => {
if (event.getType() !== eventType) return;
setValue(event.getContent());
}, [cli, eventType]);
useEventEmitter(cli, "accountData", handler);
return value || {} as T;
};
// Hook to simplify listening to Matrix room account data
export const useRoomAccountData = <T extends {}>(room: Room, eventType: string) => {
const [value, setValue] = useState<T>(() => tryGetContent(room.getAccountData(eventType)));
const handler = useCallback((event) => {
if (event.getType() !== eventType) return;
setValue(event.getContent());
}, [room, eventType]);
useEventEmitter(room, "Room.accountData", handler);
return value || {} as T;
};