Merge remote-tracking branch 'origin/develop' into element
commit
b50c809d35
|
@ -48,15 +48,15 @@ limitations under the License.
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_NotificationBadge_2char {
|
&.mx_NotificationBadge_2char {
|
||||||
width: 16px;
|
width: $font-16px;
|
||||||
height: 16px;
|
height: $font-16px;
|
||||||
border-radius: 16px;
|
border-radius: $font-16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.mx_NotificationBadge_3char {
|
&.mx_NotificationBadge_3char {
|
||||||
width: 26px;
|
width: $font-26px;
|
||||||
height: 16px;
|
height: $font-16px;
|
||||||
border-radius: 16px;
|
border-radius: $font-16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following is the floating badge
|
// The following is the floating badge
|
||||||
|
|
|
@ -198,6 +198,8 @@ limitations under the License.
|
||||||
// as the box model should be top aligned. Happens in both FF and Chromium
|
// as the box model should be top aligned. Happens in both FF and Chromium
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
mask-image: linear-gradient(0deg, transparent, black 3px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_RoomSublist2_resizerHandles_showNButton {
|
.mx_RoomSublist2_resizerHandles_showNButton {
|
||||||
|
|
|
@ -137,9 +137,10 @@ export default class RoomSublist2 extends React.Component<IProps, IState> {
|
||||||
let padding = RESIZE_HANDLE_HEIGHT;
|
let padding = RESIZE_HANDLE_HEIGHT;
|
||||||
// this is used for calculating the max height of the whole container,
|
// this is used for calculating the max height of the whole container,
|
||||||
// and takes into account whether there should be room reserved for the show less button
|
// and takes into account whether there should be room reserved for the show less button
|
||||||
// when fully expanded. Note that the show more button might still be shown when not fully expanded,
|
// when fully expanded. We cannot check against the layout's defaultVisible tile count
|
||||||
// but in this case it will take the space of a tile and we don't need to reserve space for it.
|
// because there are conditions in which we need to know that the 'show more' button
|
||||||
if (this.numTiles > this.layout.defaultVisibleTiles) {
|
// is present while well under the default tile limit.
|
||||||
|
if (this.numTiles > this.numVisibleTiles) {
|
||||||
padding += SHOW_N_BUTTON_HEIGHT;
|
padding += SHOW_N_BUTTON_HEIGHT;
|
||||||
}
|
}
|
||||||
return padding;
|
return padding;
|
||||||
|
|
|
@ -30,10 +30,10 @@ import { TagWatcher } from "./TagWatcher";
|
||||||
import RoomViewStore from "../RoomViewStore";
|
import RoomViewStore from "../RoomViewStore";
|
||||||
import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm";
|
import { Algorithm, LIST_UPDATED_EVENT } from "./algorithms/Algorithm";
|
||||||
import { EffectiveMembership, getEffectiveMembership } from "./membership";
|
import { EffectiveMembership, getEffectiveMembership } from "./membership";
|
||||||
import { ListLayout } from "./ListLayout";
|
|
||||||
import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
|
import { isNullOrUndefined } from "matrix-js-sdk/src/utils";
|
||||||
import RoomListLayoutStore from "./RoomListLayoutStore";
|
import RoomListLayoutStore from "./RoomListLayoutStore";
|
||||||
import { MarkedExecution } from "../../utils/MarkedExecution";
|
import { MarkedExecution } from "../../utils/MarkedExecution";
|
||||||
|
import { AsyncStoreWithClient } from "../AsyncStoreWithClient";
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
tagsEnabled?: boolean;
|
tagsEnabled?: boolean;
|
||||||
|
@ -45,14 +45,13 @@ interface IState {
|
||||||
*/
|
*/
|
||||||
export const LISTS_UPDATE_EVENT = "lists_update";
|
export const LISTS_UPDATE_EVENT = "lists_update";
|
||||||
|
|
||||||
export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
export class RoomListStore2 extends AsyncStoreWithClient<ActionPayload> {
|
||||||
/**
|
/**
|
||||||
* Set to true if you're running tests on the store. Should not be touched in
|
* Set to true if you're running tests on the store. Should not be touched in
|
||||||
* any other environment.
|
* any other environment.
|
||||||
*/
|
*/
|
||||||
public static TEST_MODE = false;
|
public static TEST_MODE = false;
|
||||||
|
|
||||||
private _matrixClient: MatrixClient;
|
|
||||||
private initialListsGenerated = false;
|
private initialListsGenerated = false;
|
||||||
private enabled = false;
|
private enabled = false;
|
||||||
private algorithm = new Algorithm();
|
private algorithm = new Algorithm();
|
||||||
|
@ -80,7 +79,7 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public get matrixClient(): MatrixClient {
|
public get matrixClient(): MatrixClient {
|
||||||
return this._matrixClient;
|
return super.matrixClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intended for test usage
|
// Intended for test usage
|
||||||
|
@ -89,23 +88,28 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
this.tagWatcher = new TagWatcher(this);
|
this.tagWatcher = new TagWatcher(this);
|
||||||
this.filterConditions = [];
|
this.filterConditions = [];
|
||||||
this.initialListsGenerated = false;
|
this.initialListsGenerated = false;
|
||||||
this._matrixClient = null;
|
|
||||||
|
|
||||||
this.algorithm.off(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
|
this.algorithm.off(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
|
||||||
this.algorithm.off(FILTER_CHANGED, this.onAlgorithmListUpdated);
|
this.algorithm.off(FILTER_CHANGED, this.onAlgorithmListUpdated);
|
||||||
this.algorithm = new Algorithm();
|
this.algorithm = new Algorithm();
|
||||||
this.algorithm.on(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
|
this.algorithm.on(LIST_UPDATED_EVENT, this.onAlgorithmListUpdated);
|
||||||
this.algorithm.on(FILTER_CHANGED, this.onAlgorithmListUpdated);
|
this.algorithm.on(FILTER_CHANGED, this.onAlgorithmListUpdated);
|
||||||
|
|
||||||
|
// Reset state without causing updates as the client will have been destroyed
|
||||||
|
// and downstream code will throw NPE errors.
|
||||||
|
await this.reset(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public for test usage. Do not call this.
|
// Public for test usage. Do not call this.
|
||||||
public async makeReady(client: MatrixClient) {
|
public async makeReady(forcedClient?: MatrixClient) {
|
||||||
|
if (forcedClient) {
|
||||||
|
super.matrixClient = forcedClient;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Remove with https://github.com/vector-im/riot-web/issues/14367
|
// TODO: Remove with https://github.com/vector-im/riot-web/issues/14367
|
||||||
this.checkEnabled();
|
this.checkEnabled();
|
||||||
if (!this.enabled) return;
|
if (!this.enabled) return;
|
||||||
|
|
||||||
this._matrixClient = client;
|
|
||||||
|
|
||||||
// Update any settings here, as some may have happened before we were logically ready.
|
// Update any settings here, as some may have happened before we were logically ready.
|
||||||
// Update any settings here, as some may have happened before we were logically ready.
|
// Update any settings here, as some may have happened before we were logically ready.
|
||||||
console.log("Regenerating room lists: Startup");
|
console.log("Regenerating room lists: Startup");
|
||||||
|
@ -162,7 +166,15 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
if (trigger) this.updateFn.trigger();
|
if (trigger) this.updateFn.trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async onDispatch(payload: ActionPayload) {
|
protected async onReady(): Promise<any> {
|
||||||
|
await this.makeReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onNotReady(): Promise<any> {
|
||||||
|
await this.resetStore();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onAction(payload: ActionPayload) {
|
||||||
// When we're running tests we can't reliably use setImmediate out of timing concerns.
|
// When we're running tests we can't reliably use setImmediate out of timing concerns.
|
||||||
// As such, we use a more synchronous model.
|
// As such, we use a more synchronous model.
|
||||||
if (RoomListStore2.TEST_MODE) {
|
if (RoomListStore2.TEST_MODE) {
|
||||||
|
@ -176,29 +188,10 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async onDispatchAsync(payload: ActionPayload) {
|
protected async onDispatchAsync(payload: ActionPayload) {
|
||||||
if (payload.action === 'MatrixActions.sync') {
|
|
||||||
// Filter out anything that isn't the first PREPARED sync.
|
|
||||||
if (!(payload.prevState === 'PREPARED' && payload.state !== 'PREPARED')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.makeReady(payload.matrixClient);
|
|
||||||
|
|
||||||
return; // no point in running the next conditions - they won't match
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Remove this once the RoomListStore becomes default
|
// TODO: Remove this once the RoomListStore becomes default
|
||||||
if (!this.enabled) return;
|
if (!this.enabled) return;
|
||||||
|
|
||||||
if (payload.action === 'on_client_not_viable' || payload.action === 'on_logged_out') {
|
// Everything here requires a MatrixClient or some sort of logical readiness.
|
||||||
// Reset state without causing updates as the client will have been destroyed
|
|
||||||
// and downstream code will throw NPE errors.
|
|
||||||
await this.reset(null, true);
|
|
||||||
this._matrixClient = null;
|
|
||||||
this.initialListsGenerated = false; // we'll want to regenerate them
|
|
||||||
}
|
|
||||||
|
|
||||||
// Everything below here requires a MatrixClient or some sort of logical readiness.
|
|
||||||
const logicallyReady = this.matrixClient && this.initialListsGenerated;
|
const logicallyReady = this.matrixClient && this.initialListsGenerated;
|
||||||
if (!logicallyReady) return;
|
if (!logicallyReady) return;
|
||||||
|
|
||||||
|
@ -425,7 +418,8 @@ export class RoomListStore2 extends AsyncStore<ActionPayload> {
|
||||||
|
|
||||||
// logic must match calculateListOrder
|
// logic must match calculateListOrder
|
||||||
private calculateTagSorting(tagId: TagID): SortAlgorithm {
|
private calculateTagSorting(tagId: TagID): SortAlgorithm {
|
||||||
const defaultSort = SortAlgorithm.Alphabetic;
|
const isDefaultRecent = tagId === DefaultTagID.Invite || tagId === DefaultTagID.DM;
|
||||||
|
const defaultSort = isDefaultRecent ? SortAlgorithm.Recent : SortAlgorithm.Alphabetic;
|
||||||
const settingAlphabetical = SettingsStore.getValue("RoomList.orderAlphabetically", null, true);
|
const settingAlphabetical = SettingsStore.getValue("RoomList.orderAlphabetically", null, true);
|
||||||
const definedSort = this.getTagSorting(tagId);
|
const definedSort = this.getTagSorting(tagId);
|
||||||
const storedSort = this.getStoredTagSorting(tagId);
|
const storedSort = this.getStoredTagSorting(tagId);
|
||||||
|
|
|
@ -698,8 +698,8 @@ export class Algorithm extends EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cause === RoomUpdateCause.PossibleTagChange) {
|
|
||||||
let didTagChange = false;
|
let didTagChange = false;
|
||||||
|
if (cause === RoomUpdateCause.PossibleTagChange) {
|
||||||
const oldTags = this.roomIdsToTags[room.roomId] || [];
|
const oldTags = this.roomIdsToTags[room.roomId] || [];
|
||||||
const newTags = this.getTagsForRoom(room);
|
const newTags = this.getTagsForRoom(room);
|
||||||
const diff = arrayDiff(oldTags, newTags);
|
const diff = arrayDiff(oldTags, newTags);
|
||||||
|
@ -713,6 +713,11 @@ export class Algorithm extends EventEmitter {
|
||||||
if (!algorithm) throw new Error(`No algorithm for ${rmTag}`);
|
if (!algorithm) throw new Error(`No algorithm for ${rmTag}`);
|
||||||
await algorithm.handleRoomUpdate(room, RoomUpdateCause.RoomRemoved);
|
await algorithm.handleRoomUpdate(room, RoomUpdateCause.RoomRemoved);
|
||||||
this.cachedRooms[rmTag] = algorithm.orderedRooms;
|
this.cachedRooms[rmTag] = algorithm.orderedRooms;
|
||||||
|
|
||||||
|
// Later on we won't update the filtered rooms or sticky room for removed
|
||||||
|
// tags, so do so now.
|
||||||
|
this.recalculateFilteredRoomsForTag(rmTag);
|
||||||
|
this.recalculateStickyRoom(rmTag);
|
||||||
}
|
}
|
||||||
for (const addTag of diff.added) {
|
for (const addTag of diff.added) {
|
||||||
if (!window.mx_QuietRoomListLogging) {
|
if (!window.mx_QuietRoomListLogging) {
|
||||||
|
@ -812,7 +817,7 @@ export class Algorithm extends EventEmitter {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let changed = false;
|
let changed = didTagChange;
|
||||||
for (const tag of tags) {
|
for (const tag of tags) {
|
||||||
const algorithm: OrderingAlgorithm = this.algorithms[tag];
|
const algorithm: OrderingAlgorithm = this.algorithms[tag];
|
||||||
if (!algorithm) throw new Error(`No algorithm for ${tag}`);
|
if (!algorithm) throw new Error(`No algorithm for ${tag}`);
|
||||||
|
|
|
@ -38,7 +38,11 @@ export class RecentAlgorithm implements IAlgorithm {
|
||||||
// actually changed (probably needs to be done higher up?) then we could do an
|
// actually changed (probably needs to be done higher up?) then we could do an
|
||||||
// insertion sort or similar on the limited set of changes.
|
// insertion sort or similar on the limited set of changes.
|
||||||
|
|
||||||
const myUserId = MatrixClientPeg.get().getUserId();
|
// TODO: Don't assume we're using the same client as the peg
|
||||||
|
let myUserId = '';
|
||||||
|
if (MatrixClientPeg.get()) {
|
||||||
|
myUserId = MatrixClientPeg.get().getUserId();
|
||||||
|
}
|
||||||
|
|
||||||
const tsCache: { [roomId: string]: number } = {};
|
const tsCache: { [roomId: string]: number } = {};
|
||||||
const getLastTs = (r: Room) => {
|
const getLastTs = (r: Room) => {
|
||||||
|
@ -68,7 +72,6 @@ export class RecentAlgorithm implements IAlgorithm {
|
||||||
const ev = r.timeline[i];
|
const ev = r.timeline[i];
|
||||||
if (!ev.getTs()) continue; // skip events that don't have timestamps (tests only?)
|
if (!ev.getTs()) continue; // skip events that don't have timestamps (tests only?)
|
||||||
|
|
||||||
// TODO: Don't assume we're using the same client as the peg
|
|
||||||
if (ev.getSender() === myUserId || Unread.eventTriggersUnreadCount(ev)) {
|
if (ev.getSender() === myUserId || Unread.eventTriggersUnreadCount(ev)) {
|
||||||
return ev.getTs();
|
return ev.getTs();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue