mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-04-29 21:00:58 +01:00
Move left pane entirely to React
This commit is contained in:
@@ -6,9 +6,250 @@ import * as MIME from './MIME';
|
||||
import { arrayBufferToObjectURL } from '../util/arrayBufferToObjectURL';
|
||||
import { saveURLAsFile } from '../util/saveURLAsFile';
|
||||
import { SignalService } from '../protobuf';
|
||||
import {
|
||||
isImageTypeSupported,
|
||||
isVideoTypeSupported,
|
||||
} from '../util/GoogleChrome';
|
||||
import { LocalizerType } from './Util';
|
||||
|
||||
const MAX_WIDTH = 300;
|
||||
const MAX_HEIGHT = MAX_WIDTH * 1.5;
|
||||
const MIN_WIDTH = 200;
|
||||
const MIN_HEIGHT = 50;
|
||||
|
||||
// Used for display
|
||||
|
||||
export interface AttachmentType {
|
||||
caption?: string;
|
||||
contentType: MIME.MIMEType;
|
||||
fileName: string;
|
||||
/** Not included in protobuf, needs to be pulled from flags */
|
||||
isVoiceMessage?: boolean;
|
||||
/** For messages not already on disk, this will be a data url */
|
||||
url: string;
|
||||
size?: number;
|
||||
fileSize?: string;
|
||||
pending?: boolean;
|
||||
width?: number;
|
||||
height?: number;
|
||||
screenshot?: {
|
||||
height: number;
|
||||
width: number;
|
||||
url: string;
|
||||
contentType: MIME.MIMEType;
|
||||
};
|
||||
thumbnail?: {
|
||||
height: number;
|
||||
width: number;
|
||||
url: string;
|
||||
contentType: MIME.MIMEType;
|
||||
};
|
||||
}
|
||||
|
||||
// UI-focused functions
|
||||
|
||||
export function getExtensionForDisplay({
|
||||
fileName,
|
||||
contentType,
|
||||
}: {
|
||||
fileName: string;
|
||||
contentType: MIME.MIMEType;
|
||||
}): string | undefined {
|
||||
if (fileName && fileName.indexOf('.') >= 0) {
|
||||
const lastPeriod = fileName.lastIndexOf('.');
|
||||
const extension = fileName.slice(lastPeriod + 1);
|
||||
if (extension.length) {
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
|
||||
if (!contentType) {
|
||||
return;
|
||||
}
|
||||
|
||||
const slash = contentType.indexOf('/');
|
||||
if (slash >= 0) {
|
||||
return contentType.slice(slash + 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
export function isAudio(attachments?: Array<AttachmentType>) {
|
||||
return (
|
||||
attachments &&
|
||||
attachments[0] &&
|
||||
attachments[0].contentType &&
|
||||
MIME.isAudio(attachments[0].contentType)
|
||||
);
|
||||
}
|
||||
|
||||
export function canDisplayImage(attachments?: Array<AttachmentType>) {
|
||||
const { height, width } =
|
||||
attachments && attachments[0] ? attachments[0] : { height: 0, width: 0 };
|
||||
|
||||
return (
|
||||
height &&
|
||||
height > 0 &&
|
||||
height <= 4096 &&
|
||||
width &&
|
||||
width > 0 &&
|
||||
width <= 4096
|
||||
);
|
||||
}
|
||||
|
||||
export function getThumbnailUrl(attachment: AttachmentType) {
|
||||
if (attachment.thumbnail) {
|
||||
return attachment.thumbnail.url;
|
||||
}
|
||||
|
||||
return getUrl(attachment);
|
||||
}
|
||||
|
||||
export function getUrl(attachment: AttachmentType) {
|
||||
if (attachment.screenshot) {
|
||||
return attachment.screenshot.url;
|
||||
}
|
||||
|
||||
return attachment.url;
|
||||
}
|
||||
|
||||
export function isImage(attachments?: Array<AttachmentType>) {
|
||||
return (
|
||||
attachments &&
|
||||
attachments[0] &&
|
||||
attachments[0].contentType &&
|
||||
isImageTypeSupported(attachments[0].contentType)
|
||||
);
|
||||
}
|
||||
|
||||
export function isImageAttachment(attachment: AttachmentType) {
|
||||
return (
|
||||
attachment &&
|
||||
attachment.contentType &&
|
||||
isImageTypeSupported(attachment.contentType)
|
||||
);
|
||||
}
|
||||
export function hasImage(attachments?: Array<AttachmentType>) {
|
||||
return (
|
||||
attachments &&
|
||||
attachments[0] &&
|
||||
(attachments[0].url || attachments[0].pending)
|
||||
);
|
||||
}
|
||||
|
||||
export function isVideo(attachments?: Array<AttachmentType>) {
|
||||
return attachments && isVideoAttachment(attachments[0]);
|
||||
}
|
||||
|
||||
export function isVideoAttachment(attachment?: AttachmentType) {
|
||||
return (
|
||||
attachment &&
|
||||
attachment.contentType &&
|
||||
isVideoTypeSupported(attachment.contentType)
|
||||
);
|
||||
}
|
||||
|
||||
export function hasVideoScreenshot(attachments?: Array<AttachmentType>) {
|
||||
const firstAttachment = attachments ? attachments[0] : null;
|
||||
|
||||
return (
|
||||
firstAttachment &&
|
||||
firstAttachment.screenshot &&
|
||||
firstAttachment.screenshot.url
|
||||
);
|
||||
}
|
||||
|
||||
type DimensionsType = {
|
||||
height: number;
|
||||
width: number;
|
||||
};
|
||||
|
||||
export function getImageDimensions(attachment: AttachmentType): DimensionsType {
|
||||
const { height, width } = attachment;
|
||||
if (!height || !width) {
|
||||
return {
|
||||
height: MIN_HEIGHT,
|
||||
width: MIN_WIDTH,
|
||||
};
|
||||
}
|
||||
|
||||
const aspectRatio = height / width;
|
||||
const targetWidth = Math.max(Math.min(MAX_WIDTH, width), MIN_WIDTH);
|
||||
const candidateHeight = Math.round(targetWidth * aspectRatio);
|
||||
|
||||
return {
|
||||
width: targetWidth,
|
||||
height: Math.max(Math.min(MAX_HEIGHT, candidateHeight), MIN_HEIGHT),
|
||||
};
|
||||
}
|
||||
|
||||
export function areAllAttachmentsVisual(
|
||||
attachments?: Array<AttachmentType>
|
||||
): boolean {
|
||||
if (!attachments) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const max = attachments.length;
|
||||
for (let i = 0; i < max; i += 1) {
|
||||
const attachment = attachments[i];
|
||||
if (!isImageAttachment(attachment) && !isVideoAttachment(attachment)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export function getGridDimensions(
|
||||
attachments?: Array<AttachmentType>
|
||||
): null | DimensionsType {
|
||||
if (!attachments || !attachments.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!isImage(attachments) && !isVideo(attachments)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (attachments.length === 1) {
|
||||
return getImageDimensions(attachments[0]);
|
||||
}
|
||||
|
||||
if (attachments.length === 2) {
|
||||
return {
|
||||
height: 150,
|
||||
width: 300,
|
||||
};
|
||||
}
|
||||
|
||||
if (attachments.length === 4) {
|
||||
return {
|
||||
height: 300,
|
||||
width: 300,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
height: 200,
|
||||
width: 300,
|
||||
};
|
||||
}
|
||||
|
||||
export function getAlt(
|
||||
attachment: AttachmentType,
|
||||
i18n: LocalizerType
|
||||
): string {
|
||||
return isVideoAttachment(attachment)
|
||||
? i18n('videoAttachmentAlt')
|
||||
: i18n('imageAttachmentAlt');
|
||||
}
|
||||
|
||||
// Migration-related attachment stuff
|
||||
|
||||
export type Attachment = {
|
||||
fileName?: string | null;
|
||||
fileName?: string;
|
||||
flags?: SignalService.AttachmentPointer.Flags;
|
||||
contentType?: MIME.MIMEType;
|
||||
size?: number;
|
||||
@@ -72,7 +313,7 @@ export const isVoiceMessage = (attachment: Attachment): boolean => {
|
||||
const isLegacyAndroidVoiceMessage =
|
||||
!is.undefined(attachment.contentType) &&
|
||||
MIME.isAudio(attachment.contentType) &&
|
||||
attachment.fileName === null;
|
||||
!attachment.fileName;
|
||||
if (isLegacyAndroidVoiceMessage) {
|
||||
return true;
|
||||
}
|
||||
@@ -131,9 +372,11 @@ export const getSuggestedFilename = ({
|
||||
return `${prefix}${suffix}${indexSuffix}${extension}`;
|
||||
};
|
||||
|
||||
export const getFileExtension = (attachment: Attachment): string | null => {
|
||||
export const getFileExtension = (
|
||||
attachment: Attachment
|
||||
): string | undefined => {
|
||||
if (!attachment.contentType) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (attachment.contentType) {
|
||||
|
||||
Reference in New Issue
Block a user