Get placeholder->room logic working
Feels somewhat hacky, but it mostly works with the caveats: - Room names / avatars bleed between rooms when there are updates. - Clicking on a room doesn't immediately highlight it on the list
This commit is contained in:
parent
cc69fc099d
commit
1b6d9db7cd
6 changed files with 52 additions and 11 deletions
|
@ -33,8 +33,7 @@ export class LeftPanelViewModel extends ViewModel {
|
||||||
this._sync = sync;
|
this._sync = sync;
|
||||||
const sync3List = new Sync3ObservableList(sync, rooms);
|
const sync3List = new Sync3ObservableList(sync, rooms);
|
||||||
const list = new ConcatList(invites.sortValues((a,b) => a.compare(b)), sync3List);
|
const list = new ConcatList(invites.sortValues((a,b) => a.compare(b)), sync3List);
|
||||||
this._tileViewModelsMap = this._mapTileViewModels(list);
|
this._tileViewModels = this._mapTileViewModels(list);
|
||||||
this._tileViewModels = this._tileViewModelsMap;
|
|
||||||
this._currentTileVM = null;
|
this._currentTileVM = null;
|
||||||
this._setupNavigation();
|
this._setupNavigation();
|
||||||
this._closeUrl = this.urlCreator.urlForSegment("session");
|
this._closeUrl = this.urlCreator.urlForSegment("session");
|
||||||
|
@ -106,8 +105,21 @@ export class LeftPanelViewModel extends ViewModel {
|
||||||
this._currentTileVM?.close();
|
this._currentTileVM?.close();
|
||||||
this._currentTileVM = null;
|
this._currentTileVM = null;
|
||||||
if (roomId) {
|
if (roomId) {
|
||||||
this._currentTileVM = this._tileViewModelsMap.get(roomId);
|
// find the vm for the room. Previously we used a map to do this but sync3 only gives
|
||||||
this._currentTileVM?.open();
|
// us a list. We could've re-mapped things in the observable pipeline but we don't need
|
||||||
|
// these values to be kept up-to-date when a O(n) search on click isn't particularly
|
||||||
|
// expensive.
|
||||||
|
let targetVM;
|
||||||
|
for ( let vm of this._tileViewModels ) {
|
||||||
|
if (vm.id === roomId) {
|
||||||
|
targetVM = vm;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetVM) {
|
||||||
|
this._currentTileVM = targetVM;
|
||||||
|
this._currentTileVM?.open();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,10 @@ export class RoomTileViewModel extends BaseTileViewModel {
|
||||||
return this._url;
|
return this._url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get id() {
|
||||||
|
return this._room.id;
|
||||||
|
}
|
||||||
|
|
||||||
compare(other) {
|
compare(other) {
|
||||||
return this._compareFn(this._room.id, other._room.id);
|
return this._compareFn(this._room.id, other._room.id);
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,7 @@ export class Sync3 {
|
||||||
this.status = new ObservableValue(SyncStatus.Stopped);
|
this.status = new ObservableValue(SyncStatus.Stopped);
|
||||||
this.error = null;
|
this.error = null;
|
||||||
// Hydrogen only has 1 list currently (no DM section) so we only need 1 range
|
// Hydrogen only has 1 list currently (no DM section) so we only need 1 range
|
||||||
this.ranges = [[0, 4]];
|
this.ranges = [[0, 49]];
|
||||||
this.roomIndexToRoomId = {};
|
this.roomIndexToRoomId = {};
|
||||||
this.roomIdToRoomIndex = {};
|
this.roomIdToRoomIndex = {};
|
||||||
this.totalRooms = 0;
|
this.totalRooms = 0;
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { BaseObservableList } from "./BaseObservableList";
|
||||||
import { findAndUpdateInArray } from "./common";
|
import { findAndUpdateInArray } from "./common";
|
||||||
|
|
||||||
export type Mapper<F, T> = (value: F) => T
|
export type Mapper<F, T> = (value: F) => T
|
||||||
export type Updater<F, T> = (mappedValue: T, params: any, value: F) => void;
|
export type Updater<F, T> = (mappedValue: T, params: any, value: F) => any;
|
||||||
|
|
||||||
export class BaseMappedList<F, T, R = T> extends BaseObservableList<T> {
|
export class BaseMappedList<F, T, R = T> extends BaseObservableList<T> {
|
||||||
protected _sourceList: BaseObservableList<F>;
|
protected _sourceList: BaseObservableList<F>;
|
||||||
|
@ -56,10 +56,21 @@ export function runAdd<F, T, R>(list: BaseMappedList<F, T, R>, index: number, ma
|
||||||
}
|
}
|
||||||
|
|
||||||
export function runUpdate<F, T, R>(list: BaseMappedList<F, T, R>, index: number, value: F, params: any): void {
|
export function runUpdate<F, T, R>(list: BaseMappedList<F, T, R>, index: number, value: F, params: any): void {
|
||||||
const mappedValue = list._mappedValues![index];
|
let mappedValue = list._mappedValues![index];
|
||||||
if (list._updater) {
|
if (list._updater) {
|
||||||
list._updater(mappedValue, params, value);
|
// allow updates to completely remap the underlying data type
|
||||||
|
// TODO: do we need to unsubscribe from anything here?
|
||||||
|
let newMappedValue = list._updater(mappedValue, params, value);
|
||||||
|
if (newMappedValue) {
|
||||||
|
if (!params) {
|
||||||
|
params = {};
|
||||||
|
}
|
||||||
|
params.oldValue = mappedValue;
|
||||||
|
mappedValue = newMappedValue;
|
||||||
|
list._mappedValues![index] = mappedValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// pass the new updated value down the chain
|
||||||
list.emitUpdate(index, mappedValue, params);
|
list.emitUpdate(index, mappedValue, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { IView } from "./types";
|
||||||
export interface IOptions<T, V> extends IParentOptions<T, V> {
|
export interface IOptions<T, V> extends IParentOptions<T, V> {
|
||||||
itemHeight: number;
|
itemHeight: number;
|
||||||
overflowItems?: number;
|
overflowItems?: number;
|
||||||
|
shouldRecreateItem?: (value: any, oldValue: any) => boolean;
|
||||||
onRangeVisible?: (range: ListRange) => void;
|
onRangeVisible?: (range: ListRange) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,15 +34,17 @@ export class LazyListView<T, V extends IView> extends ListView<T, V> {
|
||||||
private overflowItems: number;
|
private overflowItems: number;
|
||||||
private scrollContainer?: HTMLElement;
|
private scrollContainer?: HTMLElement;
|
||||||
private onRangeVisible?: (range: ListRange) => void;
|
private onRangeVisible?: (range: ListRange) => void;
|
||||||
|
private shouldRecreateItem?: (value: any, oldValue: any) => boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
{ itemHeight, onRangeVisible, overflowItems = 20, ...options }: IOptions<T, V>,
|
{ itemHeight, onRangeVisible, shouldRecreateItem, overflowItems = 20, ...options }: IOptions<T, V>,
|
||||||
childCreator: (value: T) => V
|
childCreator: (value: T) => V
|
||||||
) {
|
) {
|
||||||
super(options, childCreator);
|
super(options, childCreator);
|
||||||
this.itemHeight = itemHeight;
|
this.itemHeight = itemHeight;
|
||||||
this.overflowItems = overflowItems;
|
this.overflowItems = overflowItems;
|
||||||
this.onRangeVisible = onRangeVisible; // function(ItemRange)
|
this.onRangeVisible = onRangeVisible;
|
||||||
|
this.shouldRecreateItem = shouldRecreateItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEvent(e: Event) {
|
handleEvent(e: Event) {
|
||||||
|
@ -190,7 +193,11 @@ export class LazyListView<T, V extends IView> extends ListView<T, V> {
|
||||||
|
|
||||||
onUpdate(i: number, value: T, params: any) {
|
onUpdate(i: number, value: T, params: any) {
|
||||||
if (this.renderRange!.containsIndex(i)) {
|
if (this.renderRange!.containsIndex(i)) {
|
||||||
this.updateChild(this.renderRange!.toLocalIndex(i), value, params);
|
if (this.shouldRecreateItem && this.shouldRecreateItem(value, params?.oldValue)) {
|
||||||
|
super.recreateItem(this.renderRange!.toLocalIndex(i), value);
|
||||||
|
} else {
|
||||||
|
this.updateChild(this.renderRange!.toLocalIndex(i), value, params);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ import {TemplateView} from "../../general/TemplateView";
|
||||||
import {RoomTileView} from "./RoomTileView.js";
|
import {RoomTileView} from "./RoomTileView.js";
|
||||||
import {InviteTileView} from "./InviteTileView.js";
|
import {InviteTileView} from "./InviteTileView.js";
|
||||||
import { PlaceholderRoomTileView } from "./PlaceholderRoomTileView";
|
import { PlaceholderRoomTileView } from "./PlaceholderRoomTileView";
|
||||||
|
import { PlaceholderRoomTileViewModel } from "../../../../../domain/session/leftpanel/PlaceholderRoomTileViewModel";
|
||||||
|
import { RoomTileViewModel } from "../../../../../domain/session/leftpanel/RoomTileViewModel";
|
||||||
|
|
||||||
class FilterField extends TemplateView {
|
class FilterField extends TemplateView {
|
||||||
render(t, options) {
|
render(t, options) {
|
||||||
|
@ -67,6 +69,11 @@ export class LeftPanelView extends TemplateView {
|
||||||
onRangeVisible: (range) => {
|
onRangeVisible: (range) => {
|
||||||
vm.loadRoomRange(range);
|
vm.loadRoomRange(range);
|
||||||
},
|
},
|
||||||
|
shouldRecreateItem: (value, oldValue) => {
|
||||||
|
const isOldRoom = oldValue instanceof RoomTileViewModel;
|
||||||
|
const isNewRoom = value instanceof RoomTileViewModel;
|
||||||
|
return isOldRoom != isNewRoom;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
tileVM => {
|
tileVM => {
|
||||||
if (tileVM.kind === "invite") {
|
if (tileVM.kind === "invite") {
|
||||||
|
|
Reference in a new issue