diff --git a/res/css/views/globals/_MatrixToolbar.scss b/res/css/views/globals/_MatrixToolbar.scss
index 1109b9e264..1791d619ae 100644
--- a/res/css/views/globals/_MatrixToolbar.scss
+++ b/res/css/views/globals/_MatrixToolbar.scss
@@ -28,6 +28,12 @@ limitations under the License.
margin-top: -2px;
}
+.mx_MatrixToolbar_info {
+ padding-left: 16px;
+ padding-right: 8px;
+ background-color: $info-bg-color;
+}
+
.mx_MatrixToolbar_error {
padding-left: 16px;
padding-right: 8px;
diff --git a/res/themes/dark/css/_dark.scss b/res/themes/dark/css/_dark.scss
index ad4630d668..8ab338790e 100644
--- a/res/themes/dark/css/_dark.scss
+++ b/res/themes/dark/css/_dark.scss
@@ -20,6 +20,7 @@ $focus-brightness: 200%;
// red warning colour
$warning-color: #ff0064;
$warning-bg-color: #DF2A8B;
+$info-bg-color: #2A9EDF;
// groups
$info-plinth-bg-color: #454545;
diff --git a/res/themes/light/css/_base.scss b/res/themes/light/css/_base.scss
index dedfeaeb2f..7d004bd831 100644
--- a/res/themes/light/css/_base.scss
+++ b/res/themes/light/css/_base.scss
@@ -27,6 +27,7 @@ $focus-brightness: 125%;
$warning-color: #ff0064;
// background colour for warnings
$warning-bg-color: #DF2A8B;
+$info-bg-color: #2A9EDF;
$mention-user-pill-bg-color: #ff0064;
$other-user-pill-bg-color: rgba(0, 0, 0, 0.1);
diff --git a/src/components/structures/LoggedInView.js b/src/components/structures/LoggedInView.js
index 65ef69d547..a6c373f7ef 100644
--- a/src/components/structures/LoggedInView.js
+++ b/src/components/structures/LoggedInView.js
@@ -30,10 +30,16 @@ import dis from '../../dispatcher';
import sessionStore from '../../stores/SessionStore';
import MatrixClientPeg from '../../MatrixClientPeg';
import SettingsStore from "../../settings/SettingsStore";
+import RoomListStore from "../../stores/RoomListStore";
import TagOrderActions from '../../actions/TagOrderActions';
import RoomListActions from '../../actions/RoomListActions';
+// We need to fetch each pinned message individually (if we don't already have it)
+// so each pinned message may trigger a request. Limit the number per room for sanity.
+// NB. this is just for server notices rather than pinned messages in general.
+const MAX_PINNED_NOTICES_PER_ROOM = 2;
+
/**
* This is what our MatrixChat shows when we are logged in. The precise view is
* determined by the page_type property.
@@ -80,6 +86,8 @@ const LoggedInView = React.createClass({
return {
// use compact timeline view
useCompactLayout: SettingsStore.getValue('useCompactLayout'),
+ // any currently active server notice events
+ serverNoticeEvents: [],
};
},
@@ -97,13 +105,18 @@ const LoggedInView = React.createClass({
);
this._setStateFromSessionStore();
+ this._updateServerNoticeEvents();
+
this._matrixClient.on("accountData", this.onAccountData);
this._matrixClient.on("sync", this.onSync);
+ this._matrixClient.on("RoomState.events", this.onRoomStateEvents);
},
componentWillUnmount: function() {
document.removeEventListener('keydown', this._onKeyDown);
this._matrixClient.removeListener("accountData", this.onAccountData);
+ this._matrixClient.removeListener("sync", this.onSync);
+ this._matrixClient.removeListener("RoomState.events", this.onRoomStateEvents);
if (this._sessionStoreToken) {
this._sessionStoreToken.remove();
}
@@ -157,8 +170,42 @@ const LoggedInView = React.createClass({
syncErrorData: null,
});
}
+
+ if (oldSyncState === 'PREPARED' && syncState === 'SYNCING') {
+ this._updateServerNoticeEvents();
+ }
},
+ onRoomStateEvents: function(ev, state) {
+ const roomLists = RoomListStore.getRoomLists();
+ if (roomLists['m.server_notices'] && roomLists['m.server_notices'].includes(ev.getRoomId())) {
+ this._updateServerNoticeEvents();
+ }
+ },
+
+ _updateServerNoticeEvents: async function() {
+ const roomLists = RoomListStore.getRoomLists();
+ if (!roomLists['m.server_notice']) return [];
+
+ const pinnedEvents = [];
+ for (const room of roomLists['m.server_notice']) {
+ const pinStateEvent = room.currentState.getStateEvents("m.room.pinned_events", "");
+
+ if (!pinStateEvent || !pinStateEvent.getContent().pinned) continue;
+
+ const pinnedEventIds = pinStateEvent.getContent().pinned.slice(0, MAX_PINNED_NOTICES_PER_ROOM);
+ for (const eventId of pinnedEventIds) {
+ const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId, 0);
+ const ev = timeline.getEvents().find(ev => ev.getId() === eventId);
+ if (ev) pinnedEvents.push(ev);
+ }
+ }
+ this.setState({
+ serverNoticeEvents: pinnedEvents,
+ });
+ },
+
+
_onKeyDown: function(ev) {
/*
// Remove this for now as ctrl+alt = alt-gr so this breaks keyboards which rely on alt-gr for numbers
@@ -386,10 +433,18 @@ const LoggedInView = React.createClass({
break;
}
+ const mauLimitEvent = this.state.serverNoticeEvents.find((e) => {
+ return e && e.getType() === 'm.server_notice.usage_limit_reached' &&
+ e.getContent().limit &&
+ e.getContent().limit === 'monthly_active_user'
+ });
+
let topBar;
const isGuest = this.props.matrixClient.isGuest();
if (this.state.syncErrorData && this.state.syncErrorData.error.errcode === 'M_MAU_LIMIT_EXCEEDED') {
- topBar =