269 lines
7.2 KiB
C++
269 lines
7.2 KiB
C++
/*
|
|
This file is part of Telegram Desktop,
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
For license and copyright information please follow this link:
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
*/
|
|
#include "data/components/recent_shared_media_gifts.h"
|
|
|
|
#include "api/api_credits.h" // InputSavedStarGiftId
|
|
#include "api/api_premium.h"
|
|
#include "apiwrap.h"
|
|
#include "chat_helpers/compose/compose_show.h"
|
|
#include "data/data_document.h"
|
|
#include "data/data_peer.h"
|
|
#include "data/data_session.h"
|
|
#include "data/data_user.h"
|
|
#include "lang/lang_keys.h"
|
|
#include "main/main_app_config.h"
|
|
#include "main/main_session.h"
|
|
#include "ui/text/text_utilities.h"
|
|
#include "ui/toast/toast.h"
|
|
|
|
namespace Data {
|
|
namespace {
|
|
|
|
constexpr auto kReloadThreshold = 60 * crl::time(1000);
|
|
constexpr auto kMaxGifts = 3;
|
|
constexpr auto kMaxPinnedGifts = 6;
|
|
|
|
} // namespace
|
|
|
|
RecentSharedMediaGifts::RecentSharedMediaGifts(
|
|
not_null<Main::Session*> session)
|
|
: _session(session) {
|
|
}
|
|
|
|
RecentSharedMediaGifts::~RecentSharedMediaGifts() = default;
|
|
|
|
std::vector<Data::SavedStarGift> RecentSharedMediaGifts::filterGifts(
|
|
const std::deque<Data::SavedStarGift> &gifts,
|
|
bool onlyPinnedToTop) {
|
|
auto result = std::vector<Data::SavedStarGift>();
|
|
const auto maxCount = onlyPinnedToTop ? kMaxPinnedGifts : kMaxGifts;
|
|
for (const auto &gift : gifts) {
|
|
if (!onlyPinnedToTop || gift.pinned) {
|
|
result.push_back(gift);
|
|
if (result.size() >= maxCount) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void RecentSharedMediaGifts::request(
|
|
not_null<PeerData*> peer,
|
|
Fn<void(std::vector<SavedStarGift>)> done,
|
|
bool onlyPinnedToTop) {
|
|
const auto it = _recent.find(peer->id);
|
|
if (it != _recent.end()) {
|
|
auto &entry = it->second;
|
|
if (entry.lastRequestTime
|
|
&& entry.lastRequestTime + kReloadThreshold > crl::now()) {
|
|
done(filterGifts(entry.gifts, onlyPinnedToTop));
|
|
return;
|
|
}
|
|
if (entry.requestId) {
|
|
entry.pendingCallbacks.push_back([=] {
|
|
const auto it = _recent.find(peer->id);
|
|
if (it != _recent.end()) {
|
|
done(filterGifts(it->second.gifts, onlyPinnedToTop));
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
|
|
_recent[peer->id].requestId = peer->session().api().request(
|
|
MTPpayments_GetSavedStarGifts(
|
|
MTP_flags(0),
|
|
peer->input(),
|
|
MTP_int(0), // collection_id
|
|
MTP_string(QString()),
|
|
MTP_int(kMaxPinnedGifts)
|
|
)).done([=](const MTPpayments_SavedStarGifts &result) {
|
|
const auto &data = result.data();
|
|
const auto owner = &peer->owner();
|
|
owner->processUsers(data.vusers());
|
|
owner->processChats(data.vchats());
|
|
auto &entry = _recent[peer->id];
|
|
entry.lastRequestTime = crl::now();
|
|
entry.requestId = 0;
|
|
entry.gifts.clear();
|
|
|
|
for (const auto &gift : data.vgifts().v) {
|
|
if (auto parsed = Api::FromTL(peer, gift)) {
|
|
entry.gifts.push_back(std::move(*parsed));
|
|
}
|
|
}
|
|
|
|
done(filterGifts(entry.gifts, onlyPinnedToTop));
|
|
for (const auto &callback : entry.pendingCallbacks) {
|
|
callback();
|
|
}
|
|
entry.pendingCallbacks.clear();
|
|
}).send();
|
|
}
|
|
|
|
void RecentSharedMediaGifts::clearLastRequestTime(
|
|
not_null<PeerData*> peer) {
|
|
const auto it = _recent.find(peer->id);
|
|
if (it != _recent.end()) {
|
|
it->second.lastRequestTime = 0;
|
|
}
|
|
}
|
|
|
|
void RecentSharedMediaGifts::updatePinnedOrder(
|
|
std::shared_ptr<ChatHelpers::Show> show,
|
|
not_null<PeerData*> peer,
|
|
const std::vector<SavedStarGift> &gifts,
|
|
const std::vector<Data::SavedStarGiftId> &manageIds,
|
|
Fn<void()> done) {
|
|
auto inputs = QVector<MTPInputSavedStarGift>();
|
|
inputs.reserve(manageIds.size());
|
|
for (const auto &id : manageIds) {
|
|
inputs.push_back(Api::InputSavedStarGiftId(id));
|
|
}
|
|
|
|
_session->api().request(MTPpayments_ToggleStarGiftsPinnedToTop(
|
|
peer->input(),
|
|
MTP_vector<MTPInputSavedStarGift>(std::move(inputs))
|
|
)).done([=] {
|
|
auto result = std::deque<SavedStarGift>();
|
|
for (const auto &id : manageIds) {
|
|
for (const auto &gift : gifts) {
|
|
if (gift.manageId == id) {
|
|
result.push_back(gift);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
_recent[peer->id].gifts = std::move(result);
|
|
if (done) {
|
|
done();
|
|
}
|
|
}).fail([=](const MTP::Error &error) {
|
|
show->showToast(error.type());
|
|
}).send();
|
|
}
|
|
|
|
void RecentSharedMediaGifts::togglePinned(
|
|
std::shared_ptr<ChatHelpers::Show> show,
|
|
not_null<PeerData*> peer,
|
|
const Data::SavedStarGiftId &manageId,
|
|
bool pinned,
|
|
std::shared_ptr<Data::UniqueGift> uniqueData,
|
|
std::shared_ptr<Data::UniqueGift> replacingData) {
|
|
const auto performToggle = [=](const std::vector<SavedStarGift> &gifts) {
|
|
const auto limit = _session->appConfig().pinnedGiftsLimit();
|
|
auto manageIds = std::vector<Data::SavedStarGiftId>();
|
|
|
|
if (pinned) {
|
|
for (const auto &gift : gifts) {
|
|
if (gift.pinned && gift.manageId != manageId) {
|
|
manageIds.push_back(gift.manageId);
|
|
if (manageIds.size() >= limit - 1) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
manageIds.push_back(manageId);
|
|
} else {
|
|
for (const auto &gift : gifts) {
|
|
if (gift.pinned && gift.manageId != manageId) {
|
|
manageIds.push_back(gift.manageId);
|
|
}
|
|
}
|
|
}
|
|
|
|
const auto updateLocal = [=] {
|
|
using GiftAction = Data::GiftUpdate::Action;
|
|
_session->data().notifyGiftUpdate({
|
|
.id = manageId,
|
|
.action = (pinned ? GiftAction::Pin : GiftAction::Unpin),
|
|
});
|
|
if (pinned) {
|
|
show->showToast({
|
|
.title = (uniqueData
|
|
? tr::lng_gift_pinned_done_title(
|
|
tr::now,
|
|
lt_gift,
|
|
Data::UniqueGiftName(*uniqueData))
|
|
: QString()),
|
|
.text = (replacingData
|
|
? tr::lng_gift_pinned_done_replaced(
|
|
tr::now,
|
|
lt_gift,
|
|
TextWithEntities{
|
|
Data::UniqueGiftName(*replacingData),
|
|
},
|
|
tr::marked)
|
|
: tr::lng_gift_pinned_done(
|
|
tr::now,
|
|
tr::marked)),
|
|
.duration = Ui::Toast::kDefaultDuration * 2,
|
|
});
|
|
}
|
|
};
|
|
|
|
if (!pinned) {
|
|
updatePinnedOrder(show, peer, gifts, manageIds, updateLocal);
|
|
} else {
|
|
_session->api().request(MTPpayments_GetSavedStarGift(
|
|
MTP_vector<MTPInputSavedStarGift>(
|
|
1,
|
|
Api::InputSavedStarGiftId(manageId))
|
|
)).done([=](const MTPpayments_SavedStarGifts &result) {
|
|
const auto &tlGift = result.data().vgifts().v.front();
|
|
if (auto parsed = Api::FromTL(peer, tlGift)) {
|
|
auto updatedGifts = std::vector<SavedStarGift>();
|
|
for (const auto &gift : gifts) {
|
|
if (gift.pinned && gift.manageId != manageId) {
|
|
updatedGifts.push_back(gift);
|
|
}
|
|
}
|
|
parsed->pinned = true;
|
|
updatedGifts.push_back(*parsed);
|
|
updatePinnedOrder(
|
|
show,
|
|
peer,
|
|
updatedGifts,
|
|
manageIds,
|
|
updateLocal);
|
|
}
|
|
}).send();
|
|
}
|
|
};
|
|
|
|
request(peer, performToggle, true);
|
|
}
|
|
|
|
void RecentSharedMediaGifts::reorderPinned(
|
|
std::shared_ptr<ChatHelpers::Show> show,
|
|
not_null<PeerData*> peer,
|
|
int oldPosition,
|
|
int newPosition) {
|
|
const auto performReorder = [=](const std::vector<SavedStarGift> &gifts) {
|
|
if (oldPosition < 0 || oldPosition >= gifts.size()
|
|
|| newPosition < 0 || newPosition >= gifts.size()
|
|
|| oldPosition == newPosition) {
|
|
return;
|
|
}
|
|
|
|
auto manageIds = std::vector<Data::SavedStarGiftId>();
|
|
manageIds.reserve(gifts.size());
|
|
for (const auto &gift : gifts) {
|
|
manageIds.push_back(gift.manageId);
|
|
}
|
|
base::reorder(manageIds, oldPosition, newPosition);
|
|
|
|
updatePinnedOrder(show, peer, gifts, manageIds, nullptr);
|
|
};
|
|
|
|
request(peer, performReorder, true);
|
|
}
|
|
|
|
} // namespace Data
|