Sync breadcrumb rooms through account data

Fixes https://github.com/vector-im/riot-web/issues/9315

Other clients would need to listen for and update im.vector.riot.breadcrumb_rooms in account data.
This commit is contained in:
Travis Ralston 2019-04-04 15:06:03 -06:00
parent 37afa9fc0e
commit 44198ea97d
3 changed files with 94 additions and 24 deletions

View file

@ -24,6 +24,7 @@ import classNames from 'classnames';
import sdk from "../../../index"; import sdk from "../../../index";
import * as RoomNotifs from '../../../RoomNotifs'; import * as RoomNotifs from '../../../RoomNotifs';
import * as FormattingUtils from "../../../utils/FormattingUtils"; import * as FormattingUtils from "../../../utils/FormattingUtils";
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
const MAX_ROOMS = 20; const MAX_ROOMS = 20;
@ -38,22 +39,22 @@ export default class RoomBreadcrumbs extends React.Component {
componentWillMount() { componentWillMount() {
this._dispatcherRef = dis.register(this.onAction); this._dispatcherRef = dis.register(this.onAction);
let storedRooms = SettingsStore.getValue("breadcrumb_rooms");
if (!storedRooms || !storedRooms.length) {
// Fallback to the rooms stored in localstorage for those who would have had this.
// TODO: Remove this after a bit - the feature was only on develop, so a few weeks should be plenty time.
const roomStr = localStorage.getItem("mx_breadcrumb_rooms"); const roomStr = localStorage.getItem("mx_breadcrumb_rooms");
if (roomStr) { if (roomStr) {
try { try {
const roomIds = JSON.parse(roomStr); storedRooms = JSON.parse(roomStr);
this.setState({
rooms: roomIds.map((r) => {
return {
room: MatrixClientPeg.get().getRoom(r),
animated: false,
};
}).filter((r) => r.room),
});
} catch (e) { } catch (e) {
console.error("Failed to parse breadcrumbs:", e); console.error("Failed to parse breadcrumbs:", e);
} }
} }
}
this._loadRoomIds(storedRooms || []);
this._settingWatchRef = SettingsStore.watchSetting("breadcrumb_rooms", null, this.onBreadcrumbsChanged);
MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership); MatrixClientPeg.get().on("Room.myMembership", this.onMyMembership);
MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt); MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt);
@ -64,6 +65,8 @@ export default class RoomBreadcrumbs extends React.Component {
componentWillUnmount() { componentWillUnmount() {
dis.unregister(this._dispatcherRef); dis.unregister(this._dispatcherRef);
SettingsStore.unwatchSetting(this._settingWatchRef);
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get();
if (client) { if (client) {
client.removeListener("Room.myMembership", this.onMyMembership); client.removeListener("Room.myMembership", this.onMyMembership);
@ -84,8 +87,8 @@ export default class RoomBreadcrumbs extends React.Component {
} }
} }
const roomStr = JSON.stringify(rooms.map((r) => r.room.roomId)); const roomIds = rooms.map((r) => r.room.roomId);
localStorage.setItem("mx_breadcrumb_rooms", roomStr); SettingsStore.setValue("breadcrumb_rooms", null, SettingLevel.ACCOUNT, roomIds);
} }
onAction(payload) { onAction(payload) {
@ -125,17 +128,48 @@ export default class RoomBreadcrumbs extends React.Component {
} }
}; };
_calculateRoomBadges(room) { onBreadcrumbsChanged = (settingName, roomId, level, valueAtLevel, value) => {
if (!room) return; if (!value) return;
const rooms = this.state.rooms.slice(); const currentState = this.state.rooms.map((r) => r.room.roomId);
const roomModel = rooms.find((r) => r.room.roomId === room.roomId); if (currentState.length === value.length) {
if (!roomModel) return; // No applicable room, so don't do math on it let changed = false;
for (let i = 0; i < currentState.length; i++) {
if (currentState[i] !== value[i]) {
changed = true;
break;
}
}
if (!changed) return;
}
this._loadRoomIds(value);
};
_loadRoomIds(roomIds) {
// If we're here, the list changed.
const rooms = roomIds.map((r) => MatrixClientPeg.get().getRoom(r)).filter((r) => r).map((r) => {
const badges = this._calculateBadgesForRoom(r) || {};
return {
room: r,
animated: false,
...badges,
};
});
this.setState({
rooms: rooms,
});
}
_calculateBadgesForRoom(room) {
if (!room) return null;
// Reset the notification variables for simplicity // Reset the notification variables for simplicity
roomModel.redBadge = false; const roomModel = {
roomModel.formattedCount = "0"; redBadge: false,
roomModel.showCount = false; formattedCount: "0",
showCount: false,
};
const notifState = RoomNotifs.getRoomNotifsState(room.roomId); const notifState = RoomNotifs.getRoomNotifsState(room.roomId);
if (RoomNotifs.MENTION_BADGE_STATES.includes(notifState)) { if (RoomNotifs.MENTION_BADGE_STATES.includes(notifState)) {
@ -155,6 +189,20 @@ export default class RoomBreadcrumbs extends React.Component {
} }
} }
return roomModel;
}
_calculateRoomBadges(room) {
if (!room) return;
const rooms = this.state.rooms.slice();
const roomModel = rooms.find((r) => r.room.roomId === room.roomId);
if (!roomModel) return; // No applicable room, so don't do math on it
const badges = this._calculateBadgesForRoom(room);
if (!badges) return; // No badges for some reason
Object.assign(roomModel, badges);
this.setState({rooms}); this.setState({rooms});
} }

