Support custom tags in the new algorithm
parent
e083d50e31
commit
3d152da822
|
@ -52,7 +52,6 @@ export default class AccountSettingsHandler extends MatrixClientBackedSettingsHa
|
||||||
} else if (event.getType() === "im.vector.web.settings") {
|
} else if (event.getType() === "im.vector.web.settings") {
|
||||||
// We can't really discern what changed, so trigger updates for everything
|
// We can't really discern what changed, so trigger updates for everything
|
||||||
for (const settingName of Object.keys(event.getContent())) {
|
for (const settingName of Object.keys(event.getContent())) {
|
||||||
console.log(settingName);
|
|
||||||
this._watchers.notifyUpdate(settingName, null, event.getContent()[settingName]);
|
this._watchers.notifyUpdate(settingName, null, event.getContent()[settingName]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ class RoomListStore extends Store {
|
||||||
* behave.
|
* behave.
|
||||||
* @param {boolean} forceRegeneration True to force a change in the algorithm
|
* @param {boolean} forceRegeneration True to force a change in the algorithm
|
||||||
*/
|
*/
|
||||||
updateSortingAlgorithm(forceRegeneration=false) {
|
updateSortingAlgorithm(forceRegeneration = false) {
|
||||||
const byImportance = SettingsStore.getValue("RoomList.orderByImportance");
|
const byImportance = SettingsStore.getValue("RoomList.orderByImportance");
|
||||||
if (byImportance !== this._state.orderRoomsByImportance || forceRegeneration) {
|
if (byImportance !== this._state.orderRoomsByImportance || forceRegeneration) {
|
||||||
console.log("Updating room sorting algorithm: sortByImportance=" + byImportance);
|
console.log("Updating room sorting algorithm: sortByImportance=" + byImportance);
|
||||||
|
@ -119,8 +119,15 @@ class RoomListStore extends Store {
|
||||||
const logicallyReady = this._matrixClient && this._state.ready;
|
const logicallyReady = this._matrixClient && this._state.ready;
|
||||||
switch (payload.action) {
|
switch (payload.action) {
|
||||||
case 'setting_updated': {
|
case 'setting_updated': {
|
||||||
if (payload.settingName !== 'RoomList.orderByImportance') break;
|
if (payload.settingName === 'RoomList.orderByImportance') {
|
||||||
this.updateSortingAlgorithm();
|
this.updateSortingAlgorithm();
|
||||||
|
} else if (payload.settingName === 'feature_custom_tags') {
|
||||||
|
const isActive = SettingsStore.isFeatureEnabled("feature_custom_tags");
|
||||||
|
if (isActive !== this._state.tagsEnabled) {
|
||||||
|
this._setState({tagsEnabled: isActive});
|
||||||
|
this.updateSortingAlgorithm(/*force=*/true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// Initialise state after initial sync
|
// Initialise state after initial sync
|
||||||
|
@ -129,6 +136,8 @@ class RoomListStore extends Store {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._setState({tagsEnabled: SettingsStore.isFeatureEnabled("feature_custom_tags")});
|
||||||
|
|
||||||
this._matrixClient = payload.matrixClient;
|
this._matrixClient = payload.matrixClient;
|
||||||
this.updateSortingAlgorithm(/*force=*/true);
|
this.updateSortingAlgorithm(/*force=*/true);
|
||||||
}
|
}
|
||||||
|
@ -269,14 +278,19 @@ class RoomListStore extends Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_filterTags(tags) {
|
||||||
|
tags = tags ? Object.keys(tags) : [];
|
||||||
|
if (this._state.tagsEnabled) return tags;
|
||||||
|
return tags.filter((t) => !!LIST_ORDERS[t]);
|
||||||
|
}
|
||||||
|
|
||||||
_getRecommendedTagsForRoom(room) {
|
_getRecommendedTagsForRoom(room) {
|
||||||
const tags = [];
|
const tags = [];
|
||||||
|
|
||||||
const myMembership = room.getMyMembership();
|
const myMembership = room.getMyMembership();
|
||||||
if (myMembership === 'join' || myMembership === 'invite') {
|
if (myMembership === 'join' || myMembership === 'invite') {
|
||||||
// Stack the user's tags on top
|
// Stack the user's tags on top
|
||||||
// TODO: Consider whether tags are enabled at all
|
tags.push(...this._filterTags(room.tags));
|
||||||
tags.push(...(room.tags || []));
|
|
||||||
|
|
||||||
const dmRoomMap = DMRoomMap.shared();
|
const dmRoomMap = DMRoomMap.shared();
|
||||||
if (dmRoomMap.getUserIdForRoomId(room.roomId)) {
|
if (dmRoomMap.getUserIdForRoomId(room.roomId)) {
|
||||||
|
@ -328,84 +342,83 @@ class RoomListStore extends Store {
|
||||||
// Speed optimization: Don't do complicated math if we don't have to.
|
// Speed optimization: Don't do complicated math if we don't have to.
|
||||||
if (!shouldHaveRoom) {
|
if (!shouldHaveRoom) {
|
||||||
listsClone[key] = this._state.lists[key].filter((e) => e.room.roomId !== room.roomId);
|
listsClone[key] = this._state.lists[key].filter((e) => e.room.roomId !== room.roomId);
|
||||||
|
} else if (LIST_ORDERS[key] !== 'recent') {
|
||||||
|
// Manually ordered tags are sorted later, so for now we'll just clone the tag
|
||||||
|
// and add our room if needed
|
||||||
|
listsClone[key] = this._state.lists[key].filter((e) => e.room.roomId !== room.roomId);
|
||||||
|
listsClone[key].push({room, category});
|
||||||
|
insertedIntoTags.push(key);
|
||||||
} else {
|
} else {
|
||||||
listsClone[key] = [];
|
listsClone[key] = [];
|
||||||
|
|
||||||
// Tags sorted by recents are more complicated than manually ordered tags, so hope
|
// We track where the boundary within listsClone[key] is just in case our timestamp
|
||||||
// for the best.
|
// ordering fails. If we can't stick the room in at the correct place in the category
|
||||||
// TODO: Use the SettingsStore watcher to determine if tags are enabled or not
|
// grouping based on timestamp, we'll stick it at the top of the group which will be
|
||||||
if (LIST_ORDERS[key] !== 'recent') {
|
// the index we track here.
|
||||||
// TODO: Actually insert the room
|
let desiredCategoryBoundaryIndex = 0;
|
||||||
} else {
|
let foundBoundary = false;
|
||||||
// We track where the boundary within listsClone[key] is just in case our timestamp
|
let pushedEntry = false;
|
||||||
// ordering fails. If we can't stick the room in at the correct place in the category
|
|
||||||
// grouping based on timestamp, we'll stick it at the top of the group which will be
|
|
||||||
// the index we track here.
|
|
||||||
let desiredCategoryBoundaryIndex = 0;
|
|
||||||
let foundBoundary = false;
|
|
||||||
let pushedEntry = false;
|
|
||||||
|
|
||||||
for (const entry of this._state.lists[key]) {
|
for (const entry of this._state.lists[key]) {
|
||||||
// We insert our own record as needed, so don't let the old one through.
|
// We insert our own record as needed, so don't let the old one through.
|
||||||
if (entry.room.roomId === room.roomId) {
|
if (entry.room.roomId === room.roomId) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
// if the list is a recent list, and the room appears in this list, and we're
|
|
||||||
// not looking at a sticky room (sticky rooms have unreliable categories), try
|
|
||||||
// to slot the new room in
|
|
||||||
if (entry.room.roomId !== this._state.stickyRoomId) {
|
|
||||||
if (!pushedEntry && shouldHaveRoom) {
|
|
||||||
// Micro optimization: Support lazily loading the last timestamp in a room
|
|
||||||
let _entryTimestamp = null;
|
|
||||||
const entryTimestamp = () => {
|
|
||||||
if (_entryTimestamp === null) {
|
|
||||||
_entryTimestamp = this._tsOfNewestEvent(entry.room);
|
|
||||||
}
|
|
||||||
return _entryTimestamp;
|
|
||||||
};
|
|
||||||
|
|
||||||
const entryCategoryIndex = CATEGORY_ORDER.indexOf(entry.category);
|
|
||||||
|
|
||||||
// As per above, check if we're meeting that boundary we wanted to locate.
|
|
||||||
if (entryCategoryIndex >= targetCategoryIndex && !foundBoundary) {
|
|
||||||
desiredCategoryBoundaryIndex = listsClone[key].length - 1;
|
|
||||||
foundBoundary = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we've hit the top of a boundary beyond our target category, insert at the top of
|
|
||||||
// the grouping to ensure the room isn't slotted incorrectly. Otherwise, try to insert
|
|
||||||
// based on most recent timestamp.
|
|
||||||
const changedBoundary = entryCategoryIndex > targetCategoryIndex;
|
|
||||||
const currentCategory = entryCategoryIndex === targetCategoryIndex;
|
|
||||||
if (changedBoundary || (currentCategory && targetTimestamp() >= entryTimestamp())) {
|
|
||||||
if (changedBoundary) {
|
|
||||||
// If we changed a boundary, then we've gone too far - go to the top of the last
|
|
||||||
// section instead.
|
|
||||||
listsClone[key].splice(desiredCategoryBoundaryIndex, 0, {room, category});
|
|
||||||
} else {
|
|
||||||
// If we're ordering by timestamp, just insert normally
|
|
||||||
listsClone[key].push({room, category});
|
|
||||||
}
|
|
||||||
pushedEntry = true;
|
|
||||||
insertedIntoTags.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall through and clone the list.
|
|
||||||
listsClone[key].push(entry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pushedEntry) {
|
// if the list is a recent list, and the room appears in this list, and we're
|
||||||
if (listsClone[key].length === 0) {
|
// not looking at a sticky room (sticky rooms have unreliable categories), try
|
||||||
listsClone[key].push({room, category});
|
// to slot the new room in
|
||||||
insertedIntoTags.push(key);
|
if (entry.room.roomId !== this._state.stickyRoomId) {
|
||||||
} else {
|
if (!pushedEntry && shouldHaveRoom) {
|
||||||
// In theory, this should never happen
|
// Micro optimization: Support lazily loading the last timestamp in a room
|
||||||
console.warn(`!! Room ${room.roomId} lost: No position available`);
|
let _entryTimestamp = null;
|
||||||
|
const entryTimestamp = () => {
|
||||||
|
if (_entryTimestamp === null) {
|
||||||
|
_entryTimestamp = this._tsOfNewestEvent(entry.room);
|
||||||
|
}
|
||||||
|
return _entryTimestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
const entryCategoryIndex = CATEGORY_ORDER.indexOf(entry.category);
|
||||||
|
|
||||||
|
// As per above, check if we're meeting that boundary we wanted to locate.
|
||||||
|
if (entryCategoryIndex >= targetCategoryIndex && !foundBoundary) {
|
||||||
|
desiredCategoryBoundaryIndex = listsClone[key].length - 1;
|
||||||
|
foundBoundary = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've hit the top of a boundary beyond our target category, insert at the top of
|
||||||
|
// the grouping to ensure the room isn't slotted incorrectly. Otherwise, try to insert
|
||||||
|
// based on most recent timestamp.
|
||||||
|
const changedBoundary = entryCategoryIndex > targetCategoryIndex;
|
||||||
|
const currentCategory = entryCategoryIndex === targetCategoryIndex;
|
||||||
|
if (changedBoundary || (currentCategory && targetTimestamp() >= entryTimestamp())) {
|
||||||
|
if (changedBoundary) {
|
||||||
|
// If we changed a boundary, then we've gone too far - go to the top of the last
|
||||||
|
// section instead.
|
||||||
|
listsClone[key].splice(desiredCategoryBoundaryIndex, 0, {room, category});
|
||||||
|
} else {
|
||||||
|
// If we're ordering by timestamp, just insert normally
|
||||||
|
listsClone[key].push({room, category});
|
||||||
|
}
|
||||||
|
pushedEntry = true;
|
||||||
|
insertedIntoTags.push(key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fall through and clone the list.
|
||||||
|
listsClone[key].push(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pushedEntry) {
|
||||||
|
if (listsClone[key].length === 0) {
|
||||||
|
listsClone[key].push({room, category});
|
||||||
|
insertedIntoTags.push(key);
|
||||||
|
} else {
|
||||||
|
// In theory, this should never happen
|
||||||
|
console.warn(`!! Room ${room.roomId} lost: No position available`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,6 +435,12 @@ class RoomListStore extends Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sort the favourites before we set the clone
|
||||||
|
for (const tag of Object.keys(listsClone)) {
|
||||||
|
if (LIST_ORDERS[tag] === 'recent') continue; // skip recents (pre-sorted)
|
||||||
|
listsClone[tag].sort(this._getManualComparator(tag));
|
||||||
|
}
|
||||||
|
|
||||||
this._setState({lists: listsClone});
|
this._setState({lists: listsClone});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue