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

Commit 4db41a7

Browse files
committed
Implement new notification settings UI
1 parent 511b4a5 commit 4db41a7

14 files changed

+742
-6
lines changed

res/css/_components.pcss

+3
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,7 @@
322322
@import "./views/settings/_JoinRuleSettings.pcss";
323323
@import "./views/settings/_KeyboardShortcut.pcss";
324324
@import "./views/settings/_LayoutSwitcher.pcss";
325+
@import "./views/settings/_NotificationSettings2.pcss";
325326
@import "./views/settings/_Notifications.pcss";
326327
@import "./views/settings/_PhoneNumbers.pcss";
327328
@import "./views/settings/_ProfileSettings.pcss";
@@ -332,6 +333,8 @@
332333
@import "./views/settings/_SpellCheckLanguages.pcss";
333334
@import "./views/settings/_ThemeChoicePanel.pcss";
334335
@import "./views/settings/_UpdateCheckButton.pcss";
336+
@import "./views/settings/tabs/_SettingsBanner.pcss";
337+
@import "./views/settings/tabs/_SettingsIndent.pcss";
335338
@import "./views/settings/tabs/_SettingsSection.pcss";
336339
@import "./views/settings/tabs/_SettingsTab.pcss";
337340
@import "./views/settings/tabs/room/_NotificationSettingsTab.pcss";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
.mx_NotificationSettings2 {
2+
.mx_SettingsSection_subSections {
3+
color: $primary-content;
4+
gap: 32px;
5+
display: flex;
6+
flex-direction: column;
7+
}
8+
9+
.mx_SettingsSubsection_description {
10+
margin-bottom: 20px;
11+
12+
.mx_SettingsSubsection_text {
13+
font-size: 1.2rem;
14+
15+
.mx_NotificationBadge {
16+
vertical-align: baseline;
17+
display: inline-flex;
18+
margin: 0 2px;
19+
}
20+
}
21+
}
22+
23+
.mx_SettingsSubsection_content {
24+
margin-top: 12px;
25+
grid-gap: 12px;
26+
justify-items: stretch;
27+
justify-content: stretch;
28+
}
29+
30+
.mx_SettingsBanner {
31+
margin-bottom: 32px;
32+
}
33+
34+
.mx_NotificationSettings2_flags {
35+
grid-gap: 4px;
36+
}
37+
38+
.mx_StyledRadioButton_content {
39+
margin-left: 10px;
40+
margin-right: 10px;
41+
}
42+
43+
.mx_TagComposer {
44+
margin-top: 16px;
45+
46+
&.mx_TagComposer_disabled {
47+
opacity: 0.7;
48+
}
49+
50+
.mx_TagComposer_tags {
51+
margin-top: 16px;
52+
gap: 8px;
53+
54+
.mx_Tag {
55+
border-radius: 18px;
56+
line-height: 2.4rem;
57+
padding: 6px 12px;
58+
background: $panel-actions;
59+
margin: 0;
60+
61+
.mx_Tag_delete {
62+
background: $tertiary-content;
63+
color: #fff;
64+
align-self: initial;
65+
}
66+
}
67+
}
68+
}
69+
}
70+
71+
.mx_NotificationPusherSettings {
72+
.mx_NotificationPusherSettings_description {
73+
color: $primary-content;
74+
}
75+
76+
.mx_NotificationPusherSettings_detail {
77+
margin-top: -4px;
78+
margin-bottom: 12px;
79+
}
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
.mx_SettingsBanner {
2+
background: $system;
3+
line-height: 2.25rem;
4+
border-radius: 8px;
5+
padding: 12px 16px;
6+
gap: 12px;
7+
display: flex;
8+
flex-direction: row;
9+
align-items: center;
10+
11+
.mx_SettingsBanner_content {
12+
margin: 0;
13+
}
14+
15+
.mx_AccessibleButton {
16+
align-self: initial;
17+
white-space: nowrap;
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
Copyright 2023 New Vector Ltd
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
.mx_SettingsIndent {
17+
padding-left: 16px;
18+
display: flex;
19+
flex-direction: column;
20+
gap: 12px;
21+
}
Loading

src/components/views/elements/TagComposer.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
import classNames from "classnames";
1718
import React, { ChangeEvent, FormEvent } from "react";
1819

1920
import Field from "./Field";
@@ -67,7 +68,11 @@ export default class TagComposer extends React.PureComponent<IProps, IState> {
6768

6869
public render(): React.ReactNode {
6970
return (
70-
<div className="mx_TagComposer">
71+
<div
72+
className={classNames("mx_TagComposer", {
73+
mx_TagComposer_disabled: this.props.disabled,
74+
})}
75+
>
7176
<form className="mx_TagComposer_input" onSubmit={this.onAdd}>
7277
<Field
7378
value={this.state.newTag}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
Copyright 2023 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import { ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
18+
import { IPusher } from "matrix-js-sdk/src/matrix";
19+
import React, { useCallback } from "react";
20+
21+
import { useMatrixClientContext } from "../../../../contexts/MatrixClientContext";
22+
import { Action } from "../../../../dispatcher/actions";
23+
import dispatcher from "../../../../dispatcher/dispatcher";
24+
import { usePushers } from "../../../../hooks/usePushers";
25+
import { useThreepids } from "../../../../hooks/useThreepids";
26+
import { _t } from "../../../../languageHandler";
27+
import SdkConfig from "../../../../SdkConfig";
28+
import { UserTab } from "../../dialogs/UserTab";
29+
import AccessibleButton from "../../elements/AccessibleButton";
30+
import LabelledCheckbox from "../../elements/LabelledCheckbox";
31+
import { SettingsIndent } from "../shared/SettingsIndent";
32+
import SettingsSubsection, { SettingsSubsectionText } from "../shared/SettingsSubsection";
33+
34+
const EmailPusherTemplate: Omit<IPusher, "pushkey" | "device_display_name" | "append"> = {
35+
kind: "email",
36+
app_id: "m.email",
37+
app_display_name: "Email Notifications",
38+
lang: navigator.language,
39+
data: {
40+
brand: SdkConfig.get().brand,
41+
},
42+
};
43+
44+
function generalTabButton(content: string): JSX.Element {
45+
return (
46+
<AccessibleButton
47+
kind="link_inline"
48+
onClick={() => {
49+
dispatcher.dispatch({
50+
action: Action.ViewUserSettings,
51+
initialTabId: UserTab.General,
52+
});
53+
}}
54+
>
55+
{content}
56+
</AccessibleButton>
57+
);
58+
}
59+
60+
export function NotificationPusherSettings(): JSX.Element {
61+
const cli = useMatrixClientContext();
62+
const [pushers, refreshPushers] = usePushers(cli);
63+
const [threepids, refreshThreepids] = useThreepids(cli);
64+
65+
const setEmailEnabled = useCallback(
66+
(email: string, enabled: boolean) => {
67+
if (enabled) {
68+
cli.setPusher({
69+
...EmailPusherTemplate,
70+
pushkey: email,
71+
device_display_name: email,
72+
// We always append for email pushers since we don't want to stop other
73+
// accounts notifying to the same email address
74+
append: true,
75+
}).catch((err) => console.error(err));
76+
} else {
77+
const pusher = pushers.find((p) => p.kind === "email" && p.pushkey === email);
78+
if (pusher) {
79+
cli.removePusher(pusher.pushkey, pusher.app_id).catch((err) => console.error(err));
80+
}
81+
}
82+
refreshThreepids();
83+
refreshPushers();
84+
},
85+
[cli, pushers, refreshPushers, refreshThreepids],
86+
);
87+
88+
const notificationTargets = pushers.filter((it) => it.kind !== "email");
89+
90+
return (
91+
<>
92+
<SettingsSubsection className="mx_NotificationPusherSettings" heading={_t("Email summary")}>
93+
<SettingsSubsectionText className="mx_NotificationPusherSettings_description">
94+
{_t("Receive an email summary of missed notifications")}
95+
</SettingsSubsectionText>
96+
<div className="mx_SettingsSubsection_description mx_NotificationPusherSettings_detail">
97+
<SettingsSubsectionText>
98+
{_t(
99+
"Select which emails you want to send summaries to. Manage your emails in <button>General</button>.",
100+
{},
101+
{ button: generalTabButton },
102+
)}
103+
</SettingsSubsectionText>
104+
</div>
105+
<SettingsIndent>
106+
{threepids
107+
.filter((t) => t.medium === ThreepidMedium.Email)
108+
.map((email) => (
109+
<LabelledCheckbox
110+
key={email.address}
111+
label={email.address}
112+
value={pushers.find((it) => it.pushkey === email.address) !== undefined}
113+
onChange={(value) => setEmailEnabled(email.address, value)}
114+
/>
115+
))}
116+
</SettingsIndent>
117+
</SettingsSubsection>
118+
{notificationTargets.length > 0 && (
119+
<SettingsSubsection heading={_t("Notification targets")}>
120+
<ul>
121+
{pushers
122+
.filter((it) => it.kind !== "email")
123+
.map((pusher) => (
124+
<li key={pusher.pushkey}>{pusher.device_display_name || pusher.app_display_name}</li>
125+
))}
126+
</ul>
127+
</SettingsSubsection>
128+
)}
129+
</>
130+
);
131+
}

0 commit comments

Comments
 (0)