2
0
mirror of https://github.com/kotatogram/kotatogram-desktop synced 2025-08-31 06:35:14 +00:00

Move EmptyUserpic from data_peer to empty_userpic.

This commit is contained in:
John Preston
2017-12-05 12:43:18 +04:00
parent 68009b6fba
commit 5eeb8143b6
14 changed files with 346 additions and 303 deletions

View File

@@ -35,29 +35,25 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
#include "messenger.h"
#include "mainwindow.h"
#include "window/window_controller.h"
#include "ui/empty_userpic.h"
namespace {
constexpr auto kUpdateFullPeerTimeout = TimeMs(5000); // Not more than once in 5 seconds.
constexpr auto kUserpicSize = 160;
int peerColorIndex(const PeerId &peer) {
auto myId = Auth().userId();
auto peerId = peerToBareInt(peer);
auto both = (QByteArray::number(peerId) + QByteArray::number(myId)).mid(0, 15);
uchar md5[16];
hashMd5(both.constData(), both.size(), md5);
return (md5[peerId & 0x0F] & (peerIsUser(peer) ? 0x07 : 0x03));
} // namespace
namespace Data {
int PeerColorIndex(int32 bareId) {
const auto index = std::abs(bareId) % 7;
const int map[] = { 0, 7, 4, 1, 6, 3, 5 };
return map[index];
}
ImagePtr generateUserpicImage(const style::icon &icon) {
auto data = QImage(icon.size() * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
data.setDevicePixelRatio(cRetinaFactor());
{
Painter p(&data);
icon.paint(p, 0, 0, icon.width());
}
return ImagePtr(App::pixmapFromImageInPlace(std::move(data)), "PNG");
int PeerColorIndex(PeerId peerId) {
return PeerColorIndex(peerToBareInt(peerId));
}
style::color PeerUserpicColor(PeerId peerId) {
@@ -74,190 +70,7 @@ style::color PeerUserpicColor(PeerId peerId) {
return colors[PeerColorIndex(peerId)];
}
} // namespace
int PeerColorIndex(int32 bareId) {
const auto index = std::abs(bareId) % 7;
const int map[] = { 0, 7, 4, 1, 6, 3, 5 };
return map[index];
}
int PeerColorIndex(PeerId peerId) {
return PeerColorIndex(peerToBareInt(peerId));
}
class EmptyUserpic::Impl {
public:
Impl(PeerId peerId, const QString &name)
: _color(PeerUserpicColor(peerId)) {
fillString(name);
}
void paint(Painter &p, int x, int y, int size);
void paintRounded(Painter &p, int x, int y, int size);
void paintSquare(Painter &p, int x, int y, int size);
StorageKey uniqueKey() const;
private:
template <typename PaintBackground>
void paint(Painter &p, int x, int y, int size, PaintBackground paintBackground);
void fillString(const QString &name);
style::color _color;
QString _string;
};
template <typename PaintBackground>
void EmptyUserpic::Impl::paint(Painter &p, int x, int y, int size, PaintBackground paintBackground) {
auto fontsize = (size * 13) / 33;
auto font = st::historyPeerUserpicFont->f;
font.setPixelSize(fontsize);
PainterHighQualityEnabler hq(p);
p.setBrush(_color);
p.setPen(Qt::NoPen);
paintBackground();
p.setFont(font);
p.setBrush(Qt::NoBrush);
p.setPen(st::historyPeerUserpicFg);
p.drawText(QRect(x, y, size, size), _string, QTextOption(style::al_center));
}
void EmptyUserpic::Impl::paint(Painter &p, int x, int y, int size) {
paint(p, x, y, size, [&p, x, y, size] {
p.drawEllipse(x, y, size, size);
});
}
void EmptyUserpic::Impl::paintRounded(Painter &p, int x, int y, int size) {
paint(p, x, y, size, [&p, x, y, size] {
p.drawRoundedRect(x, y, size, size, st::buttonRadius, st::buttonRadius);
});
}
void EmptyUserpic::Impl::paintSquare(Painter &p, int x, int y, int size) {
paint(p, x, y, size, [&p, x, y, size] {
p.fillRect(x, y, size, size, p.brush());
});
}
StorageKey EmptyUserpic::Impl::uniqueKey() const {
auto first = 0xFFFFFFFF00000000ULL | anim::getPremultiplied(_color->c);
auto second = uint64(0);
memcpy(&second, _string.constData(), qMin(sizeof(second), _string.size() * sizeof(QChar)));
return StorageKey(first, second);
}
void EmptyUserpic::Impl::fillString(const QString &name) {
QList<QString> letters;
QList<int> levels;
auto level = 0;
auto letterFound = false;
auto ch = name.constData(), end = ch + name.size();
while (ch != end) {
auto emojiLength = 0;
if (auto emoji = Ui::Emoji::Find(ch, end, &emojiLength)) {
ch += emojiLength;
} else if (ch->isHighSurrogate()) {
++ch;
if (ch != end && ch->isLowSurrogate()) {
++ch;
}
} else if (!letterFound && ch->isLetterOrNumber()) {
letterFound = true;
if (ch + 1 != end && chIsDiac(*(ch + 1))) {
letters.push_back(QString(ch, 2));
levels.push_back(level);
++ch;
} else {
letters.push_back(QString(ch, 1));
levels.push_back(level);
}
++ch;
} else {
if (*ch == ' ') {
level = 0;
letterFound = false;
} else if (letterFound && *ch == '-') {
level = 1;
letterFound = true;
}
++ch;
}
}
// We prefer the second letter to be after ' ', but it can also be after '-'.
_string = QString();
if (!letters.isEmpty()) {
_string += letters.front();
auto bestIndex = 0;
auto bestLevel = 2;
for (auto i = letters.size(); i != 1;) {
if (levels[--i] < bestLevel) {
bestIndex = i;
bestLevel = levels[i];
}
}
if (bestIndex > 0) {
_string += letters[bestIndex];
}
}
_string = _string.toUpper();
}
EmptyUserpic::EmptyUserpic() = default;
EmptyUserpic::EmptyUserpic(PeerId peerId, const QString &name)
: _impl(std::make_unique<Impl>(peerId, name)) {
}
EmptyUserpic::EmptyUserpic(const QString &nonce, const QString &name)
: EmptyUserpic(qHash(nonce), name) {
}
void EmptyUserpic::set(PeerId peerId, const QString &name) {
_impl = std::make_unique<Impl>(peerId, name);
}
void EmptyUserpic::clear() {
_impl.reset();
}
void EmptyUserpic::paint(Painter &p, int x, int y, int outerWidth, int size) const {
Expects(_impl != nullptr);
_impl->paint(p, rtl() ? (outerWidth - x - size) : x, y, size);
}
void EmptyUserpic::paintRounded(Painter &p, int x, int y, int outerWidth, int size) const {
Expects(_impl != nullptr);
_impl->paintRounded(p, rtl() ? (outerWidth - x - size) : x, y, size);
}
void EmptyUserpic::paintSquare(Painter &p, int x, int y, int outerWidth, int size) const {
Expects(_impl != nullptr);
_impl->paintSquare(p, rtl() ? (outerWidth - x - size) : x, y, size);
}
StorageKey EmptyUserpic::uniqueKey() const {
Expects(_impl != nullptr);
return _impl->uniqueKey();
}
QPixmap EmptyUserpic::generate(int size) {
auto result = QImage(QSize(size, size) * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(cRetinaFactor());
result.fill(Qt::transparent);
{
Painter p(&result);
paint(p, 0, 0, size, size);
}
return App::pixmapFromImageInPlace(std::move(result));
}
EmptyUserpic::~EmptyUserpic() = default;
} // namespace Data
using UpdateFlag = Notify::PeerUpdate::Flag;
@@ -285,13 +98,11 @@ void PeerClickHandler::onClick(Qt::MouseButton button) const {
}
PeerData::PeerData(const PeerId &id)
: id(id) {
: id(id)
, _userpicEmpty(createEmptyUserpic()) {
nameText.setText(st::msgNameStyle, QString(), _textNameOptions);
_userpicEmpty.set(id, QString());
}
PeerData::~PeerData() = default;
void PeerData::updateNameDelayed(
const QString &newName,
const QString &newNameOrPhone,
@@ -314,9 +125,7 @@ void PeerData::updateNameDelayed(
++nameVersion;
name = newName;
nameText.setText(st::msgNameStyle, name, _textNameOptions);
if (useEmptyUserpic()) {
_userpicEmpty.set(id, name);
}
refreshEmptyUserpic();
Notify::PeerUpdate update(this);
update.flags |= UpdateFlag::NameChanged;
@@ -344,6 +153,16 @@ void PeerData::updateNameDelayed(
Notify::PeerUpdated().notify(update, true);
}
std::unique_ptr<Ui::EmptyUserpic> PeerData::createEmptyUserpic() const {
return std::make_unique<Ui::EmptyUserpic>(
Data::PeerUserpicColor(id),
name);
}
void PeerData::refreshEmptyUserpic() const {
_userpicEmpty = useEmptyUserpic() ? createEmptyUserpic() : nullptr;
}
ClickHandlerPtr PeerData::createOpenLink() {
return MakeShared<PeerClickHandler>(this);
}
@@ -355,11 +174,7 @@ void PeerData::setUserpic(
_userpicPhotoId = photoId;
_userpic = userpic;
_userpicLocation = location;
if (useEmptyUserpic()) {
_userpicEmpty.set(id, name);
} else {
_userpicEmpty.clear();
}
refreshEmptyUserpic();
}
void PeerData::setUserpicPhoto(const MTPPhoto &data) {
@@ -381,7 +196,7 @@ ImagePtr PeerData::currentUserpic() const {
_userpic->load();
if (_userpic->loaded()) {
if (!useEmptyUserpic()) {
_userpicEmpty.clear();
_userpicEmpty = nullptr;
}
return _userpic;
}
@@ -393,7 +208,7 @@ void PeerData::paintUserpic(Painter &p, int x, int y, int size) const {
if (auto userpic = currentUserpic()) {
p.drawPixmap(x, y, userpic->pixCircled(size, size));
} else {
_userpicEmpty.paint(p, x, y, x + size + x, size);
_userpicEmpty->paint(p, x, y, x + size + x, size);
}
}
@@ -401,7 +216,7 @@ void PeerData::paintUserpicRounded(Painter &p, int x, int y, int size) const {
if (auto userpic = currentUserpic()) {
p.drawPixmap(x, y, userpic->pixRounded(size, size, ImageRoundRadius::Small));
} else {
_userpicEmpty.paintRounded(p, x, y, x + size + x, size);
_userpicEmpty->paintRounded(p, x, y, x + size + x, size);
}
}
@@ -409,13 +224,13 @@ void PeerData::paintUserpicSquare(Painter &p, int x, int y, int size) const {
if (auto userpic = currentUserpic()) {
p.drawPixmap(x, y, userpic->pix(size, size));
} else {
_userpicEmpty.paintSquare(p, x, y, x + size + x, size);
_userpicEmpty->paintSquare(p, x, y, x + size + x, size);
}
}
StorageKey PeerData::userpicUniqueKey() const {
if (useEmptyUserpic()) {
return _userpicEmpty.uniqueKey();
return _userpicEmpty->uniqueKey();
}
return storageKey(_userpicLocation);
}
@@ -456,17 +271,6 @@ QPixmap PeerData::genUserpicRounded(int size) const {
return App::pixmapFromImageInPlace(std::move(result));
}
const Text &BotCommand::descriptionText() const {
if (_descriptionText.isEmpty() && !_description.isEmpty()) {
_descriptionText.setText(st::defaultTextStyle, _description, _textNameOptions);
}
return _descriptionText;
}
bool UserData::canShareThisContact() const {
return canShareThisContactFast() || !App::phoneFromSharedContact(peerToUser(id)).isEmpty();
}
void PeerData::updateUserpic(
PhotoId photoId,
const MTPFileLocation &location) {
@@ -498,16 +302,6 @@ void PeerData::clearUserpic() {
}();
}
// see Local::readPeer as well
void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
if (photo.type() == mtpc_userProfilePhoto) {
const auto &data = photo.c_userProfilePhoto();
updateUserpic(data.vphoto_id.v, data.vphoto_small);
} else {
clearUserpic();
}
}
void PeerData::fillNames() {
_nameWords.clear();
_nameFirstChars.clear();
@@ -530,6 +324,29 @@ void PeerData::fillNames() {
}
}
PeerData::~PeerData() = default;
const Text &BotCommand::descriptionText() const {
if (_descriptionText.isEmpty() && !_description.isEmpty()) {
_descriptionText.setText(st::defaultTextStyle, _description, _textNameOptions);
}
return _descriptionText;
}
bool UserData::canShareThisContact() const {
return canShareThisContactFast() || !App::phoneFromSharedContact(peerToUser(id)).isEmpty();
}
// see Local::readPeer as well
void UserData::setPhoto(const MTPUserProfilePhoto &photo) {
if (photo.type() == mtpc_userProfilePhoto) {
const auto &data = photo.c_userProfilePhoto();
updateUserpic(data.vphoto_id.v, data.vphoto_small);
} else {
clearUserpic();
}
}
bool UserData::setAbout(const QString &newAbout) {
if (_about == newAbout) {
return false;