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

Add option to change the size of images/videos in the timeline #7017

Merged
merged 18 commits into from
Nov 17, 2021
Merged
Show file tree
Hide file tree
Changes from 4 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
3 changes: 2 additions & 1 deletion res/css/views/messages/_MImageBody.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ $timelineImageBorderRadius: 8px;
height: 100%;
width: 100%;

// this is needed so that the Blurhash can get have rounded corners without beeing the correct size during loading.
overflow: hidden;
.mx_Blurhash > canvas {
animation: mx--anim-pulse 1.75s infinite cubic-bezier(.4, 0, .6, 1);
border-radius: $timelineImageBorderRadius;
}

.mx_no-image-placeholder {
Expand Down
34 changes: 19 additions & 15 deletions src/components/views/messages/MImageBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import classNames from 'classnames';
import { CSSTransition, SwitchTransition } from 'react-transition-group';

import { logger } from "matrix-js-sdk/src/logger";
import { ImageSize } from "../../../settings/enums/ImageSize";
import { ImageSize, suggestedSize as suggestedImageSize } from "../../../settings/enums/ImageSize";

interface IState {
decryptedUrl?: string;
Expand Down Expand Up @@ -374,21 +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>
let maxHeight = forcedHeight;
if (!maxHeight) {
switch (SettingsStore.getValue("Images.size") as ImageSize) {
case ImageSize.Large:
maxHeight = Math.min((this.props.maxImageHeight || 600), infoHeight);
break;
case ImageSize.Normal:
default:
maxHeight = Math.min((this.props.maxImageHeight || 220), infoHeight);
}
// The maximum size of the thumbnail as it is rendered as an <img>
//check for any height contraints
toger5 marked this conversation as resolved.
Show resolved Hide resolved
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;
}
// The maximum width of the thumbnail, as dictated by its natural
// maximum height.
const maxWidth = infoWidth * maxHeight / infoHeight;

let img = null;
let placeholder = null;
Expand Down
24 changes: 6 additions & 18 deletions src/components/views/messages/MVideoBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { IBodyProps } from "./IBodyProps";
import MFileBody from "./MFileBody";

import { logger } from "matrix-js-sdk/src/logger";
import { ImageSize } from "../../../settings/enums/ImageSize";
import { ImageSize, suggestedSize as suggestedVideoSize } from "../../../settings/enums/ImageSize";

interface IState {
decryptedUrl?: string;
Expand Down Expand Up @@ -60,20 +60,14 @@ export default class MVideoBody extends React.PureComponent<IBodyProps, IState>
}

private get suggestedDimensions(): { w: number, h: number } {
switch (SettingsStore.getValue("Images.size") as ImageSize) {
case ImageSize.Large:
return { w: 480, h: 360 };
case ImageSize.Normal:
default:
return { w: 324, h: 220 };
}
return suggestedVideoSize(SettingsStore.getValue("Images.size") as ImageSize);
}

private thumbScale(
fullWidth: number,
fullHeight: number,
thumbWidth?,
thumbHeight?,
thumbWidth?: number,
thumbHeight?: number,
) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return type plz

if (!thumbWidth || !thumbHeight) {
const dims = this.suggestedDimensions;
Expand All @@ -91,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 {
Expand Down
2 changes: 1 addition & 1 deletion src/components/views/rooms/EventTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1166,7 +1166,7 @@ export default class EventTile extends React.Component<IProps, IState> {
|| this.state.actionBarFocused);

const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
const thread = room.findThreadForEvent?.(this.props.mxEvent);
const thread = room?.findThreadForEvent?.(this.props.mxEvent);

// Thread panel shows the timestamp of the last reply in that thread
const ts = this.props.tileShape !== TileShape.ThreadPanel
Expand Down
12 changes: 12 additions & 0 deletions src/settings/enums/ImageSize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,20 @@ 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.
*/
toger5 marked this conversation as resolved.
Show resolved Hide resolved
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;
}
}