From 2192332968b600b492d65a677e36984818fccdd3 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens <joriksch@gmail.com>
Date: Tue, 16 Jun 2020 17:55:19 +0100
Subject: [PATCH 1/5] Add layout options to the appearance tab

---
 res/css/views/rooms/_IRCLayout.scss           |  4 +-
 .../tabs/user/_AppearanceUserSettingsTab.scss | 61 +++++++++++++++++++
 src/components/structures/RoomView.js         |  6 +-
 .../views/elements/StyledRadioButton.tsx      |  1 +
 .../tabs/user/AppearanceUserSettingsTab.tsx   | 61 ++++++++++++++++++-
 src/i18n/strings/en_EN.json                   |  6 +-
 src/settings/Settings.js                      |  7 ++-
 7 files changed, 138 insertions(+), 8 deletions(-)

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 14189fc5e1..7fefdd1505 100644
--- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
@@ -16,6 +16,7 @@ limitations under the License.
 
 .mx_AppearanceUserSettingsTab_fontSlider,
 .mx_AppearanceUserSettingsTab_fontSlider_preview,
+.mx_AppearanceUserSettingsTab_Layout,
 .mx_AppearanceUserSettingsTab .mx_Field {
     @mixin mx_Settings_fullWidthField;
 }
@@ -41,6 +42,14 @@ limitations under the License.
     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 {
@@ -135,3 +144,55 @@ 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;
+    }
+
+    .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 ab3da035c4..126ae5d4ce 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/StyledRadioButton.tsx b/src/components/views/elements/StyledRadioButton.tsx
index fdedd16230..6af7549df8 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<IProps, IStat
             {
                 "mx_RadioButton_disabled": disabled,
                 "mx_RadioButton_enabled": !disabled,
+                "mx_RadioButton_checked": this.props.checked,
             });
         return <label className={_className}>
             <input type='radio' disabled={disabled} {...otherProps} />
diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
index 8838979021..0620626181 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
@@ -52,8 +52,11 @@ interface IState extends IThemeState {
     customThemeUrl: string,
     customThemeMessage: CustomThemeMessage,
     useCustomFontSize: boolean,
+    useIRCLayout: boolean,
 }
 
+const MESSAGE_PREVIEW_TEXT = "Hey you. You're the best"
+
 export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> {
 
     private themeTimer: NodeJS.Timeout;
@@ -67,6 +70,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
             customThemeUrl: "",
             customThemeMessage: {isError: false, text: ""},
             useCustomFontSize: SettingsStore.getValue("useCustomFontSize"),
+            useIRCLayout: SettingsStore.getValue("useIRCLayout", null),
         };
     }
 
@@ -197,6 +201,16 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
         this.setState({customThemeUrl: e.target.value});
     };
 
+    private onLayoutChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
+        const val = e.target.value === "true";
+
+        this.setState({
+            useIRCLayout: val,
+        });
+
+        SettingsStore.setValue("useIRCLayout", null, SettingLevel.DEVICE, val);
+    }
+
     private renderThemeSection() {
         const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
         const StyledCheckbox = sdk.getComponent("views.elements.StyledCheckbox");
@@ -287,7 +301,8 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
             <span className="mx_SettingsTab_subheading">{_t("Font size")}</span>
             <MessagePreview
                 className="mx_AppearanceUserSettingsTab_fontSlider_preview"
-                message="Hey you. You're the best"
+                message={MESSAGE_PREVIEW_TEXT}
+                useIRCLayout={this.state.useIRCLayout}
             />
             <div className="mx_AppearanceUserSettingsTab_fontSlider">
                 <div className="mx_AppearanceUserSettingsTab_fontSlider_smallText">Aa</div>
@@ -323,6 +338,49 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
         </div>;
     }
 
