Upload wallpaper
This commit is contained in:
parent
9174307be0
commit
dede33e9e4
@ -10,13 +10,16 @@ import blur from "../../../helpers/blur";
|
||||
import { deferredPromise } from "../../../helpers/cancellablePromise";
|
||||
import { attachClickEvent } from "../../../helpers/dom";
|
||||
import findUpClassName from "../../../helpers/dom/findUpClassName";
|
||||
import { requestFile } from "../../../helpers/files";
|
||||
import highlightningColor from "../../../helpers/highlightningColor";
|
||||
import { copy } from "../../../helpers/object";
|
||||
import { AccountWallPapers, WallPaper } from "../../../layer";
|
||||
import sequentialDom from "../../../helpers/sequentialDom";
|
||||
import { AccountWallPapers, PhotoSize, WallPaper } from "../../../layer";
|
||||
import appDocsManager, { MyDocument } from "../../../lib/appManagers/appDocsManager";
|
||||
import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
|
||||
import appImManager from "../../../lib/appManagers/appImManager";
|
||||
import appStateManager, { STATE_INIT } from "../../../lib/appManagers/appStateManager";
|
||||
import appPhotosManager from "../../../lib/appManagers/appPhotosManager";
|
||||
import appStateManager, { Theme, STATE_INIT } from "../../../lib/appManagers/appStateManager";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
import rootScope from "../../../lib/rootScope";
|
||||
import Button from "../../button";
|
||||
@ -26,43 +29,45 @@ import { SliderSuperTab } from "../../slider";
|
||||
import { wrapPhoto } from "../../wrappers";
|
||||
import AppBackgroundColorTab from "./backgroundColor";
|
||||
|
||||
let uploadTempId = 0;
|
||||
|
||||
export default class AppBackgroundTab extends SliderSuperTab {
|
||||
private grid: HTMLElement;
|
||||
private tempId = 0;
|
||||
private theme: Theme;
|
||||
private clicked: Set<string> = new Set();
|
||||
private blurCheckboxField: CheckboxField;
|
||||
|
||||
init() {
|
||||
this.container.classList.add('background-container', 'background-image-container');
|
||||
this.setTitle('ChatBackground');
|
||||
|
||||
this.theme = rootScope.settings.themes.find(t => t.name === rootScope.settings.theme);
|
||||
|
||||
{
|
||||
const container = generateSection(this.scrollable);
|
||||
|
||||
//const uploadButton = Button('btn-primary btn-transparent', {icon: 'cameraadd', text: 'ChatBackground.UploadWallpaper', disabled: true});
|
||||
const uploadButton = Button('btn-primary btn-transparent', {icon: 'cameraadd', text: 'ChatBackground.UploadWallpaper'});
|
||||
const colorButton = Button('btn-primary btn-transparent', {icon: 'colorize', text: 'SetColor'});
|
||||
const resetButton = Button('btn-primary btn-transparent', {icon: 'favourites', text: 'Appearance.Reset'});
|
||||
|
||||
attachClickEvent(uploadButton, this.onUploadClick, {listenerSetter: this.listenerSetter});
|
||||
|
||||
attachClickEvent(colorButton, () => {
|
||||
new AppBackgroundColorTab(this.slider).open();
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
attachClickEvent(resetButton, () => {
|
||||
const defaultTheme = STATE_INIT.settings.themes.find(t => t.name === theme.name);
|
||||
if(defaultTheme) {
|
||||
++tempId;
|
||||
theme.background = copy(defaultTheme.background);
|
||||
appStateManager.pushToState('settings', rootScope.settings);
|
||||
appImManager.applyCurrentTheme(undefined, undefined, true);
|
||||
blurCheckboxField.setValueSilently(theme.background.blur);
|
||||
}
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
attachClickEvent(resetButton, this.onResetClick, {listenerSetter: this.listenerSetter});
|
||||
|
||||
const theme = rootScope.settings.themes.find(t => t.name === rootScope.settings.theme);
|
||||
const blurCheckboxField = new CheckboxField({
|
||||
const blurCheckboxField = this.blurCheckboxField = new CheckboxField({
|
||||
text: 'ChatBackground.Blur',
|
||||
name: 'blur',
|
||||
checked: theme.background.blur,
|
||||
checked: this.theme.background.blur,
|
||||
withRipple: true
|
||||
});
|
||||
|
||||
this.listenerSetter.add(blurCheckboxField.input, 'change', () => {
|
||||
theme.background.blur = blurCheckboxField.input.checked;
|
||||
this.theme.background.blur = blurCheckboxField.input.checked;
|
||||
appStateManager.pushToState('settings', rootScope.settings);
|
||||
|
||||
const active = grid.querySelector('.active') as HTMLElement;
|
||||
@ -70,178 +75,290 @@ export default class AppBackgroundTab extends SliderSuperTab {
|
||||
|
||||
// * wait for animation end
|
||||
setTimeout(() => {
|
||||
setBackgroundDocument(active.dataset.slug, appDocsManager.getDoc(active.dataset.docId));
|
||||
this.setBackgroundDocument(active.dataset.slug, appDocsManager.getDoc(active.dataset.docId));
|
||||
}, 100);
|
||||
});
|
||||
|
||||
container.append(/* uploadButton, */colorButton, resetButton, blurCheckboxField.label);
|
||||
container.append(uploadButton, colorButton, resetButton, blurCheckboxField.label);
|
||||
}
|
||||
|
||||
const grid = document.createElement('div');
|
||||
grid.classList.add('grid');
|
||||
|
||||
const saveToCache = (slug: string, url: string) => {
|
||||
fetch(url).then(response => {
|
||||
appDownloadManager.cacheStorage.save('backgrounds/' + slug, response);
|
||||
});
|
||||
};
|
||||
|
||||
let tempId = 0;
|
||||
const setBackgroundDocument = (slug: string, doc: MyDocument) => {
|
||||
let _tempId = ++tempId;
|
||||
const middleware = () => _tempId === tempId;
|
||||
|
||||
const download = appDocsManager.downloadDoc(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);
|
||||
|
||||
const deferred = deferredPromise<void>();
|
||||
deferred.addNotifyListener = download.addNotifyListener;
|
||||
deferred.cancel = download.cancel;
|
||||
|
||||
download.then(() => {
|
||||
if(!middleware()) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const background = rootScope.settings.themes.find(t => t.name === rootScope.settings.theme).background;
|
||||
const onReady = (url: string) => {
|
||||
//const perf = performance.now();
|
||||
averageColor(url).then(pixel => {
|
||||
if(!middleware()) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const hsla = highlightningColor(Array.from(pixel) as any);
|
||||
//console.log(doc, hsla, performance.now() - perf);
|
||||
|
||||
background.slug = slug;
|
||||
background.type = 'image';
|
||||
background.highlightningColor = hsla;
|
||||
appStateManager.pushToState('settings', rootScope.settings);
|
||||
|
||||
saveToCache(slug, url);
|
||||
appImManager.applyCurrentTheme(slug, url).then(deferred.resolve);
|
||||
});
|
||||
};
|
||||
|
||||
if(background.blur) {
|
||||
setTimeout(() => {
|
||||
blur(doc.url, 12, 4)
|
||||
.then(url => {
|
||||
if(!middleware()) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
onReady(url);
|
||||
});
|
||||
}, 200);
|
||||
} else {
|
||||
onReady(doc.url);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
const setActive = () => {
|
||||
const active = grid.querySelector('.active');
|
||||
const background = rootScope.settings.themes.find(t => t.name === rootScope.settings.theme).background;
|
||||
const target = background.type === 'image' ? grid.querySelector(`.grid-item[data-slug="${background.slug}"]`) : null;
|
||||
if(active === target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(active) {
|
||||
active.classList.remove('active');
|
||||
}
|
||||
|
||||
if(target) {
|
||||
target.classList.add('active');
|
||||
}
|
||||
};
|
||||
|
||||
rootScope.on('background_change', setActive);
|
||||
rootScope.on('background_change', this.setActive);
|
||||
|
||||
apiManager.invokeApiHashable('account.getWallPapers').then((accountWallpapers) => {
|
||||
const background = rootScope.settings.themes.find(t => t.name === rootScope.settings.theme).background;
|
||||
const wallpapers = (accountWallpapers as AccountWallPapers.accountWallPapers).wallpapers as WallPaper.wallPaper[];
|
||||
wallpapers.forEach((wallpaper) => {
|
||||
if(wallpaper.pFlags.pattern || (wallpaper.document as MyDocument).mime_type.indexOf('application/') === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
wallpaper.document = appDocsManager.saveDoc(wallpaper.document);
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.classList.add('grid-item');
|
||||
|
||||
const wrapped = wrapPhoto({
|
||||
photo: wallpaper.document,
|
||||
message: null,
|
||||
container: container,
|
||||
boxWidth: 0,
|
||||
boxHeight: 0,
|
||||
withoutPreloader: true
|
||||
});
|
||||
|
||||
[wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach(image => {
|
||||
image.classList.add('grid-item-media');
|
||||
});
|
||||
|
||||
container.dataset.docId = wallpaper.document.id;
|
||||
container.dataset.slug = wallpaper.slug;
|
||||
|
||||
if(background.type === 'image' && background.slug === wallpaper.slug) {
|
||||
container.classList.add('active');
|
||||
}
|
||||
|
||||
grid.append(container);
|
||||
this.addWallPaper(wallpaper);
|
||||
});
|
||||
|
||||
let clicked: Set<string> = new Set();
|
||||
attachClickEvent(grid, (e) => {
|
||||
const target = findUpClassName(e.target, 'grid-item') as HTMLElement;
|
||||
if(!target) return;
|
||||
|
||||
const {docId, slug} = target.dataset;
|
||||
if(clicked.has(docId)) return;
|
||||
clicked.add(docId);
|
||||
|
||||
const preloader = new ProgressivePreloader({
|
||||
cancelable: true,
|
||||
tryAgainOnFail: false
|
||||
});
|
||||
|
||||
const doc = appDocsManager.getDoc(docId);
|
||||
|
||||
const load = () => {
|
||||
const promise = setBackgroundDocument(slug, doc);
|
||||
if(!doc.url || background.blur) {
|
||||
preloader.attach(target, true, promise);
|
||||
}
|
||||
};
|
||||
|
||||
preloader.construct();
|
||||
|
||||
attachClickEvent(target, (e) => {
|
||||
if(preloader.preloader.parentElement) {
|
||||
preloader.onClick(e);
|
||||
preloader.detach();
|
||||
} else {
|
||||
load();
|
||||
}
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
load();
|
||||
|
||||
//console.log(doc);
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
//console.log(accountWallpapers);
|
||||
});
|
||||
|
||||
const grid = this.grid = document.createElement('div');
|
||||
grid.classList.add('grid');
|
||||
attachClickEvent(grid, this.onGridClick, {listenerSetter: this.listenerSetter});
|
||||
this.scrollable.append(grid);
|
||||
}
|
||||
|
||||
private onUploadClick = () => {
|
||||
requestFile('image/x-png,image/png,image/jpeg').then(file => {
|
||||
const id = 'wallpaper-upload-' + ++uploadTempId;
|
||||
|
||||
const thumb = {
|
||||
_: 'photoSize',
|
||||
h: 0,
|
||||
w: 0,
|
||||
location: {} as any,
|
||||
size: file.size,
|
||||
type: 'full',
|
||||
url: URL.createObjectURL(file)
|
||||
} as PhotoSize.photoSize;
|
||||
let document: MyDocument = {
|
||||
_: 'document',
|
||||
access_hash: '',
|
||||
attributes: [],
|
||||
dc_id: 0,
|
||||
file_reference: [],
|
||||
id,
|
||||
mime_type: file.type,
|
||||
size: file.size,
|
||||
downloaded: true,
|
||||
date: Date.now() / 1000,
|
||||
url: thumb.url,
|
||||
pFlags: {},
|
||||
thumbs: [thumb],
|
||||
file_name: file.name
|
||||
};
|
||||
|
||||
document = appDocsManager.saveDoc(document);
|
||||
|
||||
const docThumb = appPhotosManager.getDocumentCachedThumb(document.id);
|
||||
docThumb.downloaded = thumb.size;
|
||||
docThumb.url = thumb.url;
|
||||
|
||||
let wallpaper: WallPaper.wallPaper = {
|
||||
_: 'wallPaper',
|
||||
access_hash: '',
|
||||
document: document,
|
||||
id,
|
||||
slug: id,
|
||||
pFlags: {}
|
||||
};
|
||||
|
||||
const upload = appDownloadManager.upload(file, file.name);
|
||||
|
||||
const deferred = deferredPromise<void>();
|
||||
deferred.addNotifyListener = upload.addNotifyListener;
|
||||
deferred.cancel = upload.cancel;
|
||||
|
||||
upload.then(inputFile => {
|
||||
apiManager.invokeApi('account.uploadWallPaper', {
|
||||
file: inputFile,
|
||||
mime_type: file.type,
|
||||
settings: {
|
||||
_: 'wallPaperSettings'
|
||||
}
|
||||
}).then(_wallpaper => {
|
||||
const newDoc = (_wallpaper as WallPaper.wallPaper).document as MyDocument;
|
||||
newDoc.downloaded = document.downloaded;
|
||||
newDoc.url = document.url;
|
||||
|
||||
wallpaper = _wallpaper as WallPaper.wallPaper;
|
||||
wallpaper.document = appDocsManager.saveDoc(wallpaper.document);
|
||||
|
||||
container.dataset.docId = wallpaper.document.id;
|
||||
container.dataset.slug = wallpaper.slug;
|
||||
|
||||
this.setBackgroundDocument(wallpaper.slug, wallpaper.document).then(deferred.resolve, deferred.reject);
|
||||
}, deferred.reject);
|
||||
}, deferred.reject);
|
||||
|
||||
deferred.then(() => {
|
||||
this.clicked.delete(wallpaper.document.id);
|
||||
}, (err) => {
|
||||
container.remove();
|
||||
//console.error('i saw the body drop', err);
|
||||
});
|
||||
|
||||
const preloader = new ProgressivePreloader({
|
||||
isUpload: true,
|
||||
cancelable: true,
|
||||
tryAgainOnFail: false
|
||||
});
|
||||
|
||||
const container = this.addWallPaper(wallpaper, false);
|
||||
this.clicked.add(wallpaper.document.id);
|
||||
|
||||
preloader.attach(container, false, deferred);
|
||||
});
|
||||
};
|
||||
|
||||
private onResetClick = () => {
|
||||
const defaultTheme = STATE_INIT.settings.themes.find(t => t.name === this.theme.name);
|
||||
if(defaultTheme) {
|
||||
++this.tempId;
|
||||
this.theme.background = copy(defaultTheme.background);
|
||||
appStateManager.pushToState('settings', rootScope.settings);
|
||||
appImManager.applyCurrentTheme(undefined, undefined, true);
|
||||
this.blurCheckboxField.setValueSilently(this.theme.background.blur);
|
||||
}
|
||||
};
|
||||
|
||||
private addWallPaper(wallpaper: WallPaper.wallPaper, append = true) {
|
||||
if(wallpaper.pFlags.pattern || (wallpaper.document as MyDocument).mime_type.indexOf('application/') === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
wallpaper.document = appDocsManager.saveDoc(wallpaper.document);
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.classList.add('grid-item');
|
||||
|
||||
const media = document.createElement('div');
|
||||
media.classList.add('grid-item-media');
|
||||
|
||||
const wrapped = wrapPhoto({
|
||||
photo: wallpaper.document,
|
||||
message: null,
|
||||
container: media,
|
||||
boxWidth: 0,
|
||||
boxHeight: 0,
|
||||
withoutPreloader: true
|
||||
});
|
||||
|
||||
container.dataset.docId = wallpaper.document.id;
|
||||
container.dataset.slug = wallpaper.slug;
|
||||
|
||||
if(this.theme.background.type === 'image' && this.theme.background.slug === wallpaper.slug) {
|
||||
container.classList.add('active');
|
||||
}
|
||||
|
||||
(wrapped.loadPromises.thumb || wrapped.loadPromises.full).then(() => {
|
||||
sequentialDom.mutate(() => {
|
||||
container.append(media);
|
||||
});
|
||||
});
|
||||
|
||||
this.grid[append ? 'append' : 'prepend'](container);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private onGridClick = (e: MouseEvent | TouchEvent) => {
|
||||
const target = findUpClassName(e.target, 'grid-item') as HTMLElement;
|
||||
if(!target) return;
|
||||
|
||||
const {docId, slug} = target.dataset;
|
||||
if(this.clicked.has(docId)) return;
|
||||
this.clicked.add(docId);
|
||||
|
||||
const preloader = new ProgressivePreloader({
|
||||
cancelable: true,
|
||||
tryAgainOnFail: false
|
||||
});
|
||||
|
||||
const doc = appDocsManager.getDoc(docId);
|
||||
|
||||
const load = () => {
|
||||
const promise = this.setBackgroundDocument(slug, doc);
|
||||
if(!doc.url || this.theme.background.blur) {
|
||||
preloader.attach(target, true, promise);
|
||||
}
|
||||
};
|
||||
|
||||
preloader.construct();
|
||||
|
||||
attachClickEvent(target, (e) => {
|
||||
if(preloader.preloader.parentElement) {
|
||||
preloader.onClick(e);
|
||||
preloader.detach();
|
||||
} else {
|
||||
load();
|
||||
}
|
||||
}, {listenerSetter: this.listenerSetter});
|
||||
|
||||
load();
|
||||
|
||||
//console.log(doc);
|
||||
};
|
||||
|
||||
private saveToCache = (slug: string, url: string) => {
|
||||
fetch(url).then(response => {
|
||||
appDownloadManager.cacheStorage.save('backgrounds/' + slug, response);
|
||||
});
|
||||
};
|
||||
|
||||
private setBackgroundDocument = (slug: string, doc: MyDocument) => {
|
||||
let _tempId = ++this.tempId;
|
||||
const middleware = () => _tempId === this.tempId;
|
||||
|
||||
const download = appDocsManager.downloadDoc(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);
|
||||
|
||||
const deferred = deferredPromise<void>();
|
||||
deferred.addNotifyListener = download.addNotifyListener;
|
||||
deferred.cancel = download.cancel;
|
||||
|
||||
download.then(() => {
|
||||
if(!middleware()) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const background = this.theme.background;
|
||||
const onReady = (url: string) => {
|
||||
//const perf = performance.now();
|
||||
averageColor(url).then(pixel => {
|
||||
if(!middleware()) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
const hsla = highlightningColor(Array.from(pixel) as any);
|
||||
//console.log(doc, hsla, performance.now() - perf);
|
||||
|
||||
background.slug = slug;
|
||||
background.type = 'image';
|
||||
background.highlightningColor = hsla;
|
||||
appStateManager.pushToState('settings', rootScope.settings);
|
||||
|
||||
this.saveToCache(slug, url);
|
||||
appImManager.applyCurrentTheme(slug, url).then(deferred.resolve);
|
||||
});
|
||||
};
|
||||
|
||||
if(background.blur) {
|
||||
setTimeout(() => {
|
||||
blur(doc.url, 12, 4)
|
||||
.then(url => {
|
||||
if(!middleware()) {
|
||||
deferred.resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
onReady(url);
|
||||
});
|
||||
}, 200);
|
||||
} else {
|
||||
onReady(doc.url);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred;
|
||||
};
|
||||
|
||||
private setActive = () => {
|
||||
const active = this.grid.querySelector('.active');
|
||||
const background = rootScope.settings.themes.find(t => t.name === rootScope.settings.theme).background;
|
||||
const target = background.type === 'image' ? this.grid.querySelector(`.grid-item[data-slug="${background.slug}"]`) : null;
|
||||
if(active === target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(active) {
|
||||
active.classList.remove('active');
|
||||
}
|
||||
|
||||
if(target) {
|
||||
target.classList.add('active');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -120,3 +120,33 @@ export async function getFilesFromEvent(e: ClipboardEvent | DragEvent, onlyTypes
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
export function requestFile(accept?: string) {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'file';
|
||||
input.style.display = 'none';
|
||||
|
||||
if(accept) {
|
||||
input.accept = accept;
|
||||
}
|
||||
|
||||
document.body.append(input);
|
||||
|
||||
const promise = new Promise<File>((resolve, reject) => {
|
||||
input.addEventListener('change', (e: any) => {
|
||||
const file: File = e.target.files[0];
|
||||
if(!file) {
|
||||
reject('NO_FILE_SELECTED');
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(file);
|
||||
}, {once: true});
|
||||
}).finally(() => {
|
||||
input.remove();
|
||||
});
|
||||
|
||||
input.click();
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import DEBUG, { MOUNT_CLASS_TO } from '../../config/debug';
|
||||
const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day
|
||||
const STATE_VERSION = App.version;
|
||||
|
||||
type Background = {
|
||||
export type Background = {
|
||||
type: 'color' | 'image' | 'default',
|
||||
blur: boolean,
|
||||
highlightningColor?: string,
|
||||
@ -32,7 +32,7 @@ type Background = {
|
||||
slug?: string,
|
||||
};
|
||||
|
||||
type Theme = {
|
||||
export type Theme = {
|
||||
name: 'day' | 'night',
|
||||
background: Background
|
||||
};
|
||||
|
@ -1139,6 +1139,16 @@
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.media-photo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.preloader-container {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user