Files
desktop/app/utils/utils.ts

289 lines
8.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { MantineColor } from "@mantine/core";
import { MESSAGE_MAX_TIME_TO_DELEVERED_S } from "../constants";
import { decode, encode } from "blurhash";
export function generateRandomKey(length: number): string {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
export function murmurHash3_32_gc(key: string, seed: number = 0): number {
let remainder = key.length & 3;
let bytes = key.length - remainder;
let h1 = seed;
let c1 = 0xcc9e2d51;
let c2 = 0x1b873593;
let i = 0;
while (i < bytes) {
let k1 =
((key.charCodeAt(i) & 0xff)) |
((key.charCodeAt(++i) & 0xff) << 8) |
((key.charCodeAt(++i) & 0xff) << 16) |
((key.charCodeAt(++i) & 0xff) << 24);
++i;
k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
h1 ^= k1;
h1 = (h1 << 13) | (h1 >>> 19);
let h1b = (((h1 & 0xffff) * 5) + ((((h1 >>> 16) * 5) & 0xffff) << 16)) & 0xffffffff;
h1 = ((h1b & 0xffff) + 0x6b64) + ((((h1b >>> 16) + 0xe654) & 0xffff) << 16);
}
let k1 = 0;
switch (remainder) {
case 3:
k1 ^= (key.charCodeAt(i + 2) & 0xff) << 16;
case 2:
k1 ^= (key.charCodeAt(i + 1) & 0xff) << 8;
case 1:
k1 ^= (key.charCodeAt(i) & 0xff);
k1 = (((k1 & 0xffff) * c1) + ((((k1 >>> 16) * c1) & 0xffff) << 16)) & 0xffffffff;
k1 = (k1 << 15) | (k1 >>> 17);
k1 = (((k1 & 0xffff) * c2) + ((((k1 >>> 16) * c2) & 0xffff) << 16)) & 0xffffffff;
h1 ^= k1;
}
h1 ^= key.length;
h1 ^= h1 >>> 16;
h1 = (((h1 & 0xffff) * 0x85ebca6b) + ((((h1 >>> 16) * 0x85ebca6b) & 0xffff) << 16)) & 0xffffffff;
h1 ^= h1 >>> 13;
h1 = (((h1 & 0xffff) * 0xc2b2ae35) + ((((h1 >>> 16) * 0xc2b2ae35) & 0xffff) << 16)) & 0xffffffff;
h1 ^= h1 >>> 16;
return h1 >>> 0;
}
function hashCode(input: string) {
let hash = 0;
for (let i = 0; i < input.length; i += 1) {
const char = input.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash |= 0;
}
return hash;
}
const defaultColors: MantineColor[] = [
'blue',
'cyan',
'grape',
'green',
'indigo',
'lime',
'orange',
'pink',
'red',
'teal',
'violet',
];
export function getInitialsColor(name: string, colors: MantineColor[] = defaultColors) {
const hash = hashCode(name);
const index = Math.abs(hash) % colors.length;
return colors[index];
}
export function isMessageDeliveredByTime(messageTime: number, attachmentsCount: number): boolean {
let maxMessageDeliveredTime = MESSAGE_MAX_TIME_TO_DELEVERED_S * 1000;;
//((props.time && (Date.now() - props.time * 1000 > ((MESSAGE_MAX_TIME_TO_DELEVERED * 1000) * props.attachmentsCount || 1))
if (attachmentsCount == 0) {
let t = Date.now() - messageTime < maxMessageDeliveredTime;
return t;
}
return Date.now() - messageTime < (maxMessageDeliveredTime * attachmentsCount);
}
export function filePrapareForNetworkTransfer(file : File){
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => {
if(!reader.result){
reject();
return;
}
resolve(reader.result.toString());
}
reader.readAsDataURL(file);
})
}
export function humanFilesize(size: number) {
const suffixes = ['B', 'KB', 'MB', 'GB'];
if(size >= (1024 * 1024 * 1024)){
return Math.floor(size / (1024 * 1024 * 1024)) + suffixes[3];
}
if(size >= (1024 * 1024)){
return Math.floor(size / (1024 * 1024)) + suffixes[2];
}
if(size >= 1024){
return Math.floor(size / 1024) + suffixes[1];
}
return size + suffixes[0];
}
export function imagePrepareForNetworkTransfer(file: File) {
/**
* Нужно приводить все изображения к одному формату (png) чтобы избежать проблем с отображением
* в разных платформах (ios, android, web)
*/
return new Promise<string>((resolve, reject) => {
const reader = new FileReader();
reader.onload = async () => {
if (!reader.result) {
reject();
return;
}
let base64 = reader.result.toString();
if (file.type === 'image/png') {
resolve(base64);
return;
}
try {
const jpegBlob = file;
const pngBlob = await convertJpegBlobToPngBlob(jpegBlob);
const pngBase64 = await blobToBase64(pngBlob);
resolve(pngBase64);
} catch (error) {
reject(error);
}
};
reader.readAsDataURL(file);
});
}
export function blobToBase64(blob: Blob): Promise<string> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => {
if (reader.result && typeof reader.result === "string") {
resolve(reader.result);
} else {
reject("Failed to convert blob to base64");
}
};
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
export function createBlobFromBase64Image(base64Image: string): Blob {
// Split the data URL to get the MIME type and the base64 data
const parts = base64Image.split(';');
const mimeType = parts[0].split(':')[1];
const base64 = parts[1].split(',')[1];
// Decode the base64 string
const byteCharacters = atob(base64);
const byteNumbers = new Array(byteCharacters.length);
// Convert to a Uint8Array
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
// Create the Blob
const blob = new Blob([byteArray], { type: mimeType });
return blob;
}
export function convertJpegBlobToPngBlob(jpegBlob: Blob): Promise<Blob> {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx?.drawImage(img, 0, 0);
// Convert the canvas content to a PNG Blob
canvas.toBlob((pngBlob) => {
if (pngBlob) {
resolve(pngBlob);
} else {
reject(new Error('Failed to create PNG blob.'));
}
}, 'image/png', 1);
};
img.onerror = (error) => reject(error);
img.src = URL.createObjectURL(jpegBlob);
});
}
export function dotMessageIfNeeded(message: string, maxLength: number): string {
if (message.length <= maxLength) {
return message;
}
return message.substring(0, maxLength).trim() + '...';
}
export function dotCenterIfNeeded(message: string, maxLength : number, viewSymbols : number = 3) {
if(message.length <= maxLength){
return message;
}
return message.slice(0, viewSymbols) + "..." + message.slice(-viewSymbols)
}
export function isImage(blob : string) : boolean {
if(!blob){
return false;
}
return blob.startsWith('data:image/');
}
export function blurhashToBase64Image(blurhash: string, width: number, height: number): string {
const pixels = decode(blurhash, width, height);
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
const imageData = ctx?.createImageData(width, height);
if (imageData) {
imageData.data.set(pixels);
ctx?.putImageData(imageData, 0, 0);
return canvas.toDataURL();
}
return '';
}
export function base64ImageToBlurhash(base64Image: string): Promise<string> {
const img = new Image();
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
return new Promise<string>((resolve, reject) => {
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx?.drawImage(img, 0, 0);
const imageData = ctx?.getImageData(0, 0, canvas.width, canvas.height);
if (imageData) {
const blurhash = encode(
imageData.data,
imageData.width,
imageData.height,
4,
4
);
resolve(blurhash);
} else {
reject('Failed to get image data from canvas.');
}
};
img.onerror = (error) => reject(error);
img.src = base64Image;
});
}