Stickers optimizations
File reference database Misc
This commit is contained in:
parent
3e978a8244
commit
f2b5363bb8
70
package-lock.json
generated
70
package-lock.json
generated
@ -3177,15 +3177,6 @@
|
||||
"integrity": "sha512-GdZbRSJ3Cv5fiwT6I0SQ3ckeN2PWNqxd26W9Z2fCK1tGrrasGy4puvNFtnddqH9UJFMQYXxEuuB7B8UK+LLwSg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/puppeteer": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/puppeteer/-/puppeteer-3.0.1.tgz",
|
||||
"integrity": "sha512-t03eNKCvWJXhQ8wkc5C6GYuSqMEdKLOX0GLMGtks25YZr38wKZlKTwGM/BoAPVtdysX7Bb9tdwrDS1+NrW3RRA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/pvutils": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/pvutils/-/pvutils-0.0.2.tgz",
|
||||
@ -6461,15 +6452,6 @@
|
||||
"pako": "^1.0.10"
|
||||
}
|
||||
},
|
||||
"fastdom": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/fastdom/-/fastdom-1.0.9.tgz",
|
||||
"integrity": "sha512-SSp4fbVzu8JkkG01NUX+0iOwe9M5PN3MGIQ84txLf4TkkJG4q30khkzumKgi4hUqO1+jX6wLHfnCPoZ6eSZ6Tg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"strictdom": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"fastparse": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
|
||||
@ -6499,28 +6481,6 @@
|
||||
"integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==",
|
||||
"dev": true
|
||||
},
|
||||
"file-loader": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/file-loader/-/file-loader-4.3.0.tgz",
|
||||
"integrity": "sha512-aKrYPYjF1yG3oX0kWRrqrSMfgftm7oJW5M+m4owoldH5C51C0RkIwB++JbRvEW3IU6/ZG5n8UvEcdgwOt2UOWA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "^1.2.3",
|
||||
"schema-utils": "^2.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"schema-utils": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.6.2.tgz",
|
||||
"integrity": "sha512-sazKNMBX/jwrXRkOI7N6dtiTVYqzSckzol8SGuHt0lE/v3xSW6cUkOqzu6Bq2tW+dlUzq3CWIqHU3ZKauliqdg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ajv": "^6.10.2",
|
||||
"ajv-keywords": "^3.4.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"file-uri-to-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
|
||||
@ -9288,12 +9248,6 @@
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"lottie-web": {
|
||||
"version": "5.6.10",
|
||||
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.6.10.tgz",
|
||||
"integrity": "sha512-ucTzaiBJOMm56/K7Wqjajyh7qXlonHKB3+b5fHvhSiz+jOrXt6QDNKAinI3qdw/zvvYHKzXvFMy5SgOXbOJ5ng==",
|
||||
"dev": true
|
||||
},
|
||||
"loud-rejection": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
|
||||
@ -16721,24 +16675,12 @@
|
||||
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
|
||||
"dev": true
|
||||
},
|
||||
"streamsaver": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/streamsaver/-/streamsaver-2.0.4.tgz",
|
||||
"integrity": "sha512-rGES0zmHIPxinV32H2Dz55qgOE5dXui8yfu+JEjPAI294cDmwX4Oe7tCZLrnhjc/1z7hyIv9H6TMH2kqN2Tdqw==",
|
||||
"dev": true
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
|
||||
"dev": true
|
||||
},
|
||||
"strictdom": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strictdom/-/strictdom-1.0.1.tgz",
|
||||
"integrity": "sha1-GJ3pFkn3PUTVm4Qy76aO+dJllGA=",
|
||||
"dev": true
|
||||
},
|
||||
"string-length": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz",
|
||||
@ -17974,12 +17916,6 @@
|
||||
"minimalistic-assert": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"web-streams-polyfill": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-2.1.1.tgz",
|
||||
"integrity": "sha512-dlNpL2aab3g8CKfGz6rl8FNmGaRWLLn2g/DtSc9IjB30mEdE6XxzPfPSig5BwGSzI+oLxHyETrQGKjrVVhbLCg==",
|
||||
"dev": true
|
||||
},
|
||||
"webcrypto-core": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.1.6.tgz",
|
||||
@ -18007,12 +17943,6 @@
|
||||
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
|
||||
"dev": true
|
||||
},
|
||||
"webp-hero": {
|
||||
"version": "0.0.0-dev.24",
|
||||
"resolved": "https://registry.npmjs.org/webp-hero/-/webp-hero-0.0.0-dev.24.tgz",
|
||||
"integrity": "sha512-3XG47dRMV36RFwfYLUynOiKDXuqXfQ3dz7yvqGH5VplldV0NvngQzF0qBsZ3vRQwrigekRLeX/NdNwsaGfSnPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"webpack": {
|
||||
"version": "4.43.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-4.43.0.tgz",
|
||||
|
12
package.json
12
package.json
@ -4,7 +4,7 @@
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node --max-old-space-size=8192 node_modules/webpack-dev-server/bin/webpack-dev-server.js --config webpack.dev.js",
|
||||
"start": "node --max-old-space-size=12048 node_modules/webpack-dev-server/bin/webpack-dev-server.js --config webpack.dev.js",
|
||||
"start:production": "webpack-dev-server --config webpack.prod.js",
|
||||
"serve": "npm run build; node server.js",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
@ -12,7 +12,8 @@
|
||||
"test": "jest --config=jest.config.js",
|
||||
"profile": "webpack --profile --json > stats.json --config webpack.prod.js",
|
||||
"profile:dev": "webpack --profile --json > stats.json --config webpack.dev.js",
|
||||
"whybundled": "npm run profile; whybundled stats.json"
|
||||
"whybundled": "npm run profile && whybundled stats.json",
|
||||
"generate-mtproto-types": "node ./src/scripts/generate_mtproto_types.js src/"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
@ -31,7 +32,6 @@
|
||||
"@types/aes-js": "^3.1.1",
|
||||
"@types/chrome": "0.0.91",
|
||||
"@types/jest": "^24.9.1",
|
||||
"@types/puppeteer": "^3.0.1",
|
||||
"@types/serviceworker-webpack-plugin": "^1.0.1",
|
||||
"aes-js": "^3.1.2",
|
||||
"autoprefixer": "^9.8.0",
|
||||
@ -41,8 +41,6 @@
|
||||
"css-loader": "^3.5.3",
|
||||
"express": "^4.17.1",
|
||||
"fast-png": "^5.0.2",
|
||||
"fastdom": "^1.0.9",
|
||||
"file-loader": "^4.3.0",
|
||||
"handlebars": "^4.7.6",
|
||||
"handlebars-loader": "^1.7.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
@ -50,7 +48,6 @@
|
||||
"install": "^0.13.0",
|
||||
"jest": "^24.9.0",
|
||||
"leemon": "^6.2.0",
|
||||
"lottie-web": "^5.6.10",
|
||||
"media-query-plugin": "^1.3.1",
|
||||
"mini-css-extract-plugin": "^0.9.0",
|
||||
"node-sass": "^4.14.1",
|
||||
@ -65,15 +62,12 @@
|
||||
"resolve-url-loader": "^3.1.1",
|
||||
"sass-loader": "^8.0.2",
|
||||
"serviceworker-webpack-plugin": "^1.0.1",
|
||||
"streamsaver": "^2.0.4",
|
||||
"style-loader": "^1.2.1",
|
||||
"terser-webpack-plugin": "^3.0.2",
|
||||
"ts-jest": "^24.3.0",
|
||||
"ts-loader": "^6.2.2",
|
||||
"typescript": "^3.9.3",
|
||||
"url-loader": "^2.3.0",
|
||||
"web-streams-polyfill": "^2.1.1",
|
||||
"webp-hero": "0.0.0-dev.24",
|
||||
"webpack": "^4.43.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-merge": "^4.2.2",
|
||||
|
@ -62,7 +62,7 @@ function wrapVoiceMessage(doc: MyDocument, audioEl: AudioElement) {
|
||||
timeDiv.classList.add('audio-time');
|
||||
audioEl.append(svg, timeDiv);
|
||||
|
||||
let waveform = (doc.attributes.find(attribute => attribute._ == 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || [];
|
||||
let waveform = (doc.attributes.find(attribute => attribute._ == 'documentAttributeAudio') as DocumentAttribute.documentAttributeAudio).waveform || new Uint8Array([]);
|
||||
waveform = decodeWaveform(waveform.slice());
|
||||
|
||||
//console.log('decoded waveform:', waveform);
|
||||
|
@ -147,7 +147,8 @@ export default class StickersTab implements EmoticonsTab {
|
||||
autoplay: false,
|
||||
animationData: json,
|
||||
width: 32,
|
||||
height: 32
|
||||
height: 32,
|
||||
needUpscale: true
|
||||
}, EMOTICONSSTICKERGROUP);
|
||||
});
|
||||
} else {
|
||||
|
@ -10,7 +10,7 @@ import animationIntersector from "../animationIntersector";
|
||||
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||
import { wrapSticker } from "../wrappers";
|
||||
import appSidebarRight, { AppSidebarRight } from "../../lib/appManagers/appSidebarRight";
|
||||
import { StickerSet, StickerSetCovered, Document } from "../../layer";
|
||||
import { StickerSet, StickerSetCovered } from "../../layer";
|
||||
|
||||
export default class AppStickersTab implements SliderTab {
|
||||
private container = document.getElementById('stickers-container') as HTMLDivElement;
|
||||
|
31
src/helpers/json.ts
Normal file
31
src/helpers/json.ts
Normal file
@ -0,0 +1,31 @@
|
||||
export function parse(text: string) {
|
||||
let arr: number[] = [], performedValue: any = null;
|
||||
return JSON.parse(text, (key, value) => {
|
||||
//console.log(key, value);
|
||||
if(key == 'type' && value == 'bytes') {
|
||||
arr = [];
|
||||
return undefined;
|
||||
} else if(arr) {
|
||||
if(key == 'value') {
|
||||
performedValue = new Uint8Array(arr);
|
||||
arr = null;
|
||||
return undefined;
|
||||
} else arr[+key] = value;
|
||||
} else if(performedValue) {
|
||||
const v = performedValue;
|
||||
performedValue = null;
|
||||
return v;
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
// parse('{"file_reference": {"type": "bytes", "value": [1,2,3]}, "file_reference2": {"type": "bytes", "value": [3,2,1]}}');
|
||||
// -> {file_reference: Uint8Array}
|
||||
|
||||
export function stringify(value: any) {
|
||||
return JSON.stringify(value, (key, value) => {
|
||||
if(key == 'downloaded' || (key == 'url' && value.indexOf('blob:') === 0)) return undefined;
|
||||
return value;
|
||||
});
|
||||
}
|
211
src/layer.d.ts
vendored
211
src/layer.d.ts
vendored
@ -223,7 +223,7 @@ export namespace InputMedia {
|
||||
description: string,
|
||||
photo?: InputWebDocument,
|
||||
invoice: Invoice,
|
||||
payload: Uint8Array | number[],
|
||||
payload: Uint8Array,
|
||||
provider: string,
|
||||
provider_data: DataJSON,
|
||||
start_param: string
|
||||
@ -243,7 +243,7 @@ export namespace InputMedia {
|
||||
_: 'inputMediaPoll',
|
||||
flags?: number,
|
||||
poll: Poll,
|
||||
correct_answers?: Array<Uint8Array | number[]>,
|
||||
correct_answers?: Array<Uint8Array>,
|
||||
solution?: string,
|
||||
solution_entities?: Array<MessageEntity>
|
||||
};
|
||||
@ -770,7 +770,8 @@ export type Message = Message.messageEmpty | Message.message | Message.messageSe
|
||||
export namespace Message {
|
||||
export type messageEmpty = {
|
||||
_: 'messageEmpty',
|
||||
id: number
|
||||
id: number,
|
||||
deleted?: boolean
|
||||
};
|
||||
|
||||
export type message = {
|
||||
@ -785,6 +786,7 @@ export namespace Message {
|
||||
from_scheduled?: true,
|
||||
legacy?: true,
|
||||
edit_hide?: true,
|
||||
unread?: true,
|
||||
}>,
|
||||
id: number,
|
||||
from_id?: number,
|
||||
@ -801,7 +803,12 @@ export namespace Message {
|
||||
edit_date?: number,
|
||||
post_author?: string,
|
||||
grouped_id?: string,
|
||||
restriction_reason?: Array<RestrictionReason>
|
||||
restriction_reason?: Array<RestrictionReason>,
|
||||
mid?: number,
|
||||
deleted?: boolean,
|
||||
peerID?: number,
|
||||
fromID?: number,
|
||||
canBeEdited?: boolean
|
||||
};
|
||||
|
||||
export type messageService = {
|
||||
@ -814,13 +821,19 @@ export namespace Message {
|
||||
silent?: true,
|
||||
post?: true,
|
||||
legacy?: true,
|
||||
unread?: true,
|
||||
}>,
|
||||
id: number,
|
||||
from_id?: number,
|
||||
to_id: Peer,
|
||||
reply_to_msg_id?: number,
|
||||
date: number,
|
||||
action: MessageAction
|
||||
action: MessageAction,
|
||||
mid?: number,
|
||||
deleted?: boolean,
|
||||
peerID?: number,
|
||||
fromID?: number,
|
||||
canBeEdited?: boolean
|
||||
};
|
||||
}
|
||||
|
||||
@ -1001,7 +1014,7 @@ export namespace MessageAction {
|
||||
flags?: number,
|
||||
currency: string,
|
||||
total_amount: string,
|
||||
payload: Uint8Array | number[],
|
||||
payload: Uint8Array,
|
||||
info?: PaymentRequestedInfo,
|
||||
shipping_option_id?: string,
|
||||
charge: PaymentCharge
|
||||
@ -1155,14 +1168,14 @@ export namespace PhotoSize {
|
||||
location: FileLocation,
|
||||
w: number,
|
||||
h: number,
|
||||
bytes: Uint8Array | number[],
|
||||
bytes: Uint8Array,
|
||||
url?: string
|
||||
};
|
||||
|
||||
export type photoStrippedSize = {
|
||||
_: 'photoStrippedSize',
|
||||
type: string,
|
||||
bytes: Uint8Array | number[],
|
||||
bytes: Uint8Array,
|
||||
url?: string
|
||||
};
|
||||
}
|
||||
@ -1230,7 +1243,7 @@ export namespace AuthExportedAuthorization {
|
||||
export type authExportedAuthorization = {
|
||||
_: 'auth.exportedAuthorization',
|
||||
id: number,
|
||||
bytes: Uint8Array | number[]
|
||||
bytes: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -2003,7 +2016,7 @@ export namespace Update {
|
||||
peer: Peer,
|
||||
msg_id: number,
|
||||
chat_instance: string,
|
||||
data?: Uint8Array | number[],
|
||||
data?: Uint8Array,
|
||||
game_short_name?: string
|
||||
};
|
||||
|
||||
@ -2021,7 +2034,7 @@ export namespace Update {
|
||||
user_id: number,
|
||||
msg_id: InputBotInlineMessageID,
|
||||
chat_instance: string,
|
||||
data?: Uint8Array | number[],
|
||||
data?: Uint8Array,
|
||||
game_short_name?: string
|
||||
};
|
||||
|
||||
@ -2094,7 +2107,7 @@ export namespace Update {
|
||||
_: 'updateBotShippingQuery',
|
||||
query_id: string,
|
||||
user_id: number,
|
||||
payload: Uint8Array | number[],
|
||||
payload: Uint8Array,
|
||||
shipping_address: PostAddress
|
||||
};
|
||||
|
||||
@ -2103,7 +2116,7 @@ export namespace Update {
|
||||
flags?: number,
|
||||
query_id: string,
|
||||
user_id: number,
|
||||
payload: Uint8Array | number[],
|
||||
payload: Uint8Array,
|
||||
info?: PaymentRequestedInfo,
|
||||
shipping_option_id?: string,
|
||||
currency: string,
|
||||
@ -2230,7 +2243,7 @@ export namespace Update {
|
||||
_: 'updateMessagePollVote',
|
||||
poll_id: string,
|
||||
user_id: number,
|
||||
options: Array<Uint8Array | number[]>
|
||||
options: Array<Uint8Array>
|
||||
};
|
||||
|
||||
export type updateDialogFilter = {
|
||||
@ -2440,15 +2453,15 @@ export namespace UploadFile {
|
||||
_: 'upload.file',
|
||||
type: StorageFileType,
|
||||
mtime: number,
|
||||
bytes: Uint8Array | number[]
|
||||
bytes: Uint8Array
|
||||
};
|
||||
|
||||
export type uploadFileCdnRedirect = {
|
||||
_: 'upload.fileCdnRedirect',
|
||||
dc_id: number,
|
||||
file_token: Uint8Array | number[],
|
||||
encryption_key: Uint8Array | number[],
|
||||
encryption_iv: Uint8Array | number[],
|
||||
file_token: Uint8Array,
|
||||
encryption_key: Uint8Array,
|
||||
encryption_iv: Uint8Array,
|
||||
file_hashes: Array<FileHash>
|
||||
};
|
||||
}
|
||||
@ -2472,7 +2485,7 @@ export namespace DcOption {
|
||||
id: number,
|
||||
ip_address: string,
|
||||
port: number,
|
||||
secret?: Uint8Array | number[]
|
||||
secret?: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -2619,7 +2632,7 @@ export namespace EncryptedChat {
|
||||
date: number,
|
||||
admin_id: number,
|
||||
participant_id: number,
|
||||
g_a: Uint8Array | number[]
|
||||
g_a: Uint8Array
|
||||
};
|
||||
|
||||
export type encryptedChat = {
|
||||
@ -2629,7 +2642,7 @@ export namespace EncryptedChat {
|
||||
date: number,
|
||||
admin_id: number,
|
||||
participant_id: number,
|
||||
g_a_or_b: Uint8Array | number[],
|
||||
g_a_or_b: Uint8Array,
|
||||
key_fingerprint: string
|
||||
};
|
||||
|
||||
@ -2715,7 +2728,7 @@ export namespace EncryptedMessage {
|
||||
random_id: string,
|
||||
chat_id: number,
|
||||
date: number,
|
||||
bytes: Uint8Array | number[],
|
||||
bytes: Uint8Array,
|
||||
file: EncryptedFile
|
||||
};
|
||||
|
||||
@ -2724,7 +2737,7 @@ export namespace EncryptedMessage {
|
||||
random_id: string,
|
||||
chat_id: number,
|
||||
date: number,
|
||||
bytes: Uint8Array | number[]
|
||||
bytes: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -2736,15 +2749,15 @@ export type MessagesDhConfig = MessagesDhConfig.messagesDhConfigNotModified | Me
|
||||
export namespace MessagesDhConfig {
|
||||
export type messagesDhConfigNotModified = {
|
||||
_: 'messages.dhConfigNotModified',
|
||||
random: Uint8Array | number[]
|
||||
random: Uint8Array
|
||||
};
|
||||
|
||||
export type messagesDhConfig = {
|
||||
_: 'messages.dhConfig',
|
||||
g: number,
|
||||
p: Uint8Array | number[],
|
||||
p: Uint8Array,
|
||||
version: number,
|
||||
random: Uint8Array | number[]
|
||||
random: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -3183,7 +3196,7 @@ export namespace DocumentAttribute {
|
||||
duration: number,
|
||||
title?: string,
|
||||
performer?: string,
|
||||
waveform?: Uint8Array | number[]
|
||||
waveform?: Uint8Array
|
||||
};
|
||||
|
||||
export type documentAttributeFilename = {
|
||||
@ -3359,13 +3372,13 @@ export namespace AccountPassword {
|
||||
has_password?: true,
|
||||
}>,
|
||||
current_algo?: PasswordKdfAlgo,
|
||||
srp_B?: Uint8Array | number[],
|
||||
srp_B?: Uint8Array,
|
||||
srp_id?: string,
|
||||
hint?: string,
|
||||
email_unconfirmed_pattern?: string,
|
||||
new_algo: PasswordKdfAlgo,
|
||||
new_secure_algo: SecurePasswordKdfAlgo,
|
||||
secure_random: Uint8Array | number[]
|
||||
secure_random: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -3393,7 +3406,7 @@ export namespace AccountPasswordInputSettings {
|
||||
_: 'account.passwordInputSettings',
|
||||
flags?: number,
|
||||
new_algo?: PasswordKdfAlgo,
|
||||
new_password_hash?: Uint8Array | number[],
|
||||
new_password_hash?: Uint8Array,
|
||||
hint?: string,
|
||||
email?: string,
|
||||
new_secure_settings?: SecureSecretSettings
|
||||
@ -3587,7 +3600,7 @@ export namespace KeyboardButton {
|
||||
export type keyboardButtonCallback = {
|
||||
_: 'keyboardButtonCallback',
|
||||
text: string,
|
||||
data: Uint8Array | number[]
|
||||
data: Uint8Array
|
||||
};
|
||||
|
||||
export type keyboardButtonRequestPhone = {
|
||||
@ -5307,7 +5320,7 @@ export namespace UploadWebFile {
|
||||
mime_type: string,
|
||||
file_type: StorageFileType,
|
||||
mtime: number,
|
||||
bytes: Uint8Array | number[]
|
||||
bytes: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -5414,7 +5427,7 @@ export namespace InputPaymentCredentials {
|
||||
export type inputPaymentCredentialsSaved = {
|
||||
_: 'inputPaymentCredentialsSaved',
|
||||
id: string,
|
||||
tmp_password: Uint8Array | number[]
|
||||
tmp_password: Uint8Array
|
||||
};
|
||||
|
||||
export type inputPaymentCredentials = {
|
||||
@ -5446,7 +5459,7 @@ export type AccountTmpPassword = AccountTmpPassword.accountTmpPassword;
|
||||
export namespace AccountTmpPassword {
|
||||
export type accountTmpPassword = {
|
||||
_: 'account.tmpPassword',
|
||||
tmp_password: Uint8Array | number[],
|
||||
tmp_password: Uint8Array,
|
||||
valid_until: number
|
||||
};
|
||||
}
|
||||
@ -5530,7 +5543,7 @@ export namespace PhoneCall {
|
||||
date: number,
|
||||
admin_id: number,
|
||||
participant_id: number,
|
||||
g_a_hash: Uint8Array | number[],
|
||||
g_a_hash: Uint8Array,
|
||||
protocol: PhoneCallProtocol
|
||||
};
|
||||
|
||||
@ -5545,7 +5558,7 @@ export namespace PhoneCall {
|
||||
date: number,
|
||||
admin_id: number,
|
||||
participant_id: number,
|
||||
g_b: Uint8Array | number[],
|
||||
g_b: Uint8Array,
|
||||
protocol: PhoneCallProtocol
|
||||
};
|
||||
|
||||
@ -5560,7 +5573,7 @@ export namespace PhoneCall {
|
||||
date: number,
|
||||
admin_id: number,
|
||||
participant_id: number,
|
||||
g_a_or_b: Uint8Array | number[],
|
||||
g_a_or_b: Uint8Array,
|
||||
key_fingerprint: string,
|
||||
protocol: PhoneCallProtocol,
|
||||
connections: Array<PhoneConnection>,
|
||||
@ -5593,7 +5606,7 @@ export namespace PhoneConnection {
|
||||
ip: string,
|
||||
ipv6: string,
|
||||
port: number,
|
||||
peer_tag: Uint8Array | number[]
|
||||
peer_tag: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -5637,12 +5650,12 @@ export type UploadCdnFile = UploadCdnFile.uploadCdnFileReuploadNeeded | UploadCd
|
||||
export namespace UploadCdnFile {
|
||||
export type uploadCdnFileReuploadNeeded = {
|
||||
_: 'upload.cdnFileReuploadNeeded',
|
||||
request_token: Uint8Array | number[]
|
||||
request_token: Uint8Array
|
||||
};
|
||||
|
||||
export type uploadCdnFile = {
|
||||
_: 'upload.cdnFile',
|
||||
bytes: Uint8Array | number[]
|
||||
bytes: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6132,7 +6145,7 @@ export namespace FileHash {
|
||||
_: 'fileHash',
|
||||
offset: number,
|
||||
limit: number,
|
||||
hash: Uint8Array | number[]
|
||||
hash: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6178,8 +6191,8 @@ export namespace InputSecureFile {
|
||||
id: string,
|
||||
parts: number,
|
||||
md5_checksum: string,
|
||||
file_hash: Uint8Array | number[],
|
||||
secret: Uint8Array | number[]
|
||||
file_hash: Uint8Array,
|
||||
secret: Uint8Array
|
||||
};
|
||||
|
||||
export type inputSecureFile = {
|
||||
@ -6206,8 +6219,8 @@ export namespace SecureFile {
|
||||
size: number,
|
||||
dc_id: number,
|
||||
date: number,
|
||||
file_hash: Uint8Array | number[],
|
||||
secret: Uint8Array | number[]
|
||||
file_hash: Uint8Array,
|
||||
secret: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6219,9 +6232,9 @@ export type SecureData = SecureData.secureData;
|
||||
export namespace SecureData {
|
||||
export type secureData = {
|
||||
_: 'secureData',
|
||||
data: Uint8Array | number[],
|
||||
data_hash: Uint8Array | number[],
|
||||
secret: Uint8Array | number[]
|
||||
data: Uint8Array,
|
||||
data_hash: Uint8Array,
|
||||
secret: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6318,7 +6331,7 @@ export namespace SecureValue {
|
||||
translation?: Array<SecureFile>,
|
||||
files?: Array<SecureFile>,
|
||||
plain_data?: SecurePlainData,
|
||||
hash: Uint8Array | number[]
|
||||
hash: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6351,7 +6364,7 @@ export namespace SecureValueHash {
|
||||
export type secureValueHash = {
|
||||
_: 'secureValueHash',
|
||||
type: SecureValueType,
|
||||
hash: Uint8Array | number[]
|
||||
hash: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6364,7 +6377,7 @@ export namespace SecureValueError {
|
||||
export type secureValueErrorData = {
|
||||
_: 'secureValueErrorData',
|
||||
type: SecureValueType,
|
||||
data_hash: Uint8Array | number[],
|
||||
data_hash: Uint8Array,
|
||||
field: string,
|
||||
text: string
|
||||
};
|
||||
@ -6372,56 +6385,56 @@ export namespace SecureValueError {
|
||||
export type secureValueErrorFrontSide = {
|
||||
_: 'secureValueErrorFrontSide',
|
||||
type: SecureValueType,
|
||||
file_hash: Uint8Array | number[],
|
||||
file_hash: Uint8Array,
|
||||
text: string
|
||||
};
|
||||
|
||||
export type secureValueErrorReverseSide = {
|
||||
_: 'secureValueErrorReverseSide',
|
||||
type: SecureValueType,
|
||||
file_hash: Uint8Array | number[],
|
||||
file_hash: Uint8Array,
|
||||
text: string
|
||||
};
|
||||
|
||||
export type secureValueErrorSelfie = {
|
||||
_: 'secureValueErrorSelfie',
|
||||
type: SecureValueType,
|
||||
file_hash: Uint8Array | number[],
|
||||
file_hash: Uint8Array,
|
||||
text: string
|
||||
};
|
||||
|
||||
export type secureValueErrorFile = {
|
||||
_: 'secureValueErrorFile',
|
||||
type: SecureValueType,
|
||||
file_hash: Uint8Array | number[],
|
||||
file_hash: Uint8Array,
|
||||
text: string
|
||||
};
|
||||
|
||||
export type secureValueErrorFiles = {
|
||||
_: 'secureValueErrorFiles',
|
||||
type: SecureValueType,
|
||||
file_hash: Array<Uint8Array | number[]>,
|
||||
file_hash: Array<Uint8Array>,
|
||||
text: string
|
||||
};
|
||||
|
||||
export type secureValueError = {
|
||||
_: 'secureValueError',
|
||||
type: SecureValueType,
|
||||
hash: Uint8Array | number[],
|
||||
hash: Uint8Array,
|
||||
text: string
|
||||
};
|
||||
|
||||
export type secureValueErrorTranslationFile = {
|
||||
_: 'secureValueErrorTranslationFile',
|
||||
type: SecureValueType,
|
||||
file_hash: Uint8Array | number[],
|
||||
file_hash: Uint8Array,
|
||||
text: string
|
||||
};
|
||||
|
||||
export type secureValueErrorTranslationFiles = {
|
||||
_: 'secureValueErrorTranslationFiles',
|
||||
type: SecureValueType,
|
||||
file_hash: Array<Uint8Array | number[]>,
|
||||
file_hash: Array<Uint8Array>,
|
||||
text: string
|
||||
};
|
||||
}
|
||||
@ -6434,9 +6447,9 @@ export type SecureCredentialsEncrypted = SecureCredentialsEncrypted.secureCreden
|
||||
export namespace SecureCredentialsEncrypted {
|
||||
export type secureCredentialsEncrypted = {
|
||||
_: 'secureCredentialsEncrypted',
|
||||
data: Uint8Array | number[],
|
||||
hash: Uint8Array | number[],
|
||||
secret: Uint8Array | number[]
|
||||
data: Uint8Array,
|
||||
hash: Uint8Array,
|
||||
secret: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6530,10 +6543,10 @@ export namespace PasswordKdfAlgo {
|
||||
|
||||
export type passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow = {
|
||||
_: 'passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow',
|
||||
salt1: Uint8Array | number[],
|
||||
salt2: Uint8Array | number[],
|
||||
salt1: Uint8Array,
|
||||
salt2: Uint8Array,
|
||||
g: number,
|
||||
p: Uint8Array | number[]
|
||||
p: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6549,12 +6562,12 @@ export namespace SecurePasswordKdfAlgo {
|
||||
|
||||
export type securePasswordKdfAlgoPBKDF2HMACSHA512iter100000 = {
|
||||
_: 'securePasswordKdfAlgoPBKDF2HMACSHA512iter100000',
|
||||
salt: Uint8Array | number[]
|
||||
salt: Uint8Array
|
||||
};
|
||||
|
||||
export type securePasswordKdfAlgoSHA512 = {
|
||||
_: 'securePasswordKdfAlgoSHA512',
|
||||
salt: Uint8Array | number[]
|
||||
salt: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6567,7 +6580,7 @@ export namespace SecureSecretSettings {
|
||||
export type secureSecretSettings = {
|
||||
_: 'secureSecretSettings',
|
||||
secure_algo: SecurePasswordKdfAlgo,
|
||||
secure_secret: Uint8Array | number[],
|
||||
secure_secret: Uint8Array,
|
||||
secure_secret_id: string
|
||||
};
|
||||
}
|
||||
@ -6585,8 +6598,8 @@ export namespace InputCheckPasswordSRP {
|
||||
export type inputCheckPasswordSRP = {
|
||||
_: 'inputCheckPasswordSRP',
|
||||
srp_id: string,
|
||||
A: Uint8Array | number[],
|
||||
M1: Uint8Array | number[]
|
||||
A: Uint8Array,
|
||||
M1: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6858,7 +6871,7 @@ export namespace PollAnswer {
|
||||
export type pollAnswer = {
|
||||
_: 'pollAnswer',
|
||||
text: string,
|
||||
option: Uint8Array | number[]
|
||||
option: Uint8Array
|
||||
};
|
||||
}
|
||||
|
||||
@ -6898,7 +6911,7 @@ export namespace PollAnswerVoters {
|
||||
chosen?: true,
|
||||
correct?: true,
|
||||
}>,
|
||||
option: Uint8Array | number[],
|
||||
option: Uint8Array,
|
||||
voters: number
|
||||
};
|
||||
}
|
||||
@ -7385,13 +7398,13 @@ export namespace AuthLoginToken {
|
||||
export type authLoginToken = {
|
||||
_: 'auth.loginToken',
|
||||
expires: number,
|
||||
token: Uint8Array | number[]
|
||||
token: Uint8Array
|
||||
};
|
||||
|
||||
export type authLoginTokenMigrateTo = {
|
||||
_: 'auth.loginTokenMigrateTo',
|
||||
dc_id: number,
|
||||
token: Uint8Array | number[]
|
||||
token: Uint8Array
|
||||
};
|
||||
|
||||
export type authLoginTokenSuccess = {
|
||||
@ -7515,7 +7528,7 @@ export namespace MessageUserVote {
|
||||
export type messageUserVote = {
|
||||
_: 'messageUserVote',
|
||||
user_id: number,
|
||||
option: Uint8Array | number[],
|
||||
option: Uint8Array,
|
||||
date: number
|
||||
};
|
||||
|
||||
@ -7528,7 +7541,7 @@ export namespace MessageUserVote {
|
||||
export type messageUserVoteMultiple = {
|
||||
_: 'messageUserVoteMultiple',
|
||||
user_id: number,
|
||||
options: Array<Uint8Array | number[]>,
|
||||
options: Array<Uint8Array>,
|
||||
date: number
|
||||
};
|
||||
}
|
||||
@ -8645,14 +8658,14 @@ export type AuthExportAuthorization = {
|
||||
|
||||
export type AuthImportAuthorization = {
|
||||
id: number,
|
||||
bytes: Uint8Array | number[]
|
||||
bytes: Uint8Array
|
||||
};
|
||||
|
||||
export type AuthBindTempAuthKey = {
|
||||
perm_auth_key_id: string,
|
||||
nonce: string,
|
||||
expires_at: number,
|
||||
encrypted_message: Uint8Array | number[]
|
||||
encrypted_message: Uint8Array
|
||||
};
|
||||
|
||||
export type AuthImportBotAuthorization = {
|
||||
@ -8695,11 +8708,11 @@ export type AuthExportLoginToken = {
|
||||
};
|
||||
|
||||
export type AuthImportLoginToken = {
|
||||
token: Uint8Array | number[]
|
||||
token: Uint8Array
|
||||
};
|
||||
|
||||
export type AuthAcceptLoginToken = {
|
||||
token: Uint8Array | number[]
|
||||
token: Uint8Array
|
||||
};
|
||||
|
||||
export type AccountRegisterDevice = {
|
||||
@ -8708,7 +8721,7 @@ export type AccountRegisterDevice = {
|
||||
token_type: number,
|
||||
token: string,
|
||||
app_sandbox: boolean,
|
||||
secret: Uint8Array | number[],
|
||||
secret: Uint8Array,
|
||||
other_uids: Array<number>
|
||||
};
|
||||
|
||||
@ -9314,12 +9327,12 @@ export type MessagesGetDhConfig = {
|
||||
export type MessagesRequestEncryption = {
|
||||
user_id: InputUser,
|
||||
random_id: number,
|
||||
g_a: Uint8Array | number[]
|
||||
g_a: Uint8Array
|
||||
};
|
||||
|
||||
export type MessagesAcceptEncryption = {
|
||||
peer: InputEncryptedChat,
|
||||
g_b: Uint8Array | number[],
|
||||
g_b: Uint8Array,
|
||||
key_fingerprint: string
|
||||
};
|
||||
|
||||
@ -9340,20 +9353,20 @@ export type MessagesReadEncryptedHistory = {
|
||||
export type MessagesSendEncrypted = {
|
||||
peer: InputEncryptedChat,
|
||||
random_id: string,
|
||||
data: Uint8Array | number[]
|
||||
data: Uint8Array
|
||||
};
|
||||
|
||||
export type MessagesSendEncryptedFile = {
|
||||
peer: InputEncryptedChat,
|
||||
random_id: string,
|
||||
data: Uint8Array | number[],
|
||||
data: Uint8Array,
|
||||
file: InputEncryptedFile
|
||||
};
|
||||
|
||||
export type MessagesSendEncryptedService = {
|
||||
peer: InputEncryptedChat,
|
||||
random_id: string,
|
||||
data: Uint8Array | number[]
|
||||
data: Uint8Array
|
||||
};
|
||||
|
||||
export type MessagesReceivedQueue = {
|
||||
@ -9448,7 +9461,7 @@ export type MessagesReorderStickerSets = {
|
||||
};
|
||||
|
||||
export type MessagesGetDocumentByHash = {
|
||||
sha256: Uint8Array | number[],
|
||||
sha256: Uint8Array,
|
||||
size: number,
|
||||
mime_type: string
|
||||
};
|
||||
@ -9533,7 +9546,7 @@ export type MessagesGetBotCallbackAnswer = {
|
||||
game?: true,
|
||||
peer: InputPeer,
|
||||
msg_id: number,
|
||||
data?: Uint8Array | number[]
|
||||
data?: Uint8Array
|
||||
};
|
||||
|
||||
export type MessagesSetBotCallbackAnswer = {
|
||||
@ -9769,7 +9782,7 @@ export type MessagesUpdatePinnedMessage = {
|
||||
export type MessagesSendVote = {
|
||||
peer: InputPeer,
|
||||
msg_id: number,
|
||||
options: Array<Uint8Array | number[]>
|
||||
options: Array<Uint8Array>
|
||||
};
|
||||
|
||||
export type MessagesGetPollResults = {
|
||||
@ -9862,7 +9875,7 @@ export type MessagesGetPollVotes = {
|
||||
flags?: number,
|
||||
peer: InputPeer,
|
||||
id: number,
|
||||
option?: Uint8Array | number[],
|
||||
option?: Uint8Array,
|
||||
offset?: string,
|
||||
limit: number
|
||||
};
|
||||
@ -9942,7 +9955,7 @@ export type PhotosGetUserPhotos = {
|
||||
export type UploadSaveFilePart = {
|
||||
file_id: string,
|
||||
file_part: number,
|
||||
bytes: Uint8Array | number[]
|
||||
bytes: Uint8Array
|
||||
};
|
||||
|
||||
export type UploadGetFile = {
|
||||
@ -9958,7 +9971,7 @@ export type UploadSaveBigFilePart = {
|
||||
file_id: string,
|
||||
file_part: number,
|
||||
file_total_parts: number,
|
||||
bytes: Uint8Array | number[]
|
||||
bytes: Uint8Array
|
||||
};
|
||||
|
||||
export type UploadGetWebFile = {
|
||||
@ -9968,18 +9981,18 @@ export type UploadGetWebFile = {
|
||||
};
|
||||
|
||||
export type UploadGetCdnFile = {
|
||||
file_token: Uint8Array | number[],
|
||||
file_token: Uint8Array,
|
||||
offset: number,
|
||||
limit: number
|
||||
};
|
||||
|
||||
export type UploadReuploadCdnFile = {
|
||||
file_token: Uint8Array | number[],
|
||||
request_token: Uint8Array | number[]
|
||||
file_token: Uint8Array,
|
||||
request_token: Uint8Array
|
||||
};
|
||||
|
||||
export type UploadGetCdnFileHashes = {
|
||||
file_token: Uint8Array | number[],
|
||||
file_token: Uint8Array,
|
||||
offset: number
|
||||
};
|
||||
|
||||
@ -10350,19 +10363,19 @@ export type PhoneRequestCall = {
|
||||
video?: true,
|
||||
user_id: InputUser,
|
||||
random_id: number,
|
||||
g_a_hash: Uint8Array | number[],
|
||||
g_a_hash: Uint8Array,
|
||||
protocol: PhoneCallProtocol
|
||||
};
|
||||
|
||||
export type PhoneAcceptCall = {
|
||||
peer: InputPhoneCall,
|
||||
g_b: Uint8Array | number[],
|
||||
g_b: Uint8Array,
|
||||
protocol: PhoneCallProtocol
|
||||
};
|
||||
|
||||
export type PhoneConfirmCall = {
|
||||
peer: InputPhoneCall,
|
||||
g_a: Uint8Array | number[],
|
||||
g_a: Uint8Array,
|
||||
key_fingerprint: string,
|
||||
protocol: PhoneCallProtocol
|
||||
};
|
||||
|
@ -6,7 +6,6 @@ import appPeersManager from "./appPeersManager";
|
||||
import appUsersManager from "./appUsersManager";
|
||||
import appChatsManager from "./appChatsManager";
|
||||
import { logger, LogLevels } from '../logger';
|
||||
import { Updates, UpdatesState } from '../../layer';
|
||||
|
||||
export class ApiUpdatesManager {
|
||||
public updatesState: {
|
||||
@ -63,7 +62,7 @@ export class ApiUpdatesManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
public popPendingPtsUpdate(channelID: any) {
|
||||
public popPendingPtsUpdate(channelID: number) {
|
||||
var curState = channelID ? this.getChannelState(channelID) : this.updatesState;
|
||||
if(!curState.pendingPtsUpdates.length) {
|
||||
return false;
|
||||
@ -216,7 +215,7 @@ export class ApiUpdatesManager {
|
||||
// Should be first because of updateMessageID
|
||||
// this.log('applying', differenceResult.other_updates.length, 'other updates')
|
||||
|
||||
differenceResult.other_updates.forEach((update: any) => {
|
||||
differenceResult.other_updates.forEach((update) => {
|
||||
switch(update._) {
|
||||
case 'updateChannelTooLong':
|
||||
case 'updateNewChannelMessage':
|
||||
@ -229,7 +228,7 @@ export class ApiUpdatesManager {
|
||||
});
|
||||
|
||||
// this.log('applying', differenceResult.new_messages.length, 'new messages')
|
||||
differenceResult.new_messages.forEach((apiMessage: any) => {
|
||||
differenceResult.new_messages.forEach((apiMessage) => {
|
||||
this.saveUpdate({
|
||||
_: 'updateNewMessage',
|
||||
message: apiMessage,
|
||||
@ -303,13 +302,13 @@ export class ApiUpdatesManager {
|
||||
appChatsManager.saveApiChats(differenceResult.chats);
|
||||
|
||||
// Should be first because of updateMessageID
|
||||
this.log('applying', differenceResult.other_updates.length, 'channel other updates')
|
||||
differenceResult.other_updates.forEach((update: any) => {
|
||||
this.log('applying', differenceResult.other_updates.length, 'channel other updates');
|
||||
differenceResult.other_updates.forEach((update) => {
|
||||
this.saveUpdate(update);
|
||||
});
|
||||
|
||||
this.log('applying', differenceResult.new_messages.length, 'channel new messages')
|
||||
differenceResult.new_messages.forEach((apiMessage: any) => {
|
||||
this.log('applying', differenceResult.new_messages.length, 'channel new messages');
|
||||
differenceResult.new_messages.forEach((apiMessage) => {
|
||||
this.saveUpdate({
|
||||
_: 'updateNewChannelMessage',
|
||||
message: apiMessage,
|
||||
@ -519,7 +518,7 @@ export class ApiUpdatesManager {
|
||||
apiManager.setUpdatesProcessor(this.processUpdateMessage.bind(this));
|
||||
|
||||
if(!state || !state.pts || !state.date || !state.seq) {
|
||||
apiManager.invokeApi('updates.getState', {}, {noErrorBox: true}).then((stateResult: any) => {
|
||||
apiManager.invokeApi('updates.getState', {}, {noErrorBox: true}).then((stateResult) => {
|
||||
this.updatesState.seq = stateResult.seq;
|
||||
this.updatesState.pts = stateResult.pts;
|
||||
this.updatesState.date = stateResult.date;
|
||||
|
@ -1,11 +1,12 @@
|
||||
import {RichTextProcessor} from '../richtextprocessor';
|
||||
import { isObject, getFileURL, FileURLType } from '../utils';
|
||||
import { isObject, getFileURL, FileURLType, safeReplaceArrayInObject } from '../utils';
|
||||
import opusDecodeController from '../opusDecodeController';
|
||||
import { getFileNameByLocation } from '../bin_utils';
|
||||
import appDownloadManager, { DownloadBlob } from './appDownloadManager';
|
||||
import appPhotosManager from './appPhotosManager';
|
||||
import { isServiceWorkerSupported } from '../config';
|
||||
import { InputFileLocation, Document, PhotoSize } from '../../layer';
|
||||
import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';
|
||||
|
||||
export type MyDocument = Document.document;
|
||||
|
||||
@ -14,38 +15,35 @@ export type MyDocument = Document.document;
|
||||
class AppDocsManager {
|
||||
private docs: {[docID: string]: MyDocument} = {};
|
||||
|
||||
public saveDoc(doc: Document, context?: any): MyDocument {
|
||||
public saveDoc(doc: Document, context?: ReferenceContext): MyDocument {
|
||||
if(doc._ == 'documentEmpty') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const oldDoc = this.docs[doc.id];
|
||||
|
||||
safeReplaceArrayInObject('file_reference', oldDoc, doc);
|
||||
referenceDatabase.saveContext(doc.file_reference, context);
|
||||
|
||||
//console.log('saveDoc', apiDoc, this.docs[apiDoc.id]);
|
||||
if(this.docs[doc.id]) {
|
||||
const d = this.docs[doc.id];
|
||||
|
||||
if(oldDoc) {
|
||||
//if(doc._ != 'documentEmpty' && doc._ == d._) {
|
||||
if(doc.thumbs) {
|
||||
if(!d.thumbs) d.thumbs = doc.thumbs;
|
||||
if(!oldDoc.thumbs) oldDoc.thumbs = doc.thumbs;
|
||||
/* else if(apiDoc.thumbs[0].bytes && !d.thumbs[0].bytes) {
|
||||
d.thumbs.unshift(apiDoc.thumbs[0]);
|
||||
} else if(d.thumbs[0].url) { // fix for converted thumb in safari
|
||||
apiDoc.thumbs[0] = d.thumbs[0];
|
||||
} */
|
||||
}
|
||||
|
||||
d.file_reference = doc.file_reference;
|
||||
|
||||
//}
|
||||
|
||||
|
||||
return d;
|
||||
return oldDoc;
|
||||
|
||||
//return Object.assign(d, apiDoc, context);
|
||||
//return context ? Object.assign(d, context) : d;
|
||||
}
|
||||
|
||||
if(context) {
|
||||
Object.assign(doc, context);
|
||||
}
|
||||
|
||||
this.docs[doc.id] = doc;
|
||||
|
||||
|
@ -4,6 +4,8 @@ import { deferredPromise, CancellablePromise } from "../../helpers/cancellablePr
|
||||
import type { DownloadOptions } from "../mtproto/apiFileManager";
|
||||
import { getFileNameByLocation } from "../bin_utils";
|
||||
import { InputFile } from "../../layer";
|
||||
import referenceDatabase, {ReferenceBytes} from "../mtproto/referenceDatabase";
|
||||
import appMessagesManager from "./appMessagesManager";
|
||||
|
||||
export type ResponseMethodBlob = 'blob';
|
||||
export type ResponseMethodJson = 'json';
|
||||
@ -74,7 +76,44 @@ export class AppDownloadManager {
|
||||
if(this.downloads.hasOwnProperty(fileName)) return this.downloads[fileName];
|
||||
|
||||
const deferred = this.getNewDeferred(fileName);
|
||||
apiManager.downloadFile(options).then(deferred.resolve, deferred.reject);
|
||||
|
||||
const onError = (err: any) => {
|
||||
switch(err.type) {
|
||||
case 'FILE_REFERENCE_EXPIRED': {
|
||||
// @ts-ignore
|
||||
const bytes: ReferenceBytes = options?.location?.file_reference;
|
||||
if(bytes) {
|
||||
const context = referenceDatabase.getContext(bytes);
|
||||
switch(context?.type) {
|
||||
case 'message': {
|
||||
return appMessagesManager.wrapSingleMessage(context.messageID, true).then(() => {
|
||||
//console.log('FILE_REFERENCE_EXPIRED: got message', context, options, appMessagesManager.getMessage(context.messageID).media);
|
||||
return tryDownload();
|
||||
});
|
||||
}
|
||||
|
||||
default: {
|
||||
console.warn('FILE_REFERENCE_EXPIRED: not implemented context', context);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn('FILE_REFERENCE_EXPIRED: no context for bytes:', bytes);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
deferred.reject(err);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
const tryDownload = (): Promise<unknown> => {
|
||||
return apiManager.downloadFile(options).then(deferred.resolve, onError);
|
||||
};
|
||||
|
||||
tryDownload();
|
||||
|
||||
//console.log('Will download file:', fileName, url);
|
||||
return deferred;
|
||||
|
@ -563,7 +563,8 @@ export class AppImManager {
|
||||
cancelEvent(e);
|
||||
|
||||
if(mediaSizes.isMobile) {
|
||||
this.setPeer(0);
|
||||
//this.setPeer(0);
|
||||
this.selectTab(0);
|
||||
} else {
|
||||
const isNowOpen = document.body.classList.toggle(LEFT_COLUMN_ACTIVE_CLASSNAME);
|
||||
|
||||
@ -1056,6 +1057,10 @@ export class AppImManager {
|
||||
}
|
||||
|
||||
const samePeer = this.peerID == peerID;
|
||||
|
||||
if(samePeer) { // fix for returning back
|
||||
this.selectTab(1);
|
||||
}
|
||||
|
||||
if(this.setPeerPromise && samePeer) return this.setPeerPromise;
|
||||
|
||||
|
@ -24,10 +24,12 @@ import { Modify } from "../../types";
|
||||
import { logger, LogLevels } from "../logger";
|
||||
import type {ApiFileManager} from '../mtproto/apiFileManager';
|
||||
import appDownloadManager from "./appDownloadManager";
|
||||
import { DialogFilter, InputDialogPeer, InputMessage, MethodDeclMap, MessagesFilter, PhotoSize, DocumentAttribute, Dialog as MTDialog, MessagesDialogs, MessagesPeerDialogs } from "../../layer";
|
||||
import { DialogFilter, Message, InputMessage, MethodDeclMap, MessagesFilter, PhotoSize, DocumentAttribute, Dialog as MTDialog, MessagesDialogs, MessagesPeerDialogs, MessagesMessages, MessageMedia } from "../../layer";
|
||||
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
|
||||
|
||||
//console.trace('include');
|
||||
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
|
||||
// TODO: если удалить диалог находясь в папке, то он не удалится из папки и будет виден в настройках
|
||||
|
||||
const APITIMEOUT = 0;
|
||||
|
||||
@ -135,7 +137,7 @@ export class DialogsStorage {
|
||||
const mid = appMessagesIDsManager.getFullMessageID(dialog.top_message, channelID);
|
||||
const message = appMessagesManager.getMessage(mid);
|
||||
|
||||
let topDate = message.date;
|
||||
let topDate = (message as Message.message).date || Date.now() / 1000;
|
||||
if(channelID) {
|
||||
const channel = appChatsManager.getChat(channelID);
|
||||
if(!topDate || channel.date && channel.date > topDate) {
|
||||
@ -458,8 +460,10 @@ export class FiltersStorage {
|
||||
}
|
||||
}
|
||||
|
||||
type MyMessage = Message.message | Message.messageService;
|
||||
|
||||
export class AppMessagesManager {
|
||||
public messagesStorage: any = {};
|
||||
public messagesStorage: {[mid: string]: any} = {};
|
||||
public groupedMessagesStorage: {[groupID: string]: any} = {}; // will be used for albums
|
||||
public historiesStorage: {
|
||||
[peerID: string]: HistoryStorage
|
||||
@ -477,8 +481,7 @@ export class AppMessagesManager {
|
||||
public lastSearchResults: any = [];
|
||||
|
||||
public needSingleMessages: number[] = [];
|
||||
public fetchSingleMessagesTimeout = 0;
|
||||
private fetchSingleMessagesPromise: Promise<any> = null;
|
||||
private fetchSingleMessagesPromise: Promise<void> = null;
|
||||
|
||||
public maxSeenID = 0;
|
||||
|
||||
@ -517,9 +520,9 @@ export class AppMessagesManager {
|
||||
|
||||
$rootScope.$on('webpage_updated', (e) => {
|
||||
let eventData = e.detail;
|
||||
eventData.msgs.forEach((msgID: number) => {
|
||||
let message = this.getMessage(msgID);
|
||||
message.webpage = appWebPagesManager.getWebPage(eventData.id); // warning
|
||||
eventData.msgs.forEach((msgID) => {
|
||||
let message = this.getMessage(msgID) as Message.message;
|
||||
(message.media as MessageMedia.messageMediaWebPage).webpage = appWebPagesManager.getWebPage(eventData.id); // warning
|
||||
$rootScope.$broadcast('message_edit', {
|
||||
peerID: this.getMessagePeer(message),
|
||||
id: message.id,
|
||||
@ -626,6 +629,7 @@ export class AppMessagesManager {
|
||||
peer: appPeersManager.getInputPeerByID(peerID),
|
||||
id: appMessagesIDsManager.getMessageLocalID(messageID),
|
||||
message: text,
|
||||
// @ts-ignore
|
||||
media: message.media,
|
||||
entities: this.getInputEntities(entities),
|
||||
no_webpage: noWebPage || undefined,
|
||||
@ -2024,9 +2028,10 @@ export class AppMessagesManager {
|
||||
return Promise.all(promises);
|
||||
}
|
||||
|
||||
public getMessage(messageID: number) {
|
||||
public getMessage(messageID: number)/* : Message */ {
|
||||
return this.messagesStorage[messageID] || {
|
||||
_: 'messageEmpty',
|
||||
id: messageID,
|
||||
deleted: true,
|
||||
pFlags: {out: false, unread: false}
|
||||
};
|
||||
@ -2245,9 +2250,9 @@ export class AppMessagesManager {
|
||||
apiMessage.viaBotID = apiMessage.via_bot_id;
|
||||
}
|
||||
|
||||
const mediaContext = {
|
||||
user_id: apiMessage.fromID,
|
||||
date: apiMessage.date
|
||||
const mediaContext: ReferenceContext = {
|
||||
type: 'message',
|
||||
messageID: mid
|
||||
};
|
||||
|
||||
if(apiMessage.media) {
|
||||
@ -2638,7 +2643,8 @@ export class AppMessagesManager {
|
||||
let topMessage = dialog.top_message;
|
||||
const topPendingMessage = this.pendingTopMsgs[peerID];
|
||||
if(topPendingMessage) {
|
||||
if(!topMessage || this.getMessage(topPendingMessage).date > this.getMessage(topMessage).date) {
|
||||
if(!topMessage
|
||||
|| (this.getMessage(topPendingMessage) as MyMessage).date > (this.getMessage(topMessage) as MyMessage).date) {
|
||||
dialog.top_message = topMessage = topPendingMessage;
|
||||
}
|
||||
}
|
||||
@ -3764,11 +3770,21 @@ export class AppMessagesManager {
|
||||
|
||||
for(let i = 0; i < update.messages.length; i++) {
|
||||
let messageID = appMessagesIDsManager.getFullMessageID(update.messages[i], channelID);
|
||||
let message = this.messagesStorage[messageID];
|
||||
let message: MyMessage = this.messagesStorage[messageID];
|
||||
if(message) {
|
||||
let peerID = this.getMessagePeer(message);
|
||||
let history = historiesUpdated[peerID] || (historiesUpdated[peerID] = {count: 0, unread: 0, msgs: {}});
|
||||
|
||||
if((message as Message.message).media) {
|
||||
// @ts-ignore
|
||||
let c = message.media.webpage || message.media;
|
||||
const smth = c.photo || c.document;
|
||||
|
||||
if(smth.file_reference) {
|
||||
referenceDatabase.deleteContext(smth.file_reference, {type: 'message', messageID});
|
||||
}
|
||||
}
|
||||
|
||||
if(!message.pFlags.out && message.pFlags.unread) {
|
||||
history.unread++;
|
||||
}
|
||||
@ -4228,29 +4244,34 @@ export class AppMessagesManager {
|
||||
}, {
|
||||
//timeout: APITIMEOUT,
|
||||
noErrorBox: true
|
||||
}).then((historyResult: any) => {
|
||||
}).then((historyResult) => {
|
||||
this.log('requestHistory result:', historyResult, maxID, limit, offset);
|
||||
|
||||
if(historyResult._ == 'messages.messagesNotModified') {
|
||||
return historyResult;
|
||||
}
|
||||
|
||||
appUsersManager.saveApiUsers(historyResult.users);
|
||||
appChatsManager.saveApiChats(historyResult.chats);
|
||||
this.saveMessages(historyResult.messages);
|
||||
|
||||
if(isChannel) {
|
||||
apiUpdatesManager.addChannelState(-peerID, historyResult.pts);
|
||||
apiUpdatesManager.addChannelState(-peerID, (historyResult as MessagesMessages.messagesChannelMessages).pts);
|
||||
}
|
||||
|
||||
let length = historyResult.messages.length;
|
||||
if(length && historyResult.messages[length - 1].deleted) {
|
||||
historyResult.messages.splice(length - 1, 1);
|
||||
length--;
|
||||
historyResult.count--;
|
||||
(historyResult as MessagesMessages.messagesMessagesSlice).count--;
|
||||
}
|
||||
|
||||
// will load more history if last message is album grouped (because it can be not last item)
|
||||
const historyStorage = this.historiesStorage[peerID];
|
||||
// historyResult.messages: desc sorted
|
||||
if(length && historyResult.messages[length - 1].grouped_id && (historyStorage.history.length + historyResult.messages.length) < historyResult.count) {
|
||||
return this.requestHistory(peerID, historyResult.messages[length - 1].mid, 10, 0).then((_historyResult: any) => {
|
||||
if(length && (historyResult.messages[length - 1] as Message.message).grouped_id
|
||||
&& (historyStorage.history.length + historyResult.messages.length) < (historyResult as MessagesMessages.messagesMessagesSlice).count) {
|
||||
return this.requestHistory(peerID, (historyResult.messages[length - 1] as Message.message).mid, 10, 0).then((_historyResult) => {
|
||||
return historyResult;
|
||||
});
|
||||
}
|
||||
@ -4314,59 +4335,62 @@ export class AppMessagesManager {
|
||||
return this.fetchSingleMessagesPromise;
|
||||
}
|
||||
|
||||
const mids = this.needSingleMessages.slice();
|
||||
this.needSingleMessages.length = 0;
|
||||
|
||||
const splitted = appMessagesIDsManager.splitMessageIDsByChannels(mids);
|
||||
let promises: Promise<void>[] = [];
|
||||
Object.keys(splitted.msgIDs).forEach((channelID: number | string) => {
|
||||
channelID = +channelID;
|
||||
|
||||
const msgIDs: InputMessage[] = splitted.msgIDs[channelID].map((msgID: number) => {
|
||||
return {
|
||||
_: 'inputMessageID',
|
||||
id: msgID
|
||||
};
|
||||
});
|
||||
|
||||
let promise: Promise<MethodDeclMap['channels.getMessages']['res'] | MethodDeclMap['messages.getMessages']['res']>;
|
||||
if(channelID > 0) {
|
||||
promise = apiManager.invokeApi('channels.getMessages', {
|
||||
channel: appChatsManager.getChannelInput(channelID),
|
||||
id: msgIDs
|
||||
return this.fetchSingleMessagesPromise = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const mids = this.needSingleMessages.slice();
|
||||
this.needSingleMessages.length = 0;
|
||||
|
||||
const splitted = appMessagesIDsManager.splitMessageIDsByChannels(mids);
|
||||
let promises: Promise<void>[] = [];
|
||||
Object.keys(splitted.msgIDs).forEach((channelID: number | string) => {
|
||||
channelID = +channelID;
|
||||
|
||||
const msgIDs: InputMessage[] = splitted.msgIDs[channelID].map((msgID: number) => {
|
||||
return {
|
||||
_: 'inputMessageID',
|
||||
id: msgID
|
||||
};
|
||||
});
|
||||
|
||||
let promise: Promise<MethodDeclMap['channels.getMessages']['res'] | MethodDeclMap['messages.getMessages']['res']>;
|
||||
if(channelID > 0) {
|
||||
promise = apiManager.invokeApi('channels.getMessages', {
|
||||
channel: appChatsManager.getChannelInput(channelID),
|
||||
id: msgIDs
|
||||
});
|
||||
} else {
|
||||
promise = apiManager.invokeApi('messages.getMessages', {
|
||||
id: msgIDs
|
||||
});
|
||||
}
|
||||
|
||||
promises.push(promise.then(getMessagesResult => {
|
||||
if(getMessagesResult._ != 'messages.messagesNotModified') {
|
||||
appUsersManager.saveApiUsers(getMessagesResult.users);
|
||||
appChatsManager.saveApiChats(getMessagesResult.chats);
|
||||
this.saveMessages(getMessagesResult.messages);
|
||||
}
|
||||
|
||||
$rootScope.$broadcast('messages_downloaded', splitted.mids[+channelID]);
|
||||
}));
|
||||
});
|
||||
} else {
|
||||
promise = apiManager.invokeApi('messages.getMessages', {
|
||||
id: msgIDs
|
||||
|
||||
Promise.all(promises).finally(() => {
|
||||
this.fetchSingleMessagesPromise = null;
|
||||
if(this.needSingleMessages.length) this.fetchSingleMessages();
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
||||
promises.push(promise.then(getMessagesResult => {
|
||||
if(getMessagesResult._ != 'messages.messagesNotModified') {
|
||||
appUsersManager.saveApiUsers(getMessagesResult.users);
|
||||
appChatsManager.saveApiChats(getMessagesResult.chats);
|
||||
this.saveMessages(getMessagesResult.messages);
|
||||
}
|
||||
|
||||
$rootScope.$broadcast('messages_downloaded', splitted.mids[+channelID]);
|
||||
}));
|
||||
});
|
||||
|
||||
this.fetchSingleMessagesPromise = Promise.all(promises).finally(() => {
|
||||
this.fetchSingleMessagesTimeout = 0;
|
||||
this.fetchSingleMessagesPromise = null;
|
||||
if(this.needSingleMessages.length) this.fetchSingleMessages();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
public wrapSingleMessage(msgID: number, overwrite = false) {
|
||||
public wrapSingleMessage(msgID: number, overwrite = false): Promise<void> {
|
||||
if(this.messagesStorage[msgID] && !overwrite) {
|
||||
$rootScope.$broadcast('messages_downloaded', [msgID]);
|
||||
return Promise.resolve();
|
||||
} else if(this.needSingleMessages.indexOf(msgID) == -1) {
|
||||
this.needSingleMessages.push(msgID);
|
||||
if(this.fetchSingleMessagesTimeout == 0) {
|
||||
this.fetchSingleMessagesTimeout = window.setTimeout(this.fetchSingleMessages.bind(this), 10);
|
||||
}
|
||||
return this.fetchSingleMessages();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,17 @@
|
||||
import { calcImageInBox, isObject } from "../utils";
|
||||
import { calcImageInBox, isObject, safeReplaceArrayInObject } from "../utils";
|
||||
import { bytesFromHex, getFileNameByLocation } from "../bin_utils";
|
||||
import appDownloadManager from "./appDownloadManager";
|
||||
import { isSafari } from "../../helpers/userAgent";
|
||||
import { FileLocation, InputFileLocation, Photo, PhotoSize } from "../../layer";
|
||||
import { MyDocument } from "./appDocsManager";
|
||||
import { CancellablePromise } from "../../helpers/cancellablePromise";
|
||||
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
|
||||
|
||||
export type MyPhoto = Photo.photo;
|
||||
|
||||
// TIMES = 2 DUE TO SIDEBAR AND CHAT
|
||||
//let TEST_FILE_REFERENCE = "5440692274120994569", TEST_FILE_REFERENCE_TIMES = 2;
|
||||
|
||||
export class AppPhotosManager {
|
||||
private photos: {
|
||||
[id: string]: MyPhoto
|
||||
@ -34,20 +38,28 @@ export class AppPhotosManager {
|
||||
this.windowH = document.body.scrollHeight;
|
||||
}
|
||||
|
||||
public savePhoto(photo: Photo, context?: any) {
|
||||
public savePhoto(photo: Photo, context?: ReferenceContext) {
|
||||
if(photo._ == 'photoEmpty') return undefined;
|
||||
|
||||
if(this.photos[photo.id]) return Object.assign(this.photos[photo.id], photo);
|
||||
/* if(photo.id == TEST_FILE_REFERENCE) {
|
||||
console.warn('Testing FILE_REFERENCE_EXPIRED');
|
||||
const bytes = [2, 67, 175, 43, 190, 0, 0, 20, 62, 95, 111, 33, 45, 99, 220, 116, 218, 11, 167, 127, 213, 18, 127, 32, 243, 202, 117, 80, 30];
|
||||
//photo.file_reference = new Uint8Array(bytes);
|
||||
photo.file_reference = bytes;
|
||||
if(!--TEST_FILE_REFERENCE_TIMES) {
|
||||
TEST_FILE_REFERENCE = '';
|
||||
}
|
||||
} */
|
||||
|
||||
/* if(context) {
|
||||
Object.assign(photo, context);
|
||||
} */ // warning
|
||||
|
||||
if(!photo.id) {
|
||||
console.warn('no apiPhoto.id', photo);
|
||||
} else this.photos[photo.id] = photo;
|
||||
const oldPhoto = this.photos[photo.id];
|
||||
safeReplaceArrayInObject('file_reference', oldPhoto, photo);
|
||||
referenceDatabase.saveContext(photo.file_reference, context);
|
||||
|
||||
return photo;
|
||||
if(oldPhoto) {
|
||||
return Object.assign(oldPhoto, photo);
|
||||
}
|
||||
|
||||
return this.photos[photo.id] = photo;
|
||||
}
|
||||
|
||||
public choosePhotoSize(photo: MyPhoto | MyDocument, width = 0, height = 0) {
|
||||
|
@ -8,8 +8,10 @@ import apiUpdatesManager from './apiUpdatesManager';
|
||||
import { copy } from '../utils';
|
||||
import { logger } from '../logger';
|
||||
import type { AppStickersManager } from './appStickersManager';
|
||||
import { App } from '../mtproto/mtproto_config';
|
||||
|
||||
const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day
|
||||
const STATE_VERSION = App.version;
|
||||
|
||||
type State = Partial<{
|
||||
dialogs: Dialog[],
|
||||
@ -24,7 +26,8 @@ type State = Partial<{
|
||||
recentEmoji: string[],
|
||||
topPeers: number[],
|
||||
recentSearch: number[],
|
||||
stickerSets: AppStickersManager['stickerSets']
|
||||
stickerSets: AppStickersManager['stickerSets'],
|
||||
version: typeof STATE_VERSION
|
||||
}>;
|
||||
|
||||
const REFRESH_KEYS = ['dialogs', 'allDialogsLoaded', 'messages', 'contactsList', 'stateCreatedTime',
|
||||
@ -45,19 +48,26 @@ export class AppStateManager {
|
||||
return this.loaded = new Promise((resolve) => {
|
||||
AppStorage.get<State>('state').then((state) => {
|
||||
const time = Date.now();
|
||||
if((state?.stateCreatedTime ?? 0) + REFRESH_EVERY < time) {
|
||||
this.log('will refresh state', state.stateCreatedTime, time);
|
||||
REFRESH_KEYS.forEach(key => {
|
||||
delete state[key];
|
||||
});
|
||||
//state = {};
|
||||
if(state) {
|
||||
if(state?.version != STATE_VERSION) {
|
||||
state = {};
|
||||
} else if((state?.stateCreatedTime ?? 0) + REFRESH_EVERY < time) {
|
||||
this.log('will refresh state', state.stateCreatedTime, time);
|
||||
REFRESH_KEYS.forEach(key => {
|
||||
delete state[key];
|
||||
});
|
||||
//state = {};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// will not throw error because state can be `FALSE`
|
||||
const {dialogs, allDialogsLoaded, peers, messages, contactsList, maxSeenMsgID, updates, filters} = state;
|
||||
|
||||
this.state = state || {};
|
||||
this.state.peers = peers || {};
|
||||
this.state.version = STATE_VERSION;
|
||||
|
||||
// ??= doesn't compiles
|
||||
if(!this.state.hasOwnProperty('stateCreatedTime')) {
|
||||
this.state.stateCreatedTime = Date.now();
|
||||
}
|
||||
@ -100,13 +110,6 @@ export class AppStateManager {
|
||||
} */
|
||||
|
||||
appMessagesManager.saveMessages(messages);
|
||||
|
||||
// FIX FILE_REFERENCE_EXPIRED KOSTIL'1999
|
||||
for(let message of messages) {
|
||||
if(message.media) {
|
||||
appMessagesManager.wrapSingleMessage(message.mid, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(allDialogsLoaded) {
|
||||
|
@ -2,6 +2,7 @@ import { $rootScope, safeReplaceObject } from "../utils";
|
||||
import appPhotosManager from "./appPhotosManager";
|
||||
import appDocsManager from "./appDocsManager";
|
||||
import { RichTextProcessor } from "../richtextprocessor";
|
||||
import { ReferenceContext } from "../mtproto/referenceDatabase";
|
||||
|
||||
class AppWebPagesManager {
|
||||
webpages: any = {};
|
||||
@ -19,7 +20,7 @@ class AppWebPagesManager {
|
||||
});
|
||||
}
|
||||
|
||||
public saveWebPage(apiWebPage: any, messageID?: number, mediaContext?: any) {
|
||||
public saveWebPage(apiWebPage: any, messageID?: number, mediaContext?: ReferenceContext) {
|
||||
if(apiWebPage.photo && apiWebPage.photo._ === 'photo') {
|
||||
//appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);
|
||||
apiWebPage.photo = appPhotosManager.savePhoto(apiWebPage.photo, mediaContext);
|
||||
|
@ -5,6 +5,8 @@
|
||||
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import {str2bigInt, divInt_, int2bigInt, bigInt2str, bigInt2bytes} from '../vendor/leemon';
|
||||
|
||||
// @ts-ignore
|
||||
import {BigInteger, SecureRandom} from 'jsbn';
|
||||
import type { InputFileLocation, FileLocation } from '../layer';
|
||||
@ -23,11 +25,6 @@ export function gzipUncompress(bytes: ArrayBuffer, toString?: boolean): string |
|
||||
}
|
||||
/// #endif
|
||||
|
||||
var _logTimer = Date.now();
|
||||
export function dT () {
|
||||
return '[' + ((Date.now() - _logTimer) / 1000).toFixed(3) + ']'
|
||||
}
|
||||
|
||||
export function isObject(object: any) {
|
||||
return typeof(object) === 'object' && object !== null;
|
||||
}
|
||||
@ -294,24 +291,6 @@ export function bufferConcats(...args: any[]) {
|
||||
return tmp/* .buffer */;
|
||||
}
|
||||
|
||||
export function longToInts(sLong: string) {
|
||||
var divRem = bigStringInt(sLong).divideAndRemainder(bigint(0x100000000));
|
||||
|
||||
return [divRem[0].intValue(), divRem[1].intValue()];
|
||||
}
|
||||
|
||||
export function bytesFromWords(wordArray: {words: number[] | Uint8Array | Uint32Array, sigBytes: number}) {
|
||||
var words = wordArray.words;
|
||||
var sigBytes = wordArray.sigBytes;
|
||||
var bytes = [];
|
||||
|
||||
for(var i = 0; i < sigBytes; i++) {
|
||||
bytes.push((words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
export function bytesFromWordss(input: Uint32Array) {
|
||||
var o = [];
|
||||
for(var i = 0; i < input.length * 4; i++) {
|
||||
@ -336,10 +315,6 @@ export function bytesToWordss(input: ArrayBuffer | Uint8Array) {
|
||||
return new Uint32Array(words);
|
||||
}
|
||||
|
||||
export function longToBytes(sLong: string) {
|
||||
return bytesFromWords({words: longToInts(sLong), sigBytes: 8}).reverse();
|
||||
}
|
||||
|
||||
export function longFromInts(high: number, low: number) {
|
||||
return bigint(high).shiftLeft(32).add(bigint(low)).toString(10);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import EventListenerBase from '../helpers/eventListenerBase';
|
||||
import mediaSizes from '../helpers/mediaSizes';
|
||||
/*!
|
||||
* Webogram v0.7.0 - messaging web application for MTProto
|
||||
|
@ -7,17 +7,32 @@ import pako from 'pako/dist/pako_inflate.min.js';
|
||||
|
||||
import {str2bigInt, bpe, equalsInt, greater,
|
||||
copy_, eGCD_, add_, rightShift_, sub_, copyInt_, isZero,
|
||||
// @ts-ignore
|
||||
divide_, one, bigInt2str, powMod} from 'leemon';//from 'leemon';
|
||||
divide_, one, bigInt2str, powMod, bigInt2bytes} from '../../vendor/leemon';//from 'leemon';
|
||||
|
||||
// @ts-ignore
|
||||
import {BigInteger} from 'jsbn';
|
||||
|
||||
import { addPadding, bytesToHex, bytesFromHex, nextRandomInt, bytesFromBigInt, dT, bytesFromWords, bytesToWordss, bytesFromWordss } from '../bin_utils';
|
||||
import { addPadding, bytesToHex, bytesFromHex, nextRandomInt, bytesFromBigInt, bytesToWordss, bytesFromWordss } from '../bin_utils';
|
||||
|
||||
export function bytesFromLeemonBigInt(bigInt: BigInteger) {
|
||||
var str = bigInt2str(bigInt, 16);
|
||||
return bytesFromHex(str);
|
||||
export function longToBytes(sLong: string) {
|
||||
/* let perf = performance.now();
|
||||
for(let i = 0; i < 1000000; ++i) {
|
||||
bytesFromWords({words: longToInts(sLong), sigBytes: 8}).reverse();
|
||||
}
|
||||
console.log('longToBytes JSBN', sLong, performance.now() - perf);
|
||||
|
||||
//const bytes = bytesFromWords({words: longToInts(sLong), sigBytes: 8}).reverse();
|
||||
|
||||
perf = performance.now();
|
||||
for(let i = 0; i < 1000000; ++i) {
|
||||
bigInt2bytes(str2bigInt(sLong, 10));
|
||||
}
|
||||
console.log('longToBytes LEEMON', sLong, performance.now() - perf); */
|
||||
|
||||
const bytes = bigInt2bytes(str2bigInt(sLong, 10), false);
|
||||
//console.log('longToBytes', bytes, b);
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
export function sha1HashSync(bytes: number[] | ArrayBuffer | Uint8Array) {
|
||||
@ -225,7 +240,7 @@ export function pqPrimeLeemon(what: any) {
|
||||
|
||||
// console.log(dT(), 'done', bigInt2str(what, 10), bigInt2str(P, 10), bigInt2str(Q, 10))
|
||||
|
||||
return [bytesFromLeemonBigInt(P), bytesFromLeemonBigInt(Q), it];
|
||||
return [bigInt2bytes(P), bigInt2bytes(Q), it];
|
||||
}
|
||||
|
||||
export function bytesModPow(x: any, y: any, m: any) {
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { bufferConcats, bytesToHex, bytesFromHex, bufferConcat, bytesXor } from "../bin_utils";
|
||||
import CryptoWorker from "../crypto/cryptoworker";
|
||||
import {str2bigInt, isZero,
|
||||
// @ts-ignore
|
||||
bigInt2str, powMod, int2bigInt, mult, mod, sub, bitSize, negative, add, greater} from 'leemon';
|
||||
bigInt2str, powMod, int2bigInt, mult, mod, sub, bitSize, negative, add, greater} from '../../vendor/leemon';
|
||||
|
||||
import {logger, LogLevels} from '../logger';
|
||||
import { AccountPassword, PasswordKdfAlgo } from "../../layer";
|
||||
@ -41,8 +40,8 @@ export async function computeSRP(password: string, state: AccountPassword) {
|
||||
let B = str2bigInt(bytesToHex(state.srp_B), 16);
|
||||
let g = int2bigInt(algo.g, 32, 256);
|
||||
|
||||
log('p', bigInt2str(p, 16));
|
||||
log('B', bigInt2str(B, 16));
|
||||
//log('p', bigInt2str(p, 16));
|
||||
//log('B', bigInt2str(B, 16));
|
||||
|
||||
/* if(B.compareTo(BigInteger.ZERO) < 0) {
|
||||
console.error('srp_B < 0')
|
||||
@ -67,7 +66,7 @@ export async function computeSRP(password: string, state: AccountPassword) {
|
||||
let pw_hash = await makePasswordHash(password, new Uint8Array(algo.salt1), new Uint8Array(algo.salt2));
|
||||
let x = str2bigInt(bytesToHex(new Uint8Array(pw_hash)), 16);
|
||||
|
||||
log('computed pw_hash:', pw_hash, x, bytesToHex(new Uint8Array(pw_hash)));
|
||||
//log('computed pw_hash:', pw_hash, x, bytesToHex(new Uint8Array(pw_hash)));
|
||||
|
||||
var padArray = function(arr: any[], len: number, fill = 0) {
|
||||
return Array(len).fill(fill).concat(arr).slice(-len);
|
||||
@ -77,25 +76,25 @@ export async function computeSRP(password: string, state: AccountPassword) {
|
||||
let gForHash = padArray(bytesFromHex(bigInt2str(g, 16)), 256); // like uint8array
|
||||
let b_for_hash = padArray(bytesFromHex(bigInt2str(B, 16)), 256);
|
||||
|
||||
log(bytesToHex(pForHash));
|
||||
/* log(bytesToHex(pForHash));
|
||||
log(bytesToHex(gForHash));
|
||||
log(bytesToHex(b_for_hash));
|
||||
log(bytesToHex(b_for_hash)); */
|
||||
|
||||
let g_x = powMod(g, x, p);
|
||||
|
||||
log('g_x', bigInt2str(g_x, 16));
|
||||
//log('g_x', bigInt2str(g_x, 16));
|
||||
|
||||
let k: any = await CryptoWorker.sha256Hash(bufferConcat(pForHash, gForHash));
|
||||
k = str2bigInt(bytesToHex(new Uint8Array(k)), 16);
|
||||
|
||||
log('k', bigInt2str(k, 16));
|
||||
//log('k', bigInt2str(k, 16));
|
||||
|
||||
// kg_x = (k * g_x) % p
|
||||
let kg_x = mod(mult(k, g_x), p);
|
||||
|
||||
// good
|
||||
|
||||
log('kg_x', bigInt2str(kg_x, 16));
|
||||
//log('kg_x', bigInt2str(kg_x, 16));
|
||||
|
||||
let is_good_mod_exp_first = (modexp: any, prime: any) => {
|
||||
let diff = sub(prime, modexp);
|
||||
@ -128,10 +127,10 @@ export async function computeSRP(password: string, state: AccountPassword) {
|
||||
|
||||
//console.log('ITERATION');
|
||||
|
||||
log('g a p', bigInt2str(g, 16), bigInt2str(a, 16), bigInt2str(p, 16));
|
||||
//log('g a p', bigInt2str(g, 16), bigInt2str(a, 16), bigInt2str(p, 16));
|
||||
|
||||
const A = powMod(g, a, p);
|
||||
log('A MODPOW', bigInt2str(A, 16));
|
||||
//log('A MODPOW', bigInt2str(A, 16));
|
||||
if(is_good_mod_exp_first(A, p)) {
|
||||
const a_for_hash = bytesFromHex(bigInt2str(A, 16));
|
||||
|
||||
@ -147,9 +146,9 @@ export async function computeSRP(password: string, state: AccountPassword) {
|
||||
|
||||
let {a, a_for_hash, u} = await generate_and_check_random();
|
||||
|
||||
log('a', bigInt2str(a, 16));
|
||||
/* log('a', bigInt2str(a, 16));
|
||||
log('a_for_hash', bytesToHex(a_for_hash));
|
||||
log('u', bigInt2str(u, 16));
|
||||
log('u', bigInt2str(u, 16)); */
|
||||
|
||||
// g_b = (B - kg_x) % p
|
||||
/* log('B - kg_x', bigInt2str(sub(B, kg_x), 16));
|
||||
@ -158,26 +157,26 @@ export async function computeSRP(password: string, state: AccountPassword) {
|
||||
|
||||
let g_b;
|
||||
if(!greater(B, kg_x)) {
|
||||
log('negative');
|
||||
//log('negative');
|
||||
g_b = add(B, p);
|
||||
} else g_b = B;
|
||||
g_b = mod(sub(g_b, kg_x), p);
|
||||
/* let g_b = sub(B, kg_x);
|
||||
if(negative(g_b)) g_b = add(g_b, p); */
|
||||
|
||||
log('g_b', bigInt2str(g_b, 16));
|
||||
//log('g_b', bigInt2str(g_b, 16));
|
||||
|
||||
/* if(!is_good_mod_exp_first(g_b, p))
|
||||
throw new Error('bad g_b'); */
|
||||
|
||||
let ux = mult(u, x);
|
||||
log('u and x multiply', bigInt2str(u, 16), bigInt2str(x, 16), bigInt2str(ux, 16));
|
||||
//log('u and x multiply', bigInt2str(u, 16), bigInt2str(x, 16), bigInt2str(ux, 16));
|
||||
let a_ux = add(a, ux);
|
||||
let S = powMod(g_b, a_ux, p);
|
||||
|
||||
let K = await CryptoWorker.sha256Hash(padArray(bytesFromHex(bigInt2str(S, 16)), 256));
|
||||
|
||||
log('K', bytesToHex(K), new Uint32Array(new Uint8Array(K).buffer));
|
||||
//log('K', bytesToHex(K), new Uint32Array(new Uint8Array(K).buffer));
|
||||
|
||||
let h1 = await CryptoWorker.sha256Hash(pForHash);
|
||||
let h2 = await CryptoWorker.sha256Hash(gForHash);
|
||||
@ -201,7 +200,7 @@ export async function computeSRP(password: string, state: AccountPassword) {
|
||||
};
|
||||
|
||||
|
||||
log('out', bytesToHex(out.A), bytesToHex(out.M1));
|
||||
//log('out', bytesToHex(out.A), bytesToHex(out.M1));
|
||||
return out;
|
||||
|
||||
/* console.log(gForHash, pForHash, bForHash); */
|
||||
|
@ -3,7 +3,7 @@ import animationIntersector from "../components/animationIntersector";
|
||||
import apiManager from "./mtproto/mtprotoworker";
|
||||
import EventListenerBase from "../helpers/eventListenerBase";
|
||||
import mediaSizes from "../helpers/mediaSizes";
|
||||
import { isApple, isSafari } from "../helpers/userAgent";
|
||||
import { isAndroid, isApple, isAppleMobile, isSafari } from "../helpers/userAgent";
|
||||
import RLottieWorker from 'worker-loader!./rlottie/rlottie.worker';
|
||||
|
||||
let convert = (value: number) => {
|
||||
@ -93,7 +93,7 @@ export class RLottiePlayer extends EventListenerBase<{
|
||||
// Skip ratio
|
||||
let skipRatio: number;
|
||||
if(options.skipRatio !== undefined) skipRatio = options.skipRatio;
|
||||
else if(mediaSizes.isMobile && this.width < 100 && this.height < 100) {
|
||||
else if((isAndroid || isAppleMobile) && this.width < 100 && this.height < 100) {
|
||||
skipRatio = 0.5;
|
||||
}
|
||||
|
||||
@ -106,15 +106,20 @@ export class RLottiePlayer extends EventListenerBase<{
|
||||
if(options.needUpscale) {
|
||||
this.width = Math.round(this.width * pixelRatio);
|
||||
this.height = Math.round(this.height * pixelRatio);
|
||||
} else if(pixelRatio > 1 && this.width > 100 && this.height > 100) {
|
||||
if(isApple || !mediaSizes.isMobile) {
|
||||
/* this.width = Math.round(this.width * (pixelRatio - 1));
|
||||
this.height = Math.round(this.height * (pixelRatio - 1)); */
|
||||
this.width = Math.round(this.width * pixelRatio);
|
||||
this.height = Math.round(this.height * pixelRatio);
|
||||
} else if(pixelRatio > 2.5) {
|
||||
this.width = Math.round(this.width * (pixelRatio - 1.5));
|
||||
this.height = Math.round(this.height * (pixelRatio - 1.5));
|
||||
} else if(pixelRatio > 1) {
|
||||
if(this.width > 100 && this.height > 100) {
|
||||
if(isApple || !mediaSizes.isMobile) {
|
||||
/* this.width = Math.round(this.width * (pixelRatio - 1));
|
||||
this.height = Math.round(this.height * (pixelRatio - 1)); */
|
||||
this.width = Math.round(this.width * pixelRatio);
|
||||
this.height = Math.round(this.height * pixelRatio);
|
||||
} else if(pixelRatio > 2.5) {
|
||||
this.width = Math.round(this.width * (pixelRatio - 1.5));
|
||||
this.height = Math.round(this.height * (pixelRatio - 1.5));
|
||||
}
|
||||
} else {
|
||||
this.width = Math.round(this.width * Math.max(1.5, pixelRatio - 1.5));
|
||||
this.height = Math.round(this.height * Math.max(1.5, pixelRatio - 1.5));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -159,12 +164,14 @@ export class RLottiePlayer extends EventListenerBase<{
|
||||
}
|
||||
|
||||
public loadFromData(jsonString: string) {
|
||||
this.sendQuery('loadFromData', jsonString, this.width, this.height);
|
||||
this.sendQuery('loadFromData', jsonString, this.width, this.height/* , this.canvas.transferControlToOffscreen() */);
|
||||
}
|
||||
|
||||
public play() {
|
||||
if(!this.paused) return;
|
||||
|
||||
//return;
|
||||
|
||||
//console.log('RLOTTIE PLAY' + this.reqId);
|
||||
|
||||
this.paused = false;
|
||||
@ -373,7 +380,9 @@ export class RLottiePlayer extends EventListenerBase<{
|
||||
|
||||
console.timeEnd('cache' + this.reqId); */
|
||||
//console.log('cached');
|
||||
//return;
|
||||
/* this.el.innerHTML = '';
|
||||
this.el.append(this.canvas);
|
||||
return; */
|
||||
|
||||
this.requestFrame(0);
|
||||
this.setListenerResult('ready');
|
||||
@ -444,29 +453,29 @@ class QueryableWorker extends EventListenerBase<any> {
|
||||
}
|
||||
|
||||
public sendQuery(queryMethod: string, ...args: any[]) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
if(isSafari) {
|
||||
this.worker.postMessage({
|
||||
'queryMethod': queryMethod,
|
||||
'queryMethodArguments': args
|
||||
});
|
||||
} else {
|
||||
var transfer = [];
|
||||
for(var i = 0; i < args.length; i++) {
|
||||
if(args[i] instanceof ArrayBuffer) {
|
||||
transfer.push(args[i]);
|
||||
//const transfer: (ArrayBuffer | OffscreenCanvas)[] = [];
|
||||
const transfer: ArrayBuffer[] = [];
|
||||
args.forEach(arg => {
|
||||
if(arg instanceof ArrayBuffer) {
|
||||
transfer.push(arg);
|
||||
}
|
||||
|
||||
if(args[i].buffer && args[i].buffer instanceof ArrayBuffer) {
|
||||
transfer.push(args[i].buffer);
|
||||
if(arg.buffer && arg.buffer instanceof ArrayBuffer) {
|
||||
transfer.push(arg.buffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//console.log('transfer', transfer);
|
||||
this.worker.postMessage({
|
||||
'queryMethod': queryMethod,
|
||||
'queryMethodArguments': args
|
||||
}, transfer);
|
||||
}, transfer as PostMessageOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ export class MediaProgressLine extends ProgressLine {
|
||||
clearTimeout(this.stopAndScrubTimeout);
|
||||
}
|
||||
|
||||
this.stopAndScrubTimeout = setTimeout(() => {
|
||||
this.stopAndScrubTimeout = window.setTimeout(() => {
|
||||
!this.media.paused && this.media.pause();
|
||||
this.stopAndScrubTimeout = 0;
|
||||
}, 150);
|
||||
@ -412,7 +412,7 @@ export default class VideoPlayer {
|
||||
let showControlsTimeout = 0;
|
||||
|
||||
const t = () => {
|
||||
showControlsTimeout = setTimeout(() => {
|
||||
showControlsTimeout = window.setTimeout(() => {
|
||||
showControlsTimeout = 0;
|
||||
player.classList.remove('show-controls');
|
||||
}, 3e3);
|
||||
@ -489,7 +489,7 @@ export default class VideoPlayer {
|
||||
|
||||
video.addEventListener('play', () => {
|
||||
iconVolume.style.display = 'none';
|
||||
updateInterval = setInterval(() => {
|
||||
updateInterval = window.setInterval(() => {
|
||||
//elapsed += 0.02; // Increase with timer interval
|
||||
if(video.currentTime != prevTime) {
|
||||
elapsed = video.currentTime; // Update if getCurrentTime was changed
|
||||
@ -555,7 +555,7 @@ export default class VideoPlayer {
|
||||
let prevTime = 0;
|
||||
|
||||
if(skin === 'circle') {
|
||||
updateInterval = setInterval(() => {
|
||||
updateInterval = window.setInterval(() => {
|
||||
if(video.currentTime != prevTime) {
|
||||
elapsed = video.currentTime; // Update if getCurrentTime was changed
|
||||
prevTime = video.currentTime;
|
||||
|
@ -232,6 +232,7 @@ export class ApiFileManager {
|
||||
let resolved = false;
|
||||
let cacheFileWriter: ReturnType<typeof FileManager['getFakeFileWriter']>;
|
||||
let errorHandler = (error: any) => {
|
||||
delete this.cachedDownloadPromises[fileName];
|
||||
deferred.reject(error);
|
||||
errorHandler = () => {};
|
||||
|
||||
|
@ -10,6 +10,7 @@ import { BigInteger } from "jsbn";
|
||||
import CryptoWorker from "../crypto/cryptoworker";
|
||||
|
||||
import { logger, LogLevels } from "../logger";
|
||||
//import { bigInt2str, greater, int2bigInt, one, powMod, str2bigInt, sub } from "../../vendor/leemon";
|
||||
|
||||
/* let fNewNonce: any = bytesFromHex('8761970c24cb2329b5b2459752c502f3057cb7e8dbab200e526e8767fdc73b3c').reverse();
|
||||
let fNonce: any = bytesFromHex('b597720d11faa5914ef485c529cde414').reverse();
|
||||
@ -42,8 +43,8 @@ type AuthOptions = {
|
||||
|
||||
b?: number[],
|
||||
g?: number,
|
||||
gA?: number,
|
||||
dhPrime?: number,
|
||||
gA?: Uint8Array,
|
||||
dhPrime?: Uint8Array,
|
||||
|
||||
tmpAesKey?: Uint8Array,
|
||||
tmpAesIv?: Uint8Array,
|
||||
@ -64,7 +65,7 @@ export class Authorizer {
|
||||
private log: ReturnType<typeof logger>;
|
||||
|
||||
constructor() {
|
||||
this.log = logger(`AUTHORIZER`/* , LogLevels.error | LogLevels.log */);
|
||||
this.log = logger(`AUTHORIZER`, LogLevels.error | LogLevels.log);
|
||||
}
|
||||
|
||||
public mtpSendPlainRequest(dcID: number, requestArray: Uint8Array) {
|
||||
@ -365,8 +366,8 @@ export class Authorizer {
|
||||
timeManager.applyServerTime(auth.serverTime, auth.localTime);
|
||||
}
|
||||
|
||||
public mtpVerifyDhParams(g: number, dhPrime: any, gA: any) {
|
||||
this.log('Verifying DH params');
|
||||
public mtpVerifyDhParams(g: number, dhPrime: Uint8Array, gA: Uint8Array) {
|
||||
this.log('Verifying DH params', g, dhPrime, gA);
|
||||
var dhPrimeHex = bytesToHex(dhPrime);
|
||||
if(g != 3 || dhPrimeHex !== 'c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b') {
|
||||
// The verified value is from https://core.telegram.org/mtproto/security_guidelines
|
||||
@ -375,13 +376,20 @@ export class Authorizer {
|
||||
this.log('dhPrime cmp OK');
|
||||
|
||||
var gABigInt = new BigInteger(bytesToHex(gA), 16);
|
||||
//const _gABigInt = str2bigInt(bytesToHex(gA), 16);
|
||||
var dhPrimeBigInt = new BigInteger(dhPrimeHex, 16);
|
||||
//const _dhPrimeBigInt = str2bigInt(dhPrimeHex, 16);
|
||||
|
||||
//this.log('gABigInt.compareTo(BigInteger.ONE) <= 0', gABigInt.compareTo(BigInteger.ONE), BigInteger.ONE.compareTo(BigInteger.ONE), greater(_gABigInt, one));
|
||||
if(gABigInt.compareTo(BigInteger.ONE) <= 0) {
|
||||
//if(!greater(_gABigInt, one)) {
|
||||
throw new Error('[MT] DH params are not verified: gA <= 1');
|
||||
}
|
||||
|
||||
|
||||
/* this.log('gABigInt.compareTo(dhPrimeBigInt.subtract(BigInteger.ONE)) >= 0', gABigInt.compareTo(dhPrimeBigInt.subtract(BigInteger.ONE)),
|
||||
greater(gABigInt, sub(_dhPrimeBigInt, one))); */
|
||||
if(gABigInt.compareTo(dhPrimeBigInt.subtract(BigInteger.ONE)) >= 0) {
|
||||
//if(greater(gABigInt, sub(_dhPrimeBigInt, one))) {
|
||||
throw new Error('[MT] DH params are not verified: gA >= dhPrime - 1');
|
||||
}
|
||||
this.log('1 < gA < dhPrime-1 OK');
|
||||
@ -389,8 +397,13 @@ export class Authorizer {
|
||||
|
||||
var two = new BigInteger(/* null */'');
|
||||
two.fromInt(2);
|
||||
//const _two = int2bigInt(2, 10, 0);
|
||||
//this.log('_two:', bigInt2str(_two, 16), two.toString(16));
|
||||
var twoPow = two.pow(2048 - 64);
|
||||
//const _twoPow = powMod(_two, int2bigInt(2048 - 64, 10, 0), null);
|
||||
//this.log('twoPow:', twoPow.toString(16), bigInt2str(_twoPow, 16));
|
||||
|
||||
// this.log('gABigInt.compareTo(twoPow) < 0');
|
||||
if(gABigInt.compareTo(twoPow) < 0) {
|
||||
throw new Error('[MT] DH params are not verified: gA < 2^{2048-64}');
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {isObject} from '../bin_utils';
|
||||
import {convertToUint8Array,
|
||||
bufferConcat, nextRandomInt, bytesToHex, longToBytes,
|
||||
bufferConcat, nextRandomInt, bytesToHex,
|
||||
bytesCmp, bigStringInt} from '../bin_utils';
|
||||
import {TLDeserialization, TLSerialization} from './tl_utils';
|
||||
import CryptoWorker from '../crypto/cryptoworker';
|
||||
@ -15,6 +15,7 @@ import HTTP from './transports/http';
|
||||
import { logger, LogLevels } from '../logger';
|
||||
import { Modes, App } from './mtproto_config';
|
||||
import { InvokeApiOptions } from '../../types';
|
||||
import { longToBytes } from '../crypto/crypto_utils';
|
||||
|
||||
//console.error('networker included!', new Error().stack);
|
||||
|
||||
@ -948,7 +949,7 @@ class MTPNetworker {
|
||||
clearTimeout(this.nextReqTimeout);
|
||||
this.nextReqTimeout = 0;
|
||||
if(delay > 0) {
|
||||
this.nextReqTimeout = setTimeout(this.performScheduledRequest.bind(this), delay || 0);
|
||||
this.nextReqTimeout = self.setTimeout(this.performScheduledRequest.bind(this), delay || 0);
|
||||
} else {
|
||||
setTimeout(this.performScheduledRequest.bind(this), 0);
|
||||
}
|
||||
|
@ -1,9 +1,71 @@
|
||||
class ReferenceDatabase {
|
||||
import { Photo } from "../../layer";
|
||||
import { deepEqual } from "../utils";
|
||||
|
||||
export type ReferenceContext = ReferenceContext.referenceContextProfilePhoto | ReferenceContext.referenceContextMessage;
|
||||
export namespace ReferenceContext {
|
||||
export type referenceContextProfilePhoto = {
|
||||
type: 'profilePhoto',
|
||||
peerID: number
|
||||
};
|
||||
|
||||
export type referenceContextMessage = {
|
||||
type: 'message',
|
||||
messageID: number
|
||||
};
|
||||
}
|
||||
|
||||
export type ReferenceBytes = Photo.photo['file_reference'];
|
||||
//type ReferenceBytes = Uint8Array;
|
||||
|
||||
class ReferenceDatabase {
|
||||
private contexts: Map<ReferenceBytes, Set<ReferenceContext>> = new Map();
|
||||
//private references: Map<ReferenceBytes, number[]> = new Map();
|
||||
|
||||
public saveContext(reference: ReferenceBytes, context: ReferenceContext) {
|
||||
const contexts = this.contexts.get(reference) ?? new Set();
|
||||
|
||||
for(const _context of contexts) {
|
||||
if(deepEqual(_context, context)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
contexts.add(context);
|
||||
this.contexts.set(reference, contexts);
|
||||
}
|
||||
|
||||
public getContext(reference: ReferenceBytes): ReferenceContext {
|
||||
const contexts = this.contexts.get(reference);
|
||||
return contexts ? contexts.values().next().value : undefined;
|
||||
}
|
||||
|
||||
public deleteContext(reference: ReferenceBytes, context: ReferenceContext) {
|
||||
const contexts = this.contexts.get(reference);
|
||||
if(contexts) {
|
||||
for(const _context of contexts) {
|
||||
if(deepEqual(_context, context)) {
|
||||
contexts.delete(_context);
|
||||
if(!contexts.size) {
|
||||
this.contexts.delete(reference);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* public replaceReference(oldReference: ReferenceBytes, newReference: ReferenceBytes) {
|
||||
const contexts = this.contexts.get(oldReference);
|
||||
if(contexts) {
|
||||
this.contexts.delete(oldReference);
|
||||
this.contexts.set(newReference, contexts);
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
const referenceDatabase = new ReferenceDatabase();
|
||||
// @ts-ignore
|
||||
if(process.env.NODE_ENV != 'production') {
|
||||
(window as any).referenceDatabase = referenceDatabase;
|
||||
}
|
||||
|
@ -25,12 +25,13 @@ Uint8Array.prototype.concat = function(...args: Array<Uint8Array | ArrayBuffer |
|
||||
return bufferConcats(this, ...args);
|
||||
};
|
||||
|
||||
Uint8Array.prototype.toString = function() {
|
||||
/* Uint8Array.prototype.toString = function() {
|
||||
return String.fromCharCode.apply(null, [...this]);
|
||||
};
|
||||
}; */
|
||||
|
||||
Uint8Array.prototype.toJSON = function() {
|
||||
return [...this];
|
||||
//return [...this];
|
||||
return {type: 'bytes', value: [...this]};
|
||||
};
|
||||
|
||||
Array.prototype.forEachReverse = function<T>(callback: (value: T, index?: number, array?: Array<T>) => void) {
|
||||
@ -62,8 +63,9 @@ declare global {
|
||||
hex: string;
|
||||
randomize: () => Uint8Array,
|
||||
concat: (...args: Array<Uint8Array | ArrayBuffer | number[]>) => Uint8Array,
|
||||
toString: () => string,
|
||||
toJSON: () => number[],
|
||||
//toString: () => string,
|
||||
//toJSON: () => number[],
|
||||
toJSON: () => {type: 'bytes', value: number[]},
|
||||
}
|
||||
|
||||
interface Array<T> {
|
||||
|
@ -1,7 +1,7 @@
|
||||
importScripts('rlottie-wasm.js');
|
||||
//import Module, { allocate, intArrayFromString } from './rlottie-wasm';
|
||||
|
||||
const _Module = Module as any;
|
||||
const _Module = (self as any).Module as any;
|
||||
|
||||
const DEFAULT_FPS = 60;
|
||||
|
||||
@ -11,13 +11,23 @@ export class RLottieItem {
|
||||
private frameCount = 0;
|
||||
|
||||
private dead = false;
|
||||
//private context: OffscreenCanvasRenderingContext2D;
|
||||
|
||||
constructor(private reqId: number, jsString: string, private width: number, private height: number, private fps: number) {
|
||||
constructor(private reqId: number, jsString: string, private width: number, private height: number, private fps: number/* , private canvas: OffscreenCanvas */) {
|
||||
this.fps = Math.max(1, Math.min(60, fps || DEFAULT_FPS));
|
||||
|
||||
//this.context = canvas.getContext('2d');
|
||||
|
||||
this.init(jsString);
|
||||
|
||||
reply('loaded', this.reqId, this.frameCount, this.fps);
|
||||
|
||||
/* let frame = 0;
|
||||
setInterval(() => {
|
||||
if(frame >= this.frameCount) frame = 0;
|
||||
let _frame = frame++;
|
||||
this.render(_frame, null);
|
||||
}, 1000 / this.fps); */
|
||||
}
|
||||
|
||||
private init(jsString: string) {
|
||||
@ -56,6 +66,8 @@ export class RLottieItem {
|
||||
} else {
|
||||
clamped.set(data);
|
||||
}
|
||||
|
||||
//this.context.putImageData(new ImageData(clamped, this.width, this.height), 0, 0);
|
||||
|
||||
reply('frame', this.reqId, frameNo, clamped);
|
||||
} catch(e) {
|
||||
@ -94,13 +106,13 @@ class RLottieWorker {
|
||||
|
||||
const worker = new RLottieWorker();
|
||||
|
||||
Module.onRuntimeInitialized = function() {
|
||||
_Module.onRuntimeInitialized = function() {
|
||||
worker.init();
|
||||
};
|
||||
|
||||
const items: {[reqId: string]: RLottieItem} = {};
|
||||
const queryableFunctions = {
|
||||
loadFromData: function(reqId: number, jsString: string, width: number, height: number) {
|
||||
loadFromData: function(reqId: number, jsString: string, width: number, height: number/* , canvas: OffscreenCanvas */) {
|
||||
try {
|
||||
// ! WARNING, с этой проверкой не все стикеры работают, например - ДУРКА
|
||||
/* if(!/"tgs":\s*?1./.test(jsString)) {
|
||||
@ -112,7 +124,7 @@ const queryableFunctions = {
|
||||
|
||||
//console.log('Rendering sticker:', reqId, frameRate, 'now rendered:', Object.keys(items).length);
|
||||
|
||||
items[reqId] = new RLottieItem(reqId, jsString, width, height, frameRate);
|
||||
items[reqId] = new RLottieItem(reqId, jsString, width, height, frameRate/* , canvas */);
|
||||
} catch(e) {
|
||||
console.error('Invalid file for sticker:', jsString);
|
||||
reply('error', reqId, e);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Modes } from './mtproto/mtproto_config';
|
||||
import { notifySomeone, isWorker } from '../helpers/context';
|
||||
import { parse, stringify } from '../helpers/json';
|
||||
|
||||
class ConfigStorage {
|
||||
public keyPrefix = '';
|
||||
@ -16,24 +17,24 @@ class ConfigStorage {
|
||||
return this.keyPrefix;
|
||||
}
|
||||
|
||||
get(keys: any, callback: any) {
|
||||
get(keys: string | string[], callback: any) {
|
||||
var single = false;
|
||||
if(!Array.isArray(keys)) {
|
||||
keys = Array.prototype.slice.call(arguments);
|
||||
callback = keys.pop();
|
||||
single = keys.length == 1;
|
||||
}
|
||||
var result = [],
|
||||
value;
|
||||
var result = [];
|
||||
var allFound = true;
|
||||
var prefix = this.storageGetPrefix(),
|
||||
i, key;
|
||||
var prefix = this.storageGetPrefix();
|
||||
|
||||
for(i = 0; i < keys.length; i++) {
|
||||
key = keys[i] = prefix + keys[i];
|
||||
if(key.substr(0, 3) != 'xt_' && this.cache[key] !== undefined) {
|
||||
for(let key of keys) {
|
||||
key = prefix + key;
|
||||
|
||||
if(this.cache.hasOwnProperty(key)) {
|
||||
result.push(this.cache[key]);
|
||||
} else if(this.useLs) {
|
||||
let value: any;
|
||||
try {
|
||||
value = localStorage.getItem(key);
|
||||
} catch(e) {
|
||||
@ -41,7 +42,7 @@ class ConfigStorage {
|
||||
}
|
||||
|
||||
try {
|
||||
value = (value === undefined || value === null) ? false : JSON.parse(value);
|
||||
value = (value === undefined || value === null) ? false : parse(value);
|
||||
} catch(e) {
|
||||
value = false;
|
||||
}
|
||||
@ -68,10 +69,7 @@ class ConfigStorage {
|
||||
value = obj[key];
|
||||
key = prefix + key;
|
||||
this.cache[key] = value;
|
||||
value = JSON.stringify(value, (key, value) => {
|
||||
if(key == 'downloaded' || (key == 'url' && value.indexOf('blob:') === 0)) return undefined;
|
||||
return value;
|
||||
});
|
||||
value = stringify(value);
|
||||
|
||||
if(this.useLs) {
|
||||
try {
|
||||
|
@ -343,6 +343,28 @@ export function safeReplaceObject(wasObject: any, newObject: any) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be used for FILE_REFERENCE_EXPIRED
|
||||
* @param key
|
||||
* @param wasObject
|
||||
* @param newObject
|
||||
*/
|
||||
export function safeReplaceArrayInObject<K>(key: K, wasObject: any, newObject: any) {
|
||||
if('byteLength' in newObject[key]) { // Uint8Array
|
||||
newObject[key] = [...newObject[key]];
|
||||
}
|
||||
|
||||
if(wasObject && wasObject[key] != newObject[key]) {
|
||||
wasObject[key].length = newObject[key].length;
|
||||
(newObject[key] as any[]).forEach((v, i) => {
|
||||
wasObject[key][i] = v;
|
||||
})
|
||||
|
||||
/* wasObject[key].set(newObject[key]); */
|
||||
newObject[key] = wasObject[key];
|
||||
}
|
||||
}
|
||||
|
||||
export function numberWithCommas(x: number) {
|
||||
var parts = x.toString().split(".");
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
|
@ -1,6 +1,7 @@
|
||||
// @ts-check
|
||||
const schema = require('./in/schema.json');
|
||||
const additional = require('./in/schema_additional_params.json');
|
||||
const schema = require(__dirname + '/in/schema.json');
|
||||
const additional = require(__dirname + '/in/schema_additional_params.json');
|
||||
const replace = require(__dirname + '/in/schema_replace_types.json');
|
||||
|
||||
const mtproto = schema.API;
|
||||
|
||||
@ -10,6 +11,12 @@ for(const constructor of additional) {
|
||||
});
|
||||
|
||||
const realConstructor = mtproto.constructors.find(c => c.predicate == constructor.predicate);
|
||||
/* constructor.params.forEach(param => {
|
||||
const index = realConstructor.params.findIndex(_param => _param.predicate == param.predicate);
|
||||
if(index !== -1) {
|
||||
realConstructor.params.splice(index, 1);
|
||||
}
|
||||
}); */
|
||||
realConstructor.params.splice(realConstructor.params.length, 0, ...constructor.params);
|
||||
}
|
||||
|
||||
@ -80,7 +87,7 @@ const processParamType = (type) => {
|
||||
return 'string';
|
||||
|
||||
case 'bytes':
|
||||
return 'Uint8Array | number[]';
|
||||
return 'Uint8Array';
|
||||
|
||||
case 'string':
|
||||
return 'string';
|
||||
@ -105,6 +112,10 @@ const processParams = (params, object = {}, parseBooleanFlags = true) => {
|
||||
name += '?';
|
||||
}
|
||||
|
||||
if(replace[name]) {
|
||||
type = replace[name];
|
||||
}
|
||||
|
||||
const processed = processParamType(type);
|
||||
if(type.includes('?true') && parseBooleanFlags) {
|
||||
if(!object.pFlags) object.pFlags = {};
|
||||
@ -238,4 +249,5 @@ for(const method in methodsMap) {
|
||||
}
|
||||
out += `}\n\n`;
|
||||
|
||||
require('fs').writeFileSync('./out/layer.d.ts', out);
|
||||
const path = process.argv[2];
|
||||
require('fs').writeFileSync((path || __dirname + '/out/') + 'layer.d.ts', out);
|
@ -54,4 +54,30 @@
|
||||
{"name": "peerID", "type": "number"},
|
||||
{"name": "folder_id", "type": "number"}
|
||||
]
|
||||
}, {
|
||||
"predicate": "message",
|
||||
"params": [
|
||||
{"name": "mid", "type": "number"},
|
||||
{"name": "deleted", "type": "boolean"},
|
||||
{"name": "peerID", "type": "number"},
|
||||
{"name": "fromID", "type": "number"},
|
||||
{"name": "grouped_id", "type": "string"},
|
||||
{"name": "canBeEdited", "type": "boolean"},
|
||||
{"name": "unread", "type": "true"}
|
||||
]
|
||||
}, {
|
||||
"predicate": "messageService",
|
||||
"params": [
|
||||
{"name": "mid", "type": "number"},
|
||||
{"name": "deleted", "type": "boolean"},
|
||||
{"name": "peerID", "type": "number"},
|
||||
{"name": "fromID", "type": "number"},
|
||||
{"name": "canBeEdited", "type": "boolean"},
|
||||
{"name": "unread", "type": "true"}
|
||||
]
|
||||
}, {
|
||||
"predicate": "messageEmpty",
|
||||
"params": [
|
||||
{"name": "deleted", "type": "boolean"}
|
||||
]
|
||||
}]
|
3
src/scripts/in/schema_replace_types.json
Normal file
3
src/scripts/in/schema_replace_types.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"file_reference": "Uint8Array | number[]"
|
||||
}
|
@ -249,15 +249,24 @@
|
||||
padding: 0 .5rem;
|
||||
flex: 0 0 auto;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding-bottom: .5rem;
|
||||
}
|
||||
|
||||
@include respond-to(not-handhelds) {
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
padding-bottom: 21px;
|
||||
}
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
padding-bottom: .5rem;
|
||||
}
|
||||
|
||||
@include respond-to(esg-bottom) {
|
||||
padding-bottom: .5rem;
|
||||
|
||||
.btn-circle {
|
||||
height: 46px;
|
||||
width: 46px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* @include respond-to(handhelds) {
|
||||
@ -313,7 +322,7 @@
|
||||
align-self: flex-end;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
||||
#btn-send {
|
||||
color: #9e9e9e;
|
||||
|
||||
@ -551,11 +560,15 @@
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
min-height: 46px;
|
||||
padding: .5px .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@include respond-to(esg-bottom) {
|
||||
min-height: 46px;
|
||||
padding: .5px .5rem;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
@ -697,7 +710,7 @@
|
||||
}
|
||||
|
||||
html.no-touch &:hover {
|
||||
background-color: rgba(112, 117, 121, 0.08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
|
||||
&-border {
|
||||
|
@ -1776,11 +1776,11 @@ poll-element {
|
||||
}
|
||||
}
|
||||
|
||||
&-line {
|
||||
/* &-line {
|
||||
use {
|
||||
|
||||
}
|
||||
}
|
||||
} */
|
||||
}
|
||||
|
||||
avatar-element {
|
||||
|
@ -26,7 +26,7 @@
|
||||
|
||||
input {
|
||||
--border-width: 1px;
|
||||
background-color: rgba(112, 117, 121, .08);
|
||||
background-color: var(--color-gray-hover);
|
||||
height: 40px;
|
||||
border-radius: 22px;
|
||||
border: var(--border-width) solid transparent;
|
||||
@ -42,7 +42,7 @@
|
||||
|
||||
&:focus {
|
||||
--border-width: 2px;
|
||||
background-color: rgba(112, 117, 121, 0);
|
||||
background-color: transparent;
|
||||
border: 2px solid $button-primary-background;
|
||||
|
||||
& + .tgico {
|
||||
@ -151,13 +151,19 @@
|
||||
}
|
||||
|
||||
html.no-touch &:hover {
|
||||
background: rgba(112, 117, 121, .08);
|
||||
background: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
|
||||
li.active, li.menu-open {
|
||||
li.menu-open {
|
||||
> .rp {
|
||||
background: rgba(112, 117, 121, 0.08);
|
||||
background: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
|
||||
@include respond-to(not-handhelds) {
|
||||
li.active > .rp {
|
||||
background: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@
|
||||
}
|
||||
|
||||
html.no-touch &:hover {
|
||||
background-color: rgba(112, 117, 121, .08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -226,7 +226,7 @@
|
||||
> .grid-item {
|
||||
html.no-touch &:hover {
|
||||
border-radius: 12px;
|
||||
background-color: rgba(112, 117, 121, .08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
|
||||
/* &:nth-child(5n+5) {
|
||||
@ -243,6 +243,7 @@
|
||||
|
||||
> img {
|
||||
animation: fadeIn .2s ease forwards;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,7 +311,7 @@
|
||||
|
||||
&.active {
|
||||
&:not(.tgico-recent) {
|
||||
background-color: rgba(112, 117, 121, .08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -371,7 +371,7 @@
|
||||
}
|
||||
|
||||
html.no-touch &:hover {
|
||||
background: rgba(112, 117, 121, 0.08);
|
||||
background: var(--color-gray-hover);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -605,7 +605,7 @@
|
||||
|
||||
&:hover {
|
||||
border-radius: 12px;
|
||||
background-color: rgba(112, 117, 121, 0.08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
|
||||
img {
|
||||
|
@ -45,7 +45,7 @@
|
||||
|
||||
&-user {
|
||||
color: #000;
|
||||
background-color: rgba(112, 117, 121, 0.08);
|
||||
background-color: var(--color-gray-hover);
|
||||
font-size: 16px;
|
||||
padding: 0 17px 0px 0px;
|
||||
line-height: 31px;
|
||||
|
@ -38,7 +38,7 @@ $slider-time: .25s;
|
||||
transition: background-color .15s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(112, 117, 121, .08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@
|
||||
overflow: hidden;
|
||||
|
||||
html.no-touch &:hover {
|
||||
background-color: rgba(112, 117, 121, 0.08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
|
||||
& + button {
|
||||
|
@ -68,7 +68,7 @@
|
||||
|
||||
&:hover {
|
||||
border-radius: 12px;
|
||||
background-color: rgba(112, 117, 121, 0.08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
|
||||
img {
|
||||
|
@ -65,10 +65,15 @@ $floating-left-sidebar: 925px;
|
||||
@else if $media == esg-top { // topbar + chat input + margin bottom + height of ESG
|
||||
@media only screen and (min-height: 570px) and (min-width: $small-screen + 1) { @content; }
|
||||
}
|
||||
|
||||
@else if $media == esg-bottom {
|
||||
@media only screen and (max-height: 569px) { @content; }
|
||||
}
|
||||
}
|
||||
|
||||
:root {
|
||||
--color-gray: #c4c9cc;
|
||||
--color-gray-hover: rgba(112, 117, 121, .08);
|
||||
--layer-transition: .2s ease-in-out;
|
||||
//--layer-transition: .3s cubic-bezier(.33, 1, .68, 1);
|
||||
//--layer-transition: none;
|
||||
@ -315,7 +320,7 @@ input, textarea {
|
||||
}
|
||||
|
||||
html.no-touch &:hover {
|
||||
background-color: rgba(112, 117, 121, .08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
|
||||
@ -798,7 +803,7 @@ hr {
|
||||
grid-template-columns: calc(26px + 2rem) 1fr 50px;
|
||||
|
||||
html.no-touch &:hover {
|
||||
background-color: rgba(112, 117, 121, .08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
|
||||
@ -920,7 +925,7 @@ input:focus, button:focus {
|
||||
pointer-events: all !important;
|
||||
|
||||
&:not(.btn-primary).menu-open {
|
||||
background-color: rgba(112, 117, 121, 0.08);
|
||||
background-color: var(--color-gray-hover);
|
||||
}
|
||||
}
|
||||
|
||||
|
2136
src/vendor/leemon.ts
vendored
Normal file
2136
src/vendor/leemon.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user