Browse Source

webpage title & file downloads & progress bars

master
Eduard Kuzmenko 5 years ago
parent
commit
427718d852
  1. 19
      package-lock.json
  2. 4
      package.json
  3. 22
      src/components/pageSignUp.ts
  4. 37
      src/components/wrappers.ts
  5. 42
      src/lib/appManagers/appDocsManager.ts
  6. 4
      src/lib/appManagers/appImManager.ts
  7. 5
      src/lib/appManagers/appMediaViewer.ts
  8. 68
      src/lib/appManagers/appPhotosManager.ts
  9. 192
      src/lib/filemanager.ts
  10. 5
      src/lib/lottieLoader.ts
  11. 42
      src/lib/mtproto/apiFileManager.ts
  12. 8
      src/scss/partials/_sidebar.scss
  13. 42
      src/scss/style.scss
  14. 3
      webpack.dev.js
  15. 2
      webpack.prod.js

19
package-lock.json generated

@ -6521,9 +6521,10 @@
} }
}, },
"lottie-web": { "lottie-web": {
"version": "5.6.3", "version": "5.6.4",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.6.3.tgz", "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.6.4.tgz",
"integrity": "sha512-cSG6kSA2m5ppxV/QMVHRVGop/R+oXgO4vVMvDcZR015Cy0PGml5hHP+XG21yB2qV6cYZy+X3ChTogSALgch7CA==" "integrity": "sha512-eU+21Wo/RSi4i260S7fDUxfhNJ9PhfzUJMVQpip0yZd19oJ18jrNCoSQKVUzjC2TzOjqumlLZXR636ezKoWNQg==",
"dev": true
}, },
"loud-rejection": { "loud-rejection": {
"version": "1.6.0", "version": "1.6.0",
@ -12816,6 +12817,12 @@
"integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
"dev": true "dev": true
}, },
"streamsaver": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/streamsaver/-/streamsaver-2.0.3.tgz",
"integrity": "sha512-IpXeZ67YxcsrfZHe3yg/IyZ5KPfRSn1teDy5mRX2e8M6K410NcJNcR+SFQ2Z92DO36VBUArQP4Vy3Qu33MwIOQ==",
"dev": true
},
"string-length": { "string-length": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz",
@ -13761,6 +13768,12 @@
"minimalistic-assert": "^1.0.0" "minimalistic-assert": "^1.0.0"
} }
}, },
"web-streams-polyfill": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-2.0.6.tgz",
"integrity": "sha512-nXOi4fBykO4LzyQhZX3MAGib635KGZBoNTkNXrNIkz0zthEf2QokEWxRb0H632xNLDWtHFb1R6dFGzksjYMSDw==",
"dev": true
},
"webidl-conversions": { "webidl-conversions": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",

4
package.json

@ -14,7 +14,6 @@
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"jsbn": "^1.1.0", "jsbn": "^1.1.0",
"lottie-web": "^5.6.3",
"materialize-css": "^1.0.0", "materialize-css": "^1.0.0",
"roboto-fontface": "^0.10.0", "roboto-fontface": "^0.10.0",
"rusha": "^0.8.13", "rusha": "^0.8.13",
@ -41,6 +40,7 @@
"install": "^0.13.0", "install": "^0.13.0",
"jest": "^24.9.0", "jest": "^24.9.0",
"leemon": "^6.2.0", "leemon": "^6.2.0",
"lottie-web": "^5.6.4",
"node-sass": "^4.13.0", "node-sass": "^4.13.0",
"npm": "^6.13.4", "npm": "^6.13.4",
"offscreen-canvas": "^0.1.1", "offscreen-canvas": "^0.1.1",
@ -49,11 +49,13 @@
"pako": "^1.0.10", "pako": "^1.0.10",
"resolve-url-loader": "^3.1.1", "resolve-url-loader": "^3.1.1",
"sass-loader": "^8.0.0", "sass-loader": "^8.0.0",
"streamsaver": "^2.0.3",
"style-loader": "^1.0.0", "style-loader": "^1.0.0",
"ts-jest": "^24.3.0", "ts-jest": "^24.3.0",
"ts-loader": "^6.2.1", "ts-loader": "^6.2.1",
"typescript": "^3.7.2", "typescript": "^3.7.2",
"url-loader": "^2.2.0", "url-loader": "^2.2.0",
"web-streams-polyfill": "^2.0.6",
"webp-hero": "0.0.0-dev.24", "webp-hero": "0.0.0-dev.24",
"webpack": "^4.41.2", "webpack": "^4.41.2",
"webpack-cli": "^3.3.10", "webpack-cli": "^3.3.10",

22
src/components/pageSignUp.ts

@ -9,6 +9,7 @@ let authCode: {
import resizeableImage from '../lib/cropper'; import resizeableImage from '../lib/cropper';
import pageIm from './pageIm'; import pageIm from './pageIm';
import apiManager from '../lib/mtproto/apiManager'; import apiManager from '../lib/mtproto/apiManager';
import apiFileManager from '../lib/mtproto/apiFileManager';
export default (_authCode: typeof authCode) => { export default (_authCode: typeof authCode) => {
authCode = _authCode; authCode = _authCode;
@ -71,19 +72,6 @@ export default (_authCode: typeof authCode) => {
if(!file) { if(!file) {
return; return;
} }
/* console.log(file, typeof(file)); */
// @ts-ignore
/* apiFileManager.uploadFile(file).then(function(inputFile) {
console.log('uploaded smthn', inputFile);
apiManager.invokeApi('photos.uploadProfilePhoto', {
file: inputFile
}).then(function (updateResult) {
console.log('updated photo!');
});
}); */
var reader = new FileReader(); var reader = new FileReader();
reader.onload = (e) => { reader.onload = (e) => {
@ -94,18 +82,11 @@ export default (_authCode: typeof authCode) => {
avatarImage.src = contents; avatarImage.src = contents;
avatarImage.onload = () => { avatarImage.onload = () => {
/* avatarPreviewCtx.drawImage(avatarImage,
70, 20, // Start at 70/20 pixels from the left and the top of the image (crop),
50, 50, // "Get" a `50 * 50` (w * h) area from the source image (crop),
0, 0, // Place the result at 0, 0 in the canvas,
100, 100); // With as width / height: 100 * 100 (scale) */
cropper = resizeableImage(avatarImage, avatarPreview); cropper = resizeableImage(avatarImage, avatarPreview);
avatarInput.value = ''; avatarInput.value = '';
}; };
avatarPopup.classList.add('active'); avatarPopup.classList.add('active');
//console.log(contents);
}; };
reader.readAsDataURL(file); reader.readAsDataURL(file);
@ -136,7 +117,6 @@ export default (_authCode: typeof authCode) => {
} }
console.log('invoking uploadFile...'); console.log('invoking uploadFile...');
// @ts-ignore
apiFileManager.uploadFile(avatarBlob).then((inputFile: any) => { apiFileManager.uploadFile(avatarBlob).then((inputFile: any) => {
console.log('uploaded smthn', inputFile); console.log('uploaded smthn', inputFile);

37
src/components/wrappers.ts

@ -7,7 +7,7 @@ import {AppImManager} from "../lib/appManagers/appImManager";
import { formatBytes } from "../lib/utils"; import { formatBytes } from "../lib/utils";
import ProgressivePreloader from './preloader'; import ProgressivePreloader from './preloader';
import LazyLoadQueue from './lazyLoadQueue'; import LazyLoadQueue from './lazyLoadQueue';
import apiFileManager from '../lib/mtproto/apiFileManager'; import apiFileManager, { CancellablePromise } from '../lib/mtproto/apiFileManager';
import appWebpManager from '../lib/appManagers/appWebpManager'; import appWebpManager from '../lib/appManagers/appWebpManager';
import {wrapPlayer} from '../lib/ckin'; import {wrapPlayer} from '../lib/ckin';
@ -190,9 +190,44 @@ export function wrapDocument(doc: MTDocument, withTime = false): HTMLDivElement
docDiv.innerHTML = ` docDiv.innerHTML = `
<div class="document-ico ext-${ext}">${ext2}</div> <div class="document-ico ext-${ext}">${ext2}</div>
<div class="document-download"><div class="tgico-download"></div></div>
<div class="document-name">${fileName}</div> <div class="document-name">${fileName}</div>
<div class="document-size">${size}</div> <div class="document-size">${size}</div>
`; `;
let downloadDiv = docDiv.querySelector('.document-download') as HTMLDivElement;
let preloader: ProgressivePreloader;
let promise: CancellablePromise<Blob>;
docDiv.addEventListener('click', () => {
if(!promise) {
if(!preloader) {
preloader = new ProgressivePreloader(downloadDiv, true);
} else {
preloader.attach(downloadDiv, true);
}
promise = appDocsManager.saveDocFile(doc.id);
promise.notify = (details: {done: number, total: number}) => {
console.log('docDiv download', promise, details);
let percents = details.done / details.total * 100;
preloader.setProgress(percents);
};
downloadDiv.classList.add('downloading');
promise.then(() => {
downloadDiv.classList.remove('downloading');
preloader.detach();
downloadDiv.remove();
});
} else {
downloadDiv.classList.remove('downloading');
promise.cancel();
preloader.detach();
promise = null;
}
});
return docDiv; return docDiv;
} }

42
src/lib/appManagers/appDocsManager.ts

@ -232,27 +232,37 @@ class AppDocsManager {
}; */ }; */
//historyDoc.progress.cancel = downloadPromise.cancel; //historyDoc.progress.cancel = downloadPromise.cancel;
console.log('return downloadPromise:', downloadPromise);
return downloadPromise; return downloadPromise;
} }
/* public saveDocFile(docID: string) { public saveDocFile(docID: string): CancellablePromise<Blob> {
var doc = this.docs[docID] var doc = this.docs[docID];
var historyDoc = this.docsForHistory[docID] || doc || {} var fileName = this.getFileName(doc);
var mimeType = doc.mime_type var ext = (fileName.split('.', 2) || [])[1] || '';
var fileName = this.getFileName(doc)
var ext = (fileName.split('.', 2) || [])[1] || '' try {
let writer = FileManager.chooseSaveFile(fileName, ext, doc.mime_type, doc.size);
FileManager.chooseSave(this.getFileName(doc), ext, doc.mime_type).then((writableFileEntry) => { return writer.ready.then(() => {
if (writableFileEntry) { let promise = this.downloadDoc(docID, writer);
this.downloadDoc(docID, writableFileEntry) promise.then(() => {
} writer.close();
}, () => { console.log('saved doc', doc);
this.downloadDoc(docID).then((blob) => { });
return promise;
});
} catch(err) {
let promise = this.downloadDoc(docID);
promise.then((blob) => {
FileManager.download(blob, doc.mime_type, fileName) FileManager.download(blob, doc.mime_type, fileName)
}) });
})
} */ return promise;
}
}
} }
export default new AppDocsManager(); export default new AppDocsManager();