+    private renderLayoutSection = () => {
+        const StyledRadioButton = sdk.getComponent("views.elements.StyledRadioButton");
+        const MessagePreview = sdk.getComponent("views.elements.MessagePreview");
+
+        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="mx_AppearanceUserSettingsTab_Layout_RadioButton">
+                    <MessagePreview
+                        className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
+                        message={MESSAGE_PREVIEW_TEXT}
+                        useIRCLayout={true}
+                    />
+                    <StyledRadioButton
+                        name={"layout"}
+                        value={true}
+                        checked={this.state.useIRCLayout}
+                        onChange={this.onLayoutChange}
+                    >
+                        {_t("Compact")}
+                    </StyledRadioButton>
+                </div>
+                <div className="mx_AppearanceUserSettingsTab_spacer" />
+                <div className="mx_AppearanceUserSettingsTab_Layout_RadioButton">
+                    <MessagePreview
+                        className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
+                        message={MESSAGE_PREVIEW_TEXT}
+                        useIRCLayout={false}
+                    />
+                    <StyledRadioButton
+                        name={"layout"}
+                        value={false}
+                        checked={!this.state.useIRCLayout}
+                        onChange={this.onLayoutChange}
+                    >
+                        {_t("Modern")}
+                    </StyledRadioButton>
+                </div>
+            </div>
+        </div>
+    }
+
     render() {
         return (
             <div className="mx_SettingsTab mx_AppearanceUserSettingsTab">
@@ -332,6 +390,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
                 </div>
                 {this.renderThemeSection()}
                 {SettingsStore.isFeatureEnabled("feature_font_scaling") ? this.renderFontSection() : null}
+                {SettingsStore.isFeatureEnabled("feature_irc_ui") ? this.renderLayoutSection() : null}
             </div>
         );
     }
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index aacec471f6..157d83ba57 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -434,7 +434,7 @@
     "Try out new ways to ignore people (experimental)": "Try out new ways to ignore people (experimental)",
     "Use the improved room list (in development - refresh to apply changes)": "Use the improved room list (in development - 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",
     "Use custom size": "Use custom size",
@@ -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",
@@ -779,6 +780,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 b3ee71c767..70e29483a2 100644
--- a/src/settings/Settings.js
+++ b/src/settings/Settings.js
@@ -152,7 +152,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,
     },
@@ -549,4 +549,9 @@ export const SETTINGS = {
         displayName: _td("IRC display name width"),
         default: 80,
     },
+    "useIRCLayout": {
+        supportedLevels: LEVELS_ACCOUNT_SETTINGS,
+        displayName: _td("Use IRC layout"),
+        default: false,
+    },
 };

From 2d6077f2c8a9fe3233e4593ee5b58cf933aa8e2e Mon Sep 17 00:00:00 2001
From: Jorik Schellekens <joriksch@gmail.com>
Date: Tue, 16 Jun 2020 18:02:34 +0100
Subject: [PATCH 2/5] Fix radio circle color

---
 .../views/settings/tabs/user/_AppearanceUserSettingsTab.scss  | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
index 7fefdd1505..b6fe9adccb 100644
--- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
@@ -189,6 +189,10 @@ limitations under the License.
 
     .mx_RadioButton {
         border-top: 1px solid $input-darker-bg-color;
+
+        > input + div {
+            border-color: rgba($muted-fg-color, 0.2);
+        }
     }
 
     .mx_RadioButton_checked {

From a250bf6a971be00c582687af2db823ffcd4cedc5 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens <joriksch@gmail.com>
Date: Tue, 16 Jun 2020 18:08:49 +0100
Subject: [PATCH 3/5] Fix whitespace

---
 .../views/settings/tabs/user/_AppearanceUserSettingsTab.scss   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
index b6fe9adccb..044b5e2240 100644
--- a/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
+++ b/res/css/views/settings/tabs/user/_AppearanceUserSettingsTab.scss
@@ -45,7 +45,7 @@ limitations under the License.
 
     .mx_EventTile_msgOption {
         display: none;
-}
+    }
 
     &.mx_IRCLayout {
         padding-top: 9px;
@@ -199,4 +199,3 @@ limitations under the License.
         background-color: rgba($accent-color, 0.08);
     }
 }
-

From a579ea95db812423055e8ab0f72c15bed4e62393 Mon Sep 17 00:00:00 2001
From: Jorik Schellekens <joriksch@gmail.com>
Date: Thu, 18 Jun 2020 13:28:24 +0100
Subject: [PATCH 4/5] Lint and i18n

---
 .../tabs/user/AppearanceUserSettingsTab.tsx   | 36 +++++++++----------
 src/i18n/strings/en_EN.json                   |  1 +
 2 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
index 0620626181..0f1779270b 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
@@ -35,27 +35,27 @@ interface IProps {
 }
 
 interface IThemeState {
-    theme: string,
-    useSystemTheme: boolean,
+    theme: string;
+    useSystemTheme: boolean;
 }
 
 export interface CustomThemeMessage {
-    isError: boolean,
-    text: string
+    isError: boolean;
+    text: string;
 };
 
 interface IState extends IThemeState {
     // String displaying the current selected fontSize.
     // Needs to be string for things like '17.' without
     // trailing 0s.
-    fontSize: string,
-    customThemeUrl: string,
-    customThemeMessage: CustomThemeMessage,
-    useCustomFontSize: boolean,
-    useIRCLayout: boolean,
+    fontSize: string;
+    customThemeUrl: string;
+    customThemeMessage: CustomThemeMessage;
+    useCustomFontSize: boolean;
+    useIRCLayout: boolean;
 }
 
-const MESSAGE_PREVIEW_TEXT = "Hey you. You're the best"
+const MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!");
 
 export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> {
 
@@ -70,7 +70,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
             customThemeUrl: "",
             customThemeMessage: {isError: false, text: ""},
             useCustomFontSize: SettingsStore.getValue("useCustomFontSize"),
-            useIRCLayout: SettingsStore.getValue("useIRCLayout", null),
+            useIRCLayout: SettingsStore.getValue("useIRCLayout"),
         };
     }
 
@@ -277,7 +277,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
                         return <StyledRadioButton
                             key={theme.id}
                             value={theme.id}
-                            name={"theme"}
+                            name="theme"
                             disabled={this.state.useSystemTheme}
                             checked={!this.state.useSystemTheme && theme.id === this.state.theme}
                             className={"mx_ThemeSelector_" + theme.id}
@@ -350,11 +350,11 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
                     <MessagePreview
                         className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
                         message={MESSAGE_PREVIEW_TEXT}
-                        useIRCLayout={true}
+                        useIRCLayout="true"
                     />
                     <StyledRadioButton
-                        name={"layout"}
-                        value={true}
+                        name="layout"
+                        value="true"
                         checked={this.state.useIRCLayout}
                         onChange={this.onLayoutChange}
                     >
@@ -366,11 +366,11 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
                     <MessagePreview
                         className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
                         message={MESSAGE_PREVIEW_TEXT}
-                        useIRCLayout={false}
+                        useIRCLayout="false"
                     />
                     <StyledRadioButton
-                        name={"layout"}
-                        value={false}
+                        name="layout"
+                        value="false"
                         checked={!this.state.useIRCLayout}
                         onChange={this.onLayoutChange}
                     >
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index 157d83ba57..6a16f947f4 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -771,6 +771,7 @@
     "Downloading update...": "Downloading update...",
     "New version available. <a>Update now.</a>": "New version available. <a>Update now.</a>",
     "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",

From 37b299412f463043c5eb90d040162eefef09668f Mon Sep 17 00:00:00 2001
From: Jorik Schellekens <joriksch@gmail.com>
Date: Thu, 18 Jun 2020 15:47:26 +0100
Subject: [PATCH 5/5] Fix merge conflicts

---
 .../tabs/user/AppearanceUserSettingsTab.tsx    | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
index c3538e5099..46723ec7cd 100644
--- a/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/AppearanceUserSettingsTab.tsx
@@ -58,9 +58,9 @@ interface IState extends IThemeState {
     useIRCLayout: boolean;
 }
 
-const MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!");
 
 export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> {
+    private readonly MESSAGE_PREVIEW_TEXT = _t("Hey you. You're the best!");
 
     private themeTimer: NodeJS.Timeout;
 
@@ -212,7 +212,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
         });
 
         SettingsStore.setValue("useIRCLayout", null, SettingLevel.DEVICE, val);
-    }
+    };
 
     private renderThemeSection() {
         const themeWatcher = new ThemeWatcher();
@@ -297,7 +297,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
             <span className="mx_SettingsTab_subheading">{_t("Font size")}</span>
             <EventTilePreview
                 className="mx_AppearanceUserSettingsTab_fontSlider_preview"
-                message={MESSAGE_PREVIEW_TEXT}
+                message={this.MESSAGE_PREVIEW_TEXT}
                 useIRCLayout={this.state.useIRCLayout}
             />
             <div className="mx_AppearanceUserSettingsTab_fontSlider">
@@ -340,9 +340,9 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
 
             <div className="mx_AppearanceUserSettingsTab_Layout_RadioButtons" >
                 <div className="mx_AppearanceUserSettingsTab_Layout_RadioButton">
-                    <MessagePreview
+                    <EventTilePreview
                         className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
-                        message={MESSAGE_PREVIEW_TEXT}
+                        message={this.MESSAGE_PREVIEW_TEXT}
                         useIRCLayout={true}
                     />
                     <StyledRadioButton
@@ -356,9 +356,9 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
                 </div>
                 <div className="mx_AppearanceUserSettingsTab_spacer" />
                 <div className="mx_AppearanceUserSettingsTab_Layout_RadioButton">
-                    <MessagePreview
+                    <EventTilePreview
                         className="mx_AppearanceUserSettingsTab_Layout_RadioButton_preview"
-                        message={MESSAGE_PREVIEW_TEXT}
+                        message={this.MESSAGE_PREVIEW_TEXT}
                         useIRCLayout={false}
                     />
                     <StyledRadioButton
@@ -371,8 +371,8 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
                     </StyledRadioButton>
                 </div>
             </div>
-        </div>
-    }
+        </div>;
+    };
 
     render() {
         return (