Add option to change the size of images/videos in the timeline (#7017)
Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com> Co-authored-by: J. Ryan Stinnett <jryans@gmail.com> Co-authored-by: Timo K <toger5@hotmail.de>
This commit is contained in:
parent
816136de97
commit
3c06e7f7a0
35 changed files with 293 additions and 45 deletions
|
@ -36,7 +36,7 @@ import ResizeNotifier from '../../utils/ResizeNotifier';
|
|||
import TimelinePanel from "./TimelinePanel";
|
||||
import Spinner from "../views/elements/Spinner";
|
||||
import { TileShape } from '../views/rooms/EventTile';
|
||||
import { Layout } from "../../settings/Layout";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import RoomContext, { TimelineRenderingType } from '../../contexts/RoomContext';
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
|
|
@ -27,7 +27,7 @@ import { wantsDateSeparator } from '../../DateUtils';
|
|||
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
||||
import SettingsStore from '../../settings/SettingsStore';
|
||||
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||
import { Layout } from "../../settings/Layout";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import { _t } from "../../languageHandler";
|
||||
import EventTile, { haveTileForEvent, IReadReceiptProps, TileShape } from "../views/rooms/EventTile";
|
||||
import { hasText } from "../../TextForEvent";
|
||||
|
|
|
@ -23,7 +23,7 @@ import { replaceableComponent } from "../../utils/replaceableComponent";
|
|||
import TimelinePanel from "./TimelinePanel";
|
||||
import Spinner from "../views/elements/Spinner";
|
||||
import { TileShape } from "../views/rooms/EventTile";
|
||||
import { Layout } from "../../settings/Layout";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
|
|
@ -44,7 +44,7 @@ import RoomViewStore from '../../stores/RoomViewStore';
|
|||
import RoomScrollStateStore, { ScrollState } from '../../stores/RoomScrollStateStore';
|
||||
import WidgetEchoStore from '../../stores/WidgetEchoStore';
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import { Layout } from "../../settings/Layout";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||
import RightPanelStore from "../../stores/RightPanelStore";
|
||||
import { haveTileForEvent } from "../views/rooms/EventTile";
|
||||
|
|
|
@ -27,7 +27,7 @@ import { ContextMenuButton } from '../../accessibility/context_menu/ContextMenuB
|
|||
import ContextMenu, { ChevronFace, useContextMenu } from './ContextMenu';
|
||||
import RoomContext, { TimelineRenderingType } from '../../contexts/RoomContext';
|
||||
import TimelinePanel from './TimelinePanel';
|
||||
import { Layout } from '../../settings/Layout';
|
||||
import { Layout } from '../../settings/enums/Layout';
|
||||
import { useEventEmitter } from '../../hooks/useEventEmitter';
|
||||
import AccessibleButton from '../views/elements/AccessibleButton';
|
||||
import { TileShape } from '../views/rooms/EventTile';
|
||||
|
|
|
@ -27,7 +27,7 @@ import ResizeNotifier from '../../utils/ResizeNotifier';
|
|||
import { TileShape } from '../views/rooms/EventTile';
|
||||
import MessageComposer from '../views/rooms/MessageComposer';
|
||||
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
||||
import { Layout } from '../../settings/Layout';
|
||||
import { Layout } from '../../settings/enums/Layout';
|
||||
import TimelinePanel from './TimelinePanel';
|
||||
import dis from "../../dispatcher/dispatcher";
|
||||
import { ActionPayload } from '../../dispatcher/payloads';
|
||||
|
|
|
@ -25,7 +25,7 @@ import { EventType, RelationType } from 'matrix-js-sdk/src/@types/event';
|
|||
import { SyncState } from 'matrix-js-sdk/src/sync.api';
|
||||
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
import { Layout } from "../../settings/Layout";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import { _t } from '../../languageHandler';
|
||||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||
import RoomContext from "../../contexts/RoomContext";
|
||||
|
|
|
@ -25,7 +25,7 @@ import { _t } from "../../../languageHandler";
|
|||
import dis from "../../../dispatcher/dispatcher";
|
||||
import { useSettingValue, useFeatureEnabled } from "../../../hooks/useSettings";
|
||||
import { UIFeature } from "../../../settings/UIFeature";
|
||||
import { Layout } from "../../../settings/Layout";
|
||||
import { Layout } from "../../../settings/enums/Layout";
|
||||
import { IDialogProps } from "./IDialogProps";
|
||||
import BaseDialog from "./BaseDialog";
|
||||
import { avatarUrlForUser } from "../../../Avatar";
|
||||
|
|
|
@ -22,7 +22,7 @@ import MemberAvatar from '../avatars/MemberAvatar';
|
|||
import { _t } from '../../../languageHandler';
|
||||
import { useStateToggle } from "../../../hooks/useStateToggle";
|
||||
import AccessibleButton from "./AccessibleButton";
|
||||
import { Layout } from '../../../settings/Layout';
|
||||
import { Layout } from '../../../settings/enums/Layout';
|
||||
|
||||
interface IProps {
|
||||
// An array of member events to summarise
|
||||
|
|
|
@ -22,7 +22,7 @@ import { RoomMember } from 'matrix-js-sdk/src/models/room-member';
|
|||
import * as Avatar from '../../../Avatar';
|
||||
import EventTile from '../rooms/EventTile';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { Layout } from "../../../settings/Layout";
|
||||
import { Layout } from "../../../settings/enums/Layout";
|
||||
import { UIFeature } from "../../../settings/UIFeature";
|
||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||
import Spinner from './Spinner';
|
||||
|
|
|
@ -31,7 +31,7 @@ import { Action } from '../../../dispatcher/actions';
|
|||
import { SetRightPanelPhasePayload } from '../../../dispatcher/payloads/SetRightPanelPhasePayload';
|
||||
import { jsxJoin } from '../../../utils/ReactUtils';
|
||||
import { EventType } from 'matrix-js-sdk/src/@types/event';
|
||||
import { Layout } from '../../../settings/Layout';
|
||||
import { Layout } from '../../../settings/enums/Layout';
|
||||
|
||||
const onPinnedMessagesClick = (): void => {
|
||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
||||
|
|
|
@ -23,7 +23,7 @@ import dis from '../../../dispatcher/dispatcher';
|
|||
import { MatrixEvent } from 'matrix-js-sdk/src/models/event';
|
||||
import { makeUserPermalink, RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import { Layout } from "../../../settings/Layout";
|
||||
import { Layout } from "../../../settings/enums/Layout";
|
||||
import escapeHtml from "escape-html";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { getUserNameColorClass } from "../../../utils/FormattingUtils";
|
||||
|
|
|
@ -35,6 +35,7 @@ import classNames from 'classnames';
|
|||
import { CSSTransition, SwitchTransition } from 'react-transition-group';
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { ImageSize, suggestedSize as suggestedImageSize } from "../../../settings/enums/ImageSize";
|
||||
|
||||
interface IState {
|
||||
decryptedUrl?: string;
|
||||
|
@ -58,6 +59,7 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
private unmounted = true;
|
||||
private image = createRef<HTMLImageElement>();
|
||||
private timeout?: number;
|
||||
private sizeWatcher: string;
|
||||
|
||||
constructor(props: IBodyProps) {
|
||||
super(props);
|
||||
|
@ -317,12 +319,17 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
}
|
||||
}, 150);
|
||||
}
|
||||
|
||||
this.sizeWatcher = SettingsStore.watchSetting("Images.size", null, () => {
|
||||
this.forceUpdate(); // we don't really have a reliable thing to update, so just update the whole thing
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unmounted = true;
|
||||
this.context.removeListener('sync', this.onClientSync);
|
||||
this.clearBlurhashTimeout();
|
||||
SettingsStore.unwatchSetting(this.sizeWatcher);
|
||||
}
|
||||
|
||||
protected messageContent(
|
||||
|
@ -367,11 +374,25 @@ export default class MImageBody extends React.Component<IBodyProps, IState> {
|
|||
infoHeight = this.state.loadedImageDimensions.naturalHeight;
|
||||
}
|
||||
|
||||
// The maximum height of the thumbnail as it is rendered as an <img>
|
||||
const maxHeight = forcedHeight || Math.min((this.props.maxImageHeight || 600), infoHeight);
|
||||
// The maximum width of the thumbnail, as dictated by its natural
|
||||
// maximum height.
|
||||
const maxWidth = infoWidth * maxHeight / infoHeight;
|
||||
// The maximum size of the thumbnail as it is rendered as an <img>
|
||||
// check for any height constraints
|
||||
const imageSize = SettingsStore.getValue("Images.size") as ImageSize;
|
||||
const suggestedAndPossibleWidth = Math.min(suggestedImageSize(imageSize).w, infoWidth);
|
||||
const aspectRatio = infoWidth / infoHeight;
|
||||
|
||||
let maxWidth;
|
||||
let maxHeight;
|
||||
const maxHeightConstraint = forcedHeight || this.props.maxImageHeight || undefined;
|
||||
if (maxHeightConstraint && maxHeightConstraint * aspectRatio < suggestedAndPossibleWidth) {
|
||||
// width is dictated by the maximum height that was defined by the props or the function param `forcedHeight`
|
||||
maxWidth = maxHeightConstraint * aspectRatio;
|
||||
// there is no need to check for infoHeight here since this is done with `maxHeightConstraint * aspectRatio < suggestedAndPossibleWidth`
|
||||
maxHeight = maxHeightConstraint;
|
||||
} else {
|
||||
// height is dictated by suggestedWidth (based on the Image.size setting)
|
||||
maxWidth = suggestedAndPossibleWidth;
|
||||
maxHeight = suggestedAndPossibleWidth / aspectRatio;
|
||||
}
|
||||
|
||||
let img = null;
|
||||
let placeholder = null;
|
||||
|
|
|
@ -28,6 +28,7 @@ import { IBodyProps } from "./IBodyProps";
|
|||
import MFileBody from "./MFileBody";
|
||||
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { ImageSize, suggestedSize as suggestedVideoSize } from "../../../settings/enums/ImageSize";
|
||||
|
||||
interface IState {
|
||||
decryptedUrl?: string;
|
||||
|
@ -42,6 +43,7 @@ interface IState {
|
|||
@replaceableComponent("views.messages.MVideoBody")
|
||||
export default class MVideoBody extends React.PureComponent<IBodyProps, IState> {
|
||||
private videoRef = React.createRef<HTMLVideoElement>();
|
||||
private sizeWatcher: string;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
@ -57,7 +59,22 @@ export default class MVideoBody extends React.PureComponent<IBodyProps, IState>
|
|||
};
|
||||
}
|
||||
|
||||
thumbScale(fullWidth: number, fullHeight: number, thumbWidth = 480, thumbHeight = 360) {
|
||||
private get suggestedDimensions(): { w: number, h: number } {
|
||||
return suggestedVideoSize(SettingsStore.getValue("Images.size") as ImageSize);
|
||||
}
|
||||
|
||||
private thumbScale(
|
||||
fullWidth: number,
|
||||
fullHeight: number,
|
||||
thumbWidth?: number,
|
||||
thumbHeight?: number,
|
||||
): number {
|
||||
if (!thumbWidth || !thumbHeight) {
|
||||
const dims = this.suggestedDimensions;
|
||||
thumbWidth = dims.w;
|
||||
thumbHeight = dims.h;
|
||||
}
|
||||
|
||||
if (!fullWidth || !fullHeight) {
|
||||
// Cannot calculate thumbnail height for image: missing w/h in metadata. We can't even
|
||||
// log this because it's spammy
|
||||
|
@ -68,14 +85,8 @@ export default class MVideoBody extends React.PureComponent<IBodyProps, IState>
|
|||
return 1;
|
||||
}
|
||||
const widthMulti = thumbWidth / fullWidth;
|
||||
const heightMulti = thumbHeight / fullHeight;
|
||||
if (widthMulti < heightMulti) {
|
||||
// width is the dominant dimension so scaling will be fixed on that
|
||||
return widthMulti;
|
||||
} else {
|
||||
// height is the dominant dimension so scaling will be fixed on that
|
||||
return heightMulti;
|
||||
}
|
||||
// always scale the videos based on their width.
|
||||
return widthMulti;
|
||||
}
|
||||
|
||||
private getContentUrl(): string|null {
|
||||
|
@ -152,12 +163,16 @@ export default class MVideoBody extends React.PureComponent<IBodyProps, IState>
|
|||
}
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const autoplay = SettingsStore.getValue("autoplayVideo") as boolean;
|
||||
public async componentDidMount() {
|
||||
this.sizeWatcher = SettingsStore.watchSetting("Images.size", null, () => {
|
||||
this.forceUpdate(); // we don't really have a reliable thing to update, so just update the whole thing
|
||||
});
|
||||
|
||||
this.loadBlurhash();
|
||||
|
||||
if (this.props.mediaEventHelper.media.isEncrypted && this.state.decryptedUrl === null) {
|
||||
try {
|
||||
const autoplay = SettingsStore.getValue("autoplayVideo") as boolean;
|
||||
const thumbnailUrl = await this.props.mediaEventHelper.thumbnailUrl.value;
|
||||
if (autoplay) {
|
||||
logger.log("Preloading video");
|
||||
|
@ -189,6 +204,10 @@ export default class MVideoBody extends React.PureComponent<IBodyProps, IState>
|
|||
}
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
SettingsStore.unwatchSetting(this.sizeWatcher);
|
||||
}
|
||||
|
||||
private videoOnPlay = async () => {
|
||||
if (this.hasContentUrl() || this.state.fetchingData || this.state.error) {
|
||||
// We have the file, we are fetching the file, or there is an error.
|
||||
|
@ -249,8 +268,9 @@ export default class MVideoBody extends React.PureComponent<IBodyProps, IState>
|
|||
|
||||
const contentUrl = this.getContentUrl();
|
||||
const thumbUrl = this.getThumbUrl();
|
||||
let height = null;
|
||||
let width = null;
|
||||
const defaultDims = this.suggestedDimensions;
|
||||
let height = defaultDims.h;
|
||||
let width = defaultDims.w;
|
||||
let poster = null;
|
||||
let preload = "metadata";
|
||||
if (content.info) {
|
||||
|
|
|
@ -28,7 +28,7 @@ import { _t } from '../../../languageHandler';
|
|||
import { hasText } from "../../../TextForEvent";
|
||||
import * as sdk from "../../../index";
|
||||
import dis from '../../../dispatcher/dispatcher';
|
||||
import { Layout } from "../../../settings/Layout";
|
||||
import { Layout } from "../../../settings/enums/Layout";
|
||||
import { formatTime } from "../../../DateUtils";
|
||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||
import { ALL_RULE_TYPES } from "../../../mjolnir/BanList";
|
||||
|
|
|
@ -22,7 +22,7 @@ import SettingsStore from "../../../settings/SettingsStore";
|
|||
import Slider from "../elements/Slider";
|
||||
import { FontWatcher } from "../../../settings/watchers/FontWatcher";
|
||||
import { IValidationResult, IFieldState } from '../elements/Validation';
|
||||
import { Layout } from "../../../settings/Layout";
|
||||
import { Layout } from "../../../settings/enums/Layout";
|
||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||
import { _t } from "../../../languageHandler";
|
||||
|
|
79
src/components/views/settings/ImageSizePanel.tsx
Normal file
79
src/components/views/settings/ImageSizePanel.tsx
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
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 React from "react";
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import StyledRadioButton from "../elements/StyledRadioButton";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||
import { ImageSize } from "../../../settings/enums/ImageSize";
|
||||
|
||||
interface IProps {
|
||||
// none
|
||||
}
|
||||
|
||||
interface IState {
|
||||
size: ImageSize;
|
||||
}
|
||||
|
||||
export default class ImageSizePanel extends React.Component<IProps, IState> {
|
||||
constructor(props: IProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
size: SettingsStore.getValue("Images.size"),
|
||||
};
|
||||
}
|
||||
|
||||
private onSizeChange = (ev: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const newSize = ev.target.value as ImageSize;
|
||||
this.setState({ size: newSize });
|
||||
|
||||
// noinspection JSIgnoredPromiseFromCall
|
||||
SettingsStore.setValue("Images.size", null, SettingLevel.ACCOUNT, newSize);
|
||||
};
|
||||
|
||||
public render(): JSX.Element {
|
||||
return (
|
||||
<div className="mx_SettingsTab_section mx_ImageSizePanel">
|
||||
<span className="mx_SettingsTab_subheading">
|
||||
{ _t("Image size in the timeline") }
|
||||
</span>
|
||||
|
||||
<div className="mx_ImageSizePanel_radios">
|
||||
<label>
|
||||
<div className="mx_ImageSizePanel_size mx_ImageSizePanel_sizeDefault" />
|
||||
<StyledRadioButton
|
||||
name="image_size"
|
||||
value={ImageSize.Normal}
|
||||
checked={this.state.size === ImageSize.Normal}
|
||||
onChange={this.onSizeChange}
|
||||
>{ _t("Default") }</StyledRadioButton>
|
||||
</label>
|
||||
<label>
|
||||
<div className="mx_ImageSizePanel_size mx_ImageSizePanel_sizeLarge" />
|
||||
<StyledRadioButton
|
||||
name="image_size"
|
||||
value={ImageSize.Large}
|
||||
checked={this.state.size === ImageSize.Large}
|
||||
onChange={this.onSizeChange}
|
||||
>{ _t("Large") }</StyledRadioButton>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -22,7 +22,7 @@ import SettingsStore from "../../../settings/SettingsStore";
|
|||
import EventTilePreview from "../elements/EventTilePreview";
|
||||
import StyledRadioButton from "../elements/StyledRadioButton";
|
||||
import { _t } from "../../../languageHandler";
|
||||
import { Layout } from "../../../settings/Layout";
|
||||
import { Layout } from "../../../settings/enums/Layout";
|
||||
import { SettingLevel } from "../../../settings/SettingLevel";
|
||||
|
||||
interface IProps {
|
||||
|
|
|
@ -25,12 +25,13 @@ import SettingsFlag from '../../../elements/SettingsFlag';
|
|||
import Field from '../../../elements/Field';
|
||||
import { SettingLevel } from "../../../../../settings/SettingLevel";
|
||||
import { UIFeature } from "../../../../../settings/UIFeature";
|
||||
import { Layout } from "../../../../../settings/Layout";
|
||||
import { Layout } from "../../../../../settings/enums/Layout";
|
||||
import { replaceableComponent } from "../../../../../utils/replaceableComponent";
|
||||
import LayoutSwitcher from "../../LayoutSwitcher";
|
||||
|
||||
import FontScalingPanel from '../../FontScalingPanel';
|
||||
import ThemeChoicePanel from '../../ThemeChoicePanel';
|
||||
import ImageSizePanel from "../../ImageSizePanel";
|
||||
|
||||
interface IProps {
|
||||
}
|
||||
|
@ -188,6 +189,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
|
|||
{ layoutSection }
|
||||
<FontScalingPanel />
|
||||
{ this.renderAdvancedSection() }
|
||||
<ImageSizePanel />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
import { createContext } from "react";
|
||||
|
||||
import { IRoomState } from "../components/structures/RoomView";
|
||||
import { Layout } from "../settings/Layout";
|
||||
import { Layout } from "../settings/enums/Layout";
|
||||
|
||||
export enum TimelineRenderingType {
|
||||
Room = "Room",
|
||||
|
|
|
@ -1182,6 +1182,8 @@
|
|||
"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",
|
||||
"Image size in the timeline": "Image size in the timeline",
|
||||
"Large": "Large",
|
||||
"Connecting to integration manager...": "Connecting to integration manager...",
|
||||
"Cannot connect to integration manager": "Cannot connect to integration manager",
|
||||
"The integration manager is offline or it cannot reach your homeserver.": "The integration manager is offline or it cannot reach your homeserver.",
|
||||
|
|
|
@ -37,11 +37,12 @@ import { isMac } from '../Keyboard';
|
|||
import UIFeatureController from "./controllers/UIFeatureController";
|
||||
import { UIFeature } from "./UIFeature";
|
||||
import { OrderedMultiController } from "./controllers/OrderedMultiController";
|
||||
import { Layout } from "./Layout";
|
||||
import { Layout } from "./enums/Layout";
|
||||
import ReducedMotionController from './controllers/ReducedMotionController';
|
||||
import IncompatibleController from "./controllers/IncompatibleController";
|
||||
import PseudonymousAnalyticsController from './controllers/PseudonymousAnalyticsController';
|
||||
import NewLayoutSwitcherController from './controllers/NewLayoutSwitcherController';
|
||||
import { ImageSize } from "./enums/ImageSize";
|
||||
import { MetaSpace } from "../stores/spaces";
|
||||
|
||||
// These are just a bunch of helper arrays to avoid copy/pasting a bunch of times
|
||||
|
@ -737,6 +738,10 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
|||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||
default: Layout.Group,
|
||||
},
|
||||
"Images.size": {
|
||||
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
|
||||
default: ImageSize.Normal,
|
||||
},
|
||||
"showChatEffects": {
|
||||
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
|
||||
displayName: _td("Show chat effects (animations when receiving e.g. confetti)"),
|
||||
|
|
|
@ -14,7 +14,7 @@ limitations under the License.
|
|||
import SettingController from "./SettingController";
|
||||
import { SettingLevel } from "../SettingLevel";
|
||||
import SettingsStore from "../SettingsStore";
|
||||
import { Layout } from "../Layout";
|
||||
import { Layout } from "../enums/Layout";
|
||||
|
||||
export default class NewLayoutSwitcherController extends SettingController {
|
||||
public onChange(level: SettingLevel, roomId: string, newValue: any) {
|
||||
|
|
33
src/settings/enums/ImageSize.ts
Normal file
33
src/settings/enums/ImageSize.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
const SIZE_LARGE = { w: 480, h: 360 };
|
||||
const SIZE_NORMAL = { w: 324, h: 220 };
|
||||
|
||||
export enum ImageSize {
|
||||
Normal = "normal",
|
||||
Large = "large",
|
||||
}
|
||||
|
||||
export function suggestedSize(size: ImageSize): { w: number, h: number } {
|
||||
switch (size) {
|
||||
case ImageSize.Large:
|
||||
return SIZE_LARGE;
|
||||
case ImageSize.Normal:
|
||||
default:
|
||||
return SIZE_NORMAL;
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ import SettingsHandler from "./SettingsHandler";
|
|||
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||
import { SettingLevel } from "../SettingLevel";
|
||||
import { CallbackFn, WatchManager } from "../WatchManager";
|
||||
import { Layout } from "../Layout";
|
||||
import { Layout } from "../enums/Layout";
|
||||
|
||||
/**
|
||||
* Gets and sets settings at the "device" level for the current device.
|
||||
|
|
|
@ -21,7 +21,7 @@ import { mediaFromMxc } from "../../customisations/Media";
|
|||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { Layout } from "../../settings/Layout";
|
||||
import { Layout } from "../../settings/enums/Layout";
|
||||
import { shouldFormContinuation } from "../../components/structures/MessagePanel";
|
||||
import { formatFullDateNoDayNoTime, wantsDateSeparator } from "../../DateUtils";
|
||||
import { RoomPermalinkCreator } from "../permalinks/Permalinks";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue