Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Refreshing compact timeline layout #4335

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions res/css/views/rooms/_EventTile.scss
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,8 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody {

.mx_EventTile .mx_SenderProfile {
font-size: $font-13px;
font-size: 13px;
padding-left: 10px;
}

.mx_EventTile.mx_EventTile_emote {
Expand All @@ -627,6 +629,7 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody {
.mx_EventTile_line, .mx_EventTile_reply {
padding-top: 0px;
padding-bottom: 0px;
padding-left: 45px;
}

.mx_EventTile_avatar {
Expand Down Expand Up @@ -654,6 +657,15 @@ div.mx_EventTile_notSent.mx_EventTile_redacted .mx_UnknownBody {
margin-top: 6px;
}

.mx_ReplyThread {
margin-bottom: 5px;
padding-left: 0;
}

.mx_ReplyThread_show {
padding-left: 10px;
}

.mx_EventTile_content .markdown-body {
p, ul, ol, dl, blockquote, pre, table {
margin-bottom: 4px; // 1/4 of the non-compact margin-bottom
Expand Down
8 changes: 8 additions & 0 deletions src/components/views/rooms/EventTile.js
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,14 @@ export default createReactClass({
needsSenderProfile = true;
}

const useCompactLayout = SettingsStore.getValue("useCompactLayout");

// Do not display avatar in compact layout. We do not touch to the
// SenderProfile since it depends on message groups.
if (useCompactLayout) {
avatarSize = 0;
}

if (this.props.mxEvent.sender && avatarSize) {
avatar = (
<div className="mx_EventTile_avatar">
Expand Down
170 changes: 0 additions & 170 deletions src/components/views/settings/tabs/user/GeneralUserSettingsTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ limitations under the License.
import React from 'react';
import {_t} from "../../../../../languageHandler";
import ProfileSettings from "../../ProfileSettings";
import Field from "../../../elements/Field";
import * as languageHandler from "../../../../../languageHandler";
import {SettingLevel} from "../../../../../settings/SettingsStore";
import SettingsStore from "../../../../../settings/SettingsStore";
import LanguageDropdown from "../../../elements/LanguageDropdown";
import AccessibleButton from "../../../elements/AccessibleButton";
import DeactivateAccountDialog from "../../../dialogs/DeactivateAccountDialog";
import PropTypes from "prop-types";
import {enumerateThemes, ThemeWatcher} from "../../../../../theme";
import PlatformPeg from "../../../../../PlatformPeg";
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
import * as sdk from "../../../../..";
Expand Down Expand Up @@ -60,7 +58,6 @@ export default class GeneralUserSettingsTab extends React.Component {
},
emails: [],
msisdns: [],
...this._calculateThemeState(),
customThemeUrl: "",
customThemeMessage: {isError: false, text: ""},
};
Expand Down Expand Up @@ -91,39 +88,6 @@ export default class GeneralUserSettingsTab extends React.Component {
dis.unregister(this.dispatcherRef);
}

_calculateThemeState() {
// We have to mirror the logic from ThemeWatcher.getEffectiveTheme so we
// show the right values for things.

const themeChoice = SettingsStore.getValueAt(SettingLevel.ACCOUNT, "theme");
const systemThemeExplicit = SettingsStore.getValueAt(
SettingLevel.DEVICE, "use_system_theme", null, false, true);
const themeExplicit = SettingsStore.getValueAt(
SettingLevel.DEVICE, "theme", null, false, true);

// If the user has enabled system theme matching, use that.
if (systemThemeExplicit) {
return {
theme: themeChoice,
useSystemTheme: true,
};
}

// If the user has set a theme explicitly, use that (no system theme matching)
if (themeExplicit) {
return {
theme: themeChoice,
useSystemTheme: false,
};
}

// Otherwise assume the defaults for the settings
return {
theme: themeChoice,
useSystemTheme: SettingsStore.getValueAt(SettingLevel.DEVICE, "use_system_theme"),
};
}

_onAction = (payload) => {
if (payload.action === 'id_server_changed') {
this.setState({haveIdServer: Boolean(MatrixClientPeg.get().getIdentityServerUrl())});
Expand Down Expand Up @@ -214,33 +178,6 @@ export default class GeneralUserSettingsTab extends React.Component {
PlatformPeg.get().reload();
};

_onThemeChange = (e) => {
const newTheme = e.target.value;
if (this.state.theme === newTheme) return;

// doing getValue in the .catch will still return the value we failed to set,
// so remember what the value was before we tried to set it so we can revert
const oldTheme = SettingsStore.getValue('theme');
SettingsStore.setValue("theme", null, SettingLevel.ACCOUNT, newTheme).catch(() => {
dis.dispatch({action: 'recheck_theme'});
this.setState({theme: oldTheme});
});
this.setState({theme: newTheme});
// The settings watcher doesn't fire until the echo comes back from the
// server, so to make the theme change immediately we need to manually
// do the dispatch now
// XXX: The local echoed value appears to be unreliable, in particular
// when settings custom themes(!) so adding forceTheme to override
// the value from settings.
dis.dispatch({action: 'recheck_theme', forceTheme: newTheme});
};

_onUseSystemThemeChanged = (checked) => {
this.setState({useSystemTheme: checked});
SettingsStore.setValue("use_system_theme", null, SettingLevel.DEVICE, checked);
dis.dispatch({action: 'recheck_theme'});
};

_onPasswordChangeError = (err) => {
// TODO: Figure out a design that doesn't involve replacing the current dialog
let errMsg = err.error || "";
Expand Down Expand Up @@ -277,41 +214,6 @@ export default class GeneralUserSettingsTab extends React.Component {
});
};

_onAddCustomTheme = async () => {
let currentThemes = SettingsStore.getValue("custom_themes");
if (!currentThemes) currentThemes = [];
currentThemes = currentThemes.map(c => c); // cheap clone

if (this._themeTimer) {
clearTimeout(this._themeTimer);
}

try {
const r = await fetch(this.state.customThemeUrl);
const themeInfo = await r.json();
if (!themeInfo || typeof(themeInfo['name']) !== 'string' || typeof(themeInfo['colors']) !== 'object') {
this.setState({customThemeMessage: {text: _t("Invalid theme schema."), isError: true}});
return;
}
currentThemes.push(themeInfo);
} catch (e) {
console.error(e);
this.setState({customThemeMessage: {text: _t("Error downloading theme information."), isError: true}});
return; // Don't continue on error
}

await SettingsStore.setValue("custom_themes", null, SettingLevel.ACCOUNT, currentThemes);
this.setState({customThemeUrl: "", customThemeMessage: {text: _t("Theme added!"), isError: false}});

this._themeTimer = setTimeout(() => {
this.setState({customThemeMessage: {text: "", isError: false}});
}, 3000);
};

_onCustomThemeChange = (e) => {
this.setState({customThemeUrl: e.target.value});
};

_renderProfileSection() {
return (
<div className="mx_SettingsTab_section">
Expand Down Expand Up @@ -391,77 +293,6 @@ export default class GeneralUserSettingsTab extends React.Component {
);
}

_renderThemeSection() {
const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
const LabelledToggleSwitch = sdk.getComponent("views.elements.LabelledToggleSwitch");

const themeWatcher = new ThemeWatcher();
let systemThemeSection;
if (themeWatcher.isSystemThemeSupported()) {
systemThemeSection = <div>
<LabelledToggleSwitch
value={this.state.useSystemTheme}
label={SettingsStore.getDisplayName("use_system_theme")}
onChange={this._onUseSystemThemeChanged}
/>
</div>;
}

let customThemeForm;
if (SettingsStore.isFeatureEnabled("feature_custom_themes")) {
let messageElement = null;
if (this.state.customThemeMessage.text) {
if (this.state.customThemeMessage.isError) {
messageElement = <div className='text-error'>{this.state.customThemeMessage.text}</div>;
} else {
messageElement = <div className='text-success'>{this.state.customThemeMessage.text}</div>;
}
}
customThemeForm = (
<div className='mx_SettingsTab_section'>
<form onSubmit={this._onAddCustomTheme}>
<Field
label={_t("Custom theme URL")}
type='text'
autoComplete="off"
onChange={this._onCustomThemeChange}
value={this.state.customThemeUrl}
/>
<AccessibleButton
onClick={this._onAddCustomTheme}
type="submit" kind="primary_sm"
disabled={!this.state.customThemeUrl.trim()}
>{_t("Add theme")}</AccessibleButton>
{messageElement}
</form>
</div>
);
}

const themes = Object.entries(enumerateThemes())
.map(p => ({id: p[0], name: p[1]})); // convert pairs to objects for code readability
const builtInThemes = themes.filter(p => !p.id.startsWith("custom-"));
const customThemes = themes.filter(p => !builtInThemes.includes(p))
.sort((a, b) => a.name.localeCompare(b.name));
const orderedThemes = [...builtInThemes, ...customThemes];
return (
<div className="mx_SettingsTab_section mx_GeneralUserSettingsTab_themeSection">
<span className="mx_SettingsTab_subheading">{_t("Theme")}</span>
{systemThemeSection}
<Field label={_t("Theme")} element="select"
value={this.state.theme} onChange={this._onThemeChange}
disabled={this.state.useSystemTheme}
>
{orderedThemes.map(theme => {
return <option key={theme.id} value={theme.id}>{theme.name}</option>;
})}
</Field>
{customThemeForm}
<SettingsFlag name="useCompactLayout" level={SettingLevel.ACCOUNT} />
</div>
);
}

_renderDiscoverySection() {
const SetIdServer = sdk.getComponent("views.settings.SetIdServer");

Expand Down Expand Up @@ -547,7 +378,6 @@ export default class GeneralUserSettingsTab extends React.Component {
{this._renderProfileSection()}
{this._renderAccountSection()}
{this._renderLanguageSection()}
{this._renderThemeSection()}
<div className="mx_SettingsTab_heading">{discoWarning} {_t("Discovery")}</div>
{this._renderDiscoverySection()}
{this._renderIntegrationManagerSection() /* Has its own title */}
Expand Down
Loading