mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-06 23:24:01 +02:00
Play premium video avatars in chats list.
This commit is contained in:
parent
5478a8c014
commit
201edb2e69
19 changed files with 657 additions and 253 deletions
|
@ -544,6 +544,8 @@ PRIVATE
|
||||||
dialogs/ui/dialogs_layout.h
|
dialogs/ui/dialogs_layout.h
|
||||||
dialogs/ui/dialogs_message_view.cpp
|
dialogs/ui/dialogs_message_view.cpp
|
||||||
dialogs/ui/dialogs_message_view.h
|
dialogs/ui/dialogs_message_view.h
|
||||||
|
dialogs/ui/dialogs_video_userpic.cpp
|
||||||
|
dialogs/ui/dialogs_video_userpic.h
|
||||||
editor/color_picker.cpp
|
editor/color_picker.cpp
|
||||||
editor/color_picker.h
|
editor/color_picker.h
|
||||||
editor/controllers/controllers.h
|
editor/controllers/controllers.h
|
||||||
|
|
|
@ -92,7 +92,10 @@ ChannelData::ChannelData(not_null<Data::Session*> owner, PeerId id)
|
||||||
|
|
||||||
void ChannelData::setPhoto(const MTPChatPhoto &photo) {
|
void ChannelData::setPhoto(const MTPChatPhoto &photo) {
|
||||||
photo.match([&](const MTPDchatPhoto & data) {
|
photo.match([&](const MTPDchatPhoto & data) {
|
||||||
updateUserpic(data.vphoto_id().v, data.vdc_id().v);
|
updateUserpic(
|
||||||
|
data.vphoto_id().v,
|
||||||
|
data.vdc_id().v,
|
||||||
|
data.is_has_video());
|
||||||
}, [&](const MTPDchatPhotoEmpty &) {
|
}, [&](const MTPDchatPhotoEmpty &) {
|
||||||
clearUserpic();
|
clearUserpic();
|
||||||
});
|
});
|
||||||
|
|
|
@ -39,7 +39,10 @@ ChatData::ChatData(not_null<Data::Session*> owner, PeerId id)
|
||||||
|
|
||||||
void ChatData::setPhoto(const MTPChatPhoto &photo) {
|
void ChatData::setPhoto(const MTPChatPhoto &photo) {
|
||||||
photo.match([&](const MTPDchatPhoto &data) {
|
photo.match([&](const MTPDchatPhoto &data) {
|
||||||
updateUserpic(data.vphoto_id().v, data.vdc_id().v);
|
updateUserpic(
|
||||||
|
data.vphoto_id().v,
|
||||||
|
data.vdc_id().v,
|
||||||
|
data.is_has_video());
|
||||||
}, [&](const MTPDchatPhotoEmpty &) {
|
}, [&](const MTPDchatPhotoEmpty &) {
|
||||||
clearUserpic();
|
clearUserpic();
|
||||||
});
|
});
|
||||||
|
|
|
@ -307,8 +307,12 @@ ClickHandlerPtr PeerData::createOpenLink() {
|
||||||
return std::make_shared<PeerClickHandler>(this);
|
return std::make_shared<PeerClickHandler>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerData::setUserpic(PhotoId photoId, const ImageLocation &location) {
|
void PeerData::setUserpic(
|
||||||
|
PhotoId photoId,
|
||||||
|
const ImageLocation &location,
|
||||||
|
bool hasVideo) {
|
||||||
_userpicPhotoId = photoId;
|
_userpicPhotoId = photoId;
|
||||||
|
_userpicHasVideo = hasVideo;
|
||||||
_userpic.set(&session(), ImageWithLocation{ .location = location });
|
_userpic.set(&session(), ImageWithLocation{ .location = location });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -479,7 +483,10 @@ Data::FileOrigin PeerData::userpicPhotoOrigin() const {
|
||||||
: Data::FileOrigin();
|
: Data::FileOrigin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerData::updateUserpic(PhotoId photoId, MTP::DcId dcId) {
|
void PeerData::updateUserpic(
|
||||||
|
PhotoId photoId,
|
||||||
|
MTP::DcId dcId,
|
||||||
|
bool hasVideo) {
|
||||||
setUserpicChecked(
|
setUserpicChecked(
|
||||||
photoId,
|
photoId,
|
||||||
ImageLocation(
|
ImageLocation(
|
||||||
|
@ -491,19 +498,27 @@ void PeerData::updateUserpic(PhotoId photoId, MTP::DcId dcId) {
|
||||||
input,
|
input,
|
||||||
MTP_long(photoId))) },
|
MTP_long(photoId))) },
|
||||||
kUserpicSize,
|
kUserpicSize,
|
||||||
kUserpicSize));
|
kUserpicSize),
|
||||||
|
hasVideo);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerData::clearUserpic() {
|
void PeerData::clearUserpic() {
|
||||||
setUserpicChecked(PhotoId(), ImageLocation());
|
setUserpicChecked(PhotoId(), ImageLocation(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PeerData::setUserpicChecked(
|
void PeerData::setUserpicChecked(
|
||||||
PhotoId photoId,
|
PhotoId photoId,
|
||||||
const ImageLocation &location) {
|
const ImageLocation &location,
|
||||||
if (_userpicPhotoId != photoId || _userpic.location() != location) {
|
bool hasVideo) {
|
||||||
setUserpic(photoId, location);
|
if (_userpicPhotoId != photoId
|
||||||
|
|| _userpic.location() != location
|
||||||
|
|| _userpicHasVideo != hasVideo) {
|
||||||
|
const auto known = !userpicPhotoUnknown();
|
||||||
|
setUserpic(photoId, location, hasVideo);
|
||||||
session().changes().peerUpdated(this, UpdateFlag::Photo);
|
session().changes().peerUpdated(this, UpdateFlag::Photo);
|
||||||
|
if (known && isPremium() && userpicPhotoUnknown()) {
|
||||||
|
updateFull();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,6 +864,13 @@ bool PeerData::isVerified() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PeerData::isPremium() const {
|
||||||
|
if (const auto user = asUser()) {
|
||||||
|
return user->isPremium();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool PeerData::isScam() const {
|
bool PeerData::isScam() const {
|
||||||
if (const auto user = asUser()) {
|
if (const auto user = asUser()) {
|
||||||
return user->isScam();
|
return user->isScam();
|
||||||
|
|
|
@ -172,6 +172,7 @@ public:
|
||||||
}
|
}
|
||||||
[[nodiscard]] bool isSelf() const;
|
[[nodiscard]] bool isSelf() const;
|
||||||
[[nodiscard]] bool isVerified() const;
|
[[nodiscard]] bool isVerified() const;
|
||||||
|
[[nodiscard]] bool isPremium() const;
|
||||||
[[nodiscard]] bool isScam() const;
|
[[nodiscard]] bool isScam() const;
|
||||||
[[nodiscard]] bool isFake() const;
|
[[nodiscard]] bool isFake() const;
|
||||||
[[nodiscard]] bool isMegagroup() const;
|
[[nodiscard]] bool isMegagroup() const;
|
||||||
|
@ -266,7 +267,10 @@ public:
|
||||||
return _nameFirstLetters;
|
return _nameFirstLetters;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUserpic(PhotoId photoId, const ImageLocation &location);
|
void setUserpic(
|
||||||
|
PhotoId photoId,
|
||||||
|
const ImageLocation &location,
|
||||||
|
bool hasVideo);
|
||||||
void setUserpicPhoto(const MTPPhoto &data);
|
void setUserpicPhoto(const MTPPhoto &data);
|
||||||
void paintUserpic(
|
void paintUserpic(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
|
@ -320,6 +324,9 @@ public:
|
||||||
[[nodiscard]] PhotoId userpicPhotoId() const {
|
[[nodiscard]] PhotoId userpicPhotoId() const {
|
||||||
return userpicPhotoUnknown() ? 0 : _userpicPhotoId;
|
return userpicPhotoUnknown() ? 0 : _userpicPhotoId;
|
||||||
}
|
}
|
||||||
|
[[nodiscard]] bool userpicHasVideo() const {
|
||||||
|
return _userpicHasVideo;
|
||||||
|
}
|
||||||
[[nodiscard]] Data::FileOrigin userpicOrigin() const;
|
[[nodiscard]] Data::FileOrigin userpicOrigin() const;
|
||||||
[[nodiscard]] Data::FileOrigin userpicPhotoOrigin() const;
|
[[nodiscard]] Data::FileOrigin userpicPhotoOrigin() const;
|
||||||
|
|
||||||
|
@ -426,7 +433,7 @@ protected:
|
||||||
const QString &newName,
|
const QString &newName,
|
||||||
const QString &newNameOrPhone,
|
const QString &newNameOrPhone,
|
||||||
const QString &newUsername);
|
const QString &newUsername);
|
||||||
void updateUserpic(PhotoId photoId, MTP::DcId dcId);
|
void updateUserpic(PhotoId photoId, MTP::DcId dcId, bool hasVideo);
|
||||||
void clearUserpic();
|
void clearUserpic();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -435,12 +442,17 @@ private:
|
||||||
[[nodiscard]] virtual auto unavailableReasons() const
|
[[nodiscard]] virtual auto unavailableReasons() const
|
||||||
-> const std::vector<Data::UnavailableReason> &;
|
-> const std::vector<Data::UnavailableReason> &;
|
||||||
|
|
||||||
void setUserpicChecked(PhotoId photoId, const ImageLocation &location);
|
void setUserpicChecked(
|
||||||
|
PhotoId photoId,
|
||||||
|
const ImageLocation &location,
|
||||||
|
bool hasVideo);
|
||||||
|
|
||||||
const not_null<Data::Session*> _owner;
|
const not_null<Data::Session*> _owner;
|
||||||
|
|
||||||
mutable Data::CloudImage _userpic;
|
mutable Data::CloudImage _userpic;
|
||||||
PhotoId _userpicPhotoId = kUnknownPhotoId;
|
PhotoId _userpicPhotoId = kUnknownPhotoId;
|
||||||
|
bool _userpicHasVideo = false;
|
||||||
|
|
||||||
mutable std::unique_ptr<Ui::EmptyUserpic> _userpicEmpty;
|
mutable std::unique_ptr<Ui::EmptyUserpic> _userpicEmpty;
|
||||||
Ui::Text::String _nameText;
|
Ui::Text::String _nameText;
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,10 @@ void UserData::setIsContact(bool is) {
|
||||||
// see Serialize::readPeer as well
|
// see Serialize::readPeer as well
|
||||||
void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
|
void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
|
||||||
photo.match([&](const MTPDuserProfilePhoto &data) {
|
photo.match([&](const MTPDuserProfilePhoto &data) {
|
||||||
updateUserpic(data.vphoto_id().v, data.vdc_id().v);
|
updateUserpic(
|
||||||
|
data.vphoto_id().v,
|
||||||
|
data.vdc_id().v,
|
||||||
|
data.is_has_video());
|
||||||
}, [&](const MTPDuserProfilePhotoEmpty &) {
|
}, [&](const MTPDuserProfilePhotoEmpty &) {
|
||||||
clearUserpic();
|
clearUserpic();
|
||||||
});
|
});
|
||||||
|
@ -191,6 +194,75 @@ void UserData::removeFlags(UserDataFlags which) {
|
||||||
_flags.remove(which & ~UserDataFlag::Self);
|
_flags.remove(which & ~UserDataFlag::Self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UserData::isVerified() const {
|
||||||
|
return flags() & UserDataFlag::Verified;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::isScam() const {
|
||||||
|
return flags() & UserDataFlag::Scam;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::isFake() const {
|
||||||
|
return flags() & UserDataFlag::Fake;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::isPremium() const {
|
||||||
|
return flags() & UserDataFlag::Premium;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::isBotInlineGeo() const {
|
||||||
|
return flags() & UserDataFlag::BotInlineGeo;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::isBot() const {
|
||||||
|
return botInfo != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::isSupport() const {
|
||||||
|
return flags() & UserDataFlag::Support;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::isInaccessible() const {
|
||||||
|
return flags() & UserDataFlag::Deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::canWrite() const {
|
||||||
|
// Duplicated in Data::CanWriteValue().
|
||||||
|
return !isInaccessible() && !isRepliesChat();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::applyMinPhoto() const {
|
||||||
|
return !(flags() & UserDataFlag::DiscardMinPhoto);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::canAddContact() const {
|
||||||
|
return canShareThisContact() && !isContact();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::canShareThisContactFast() const {
|
||||||
|
return !_phone.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString &UserData::phone() const {
|
||||||
|
return _phone;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserData::ContactStatus UserData::contactStatus() const {
|
||||||
|
return _contactStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UserData::isContact() const {
|
||||||
|
return (contactStatus() == ContactStatus::Contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserData::CallsStatus UserData::callsStatus() const {
|
||||||
|
return _callsStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UserData::commonChatsCount() const {
|
||||||
|
return _commonChatsCount;
|
||||||
|
}
|
||||||
|
|
||||||
void UserData::setCallsStatus(CallsStatus callsStatus) {
|
void UserData::setCallsStatus(CallsStatus callsStatus) {
|
||||||
if (callsStatus != _callsStatus) {
|
if (callsStatus != _callsStatus) {
|
||||||
_callsStatus = callsStatus;
|
_callsStatus = callsStatus;
|
||||||
|
|
|
@ -88,58 +88,31 @@ public:
|
||||||
void addFlags(UserDataFlags which);
|
void addFlags(UserDataFlags which);
|
||||||
void removeFlags(UserDataFlags which);
|
void removeFlags(UserDataFlags which);
|
||||||
|
|
||||||
[[nodiscard]] bool isVerified() const {
|
[[nodiscard]] bool isVerified() const;
|
||||||
return flags() & UserDataFlag::Verified;
|
[[nodiscard]] bool isScam() const;
|
||||||
}
|
[[nodiscard]] bool isFake() const;
|
||||||
[[nodiscard]] bool isScam() const {
|
[[nodiscard]] bool isPremium() const;
|
||||||
return flags() & UserDataFlag::Scam;
|
[[nodiscard]] bool isBotInlineGeo() const;
|
||||||
}
|
[[nodiscard]] bool isBot() const;
|
||||||
[[nodiscard]] bool isFake() const {
|
[[nodiscard]] bool isSupport() const;
|
||||||
return flags() & UserDataFlag::Fake;
|
[[nodiscard]] bool isInaccessible() const;
|
||||||
}
|
[[nodiscard]] bool canWrite() const;
|
||||||
[[nodiscard]] bool isPremium() const {
|
[[nodiscard]] bool applyMinPhoto() const;
|
||||||
return flags() & UserDataFlag::Premium;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool isBotInlineGeo() const {
|
|
||||||
return flags() & UserDataFlag::BotInlineGeo;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool isBot() const {
|
|
||||||
return botInfo != nullptr;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool isSupport() const {
|
|
||||||
return flags() & UserDataFlag::Support;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool isInaccessible() const {
|
|
||||||
return flags() & UserDataFlag::Deleted;
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool canWrite() const {
|
|
||||||
// Duplicated in Data::CanWriteValue().
|
|
||||||
return !isInaccessible() && !isRepliesChat();
|
|
||||||
}
|
|
||||||
[[nodiscard]] bool applyMinPhoto() const {
|
|
||||||
return !(flags() & UserDataFlag::DiscardMinPhoto);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool canShareThisContact() const;
|
[[nodiscard]] bool canShareThisContact() const;
|
||||||
[[nodiscard]] bool canAddContact() const {
|
[[nodiscard]] bool canAddContact() const;
|
||||||
return canShareThisContact() && !isContact();
|
|
||||||
}
|
|
||||||
|
|
||||||
// In Data::Session::processUsers() we check only that.
|
// In Data::Session::processUsers() we check only that.
|
||||||
// When actually trying to share contact we perform
|
// When actually trying to share contact we perform
|
||||||
// a full check by canShareThisContact() call.
|
// a full check by canShareThisContact() call.
|
||||||
[[nodiscard]] bool canShareThisContactFast() const {
|
[[nodiscard]] bool canShareThisContactFast() const;
|
||||||
return !_phone.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
MTPInputUser inputUser = MTP_inputUserEmpty();
|
MTPInputUser inputUser = MTP_inputUserEmpty();
|
||||||
|
|
||||||
QString firstName;
|
QString firstName;
|
||||||
QString lastName;
|
QString lastName;
|
||||||
QString username;
|
QString username;
|
||||||
[[nodiscard]] const QString &phone() const {
|
[[nodiscard]] const QString &phone() const;
|
||||||
return _phone;
|
|
||||||
}
|
|
||||||
QString nameOrPhone;
|
QString nameOrPhone;
|
||||||
Ui::Text::String phoneText;
|
Ui::Text::String phoneText;
|
||||||
TimeId onlineTill = 0;
|
TimeId onlineTill = 0;
|
||||||
|
@ -149,12 +122,8 @@ public:
|
||||||
Contact,
|
Contact,
|
||||||
NotContact,
|
NotContact,
|
||||||
};
|
};
|
||||||
[[nodiscard]] ContactStatus contactStatus() const {
|
[[nodiscard]] ContactStatus contactStatus() const;
|
||||||
return _contactStatus;
|
[[nodiscard]] bool isContact() const;
|
||||||
}
|
|
||||||
[[nodiscard]] bool isContact() const {
|
|
||||||
return (contactStatus() == ContactStatus::Contact);
|
|
||||||
}
|
|
||||||
void setIsContact(bool is);
|
void setIsContact(bool is);
|
||||||
|
|
||||||
enum class CallsStatus : char {
|
enum class CallsStatus : char {
|
||||||
|
@ -163,9 +132,7 @@ public:
|
||||||
Disabled,
|
Disabled,
|
||||||
Private,
|
Private,
|
||||||
};
|
};
|
||||||
CallsStatus callsStatus() const {
|
CallsStatus callsStatus() const;
|
||||||
return _callsStatus;
|
|
||||||
}
|
|
||||||
bool hasCalls() const;
|
bool hasCalls() const;
|
||||||
void setCallsStatus(CallsStatus callsStatus);
|
void setCallsStatus(CallsStatus callsStatus);
|
||||||
|
|
||||||
|
@ -174,9 +141,7 @@ public:
|
||||||
void setUnavailableReasons(
|
void setUnavailableReasons(
|
||||||
std::vector<Data::UnavailableReason> &&reasons);
|
std::vector<Data::UnavailableReason> &&reasons);
|
||||||
|
|
||||||
int commonChatsCount() const {
|
int commonChatsCount() const;
|
||||||
return _commonChatsCount;
|
|
||||||
}
|
|
||||||
void setCommonChatsCount(int count);
|
void setCommonChatsCount(int count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "dialogs/dialogs_indexed_list.h"
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
#include "dialogs/ui/dialogs_layout.h"
|
#include "dialogs/ui/dialogs_layout.h"
|
||||||
|
#include "dialogs/ui/dialogs_video_userpic.h"
|
||||||
#include "dialogs/dialogs_widget.h"
|
#include "dialogs/dialogs_widget.h"
|
||||||
#include "dialogs/dialogs_search_from_controllers.h"
|
#include "dialogs/dialogs_search_from_controllers.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -218,9 +219,21 @@ InnerWidget::InnerWidget(
|
||||||
UpdateFlag::Name
|
UpdateFlag::Name
|
||||||
| UpdateFlag::Photo
|
| UpdateFlag::Photo
|
||||||
| UpdateFlag::IsContact
|
| UpdateFlag::IsContact
|
||||||
|
| UpdateFlag::FullInfo
|
||||||
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
||||||
if (update.flags & (UpdateFlag::Name | UpdateFlag::Photo)) {
|
if (update.flags
|
||||||
|
& (UpdateFlag::Name
|
||||||
|
| UpdateFlag::Photo
|
||||||
|
| UpdateFlag::FullInfo)) {
|
||||||
|
const auto peer = update.peer;
|
||||||
|
const auto history = peer->owner().historyLoaded(peer);
|
||||||
|
if (_state == WidgetState::Default) {
|
||||||
|
if (history) {
|
||||||
|
updateDialogRow({ history, FullMsgId() });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
this->update();
|
this->update();
|
||||||
|
}
|
||||||
_updated.fire({});
|
_updated.fire({});
|
||||||
}
|
}
|
||||||
if (update.flags & UpdateFlag::IsContact) {
|
if (update.flags & UpdateFlag::IsContact) {
|
||||||
|
@ -425,11 +438,13 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
if (xadd || yadd) {
|
if (xadd || yadd) {
|
||||||
p.translate(xadd, yadd);
|
p.translate(xadd, yadd);
|
||||||
}
|
}
|
||||||
const auto isActive = (row->key() == active);
|
const auto key = row->key();
|
||||||
const auto isSelected = (row->key() == selected);
|
const auto isActive = (key == active);
|
||||||
|
const auto isSelected = (key == selected);
|
||||||
Ui::RowPainter::paint(
|
Ui::RowPainter::paint(
|
||||||
p,
|
p,
|
||||||
row,
|
row,
|
||||||
|
validateVideoUserpic(row),
|
||||||
_filterId,
|
_filterId,
|
||||||
fullWidth,
|
fullWidth,
|
||||||
isActive,
|
isActive,
|
||||||
|
@ -548,6 +563,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
Ui::RowPainter::paint(
|
Ui::RowPainter::paint(
|
||||||
p,
|
p,
|
||||||
_filterResults[from],
|
_filterResults[from],
|
||||||
|
validateVideoUserpic(row),
|
||||||
_filterId,
|
_filterId,
|
||||||
fullWidth,
|
fullWidth,
|
||||||
active,
|
active,
|
||||||
|
@ -652,6 +668,34 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ui::VideoUserpic *InnerWidget::validateVideoUserpic(not_null<Row*> row) {
|
||||||
|
const auto history = row->history();
|
||||||
|
return history ? validateVideoUserpic(history) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ui::VideoUserpic *InnerWidget::validateVideoUserpic(
|
||||||
|
not_null<History*> history) {
|
||||||
|
const auto peer = history->peer;
|
||||||
|
if (!peer->isPremium()
|
||||||
|
|| peer->userpicPhotoUnknown()
|
||||||
|
|| !peer->userpicHasVideo()) {
|
||||||
|
_videoUserpics.remove(peer);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const auto i = _videoUserpics.find(peer);
|
||||||
|
if (i != end(_videoUserpics)) {
|
||||||
|
return i->second.get();
|
||||||
|
}
|
||||||
|
const auto update = [=] {
|
||||||
|
updateDialogRow({ history, FullMsgId() });
|
||||||
|
updateSearchResult(history->peer);
|
||||||
|
};
|
||||||
|
return _videoUserpics.emplace(peer, std::make_unique<Ui::VideoUserpic>(
|
||||||
|
peer,
|
||||||
|
update
|
||||||
|
)).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
void InnerWidget::paintCollapsedRows(Painter &p, QRect clip) const {
|
void InnerWidget::paintCollapsedRows(Painter &p, QRect clip) const {
|
||||||
auto index = 0;
|
auto index = 0;
|
||||||
const auto rowHeight = st::dialogsImportantBarHeight;
|
const auto rowHeight = st::dialogsImportantBarHeight;
|
||||||
|
@ -1528,15 +1572,18 @@ void InnerWidget::refreshDialogRow(RowDescriptor row) {
|
||||||
|
|
||||||
void InnerWidget::updateSearchResult(not_null<PeerData*> peer) {
|
void InnerWidget::updateSearchResult(not_null<PeerData*> peer) {
|
||||||
if (_state == WidgetState::Filtered) {
|
if (_state == WidgetState::Filtered) {
|
||||||
if (!_peerSearchResults.empty()) {
|
const auto i = ranges::find(
|
||||||
auto index = 0, add = peerSearchOffset();
|
_peerSearchResults,
|
||||||
for (const auto &result : _peerSearchResults) {
|
peer,
|
||||||
if (result->peer == peer) {
|
&PeerSearchResult::peer);
|
||||||
rtlupdate(0, add + index * st::dialogsRowHeight, width(), st::dialogsRowHeight);
|
if (i != end(_peerSearchResults)) {
|
||||||
break;
|
const auto top = peerSearchOffset();
|
||||||
}
|
const auto index = (i - begin(_peerSearchResults));
|
||||||
++index;
|
rtlupdate(
|
||||||
}
|
0,
|
||||||
|
top + index * st::dialogsRowHeight,
|
||||||
|
width(),
|
||||||
|
st::dialogsRowHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1968,11 +2015,13 @@ void InnerWidget::visibleTopBottomUpdated(
|
||||||
_visibleTop = visibleTop;
|
_visibleTop = visibleTop;
|
||||||
_visibleBottom = visibleBottom;
|
_visibleBottom = visibleBottom;
|
||||||
loadPeerPhotos();
|
loadPeerPhotos();
|
||||||
if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop) >= height()) {
|
if (_visibleTop + PreloadHeightsCount * (_visibleBottom - _visibleTop)
|
||||||
|
>= height()) {
|
||||||
if (_loadMoreCallback) {
|
if (_loadMoreCallback) {
|
||||||
_loadMoreCallback();
|
_loadMoreCallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::itemRemoved(not_null<const HistoryItem*> item) {
|
void InnerWidget::itemRemoved(not_null<const HistoryItem*> item) {
|
||||||
|
|
|
@ -38,6 +38,11 @@ namespace Data {
|
||||||
class CloudImageView;
|
class CloudImageView;
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Dialogs::Ui {
|
||||||
|
using namespace ::Ui;
|
||||||
|
class VideoUserpic;
|
||||||
|
} // namespace Dialogs::Ui
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
|
||||||
class Row;
|
class Row;
|
||||||
|
@ -312,6 +317,9 @@ private:
|
||||||
const Ui::Text::String &text) const;
|
const Ui::Text::String &text) const;
|
||||||
void refreshSearchInChatLabel();
|
void refreshSearchInChatLabel();
|
||||||
|
|
||||||
|
Ui::VideoUserpic *validateVideoUserpic(not_null<Row*> row);
|
||||||
|
Ui::VideoUserpic *validateVideoUserpic(not_null<History*> history);
|
||||||
|
|
||||||
void clearSearchResults(bool clearPeerSearchResults = true);
|
void clearSearchResults(bool clearPeerSearchResults = true);
|
||||||
void updateSelectedRow(Key key = Key());
|
void updateSelectedRow(Key key = Key());
|
||||||
|
|
||||||
|
@ -411,6 +419,10 @@ private:
|
||||||
Ui::Text::String _searchFromUserText;
|
Ui::Text::String _searchFromUserText;
|
||||||
RowDescriptor _menuRow;
|
RowDescriptor _menuRow;
|
||||||
|
|
||||||
|
base::flat_map<
|
||||||
|
not_null<PeerData*>,
|
||||||
|
std::unique_ptr<Ui::VideoUserpic>> _videoUserpics;
|
||||||
|
|
||||||
Fn<void()> _loadMoreCallback;
|
Fn<void()> _loadMoreCallback;
|
||||||
rpl::event_stream<> _listBottomReached;
|
rpl::event_stream<> _listBottomReached;
|
||||||
rpl::event_stream<ChosenRow> _chosenRow;
|
rpl::event_stream<ChosenRow> _chosenRow;
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/text/text_options.h"
|
#include "ui/text/text_options.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "dialogs/dialogs_entry.h"
|
#include "dialogs/dialogs_entry.h"
|
||||||
|
#include "dialogs/ui/dialogs_video_userpic.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_peer_values.h"
|
#include "data/data_peer_values.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
|
@ -79,37 +80,27 @@ namespace {
|
||||||
: accumulated;
|
: accumulated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PaintUserpic(
|
||||||
|
Painter &p,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Ui::VideoUserpic *videoUserpic,
|
||||||
|
std::shared_ptr<Data::CloudImageView> &view,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int outerWidth,
|
||||||
|
int size) {
|
||||||
|
if (videoUserpic) {
|
||||||
|
videoUserpic->paintLeft(p, view, x, y, outerWidth, size);
|
||||||
|
} else {
|
||||||
|
peer->paintUserpicLeft(p, view, x, y, outerWidth, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
BasicRow::BasicRow() = default;
|
BasicRow::BasicRow() = default;
|
||||||
BasicRow::~BasicRow() = default;
|
BasicRow::~BasicRow() = default;
|
||||||
|
|
||||||
void BasicRow::setCornerBadgeShown(
|
|
||||||
bool shown,
|
|
||||||
Fn<void()> updateCallback) const {
|
|
||||||
if (_cornerBadgeShown == shown) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_cornerBadgeShown = shown;
|
|
||||||
if (_cornerBadgeUserpic && _cornerBadgeUserpic->animation.animating()) {
|
|
||||||
_cornerBadgeUserpic->animation.change(
|
|
||||||
_cornerBadgeShown ? 1. : 0.,
|
|
||||||
st::dialogsOnlineBadgeDuration);
|
|
||||||
} else if (updateCallback) {
|
|
||||||
ensureCornerBadgeUserpic();
|
|
||||||
_cornerBadgeUserpic->animation.start(
|
|
||||||
std::move(updateCallback),
|
|
||||||
_cornerBadgeShown ? 0. : 1.,
|
|
||||||
_cornerBadgeShown ? 1. : 0.,
|
|
||||||
st::dialogsOnlineBadgeDuration);
|
|
||||||
}
|
|
||||||
if (!_cornerBadgeShown
|
|
||||||
&& _cornerBadgeUserpic
|
|
||||||
&& !_cornerBadgeUserpic->animation.animating()) {
|
|
||||||
_cornerBadgeUserpic = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasicRow::addRipple(
|
void BasicRow::addRipple(
|
||||||
QPoint origin,
|
QPoint origin,
|
||||||
QSize size,
|
QSize size,
|
||||||
|
@ -144,130 +135,23 @@ void BasicRow::paintRipple(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasicRow::updateCornerBadgeShown(
|
|
||||||
not_null<PeerData*> peer,
|
|
||||||
Fn<void()> updateCallback) const {
|
|
||||||
const auto shown = [&] {
|
|
||||||
if (const auto user = peer->asUser()) {
|
|
||||||
return Data::IsUserOnline(user);
|
|
||||||
} else if (const auto channel = peer->asChannel()) {
|
|
||||||
return Data::ChannelHasActiveCall(channel);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}();
|
|
||||||
setCornerBadgeShown(shown, std::move(updateCallback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasicRow::ensureCornerBadgeUserpic() const {
|
|
||||||
if (_cornerBadgeUserpic) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_cornerBadgeUserpic = std::make_unique<CornerBadgeUserpic>();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasicRow::PaintCornerBadgeFrame(
|
|
||||||
not_null<CornerBadgeUserpic*> data,
|
|
||||||
not_null<PeerData*> peer,
|
|
||||||
std::shared_ptr<Data::CloudImageView> &view) {
|
|
||||||
data->frame.fill(Qt::transparent);
|
|
||||||
|
|
||||||
Painter q(&data->frame);
|
|
||||||
peer->paintUserpic(
|
|
||||||
q,
|
|
||||||
view,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
st::dialogsPhotoSize);
|
|
||||||
|
|
||||||
PainterHighQualityEnabler hq(q);
|
|
||||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
|
||||||
|
|
||||||
const auto size = peer->isUser()
|
|
||||||
? st::dialogsOnlineBadgeSize
|
|
||||||
: st::dialogsCallBadgeSize;
|
|
||||||
const auto stroke = st::dialogsOnlineBadgeStroke;
|
|
||||||
const auto skip = peer->isUser()
|
|
||||||
? st::dialogsOnlineBadgeSkip
|
|
||||||
: st::dialogsCallBadgeSkip;
|
|
||||||
const auto shrink = (size / 2) * (1. - data->shown);
|
|
||||||
|
|
||||||
auto pen = QPen(Qt::transparent);
|
|
||||||
pen.setWidthF(stroke * data->shown);
|
|
||||||
q.setPen(pen);
|
|
||||||
q.setBrush(data->active
|
|
||||||
? st::dialogsOnlineBadgeFgActive
|
|
||||||
: st::dialogsOnlineBadgeFg);
|
|
||||||
q.drawEllipse(QRectF(
|
|
||||||
st::dialogsPhotoSize - skip.x() - size,
|
|
||||||
st::dialogsPhotoSize - skip.y() - size,
|
|
||||||
size,
|
|
||||||
size
|
|
||||||
).marginsRemoved({ shrink, shrink, shrink, shrink }));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BasicRow::paintUserpic(
|
void BasicRow::paintUserpic(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
|
Ui::VideoUserpic *videoUserpic,
|
||||||
History *historyForCornerBadge,
|
History *historyForCornerBadge,
|
||||||
crl::time now,
|
crl::time now,
|
||||||
bool active,
|
bool active,
|
||||||
int fullWidth) const {
|
int fullWidth) const {
|
||||||
updateCornerBadgeShown(peer);
|
PaintUserpic(
|
||||||
|
|
||||||
const auto shown = _cornerBadgeUserpic
|
|
||||||
? _cornerBadgeUserpic->animation.value(_cornerBadgeShown ? 1. : 0.)
|
|
||||||
: (_cornerBadgeShown ? 1. : 0.);
|
|
||||||
if (!historyForCornerBadge || shown == 0.) {
|
|
||||||
peer->paintUserpicLeft(
|
|
||||||
p,
|
p,
|
||||||
|
peer,
|
||||||
|
videoUserpic,
|
||||||
_userpic,
|
_userpic,
|
||||||
st::dialogsPadding.x(),
|
st::dialogsPadding.x(),
|
||||||
st::dialogsPadding.y(),
|
st::dialogsPadding.y(),
|
||||||
fullWidth,
|
fullWidth,
|
||||||
st::dialogsPhotoSize);
|
st::dialogsPhotoSize);
|
||||||
if (!historyForCornerBadge || !_cornerBadgeShown) {
|
|
||||||
_cornerBadgeUserpic = nullptr;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ensureCornerBadgeUserpic();
|
|
||||||
if (_cornerBadgeUserpic->frame.isNull()) {
|
|
||||||
_cornerBadgeUserpic->frame = QImage(
|
|
||||||
st::dialogsPhotoSize * cRetinaFactor(),
|
|
||||||
st::dialogsPhotoSize * cRetinaFactor(),
|
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
|
||||||
_cornerBadgeUserpic->frame.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
}
|
|
||||||
const auto key = peer->userpicUniqueKey(_userpic);
|
|
||||||
if (_cornerBadgeUserpic->shown != shown
|
|
||||||
|| _cornerBadgeUserpic->key != key
|
|
||||||
|| _cornerBadgeUserpic->active != active) {
|
|
||||||
_cornerBadgeUserpic->shown = shown;
|
|
||||||
_cornerBadgeUserpic->key = key;
|
|
||||||
_cornerBadgeUserpic->active = active;
|
|
||||||
PaintCornerBadgeFrame(_cornerBadgeUserpic.get(), peer, _userpic);
|
|
||||||
}
|
|
||||||
p.drawImage(st::dialogsPadding, _cornerBadgeUserpic->frame);
|
|
||||||
if (historyForCornerBadge->peer->isUser()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto actionPainter = historyForCornerBadge->sendActionPainter();
|
|
||||||
const auto bg = active
|
|
||||||
? st::dialogsBgActive
|
|
||||||
: st::dialogsBg;
|
|
||||||
const auto size = st::dialogsCallBadgeSize;
|
|
||||||
const auto skip = st::dialogsCallBadgeSkip;
|
|
||||||
p.setOpacity(shown);
|
|
||||||
p.translate(st::dialogsPadding);
|
|
||||||
actionPainter->paintSpeaking(
|
|
||||||
p,
|
|
||||||
st::dialogsPhotoSize - skip.x() - size,
|
|
||||||
st::dialogsPhotoSize - skip.y() - size,
|
|
||||||
fullWidth,
|
|
||||||
bg,
|
|
||||||
now);
|
|
||||||
p.translate(-st::dialogsPadding);
|
|
||||||
p.setOpacity(1.);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Row::Row(Key key, int pos) : _id(key), _pos(pos) {
|
Row::Row(Key key, int pos) : _id(key), _pos(pos) {
|
||||||
|
@ -297,6 +181,172 @@ void Row::validateListEntryCache() const {
|
||||||
Ui::ItemTextDefaultOptions());
|
Ui::ItemTextDefaultOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Row::setCornerBadgeShown(
|
||||||
|
bool shown,
|
||||||
|
Fn<void()> updateCallback) const {
|
||||||
|
if (_cornerBadgeShown == shown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_cornerBadgeShown = shown;
|
||||||
|
if (_cornerBadgeUserpic && _cornerBadgeUserpic->animation.animating()) {
|
||||||
|
_cornerBadgeUserpic->animation.change(
|
||||||
|
_cornerBadgeShown ? 1. : 0.,
|
||||||
|
st::dialogsOnlineBadgeDuration);
|
||||||
|
} else if (updateCallback) {
|
||||||
|
ensureCornerBadgeUserpic();
|
||||||
|
_cornerBadgeUserpic->animation.start(
|
||||||
|
std::move(updateCallback),
|
||||||
|
_cornerBadgeShown ? 0. : 1.,
|
||||||
|
_cornerBadgeShown ? 1. : 0.,
|
||||||
|
st::dialogsOnlineBadgeDuration);
|
||||||
|
}
|
||||||
|
if (!_cornerBadgeShown
|
||||||
|
&& _cornerBadgeUserpic
|
||||||
|
&& !_cornerBadgeUserpic->animation.animating()) {
|
||||||
|
_cornerBadgeUserpic = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Row::updateCornerBadgeShown(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Fn<void()> updateCallback) const {
|
||||||
|
const auto shown = [&] {
|
||||||
|
if (const auto user = peer->asUser()) {
|
||||||
|
return Data::IsUserOnline(user);
|
||||||
|
} else if (const auto channel = peer->asChannel()) {
|
||||||
|
return Data::ChannelHasActiveCall(channel);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}();
|
||||||
|
setCornerBadgeShown(shown, std::move(updateCallback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Row::ensureCornerBadgeUserpic() const {
|
||||||
|
if (_cornerBadgeUserpic) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_cornerBadgeUserpic = std::make_unique<CornerBadgeUserpic>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Row::PaintCornerBadgeFrame(
|
||||||
|
not_null<CornerBadgeUserpic*> data,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Ui::VideoUserpic *videoUserpic,
|
||||||
|
std::shared_ptr<Data::CloudImageView> &view) {
|
||||||
|
data->frame.fill(Qt::transparent);
|
||||||
|
|
||||||
|
Painter q(&data->frame);
|
||||||
|
PaintUserpic(
|
||||||
|
q,
|
||||||
|
peer,
|
||||||
|
videoUserpic,
|
||||||
|
view,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
data->frame.width() / data->frame.devicePixelRatio(),
|
||||||
|
st::dialogsPhotoSize);
|
||||||
|
|
||||||
|
PainterHighQualityEnabler hq(q);
|
||||||
|
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
|
||||||
|
const auto size = peer->isUser()
|
||||||
|
? st::dialogsOnlineBadgeSize
|
||||||
|
: st::dialogsCallBadgeSize;
|
||||||
|
const auto stroke = st::dialogsOnlineBadgeStroke;
|
||||||
|
const auto skip = peer->isUser()
|
||||||
|
? st::dialogsOnlineBadgeSkip
|
||||||
|
: st::dialogsCallBadgeSkip;
|
||||||
|
const auto shrink = (size / 2) * (1. - data->shown);
|
||||||
|
|
||||||
|
auto pen = QPen(Qt::transparent);
|
||||||
|
pen.setWidthF(stroke * data->shown);
|
||||||
|
q.setPen(pen);
|
||||||
|
q.setBrush(data->active
|
||||||
|
? st::dialogsOnlineBadgeFgActive
|
||||||
|
: st::dialogsOnlineBadgeFg);
|
||||||
|
q.drawEllipse(QRectF(
|
||||||
|
st::dialogsPhotoSize - skip.x() - size,
|
||||||
|
st::dialogsPhotoSize - skip.y() - size,
|
||||||
|
size,
|
||||||
|
size
|
||||||
|
).marginsRemoved({ shrink, shrink, shrink, shrink }));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Row::paintUserpic(
|
||||||
|
Painter &p,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Ui::VideoUserpic *videoUserpic,
|
||||||
|
History *historyForCornerBadge,
|
||||||
|
crl::time now,
|
||||||
|
bool active,
|
||||||
|
int fullWidth) const {
|
||||||
|
updateCornerBadgeShown(peer);
|
||||||
|
|
||||||
|
const auto shown = _cornerBadgeUserpic
|
||||||
|
? _cornerBadgeUserpic->animation.value(_cornerBadgeShown ? 1. : 0.)
|
||||||
|
: (_cornerBadgeShown ? 1. : 0.);
|
||||||
|
if (!historyForCornerBadge || shown == 0.) {
|
||||||
|
BasicRow::paintUserpic(
|
||||||
|
p,
|
||||||
|
peer,
|
||||||
|
videoUserpic,
|
||||||
|
historyForCornerBadge,
|
||||||
|
now,
|
||||||
|
active,
|
||||||
|
fullWidth);
|
||||||
|
if (!historyForCornerBadge || !_cornerBadgeShown) {
|
||||||
|
_cornerBadgeUserpic = nullptr;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ensureCornerBadgeUserpic();
|
||||||
|
if (_cornerBadgeUserpic->frame.isNull()) {
|
||||||
|
_cornerBadgeUserpic->frame = QImage(
|
||||||
|
st::dialogsPhotoSize * cRetinaFactor(),
|
||||||
|
st::dialogsPhotoSize * cRetinaFactor(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
_cornerBadgeUserpic->frame.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
}
|
||||||
|
const auto key = peer->userpicUniqueKey(userpicView());
|
||||||
|
const auto frameIndex = videoUserpic ? videoUserpic->frameIndex() : -1;
|
||||||
|
if (_cornerBadgeUserpic->shown != shown
|
||||||
|
|| _cornerBadgeUserpic->key != key
|
||||||
|
|| _cornerBadgeUserpic->active != active
|
||||||
|
|| _cornerBadgeUserpic->frameIndex != frameIndex
|
||||||
|
|| videoUserpic) {
|
||||||
|
_cornerBadgeUserpic->shown = shown;
|
||||||
|
_cornerBadgeUserpic->key = key;
|
||||||
|
_cornerBadgeUserpic->active = active;
|
||||||
|
_cornerBadgeUserpic->frameIndex = frameIndex;
|
||||||
|
PaintCornerBadgeFrame(
|
||||||
|
_cornerBadgeUserpic.get(),
|
||||||
|
peer,
|
||||||
|
videoUserpic,
|
||||||
|
userpicView());
|
||||||
|
}
|
||||||
|
p.drawImage(st::dialogsPadding, _cornerBadgeUserpic->frame);
|
||||||
|
if (historyForCornerBadge->peer->isUser()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto actionPainter = historyForCornerBadge->sendActionPainter();
|
||||||
|
const auto bg = active
|
||||||
|
? st::dialogsBgActive
|
||||||
|
: st::dialogsBg;
|
||||||
|
const auto size = st::dialogsCallBadgeSize;
|
||||||
|
const auto skip = st::dialogsCallBadgeSkip;
|
||||||
|
p.setOpacity(shown);
|
||||||
|
p.translate(st::dialogsPadding);
|
||||||
|
actionPainter->paintSpeaking(
|
||||||
|
p,
|
||||||
|
st::dialogsPhotoSize - skip.x() - size,
|
||||||
|
st::dialogsPhotoSize - skip.y() - size,
|
||||||
|
fullWidth,
|
||||||
|
bg,
|
||||||
|
now);
|
||||||
|
p.translate(-st::dialogsPadding);
|
||||||
|
p.setOpacity(1.);
|
||||||
|
}
|
||||||
|
|
||||||
FakeRow::FakeRow(Key searchInChat, not_null<HistoryItem*> item)
|
FakeRow::FakeRow(Key searchInChat, not_null<HistoryItem*> item)
|
||||||
: _searchInChat(searchInChat)
|
: _searchInChat(searchInChat)
|
||||||
, _item(item) {
|
, _item(item) {
|
||||||
|
|
|
@ -26,6 +26,7 @@ class RippleAnimation;
|
||||||
namespace Dialogs::Ui {
|
namespace Dialogs::Ui {
|
||||||
using namespace ::Ui;
|
using namespace ::Ui;
|
||||||
class RowPainter;
|
class RowPainter;
|
||||||
|
class VideoUserpic;
|
||||||
} // namespace Dialogs::Ui
|
} // namespace Dialogs::Ui
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
@ -35,14 +36,12 @@ enum class SortMode;
|
||||||
class BasicRow {
|
class BasicRow {
|
||||||
public:
|
public:
|
||||||
BasicRow();
|
BasicRow();
|
||||||
~BasicRow();
|
virtual ~BasicRow();
|
||||||
|
|
||||||
void updateCornerBadgeShown(
|
virtual void paintUserpic(
|
||||||
not_null<PeerData*> peer,
|
|
||||||
Fn<void()> updateCallback = nullptr) const;
|
|
||||||
void paintUserpic(
|
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
|
Ui::VideoUserpic *videoUserpic,
|
||||||
History *historyForCornerBadge,
|
History *historyForCornerBadge,
|
||||||
crl::time now,
|
crl::time now,
|
||||||
bool active,
|
bool active,
|
||||||
|
@ -63,27 +62,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CornerBadgeUserpic {
|
|
||||||
InMemoryKey key;
|
|
||||||
float64 shown = 0.;
|
|
||||||
bool active = false;
|
|
||||||
QImage frame;
|
|
||||||
Ui::Animations::Simple animation;
|
|
||||||
};
|
|
||||||
|
|
||||||
void setCornerBadgeShown(
|
|
||||||
bool shown,
|
|
||||||
Fn<void()> updateCallback) const;
|
|
||||||
void ensureCornerBadgeUserpic() const;
|
|
||||||
static void PaintCornerBadgeFrame(
|
|
||||||
not_null<CornerBadgeUserpic*> data,
|
|
||||||
not_null<PeerData*> peer,
|
|
||||||
std::shared_ptr<Data::CloudImageView> &view);
|
|
||||||
|
|
||||||
mutable std::shared_ptr<Data::CloudImageView> _userpic;
|
mutable std::shared_ptr<Data::CloudImageView> _userpic;
|
||||||
mutable std::unique_ptr<Ui::RippleAnimation> _ripple;
|
mutable std::unique_ptr<Ui::RippleAnimation> _ripple;
|
||||||
mutable std::unique_ptr<CornerBadgeUserpic> _cornerBadgeUserpic;
|
|
||||||
mutable bool _cornerBadgeShown = false;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,6 +74,18 @@ public:
|
||||||
}
|
}
|
||||||
Row(Key key, int pos);
|
Row(Key key, int pos);
|
||||||
|
|
||||||
|
void updateCornerBadgeShown(
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Fn<void()> updateCallback = nullptr) const;
|
||||||
|
void paintUserpic(
|
||||||
|
Painter &p,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Ui::VideoUserpic *videoUserpic,
|
||||||
|
History *historyForCornerBadge,
|
||||||
|
crl::time now,
|
||||||
|
bool active,
|
||||||
|
int fullWidth) const final override;
|
||||||
|
|
||||||
[[nodiscard]] Key key() const {
|
[[nodiscard]] Key key() const {
|
||||||
return _id;
|
return _id;
|
||||||
}
|
}
|
||||||
|
@ -122,10 +114,31 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class List;
|
friend class List;
|
||||||
|
|
||||||
|
struct CornerBadgeUserpic {
|
||||||
|
InMemoryKey key;
|
||||||
|
float64 shown = 0.;
|
||||||
|
int frameIndex = -1;
|
||||||
|
bool active = false;
|
||||||
|
QImage frame;
|
||||||
|
Ui::Animations::Simple animation;
|
||||||
|
};
|
||||||
|
|
||||||
|
void setCornerBadgeShown(
|
||||||
|
bool shown,
|
||||||
|
Fn<void()> updateCallback) const;
|
||||||
|
void ensureCornerBadgeUserpic() const;
|
||||||
|
static void PaintCornerBadgeFrame(
|
||||||
|
not_null<CornerBadgeUserpic*> data,
|
||||||
|
not_null<PeerData*> peer,
|
||||||
|
Ui::VideoUserpic *videoUserpic,
|
||||||
|
std::shared_ptr<Data::CloudImageView> &view);
|
||||||
|
|
||||||
Key _id;
|
Key _id;
|
||||||
int _pos = 0;
|
int _pos = 0;
|
||||||
mutable uint32 _listEntryCacheVersion = 0;
|
mutable uint32 _listEntryCacheVersion = 0;
|
||||||
mutable Ui::Text::String _listEntryCache;
|
mutable Ui::Text::String _listEntryCache;
|
||||||
|
mutable std::unique_ptr<CornerBadgeUserpic> _cornerBadgeUserpic;
|
||||||
|
mutable bool _cornerBadgeShown = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "dialogs/dialogs_list.h"
|
#include "dialogs/dialogs_list.h"
|
||||||
|
#include "dialogs/ui/dialogs_video_userpic.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_window.h"
|
#include "styles/style_window.h"
|
||||||
#include "storage/localstorage.h"
|
#include "storage/localstorage.h"
|
||||||
|
@ -310,6 +311,7 @@ void paintRow(
|
||||||
not_null<const BasicRow*> row,
|
not_null<const BasicRow*> row,
|
||||||
not_null<Entry*> entry,
|
not_null<Entry*> entry,
|
||||||
Dialogs::Key chat,
|
Dialogs::Key chat,
|
||||||
|
VideoUserpic *videoUserpic,
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
PeerData *from,
|
PeerData *from,
|
||||||
const HiddenSenderInfo *hiddenSenderInfo,
|
const HiddenSenderInfo *hiddenSenderInfo,
|
||||||
|
@ -360,6 +362,7 @@ void paintRow(
|
||||||
row->paintUserpic(
|
row->paintUserpic(
|
||||||
p,
|
p,
|
||||||
from,
|
from,
|
||||||
|
videoUserpic,
|
||||||
(flags & Flag::AllowUserOnline) ? history : nullptr,
|
(flags & Flag::AllowUserOnline) ? history : nullptr,
|
||||||
ms,
|
ms,
|
||||||
active,
|
active,
|
||||||
|
@ -450,13 +453,13 @@ void paintRow(
|
||||||
if (!ShowSendActionInDialogs(history)
|
if (!ShowSendActionInDialogs(history)
|
||||||
|| !history->sendActionPainter()->paint(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) {
|
|| !history->sendActionPainter()->paint(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) {
|
||||||
if (history->cloudDraftTextCache.isEmpty()) {
|
if (history->cloudDraftTextCache.isEmpty()) {
|
||||||
auto draftWrapped = Ui::Text::PlainLink(
|
auto draftWrapped = Text::PlainLink(
|
||||||
tr::lng_dialogs_text_from_wrapped(
|
tr::lng_dialogs_text_from_wrapped(
|
||||||
tr::now,
|
tr::now,
|
||||||
lt_from,
|
lt_from,
|
||||||
tr::lng_from_draft(tr::now)));
|
tr::lng_from_draft(tr::now)));
|
||||||
auto draftText = supportMode
|
auto draftText = supportMode
|
||||||
? Ui::Text::PlainLink(
|
? Text::PlainLink(
|
||||||
Support::ChatOccupiedString(history))
|
Support::ChatOccupiedString(history))
|
||||||
: tr::lng_dialogs_text_with_from(
|
: tr::lng_dialogs_text_with_from(
|
||||||
tr::now,
|
tr::now,
|
||||||
|
@ -464,7 +467,7 @@ void paintRow(
|
||||||
draftWrapped,
|
draftWrapped,
|
||||||
lt_message,
|
lt_message,
|
||||||
{ .text = draft->textWithTags.text },
|
{ .text = draft->textWithTags.text },
|
||||||
Ui::Text::WithEntities);
|
Text::WithEntities);
|
||||||
history->cloudDraftTextCache.setMarkedText(
|
history->cloudDraftTextCache.setMarkedText(
|
||||||
st::dialogsTextStyle,
|
st::dialogsTextStyle,
|
||||||
draftText,
|
draftText,
|
||||||
|
@ -790,6 +793,7 @@ QRect PaintUnreadBadge(
|
||||||
void RowPainter::paint(
|
void RowPainter::paint(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<const Row*> row,
|
not_null<const Row*> row,
|
||||||
|
VideoUserpic *videoUserpic,
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
int fullWidth,
|
int fullWidth,
|
||||||
bool active,
|
bool active,
|
||||||
|
@ -934,6 +938,7 @@ void RowPainter::paint(
|
||||||
row,
|
row,
|
||||||
entry,
|
entry,
|
||||||
row->key(),
|
row->key(),
|
||||||
|
videoUserpic,
|
||||||
filterId,
|
filterId,
|
||||||
from,
|
from,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -1067,6 +1072,7 @@ void RowPainter::paint(
|
||||||
row,
|
row,
|
||||||
history,
|
history,
|
||||||
history,
|
history,
|
||||||
|
nullptr,
|
||||||
FilterId(),
|
FilterId(),
|
||||||
from,
|
from,
|
||||||
hiddenSenderInfo,
|
hiddenSenderInfo,
|
||||||
|
|
|
@ -18,6 +18,8 @@ class BasicRow;
|
||||||
|
|
||||||
namespace Dialogs::Ui {
|
namespace Dialogs::Ui {
|
||||||
|
|
||||||
|
class VideoUserpic;
|
||||||
|
|
||||||
using namespace ::Ui;
|
using namespace ::Ui;
|
||||||
|
|
||||||
const style::icon *ChatTypeIcon(
|
const style::icon *ChatTypeIcon(
|
||||||
|
@ -30,6 +32,7 @@ public:
|
||||||
static void paint(
|
static void paint(
|
||||||
Painter &p,
|
Painter &p,
|
||||||
not_null<const Row*> row,
|
not_null<const Row*> row,
|
||||||
|
VideoUserpic *videoUserpic,
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
int fullWidth,
|
int fullWidth,
|
||||||
bool active,
|
bool active,
|
||||||
|
|
125
Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp
Normal file
125
Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.cpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
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 "dialogs/ui/dialogs_video_userpic.h"
|
||||||
|
|
||||||
|
#include "core/file_location.h"
|
||||||
|
#include "data/data_peer.h"
|
||||||
|
#include "data/data_photo.h"
|
||||||
|
#include "data/data_photo_media.h"
|
||||||
|
#include "data/data_file_origin.h"
|
||||||
|
#include "data/data_session.h"
|
||||||
|
|
||||||
|
namespace Dialogs::Ui {
|
||||||
|
|
||||||
|
VideoUserpic::VideoUserpic(not_null<PeerData*> peer, Fn<void()> repaint)
|
||||||
|
: _peer(peer)
|
||||||
|
, _repaint(std::move(repaint)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoUserpic::~VideoUserpic() = default;
|
||||||
|
|
||||||
|
int VideoUserpic::frameIndex() const {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoUserpic::paintLeft(
|
||||||
|
Painter &p,
|
||||||
|
std::shared_ptr<Data::CloudImageView> &view,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int w,
|
||||||
|
int size) {
|
||||||
|
_lastSize = size;
|
||||||
|
|
||||||
|
const auto photoId = _peer->userpicPhotoId();
|
||||||
|
if (_videoPhotoId != photoId) {
|
||||||
|
_videoPhotoId = photoId;
|
||||||
|
_video = nullptr;
|
||||||
|
_videoPhotoMedia = nullptr;
|
||||||
|
const auto photo = _peer->owner().photo(photoId);
|
||||||
|
if (photo->isNull()) {
|
||||||
|
_peer->updateFullForced();
|
||||||
|
} else {
|
||||||
|
_videoPhotoMedia = photo->createMediaView();
|
||||||
|
_videoPhotoMedia->videoWanted(_peer->userpicPhotoOrigin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_video) {
|
||||||
|
if (!_videoPhotoMedia) {
|
||||||
|
const auto photo = _peer->owner().photo(photoId);
|
||||||
|
if (!photo->isNull()) {
|
||||||
|
_videoPhotoMedia = photo->createMediaView();
|
||||||
|
_videoPhotoMedia->videoWanted(_peer->userpicPhotoOrigin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_videoPhotoMedia) {
|
||||||
|
auto bytes = _videoPhotoMedia->videoContent();
|
||||||
|
if (!bytes.isEmpty()) {
|
||||||
|
auto callback = [=](Media::Clip::Notification notification) {
|
||||||
|
clipCallback(notification);
|
||||||
|
};
|
||||||
|
_video = Media::Clip::MakeReader(
|
||||||
|
Core::FileLocation(),
|
||||||
|
std::move(bytes),
|
||||||
|
std::move(callback));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (rtl()) {
|
||||||
|
x = w - x - size;
|
||||||
|
}
|
||||||
|
if (_video && _video->ready()) {
|
||||||
|
startReady();
|
||||||
|
|
||||||
|
const auto now = crl::now();
|
||||||
|
p.drawPixmap(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
_video->current(request(size), now));
|
||||||
|
} else {
|
||||||
|
_peer->paintUserpicLeft(p, view, x, y, w, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Media::Clip::FrameRequest VideoUserpic::request(int size) const {
|
||||||
|
return {
|
||||||
|
.frame = { size, size },
|
||||||
|
.outer = { size, size },
|
||||||
|
.factor = cIntRetinaFactor(),
|
||||||
|
.radius = ImageRoundRadius::Ellipse,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VideoUserpic::startReady(int size) {
|
||||||
|
if (!_video->ready() || _video->started()) {
|
||||||
|
return false;
|
||||||
|
} else if (!_lastSize) {
|
||||||
|
_lastSize = size ? size : _video->width();
|
||||||
|
}
|
||||||
|
_video->start(request(_lastSize));
|
||||||
|
_repaint();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoUserpic::clipCallback(Media::Clip::Notification notification) {
|
||||||
|
using namespace Media::Clip;
|
||||||
|
|
||||||
|
switch (notification) {
|
||||||
|
case Notification::Reinit: {
|
||||||
|
if (_video->state() == State::Error) {
|
||||||
|
_video.setBad();
|
||||||
|
} else if (startReady()) {
|
||||||
|
_repaint();
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case Notification::Repaint: _repaint(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Dialogs::Ui
|
54
Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h
Normal file
54
Telegram/SourceFiles/dialogs/ui/dialogs_video_userpic.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "media/clip/media_clip_reader.h"
|
||||||
|
|
||||||
|
class Painter;
|
||||||
|
|
||||||
|
namespace Data {
|
||||||
|
class CloudImageView;
|
||||||
|
class PhotoMedia;
|
||||||
|
} // namespace Data
|
||||||
|
|
||||||
|
namespace Dialogs::Ui {
|
||||||
|
|
||||||
|
using namespace ::Ui;
|
||||||
|
|
||||||
|
class VideoUserpic final {
|
||||||
|
public:
|
||||||
|
VideoUserpic(not_null<PeerData*> peer, Fn<void()> repaint);
|
||||||
|
~VideoUserpic();
|
||||||
|
|
||||||
|
[[nodiscard]] int frameIndex() const;
|
||||||
|
|
||||||
|
void paintLeft(
|
||||||
|
Painter &p,
|
||||||
|
std::shared_ptr<Data::CloudImageView> &view,
|
||||||
|
int x,
|
||||||
|
int y,
|
||||||
|
int w,
|
||||||
|
int size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void clipCallback(Media::Clip::Notification notification);
|
||||||
|
[[nodiscard]] Media::Clip::FrameRequest request(int size) const;
|
||||||
|
bool startReady(int size = 0);
|
||||||
|
|
||||||
|
const not_null<PeerData*> _peer;
|
||||||
|
const Fn<void()> _repaint;
|
||||||
|
|
||||||
|
Media::Clip::ReaderPointer _video;
|
||||||
|
int _lastSize = 0;
|
||||||
|
std::shared_ptr<Data::PhotoMedia> _videoPhotoMedia;
|
||||||
|
PhotoId _videoPhotoId = 0;
|
||||||
|
PhotoId _photoIdRequested = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Dialogs::Ui
|
|
@ -1470,7 +1470,7 @@ void InnerWidget::suggestRestrictParticipant(
|
||||||
editRestrictions(false, ChatRestrictionsInfo());
|
editRestrictions(false, ChatRestrictionsInfo());
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
});
|
}, &st::menuIconRestrict);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::restrictParticipant(
|
void InnerWidget::restrictParticipant(
|
||||||
|
|
|
@ -1362,6 +1362,7 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
||||||
const auto payment = Get<HistoryServicePayment>();
|
const auto payment = Get<HistoryServicePayment>();
|
||||||
const auto id = fullId();
|
const auto id = fullId();
|
||||||
const auto owner = &history()->owner();
|
const auto owner = &history()->owner();
|
||||||
|
payment->slug = data.vinvoice_slug().value_or_empty();
|
||||||
payment->amount = Ui::FillAmountAndCurrency(amount, currency);
|
payment->amount = Ui::FillAmountAndCurrency(amount, currency);
|
||||||
payment->invoiceLink = std::make_shared<LambdaClickHandler>([=](
|
payment->invoiceLink = std::make_shared<LambdaClickHandler>([=](
|
||||||
ClickContext context) {
|
ClickContext context) {
|
||||||
|
|
|
@ -153,10 +153,13 @@ void UploadPhoto(not_null<UserData*> user, QImage image) {
|
||||||
auto bytes = QByteArray();
|
auto bytes = QByteArray();
|
||||||
auto buffer = QBuffer(&bytes);
|
auto buffer = QBuffer(&bytes);
|
||||||
image.save(&buffer, "JPG", 87);
|
image.save(&buffer, "JPG", 87);
|
||||||
user->setUserpic(base::RandomValue<PhotoId>(), ImageLocation(
|
user->setUserpic(
|
||||||
|
base::RandomValue<PhotoId>(),
|
||||||
|
ImageLocation(
|
||||||
{ .data = InMemoryLocation{ .bytes = bytes } },
|
{ .data = InMemoryLocation{ .bytes = bytes } },
|
||||||
image.width(),
|
image.width(),
|
||||||
image.height()));
|
image.height()),
|
||||||
|
false);
|
||||||
user->session().api().peerPhoto().upload(user, std::move(image));
|
user->session().api().peerPhoto().upload(user, std::move(image));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,6 +146,7 @@ uint32 peerSize(not_null<PeerData*> peer) {
|
||||||
void writePeer(QDataStream &stream, not_null<PeerData*> peer) {
|
void writePeer(QDataStream &stream, not_null<PeerData*> peer) {
|
||||||
stream << SerializePeerId(peer->id) << quint64(peer->userpicPhotoId());
|
stream << SerializePeerId(peer->id) << quint64(peer->userpicPhotoId());
|
||||||
writeImageLocation(stream, peer->userpicLocation());
|
writeImageLocation(stream, peer->userpicLocation());
|
||||||
|
stream << qint32(peer->userpicHasVideo() ? 1 : 0);
|
||||||
if (const auto user = peer->asUser()) {
|
if (const auto user = peer->asUser()) {
|
||||||
const auto botInlinePlaceholder = user->isBot()
|
const auto botInlinePlaceholder = user->isBot()
|
||||||
? user->botInfo->inlinePlaceholder
|
? user->botInfo->inlinePlaceholder
|
||||||
|
@ -190,6 +191,7 @@ PeerData *readPeer(
|
||||||
int streamAppVersion,
|
int streamAppVersion,
|
||||||
QDataStream &stream) {
|
QDataStream &stream) {
|
||||||
quint64 peerIdSerialized = 0, photoId = 0;
|
quint64 peerIdSerialized = 0, photoId = 0;
|
||||||
|
qint32 photoHasVideo = 0;
|
||||||
stream >> peerIdSerialized >> photoId;
|
stream >> peerIdSerialized >> photoId;
|
||||||
const auto peerId = DeserializePeerId(peerIdSerialized);
|
const auto peerId = DeserializePeerId(peerIdSerialized);
|
||||||
if (!peerId) {
|
if (!peerId) {
|
||||||
|
@ -201,6 +203,9 @@ PeerData *readPeer(
|
||||||
if (!userpic) {
|
if (!userpic) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
if (streamAppVersion >= 4000000 || true AssertIsDebug()) {
|
||||||
|
stream >> photoHasVideo;
|
||||||
|
}
|
||||||
|
|
||||||
const auto selfId = session->userPeerId();
|
const auto selfId = session->userPeerId();
|
||||||
const auto loaded = (peerId == selfId)
|
const auto loaded = (peerId == selfId)
|
||||||
|
@ -424,7 +429,7 @@ PeerData *readPeer(
|
||||||
result->id.value,
|
result->id.value,
|
||||||
userpicAccessHash,
|
userpicAccessHash,
|
||||||
photoId);
|
photoId);
|
||||||
result->setUserpic(photoId, location);
|
result->setUserpic(photoId, location, (photoHasVideo == 1));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -439,6 +444,10 @@ QString peekUserPhone(int streamAppVersion, QDataStream &stream) {
|
||||||
|| !readImageLocation(streamAppVersion, stream)) {
|
|| !readImageLocation(streamAppVersion, stream)) {
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
if (streamAppVersion >= 4000000 || true AssertIsDebug()) {
|
||||||
|
qint32 photoHasVideo = 0;
|
||||||
|
stream >> photoHasVideo;
|
||||||
|
}
|
||||||
|
|
||||||
QString first, last, phone;
|
QString first, last, phone;
|
||||||
stream >> first >> last >> phone;
|
stream >> first >> last >> phone;
|
||||||
|
|
Loading…
Add table
Reference in a new issue