mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-14 13:17:08 +02:00
Show first paid media in transactions history.
This commit is contained in:
parent
57254ca259
commit
1399d2501d
8 changed files with 200 additions and 40 deletions
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "apiwrap.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_peer.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -28,9 +29,40 @@ constexpr auto kTransactionsLimit = 100;
|
|||
const MTPStarsTransaction &tl,
|
||||
not_null<PeerData*> peer) {
|
||||
using HistoryPeerTL = MTPDstarsTransactionPeer;
|
||||
using namespace Data;
|
||||
const auto owner = &peer->owner();
|
||||
const auto photo = tl.data().vphoto()
|
||||
? peer->owner().photoFromWeb(*tl.data().vphoto(), ImageLocation())
|
||||
? owner->photoFromWeb(*tl.data().vphoto(), ImageLocation())
|
||||
: nullptr;
|
||||
auto extended = std::vector<CreditsHistoryEntry::Media>();
|
||||
if (const auto list = tl.data().vextended_media()) {
|
||||
extended.reserve(list->v.size());
|
||||
for (const auto &media : list->v) {
|
||||
media.match([&](const MTPDmessageMediaPhoto &photo) {
|
||||
if (const auto inner = photo.vphoto()) {
|
||||
const auto photo = owner->processPhoto(*inner);
|
||||
if (!photo->isNull()) {
|
||||
extended.push_back(CreditsHistoryEntry::Media{
|
||||
.type = CreditsHistoryEntry::MediaType::Photo,
|
||||
.mediaId = photo->id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDmessageMediaDocument &document) {
|
||||
if (const auto inner = document.vdocument()) {
|
||||
const auto document = owner->processDocument(*inner);
|
||||
if (document->isAnimation()
|
||||
|| document->isVideoFile()
|
||||
|| document->isGifv()) {
|
||||
extended.push_back(CreditsHistoryEntry::Media{
|
||||
.type = CreditsHistoryEntry::MediaType::Video,
|
||||
.mediaId = document->id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [&](const auto &) {});
|
||||
}
|
||||
}
|
||||
const auto barePeerId = tl.data().vpeer().match([](
|
||||
const HistoryPeerTL &p) {
|
||||
return peerFromMTP(p.vpeer());
|
||||
|
@ -53,6 +85,7 @@ constexpr auto kTransactionsLimit = 100;
|
|||
.description = qs(tl.data().vdescription().value_or_empty()),
|
||||
.date = base::unixtime::parse(tl.data().vdate().v),
|
||||
.photoId = photo ? photo->id : 0,
|
||||
.extended = std::move(extended),
|
||||
.credits = tl.data().vstars().v,
|
||||
.bareMsgId = uint64(tl.data().vmsg_id().value_or_empty()),
|
||||
.barePeerId = barePeerId,
|
||||
|
|
|
@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "storage/storage_media_prepare.h"
|
||||
#include "iv/iv_instance.h"
|
||||
#include "mainwidget.h"
|
||||
#include "main/main_app_config.h"
|
||||
#include "main/main_session.h"
|
||||
#include "main/main_session_settings.h"
|
||||
#include "mtproto/mtproto_config.h"
|
||||
|
@ -64,7 +65,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace {
|
||||
|
||||
constexpr auto kMaxMessageLength = 4096;
|
||||
constexpr auto kMaxPrice = 1000ULL;
|
||||
|
||||
using Ui::SendFilesWay;
|
||||
|
||||
|
@ -125,6 +125,9 @@ void EditPriceBox(
|
|||
0,
|
||||
st::defaultSubsectionTitlePadding.right(),
|
||||
0)));
|
||||
const auto limit = session->appConfig().get<int>(
|
||||
u"stars_paid_post_amount_max"_q,
|
||||
10'000);
|
||||
const auto wrap = box->addRow(object_ptr<Ui::FixedHeightWidget>(
|
||||
box,
|
||||
st::editTagField.heightMin));
|
||||
|
@ -133,7 +136,7 @@ void EditPriceBox(
|
|||
st::editTagField,
|
||||
tr::lng_paid_cost_placeholder(),
|
||||
price ? QString::number(price) : QString(),
|
||||
kMaxPrice);
|
||||
limit);
|
||||
const auto field = owned.data();
|
||||
wrap->widthValue() | rpl::start_with_next([=](int width) {
|
||||
field->move(0, 0);
|
||||
|
@ -167,7 +170,7 @@ void EditPriceBox(
|
|||
|
||||
const auto save = [=] {
|
||||
const auto now = field->getLastText().toULongLong();
|
||||
if (now > kMaxPrice) {
|
||||
if (now > limit) {
|
||||
field->showError();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -30,11 +30,21 @@ struct CreditsHistoryEntry final {
|
|||
PremiumBot,
|
||||
Ads,
|
||||
};
|
||||
enum class MediaType {
|
||||
Photo,
|
||||
Video,
|
||||
};
|
||||
struct Media {
|
||||
MediaType type = MediaType::Photo;
|
||||
uint64 mediaId = 0;
|
||||
};
|
||||
|
||||
QString id;
|
||||
QString title;
|
||||
QString description;
|
||||
QDateTime date;
|
||||
PhotoId photoId = 0;
|
||||
std::vector<Media> extended;
|
||||
uint64 credits = 0;
|
||||
uint64 bareMsgId = 0;
|
||||
uint64 barePeerId = 0;
|
||||
|
|
|
@ -756,20 +756,24 @@ private:
|
|||
QString _name;
|
||||
|
||||
Ui::Text::String _rightText;
|
||||
|
||||
base::has_weak_ptr _guard;
|
||||
};
|
||||
|
||||
CreditsRow::CreditsRow(not_null<PeerData*> peer, const Descriptor &descriptor)
|
||||
CreditsRow::CreditsRow(
|
||||
not_null<PeerData*> peer,
|
||||
const Descriptor &descriptor)
|
||||
: PeerListRow(peer, UniqueRowIdFromEntry(descriptor.entry))
|
||||
, _entry(descriptor.entry)
|
||||
, _creditIcon(descriptor.creditIcon)
|
||||
, _rowHeight(descriptor.rowHeight) {
|
||||
const auto photo = _entry.photoId
|
||||
? peer->session().data().photo(_entry.photoId).get()
|
||||
: nullptr;
|
||||
if (photo) {
|
||||
_paintUserpicCallback = Ui::GenerateCreditsPaintEntryCallback(
|
||||
photo,
|
||||
[this, update = descriptor.updateCallback] { update(this); });
|
||||
const auto callback = Ui::PaintPreviewCallback(
|
||||
&peer->session(),
|
||||
_entry);
|
||||
if (callback) {
|
||||
_paintUserpicCallback = callback(crl::guard(&_guard, [this, update = descriptor.updateCallback] {
|
||||
update(this);
|
||||
}));
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/gift_premium_box.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "core/ui_integration.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "core/click_handler_types.h" // UrlClickHandler
|
||||
#include "data/data_photo_media.h"
|
||||
|
@ -350,18 +351,16 @@ void ReceiptCreditsBox(
|
|||
using Type = Data::CreditsHistoryEntry::PeerType;
|
||||
|
||||
const auto &stUser = st::boostReplaceUserpic;
|
||||
const auto session = &controller->session();
|
||||
const auto peer = (e.peerType == Type::PremiumBot)
|
||||
? premiumBot
|
||||
: e.barePeerId
|
||||
? controller->session().data().peer(PeerId(e.barePeerId)).get()
|
||||
? session->data().peer(PeerId(e.barePeerId)).get()
|
||||
: nullptr;
|
||||
const auto photo = e.photoId
|
||||
? controller->session().data().photo(e.photoId).get()
|
||||
: nullptr;
|
||||
if (photo) {
|
||||
if (const auto callback = Ui::PaintPreviewCallback(session, e)) {
|
||||
content->add(object_ptr<Ui::CenterWrap<>>(
|
||||
content,
|
||||
HistoryEntryPhoto(content, photo, stUser.photoSize)));
|
||||
GenericEntryPhoto(content, callback, stUser.photoSize)));
|
||||
} else if (peer) {
|
||||
content->add(object_ptr<Ui::CenterWrap<>>(
|
||||
content,
|
||||
|
@ -539,18 +538,16 @@ void ReceiptCreditsBox(
|
|||
}, button->lifetime());
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> HistoryEntryPhoto(
|
||||
object_ptr<Ui::RpWidget> GenericEntryPhoto(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<PhotoData*> photo,
|
||||
Fn<Fn<void(Painter &, int, int, int, int)>(Fn<void()>)> callback,
|
||||
int photoSize) {
|
||||
auto owned = object_ptr<Ui::RpWidget>(parent);
|
||||
const auto widget = owned.data();
|
||||
widget->resize(Size(photoSize));
|
||||
|
||||
const auto draw = Ui::GenerateCreditsPaintEntryCallback(
|
||||
photo,
|
||||
[=] { widget->update(); });
|
||||
|
||||
const auto draw = callback(
|
||||
crl::guard(widget, [=] { widget->update(); }));
|
||||
widget->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto p = Painter(widget);
|
||||
|
@ -560,25 +557,40 @@ object_ptr<Ui::RpWidget> HistoryEntryPhoto(
|
|||
return owned;
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> HistoryEntryPhoto(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<PhotoData*> photo,
|
||||
int photoSize) {
|
||||
return GenericEntryPhoto(
|
||||
parent,
|
||||
[=](Fn<void()> update) {
|
||||
return Ui::GenerateCreditsPaintEntryCallback(photo, update);
|
||||
},
|
||||
photoSize);
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> HistoryEntryVideo(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<DocumentData*> video,
|
||||
int photoSize) {
|
||||
return GenericEntryPhoto(
|
||||
parent,
|
||||
[=](Fn<void()> update) {
|
||||
return Ui::GenerateCreditsPaintEntryCallback(video, update);
|
||||
},
|
||||
photoSize);
|
||||
}
|
||||
|
||||
object_ptr<Ui::RpWidget> PaidMediaPhoto(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<PhotoData*> photo,
|
||||
int photoSize) {
|
||||
auto owned = object_ptr<Ui::RpWidget>(parent);
|
||||
const auto widget = owned.data();
|
||||
widget->resize(Size(photoSize));
|
||||
|
||||
const auto draw = Ui::GeneratePaidMediaPaintCallback(
|
||||
photo,
|
||||
[=] { widget->update(); });
|
||||
|
||||
widget->paintRequest(
|
||||
) | rpl::start_with_next([=] {
|
||||
auto p = Painter(widget);
|
||||
draw(p, 0, 0, photoSize, photoSize);
|
||||
}, widget->lifetime());
|
||||
|
||||
return owned;
|
||||
return GenericEntryPhoto(
|
||||
parent,
|
||||
[=](Fn<void()> update) {
|
||||
return Ui::GeneratePaidMediaPaintCallback(photo, update);
|
||||
},
|
||||
photoSize);
|
||||
}
|
||||
|
||||
void SmallBalanceBox(
|
||||
|
|
|
@ -55,11 +55,21 @@ void ReceiptCreditsBox(
|
|||
PeerData *premiumBot,
|
||||
const Data::CreditsHistoryEntry &e);
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> GenericEntryPhoto(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
Fn<Fn<void(Painter &, int, int, int, int)>(Fn<void()> update)> callback,
|
||||
int photoSize);
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> HistoryEntryPhoto(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<PhotoData*> photo,
|
||||
int photoSize);
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> HistoryEntryVideo(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<DocumentData*> video,
|
||||
int photoSize);
|
||||
|
||||
[[nodiscard]] object_ptr<Ui::RpWidget> PaidMediaPhoto(
|
||||
not_null<Ui::RpWidget*> parent,
|
||||
not_null<PhotoData*> photo,
|
||||
|
|
|
@ -11,6 +11,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "data/data_credits.h"
|
||||
#include "data/data_file_origin.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_document_media.h"
|
||||
#include "data/data_photo.h"
|
||||
#include "data/data_photo_media.h"
|
||||
#include "data/data_session.h"
|
||||
|
@ -232,7 +234,53 @@ Fn<void(Painter &, int, int, int, int)> GenerateCreditsPaintEntryCallback(
|
|||
minSize,
|
||||
minSize),
|
||||
size * style::DevicePixelRatio(),
|
||||
{ .options = Images::Option::RoundCircle });
|
||||
{ .options = Images::Option::RoundLarge });
|
||||
}
|
||||
p.drawImage(x, y, state->image);
|
||||
};
|
||||
}
|
||||
|
||||
Fn<void(Painter &, int, int, int, int)> GenerateCreditsPaintEntryCallback(
|
||||
not_null<DocumentData*> video,
|
||||
Fn<void()> update) {
|
||||
struct State {
|
||||
std::shared_ptr<Data::DocumentMedia> view;
|
||||
Image *imagePtr = nullptr;
|
||||
QImage image;
|
||||
rpl::lifetime downloadLifetime;
|
||||
bool entryImageLoaded = false;
|
||||
};
|
||||
const auto state = std::make_shared<State>();
|
||||
state->view = video->createMediaView();
|
||||
video->loadThumbnail({});
|
||||
|
||||
rpl::single(rpl::empty_value()) | rpl::then(
|
||||
video->owner().session().downloaderTaskFinished()
|
||||
) | rpl::start_with_next([=] {
|
||||
using Size = Data::PhotoSize;
|
||||
if (const auto thumbnail = state->view->thumbnail()) {
|
||||
state->imagePtr = thumbnail;
|
||||
}
|
||||
update();
|
||||
if (state->imagePtr) {
|
||||
state->entryImageLoaded = true;
|
||||
state->downloadLifetime.destroy();
|
||||
}
|
||||
}, state->downloadLifetime);
|
||||
|
||||
return [=](Painter &p, int x, int y, int outerWidth, int size) {
|
||||
if (state->imagePtr
|
||||
&& (!state->entryImageLoaded || state->image.isNull())) {
|
||||
const auto image = state->imagePtr->original();
|
||||
const auto minSize = std::min(image.width(), image.height());
|
||||
state->image = Images::Prepare(
|
||||
image.copy(
|
||||
(image.width() - minSize) / 2,
|
||||
(image.height() - minSize) / 2,
|
||||
minSize,
|
||||
minSize),
|
||||
size * style::DevicePixelRatio(),
|
||||
{ .options = Images::Option::RoundLarge });
|
||||
}
|
||||
p.drawImage(x, y, state->image);
|
||||
};
|
||||
|
@ -282,6 +330,33 @@ Fn<void(Painter &, int, int, int, int)> GeneratePaidMediaPaintCallback(
|
|||
};
|
||||
}
|
||||
|
||||
Fn<Fn<void(Painter&, int, int, int, int)>(Fn<void()>)> PaintPreviewCallback(
|
||||
not_null<Main::Session*> session,
|
||||
const Data::CreditsHistoryEntry &entry) {
|
||||
using MediaType = Data::CreditsHistoryEntry::MediaType;
|
||||
const auto &extended = entry.extended;
|
||||
const auto owner = &session->data();
|
||||
const auto photo = entry.photoId
|
||||
? owner->photo(entry.photoId).get()
|
||||
: (!extended.empty() && extended.front().type == MediaType::Photo)
|
||||
? owner->photo(extended.front().mediaId).get()
|
||||
: nullptr;
|
||||
const auto video = (!extended.empty()
|
||||
&& extended.front().type == MediaType::Video)
|
||||
? owner->document(extended.front().mediaId).get()
|
||||
: nullptr;
|
||||
if (photo) {
|
||||
return [=](Fn<void()> update) {
|
||||
return Ui::GenerateCreditsPaintEntryCallback(photo, update);
|
||||
};
|
||||
} else if (video) {
|
||||
return [=](Fn<void()> update) {
|
||||
return Ui::GenerateCreditsPaintEntryCallback(video, update);
|
||||
};
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TextWithEntities GenerateEntryName(const Data::CreditsHistoryEntry &entry) {
|
||||
return ((entry.peerType == Data::CreditsHistoryEntry::PeerType::Fragment)
|
||||
? tr::lng_bot_username_description1_link
|
||||
|
|
|
@ -8,11 +8,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#pragma once
|
||||
|
||||
class PhotoData;
|
||||
class DocumentData;
|
||||
|
||||
namespace Data {
|
||||
struct CreditsHistoryEntry;
|
||||
} // namespace Data
|
||||
|
||||
namespace Main {
|
||||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace Ui {
|
||||
class MaskedInputField;
|
||||
class RpWidget;
|
||||
|
@ -38,10 +43,18 @@ Fn<void(Painter &, int, int, int, int)> GenerateCreditsPaintEntryCallback(
|
|||
not_null<PhotoData*> photo,
|
||||
Fn<void()> update);
|
||||
|
||||
Fn<void(Painter &, int, int, int, int)> GenerateCreditsPaintEntryCallback(
|
||||
not_null<DocumentData*> video,
|
||||
Fn<void()> update);
|
||||
|
||||
Fn<void(Painter &, int, int, int, int)> GeneratePaidMediaPaintCallback(
|
||||
not_null<PhotoData*> photo,
|
||||
Fn<void()> update);
|
||||
|
||||
Fn<Fn<void(Painter&, int, int, int, int)>(Fn<void()>)> PaintPreviewCallback(
|
||||
not_null<Main::Session*> session,
|
||||
const Data::CreditsHistoryEntry &entry);
|
||||
|
||||
[[nodiscard]] TextWithEntities GenerateEntryName(
|
||||
const Data::CreditsHistoryEntry &entry);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue