Browse Source

Fix loading lists in media viewer

master
morethanwords 3 years ago
parent
commit
9f168465b5
  1. 179
      src/components/appMediaViewer.ts
  2. 18
      src/lib/appManagers/appPhotosManager.ts
  3. 11
      src/lib/appManagers/appProfileManager.ts

179
src/components/appMediaViewer.ts

@ -76,6 +76,7 @@ type MediaQueueLoaderOptions<Item extends {}> = { @@ -76,6 +76,7 @@ type MediaQueueLoaderOptions<Item extends {}> = {
};
class MediaQueueLoader<Item extends {}> {
public target: Item = false as any;
public prevTargets: Item[] = [];
public nextTargets: Item[] = [];
@ -129,6 +130,10 @@ class MediaQueueLoader<Item extends {}> { @@ -129,6 +130,10 @@ class MediaQueueLoader<Item extends {}> {
}
const promise = this.getLoadPromise(older, anchor, loadCount).then(items => {
if((older && this.loadMediaPromiseDown !== promise) || (!older && this.loadMediaPromiseUp !== promise)) {
return;
}
if(items.length < loadCount) {
/* if(this.reverse) {
if(older) this.loadedAllMediaUp = true;
@ -169,7 +174,6 @@ class MediaQueueLoader<Item extends {}> { @@ -169,7 +174,6 @@ class MediaQueueLoader<Item extends {}> {
}
class MediaSearchQueueLoader<Item extends {mid: number, peerId: number}> extends MediaQueueLoader<Item> {
public currentMessageId = 0;
public searchContext: SearchSuperContext;
constructor(options: Omit<MediaQueueLoaderOptions<Item>, 'getLoadPromise'> = {}) {
@ -177,13 +181,14 @@ class MediaSearchQueueLoader<Item extends {mid: number, peerId: number}> extends @@ -177,13 +181,14 @@ class MediaSearchQueueLoader<Item extends {mid: number, peerId: number}> extends
...options,
getLoadPromise: (older, anchor, loadCount) => {
const backLimit = older ? 0 : loadCount;
let maxId = this.currentMessageId;
let maxId = this.target?.mid;
if(anchor) maxId = anchor.mid;
if(!older) maxId = appMessagesIdsManager.incrementMessageId(maxId, 1);
return appMessagesManager.getSearch({
...this.searchContext,
peerId: anchor?.peerId,
maxId,
limit: backLimit ? 0 : loadCount,
backLimit
@ -204,6 +209,40 @@ class MediaSearchQueueLoader<Item extends {mid: number, peerId: number}> extends @@ -204,6 +209,40 @@ class MediaSearchQueueLoader<Item extends {mid: number, peerId: number}> extends
public setSearchContext(context: SearchSuperContext) {
this.searchContext = context;
if(this.searchContext.folderId !== undefined) {
this.loadedAllMediaUp = true;
if(this.searchContext.nextRate === undefined) {
this.loadedAllMediaDown = true;
}
}
}
}
class MediaAvatarQueueLoader<Item extends {photoId: string}> extends MediaQueueLoader<Item> {
private peerId: number;
constructor(options: Omit<MediaQueueLoaderOptions<Item>, 'getLoadPromise'> & {peerId: number}) {
super({
...options,
getLoadPromise: (older, anchor, loadCount) => {
if(this.peerId < 0) return Promise.resolve([]); // ! это значит, что открыло аватар чата, но следующих фотографий нет.
return appPhotosManager.getUserPhotos(this.peerId, anchor?.photoId, loadCount).then(value => {
const idx = value.photos.indexOf(this.target.photoId);
if(idx !== -1) {
value.photos.splice(idx, 1);
}
return value.photos.map(photoId => {
return {element: null as HTMLElement, photoId} as any;
});
});
}
});
this.peerId = options.peerId;
}
}
@ -220,7 +259,6 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -220,7 +259,6 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
protected preloader: ProgressivePreloader = null;
protected preloaderStreamable: ProgressivePreloader = null;
protected target: TargetType = null;
protected prevTargets: TargetType[] = [];
protected nextTargets: TargetType[] = [];
//protected targetContainer: HTMLElement = null;
@ -229,10 +267,6 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -229,10 +267,6 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
protected log: ReturnType<typeof logger>;
protected isFirstOpen = true;
protected loadMediaPromiseUp: Promise<void> = null;
protected loadMediaPromiseDown: Promise<void> = null;
protected loadedAllMediaUp = false;
protected loadedAllMediaDown = false;
protected reverse = false; // reverse means next = higher msgid
protected needLoadMore = true;
@ -249,7 +283,6 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -249,7 +283,6 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
protected onDownloadClick: (e: MouseEvent) => void;
protected onPrevClick: (target: TargetType) => void;
protected onNextClick: (target: TargetType) => void;
protected loadMoreMedia: (older: boolean) => Promise<void>;
protected videoPlayer: VideoPlayer;
@ -268,7 +301,16 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -268,7 +301,16 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
protected ctrlKeyDown: boolean;
constructor(topButtons: Array<keyof AppMediaViewerBase<ContentAdditionType, ButtonsAdditionType, TargetType>['buttons']>) {
get target() {
return this.queueLoader.target;
}
set target(value) {
this.queueLoader.target = value;
}
constructor(protected queueLoader: MediaQueueLoader<TargetType>,
topButtons: Array<keyof AppMediaViewerBase<ContentAdditionType, ButtonsAdditionType, TargetType>['buttons']>) {
this.log = logger('AMV');
this.preloader = new ProgressivePreloader();
this.preloaderStreamable = new ProgressivePreloader({
@ -564,13 +606,12 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -564,13 +606,12 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
const promise = this.setMoverToTarget(this.target?.element, true).then(({onAnimationEnd}) => onAnimationEnd);
this.target = null;
this.prevTargets = [];
this.nextTargets = [];
this.loadedAllMediaUp = this.loadedAllMediaDown = false;
this.loadMediaPromiseUp = this.loadMediaPromiseDown = null;
this.target = false as any;
this.prevTargets.length = 0;
this.nextTargets.length = 0;
this.setMoverPromise = null;
this.tempId = -1;
(window as any).appMediaViewer = undefined;
if(this.zoomSwipeHandler) {
this.zoomSwipeHandler.removeListeners();
@ -1331,6 +1372,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -1331,6 +1372,8 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
this.reverse = reverse;
this.needLoadMore = needLoadMore;
this.isFirstOpen = false;
this.queueLoader.setTargets(this.prevTargets, this.nextTargets, this.reverse);
(window as any).appMediaViewer = this;
//this.loadMore = loadMore;
/* if(appSidebarRight.historyTabIDs.slice(-1)[0] === AppSidebarRight.SLIDERITEMSIDS.forward) {
@ -1358,11 +1401,11 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType @@ -1358,11 +1401,11 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
if(this.needLoadMore) {
if(this.nextTargets.length < 20) {
this.loadMoreMedia(!this.reverse);
this.queueLoader.loadMoreMedia(!this.reverse);
}
if(this.prevTargets.length < 20) {
this.loadMoreMedia(this.reverse);
this.queueLoader.loadMoreMedia(this.reverse);
}
}
@ -1702,23 +1745,16 @@ type AppMediaViewerTargetType = { @@ -1702,23 +1745,16 @@ type AppMediaViewerTargetType = {
peerId: number
};
export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delete' | 'forward', AppMediaViewerTargetType> {
protected currentMessageId = 0;
protected currentPeerId = 0;
protected searchContext: SearchSuperContext;
protected btnMenuDelete: HTMLElement;
protected queueLoader: MediaSearchQueueLoader<AppMediaViewerTargetType>;
constructor() {
super(['delete', 'forward']);
/* const stub = document.createElement('div');
stub.classList.add(MEDIA_VIEWER_CLASSNAME + '-stub');
this.content.main.prepend(stub); */
get searchContext() {
return this.queueLoader.searchContext;
}
this.queueLoader = new MediaSearchQueueLoader({
prevTargets: this.prevTargets,
nextTargets: this.nextTargets,
constructor() {
super(new MediaSearchQueueLoader({
generateItem: (item) => {
const isForDocument = this.searchContext.inputFilter._ === 'inputMessagesFilterDocument';
const {mid, peerId} = item;
@ -1732,7 +1768,11 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet @@ -1732,7 +1768,11 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
return {element: null as HTMLElement, mid, peerId};
}
});
}), ['delete', 'forward']);
/* const stub = document.createElement('div');
stub.classList.add(MEDIA_VIEWER_CLASSNAME + '-stub');
this.content.main.prepend(stub); */
this.content.caption = document.createElement('div');
this.content.caption.classList.add(MEDIA_VIEWER_CLASSNAME + '-caption'/* , 'media-viewer-stub' */);
@ -1837,17 +1877,19 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet @@ -1837,17 +1877,19 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
};
onDeleteClick = () => {
new PopupDeleteMessages(this.currentPeerId, [this.currentMessageId], 'chat', () => {
const target = this.target;
new PopupDeleteMessages(target.peerId, [target.mid], 'chat', () => {
this.target = {element: this.content.media} as any;
this.close();
});
};
onForwardClick = () => {
if(this.currentMessageId) {
//appSidebarRight.forwardTab.open([this.currentMessageId]);
const target = this.target;
if(target.mid) {
//appSidebarRight.forwardTab.open([target.mid]);
new PopupForward({
[this.currentPeerId]: [this.currentMessageId]
[target.peerId]: [target.mid]
}, () => {
return this.close();
});
@ -1855,9 +1897,8 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet @@ -1855,9 +1897,8 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
};
onAuthorClick = (e: MouseEvent) => {
if(this.currentMessageId && this.currentMessageId !== Number.MAX_SAFE_INTEGER) {
const mid = this.currentMessageId;
const peerId = this.currentPeerId;
const {mid, peerId} = this.target;
if(mid && mid !== Number.MAX_SAFE_INTEGER) {
const threadId = this.searchContext.threadId;
this.close(e)
//.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())
@ -1876,7 +1917,8 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet @@ -1876,7 +1917,8 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
};
onDownloadClick = () => {
const message = appMessagesManager.getMessageByPeer(this.currentPeerId, this.currentMessageId);
const {peerId, mid} = this.target;
const message = appMessagesManager.getMessageByPeer(peerId, mid);
if(message.media.photo) {
appPhotosManager.savePhotoFile(message.media.photo, appImManager.chat.bubbles.lazyLoadQueue.queueId);
} else {
@ -1892,11 +1934,6 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet @@ -1892,11 +1934,6 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
}
};
// нет смысла делать проверку для reverse и loadMediaPromise
protected loadMoreMedia = (older = true) => {
return this.queueLoader.loadMoreMedia(older);
};
private setCaption(message: Message.message) {
const caption = message.message;
let html = '';
@ -1913,15 +1950,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet @@ -1913,15 +1950,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
}
public setSearchContext(context: SearchSuperContext) {
this.searchContext = context;
if(this.searchContext.folderId !== undefined) {
this.loadedAllMediaUp = true;
if(this.searchContext.nextRate === undefined) {
this.loadedAllMediaDown = true;
}
}
this.queueLoader.setSearchContext(context);
return this;
}
@ -1941,8 +1970,6 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet @@ -1941,8 +1970,6 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
button.classList.toggle('hide', !canDeleteMessage);
});
this.currentMessageId = mid;
this.currentPeerId = message.peerId;
this.setCaption(message);
const promise = super._openMedia(media, message.date, fromId, fromRight, target, reverse, prevTargets, nextTargets, needLoadMore);
this.target.mid = mid;
@ -1958,11 +1985,10 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet @@ -1958,11 +1985,10 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
type AppMediaViewerAvatarTargetType = {element: HTMLElement, photoId: string};
export class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMediaViewerAvatarTargetType> {
public currentPhotoId: string;
public peerId: number;
constructor(peerId: number) {
super([/* 'delete' */]);
super(new MediaAvatarQueueLoader({peerId}), [/* 'delete' */]);
this.peerId = peerId;
@ -1990,54 +2016,13 @@ export class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMe @@ -1990,54 +2016,13 @@ export class AppMediaViewerAvatar extends AppMediaViewerBase<'', 'delete', AppMe
};
onDownloadClick = () => {
appPhotosManager.savePhotoFile(appPhotosManager.getPhoto(this.currentPhotoId), appImManager.chat.bubbles.lazyLoadQueue.queueId);
};
protected loadMoreMedia = (older = true) => {
if(this.peerId < 0) return Promise.resolve(); // ! это значит, что открыло аватар чата, но следующих фотографий нет.
if(this.loadedAllMediaDown) return Promise.resolve();
if(this.loadMediaPromiseDown) return this.loadMediaPromiseDown;
const peerId = this.peerId;
const loadCount = 50;
const maxId = this.nextTargets.length ? this.nextTargets[this.nextTargets.length - 1].photoId : this.currentPhotoId;
const promise = appPhotosManager.getUserPhotos(peerId, maxId, loadCount).then(value => {
if(this.peerId !== peerId) {
this.log.warn('peer changed');
return;
}
// if(DEBUG) {
// this.log('loaded more media by maxId:', /* maxId, */value, older, this.reverse);
// }
if(value.photos.length < loadCount) {
this.loadedAllMediaDown = true;
}
value.photos.forEach(photoId => {
if(this.currentPhotoId === photoId) return;
this.nextTargets.push({element: null as HTMLElement, photoId: photoId});
});
this.buttons.prev.classList.toggle('hide', !this.prevTargets.length);
this.buttons.next.classList.toggle('hide', !this.nextTargets.length);
}, () => {}).then(() => {
this.loadMediaPromiseDown = null;
});
return this.loadMediaPromiseDown = promise;
appPhotosManager.savePhotoFile(appPhotosManager.getPhoto(this.target.photoId), appImManager.chat.bubbles.lazyLoadQueue.queueId);
};
public async openMedia(photoId: string, target?: HTMLElement, fromRight = 0, prevTargets?: AppMediaViewerAvatarTargetType[], nextTargets?: AppMediaViewerAvatarTargetType[]) {
if(this.setMoverPromise) return this.setMoverPromise;
const photo = appPhotosManager.getPhoto(photoId);
this.currentPhotoId = photo.id;
const ret = super._openMedia(photo, photo.date, this.peerId, fromRight, target, false, prevTargets, nextTargets);
this.target.photoId = photo.id;

18
src/lib/appManagers/appPhotosManager.ts

@ -15,7 +15,7 @@ import { CancellablePromise } from "../../helpers/cancellablePromise"; @@ -15,7 +15,7 @@ import { CancellablePromise } from "../../helpers/cancellablePromise";
import { getFileNameByLocation } from "../../helpers/fileName";
import { safeReplaceArrayInObject, isObject } from "../../helpers/object";
import { isSafari } from "../../helpers/userAgent";
import { InputFileLocation, InputMedia, Photo, PhotoSize, PhotosPhotos } from "../../layer";
import { InputFileLocation, InputMedia, InputPhoto, Photo, PhotoSize, PhotosPhotos } from "../../layer";
import apiManager from "../mtproto/mtprotoworker";
import referenceDatabase, { ReferenceContext } from "../mtproto/referenceDatabase";
import { MyDocument } from "./appDocsManager";
@ -383,15 +383,19 @@ export class AppPhotosManager { @@ -383,15 +383,19 @@ export class AppPhotosManager {
return isObject(photoId) ? photoId as MyPhoto : this.photos[photoId as any as string];
}
public getInput(photo: MyPhoto): InputPhoto.inputPhoto {
return {
_: 'inputPhoto',
id: photo.id,
access_hash: photo.access_hash,
file_reference: photo.file_reference
};
}
public getMediaInput(photo: MyPhoto): InputMedia.inputMediaPhoto {
return {
_: 'inputMediaPhoto',
id: {
_: 'inputPhoto',
id: photo.id,
access_hash: photo.access_hash,
file_reference: photo.file_reference
},
id: this.getInput(photo),
ttl_seconds: 0
};
}

11
src/lib/appManagers/appProfileManager.ts

@ -488,6 +488,17 @@ export class AppProfileManager { @@ -488,6 +488,17 @@ export class AppProfileManager {
});
}
public deletePhotos(photoIds: string[]) {
return apiManager.invokeApiSingle('photos.deletePhotos', {
id: photoIds.map(photoId => {
const photo = appPhotosManager.getPhoto(photoId);
return appPhotosManager.getInput(photo);
})
}).then((deletedList) => {
});
}
public getChatMembersString(id: number) {
const chat: Chat = appChatsManager.getChat(id);
if(chat._ === 'chatForbidden') {

Loading…
Cancel
Save