View file

@ -258,6 +258,10 @@ export const SETTINGS = {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
default: "en", default: "en",
}, },
"breadcrumb_rooms": {
supportedLevels: ['account'],
default: [],
},
"analyticsOptIn": { "analyticsOptIn": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG, supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS_WITH_CONFIG,
displayName: _td('Send analytics data'), displayName: _td('Send analytics data'),

View file

@ -19,6 +19,8 @@ import MatrixClientPeg from '../../MatrixClientPeg';
import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler"; import MatrixClientBackedSettingsHandler from "./MatrixClientBackedSettingsHandler";
import {SettingLevel} from "../SettingsStore"; import {SettingLevel} from "../SettingsStore";
const BREADCRUMBS_EVENT_TYPE = "im.vector.riot.breadcrumb_rooms";
/** /**
* Gets and sets settings at the "account" level for the current user. * Gets and sets settings at the "account" level for the current user.
* This handler does not make use of the roomId parameter. * This handler does not make use of the roomId parameter.
@ -55,6 +57,9 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
const val = event.getContent()[settingName]; const val = event.getContent()[settingName];
this._watchers.notifyUpdate(settingName, null, SettingLevel.ACCOUNT, val); this._watchers.notifyUpdate(settingName, null, SettingLevel.ACCOUNT, val);
} }
} else if (event.getType() === BREADCRUMBS_EVENT_TYPE) {
const val = event.getContent()['rooms'] || [];
this._watchers.notifyUpdate("breadcrumb_rooms", null, SettingLevel.ACCOUNT, val);
} }
} }
@ -68,6 +73,12 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
return !content['disable']; return !content['disable'];
} }
// Special case for breadcrumbs
if (settingName === "breadcrumb_rooms") {
const content = this._getSettings(BREADCRUMBS_EVENT_TYPE) || {};
return content['rooms'] || [];
}
const settings = this._getSettings() || {}; const settings = this._getSettings() || {};
let preferredValue = settings[settingName]; let preferredValue = settings[settingName];
@ -89,6 +100,13 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
return MatrixClientPeg.get().setAccountData("org.matrix.preview_urls", content); return MatrixClientPeg.get().setAccountData("org.matrix.preview_urls", content);
} }
// Special case for breadcrumbs
if (settingName === "breadcrumb_rooms") {
const content = this._getSettings(BREADCRUMBS_EVENT_TYPE) || {};
content['rooms'] = newValue;
return MatrixClientPeg.get().setAccountData(BREADCRUMBS_EVENT_TYPE, content);
}
const content = this._getSettings() || {}; const content = this._getSettings() || {};
content[settingName] = newValue; content[settingName] = newValue;
return MatrixClientPeg.get().setAccountData("im.vector.web.settings", content); return MatrixClientPeg.get().setAccountData("im.vector.web.settings", content);