Build out a store for the right panel state machine

This should make it easier to funnel the expected behaviour through a central block of code.
This commit is contained in:
Travis Ralston 2019-12-05 15:31:01 -07:00
parent 625e3ef93a
commit 5253f29928
4 changed files with 175 additions and 13 deletions

View file

@ -1,9 +1,9 @@
/*
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2017 New Vector Ltd
Copyright 2018 New Vector Ltd
Copyright 2017, 2018 New Vector Ltd
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -28,6 +28,7 @@ import RateLimitedFunc from '../../ratelimitedfunc';
import { showGroupInviteDialog, showGroupAddRoomDialog } from '../../GroupAddressPicker';
import GroupStore from '../../stores/GroupStore';
import SettingsStore from "../../settings/SettingsStore";
import {RIGHT_PANEL_PHASES} from "../../stores/RightPanelStore";
export default class RightPanel extends React.Component {
static get propTypes() {
@ -44,17 +45,7 @@ export default class RightPanel extends React.Component {
};
}
static Phase = Object.freeze({
RoomMemberList: 'RoomMemberList',
GroupMemberList: 'GroupMemberList',
GroupRoomList: 'GroupRoomList',
GroupRoomInfo: 'GroupRoomInfo',
FilePanel: 'FilePanel',
NotificationPanel: 'NotificationPanel',
RoomMemberInfo: 'RoomMemberInfo',
Room3pidMemberInfo: 'Room3pidMemberInfo',
GroupMemberInfo: 'GroupMemberInfo',
});
static Phase = RIGHT_PANEL_PHASES;
constructor(props, context) {
super(props, context);

View file

@ -1,6 +1,7 @@
/*
Copyright 2017 Travis Ralston
Copyright 2018, 2019 New Vector Ltd.
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -24,6 +25,8 @@ import {
import CustomStatusController from "./controllers/CustomStatusController";
import ThemeController from './controllers/ThemeController';
import ReloadOnChangeController from "./controllers/ReloadOnChangeController";
import RightPanel from "../components/structures/RightPanel";
import {RIGHT_PANEL_PHASES} from "../stores/RightPanelStore";
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
const LEVELS_ROOM_SETTINGS = ['device', 'room-device', 'room-account', 'account', 'config'];
@ -463,4 +466,20 @@ export const SETTINGS = {
displayName: _td("Show previews/thumbnails for images"),
default: true,
},
"showRightPanelInRoom": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: false,
},
"showRightPanelInGroup": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: false,
},
"lastRightPanelPhaseForRoom": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: RIGHT_PANEL_PHASES.RoomMemberInfo,
},
"lastRightPanelPhaseForGroup": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: RIGHT_PANEL_PHASES.GroupMemberList,
},
};

View file

@ -1,6 +1,7 @@
/*
Copyright 2017 Travis Ralston
Copyright 2019 New Vector Ltd.
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -56,6 +57,17 @@ export default class DeviceSettingsHandler extends SettingsHandler {
return null; // wrong type or otherwise not set
}
// Special case the right panel - see `setValue` for rationale.
if ([
"showRightPanelInRoom",
"showRightPanelInGroup",
"lastRightPanelPhaseForRoom",
"lastRightPanelPhaseForGroup",
].includes(settingName)) {
const val = JSON.parse(localStorage.getItem(`mx_${settingName}`) || "{}");
return val['value'];
}
const settings = this._getSettings() || {};
return settings[settingName];
}
@ -81,6 +93,20 @@ export default class DeviceSettingsHandler extends SettingsHandler {
return Promise.resolve();
}
// Special case the right panel because we want to be able to update these all
// concurrently without stomping on one another. We could use async/await, though
// that introduces just enough latency to be annoying.
if ([
"showRightPanelInRoom",
"showRightPanelInGroup",
"lastRightPanelPhaseForRoom",
"lastRightPanelPhaseForGroup",
].includes(settingName)) {
localStorage.setItem(`mx_${settingName}`, JSON.stringify({value: newValue}));
this._watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue);
return Promise.resolve();
}
const settings = this._getSettings() || {};
settings[settingName] = newValue;
localStorage.setItem("mx_local_settings", JSON.stringify(settings));

View file

@ -0,0 +1,126 @@
/*
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import dis from '../dispatcher';
import {Store} from 'flux/utils';
import SettingsStore, {SettingLevel} from "../settings/SettingsStore";
const INITIAL_STATE = {
// Whether or not to show the right panel at all. We split out rooms and groups
// because they're different flows for the user to follow.
showRoomPanel: SettingsStore.getValue("showRightPanelInRoom"),
showGroupPanel: SettingsStore.getValue("showRightPanelInGroup"),
// The last phase (screen) the right panel was showing
lastRoomPhase: SettingsStore.getValue("lastRightPanelPhaseForRoom"),
lastGroupPhase: SettingsStore.getValue("lastRightPanelPhaseForGroup"),
};
export const RIGHT_PANEL_PHASES = Object.freeze({
// Room stuff
RoomMemberList: 'RoomMemberList',
FilePanel: 'FilePanel',
NotificationPanel: 'NotificationPanel',
RoomMemberInfo: 'RoomMemberInfo',
Room3pidMemberInfo: 'Room3pidMemberInfo',
// Group stuff
GroupMemberList: 'GroupMemberList',
GroupRoomList: 'GroupRoomList',
GroupRoomInfo: 'GroupRoomInfo',
GroupMemberInfo: 'GroupMemberInfo',
});
const GROUP_PHASES = Object.keys(RIGHT_PANEL_PHASES).filter(k => k.startsWith("Group"));
/**
* A class for tracking the state of the right panel between layouts and
* sessions.
*/
export default class RightPanelStore extends Store {
static _instance;
constructor() {
super(dis);
// Initialise state
this._state = INITIAL_STATE;
}
get isOpenForRoom(): boolean {
return this._state.showRoomPanel;
}
get isOpenForGroup(): boolean {
return this._state.showGroupPanel;
}
get roomPanelPhase(): string {
return this._state.lastRoomPhase;
}
get groupPanelPhase(): string {
return this._state.lastGroupPhase;
}
_setState(newState) {
this._state = Object.assign(this._state, newState);
SettingsStore.setValue("showRightPanelInRoom", null, SettingLevel.DEVICE, this._state.showRoomPanel);
SettingsStore.setValue("showRightPanelInGroup", null, SettingLevel.DEVICE, this._state.showGroupPanel);
SettingsStore.setValue("lastRightPanelPhaseForRoom", null, SettingLevel.DEVICE, this._state.lastRoomPhase);
SettingsStore.setValue("lastRightPanelPhaseForGroup", null, SettingLevel.DEVICE, this._state.lastGroupPhase);
this.__emitChange();
}
__onDispatch(payload) {
if (payload.action !== 'set_right_panel_phase') return;
const targetPhase = payload.phase;
if (!RIGHT_PANEL_PHASES[targetPhase]) {
console.warn(`Tried to switch right panel to unknown phase: ${targetPhase}`);
return;
}
if (GROUP_PHASES.includes(targetPhase)) {
if (targetPhase === this._state.lastGroupPhase) {
this._setState({
showGroupPanel: !this._state.showGroupPanel,
});
} else {
this._setState({
lastGroupPhase: targetPhase,
});
}
} else {
if (targetPhase === this._state.lastRoomPhase) {
this._setState({
showRoomPanel: !this._state.showRoomPanel,
});
} else {
this._setState({
lastRoomPhase: targetPhase,
});
}
}
}
static getSharedInstance(): RightPanelStore {
if (!RightPanelStore._instance) {
RightPanelStore._instance = new RightPanelStore();
}
return RightPanelStore._instance;
}
}