4
src/lib/appManagers/appImManager.ts

@ -1726,7 +1726,9 @@ export class AppImManager {
textDiv.innerHTML = RichTextProcessor.wrapRichText(webpage.description); textDiv.innerHTML = RichTextProcessor.wrapRichText(webpage.description);
} }
//textDiv.innerText = webpage.description || ''; if(webpage.title) {
titleDiv.innerHTML = RichTextProcessor.wrapRichText(webpage.title);
}
quote.append(nameEl, titleDiv, textDiv); quote.append(nameEl, titleDiv, textDiv);
box.append(quote); box.append(quote);

5
src/lib/appManagers/appMediaViewer.ts

@ -66,6 +66,11 @@ export class AppMediaViewer {
this.buttons.next.style.display = 'none'; this.buttons.next.style.display = 'none';
} }
}); });
this.buttons.download.addEventListener('click', () => {
let message = appMessagesManager.getMessage(this.currentMessageID);
appPhotosManager.downloadPhoto(message.media.photo.id);
});
/* this.buttons.prev.onclick = (e) => { /* this.buttons.prev.onclick = (e) => {
let history = appSidebarRight.historiesStorage[$rootScope.selectedPeerID]['inputMessagesFilterPhotoVideo'].slice(); let history = appSidebarRight.historiesStorage[$rootScope.selectedPeerID]['inputMessagesFilterPhotoVideo'].slice();

68
src/lib/appManagers/appPhotosManager.ts

@ -283,7 +283,7 @@ export class AppPhotosManager {
return photo; return photo;
} }
public wrapForFull(photoID: string) { /* public wrapForFull(photoID: string) {
var photo = this.wrapForHistory(photoID); var photo = this.wrapForHistory(photoID);
var fullWidth = document.body.scrollWidth - (Config.Mobile ? 0 : 32); var fullWidth = document.body.scrollWidth - (Config.Mobile ? 0 : 32);
var fullHeight = document.body.scrollHeight - (Config.Mobile ? 0 : 116); var fullHeight = document.body.scrollHeight - (Config.Mobile ? 0 : 116);
@ -310,38 +310,6 @@ export class AppPhotosManager {
photo.full = full; photo.full = full;
return photo; return photo;
}
/* public openPhoto(photoID: number, list: any) {
if(!photoID || photoID === '0') {
return false;
}
var scope = $rootScope.$new(true);
scope.photoID = photoID;
var controller = 'PhotoModalController';
if (list && list.p > 0) {
controller = 'UserpicModalController';
scope.userID = list.p;
} else if (list && list.p < 0) {
controller = 'ChatpicModalController';
scope.chatID = -list.p;
} else if (list && list.m > 0) {
scope.messageID = list.m;
if (list.w) {
scope.webpageID = list.w;
}
}
var modalInstance = $modal.open({
templateUrl: templateUrl('photo_modal'),
windowTemplateUrl: templateUrl('media_modal_layout'),
controller: controller,
scope: scope,
windowClass: 'photo_modal_window'
});
} */ } */
public downloadPhoto(photoID: string) { public downloadPhoto(photoID: string) {
@ -349,28 +317,36 @@ export class AppPhotosManager {
var ext = 'jpg'; var ext = 'jpg';
var mimeType = 'image/jpeg'; var mimeType = 'image/jpeg';
var fileName = 'photo' + photoID + '.' + ext; var fileName = 'photo' + photoID + '.' + ext;
var fullWidth = Math.max(screen.width || 0, document.body.scrollWidth - 36, 800); var fullWidth = this.windowW;
var fullHeight = Math.max(screen.height || 0, document.body.scrollHeight - 150, 800); var fullHeight = this.windowH;
var fullPhotoSize = this.choosePhotoSize(photo, fullWidth, fullHeight); var fullPhotoSize = this.choosePhotoSize(photo, fullWidth, fullHeight);
var inputFileLocation = { var inputFileLocation = {
_: 'inputFileLocation', // @ts-ignore
volume_id: fullPhotoSize.location.volume_id, _: photo._ == 'document' ? 'inputDocumentFileLocation' : 'inputPhotoFileLocation',
local_id: fullPhotoSize.location.local_id, id: photo.id,
secret: fullPhotoSize.location.secret access_hash: photo.access_hash,
file_reference: photo.file_reference,
thumb_size: fullPhotoSize.type
}; };
fileManager.chooseSaveFile(fileName, ext, mimeType).then((writableFileEntry) => { try { // photo.dc_id, location, photoSize.size
if(writableFileEntry) { let writer = fileManager.chooseSaveFile(fileName, ext, mimeType, fullPhotoSize.size);
writer.ready.then(() => {
console.log('ready');
apiFileManager.downloadFile(photo.dc_id, inputFileLocation, fullPhotoSize.size, { apiFileManager.downloadFile(photo.dc_id, inputFileLocation, fullPhotoSize.size, {
mimeType: mimeType, mimeType: mimeType,
toFileEntry: writableFileEntry toFileEntry: writer
}).then(() => { }).then(() => {
// console.log('file save done') writer.close();
//writer.abort();
console.log('file save done', fileName, ext, mimeType, writer);
}, (e: any) => { }, (e: any) => {
console.log('photo download failed', e); console.log('photo download failed', e);
}); });
} });
}, () => { } catch(err) {
console.error('err', err);
var cachedBlob = apiFileManager.getCachedFile(inputFileLocation) var cachedBlob = apiFileManager.getCachedFile(inputFileLocation)
if (cachedBlob) { if (cachedBlob) {
return fileManager.download(cachedBlob, mimeType, fileName); return fileManager.download(cachedBlob, mimeType, fileName);
@ -382,7 +358,7 @@ export class AppPhotosManager {
}, (e: any) => { }, (e: any) => {
console.log('photo download failed', e); console.log('photo download failed', e);
}); });
}); }
} }
} }

192
src/lib/filemanager.ts

@ -1,16 +1,20 @@
import {bytesToArrayBuffer, blobSafeMimeType, blobConstruct, bytesToBase64} from './bin_utils'; import {bytesToArrayBuffer, blobSafeMimeType, blobConstruct, bytesToBase64} from './bin_utils';
class FileManager { import 'web-streams-polyfill/ponyfill';
/* $window.URL = $window.URL || $window.webkitURL // @ts-ignore
$window.BlobBuilder = $window.BlobBuilder || $window.WebKitBlobBuilder || $window.MozBlobBuilder */ import streamSaver from 'streamsaver';
if(window.location.href.indexOf('localhost') === -1) {
streamSaver.mitm = 'mitm.html';
}
class FileManager {
public isSafari = 'safari' in window; public isSafari = 'safari' in window;
public safariVersion = parseFloat(this.isSafari && (navigator.userAgent.match(/Version\/(\d+\.\d+).* Safari/) || [])[1]); public safariVersion = parseFloat(this.isSafari && (navigator.userAgent.match(/Version\/(\d+\.\d+).* Safari/) || [])[1]);
public safariWithDownload = this.isSafari && this.safariVersion >= 11.0; public safariWithDownload = this.isSafari && this.safariVersion >= 11.0;
public buggyUnknownBlob = this.isSafari && !this.safariWithDownload; public buggyUnknownBlob = this.isSafari && !this.safariWithDownload;
public blobSupported = true; public blobSupported = true;
constructor() { constructor() {
try { try {
blobConstruct([], ''); blobConstruct([], '');
@ -18,12 +22,12 @@ class FileManager {
this.blobSupported = false; this.blobSupported = false;
} }
} }
public isAvailable() { public isAvailable() {
return this.blobSupported; return this.blobSupported;
} }
public copy(fromFileEntry: any, toFileEntry: any) { /* public copy(fromFileEntry: any, toFileEntry: any) {
return this.getFileWriter(toFileEntry).then((fileWriter) => { return this.getFileWriter(toFileEntry).then((fileWriter) => {
return this.write(fileWriter, fromFileEntry).then(() => { return this.write(fileWriter, fromFileEntry).then(() => {
return fileWriter; return fileWriter;
@ -32,13 +36,28 @@ class FileManager {
// @ts-ignore // @ts-ignore
fileWriter.truncate(0); fileWriter.truncate(0);
} catch (e) {} } catch (e) {}
return Promise.reject(error); return Promise.reject(error);
}); });
}); });
} */
public copy(fromFileEntry: any, toFileEntry: any) {
return this.write(toFileEntry, fromFileEntry).then(() => {
console.log('copy success');
return toFileEntry;
}, (error: any) => {
console.error('copy error 1:', error);
try {
toFileEntry.truncate(0);
} catch(e) {
console.error('copy error', e);
}
return Promise.reject(error);
});
} }
public write(fileWriter: any, bytes: any) { /* public write(fileWriter: any, bytes: any) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fileWriter.onwriteend = function(e: any) { fileWriter.onwriteend = function(e: any) {
resolve(); resolve();
@ -46,7 +65,7 @@ class FileManager {
fileWriter.onerror = function(e: any) { fileWriter.onerror = function(e: any) {
reject(e); reject(e);
}; };
if(bytes.file) { if(bytes.file) {
bytes.file((file: any) => { bytes.file((file: any) => {
fileWriter.write(file); fileWriter.write(file);
@ -62,54 +81,52 @@ class FileManager {
} }
} }
}); });
} } */
public write(fileWriter: any, bytes: any): Promise<void> {
if(bytes.file) {
return bytes.file((file: any) => {
return fileWriter.write(file);
});
} else if(bytes instanceof Blob) { // is file bytes
return new Promise((resolve, reject) => {
let fileReader = new FileReader();
fileReader.onload = function(event) {
let arrayBuffer = event.target.result as ArrayBuffer;
public chooseSaveFile(fileName: string, ext: string, mimeType: string) { let arr = new Uint8Array(arrayBuffer);
return Promise.reject();
/* if(!window.chrome || !chrome.fileSystem || !chrome.fileSystem.chooseEntry) {
//return qSync.reject()
return Promise.reject();
}
var deferred = $q.defer()
chrome.fileSystem.chooseEntry({ fileWriter.write(arr).then(resolve, reject);
type: 'saveFile', };
suggestedName: fileName,
accepts: [{
mimeTypes: [mimeType],
extensions: [ext]
}]
}, function (writableFileEntry) {
deferred.resolve(writableFileEntry)
})
return deferred.promise */ fileReader.readAsArrayBuffer(bytes);
});
} else {
//var blob = blobConstruct([bytesToArrayBuffer(bytes)]);
//return fileWriter.write(blob);
return fileWriter.write(bytes);
}
} }
public getFileWriter(fileEntry: any) { public chooseSaveFile(fileName: string, ext: string, mimeType: string, size?: number): any {
return new Promise((resolve, reject) => { let fileStream = streamSaver.createWriteStream(fileName, {
fileEntry.createWriter(resolve, reject); size: size,
writableStrategy: undefined,
readableStrategy: undefined
}); });
let writer = fileStream.getWriter();
return writer;
} }
public getFakeFileWriter(mimeType: string, saveFileCallback: any) { public getFakeFileWriter(mimeType: string, saveFileCallback: any) {
var blobParts: Array<Blob> = []; var blobParts: Array<Blob> = [];
var fakeFileWriter: any = { var fakeFileWriter = {
write: (blob: Blob) => { write: async(blob: Blob) => {
if(!this.blobSupported) { if(!this.blobSupported) {
if(fakeFileWriter.onerror) { throw false;
fakeFileWriter.onerror(new Error('Blob not supported by browser'));
}
return false;
} }
blobParts.push(blob); blobParts.push(blob);
setTimeout(() => {
if(fakeFileWriter.onwriteend) {
fakeFileWriter.onwriteend();
}
}, 0);
}, },
truncate: () => { truncate: () => {
blobParts = []; blobParts = [];
@ -119,14 +136,14 @@ class FileManager {
if(saveFileCallback) { if(saveFileCallback) {
saveFileCallback(blob); saveFileCallback(blob);
} }
return blob; return blob;
} }
}; };
return fakeFileWriter; return fakeFileWriter;
} }
public getUrl(fileData: any, mimeType: string) { public getUrl(fileData: any, mimeType: string) {
var safeMimeType = blobSafeMimeType(mimeType); var safeMimeType = blobSafeMimeType(mimeType);
// console.log(dT(), 'get url', fileData, mimeType, fileData.toURL !== undefined, fileData instanceof Blob) // console.log(dT(), 'get url', fileData, mimeType, fileData.toURL !== undefined, fileData instanceof Blob)
@ -138,7 +155,7 @@ class FileManager {
} }
return 'data:' + safeMimeType + ';base64,' + bytesToBase64(fileData); return 'data:' + safeMimeType + ';base64,' + bytesToBase64(fileData);
} }
public getByteArray(fileData: any) { public getByteArray(fileData: any) {
if(fileData instanceof Blob) { if(fileData instanceof Blob) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -146,7 +163,7 @@ class FileManager {
var reader = new FileReader(); var reader = new FileReader();
reader.onloadend = (e) => { reader.onloadend = (e) => {
// @ts-ignore // @ts-ignore
resolve(new Uint8Array(e.target.result)); resolve(new Uint8Array(e.target.result));
}; };
reader.onerror = (e) => { reader.onerror = (e) => {
reject(e); reject(e);
@ -163,11 +180,11 @@ class FileManager {
}, reject); }, reject);
}); });
} }
return Promise.resolve(fileData); return Promise.resolve(fileData);
//return $q.when(fileData); //return $q.when(fileData);
} }
public getDataUrl(blob: any) { public getDataUrl(blob: any) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
@ -181,7 +198,7 @@ class FileManager {
} }
}); });
} }
public getFileCorrectUrl(blob: any, mimeType: string) { public getFileCorrectUrl(blob: any, mimeType: string) {
if(this.buggyUnknownBlob && blob instanceof Blob) { if(this.buggyUnknownBlob && blob instanceof Blob) {
// @ts-ignore // @ts-ignore
@ -190,48 +207,48 @@ class FileManager {
return this.getDataUrl(blob); return this.getDataUrl(blob);
} }
} }
return Promise.resolve(this.getUrl(blob, mimeType)); return Promise.resolve(this.getUrl(blob, mimeType));
} }
// downloadFile // downloadFile
public download(blob: any, mimeType: string, fileName: string) { public download(blob: any, mimeType: string, fileName: string) {
if(window.navigator && navigator.msSaveBlob !== undefined) { if(window.navigator && navigator.msSaveBlob !== undefined) {
window.navigator.msSaveBlob(blob, fileName); window.navigator.msSaveBlob(blob, fileName);
return false; return false;
} }
if(window.navigator && 'getDeviceStorage' in navigator) { if(window.navigator && 'getDeviceStorage' in navigator) {
var storageName = 'sdcard'; var storageName = 'sdcard';
var subdir = 'telegram/'; var subdir = 'telegram/';
switch(mimeType.split('/')[0]) { switch(mimeType.split('/')[0]) {
case 'video': case 'video':
storageName = 'videos'; storageName = 'videos';
break; break;
case 'audio': case 'audio':
storageName = 'music'; storageName = 'music';
break; break;
case 'image': case 'image':
storageName = 'pictures'; storageName = 'pictures';
break; break;
} }
// @ts-ignore // @ts-ignore
var deviceStorage = navigator.getDeviceStorage(storageName); var deviceStorage = navigator.getDeviceStorage(storageName);
var request = deviceStorage.addNamed(blob, subdir + fileName); var request = deviceStorage.addNamed(blob, subdir + fileName);
request.onsuccess = function () { request.onsuccess = function () {
console.log('Device storage save result', this.result); console.log('Device storage save result', this.result);
}; };
request.onerror = () => {}; request.onerror = () => {};
return; return;
} }
var popup: Window; var popup: Window;
if(this.isSafari && !this.safariWithDownload) { if(this.isSafari && !this.safariWithDownload) {
popup = window.open(); popup = window.open();
} }
this.getFileCorrectUrl(blob, mimeType).then((url) => { this.getFileCorrectUrl(blob, mimeType).then((url) => {
if(popup) { if(popup) {
try { try {
@ -240,7 +257,7 @@ class FileManager {
return; return;
} catch (e) {} } catch (e) {}
} }
var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement; var anchor = document.createElementNS('http://www.w3.org/1999/xhtml', 'a') as HTMLAnchorElement;
anchor.href = url as string; anchor.href = url as string;
if(!this.safariWithDownload) { if(!this.safariWithDownload) {
@ -254,29 +271,30 @@ class FileManager {
anchor.style.position = 'absolute'; anchor.style.position = 'absolute';
anchor.style.top = '1px'; anchor.style.top = '1px';
anchor.style.left = '1px'; anchor.style.left = '1px';
document.body.append(anchor); document.body.append(anchor);
try { try {
var clickEvent = document.createEvent('MouseEvents'); var clickEvent = document.createEvent('MouseEvents');
clickEvent.initMouseEvent( clickEvent.initMouseEvent(
'click', true, false, window, 0, 0, 0, 0, 0 'click', true, false, window, 0, 0, 0, 0, 0
, false, false, false, false, 0, null , false, false, false, false, 0, null
) )
anchor.dispatchEvent(clickEvent); anchor.dispatchEvent(clickEvent);
} catch (e) {
console.error('Download click error', e);
try {
anchor.click();
} catch (e) { } catch (e) {
window.open(url as string, '_blank'); console.error('Download click error', e);
try {
anchor.click();
} catch (e) {
window.open(url as string, '_blank');
}
} }
} setTimeout(() => {
setTimeout(() => { anchor.remove();
anchor.remove(); }, 100);
}, 100); })
}) }
} }
}
export default new FileManager();
export default new FileManager();

5
src/lib/lottieLoader.ts

@ -1,4 +1,7 @@
import LottiePlayer, { AnimationConfigWithPath, AnimationConfigWithData, AnimationItem } from "lottie-web"; //import LottiePlayer, { AnimationConfigWithPath, AnimationConfigWithData, AnimationItem } from "lottie-web";
// @ts-ignore
import LottiePlayer, { AnimationConfigWithPath, AnimationConfigWithData, AnimationItem } from "lottie-web/build/player/lottie_canvas.min.js";
//import LottiePlayer, { AnimationConfigWithPath, AnimationConfigWithData, AnimationItem } from "lottie-web/build/player/lottie_light.min.js";
import { isElementInViewport, isInDOM } from "./utils"; import { isElementInViewport, isInDOM } from "./utils";
class LottieLoader { class LottieLoader {

42
src/lib/mtproto/apiFileManager.ts

@ -248,12 +248,12 @@ export class ApiFileManager {
return fileStorage.getFile(fileName, size); return fileStorage.getFile(fileName, size);
} }
public async downloadFile(dcID: number, location: any, size: number, options: { public downloadFile(dcID: number, location: any, size: number, options: {
mimeType?: string, mimeType?: string,
dcID?: number, dcID?: number,
toFileEntry?: any, toFileEntry?: any,
limitPart?: number limitPart?: number
} = {}): Promise<Blob> { } = {}): CancellablePromise<Blob> {
if(!FileManager.isAvailable()) { if(!FileManager.isAvailable()) {
return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'}); return Promise.reject({type: 'BROWSER_BLOB_NOT_SUPPORTED'});
} }
@ -288,19 +288,33 @@ export class ApiFileManager {
//this.log('downloadFile cachedPromise'); //this.log('downloadFile cachedPromise');
if(size) { if(size) {
let blob = await cachedPromise; /* let blob = await cachedPromise;
if(blob.size < size) { if(blob.size < size) {
this.log('downloadFile need to deleteFile, wrong size:', blob.size, size); this.log('downloadFile need to deleteFile, wrong size:', blob.size, size);
await this.deleteFile(location); await this.deleteFile(location);
} else { } else {
return cachedPromise; return cachedPromise;
} } */
return cachedPromise.then((blob: Blob) => {
if(blob.size < size) {
this.log('downloadFile need to deleteFile, wrong size:', blob.size, size);
return this.deleteFile(location).then(() => {
return this.downloadFile(dcID, location, size, options);
}).catch(() => {
return this.downloadFile(dcID, location, size, options);
});
} else {
//return cachedPromise;
return blob;
}
});
} else { } else {
return cachedPromise; return cachedPromise;
} }
} }
//this.log('arriba'); this.log('arriba');
//var deferred = $q.defer() //var deferred = $q.defer()
let deferredHelper: any = {notify: () => {}}; let deferredHelper: any = {notify: () => {}};
@ -310,16 +324,17 @@ export class ApiFileManager {
}); });
Object.assign(deferred, deferredHelper); Object.assign(deferred, deferredHelper);
//return;
var canceled = false; var canceled = false;
var resolved = false; var resolved = false;
var mimeType = options.mimeType || 'image/jpeg', var mimeType = options.mimeType || 'image/jpeg',
cacheFileWriter: any; cacheFileWriter: any;
var errorHandler = (error: any) => { var errorHandler = (error: any) => {
deferred.reject(error) deferred.reject(error);
errorHandler = () => {}; errorHandler = () => {};
if(cacheFileWriter && if(cacheFileWriter && (!error || error.type != 'DOWNLOAD_CANCELED')) {
(!error || error.type != 'DOWNLOAD_CANCELED')) {
cacheFileWriter.truncate(0); cacheFileWriter.truncate(0);
} }
}; };
@ -336,14 +351,15 @@ export class ApiFileManager {
if(toFileEntry) { if(toFileEntry) {
FileManager.copy(blob, toFileEntry).then(() => { FileManager.copy(blob, toFileEntry).then(() => {
deferred.resolve(); deferred.resolve();
}, errorHandler) }, errorHandler);
} else { } else {
deferred.resolve(this.cachedDownloads[fileName] = blob); deferred.resolve(this.cachedDownloads[fileName] = blob);
} }
//}, () => { //}, () => {
}).catch(() => { }).catch(() => {
//this.log('not i wanted'); //this.log('not i wanted');
var fileWriterPromise = toFileEntry ? FileManager.getFileWriter(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType); //var fileWriterPromise = toFileEntry ? FileManager.getFileWriter(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
var fileWriterPromise = toFileEntry ? Promise.resolve(toFileEntry) : fileStorage.getFileWriter(fileName, mimeType);
var processDownloaded = (bytes: any) => { var processDownloaded = (bytes: any) => {
return Promise.resolve(bytes); return Promise.resolve(bytes);
@ -414,7 +430,7 @@ export class ApiFileManager {
return Promise.resolve(); return Promise.resolve();
} }
return processDownloaded(result.bytes).then((processedResult) => { return processDownloaded(result.bytes).then((processedResult: Uint8Array) => {
return FileManager.write(fileWriter, processedResult).then(() => { return FileManager.write(fileWriter, processedResult).then(() => {
writeFileDeferred.resolve(); writeFileDeferred.resolve();
}, errorHandler).then(() => { }, errorHandler).then(() => {
@ -427,7 +443,7 @@ export class ApiFileManager {
deferred.resolve(this.cachedDownloads[fileName] = fileWriter.finalize()); deferred.resolve(this.cachedDownloads[fileName] = fileWriter.finalize());
} }
} else { } else {
this.log('deferred notify 2:', {done: offset + limit, total: size}); this.log('deferred notify 2:', {done: offset + limit, total: size}, deferred);
deferred.notify({done: offset + limit, total: size}); deferred.notify({done: offset + limit, total: size});
} }
}); });
@ -449,6 +465,8 @@ export class ApiFileManager {
} }
}; };
console.log(deferred, deferred.notify, deferred.cancel);
if(!toFileEntry) { if(!toFileEntry) {
this.cachedDownloadPromises[fileName] = deferred; this.cachedDownloadPromises[fileName] = deferred;
} }

8
src/scss/partials/_sidebar.scss

@ -163,15 +163,17 @@
#content-docs { #content-docs {
padding: 15px; padding: 15px;
padding-top: 3px;
.document { .document {
padding-left: 5rem; padding-left: 5rem;
padding-right: 1rem; padding-right: 1rem;
height: 54px; //height: 54px;
height: calc(54px + 1.5rem);
& + .document { /* & + .document {
margin-top: 1.5rem; margin-top: 1.5rem;
} } */
} }
.document-name { .document-name {

42
src/scss/style.scss

@ -61,11 +61,21 @@ button, input, optgroup, select, textarea, html {
min-width: 100%; min-width: 100%;
} }
.container {
margin: 0 auto;
}
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
letter-spacing: -.66px; letter-spacing: -.66px;
font-weight: 500; font-weight: 500;
} }
h4 {
font-size: 2.28rem;
margin: 1.52rem 0 .912rem 0;
line-height: 110%;
}
input { input {
caret-color: $button-primary-background; caret-color: $button-primary-background;
} }
@ -388,7 +398,7 @@ input {
cursor: pointer; cursor: pointer;
position: relative; position: relative;
.document-ico { .document-ico, .document-download {
position: absolute; position: absolute;
left: 0; left: 0;
width: 54px; width: 54px;
@ -404,6 +414,28 @@ input {
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.document-download {
z-index: 3;
background-color: rgb(101, 161, 227);
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
cursor: pointer;
.tgico-download {
transform: scale(1);
transition: .2s scale;
}
&.downloading {
.tgico-download {
transform: scale(0);
}
}
}
&:not(.photo) { &:not(.photo) {
.document-ico { .document-ico {
padding-top: 1.5rem; padding-top: 1.5rem;
@ -692,7 +724,7 @@ input {
text-align: left; text-align: left;
display: grid; display: grid;
grid-template-columns: 15% 65% 20%; grid-template-columns: 15% 60% 25%;
&:hover { &:hover {
background-color: rgba(112, 117, 121, .08); background-color: rgba(112, 117, 121, .08);
@ -1059,6 +1091,7 @@ span.popup-close {
justify-content: space-between; */ justify-content: space-between; */
display: flex; display: flex;
margin-bottom: 2rem; margin-bottom: 2rem;
align-items: center;
} }
.popup-avatar { .popup-avatar {
@ -1074,12 +1107,17 @@ span.popup-close {
right: 15px; right: 15px;
} }
} }
.popup-close {
font-size: 1.5rem;
}
h6 { h6 {
font-size: 1.1rem; font-size: 1.1rem;
text-align: left; text-align: left;
margin: 0; margin: 0;
margin-left: 1.5rem; margin-left: 1.5rem;
font-weight: 400;
} }
.crop { .crop {

3
webpack.dev.js

@ -6,5 +6,6 @@ module.exports = merge(common, {
devtool: 'inline-source-map', devtool: 'inline-source-map',
devServer: { devServer: {
contentBase: './public', contentBase: './public',
http2: true
}, },
}); });

2
webpack.prod.js

@ -59,6 +59,8 @@ module.exports = merge(common, {
files.forEach(file => { files.forEach(file => {
//console.log('to unlink 1:', file); //console.log('to unlink 1:', file);
if(file.includes('mitm.') || file.includes('sw.js')) return;
let p = path.resolve(buildDir + file); let p = path.resolve(buildDir + file);
if(!newlyCreatedAssets[file] && ['.gz', '.js'].find(ext => file.endsWith(ext)) !== undefined) { if(!newlyCreatedAssets[file] && ['.gz', '.js'].find(ext => file.endsWith(ext)) !== undefined) {

Loading…
Cancel
Save