mirror of https://github.com/procxx/kepka.git
Don't unload all media on switching between chats.
This commit is contained in:
parent
959859f57c
commit
8e7117fa22
|
@ -405,24 +405,24 @@ void GifsListWidget::processHideFinished() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GifsListWidget::processPanelHideFinished() {
|
void GifsListWidget::processPanelHideFinished() {
|
||||||
auto itemForget = [](auto &item) {
|
const auto itemForget = [](const auto &item) {
|
||||||
if (auto document = item->getDocument()) {
|
if (const auto document = item->getDocument()) {
|
||||||
document->forget();
|
document->unload();
|
||||||
}
|
}
|
||||||
if (auto photo = item->getPhoto()) {
|
if (const auto photo = item->getPhoto()) {
|
||||||
photo->forget();
|
photo->unload();
|
||||||
}
|
}
|
||||||
if (auto result = item->getResult()) {
|
if (const auto result = item->getResult()) {
|
||||||
result->forget();
|
result->unload();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Preserve panel state through visibility toggles.
|
// Preserve panel state through visibility toggles.
|
||||||
//clearInlineRows(false);
|
//clearInlineRows(false);
|
||||||
for_const (auto &item, _gifLayouts) {
|
for (const auto &[document, layout] : _gifLayouts) {
|
||||||
itemForget(item.second);
|
itemForget(layout);
|
||||||
}
|
}
|
||||||
for_const (auto &item, _inlineLayouts) {
|
for (const auto &[document, layout] : _inlineLayouts) {
|
||||||
itemForget(item.second);
|
itemForget(layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ constexpr auto kMemoryForCache = 32 * 1024 * 1024;
|
||||||
Core::MediaActiveCache<DocumentData> &ActiveCache() {
|
Core::MediaActiveCache<DocumentData> &ActiveCache() {
|
||||||
static auto Instance = Core::MediaActiveCache<DocumentData>(
|
static auto Instance = Core::MediaActiveCache<DocumentData>(
|
||||||
kMemoryForCache,
|
kMemoryForCache,
|
||||||
[](DocumentData *document) { document->forget(); });
|
[](DocumentData *document) { document->unload(); });
|
||||||
return Instance;
|
return Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -536,7 +536,9 @@ bool DocumentData::saveToCache() const {
|
||||||
|| (isVoiceMessage() && size < Storage::kMaxVoiceInMemory);
|
|| (isVoiceMessage() && size < Storage::kMaxVoiceInMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DocumentData::forget() {
|
void DocumentData::unload() {
|
||||||
|
// Forget thumb only when image cache limit exceeds.
|
||||||
|
//thumb->unload();
|
||||||
if (sticker()) {
|
if (sticker()) {
|
||||||
if (!sticker()->img->isNull()) {
|
if (!sticker()->img->isNull()) {
|
||||||
ActiveCache().decrement(ComputeUsage(sticker()));
|
ActiveCache().decrement(ComputeUsage(sticker()));
|
||||||
|
@ -551,6 +553,7 @@ void DocumentData::forget() {
|
||||||
delete replyPreview.get();
|
delete replyPreview.get();
|
||||||
replyPreview = ImagePtr();
|
replyPreview = ImagePtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
ActiveCache().decrement(_data.size());
|
ActiveCache().decrement(_data.size());
|
||||||
_data.clear();
|
_data.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -121,7 +121,7 @@ public:
|
||||||
|
|
||||||
void performActionOnLoad();
|
void performActionOnLoad();
|
||||||
|
|
||||||
void forget();
|
void unload();
|
||||||
ImagePtr makeReplyPreview(Data::FileOrigin origin);
|
ImagePtr makeReplyPreview(Data::FileOrigin origin);
|
||||||
|
|
||||||
StickerData *sticker() const;
|
StickerData *sticker() const;
|
||||||
|
|
|
@ -30,11 +30,6 @@ struct GameData {
|
||||||
, document(document) {
|
, document(document) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void forget() {
|
|
||||||
if (document) document->forget();
|
|
||||||
if (photo) photo->forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
GameId id = 0;
|
GameId id = 0;
|
||||||
uint64 accessHash = 0;
|
uint64 accessHash = 0;
|
||||||
QString shortName;
|
QString shortName;
|
||||||
|
|
|
@ -103,15 +103,16 @@ bool PhotoData::uploading() const {
|
||||||
return (uploadingData != nullptr);
|
return (uploadingData != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhotoData::forget() {
|
void PhotoData::unload() {
|
||||||
thumb->forget();
|
// Forget thumb only when image cache limit exceeds.
|
||||||
|
//thumb->unload();
|
||||||
|
medium->unload();
|
||||||
|
full->unload();
|
||||||
if (!replyPreview->isNull()) {
|
if (!replyPreview->isNull()) {
|
||||||
// Should be std::unique_ptr<Image>.
|
// Should be std::unique_ptr<Image>.
|
||||||
delete replyPreview.get();
|
delete replyPreview.get();
|
||||||
replyPreview = ImagePtr();
|
replyPreview = ImagePtr();
|
||||||
}
|
}
|
||||||
medium->forget();
|
|
||||||
full->forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePtr PhotoData::makeReplyPreview(Data::FileOrigin origin) {
|
ImagePtr PhotoData::makeReplyPreview(Data::FileOrigin origin) {
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
void setWaitingForAlbum();
|
void setWaitingForAlbum();
|
||||||
bool waitingForAlbum() const;
|
bool waitingForAlbum() const;
|
||||||
|
|
||||||
void forget();
|
void unload();
|
||||||
ImagePtr makeReplyPreview(Data::FileOrigin origin);
|
ImagePtr makeReplyPreview(Data::FileOrigin origin);
|
||||||
|
|
||||||
MTPInputPhoto mtpInput() const;
|
MTPInputPhoto mtpInput() const;
|
||||||
|
|
|
@ -2008,18 +2008,6 @@ void Session::insertCheckedServiceNotification(
|
||||||
sendHistoryChangeNotifications();
|
sendHistoryChangeNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::forgetMedia() {
|
|
||||||
for (const auto &[id, photo] : _photos) {
|
|
||||||
photo->forget();
|
|
||||||
}
|
|
||||||
for (const auto &[id, document] : _documents) {
|
|
||||||
document->forget();
|
|
||||||
}
|
|
||||||
for (const auto &[coords, location] : _locations) {
|
|
||||||
location->thumb->forget();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::setMimeForwardIds(MessageIdsList &&list) {
|
void Session::setMimeForwardIds(MessageIdsList &&list) {
|
||||||
_mimeForwardIds = std::move(list);
|
_mimeForwardIds = std::move(list);
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,8 +420,6 @@ public:
|
||||||
const TextWithEntities &message,
|
const TextWithEntities &message,
|
||||||
const MTPMessageMedia &media = MTP_messageMediaEmpty());
|
const MTPMessageMedia &media = MTP_messageMediaEmpty());
|
||||||
|
|
||||||
void forgetMedia();
|
|
||||||
|
|
||||||
void setMimeForwardIds(MessageIdsList &&list);
|
void setMimeForwardIds(MessageIdsList &&list);
|
||||||
MessageIdsList takeMimeForwardIds();
|
MessageIdsList takeMimeForwardIds();
|
||||||
|
|
||||||
|
|
|
@ -54,11 +54,6 @@ struct WebPageData {
|
||||||
, pendingTill(pendingTill) {
|
, pendingTill(pendingTill) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void forget() {
|
|
||||||
if (document) document->forget();
|
|
||||||
if (photo) photo->forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool applyChanges(
|
bool applyChanges(
|
||||||
const QString &newType,
|
const QString &newType,
|
||||||
const QString &newUrl,
|
const QString &newUrl,
|
||||||
|
|
|
@ -2758,7 +2758,7 @@ void HistoryGif::stopAnimation() {
|
||||||
if (_gif) {
|
if (_gif) {
|
||||||
clearClipReader();
|
clearClipReader();
|
||||||
Auth().data().requestViewResize(_parent);
|
Auth().data().requestViewResize(_parent);
|
||||||
_data->forget();
|
_data->unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1922,7 +1922,6 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
|
||||||
_nonEmptySelection = false;
|
_nonEmptySelection = false;
|
||||||
|
|
||||||
if (_peer) {
|
if (_peer) {
|
||||||
Auth().data().forgetMedia();
|
|
||||||
Auth().downloader().clearPriorities();
|
Auth().downloader().clearPriorities();
|
||||||
|
|
||||||
_history = App::history(_peer);
|
_history = App::history(_peer);
|
||||||
|
|
|
@ -353,14 +353,14 @@ void Gif::clipCallback(Media::Clip::Notification notification) {
|
||||||
if (_gif) {
|
if (_gif) {
|
||||||
if (_gif->state() == State::Error) {
|
if (_gif->state() == State::Error) {
|
||||||
_gif.setBad();
|
_gif.setBad();
|
||||||
getShownDocument()->forget();
|
getShownDocument()->unload();
|
||||||
} else if (_gif->ready() && !_gif->started()) {
|
} else if (_gif->ready() && !_gif->started()) {
|
||||||
auto height = st::inlineMediaHeight;
|
auto height = st::inlineMediaHeight;
|
||||||
auto frame = countFrameSize();
|
auto frame = countFrameSize();
|
||||||
_gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, RectPart::None);
|
_gif->start(frame.width(), frame.height(), _width, height, ImageRoundRadius::None, RectPart::None);
|
||||||
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
|
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
|
||||||
_gif.reset();
|
_gif.reset();
|
||||||
getShownDocument()->forget();
|
getShownDocument()->unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1373,12 +1373,12 @@ void Game::clipCallback(Media::Clip::Notification notification) {
|
||||||
if (_gif) {
|
if (_gif) {
|
||||||
if (_gif->state() == State::Error) {
|
if (_gif->state() == State::Error) {
|
||||||
_gif.setBad();
|
_gif.setBad();
|
||||||
getResultDocument()->forget();
|
getResultDocument()->unload();
|
||||||
} else if (_gif->ready() && !_gif->started()) {
|
} else if (_gif->ready() && !_gif->started()) {
|
||||||
_gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None, RectPart::None);
|
_gif->start(_frameSize.width(), _frameSize.height(), st::inlineThumbSize, st::inlineThumbSize, ImageRoundRadius::None, RectPart::None);
|
||||||
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
|
} else if (_gif->autoPausedGif() && !context()->inlineItemVisible(this)) {
|
||||||
_gif.reset();
|
_gif.reset();
|
||||||
getResultDocument()->forget();
|
getResultDocument()->unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -279,13 +279,12 @@ bool Result::onChoose(Layout::ItemBase *layout) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Result::forget() {
|
void Result::unload() {
|
||||||
_thumb->forget();
|
|
||||||
if (_document) {
|
if (_document) {
|
||||||
_document->forget();
|
_document->unload();
|
||||||
}
|
}
|
||||||
if (_photo) {
|
if (_photo) {
|
||||||
_photo->forget();
|
_photo->unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ public:
|
||||||
// inline bot result. If it returns true you need to send this result.
|
// inline bot result. If it returns true you need to send this result.
|
||||||
bool onChoose(Layout::ItemBase *layout);
|
bool onChoose(Layout::ItemBase *layout);
|
||||||
|
|
||||||
void forget();
|
void unload();
|
||||||
void openFile();
|
void openFile();
|
||||||
void cancelFile();
|
void cancelFile();
|
||||||
|
|
||||||
|
|
|
@ -267,20 +267,20 @@ void Inner::clearSelection() {
|
||||||
|
|
||||||
void Inner::hideFinish(bool completely) {
|
void Inner::hideFinish(bool completely) {
|
||||||
if (completely) {
|
if (completely) {
|
||||||
auto itemForget = [](auto &item) {
|
const auto unload = [](const auto &item) {
|
||||||
if (auto document = item->getDocument()) {
|
if (const auto document = item->getDocument()) {
|
||||||
document->forget();
|
document->unload();
|
||||||
}
|
}
|
||||||
if (auto photo = item->getPhoto()) {
|
if (const auto photo = item->getPhoto()) {
|
||||||
photo->forget();
|
photo->unload();
|
||||||
}
|
}
|
||||||
if (auto result = item->getResult()) {
|
if (const auto result = item->getResult()) {
|
||||||
result->forget();
|
result->unload();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
clearInlineRows(false);
|
clearInlineRows(false);
|
||||||
for_const (auto &item, _inlineLayouts) {
|
for (const auto &[result, layout] : _inlineLayouts) {
|
||||||
itemForget(item.second);
|
unload(layout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2589,9 +2589,9 @@ void MediaView::preloadData(int delta) {
|
||||||
auto forgetIndex = *_index - delta * 2;
|
auto forgetIndex = *_index - delta * 2;
|
||||||
auto entity = entityByIndex(forgetIndex);
|
auto entity = entityByIndex(forgetIndex);
|
||||||
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
|
if (auto photo = base::get_if<not_null<PhotoData*>>(&entity.data)) {
|
||||||
(*photo)->forget();
|
(*photo)->unload();
|
||||||
} else if (auto document = base::get_if<not_null<DocumentData*>>(&entity.data)) {
|
} else if (auto document = base::get_if<not_null<DocumentData*>>(&entity.data)) {
|
||||||
(*document)->forget();
|
(*document)->unload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -342,7 +342,7 @@ void Photo::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
||||||
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||||
}
|
}
|
||||||
img.setDevicePixelRatio(cRetinaFactor());
|
img.setDevicePixelRatio(cRetinaFactor());
|
||||||
_data->forget();
|
_data->unload();
|
||||||
|
|
||||||
_pix = App::pixmapFromImageInPlace(std::move(img));
|
_pix = App::pixmapFromImageInPlace(std::move(img));
|
||||||
} else if (!_pix.isNull()) {
|
} else if (!_pix.isNull()) {
|
||||||
|
@ -426,7 +426,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
|
||||||
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
img = img.copy(0, (img.height() - img.width()) / 2, img.width(), img.width()).scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||||
}
|
}
|
||||||
img.setDevicePixelRatio(cRetinaFactor());
|
img.setDevicePixelRatio(cRetinaFactor());
|
||||||
_data->forget();
|
_data->unload();
|
||||||
|
|
||||||
_pix = App::pixmapFromImageInPlace(std::move(img));
|
_pix = App::pixmapFromImageInPlace(std::move(img));
|
||||||
} else if (!_pix.isNull()) {
|
} else if (!_pix.isNull()) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ int64 ComputeUsage(const QImage &image) {
|
||||||
Core::MediaActiveCache<const Image> &ActiveCache() {
|
Core::MediaActiveCache<const Image> &ActiveCache() {
|
||||||
static auto Instance = Core::MediaActiveCache<const Image>(
|
static auto Instance = Core::MediaActiveCache<const Image>(
|
||||||
kMemoryForCache,
|
kMemoryForCache,
|
||||||
[](const Image *image) { image->forget(); });
|
[](const Image *image) { image->unload(); });
|
||||||
return Instance;
|
return Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -769,9 +769,9 @@ void Image::checkSource() const {
|
||||||
ActiveCache().up(this);
|
ActiveCache().up(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::forget() const {
|
void Image::unload() const {
|
||||||
_source->takeLoaded();
|
_source->takeLoaded();
|
||||||
_source->forget();
|
_source->unload();
|
||||||
invalidateSizeCache();
|
invalidateSizeCache();
|
||||||
ActiveCache().decrement(ComputeUsage(_data));
|
ActiveCache().decrement(ComputeUsage(_data));
|
||||||
_data = QImage();
|
_data = QImage();
|
||||||
|
@ -800,6 +800,6 @@ void Image::invalidateSizeCache() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::~Image() {
|
Image::~Image() {
|
||||||
forget();
|
unload();
|
||||||
ActiveCache().remove(this);
|
ActiveCache().remove(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ public:
|
||||||
bool loadFirst,
|
bool loadFirst,
|
||||||
bool prior) = 0;
|
bool prior) = 0;
|
||||||
virtual QImage takeLoaded() = 0;
|
virtual QImage takeLoaded() = 0;
|
||||||
virtual void forget() = 0;
|
virtual void unload() = 0;
|
||||||
|
|
||||||
virtual void automaticLoad(
|
virtual void automaticLoad(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
|
@ -229,7 +229,7 @@ public:
|
||||||
|
|
||||||
bool loaded() const;
|
bool loaded() const;
|
||||||
bool isNull() const;
|
bool isNull() const;
|
||||||
void forget() const;
|
void unload() const;
|
||||||
void setDelayedStorageLocation(
|
void setDelayedStorageLocation(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
const StorageImageLocation &location);
|
const StorageImageLocation &location);
|
||||||
|
|
|
@ -37,7 +37,7 @@ QImage ImageSource::takeLoaded() {
|
||||||
return _data;
|
return _data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageSource::forget() {
|
void ImageSource::unload() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageSource::automaticLoad(
|
void ImageSource::automaticLoad(
|
||||||
|
@ -161,7 +161,7 @@ QImage LocalFileSource::takeLoaded() {
|
||||||
return std::move(_data);
|
return std::move(_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalFileSource::forget() {
|
void LocalFileSource::unload() {
|
||||||
_data = QImage();
|
_data = QImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,10 +361,6 @@ void RemoteSource::loadEvenCancelled(
|
||||||
return load(origin, loadFirst, prior);
|
return load(origin, loadFirst, prior);
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoteSource::~RemoteSource() {
|
|
||||||
forget();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RemoteSource::displayLoading() {
|
bool RemoteSource::displayLoading() {
|
||||||
return loaderValid()
|
return loaderValid()
|
||||||
&& (!_loader->loadingLocal() || !_loader->autoLoading());
|
&& (!_loader->loadingLocal() || !_loader->autoLoading());
|
||||||
|
@ -380,7 +376,7 @@ void RemoteSource::cancel() {
|
||||||
std::unique_ptr<FileLoader>(loader));
|
std::unique_ptr<FileLoader>(loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
void RemoteSource::forget() {
|
void RemoteSource::unload() {
|
||||||
if (loaderValid()) {
|
if (loaderValid()) {
|
||||||
destroyLoaderDelayed();
|
destroyLoaderDelayed();
|
||||||
}
|
}
|
||||||
|
@ -394,6 +390,10 @@ int RemoteSource::loadOffset() {
|
||||||
return loaderValid() ? _loader->currentOffset() : 0;
|
return loaderValid() ? _loader->currentOffset() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RemoteSource::~RemoteSource() {
|
||||||
|
unload();
|
||||||
|
}
|
||||||
|
|
||||||
const StorageImageLocation &RemoteSource::location() {
|
const StorageImageLocation &RemoteSource::location() {
|
||||||
return StorageImageLocation::Null;
|
return StorageImageLocation::Null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ public:
|
||||||
bool loadFirst,
|
bool loadFirst,
|
||||||
bool prior) override;
|
bool prior) override;
|
||||||
QImage takeLoaded() override;
|
QImage takeLoaded() override;
|
||||||
void forget() override;
|
void unload() override;
|
||||||
|
|
||||||
void automaticLoad(
|
void automaticLoad(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
|
@ -75,7 +75,7 @@ public:
|
||||||
bool loadFirst,
|
bool loadFirst,
|
||||||
bool prior) override;
|
bool prior) override;
|
||||||
QImage takeLoaded() override;
|
QImage takeLoaded() override;
|
||||||
void forget() override;
|
void unload() override;
|
||||||
|
|
||||||
void automaticLoad(
|
void automaticLoad(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
|
@ -126,7 +126,7 @@ public:
|
||||||
bool loadFirst,
|
bool loadFirst,
|
||||||
bool prior) override;
|
bool prior) override;
|
||||||
QImage takeLoaded() override;
|
QImage takeLoaded() override;
|
||||||
void forget() override;
|
void unload() override;
|
||||||
|
|
||||||
void automaticLoad(
|
void automaticLoad(
|
||||||
Data::FileOrigin origin,
|
Data::FileOrigin origin,
|
||||||
|
|
Loading…
Reference in New Issue