diff --git a/res/css/views/rooms/_IRCLayout.scss b/res/css/views/rooms/_IRCLayout.scss index b4ad117573..814a614007 100644 --- a/res/css/views/rooms/_IRCLayout.scss +++ b/res/css/views/rooms/_IRCLayout.scss @@ -121,8 +121,8 @@ $irc-line-height: $font-18px; } } - .mx_EvenTile_line .mx_MessageActionBar, - .mx_EvenTile_line .mx_ReplyThread_wrapper { + .mx_EventTile_line .mx_MessageActionBar, + .mx_EventTile_line .mx_ReplyThread_wrapper { display: block; } diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss index 0756e98782..044b5e2240 100644 --- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss @@ -15,11 +15,16 @@ limitations under the License. */ .mx_AppearanceUserSettingsTab_fontSlider, -.mx_AppearanceUserSettingsTab_themeSection .mx_Field, -.mx_AppearanceUserSettingsTab_fontScaling .mx_Field { +.mx_AppearanceUserSettingsTab_fontSlider_preview, +.mx_AppearanceUserSettingsTab_Layout, +.mx_AppearanceUserSettingsTab .mx_Field { @mixin mx_Settings_fullWidthField; } +.mx_AppearanceUserSettingsTab_fontScaling { + color: $primary-fg-color; +} + .mx_AppearanceUserSettingsTab_fontSlider { display: flex; flex-direction: row; @@ -32,6 +37,21 @@ limitations under the License. margin-bottom: 24px; } +.mx_AppearanceUserSettingsTab_fontSlider_preview { + border: 1px solid $input-darker-bg-color; + border-radius: 10px; + padding: 0 16px 9px 16px; + pointer-events: none; + + .mx_EventTile_msgOption { + display: none; + } + + &.mx_IRCLayout { + padding-top: 9px; + } +} + .mx_AppearanceUserSettingsTab_fontSlider_smallText { font-size: 15px; padding-right: 20px; @@ -124,3 +144,58 @@ limitations under the License. .mx_SettingsTab_customFontSizeField { margin-left: calc($font-16px + 10px); } + +.mx_AppearanceUserSettingsTab_Layout_RadioButtons { + display: flex; + flex-direction: row; + + color: $primary-fg-color; + + .mx_AppearanceUserSettingsTab_spacer { + width: 24px; + } + + > .mx_AppearanceUserSettingsTab_Layout_RadioButton { + flex-grow: 0; + flex-shrink: 1; + display: flex; + flex-direction: column; + + width: 300px; + + border: 1px solid $input-darker-bg-color; + border-radius: 10px; + + .mx_EventTile_msgOption { + display: none; + } + + .mx_AppearanceUserSettingsTab_Layout_RadioButton_preview { + flex-grow: 1; + display: flex; + align-items: center; + padding: 10px; + } + + .mx_RadioButton { + flex-grow: 0; + padding: 10px; + } + + .mx_EventTile_content { + margin-right: 0; + } + } + + .mx_RadioButton { + border-top: 1px solid $input-darker-bg-color; + + > input + div { + border-color: rgba($muted-fg-color, 0.2); + } + } + + .mx_RadioButton_checked { + background-color: rgba($accent-color, 0.08); + } +} diff --git a/src/components/structures/RoomView.js b/src/components/structures/RoomView.js index b73f2d2cde..19f1cccebd 100644 --- a/src/components/structures/RoomView.js +++ b/src/components/structures/RoomView.js @@ -166,7 +166,7 @@ export default createReactClass({ canReact: false, canReply: false, - useIRCLayout: SettingsStore.getValue("feature_irc_ui"), + useIRCLayout: SettingsStore.getValue("useIRCLayout"), matrixClientIsReady: this.context && this.context.isInitialSyncComplete(), }; @@ -199,7 +199,7 @@ export default createReactClass({ this._roomView = createRef(); this._searchResultsPanel = createRef(); - this._layoutWatcherRef = SettingsStore.watchSetting("feature_irc_ui", null, this.onLayoutChange); + this._layoutWatcherRef = SettingsStore.watchSetting("useIRCLayout", null, this.onLayoutChange); }, _onReadReceiptsChange: function() { @@ -546,7 +546,7 @@ export default createReactClass({ onLayoutChange: function() { this.setState({ - useIRCLayout: SettingsStore.getValue("feature_irc_ui"), + useIRCLayout: SettingsStore.getValue("useIRCLayout"), }); }, diff --git a/src/components/views/elements/EventTilePreview.tsx b/src/components/views/elements/EventTilePreview.tsx new file mode 100644 index 0000000000..fa600196e5 --- /dev/null +++ b/src/components/views/elements/EventTilePreview.tsx @@ -0,0 +1,129 @@ +/* +Copyright 2020 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 React from 'react'; +import classnames from 'classnames'; +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; + +import * as Avatar from '../../../Avatar'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; +import EventTile from '../rooms/EventTile'; + +interface IProps { + /** + * The text to be displayed in the message preview + */ + message: string; + + /** + * Whether to use the irc layout or not + */ + useIRCLayout: boolean; + + /** + * classnames to apply to the wrapper of the preview + */ + className: string; +} + +interface IState { + userId: string; + displayname: string; + avatar_url: string; +} + +const AVATAR_SIZE = 32; + +export default class EventTilePreview extends React.Component { + constructor(props: IProps) { + super(props); + + this.state = { + userId: "@erim:fink.fink", + displayname: "Erimayas Fink", + avatar_url: null, + }; + } + + async componentDidMount() { + // Fetch current user data + const client = MatrixClientPeg.get(); + const userId = client.getUserId(); + const profileInfo = await client.getProfileInfo(userId); + const avatar_url = Avatar.avatarUrlForUser( + {avatarUrl: profileInfo.avatar_url}, + AVATAR_SIZE, AVATAR_SIZE, "crop"); + + this.setState({ + userId, + displayname: profileInfo.displayname, + avatar_url, + }); + + } + + private fakeEvent({userId, displayname, avatar_url}: IState) { + // Fake it till we make it + const event = new MatrixEvent(JSON.parse(`{ + "type": "m.room.message", + "sender": "${userId}", + "content": { + "m.new_content": { + "msgtype": "m.text", + "body": "${this.props.message}", + "displayname": "${displayname}", + "avatar_url": "${avatar_url}" + }, + "msgtype": "m.text", + "body": "${this.props.message}", + "displayname": "${displayname}", + "avatar_url": "${avatar_url}" + }, + "unsigned": { + "age": 97 + }, + "event_id": "$9999999999999999999999999999999999999999999", + "room_id": "!999999999999999999:matrix.org" + }`)); + + // Fake it more + event.sender = { + name: displayname, + userId: userId, + getAvatarUrl: (..._) => { + return avatar_url; + }, + }; + + + } + + public render() { + const event = this.fakeEvent(this.state); + + let className = classnames( + this.props.className, + { + "mx_IRCLayout": this.props.useIRCLayout, + "mx_GroupLayout": !this.props.useIRCLayout, + } + ); + + return
+ +
; + } +} diff --git a/src/components/views/elements/StyledRadioButton.tsx b/src/components/views/elements/StyledRadioButton.tsx index 0ea786d953..d7ae4d5af8 100644 --- a/src/components/views/elements/StyledRadioButton.tsx +++ b/src/components/views/elements/StyledRadioButton.tsx @@ -36,6 +36,7 @@ export default class StyledRadioButton extends React.PureComponent diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx index 7867852c1d..46723ec7cd 100644 --- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx @@ -19,7 +19,6 @@ limitations under the License. import React from 'react'; import {_t} from "../../../../../languageHandler"; import SettingsStore, {SettingLevel} from "../../../../../settings/SettingsStore"; -import * as sdk from "../../../../../index"; import { enumerateThemes } from "../../../../../theme"; import ThemeWatcher from "../../../../../settings/watchers/ThemeWatcher"; import Field from "../../../elements/Field"; @@ -30,6 +29,10 @@ import { FontWatcher } from "../../../../../settings/watchers/FontWatcher"; import { RecheckThemePayload } from '../../../../../dispatcher/payloads/RecheckThemePayload'; import { Action } from '../../../../../dispatcher/actions'; import { IValidationResult, IFieldState } from '../../../elements/Validation'; +import StyledRadioButton from '../../../elements/StyledRadioButton'; +import StyledCheckbox from '../../../elements/StyledCheckbox'; +import SettingsFlag from '../../../elements/SettingsFlag'; +import EventTilePreview from '../../../elements/EventTilePreview'; interface IProps { } @@ -52,9 +55,12 @@ interface IState extends IThemeState { customThemeUrl: string; customThemeMessage: CustomThemeMessage; useCustomFontSize: boolean; + useIRCLayout: boolean; } + export default class AppearanceUserSettingsTab extends React.Component { + private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!"); private themeTimer: NodeJS.Timeout; @@ -67,6 +73,7 @@ export default class AppearanceUserSettingsTab extends React.Component): void => { + const val = e.target.value === "true"; + this.setState({ + useIRCLayout: val, + }); + + SettingsStore.setValue("useIRCLayout", null, SettingLevel.DEVICE, val); + }; + + private renderThemeSection() { const themeWatcher = new ThemeWatcher(); let systemThemeSection: JSX.Element; if (themeWatcher.isSystemThemeSupported()) { @@ -263,7 +276,7 @@ export default class AppearanceUserSettingsTab extends React.Component + {_t("Font size")} +
Aa
Aa
+ this.setState({useCustomFontSize: checked})} useCheckbox={true} /> + ; } + private renderLayoutSection = () => { + return
+ {_t("Message layout")} + +
+
+ + + {_t("Compact")} + +
+
+
+ + + {_t("Modern")} + +
+
+
; + }; + render() { return (
@@ -323,6 +383,7 @@ export default class AppearanceUserSettingsTab extends React.Component {this.renderThemeSection()} {SettingsStore.isFeatureEnabled("feature_font_scaling") ? this.renderFontSection() : null} + {SettingsStore.isFeatureEnabled("feature_irc_ui") ? this.renderLayoutSection() : null}
); } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 50de4e102f..646f43af33 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -435,10 +435,10 @@ "Try out new ways to ignore people (experimental)": "Try out new ways to ignore people (experimental)", "Use the improved room list (will refresh to apply changes)": "Use the improved room list (will refresh to apply changes)", "Support adding custom themes": "Support adding custom themes", - "Use IRC layout": "Use IRC layout", + "Enable IRC layout option in the appearance tab": "Enable IRC layout option in the appearance tab", "Show info about bridges in room settings": "Show info about bridges in room settings", "Font size": "Font size", - "Custom font size": "Custom font size", + "Use custom size": "Use custom size", "Enable Emoji suggestions while typing": "Enable Emoji suggestions while typing", "Use compact timeline layout": "Use compact timeline layout", "Show a placeholder for removed messages": "Show a placeholder for removed messages", @@ -483,6 +483,7 @@ "How fast should messages be downloaded.": "How fast should messages be downloaded.", "Manually verify all remote sessions": "Manually verify all remote sessions", "IRC display name width": "IRC display name width", + "Use IRC layout": "Use IRC layout", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", "Uploading report": "Uploading report", @@ -770,6 +771,7 @@ "Downloading update...": "Downloading update...", "New version available. Update now.": "New version available. Update now.", "Check for update": "Check for update", + "Hey you. You're the best!": "Hey you. You're the best!", "Size must be a number": "Size must be a number", "Custom font size can only be between %(min)s pt and %(max)s pt": "Custom font size can only be between %(min)s pt and %(max)s pt", "Use between %(min)s pt and %(max)s pt": "Use between %(min)s pt and %(max)s pt", @@ -779,6 +781,9 @@ "Custom theme URL": "Custom theme URL", "Add theme": "Add theme", "Theme": "Theme", + "Message layout": "Message layout", + "Compact": "Compact", + "Modern": "Modern", "Customise your appearance": "Customise your appearance", "Appearance Settings only affect this Riot session.": "Appearance Settings only affect this Riot session.", "Flair": "Flair", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 5715909da3..ca8647e067 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -153,7 +153,7 @@ export const SETTINGS = { }, "feature_irc_ui": { supportedLevels: LEVELS_ACCOUNT_SETTINGS, - displayName: _td('Use IRC layout'), + displayName: _td('Enable IRC layout option in the appearance tab'), default: false, isFeature: true, }, @@ -178,7 +178,7 @@ export const SETTINGS = { controller: new FontSizeController(), }, "useCustomFontSize": { - displayName: _td("Custom font size"), + displayName: _td("Use custom size"), supportedLevels: LEVELS_ACCOUNT_SETTINGS, default: false, }, @@ -545,4 +545,9 @@ export const SETTINGS = { displayName: _td("IRC display name width"), default: 80, }, + "useIRCLayout": { + supportedLevels: LEVELS_ACCOUNT_SETTINGS, + displayName: _td("Use IRC layout"), + default: false, + }, };