Add setting to hide bold notifications (#9705)

This commit is contained in:
Germain 2022-12-06 09:59:17 +00:00 committed by GitHub
parent 474f464e48
commit 3a501003e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 65 additions and 13 deletions

View file

@ -20,6 +20,7 @@ import classNames from "classnames";
import { formatCount } from "../../../../utils/FormattingUtils"; import { formatCount } from "../../../../utils/FormattingUtils";
import AccessibleButton from "../../elements/AccessibleButton"; import AccessibleButton from "../../elements/AccessibleButton";
import { NotificationColor } from "../../../../stores/notifications/NotificationColor"; import { NotificationColor } from "../../../../stores/notifications/NotificationColor";
import { useSettingValue } from "../../../../hooks/useSettings";
interface Props { interface Props {
symbol: string | null; symbol: string | null;
@ -37,8 +38,12 @@ export function StatelessNotificationBadge({
count, count,
color, color,
...props }: Props) { ...props }: Props) {
const hideBold = useSettingValue("feature_hidebold");
// Don't show a badge if we don't need to // Don't show a badge if we don't need to
if (color === NotificationColor.None) return null; if (color === NotificationColor.None || (hideBold && color == NotificationColor.Bold)) {
return null;
}
const hasUnreadCount = color >= NotificationColor.Grey && (!!count || !!symbol); const hasUnreadCount = color >= NotificationColor.Grey && (!!count || !!symbol);

View file

@ -960,6 +960,7 @@
"Show stickers button": "Show stickers button", "Show stickers button": "Show stickers button",
"Show polls button": "Show polls button", "Show polls button": "Show polls button",
"Insert a trailing colon after user mentions at the start of a message": "Insert a trailing colon after user mentions at the start of a message", "Insert a trailing colon after user mentions at the start of a message": "Insert a trailing colon after user mentions at the start of a message",
"Hide notification dot (only display counters badges)": "Hide notification dot (only display counters badges)",
"Use a more compact 'Modern' layout": "Use a more compact 'Modern' layout", "Use a more compact 'Modern' layout": "Use a more compact 'Modern' layout",
"Show a placeholder for removed messages": "Show a placeholder for removed messages", "Show a placeholder for removed messages": "Show a placeholder for removed messages",
"Show join/leave messages (invites/removes/bans unaffected)": "Show join/leave messages (invites/removes/bans unaffected)", "Show join/leave messages (invites/removes/bans unaffected)": "Show join/leave messages (invites/removes/bans unaffected)",

View file

@ -556,11 +556,18 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_ROOM_OR_ACCOUNT, supportedLevels: LEVELS_ROOM_OR_ACCOUNT,
default: false, default: false,
}, },
"feature_hidebold": {
isFeature: true,
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td("Hide notification dot (only display counters badges)"),
labsGroup: LabGroup.Rooms,
default: false,
},
"useCompactLayout": { "useCompactLayout": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
displayName: _td("Use a more compact 'Modern' layout"), displayName: _td("Use a more compact 'Modern' layout"),
default: false, default: false,
controller: new IncompatibleController("layout", false, v => v !== Layout.Group), controller: new IncompatibleController("layout", false, (v: Layout) => v !== Layout.Group),
}, },
"showRedactions": { "showRedactions": {
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM, supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,

View file

@ -31,7 +31,7 @@ export class ListNotificationState extends NotificationState {
super(); super();
} }
public get symbol(): string { public get symbol(): string | null {
return this._color === NotificationColor.Unsent ? "!" : null; return this._color === NotificationColor.Unsent ? "!" : null;
} }

View file

@ -18,6 +18,7 @@ import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter"
import { NotificationColor } from "./NotificationColor"; import { NotificationColor } from "./NotificationColor";
import { IDestroyable } from "../../utils/IDestroyable"; import { IDestroyable } from "../../utils/IDestroyable";
import SettingsStore from "../../settings/SettingsStore";
export interface INotificationStateSnapshotParams { export interface INotificationStateSnapshotParams {
symbol: string | null; symbol: string | null;
@ -37,11 +38,22 @@ export abstract class NotificationState
extends TypedEventEmitter<NotificationStateEvents, EventHandlerMap> extends TypedEventEmitter<NotificationStateEvents, EventHandlerMap>
implements INotificationStateSnapshotParams, IDestroyable { implements INotificationStateSnapshotParams, IDestroyable {
// //
protected _symbol: string | null; protected _symbol: string | null = null;
protected _count: number; protected _count = 0;
protected _color: NotificationColor; protected _color: NotificationColor = NotificationColor.None;
public get symbol(): string { private watcherReferences: string[] = [];
constructor() {
super();
this.watcherReferences.push(
SettingsStore.watchSetting("feature_hidebold", null, () => {
this.emit(NotificationStateEvents.Update);
}),
);
}
public get symbol(): string | null {
return this._symbol; return this._symbol;
} }
@ -58,7 +70,12 @@ export abstract class NotificationState
} }
public get isUnread(): boolean { public get isUnread(): boolean {
return this.color >= NotificationColor.Bold; if (this.color > NotificationColor.Bold) {
return true;
} else {
const hideBold = SettingsStore.getValue("feature_hidebold");
return this.color === NotificationColor.Bold && !hideBold;
}
} }
public get hasUnreadCount(): boolean { public get hasUnreadCount(): boolean {
@ -81,11 +98,15 @@ export abstract class NotificationState
public destroy(): void { public destroy(): void {
this.removeAllListeners(NotificationStateEvents.Update); this.removeAllListeners(NotificationStateEvents.Update);
for (const watcherReference of this.watcherReferences) {
SettingsStore.unwatchSetting(watcherReference);
}
this.watcherReferences = [];
} }
} }
export class NotificationStateSnapshot { export class NotificationStateSnapshot {
private readonly symbol: string; private readonly symbol: string | null;
private readonly count: number; private readonly count: number;
private readonly color: NotificationColor; private readonly color: NotificationColor;

View file

@ -98,8 +98,8 @@ export class RoomNotificationState extends NotificationState implements IDestroy
this.updateNotificationState(); this.updateNotificationState();
}; };
private handleRoomEventUpdate = (event: MatrixEvent, room: Room | null) => { private handleRoomEventUpdate = (event: MatrixEvent) => {
if (room?.roomId !== this.room.roomId) return; // ignore - not for us or notifications timeline if (event?.getRoomId() !== this.room.roomId) return; // ignore - not for us or notifications timeline
this.updateNotificationState(); this.updateNotificationState();
}; };

View file

@ -32,7 +32,7 @@ export class SpaceNotificationState extends NotificationState {
super(); super();
} }
public get symbol(): string { public get symbol(): string | null {
return this._color === NotificationColor.Unsent ? "!" : null; return this._color === NotificationColor.Unsent ? "!" : null;
} }

View file

@ -20,7 +20,7 @@ import { NotificationState } from "./NotificationState";
export class StaticNotificationState extends NotificationState { export class StaticNotificationState extends NotificationState {
public static readonly RED_EXCLAMATION = StaticNotificationState.forSymbol("!", NotificationColor.Red); public static readonly RED_EXCLAMATION = StaticNotificationState.forSymbol("!", NotificationColor.Red);
constructor(symbol: string, count: number, color: NotificationColor) { constructor(symbol: string | null, count: number, color: NotificationColor) {
super(); super();
this._symbol = symbol; this._symbol = symbol;
this._count = count; this._count = count;

View file

@ -20,6 +20,7 @@ import React from "react";
import { import {
StatelessNotificationBadge, StatelessNotificationBadge,
} from "../../../../../src/components/views/rooms/NotificationBadge/StatelessNotificationBadge"; } from "../../../../../src/components/views/rooms/NotificationBadge/StatelessNotificationBadge";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { NotificationColor } from "../../../../../src/stores/notifications/NotificationColor"; import { NotificationColor } from "../../../../../src/stores/notifications/NotificationColor";
describe("NotificationBadge", () => { describe("NotificationBadge", () => {
@ -45,5 +46,19 @@ describe("NotificationBadge", () => {
fireEvent.mouseLeave(container.firstChild); fireEvent.mouseLeave(container.firstChild);
expect(cb).toHaveBeenCalledTimes(3); expect(cb).toHaveBeenCalledTimes(3);
}); });
it("hides the bold icon when the settings is set", () => {
jest.spyOn(SettingsStore, "getValue").mockImplementation((name: string) => {
return name === "feature_hidebold";
});
const { container } = render(<StatelessNotificationBadge
symbol=""
color={NotificationColor.Bold}
count={1}
/>);
expect(container.firstChild).toBeNull();
});
}); });
}); });

View file

@ -38,6 +38,7 @@ jest.mock('../../../../src/settings/SettingsStore', () => ({
setValue: jest.fn(), setValue: jest.fn(),
getValue: jest.fn(), getValue: jest.fn(),
monitorSetting: jest.fn(), monitorSetting: jest.fn(),
watchSetting: jest.fn(),
})); }));
jest.mock('../../../../src/dispatcher/dispatcher', () => ({ jest.mock('../../../../src/dispatcher/dispatcher', () => ({

View file

@ -25,6 +25,7 @@ import { TestSdkContext } from "../TestSdkContext";
jest.mock("../../src/settings/SettingsStore", () => ({ jest.mock("../../src/settings/SettingsStore", () => ({
getValue: jest.fn(), getValue: jest.fn(),
monitorSetting: jest.fn(), monitorSetting: jest.fn(),
watchSetting: jest.fn(),
})); }));
describe("TypingStore", () => { describe("TypingStore", () => {

View file

@ -42,6 +42,7 @@ jest.mock('../../src/Modal', () => ({
jest.mock('../../src/settings/SettingsStore', () => ({ jest.mock('../../src/settings/SettingsStore', () => ({
getValue: jest.fn(), getValue: jest.fn(),
monitorSetting: jest.fn(), monitorSetting: jest.fn(),
watchSetting: jest.fn(),
})); }));
const mockPromptBeforeInviteUnknownUsers = (value: boolean) => { const mockPromptBeforeInviteUnknownUsers = (value: boolean) => {