mirror of
https://github.com/element-hq/element-web.git
synced 2024-12-15 07:41:30 +03:00
Add new layout switcher UI
Co-authored-by: Quirin Götz <codeworks@supercable.onl>
This commit is contained in:
parent
97e6599780
commit
ae5cd9d7ac
4 changed files with 137 additions and 11 deletions
|
@ -37,6 +37,8 @@ import StyledRadioGroup from "../../../elements/StyledRadioGroup";
|
||||||
import { SettingLevel } from "../../../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../../../settings/SettingLevel";
|
||||||
import { UIFeature } from "../../../../../settings/UIFeature";
|
import { UIFeature } from "../../../../../settings/UIFeature";
|
||||||
import { Layout } from "../../../../../settings/Layout";
|
import { Layout } from "../../../../../settings/Layout";
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import StyledRadioButton from '../../../elements/StyledRadioButton';
|
||||||
import { replaceableComponent } from "../../../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../../../utils/replaceableComponent";
|
||||||
import { compare } from "../../../../../utils/strings";
|
import { compare } from "../../../../../utils/strings";
|
||||||
|
|
||||||
|
@ -235,6 +237,19 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
||||||
this.setState({customThemeUrl: e.target.value});
|
this.setState({customThemeUrl: e.target.value});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onLayoutChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
|
let layout;
|
||||||
|
switch (e.target.value) {
|
||||||
|
case "irc": layout = Layout.IRC; break;
|
||||||
|
case "group": layout = Layout.Group; break;
|
||||||
|
case "bubble": layout = Layout.Bubble; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({ layout: layout });
|
||||||
|
|
||||||
|
SettingsStore.setValue("layout", null, SettingLevel.DEVICE, layout);
|
||||||
|
};
|
||||||
|
|
||||||
private onIRCLayoutChange = (enabled: boolean) => {
|
private onIRCLayoutChange = (enabled: boolean) => {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
this.setState({layout: Layout.IRC});
|
this.setState({layout: Layout.IRC});
|
||||||
|
@ -367,6 +382,77 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderLayoutSection = () => {
|
||||||
|
return <div className="mx_SettingsTab_section mx_AppearanceUserSettingsTab_Layout">
|
||||||
|
<span className="mx_SettingsTab_subheading">{ _t("Message layout") }</span>
|
||||||
|
|
||||||
|
<div className="mx_AppearanceUserSettingsTab_Layout_RadioButtons">
|
||||||
|
<div className={classNames("mx_AppearanceUserSettingsTab_Layout_RadioButton", {
|
||||||
|
mx_AppearanceUserSettingsTab_Layout_RadioButton_selected: this.state.layout == Layout.IRC,
|
||||||
|
})}>
|
||||||
|
<EventTilePreview
|
||||||
|
className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
|
||||||
|
message={this.MESSAGE_PREVIEW_TEXT}
|
||||||
|
layout={Layout.IRC}
|
||||||
|
userId={this.state.userId}
|
||||||
|
displayName={this.state.displayName}
|
||||||
|
avatarUrl={this.state.avatarUrl}
|
||||||
|
/>
|
||||||
|
<StyledRadioButton
|
||||||
|
name="layout"
|
||||||
|
value="irc"
|
||||||
|
checked={this.state.layout == Layout.IRC}
|
||||||
|
onChange={this.onLayoutChange}
|
||||||
|
>
|
||||||
|
{ "IRC" }
|
||||||
|
</StyledRadioButton>
|
||||||
|
</div>
|
||||||
|
<div className="mx_AppearanceUserSettingsTab_spacer" />
|
||||||
|
<div className={classNames("mx_AppearanceUserSettingsTab_Layout_RadioButton", {
|
||||||
|
mx_AppearanceUserSettingsTab_Layout_RadioButton_selected: this.state.layout == Layout.Group,
|
||||||
|
})}>
|
||||||
|
<EventTilePreview
|
||||||
|
className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
|
||||||
|
message={this.MESSAGE_PREVIEW_TEXT}
|
||||||
|
layout={Layout.Group}
|
||||||
|
userId={this.state.userId}
|
||||||
|
displayName={this.state.displayName}
|
||||||
|
avatarUrl={this.state.avatarUrl}
|
||||||
|
/>
|
||||||
|
<StyledRadioButton
|
||||||
|
name="layout"
|
||||||
|
value="group"
|
||||||
|
checked={this.state.layout == Layout.Group}
|
||||||
|
onChange={this.onLayoutChange}
|
||||||
|
>
|
||||||
|
{_t("Modern")}
|
||||||
|
</StyledRadioButton>
|
||||||
|
</div>
|
||||||
|
<div className="mx_AppearanceUserSettingsTab_spacer" />
|
||||||
|
<div className={classNames("mx_AppearanceUserSettingsTab_Layout_RadioButton", {
|
||||||
|
mx_AppearanceUserSettingsTab_Layout_RadioButton_selected: this.state.layout == Layout.Bubble,
|
||||||
|
})}>
|
||||||
|
<EventTilePreview
|
||||||
|
className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
|
||||||
|
message={this.MESSAGE_PREVIEW_TEXT}
|
||||||
|
layout={Layout.Bubble}
|
||||||
|
userId={this.state.userId}
|
||||||
|
displayName={this.state.displayName}
|
||||||
|
avatarUrl={this.state.avatarUrl}
|
||||||
|
/>
|
||||||
|
<StyledRadioButton
|
||||||
|
name="layout"
|
||||||
|
value="bubble"
|
||||||
|
checked={this.state.layout == Layout.Bubble}
|
||||||
|
onChange={this.onLayoutChange}
|
||||||
|
>
|
||||||
|
{_t("Message bubbles")}
|
||||||
|
</StyledRadioButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
private renderAdvancedSection() {
|
private renderAdvancedSection() {
|
||||||
if (!SettingsStore.getValue(UIFeature.AdvancedSettings)) return null;
|
if (!SettingsStore.getValue(UIFeature.AdvancedSettings)) return null;
|
||||||
|
|
||||||
|
@ -390,14 +476,17 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
||||||
name="useCompactLayout"
|
name="useCompactLayout"
|
||||||
level={SettingLevel.DEVICE}
|
level={SettingLevel.DEVICE}
|
||||||
useCheckbox={true}
|
useCheckbox={true}
|
||||||
disabled={this.state.layout == Layout.IRC}
|
disabled={this.state.layout !== Layout.Group}
|
||||||
/>
|
/>
|
||||||
<StyledCheckbox
|
|
||||||
checked={this.state.layout == Layout.IRC}
|
{ !SettingsStore.getValue("feature_new_layout_switcher") ?
|
||||||
onChange={(ev) => this.onIRCLayoutChange(ev.target.checked)}
|
<StyledCheckbox
|
||||||
>
|
checked={this.state.layout == Layout.IRC}
|
||||||
{_t("Enable experimental, compact IRC style layout")}
|
onChange={(ev) => this.onIRCLayoutChange(ev.target.checked)}
|
||||||
</StyledCheckbox>
|
>
|
||||||
|
{_t("Enable experimental, compact IRC style layout")}
|
||||||
|
</StyledCheckbox> : null
|
||||||
|
}
|
||||||
|
|
||||||
<SettingsFlag
|
<SettingsFlag
|
||||||
name="useSystemFont"
|
name="useSystemFont"
|
||||||
|
@ -437,9 +526,10 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
||||||
<div className="mx_SettingsTab_SubHeading">
|
<div className="mx_SettingsTab_SubHeading">
|
||||||
{_t("Appearance Settings only affect this %(brand)s session.", { brand })}
|
{_t("Appearance Settings only affect this %(brand)s session.", { brand })}
|
||||||
</div>
|
</div>
|
||||||
{this.renderThemeSection()}
|
{ this.renderThemeSection() }
|
||||||
{this.renderFontSection()}
|
{ SettingsStore.getValue("feature_new_layout_switcher") ? this.renderLayoutSection() : null }
|
||||||
{this.renderAdvancedSection()}
|
{ this.renderFontSection() }
|
||||||
|
{ this.renderAdvancedSection() }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>
|
||||||
|
Copyright 2021 Quirin Götz <codeworks@supercable.onl>
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
@ -19,7 +20,8 @@ import PropTypes from 'prop-types';
|
||||||
/* TODO: This should be later reworked into something more generic */
|
/* TODO: This should be later reworked into something more generic */
|
||||||
export enum Layout {
|
export enum Layout {
|
||||||
IRC = "irc",
|
IRC = "irc",
|
||||||
Group = "group"
|
Group = "group",
|
||||||
|
Bubble = "bubble",
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need this because multiple components are still using JavaScript */
|
/* We need this because multiple components are still using JavaScript */
|
||||||
|
|
|
@ -41,6 +41,7 @@ import { Layout } from "./Layout";
|
||||||
import ReducedMotionController from './controllers/ReducedMotionController';
|
import ReducedMotionController from './controllers/ReducedMotionController';
|
||||||
import IncompatibleController from "./controllers/IncompatibleController";
|
import IncompatibleController from "./controllers/IncompatibleController";
|
||||||
import SdkConfig from "../SdkConfig";
|
import SdkConfig from "../SdkConfig";
|
||||||
|
import NewLayoutSwitcherController from './controllers/NewLayoutSwitcherController';
|
||||||
|
|
||||||
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
|
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
|
||||||
const LEVELS_ROOM_SETTINGS = [
|
const LEVELS_ROOM_SETTINGS = [
|
||||||
|
@ -285,6 +286,13 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
||||||
displayName: _td("Show info about bridges in room settings"),
|
displayName: _td("Show info about bridges in room settings"),
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
"feature_new_layout_switcher": {
|
||||||
|
isFeature: true,
|
||||||
|
supportedLevels: LEVELS_FEATURE,
|
||||||
|
displayName: _td("Explore new ways switching layouts (including a new bubble layout)"),
|
||||||
|
default: false,
|
||||||
|
controller: new NewLayoutSwitcherController(),
|
||||||
|
},
|
||||||
"RoomList.backgroundImage": {
|
"RoomList.backgroundImage": {
|
||||||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||||
default: null,
|
default: null,
|
||||||
|
|
26
src/settings/controllers/NewLayoutSwitcherController.ts
Normal file
26
src/settings/controllers/NewLayoutSwitcherController.ts
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 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 SettingController from "./SettingController";
|
||||||
|
import { SettingLevel } from "../SettingLevel";
|
||||||
|
import SettingsStore from "../SettingsStore";
|
||||||
|
import { Layout } from "../Layout";
|
||||||
|
|
||||||
|
export default class NewLayoutSwitcherController extends SettingController {
|
||||||
|
public onChange(level: SettingLevel, roomId: string, newValue: any) {
|
||||||
|
// On disabling switch back to Layout.Group if Layout.Bubble
|
||||||
|
if (!newValue && SettingsStore.getValue("layout") == Layout.Bubble) {
|
||||||
|
SettingsStore.setValue("layout", null, SettingLevel.DEVICE, Layout.Group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue