Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Add setting to hide bold notifications #9705

Merged
merged 9 commits into from
Dec 6, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import classNames from "classnames";
import { formatCount } from "../../../../utils/FormattingUtils";
import AccessibleButton from "../../elements/AccessibleButton";
import { NotificationColor } from "../../../../stores/notifications/NotificationColor";
import { useSettingValue } from "../../../../hooks/useSettings";

interface Props {
symbol: string | null;
Expand All @@ -37,8 +38,12 @@ export function StatelessNotificationBadge({
count,
color,
...props }: Props) {
const hideBold = useSettingValue("feature_hidebold");

// 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);

Expand Down
1 change: 1 addition & 0 deletions src/i18n/strings/en_EN.json
Original file line number Diff line number Diff line change
Expand Up @@ -960,6 +960,7 @@
"Show stickers button": "Show stickers 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",
"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",
"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)",
Expand Down
9 changes: 8 additions & 1 deletion src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -556,11 +556,18 @@ export const SETTINGS: {[setting: string]: ISetting} = {
supportedLevels: LEVELS_ROOM_OR_ACCOUNT,
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": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
displayName: _td("Use a more compact 'Modern' layout"),
default: false,
controller: new IncompatibleController("layout", false, v => v !== Layout.Group),
controller: new IncompatibleController("layout", false, (v: Layout) => v !== Layout.Group),
},
"showRedactions": {
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
Expand Down
2 changes: 1 addition & 1 deletion src/stores/notifications/ListNotificationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export class ListNotificationState extends NotificationState {
super();
}

public get symbol(): string {
public get symbol(): string | null {
return this._color === NotificationColor.Unsent ? "!" : null;
}

Expand Down
33 changes: 27 additions & 6 deletions src/stores/notifications/NotificationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { TypedEventEmitter } from "matrix-js-sdk/src/models/typed-event-emitter"

import { NotificationColor } from "./NotificationColor";
import { IDestroyable } from "../../utils/IDestroyable";
import SettingsStore from "../../settings/SettingsStore";

export interface INotificationStateSnapshotParams {
symbol: string | null;
Expand All @@ -37,11 +38,22 @@ export abstract class NotificationState
extends TypedEventEmitter<NotificationStateEvents, EventHandlerMap>
implements INotificationStateSnapshotParams, IDestroyable {
//
protected _symbol: string | null;
protected _count: number;
protected _color: NotificationColor;
protected _symbol: string | null = null;
protected _count = 0;
protected _color: NotificationColor = NotificationColor.None;

private watcherReferences: string[] = [];

constructor() {
super();
this.watcherReferences.push(
SettingsStore.watchSetting("feature_hidebold", null, () => {
this.emit(NotificationStateEvents.Update);
}),
);
}

public get symbol(): string {
public get symbol(): string | null {
return this._symbol;
}

Expand All @@ -58,7 +70,12 @@ export abstract class NotificationState
}

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 {
Expand All @@ -81,11 +98,15 @@ export abstract class NotificationState

public destroy(): void {
this.removeAllListeners(NotificationStateEvents.Update);
for (const watcherReference of this.watcherReferences) {
SettingsStore.unwatchSetting(watcherReference);
}
this.watcherReferences = [];
}
}

export class NotificationStateSnapshot {
private readonly symbol: string;
private readonly symbol: string | null;
private readonly count: number;
private readonly color: NotificationColor;

Expand Down
4 changes: 2 additions & 2 deletions src/stores/notifications/RoomNotificationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ export class RoomNotificationState extends NotificationState implements IDestroy
this.updateNotificationState();
};

private handleRoomEventUpdate = (event: MatrixEvent, room: Room | null) => {
if (room?.roomId !== this.room.roomId) return; // ignore - not for us or notifications timeline
private handleRoomEventUpdate = (event: MatrixEvent) => {
if (event?.getRoomId() !== this.room.roomId) return; // ignore - not for us or notifications timeline
this.updateNotificationState();
};

Expand Down
2 changes: 1 addition & 1 deletion src/stores/notifications/SpaceNotificationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class SpaceNotificationState extends NotificationState {
super();
}

public get symbol(): string {
public get symbol(): string | null {
return this._color === NotificationColor.Unsent ? "!" : null;
}

Expand Down
2 changes: 1 addition & 1 deletion src/stores/notifications/StaticNotificationState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { NotificationState } from "./NotificationState";
export class StaticNotificationState extends NotificationState {
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();
this._symbol = symbol;
this._count = count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import React from "react";
import {
StatelessNotificationBadge,
} from "../../../../../src/components/views/rooms/NotificationBadge/StatelessNotificationBadge";
import SettingsStore from "../../../../../src/settings/SettingsStore";
import { NotificationColor } from "../../../../../src/stores/notifications/NotificationColor";

describe("NotificationBadge", () => {
Expand All @@ -45,5 +46,19 @@ describe("NotificationBadge", () => {
fireEvent.mouseLeave(container.firstChild);
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();
});
});
});
1 change: 1 addition & 0 deletions test/components/views/spaces/QuickThemeSwitcher-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ jest.mock('../../../../src/settings/SettingsStore', () => ({
setValue: jest.fn(),
getValue: jest.fn(),
monitorSetting: jest.fn(),
watchSetting: jest.fn(),
}));

jest.mock('../../../../src/dispatcher/dispatcher', () => ({
Expand Down
1 change: 1 addition & 0 deletions test/stores/TypingStore-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { TestSdkContext } from "../TestSdkContext";
jest.mock("../../src/settings/SettingsStore", () => ({
getValue: jest.fn(),
monitorSetting: jest.fn(),
watchSetting: jest.fn(),
}));

describe("TypingStore", () => {
Expand Down
1 change: 1 addition & 0 deletions test/utils/MultiInviter-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ jest.mock('../../src/Modal', () => ({
jest.mock('../../src/settings/SettingsStore', () => ({
getValue: jest.fn(),
monitorSetting: jest.fn(),
watchSetting: jest.fn(),
}));

const mockPromptBeforeInviteUnknownUsers = (value: boolean) => {
Expand Down