Merge pull request #8 from vector-im/bwindels/selectactiveroom

Mark active room visually in left panel
This commit is contained in:
Bruno Windels 2020-08-12 15:51:42 +00:00 committed by GitHub
commit 348174f973
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 24 deletions

View file

@ -22,10 +22,10 @@ import {EventEmitter} from "../utils/EventEmitter.js";
import {Disposables} from "../utils/Disposables.js"; import {Disposables} from "../utils/Disposables.js";
export class ViewModel extends EventEmitter { export class ViewModel extends EventEmitter {
constructor({clock} = {}) { constructor({clock, emitChange} = {}) {
super(); super();
this.disposables = null; this.disposables = null;
this._options = {clock}; this._options = {clock, emitChange};
} }
childOptions(explicitOptions) { childOptions(explicitOptions) {
@ -71,8 +71,12 @@ export class ViewModel extends EventEmitter {
} }
emitChange(changedProps) { emitChange(changedProps) {
if (this._options.emitChange) {
this._options.emitChange(changedProps);
} else {
this.emit("change", changedProps); this.emit("change", changedProps);
} }
}
get clock() { get clock() {
return this._options.clock; return this._options.clock;

View file

@ -28,12 +28,13 @@ export class SessionViewModel extends ViewModel {
sync: sessionContainer.sync, sync: sessionContainer.sync,
reconnector: sessionContainer.reconnector reconnector: sessionContainer.reconnector
}))); })));
this._currentRoomTileViewModel = null;
this._currentRoomViewModel = null; this._currentRoomViewModel = null;
const roomTileVMs = this._session.rooms.mapValues((room, emitUpdate) => { const roomTileVMs = this._session.rooms.mapValues((room, emitChange) => {
return new RoomTileViewModel({ return new RoomTileViewModel({
room, room,
emitUpdate, emitChange,
emitOpen: room => this._openRoom(room) emitOpen: this._openRoom.bind(this)
}); });
}); });
this._roomList = roomTileVMs.sortValues((a, b) => a.compare(b)); this._roomList = roomTileVMs.sortValues((a, b) => a.compare(b));
@ -62,7 +63,11 @@ export class SessionViewModel extends ViewModel {
} }
} }
_openRoom(room) { _openRoom(room, roomTileVM) {
if (this._currentRoomTileViewModel) {
this._currentRoomTileViewModel.close();
}
this._currentRoomTileViewModel = roomTileVM;
if (this._currentRoomViewModel) { if (this._currentRoomViewModel) {
this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel); this._currentRoomViewModel = this.disposeTracked(this._currentRoomViewModel);
} }

View file

@ -15,20 +15,33 @@ limitations under the License.
*/ */
import {avatarInitials} from "../avatar.js"; import {avatarInitials} from "../avatar.js";
import {ViewModel} from "../../ViewModel.js";
export class RoomTileViewModel { export class RoomTileViewModel extends ViewModel {
// we use callbacks to parent VM instead of emit because // we use callbacks to parent VM instead of emit because
// it would be annoying to keep track of subscriptions in // it would be annoying to keep track of subscriptions in
// parent for all RoomTileViewModels // parent for all RoomTileViewModels
// emitUpdate is ObservableMap/ObservableList update mechanism // emitUpdate is ObservableMap/ObservableList update mechanism
constructor({room, emitUpdate, emitOpen}) { constructor(options) {
super(options);
const {room, emitOpen} = options;
this._room = room; this._room = room;
this._emitUpdate = emitUpdate;
this._emitOpen = emitOpen; this._emitOpen = emitOpen;
this._isOpen = false;
}
// called by parent for now (later should integrate with router)
close() {
if (this._isOpen) {
this._isOpen = false;
this.emitChange("isOpen");
}
} }
open() { open() {
this._emitOpen(this._room); this._isOpen = true;
this.emitChange("isOpen");
this._emitOpen(this._room, this);
} }
compare(other) { compare(other) {
@ -36,6 +49,10 @@ export class RoomTileViewModel {
return this._room.name.localeCompare(other._room.name); return this._room.name.localeCompare(other._room.name);
} }
get isOpen() {
return this._isOpen;
}
get name() { get name() {
return this._room.name; return this._room.name;
} }

View file

@ -16,7 +16,7 @@ limitations under the License.
import {BaseObservableMap} from "./BaseObservableMap.js"; import {BaseObservableMap} from "./BaseObservableMap.js";
/* /*
so a mapped value can emit updates on it's own with this._updater that is passed in the mapping function so a mapped value can emit updates on it's own with this._emitSpontaneousUpdate that is passed in the mapping function
how should the mapped value be notified of an update though? and can it then decide to not propagate the update? how should the mapped value be notified of an update though? and can it then decide to not propagate the update?
*/ */
export class MappedMap extends BaseObservableMap { export class MappedMap extends BaseObservableMap {
@ -25,14 +25,18 @@ export class MappedMap extends BaseObservableMap {
this._source = source; this._source = source;
this._mapper = mapper; this._mapper = mapper;
this._mappedValues = new Map(); this._mappedValues = new Map();
this._updater = (key, params) => { // this should really be (value, params) but can't make that work for now }
_emitSpontaneousUpdate(key, params) {
const value = this._mappedValues.get(key); const value = this._mappedValues.get(key);
this.onUpdate(key, value, params); if (value) {
}; this.emitUpdate(key, value, params);
}
} }
onAdd(key, value) { onAdd(key, value) {
const mappedValue = this._mapper(value, this._updater); const emitSpontaneousUpdate = this._emitSpontaneousUpdate.bind(this, key);
const mappedValue = this._mapper(value, emitSpontaneousUpdate);
this._mappedValues.set(key, mappedValue); this._mappedValues.set(key, mappedValue);
this.emitAdd(key, mappedValue); this.emitAdd(key, mappedValue);
} }
@ -47,17 +51,16 @@ export class MappedMap extends BaseObservableMap {
onUpdate(key, value, params) { onUpdate(key, value, params) {
const mappedValue = this._mappedValues.get(key); const mappedValue = this._mappedValues.get(key);
if (mappedValue !== undefined) { if (mappedValue !== undefined) {
const newParams = this._updater(value, params); // TODO: map params somehow if needed?
// if (newParams !== undefined) { this.emitUpdate(key, mappedValue, params);
this.emitUpdate(key, mappedValue, newParams);
// }
} }
} }
onSubscribeFirst() { onSubscribeFirst() {
this._subscription = this._source.subscribe(this); this._subscription = this._source.subscribe(this);
for (let [key, value] of this._source) { for (let [key, value] of this._source) {
const mappedValue = this._mapper(value, this._updater); const emitSpontaneousUpdate = this._emitSpontaneousUpdate.bind(this, key);
const mappedValue = this._mapper(value, emitSpontaneousUpdate);
this._mappedValues.set(key, mappedValue); this._mappedValues.set(key, mappedValue);
} }
super.onSubscribeFirst(); super.onSubscribeFirst();

View file

@ -46,6 +46,11 @@ limitations under the License.
align-items: center; align-items: center;
} }
.LeftPanel li.active {
background: lightgray;
color: black;
}
.LeftPanel li { .LeftPanel li {
border-bottom: 1px #555 solid; border-bottom: 1px #555 solid;
} }
@ -66,7 +71,6 @@ a {
color: white; color: white;
} }
.SessionStatusView { .SessionStatusView {
padding: 5px; padding: 5px;
background-color: #555; background-color: #555;

View file

@ -18,7 +18,7 @@ import {TemplateView} from "../general/TemplateView.js";
export class RoomTile extends TemplateView { export class RoomTile extends TemplateView {
render(t) { render(t) {
return t.li([ return t.li({"className": {"active": vm => vm.isOpen}}, [
t.div({className: "avatar medium"}, vm => vm.avatarInitials), t.div({className: "avatar medium"}, vm => vm.avatarInitials),
t.div({className: "description"}, t.div({className: "name"}, vm => vm.name)) t.div({className: "description"}, t.div({className: "name"}, vm => vm.name))
]); ]);