stickers emoji tab done, local cache for stickers, recent stickers and voice messages

This commit is contained in:
John Preston 2015-01-02 17:55:24 +03:00
parent 59381b8ad2
commit 091bba0fc5
41 changed files with 5178 additions and 3470 deletions

View File

@ -163,7 +163,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_notification_preview" = "You have a new message"; "lng_notification_preview" = "You have a new message";
"lng_settings_section_general" = "General"; "lng_settings_section_general" = "General";
"lng_settings_change_lang" = "Change Language"; "lng_settings_change_lang" = "Change language";
"lng_languages" = "Languages"; "lng_languages" = "Languages";
"lng_sure_save_language" = "Telegram will restart\nin order to change language"; "lng_sure_save_language" = "Telegram will restart\nin order to change language";
"lng_settings_auto_update" = "Update automatically"; "lng_settings_auto_update" = "Update automatically";
@ -196,7 +196,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_download_path_label" = "Download path:"; "lng_download_path_label" = "Download path:";
"lng_download_path_temp" = "temp folder"; "lng_download_path_temp" = "temp folder";
"lng_download_path_default" = "default folder"; "lng_download_path_default" = "default folder";
"lng_download_path_clear" = "Clear All"; "lng_download_path_clear" = "Clear all";
"lng_download_path_header" = "Choose download path"; "lng_download_path_header" = "Choose download path";
"lng_download_path_default_radio" = "Telegram folder in system «Downloads»"; "lng_download_path_default_radio" = "Telegram folder in system «Downloads»";
"lng_download_path_temp_radio" = "Temp folder, cleared on logout or uninstall"; "lng_download_path_temp_radio" = "Temp folder, cleared on logout or uninstall";
@ -211,12 +211,13 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_download_path_clear_failed" = "Clear failed :("; "lng_download_path_clear_failed" = "Clear failed :(";
"lng_settings_section_cache" = "Local storage"; "lng_settings_section_cache" = "Local storage";
"lng_settings_no_images_cached" = "No cached images found!"; "lng_settings_no_data_cached" = "No cached data found!";
"lng_settings_images_cached" = "Cached: {count:_not_used_|# image|# images}, {size}"; "lng_settings_images_cached" = "{count:_not_used_|# image|# images}, {size}";
"lng_local_images_clear" = "Clear All"; "lng_settings_audios_cached" = "{count:_not_used_|# voice message|# voice messages}, {size}";
"lng_local_images_clearing" = "Clearing.."; "lng_local_storage_clear" = "Clear all";
"lng_local_images_cleared" = "Cleared!"; "lng_local_storage_clearing" = "Clearing..";
"lng_local_images_clear_failed" = "Clear failed :("; "lng_local_storage_cleared" = "Cleared!";
"lng_local_storage_clear_failed" = "Clear failed :(";
"lng_settings_section_advanced" = "Advanced"; "lng_settings_section_advanced" = "Advanced";
"lng_connection_type" = "Connection type:"; "lng_connection_type" = "Connection type:";

View File

@ -973,7 +973,6 @@ taMsgField: flatTextarea(taDefFlat) {
font: msgFont; font: msgFont;
} }
maxFieldHeight: 250px; maxFieldHeight: 250px;
minFieldHeight: 28px;
newMsgSound: ':/gui/art/newmsg.wav'; newMsgSound: ':/gui/art/newmsg.wav';
@ -1386,6 +1385,9 @@ dpiFont3: linkFont;
dpiFont4: linkFont; dpiFont4: linkFont;
emojiScroll: flatScroll(scrollDef) { emojiScroll: flatScroll(scrollDef) {
width: 5px;
deltax: 2px;
deltay: 1px;
topsh: 0px; topsh: 0px;
bottomsh: 0px; bottomsh: 0px;
} }
@ -1407,12 +1409,15 @@ emojiPlaces: sprite(90px, 197px, 20px, 20px);
emojiSymbolsActive: sprite(290px, 266px, 20px, 20px); emojiSymbolsActive: sprite(290px, 266px, 20px, 20px);
emojiSymbolsOver: sprite(311px, 266px, 20px, 20px); emojiSymbolsOver: sprite(311px, 266px, 20px, 20px);
emojiSymbols: sprite(111px, 197px, 20px, 20px); emojiSymbols: sprite(111px, 197px, 20px, 20px);
emojiStickersActive: sprite(311px, 308px, 20px, 20px);
emojiStickersOver: sprite(354px, 200px, 20px, 20px);
emojiStickers: sprite(375px, 200px, 20px, 20px);
rbEmoji: flatCheckbox { rbEmoji: flatCheckbox {
textColor: transparent; textColor: transparent;
bgColor: transparent; bgColor: transparent;
disColor: transparent; disColor: transparent;
width: 36px; width: 29px;
height: 36px; height: 36px;
textTop: 0px; textTop: 0px;
@ -1423,7 +1428,7 @@ rbEmoji: flatCheckbox {
cursor: cursor(pointer); cursor: cursor(pointer);
disabledCursor: cursor(default); disabledCursor: cursor(default);
imagePos: point(8px, 8px); imagePos: point(5px, 8px);
} }
rbEmojiRecent: flatCheckbox(rbEmoji) { rbEmojiRecent: flatCheckbox(rbEmoji) {
imageRect: emojiRecent; imageRect: emojiRecent;
@ -1473,15 +1478,26 @@ rbEmojiSymbols: flatCheckbox(rbEmoji) {
disImageRect: emojiSymbols; disImageRect: emojiSymbols;
chkDisImageRect: emojiSymbolsActive; chkDisImageRect: emojiSymbolsActive;
} }
emojiPanPadding: margins(10px, 5px, 0px, 5px); rbEmojiStickers: flatCheckbox(rbEmojiRecent) {
imageRect: emojiStickers;
chkImageRect: emojiStickersActive;
overImageRect: emojiStickersOver;
chkOverImageRect: emojiStickersActive;
disImageRect: emojiStickers;
chkDisImageRect: emojiStickersActive;
}
emojiPanPadding: margins(5px, 0px, 0px, 5px);
emojiPanSize: size(28px, 28px); emojiPanSize: size(28px, 28px);
emojiPanFont: font(fsize);
emojiPanText: #999;
emojiPanSub: 0px; emojiPanSub: 0px;
emojiPanDuration: 200; emojiPanDuration: 200;
emojiPanHover: #f0f0f0; emojiPanHover: #f0f0f0;
emojiPanRound: 2px; emojiPanRound: 2px;
stickerPanRound: 3px;
stickerPanPadding: 2px;
stickerPanDelete: sprite(158px, 197px, 12px, 12px);
stickerPanDeleteOpacity: 0.5;
medviewNavBarWidth: 132px; medviewNavBarWidth: 132px;
medviewLightNav: 0.5; medviewLightNav: 0.5;
medviewDarkNav: 1; medviewDarkNav: 1;

View File

@ -73,9 +73,11 @@ Type: filesandordirs; Name: "{userappdata}\{#MyAppName}\tdumps"
Type: dirifempty; Name: "{userappdata}\{#MyAppName}" Type: dirifempty; Name: "{userappdata}\{#MyAppName}"
[Languages] [Languages]
Name: "en"; MessagesFile: "compiler:Default.isl"
Name: "it"; MessagesFile: "compiler:Languages\Italian.isl" Name: "it"; MessagesFile: "compiler:Languages\Italian.isl"
Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl" Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl"
Name: "de"; MessagesFile: "compiler:Languages\German.isl"
Name: "nl"; MessagesFile: "compiler:Languages\Dutch.isl"
Name: "pt"; MessagesFile: "compiler:Languages\Portuguese.isl"
[Code] [Code]
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep); procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);

View File

@ -52,38 +52,41 @@ struct EmojiReplace {
}; };
EmojiReplace replaces[] = { EmojiReplace replaces[] = {
{0xD83DDE0AU, ":-)"}, { 0xD83DDE0AU, ":-)" },
{0xD83DDE03U, ":-D"}, { 0xD83DDE0DU, "8-)" },
{0xD83DDE09U, ";-)"}, { 0x2764U, "<3" },
{0xD83DDE06U, "xD"}, { 0xD83DDC8BU, ":kiss:" },
{0xD83DDE1CU, ";-P"}, { 0xD83DDE01U, ":grin:" },
{0xD83DDE0BU, ":-p"}, { 0xD83DDE02U, ":joy:" },
{0xD83DDE0DU, "8-)"}, { 0xD83DDE1AU, ":-*" },
{0xD83DDE0EU, "B-)"}, { 0xD83DDE06U, "xD" },
{0xD83DDE12U, ":-("}, { 0xD83DDC4DU, ":like:" },
{0xD83DDE0FU, ":]"}, { 0xD83DDC4EU, ":dislike:" },
{0xD83DDE14U, "3("}, { 0x261DU, ":up:" },
{0xD83DDE22U, ":'("}, { 0x270CU, ":v:" },
{0xD83DDE2DU, ":_("}, { 0xD83DDC4CU, ":ok:" },
{0xD83DDE29U, ":(("}, { 0xD83DDE0EU, "B-)" },
{0xD83DDE28U, ":o"}, { 0xD83DDE03U, ":-D" },
{0xD83DDE10U, ":|"}, { 0xD83DDE09U, ";-)" },
{0xD83DDE0CU, "3-)"}, { 0xD83DDE1CU, ";-P" },
{0xD83DDE20U, ">("}, { 0xD83DDE0BU, ":-p" },
{0xD83DDE21U, ">(("}, { 0xD83DDE14U, "3(" },
{0xD83DDE07U, "O:)"}, { 0xD83DDE1EU, ":-(" },
{0xD83DDE30U, ";o"}, { 0xD83DDE0FU, ":]" },
{0xD83DDE33U, "8|"}, { 0xD83DDE22U, ":'(" },
{0xD83DDE32U, "8o"}, { 0xD83DDE2DU, ":_(" },
{0xD83DDE37U, ":X"}, { 0xD83DDE29U, ":((" },
{0xD83DDE1AU, ":-*"}, { 0xD83DDE28U, ":o" },
{0xD83DDE08U, "}:)"}, { 0xD83DDE10U, ":|" },
{0x2764U, "<3"}, { 0xD83DDE0CU, "3-)" },
{0xD83DDC4DU, ":like:"}, { 0xD83DDE20U, ">(" },
{0xD83DDC4EU, ":dislike:"}, { 0xD83DDE21U, ">((" },
{0x261DU, ":up:"}, { 0xD83DDE07U, "O:)" },
{0x270CU, ":v:"}, { 0xD83DDE30U, ";o" },
{0xD83DDC4CU, ":ok:"} { 0xD83DDE33U, "8|" },
{ 0xD83DDE32U, "8o" },
{ 0xD83DDE37U, ":X" },
{ 0xD83DDE08U, "}:)" },
}; };
const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace); const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace);
typedef QMap<QString, uint32> ReplaceMap; typedef QMap<QString, uint32> ReplaceMap;

View File

@ -819,21 +819,21 @@ namespace App {
return App::audio(audio.vid.v, convert, audio.vaccess_hash.v, audio.vuser_id.v, audio.vdate.v, audio.vduration.v, audio.vdc_id.v, audio.vsize.v); return App::audio(audio.vid.v, convert, audio.vaccess_hash.v, audio.vuser_id.v, audio.vdate.v, audio.vduration.v, audio.vdc_id.v, audio.vsize.v);
} }
DocumentData *feedDocument(int32 user, const MTPdocument &document, const QPixmap &thumb) { DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb) {
switch (document.type()) { switch (document.type()) {
case mtpc_document: { case mtpc_document: {
const MTPDdocument &d(document.c_document()); const MTPDdocument &d(document.c_document());
return App::document(d.vid.v, 0, user, d.vaccess_hash.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v); return App::document(d.vid.v, 0, d.vaccess_hash.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v);
} break; } break;
case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v); case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v);
} }
return App::document(0); return App::document(0);
} }
DocumentData *feedDocument(int32 user, const MTPdocument &document, DocumentData *convert) { DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert) {
switch (document.type()) { switch (document.type()) {
case mtpc_document: { case mtpc_document: {
return feedDocument(user, document.c_document(), convert); return feedDocument(document.c_document(), convert);
} break; } break;
case mtpc_documentEmpty: { case mtpc_documentEmpty: {
return App::document(document.c_documentEmpty().vid.v, convert); return App::document(document.c_documentEmpty().vid.v, convert);
@ -842,8 +842,8 @@ namespace App {
return App::document(0); return App::document(0);
} }
DocumentData *feedDocument(int32 user, const MTPDdocument &document, DocumentData *convert) { DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) {
return App::document(document.vid.v, convert, user, document.vaccess_hash.v, document.vdate.v, document.vattributes.c_vector().v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v); return App::document(document.vid.v, convert, document.vaccess_hash.v, document.vdate.v, document.vattributes.c_vector().v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v);
} }
UserData *userLoaded(const PeerId &user) { UserData *userLoaded(const PeerId &user) {
@ -1058,7 +1058,7 @@ namespace App {
return result; return result;
} }
DocumentData *document(const DocumentId &document, DocumentData *convert, int32 user, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) { DocumentData *document(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) {
if (convert) { if (convert) {
if (convert->id != document) { if (convert->id != document) {
DocumentsData::iterator i = documentsData.find(convert->id); DocumentsData::iterator i = documentsData.find(convert->id);
@ -1070,13 +1070,14 @@ namespace App {
} }
convert->access = access; convert->access = access;
if (!convert->date && date) { if (!convert->date && date) {
convert->user = user;
convert->date = date; convert->date = date;
convert->setattributes(attributes); convert->setattributes(attributes);
convert->mime = mime; convert->mime = mime;
convert->thumb = thumb; convert->thumb = thumb;
convert->dc = dc; convert->dc = dc;
convert->size = size; convert->size = size;
} else if (convert->thumb->isNull() && !thumb->isNull()) {
convert->thumb = thumb;
} }
if (convert->location.check()) { if (convert->location.check()) {
@ -1089,20 +1090,23 @@ namespace App {
if (convert) { if (convert) {
result = convert; result = convert;
} else { } else {
result = new DocumentData(user, document, access, date, attributes, mime, thumb, dc, size); result = new DocumentData(document, access, date, attributes, mime, thumb, dc, size);
} }
documentsData.insert(document, result); documentsData.insert(document, result);
} else { } else {
result = i.value(); result = i.value();
if (result != convert && !result->date && date) { if (result != convert) {
result->user = user; if (!result->date && date) {
result->access = access; result->access = access;
result->date = date; result->date = date;
result->setattributes(attributes); result->setattributes(attributes);
result->mime = mime; result->mime = mime;
result->thumb = thumb; result->thumb = thumb;
result->dc = dc; result->dc = dc;
result->size = size; result->size = size;
} else if (result->thumb->isNull() && !thumb->isNull()) {
result->thumb = thumb;
}
} }
} }
return result; return result;
@ -1847,12 +1851,13 @@ namespace App {
qint32 v; qint32 v;
stream >> v; stream >> v;
switch (v) { switch (v) {
case dbietRecent : cSetEmojiTab(dbietRecent); break; case dbietRecent : cSetEmojiTab(dbietRecent); break;
case dbietPeople : cSetEmojiTab(dbietPeople); break; case dbietPeople : cSetEmojiTab(dbietPeople); break;
case dbietNature : cSetEmojiTab(dbietNature); break; case dbietNature : cSetEmojiTab(dbietNature); break;
case dbietObjects: cSetEmojiTab(dbietObjects); break; case dbietObjects : cSetEmojiTab(dbietObjects); break;
case dbietPlaces : cSetEmojiTab(dbietPlaces); break; case dbietPlaces : cSetEmojiTab(dbietPlaces); break;
case dbietSymbols: cSetEmojiTab(dbietSymbols); break; case dbietSymbols : cSetEmojiTab(dbietSymbols); break;
case dbietStickers: cSetEmojiTab(dbietStickers); break;
} }
} break; } break;
@ -2017,13 +2022,16 @@ namespace App {
return result; return result;
} }
QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated) { QImage readImage(const QString &file, QByteArray *format, bool opaque, bool *animated, QByteArray *content) {
QFile f(file); QFile f(file);
if (!f.open(QIODevice::ReadOnly)) { if (!f.open(QIODevice::ReadOnly)) {
if (animated) *animated = false; if (animated) *animated = false;
return QImage(); return QImage();
} }
return readImage(f.readAll(), format, opaque, animated); QByteArray img = f.readAll();
QImage result = readImage(img, format, opaque, animated);
if (content && !result.isNull()) *content = img;
return result;
} }
void regVideoItem(VideoData *data, HistoryItem *item) { void regVideoItem(VideoData *data, HistoryItem *item) {

View File

@ -85,9 +85,9 @@ namespace App {
PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = 0); PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert = 0);
VideoData *feedVideo(const MTPDvideo &video, VideoData *convert = 0); VideoData *feedVideo(const MTPDvideo &video, VideoData *convert = 0);
AudioData *feedAudio(const MTPDaudio &audio, AudioData *convert = 0); AudioData *feedAudio(const MTPDaudio &audio, AudioData *convert = 0);
DocumentData *feedDocument(int32 user, const MTPdocument &document, const QPixmap &thumb); DocumentData *feedDocument(const MTPdocument &document, const QPixmap &thumb);
DocumentData *feedDocument(int32 user, const MTPdocument &document, DocumentData *convert = 0); DocumentData *feedDocument(const MTPdocument &document, DocumentData *convert = 0);
DocumentData *feedDocument(int32 user, const MTPDdocument &document, DocumentData *convert = 0); DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert = 0);
UserData *userLoaded(const PeerId &user); UserData *userLoaded(const PeerId &user);
ChatData *chatLoaded(const PeerId &chat); ChatData *chatLoaded(const PeerId &chat);
@ -106,7 +106,7 @@ namespace App {
PhotoData *photo(const PhotoId &photo, PhotoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &medium = ImagePtr(), const ImagePtr &full = ImagePtr()); PhotoData *photo(const PhotoId &photo, PhotoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &medium = ImagePtr(), const ImagePtr &full = ImagePtr());
VideoData *video(const VideoId &video, VideoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 w = 0, int32 h = 0, const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0); VideoData *video(const VideoId &video, VideoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 w = 0, int32 h = 0, const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
AudioData *audio(const AudioId &audio, AudioData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 dc = 0, int32 size = 0); AudioData *audio(const AudioId &audio, AudioData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 dc = 0, int32 size = 0);
DocumentData *document(const DocumentId &document, DocumentData *convert = 0, int32 user = 0, const uint64 &access = 0, int32 date = 0, const QVector<MTPDocumentAttribute> &attributes = QVector<MTPDocumentAttribute>(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0); DocumentData *document(const DocumentId &document, DocumentData *convert = 0, const uint64 &access = 0, int32 date = 0, const QVector<MTPDocumentAttribute> &attributes = QVector<MTPDocumentAttribute>(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
ImageLinkData *imageLink(const QString &imageLink, ImageLinkType type = InvalidImageLink, const QString &url = QString()); ImageLinkData *imageLink(const QString &imageLink, ImageLinkType type = InvalidImageLink, const QString &url = QString());
void forgetMedia(); void forgetMedia();
@ -169,7 +169,7 @@ namespace App {
void setQuiting(); void setQuiting();
QImage readImage(QByteArray data, QByteArray *format = 0, bool opaque = true, bool *animated = 0); QImage readImage(QByteArray data, QByteArray *format = 0, bool opaque = true, bool *animated = 0);
QImage readImage(const QString &file, QByteArray *format = 0, bool opaque = true, bool *animated = 0); QImage readImage(const QString &file, QByteArray *format = 0, bool opaque = true, bool *animated = 0, QByteArray *content = 0);
void regVideoItem(VideoData *data, HistoryItem *item); void regVideoItem(VideoData *data, HistoryItem *item);
void unregVideoItem(VideoData *data, HistoryItem *item); void unregVideoItem(VideoData *data, HistoryItem *item);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 103 KiB

View File

@ -29,40 +29,43 @@ namespace {
const char *replace; const char *replace;
}; };
EmojiReplace replaces[] = { EmojiReplace replaces[] = {
{0xD83DDE0A, ":-)"}, { 0xD83DDE0AU, ":-)" },
{0xD83DDE03, ":-D"}, { 0xD83DDE0DU, "8-)" },
{0xD83DDE09, ";-)"}, { 0x2764U, "<3" },
{0xD83DDE06, "xD"}, { 0xD83DDC8BU, ":kiss:" },
{0xD83DDE1C, ";-P"}, { 0xD83DDE01U, ":grin:" },
{0xD83DDE0B, ":-p"}, { 0xD83DDE02U, ":joy:" },
{0xD83DDE0D, "8-)"}, { 0xD83DDE1AU, ":-*" },
{0xD83DDE0E, "B-)"}, { 0xD83DDE06U, "xD" },
{0xD83DDE12, ":-("}, { 0xD83DDC4DU, ":like:" },
{0xD83DDE0F, ":]"}, { 0xD83DDC4EU, ":dislike:" },
{0xD83DDE14, "3("}, { 0x261DU, ":up:" },
{0xD83DDE22, ":'("}, { 0x270CU, ":v:" },
{0xD83DDE2D, ":_("}, { 0xD83DDC4CU, ":ok:" },
{0xD83DDE29, ":(("}, { 0xD83DDE0EU, "B-)" },
{0xD83DDE28, ":o"}, { 0xD83DDE03U, ":-D" },
{0xD83DDE10, ":|"}, { 0xD83DDE09U, ";-)" },
{0xD83DDE0C, "3-)"}, { 0xD83DDE1CU, ";-P" },
{0xD83DDE20, ">("}, { 0xD83DDE0BU, ":-p" },
{0xD83DDE21, ">(("}, { 0xD83DDE14U, "3(" },
{0xD83DDE07, "O:)"}, { 0xD83DDE1EU, ":-(" },
{0xD83DDE30, ";o"}, { 0xD83DDE0FU, ":]" },
{0xD83DDE33, "8|"}, { 0xD83DDE22U, ":'(" },
{0xD83DDE32, "8o"}, { 0xD83DDE2DU, ":_(" },
{0xD83DDE37, ":X"}, { 0xD83DDE29U, ":((" },
{0xD83DDE1A, ":-*"}, { 0xD83DDE28U, ":o" },
{0xD83DDE08, "}:)"}, { 0xD83DDE10U, ":|" },
{0x2764, "<3"}, { 0xD83DDE0CU, "3-)" },
{0xD83DDC4D, ":like:"}, { 0xD83DDE20U, ">(" },
{0xD83DDC4E, ":dislike:"}, { 0xD83DDE21U, ">((" },
{0x261D, ":up:"}, { 0xD83DDE07U, "O:)" },
{0x270C, ":v:"}, { 0xD83DDE30U, ";o" },
{0xD83DDC4C, ":ok:"} { 0xD83DDE33U, "8|" },
{ 0xD83DDE32U, "8o" },
{ 0xD83DDE37U, ":X" },
{ 0xD83DDE08U, "}:)" },
}; };
const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace), replacesInRow = 8; const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace), replacesInRow = 7;
} }
EmojiBox::EmojiBox() : _done(this, lang(lng_about_done), st::aboutCloseButton), EmojiBox::EmojiBox() : _done(this, lang(lng_about_done), st::aboutCloseButton),

View File

@ -95,6 +95,8 @@ enum {
PreloadHeightsCount = 3, // when 3 screens to scroll left make a preload request PreloadHeightsCount = 3, // when 3 screens to scroll left make a preload request
EmojiPadPerRow = 7, EmojiPadPerRow = 7,
EmojiPadRowsPerPage = 6, EmojiPadRowsPerPage = 6,
StickerPadPerRow = 3,
StickersUpdateTimeout = 3600000, // update not more than once in an hour
SearchPeopleLimit = 5, SearchPeopleLimit = 5,
MinUsernameLength = 5, MinUsernameLength = 5,

View File

@ -20,6 +20,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "dropdown.h" #include "dropdown.h"
#include "historywidget.h" #include "historywidget.h"
#include "localstorage.h"
#include "lang.h" #include "lang.h"
Dropdown::Dropdown(QWidget *parent) : TWidget(parent), Dropdown::Dropdown(QWidget *parent) : TWidget(parent),
@ -315,39 +316,96 @@ bool DragArea::animStep(float64 ms) {
return res; return res;
} }
EmojiPanInner::EmojiPanInner(QWidget *parent) : QWidget(parent), _tab(cEmojiTab()), _selected(-1), _pressedSel(-1) { EmojiPanInner::EmojiPanInner(QWidget *parent) : QWidget(parent), _tab(cEmojiTab()), _selected(-1), _xSelected(-1), _pressedSel(-1), _xPressedSel(-1) {
resize(EmojiPadPerRow * st::emojiPanSize.width(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub); resize(EmojiPadPerRow * st::emojiPanSize.width(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub);
setMouseTracking(true); setMouseTracking(true);
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
_saveConfigTimer.setSingleShot(true); _saveConfigTimer.setSingleShot(true);
connect(&_saveConfigTimer, SIGNAL(timeout()), this, SLOT(onSaveConfig())); connect(&_saveConfigTimer, SIGNAL(timeout()), this, SLOT(onSaveConfig()));
} }
void EmojiPanInner::paintEvent(QPaintEvent *e) { void EmojiPanInner::paintEvent(QPaintEvent *e) {
QPainter p(this); QPainter p(this);
int32 size = _emojis.size();
QRect r = e ? e->rect() : rect(); QRect r = e ? e->rect() : rect();
int32 rows = (size / EmojiPadPerRow) + ((size % EmojiPadPerRow) ? 1 : 0); if (_tab == dbietStickers) {
int32 fromrow = qMax(qFloor(r.top() / st::emojiPanSize.height()), 0), torow = qMin(qCeil(r.bottom() / st::emojiPanSize.height()) + 1, rows); int32 size = _stickers.size();
for (int32 i = fromrow; i < torow; ++i) { float64 stickerWidth = width() / float64(StickerPadPerRow);
for (int32 j = 0; j < EmojiPadPerRow; ++j) { int32 rows = (size / StickerPadPerRow) + ((size % StickerPadPerRow) ? 1 : 0), stickerSize = int32(stickerWidth);
int32 index = i * EmojiPadPerRow + j; int32 fromrow = qMax(qFloor(r.top() / stickerSize), 0), torow = qMin(qCeil(r.bottom() / stickerSize) + 1, rows);
if (index >= size) break; for (int32 i = fromrow; i < torow; ++i) {
for (int32 j = 0; j < StickerPadPerRow; ++j) {
int32 index = i * StickerPadPerRow + j;
if (index >= size) break;
float64 hover = _hovers[index]; float64 hover = _hovers[index];
QPoint w(j * st::emojiPanSize.width(), i * st::emojiPanSize.height()); QPoint pos(qRound(j * stickerWidth), i * stickerSize);
if (hover > 0) { if (hover > 0) {
p.setOpacity(hover); p.setOpacity(hover);
p.setBrush(st::emojiPanHover->b); p.setBrush(st::emojiPanHover->b);
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
p.drawRoundedRect(QRect(w, st::emojiPanSize), st::emojiPanRound, st::emojiPanRound); p.drawRoundedRect(QRect(pos, QSize(stickerSize, stickerSize)), st::stickerPanRound, st::stickerPanRound);
p.setOpacity(1); p.setOpacity(1);
}
DocumentData *sticker = _stickers[index];
bool already = !sticker->already().isEmpty(), hasdata = !sticker->data.isEmpty();
if (!sticker->loader && sticker->status != FileFailed && !already && !hasdata) {
sticker->save(QString());
}
if (sticker->sticker->isNull() && (already || hasdata)) {
if (already) {
sticker->sticker = ImagePtr(sticker->already());
} else {
sticker->sticker = ImagePtr(sticker->data);
}
}
float64 coef = qMin((stickerWidth - st::stickerPanPadding * 2) / float64(sticker->dimensions.width()), (stickerSize - st::stickerPanPadding * 2) / float64(sticker->dimensions.height()));
int32 w = qRound(coef * sticker->dimensions.width()), h = qRound(coef * sticker->dimensions.height());
QPoint ppos = pos + QPoint((stickerSize - w) / 2, (stickerSize - h) / 2);
if (sticker->sticker->isNull()) {
p.drawPixmap(ppos, sticker->thumb->pix(w));
} else {
p.drawPixmap(ppos, sticker->sticker->pix(w));
}
if (hover > 0 && _isUserGen[index]) {
float64 xHover = _hovers[_stickers.size() + index];
QPoint xPos = pos + QPoint(stickerWidth - st::stickerPanDelete.pxWidth(), 0);
p.setOpacity(hover * (xHover + (1 - xHover) * st::stickerPanDeleteOpacity));
p.drawPixmap(xPos, App::sprite(), st::stickerPanDelete);
p.setOpacity(1);
}
}
}
} else {
int32 size = _emojis.size();
int32 rows = (size / EmojiPadPerRow) + ((size % EmojiPadPerRow) ? 1 : 0);
int32 fromrow = qMax(qFloor(r.top() / st::emojiPanSize.height()), 0), torow = qMin(qCeil(r.bottom() / st::emojiPanSize.height()) + 1, rows);
for (int32 i = fromrow; i < torow; ++i) {
for (int32 j = 0; j < EmojiPadPerRow; ++j) {
int32 index = i * EmojiPadPerRow + j;
if (index >= size) break;
float64 hover = _hovers[index];
QPoint w(j * st::emojiPanSize.width(), i * st::emojiPanSize.height());
if (hover > 0) {
p.setOpacity(hover);
p.setBrush(st::emojiPanHover->b);
p.setPen(Qt::NoPen);
p.drawRoundedRect(QRect(w, st::emojiPanSize), st::emojiPanRound, st::emojiPanRound);
p.setOpacity(1);
}
QRect r(_emojis[index]->x, _emojis[index]->y, st::emojiImgSize, st::emojiImgSize);
p.drawPixmap(w + QPoint((st::emojiPanSize.width() - st::emojiSize) / 2, (st::emojiPanSize.height() - st::emojiSize) / 2), App::emojis(), r);
} }
QRect r(_emojis[index]->x, _emojis[index]->y, st::emojiImgSize, st::emojiImgSize);
p.drawPixmap(w + QPoint((st::emojiPanSize.width() - st::emojiSize) / 2, (st::emojiPanSize.height() - st::emojiSize) / 2), App::emojis(), r);
} }
} }
} }
@ -356,50 +414,70 @@ void EmojiPanInner::mousePressEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos(); _lastMousePos = e->globalPos();
updateSelected(); updateSelected();
_pressedSel = _selected; _pressedSel = _selected;
_xPressedSel = _xSelected;
} }
void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) { void EmojiPanInner::mouseReleaseEvent(QMouseEvent *e) {
_lastMousePos = e->globalPos(); _lastMousePos = e->globalPos();
updateSelected(); updateSelected();
if (_selected == _pressedSel && _selected >= 0 && _selected < _emojis.size()) { if (_xSelected == _xPressedSel && _xSelected >= 0 && _tab == dbietStickers) {
EmojiPtr emoji(_emojis[_selected]); RecentStickerPack recent(cRecentStickers());
RecentEmojiPack recent(cGetRecentEmojis()); DocumentData *sticker = _stickers.at(_xSelected - _stickers.size());
RecentEmojiPack::iterator i = recent.begin(), e = recent.end(); for (int32 i = 0, l = recent.size(); i < l; ++i) {
for (; i != e; ++i) { if (recent.at(i).first == sticker) {
if (i->first == emoji) { recent.removeAt(i);
++i->second; cSetRecentStickers(recent);
if (i->second > 0x8000) { Local::writeRecentStickers();
for (RecentEmojiPack::iterator j = recent.begin(); j != e; ++j) { showEmojiPack(dbietStickers);
if (j->second > 1) { updateSelected();
j->second /= 2; break;
} else { }
j->second = 1; }
} else if (_selected == _pressedSel && _selected >= 0) {
if (_tab == dbietStickers) {
if (_selected < _stickers.size()) {
emit stickerSelected(_stickers[_selected]);
}
} else if (_selected < _emojis.size()) {
EmojiPtr emoji(_emojis[_selected]);
RecentEmojiPack recent(cGetRecentEmojis());
RecentEmojiPack::iterator i = recent.begin(), e = recent.end();
for (; i != e; ++i) {
if (i->first == emoji) {
++i->second;
if (i->second > 0x8000) {
for (RecentEmojiPack::iterator j = recent.begin(); j != e; ++j) {
if (j->second > 1) {
j->second /= 2;
} else {
j->second = 1;
}
} }
} }
for (; i != recent.begin(); --i) {
if ((i - 1)->second > i->second) {
break;
}
qSwap(*i, *(i - 1));
}
break;
} }
for (; i != recent.begin(); --i) { }
if (i == e) {
while (recent.size() >= EmojiPadPerRow * EmojiPadRowsPerPage) recent.pop_back();
recent.push_back(qMakePair(emoji, 1));
for (i = recent.end() - 1; i != recent.begin(); --i) {
if ((i - 1)->second > i->second) { if ((i - 1)->second > i->second) {
break; break;
} }
qSwap(*i, *(i - 1)); qSwap(*i, *(i - 1));
} }
break;
} }
} cSetRecentEmojis(recent);
if (i == e) { _saveConfigTimer.start(SaveRecentEmojisTimeout);
while (recent.size() >= EmojiPadPerRow * EmojiPadRowsPerPage) recent.pop_back();
recent.push_back(qMakePair(emoji, 1));
for (i = recent.end() - 1; i != recent.begin(); --i) {
if ((i - 1)->second > i->second) {
break;
}
qSwap(*i, *(i - 1));
}
}
cSetRecentEmojis(recent);
_saveConfigTimer.start(SaveRecentEmojisTimeout);
emit emojiSelected(emoji); emit emojiSelected(emoji);
}
} }
} }
@ -413,21 +491,50 @@ void EmojiPanInner::mouseMoveEvent(QMouseEvent *e) {
} }
void EmojiPanInner::leaveEvent(QEvent *e) { void EmojiPanInner::leaveEvent(QEvent *e) {
_lastMousePos = QCursor::pos(); clearSelection();
updateSelected(); }
void EmojiPanInner::clearSelection(bool fast) {
_lastMousePos = mapToGlobal(QPoint(-10, -10));
if (fast) {
if (_tab == dbietStickers) {
_hovers = QVector<float64>(_stickers.size() * 2, 0);
} else {
_hovers = QVector<float64>(_emojis.size(), 0);
}
_emojiAnimations.clear();
_selected = _pressedSel = _xSelected = _xPressedSel = -1;
anim::stop(this);
} else {
updateSelected();
}
} }
void EmojiPanInner::updateSelected() { void EmojiPanInner::updateSelected() {
int32 selIndex = -1; int32 selIndex = -1, xSelIndex = -1;
QPoint p(mapFromGlobal(_lastMousePos)); QPoint p(mapFromGlobal(_lastMousePos));
if (p.x() >= 0 && p.y() >= 0 && p.x() < EmojiPadPerRow * st::emojiPanSize.width()) { if (_tab == dbietStickers) {
float64 stickerWidth = width() / float64(StickerPadPerRow);
int32 stickerSize = int32(stickerWidth);
if (p.x() >= 0 && p.y() >= 0 && p.x() < StickerPadPerRow * stickerWidth) {
selIndex = qFloor(p.y() / stickerSize) * StickerPadPerRow + qFloor(p.x() / stickerWidth);
if (selIndex >= _stickers.size()) {
selIndex = -1;
} else {
int32 inx = p.x() - (selIndex % StickerPadPerRow) * stickerWidth, iny = p.y() - ((selIndex / StickerPadPerRow) * stickerSize);
if (inx >= stickerWidth - st::stickerPanDelete.pxWidth() && iny < st::stickerPanDelete.pxHeight()) {
xSelIndex = _stickers.size() + selIndex;
}
}
}
} else if (p.x() >= 0 && p.y() >= 0 && p.x() < EmojiPadPerRow * st::emojiPanSize.width()) {
selIndex = qFloor(p.y() / st::emojiPanSize.height()) * EmojiPadPerRow + qFloor(p.x() / st::emojiPanSize.width()); selIndex = qFloor(p.y() / st::emojiPanSize.height()) * EmojiPadPerRow + qFloor(p.x() / st::emojiPanSize.width());
if (selIndex >= _emojis.size()) { if (selIndex >= _emojis.size()) {
selIndex = -1; selIndex = -1;
} }
} }
bool startanim = false;
if (selIndex != _selected) { if (selIndex != _selected) {
bool startanim = false;
if (_selected >= 0) { if (_selected >= 0) {
_emojiAnimations.remove(_selected + 1); _emojiAnimations.remove(_selected + 1);
if (_emojiAnimations.find(-_selected - 1) == _emojiAnimations.end()) { if (_emojiAnimations.find(-_selected - 1) == _emojiAnimations.end()) {
@ -443,9 +550,26 @@ void EmojiPanInner::updateSelected() {
_emojiAnimations.insert(_selected + 1, getms()); _emojiAnimations.insert(_selected + 1, getms());
} }
} }
if (startanim) anim::start(this);
setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default); setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default);
} }
if (xSelIndex != _xSelected) {
if (_xSelected >= 0) {
_emojiAnimations.remove(_xSelected + 1);
if (_emojiAnimations.find(-_xSelected - 1) == _emojiAnimations.end()) {
if (_emojiAnimations.isEmpty()) startanim = true;
_emojiAnimations.insert(-_xSelected - 1, getms());
}
}
_xSelected = xSelIndex;
if (_xSelected >= 0) {
_emojiAnimations.remove(-_xSelected - 1);
if (_emojiAnimations.find(_xSelected + 1) == _emojiAnimations.end()) {
if (_emojiAnimations.isEmpty()) startanim = true;
_emojiAnimations.insert(_xSelected + 1, getms());
}
}
}
if (startanim) anim::start(this);
} }
bool EmojiPanInner::animStep(float64 ms) { bool EmojiPanInner::animStep(float64 ms) {
@ -466,12 +590,42 @@ bool EmojiPanInner::animStep(float64 ms) {
void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) { void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
_tab = packIndex; _tab = packIndex;
_emojis = emojiPack(packIndex); int32 h, size;
_hovers = QVector<float64>(_emojis.size(), 0); if (packIndex == dbietStickers) {
_emojis.clear();
float64 stickerWidth = width() / float64(StickerPadPerRow);
int32 stickerSize = int32(stickerWidth);
int32 l = cRecentStickers().size();
_stickers.resize(l);
_isUserGen.resize(l);
for (int32 i = 0; i < l; ++i) {
DocumentData *sticker = _stickers[i] = cRecentStickers().at(i).first;
_isUserGen[i] = (cRecentStickers().at(i).second < 0);
if (i < StickerPadPerRow * ((EmojiPadRowsPerPage * st::emojiPanSize.height() - int(st::emojiPanSub)) / stickerSize + 1)) {
bool already = !sticker->already().isEmpty(), hasdata = !sticker->data.isEmpty();
if (!sticker->loader && sticker->status != FileFailed && !already && !hasdata) {
sticker->save(QString());
}
}
}
size = _stickers.size();
h = ((size / StickerPadPerRow) + ((size % StickerPadPerRow) ? 1 : 0)) * stickerSize;
_hovers = QVector<float64>(size * 2, 0);
} else {
_emojis = emojiPack(packIndex);
_stickers.clear();
_isUserGen.clear();
size = _emojis.size();
h = ((size / EmojiPadPerRow) + ((size % EmojiPadPerRow) ? 1 : 0)) * st::emojiPanSize.height();
_hovers = QVector<float64>(size, 0);
}
h = qMax(h, EmojiPadRowsPerPage * st::emojiPanSize.height() - int(st::emojiPanSub));
_emojiAnimations.clear(); _emojiAnimations.clear();
_selected = _pressedSel = -1; _selected = _pressedSel = -1;
int32 size = _emojis.size();
int32 h = qMax(((size / EmojiPadPerRow) + ((size % EmojiPadPerRow) ? 1 : 0)) * st::emojiPanSize.height(), EmojiPadRowsPerPage * st::emojiPanSize.height() - int(st::emojiPanSub));
resize(width(), h); resize(width(), h);
_lastMousePos = QCursor::pos(); _lastMousePos = QCursor::pos();
updateSelected(); updateSelected();
@ -480,18 +634,21 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent), EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent),
_hiding(false), a_opacity(0), _shadow(st::dropdownShadow), _hiding(false), a_opacity(0), _shadow(st::dropdownShadow),
_recent (this, qsl("emoji_group"), dbietRecent , QString(), cEmojiTab() == dbietRecent , st::rbEmojiRecent), _recent (this, qsl("emoji_group"), dbietRecent , QString(), cEmojiTab() == dbietRecent , st::rbEmojiRecent),
_people (this, qsl("emoji_group"), dbietPeople , QString(), cEmojiTab() == dbietPeople , st::rbEmojiPeople), _people (this, qsl("emoji_group"), dbietPeople , QString(), cEmojiTab() == dbietPeople , st::rbEmojiPeople),
_nature (this, qsl("emoji_group"), dbietNature , QString(), cEmojiTab() == dbietNature , st::rbEmojiNature), _nature (this, qsl("emoji_group"), dbietNature , QString(), cEmojiTab() == dbietNature , st::rbEmojiNature),
_objects(this, qsl("emoji_group"), dbietObjects, QString(), cEmojiTab() == dbietObjects, st::rbEmojiObjects), _objects (this, qsl("emoji_group"), dbietObjects , QString(), cEmojiTab() == dbietObjects , st::rbEmojiObjects),
_places (this, qsl("emoji_group"), dbietPlaces , QString(), cEmojiTab() == dbietPlaces , st::rbEmojiPlaces), _places (this, qsl("emoji_group"), dbietPlaces , QString(), cEmojiTab() == dbietPlaces , st::rbEmojiPlaces),
_symbols(this, qsl("emoji_group"), dbietSymbols, QString(), cEmojiTab() == dbietSymbols, st::rbEmojiSymbols), _symbols (this, qsl("emoji_group"), dbietSymbols , QString(), cEmojiTab() == dbietSymbols , st::rbEmojiSymbols),
_stickers(this, qsl("emoji_group"), dbietStickers, QString(), cEmojiTab() == dbietStickers, st::rbEmojiStickers),
_scroll(this, st::emojiScroll), _inner() { _scroll(this, st::emojiScroll), _inner() {
setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus);
_scroll.setFocusPolicy(Qt::NoFocus); _scroll.setFocusPolicy(Qt::NoFocus);
_scroll.viewport()->setFocusPolicy(Qt::NoFocus); _scroll.viewport()->setFocusPolicy(Qt::NoFocus);
_inner.showEmojiPack(cEmojiTab()); if (cEmojiTab() != dbietStickers) {
_inner.showEmojiPack(cEmojiTab());
}
_scroll.setGeometry(st::dropdownPadding.left() + st::emojiPanPadding.left(), st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top(), st::emojiPanPadding.left() + _inner.width() + st::emojiPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub); _scroll.setGeometry(st::dropdownPadding.left() + st::emojiPanPadding.left(), st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top(), st::emojiPanPadding.left() + _inner.width() + st::emojiPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub);
_scroll.setWidget(&_inner); _scroll.setWidget(&_inner);
@ -500,7 +657,7 @@ _scroll(this, st::emojiScroll), _inner() {
_height = st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top() + _scroll.height() + st::emojiPanPadding.bottom() + st::dropdownPadding.bottom(); _height = st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top() + _scroll.height() + st::emojiPanPadding.bottom() + st::dropdownPadding.bottom();
resize(_width, _height); resize(_width, _height);
int32 left = st::dropdownPadding.left() + (_width - st::dropdownPadding.left() - st::dropdownPadding.right() - 6 * _recent.width()) / 2; int32 left = st::dropdownPadding.left() + (_width - st::dropdownPadding.left() - st::dropdownPadding.right() - 7 * _recent.width()) / 2;
int32 top = st::dropdownPadding.top(); int32 top = st::dropdownPadding.top();
_recent.move(left, top); left += _recent.width(); _recent.move(left, top); left += _recent.width();
_people.move(left, top); left += _people.width(); _people.move(left, top); left += _people.width();
@ -508,20 +665,23 @@ _scroll(this, st::emojiScroll), _inner() {
_objects.move(left, top); left += _objects.width(); _objects.move(left, top); left += _objects.width();
_places.move(left, top); left += _places.width(); _places.move(left, top); left += _places.width();
_symbols.move(left, top); left += _symbols.width(); _symbols.move(left, top); left += _symbols.width();
_stickers.move(left, top); left += _stickers.width();
_hideTimer.setSingleShot(true); _hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart())); connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
connect(&_recent , SIGNAL(changed()), this, SLOT(onTabChange())); connect(&_recent , SIGNAL(changed()), this, SLOT(onTabChange()));
connect(&_people , SIGNAL(changed()), this, SLOT(onTabChange())); connect(&_people , SIGNAL(changed()), this, SLOT(onTabChange()));
connect(&_nature , SIGNAL(changed()), this, SLOT(onTabChange())); connect(&_nature , SIGNAL(changed()), this, SLOT(onTabChange()));
connect(&_objects, SIGNAL(changed()), this, SLOT(onTabChange())); connect(&_objects , SIGNAL(changed()), this, SLOT(onTabChange()));
connect(&_places , SIGNAL(changed()), this, SLOT(onTabChange())); connect(&_places , SIGNAL(changed()), this, SLOT(onTabChange()));
connect(&_symbols, SIGNAL(changed()), this, SLOT(onTabChange())); connect(&_symbols , SIGNAL(changed()), this, SLOT(onTabChange()));
connect(&_stickers, SIGNAL(changed()), this, SLOT(onTabChange()));
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSelected())); connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSelected()));
connect(&_inner, SIGNAL(emojiSelected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr))); connect(&_inner, SIGNAL(emojiSelected(EmojiPtr)), this, SIGNAL(emojiSelected(EmojiPtr)));
connect(&_inner, SIGNAL(stickerSelected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*)));
} }
void EmojiPan::paintEvent(QPaintEvent *e) { void EmojiPan::paintEvent(QPaintEvent *e) {
@ -627,14 +787,23 @@ void EmojiPan::showStart() {
show(); show();
a_opacity.start(1); a_opacity.start(1);
anim::start(this); anim::start(this);
if (_stickers.checked()) emit updateStickers();
} }
bool EmojiPan::eventFilter(QObject *obj, QEvent *e) { bool EmojiPan::eventFilter(QObject *obj, QEvent *e) {
if (e->type() == QEvent::Enter) { if (e->type() == QEvent::Enter) {
otherEnter(); //if (dynamic_cast<StickerPan*>(obj)) {
// enterEvent(e);
//} else {
otherEnter();
//}
} else if (e->type() == QEvent::Leave) { } else if (e->type() == QEvent::Leave) {
otherLeave(); //if (dynamic_cast<StickerPan*>(obj)) {
} else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton) { // leaveEvent(e);
//} else {
otherLeave();
//}
} else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton/* && !dynamic_cast<StickerPan*>(obj)*/) {
if (isHidden() || _hiding) { if (isHidden() || _hiding) {
otherEnter(); otherEnter();
} else { } else {
@ -651,6 +820,7 @@ void EmojiPan::showAll() {
_objects.show(); _objects.show();
_places.show(); _places.show();
_symbols.show(); _symbols.show();
_stickers.show();
_scroll.show(); _scroll.show();
} }
@ -661,7 +831,9 @@ void EmojiPan::hideAll() {
_objects.hide(); _objects.hide();
_places.hide(); _places.hide();
_symbols.hide(); _symbols.hide();
_stickers.hide();
_scroll.hide(); _scroll.hide();
_inner.clearSelection(true);
} }
void EmojiPan::onTabChange() { void EmojiPan::onTabChange() {
@ -671,10 +843,341 @@ void EmojiPan::onTabChange() {
else if (_objects.checked()) newTab = dbietObjects; else if (_objects.checked()) newTab = dbietObjects;
else if (_places.checked()) newTab = dbietPlaces; else if (_places.checked()) newTab = dbietPlaces;
else if (_symbols.checked()) newTab = dbietSymbols; else if (_symbols.checked()) newTab = dbietSymbols;
else if (_stickers.checked()) newTab = dbietStickers;
if (newTab != cEmojiTab()) { if (newTab != cEmojiTab()) {
cSetEmojiTab(newTab); cSetEmojiTab(newTab);
App::writeUserConfig(); App::writeUserConfig();
_scroll.scrollToY(0); _scroll.scrollToY(0);
_inner.showEmojiPack(newTab); }
_inner.showEmojiPack(newTab);
if (newTab == dbietStickers) {
emit updateStickers();
} }
} }
//StickerPanInner::StickerPanInner(QWidget *parent) : QWidget(parent), _emoji(0), _selected(-1), _pressedSel(-1) {
// resize(StickerPadPerRow * st::stickerPanSize.width(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub);
// setMouseTracking(true);
// setFocusPolicy(Qt::NoFocus);
//}
//
//void StickerPanInner::paintEvent(QPaintEvent *e) {
// QPainter p(this);
// int32 size = _stickers.size();
//
// QRect r = e ? e->rect() : rect();
//
// int32 rows = (size / StickerPadPerRow) + ((size % StickerPadPerRow) ? 1 : 0);
// int32 fromrow = qMax(qFloor(r.top() / st::stickerPanSize.height()), 0), torow = qMin(qCeil(r.bottom() / st::stickerPanSize.height()) + 1, rows);
// for (int32 i = fromrow; i < torow; ++i) {
// for (int32 j = 0; j < StickerPadPerRow; ++j) {
// int32 index = i * StickerPadPerRow + j;
// if (index >= size) break;
//
// float64 hover = _hovers[index];
// QPoint pos(j * st::stickerPanSize.width(), i * st::stickerPanSize.height());
// if (hover > 0) {
// p.setOpacity(hover);
// p.setBrush(st::stickerPanHover->b);
// p.setPen(Qt::NoPen);
// p.drawRoundedRect(QRect(pos, st::stickerPanSize), st::stickerPanRound, st::stickerPanRound);
// p.setOpacity(1);
// }
//
// DocumentData *data = _stickers[index];
// bool already = !data->already().isEmpty(), hasdata = !data->data.isEmpty();
// if (!data->loader && data->status != FileFailed && !already && !hasdata) {
// data->save(QString());
// }
// if (data->sticker->isNull() && (already || hasdata)) {
// if (already) {
// data->sticker = ImagePtr(data->already());
// } else {
// data->sticker = ImagePtr(data->data);
// }
// }
//
// float64 coef = qMin(st::stickerPanSize.width() / float64(data->dimensions.width()), st::stickerPanSize.height() / float64(data->dimensions.height()));
// int32 w = qRound(coef * data->dimensions.width()), h = qRound(coef * data->dimensions.height());
// pos += QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
//
// if (data->sticker->isNull()) {
// p.drawPixmap(pos, data->thumb->pix(w));
// } else {
// p.drawPixmap(pos, data->sticker->pix(w));
// }
// }
// }
//}
//
//void StickerPanInner::mousePressEvent(QMouseEvent *e) {
// _lastMousePos = e->globalPos();
// updateSelected();
// _pressedSel = _selected;
//}
//
//void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
// _lastMousePos = e->globalPos();
// updateSelected();
// if (_selected == _pressedSel && _selected >= 0 && _selected < _stickers.size()) {
// emit stickerSelected(_stickers[_selected]);
// }
//}
//
//void StickerPanInner::mouseMoveEvent(QMouseEvent *e) {
// _lastMousePos = e->globalPos();
// updateSelected();
//}
//
//void StickerPanInner::leaveEvent(QEvent *e) {
// _lastMousePos = QCursor::pos();
// updateSelected();
//}
//
//void StickerPanInner::updateSelected() {
// int32 selIndex = -1;
// QPoint p(mapFromGlobal(_lastMousePos));
// if (p.x() >= 0 && p.y() >= 0 && p.x() < StickerPadPerRow * st::stickerPanSize.width()) {
// selIndex = qFloor(p.y() / st::stickerPanSize.height()) * StickerPadPerRow + qFloor(p.x() / st::stickerPanSize.width());
// if (selIndex >= _stickers.size()) {
// selIndex = -1;
// }
// }
// if (selIndex != _selected) {
// bool startanim = false;
// if (_selected >= 0) {
// _stickerAnimations.remove(_selected + 1);
// if (_stickerAnimations.find(-_selected - 1) == _stickerAnimations.end()) {
// if (_stickerAnimations.isEmpty()) startanim = true;
// _stickerAnimations.insert(-_selected - 1, getms());
// }
// }
// _selected = selIndex;
// if (_selected >= 0) {
// _stickerAnimations.remove(-_selected - 1);
// if (_stickerAnimations.find(_selected + 1) == _stickerAnimations.end()) {
// if (_stickerAnimations.isEmpty()) startanim = true;
// _stickerAnimations.insert(_selected + 1, getms());
// }
// }
// if (startanim) anim::start(this);
// setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default);
// }
//}
//
//bool StickerPanInner::animStep(float64 ms) {
// uint64 now = getms();
// for (StickerAnimations::iterator i = _stickerAnimations.begin(); i != _stickerAnimations.end();) {
// float64 dt = float64(now - i.value()) / st::emojiPanDuration;
// if (dt >= 1) {
// _hovers[qAbs(i.key()) - 1] = (i.key() > 0) ? 1 : 0;
// i = _stickerAnimations.erase(i);
// } else {
// _hovers[qAbs(i.key()) - 1] = (i.key() > 0) ? dt : (1 - dt);
// ++i;
// }
// }
// update();
// return !_stickerAnimations.isEmpty();
//}
//
//void StickerPanInner::showStickerPack(EmojiPtr emoji) {
// StickerPack stickers = cStickers().value(emoji);
// if (stickers.isEmpty()) {
// _emoji = 0;
// } else {
// _emoji = emoji;
// _stickers = stickers;
// _hovers = QVector<float64>(_stickers.size(), 0);
// _stickerAnimations.clear();
// _selected = _pressedSel = -1;
// int32 size = _stickers.size();
// int32 h = qMax(((size / StickerPadPerRow) + ((size % StickerPadPerRow) ? 1 : 0)) * st::stickerPanSize.height(), EmojiPadRowsPerPage * st::emojiPanSize.height() - int(st::emojiPanSub));
// resize(width(), h);
// _lastMousePos = QCursor::pos();
// updateSelected();
// update();
// }
//}
//
//bool StickerPanInner::hasContent() const {
// return !!_emoji;
//}
//
//StickerPan::StickerPan(QWidget *parent) : TWidget(parent),
//_hiding(false), a_opacity(0), _shadow(st::dropdownShadow),
//_scroll(this, st::emojiScroll), _emoji(0), _inner() {
// setFocusPolicy(Qt::NoFocus);
// _scroll.setFocusPolicy(Qt::NoFocus);
// _scroll.viewport()->setFocusPolicy(Qt::NoFocus);
//
// _inner.showStickerPack(0);
// _scroll.setGeometry(st::dropdownPadding.left() + st::stickerPanPadding.left(), st::dropdownPadding.top() + st::rbEmoji.height + st::stickerPanPadding.top(), st::stickerPanPadding.left() + _inner.width() + st::stickerPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub);
// _scroll.setWidget(&_inner);
//
// _width = st::dropdownPadding.left() + st::stickerPanPadding.left() + _scroll.width() + st::stickerPanPadding.right() + st::dropdownPadding.right();
// _height = st::dropdownPadding.top() + st::rbEmoji.height + st::stickerPanPadding.top() + _scroll.height() + st::stickerPanPadding.bottom() + st::dropdownPadding.bottom();
// resize(_width, _height);
//
// _hideTimer.setSingleShot(true);
// connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
//
// connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSelected()));
//
// connect(&_inner, SIGNAL(stickerSelected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*)));
//}
//
//void StickerPan::setStickerPack(EmojiPtr emoji, bool show) {
// _emoji = emoji;
// _inner.showStickerPack(_emoji);
// if (!_hiding && !isHidden() && !_inner.hasContent()) {
// _hideTimer.stop();
// hideStart();
// } else if ((_hiding || isHidden()) && _inner.hasContent() && show) {
// _hideTimer.stop();
// showStart();
// }
//}
//
//void StickerPan::paintEvent(QPaintEvent *e) {
// QPainter p(this);
//
// if (!_cache.isNull()) {
// p.setOpacity(a_opacity.current());
// }
//
// QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom());
//
// // draw shadow
// _shadow.paint(p, r);
//
// if (_cache.isNull()) {
// p.fillRect(r, st::white->b);
//
// p.setFont(st::stickerPanFont->f);
// p.setPen(st::stickerPanColor->p);
// p.drawText(QRect(st::dropdownPadding.left(), st::dropdownPadding.top(), width() - st::dropdownPadding.left() - st::dropdownPadding.right(), st::rbEmoji.height), lang(lng_attach_stickers_header), style::al_center);
// } else {
// p.drawPixmap(r.left(), r.top(), _cache);
// }
//}
//
//void StickerPan::enterEvent(QEvent *e) {
// _hideTimer.stop();
// if (_hiding) showStart();
//}
//
//void StickerPan::leaveEvent(QEvent *e) {
// if (animating()) {
// hideStart();
// } else {
// _hideTimer.start(300);
// }
//}
//
//void StickerPan::otherEnter() {
// _hideTimer.stop();
// showStart();
//}
//
//void StickerPan::otherLeave() {
// if (animating()) {
// hideStart();
// } else {
// _hideTimer.start(0);
// }
//}
//
//void StickerPan::fastHide() {
// if (animating()) {
// anim::stop(this);
// }
// a_opacity = anim::fvalue(0, 0);
// _hideTimer.stop();
// hide();
// _cache = QPixmap();
//}
//
//bool StickerPan::animStep(float64 ms) {
// float64 dt = ms / 150;
// bool res = true;
// if (dt >= 1) {
// a_opacity.finish();
// if (_hiding) {
// hideFinish();
// } else {
// showAll();
// _cache = QPixmap();
// }
// res = false;
// } else {
// a_opacity.update(dt, anim::linear);
// }
// update();
// return res;
//}
//
//void StickerPan::hideStart() {
// if (_cache.isNull()) {
// showAll();
// _cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding));
// }
// hideAll();
// _hiding = true;
// a_opacity.start(0);
// anim::start(this);
//}
//
//void StickerPan::hideFinish() {
// hide();
// _cache = QPixmap();
//}
//
//void StickerPan::showStart() {
// if (!isHidden() && a_opacity.current() == 1) {
// return;
// }
// if (!_inner.hasContent()) {
// return;
// }
// if (_cache.isNull()) {
// showAll();
// _cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding));
// }
// hideAll();
// _hiding = false;
// show();
// a_opacity.start(1);
// anim::start(this);
//}
//
//bool StickerPan::eventFilter(QObject *obj, QEvent *e) {
// if (e->type() == QEvent::Enter) {
// if (dynamic_cast<EmojiPan*>(obj)) {
// enterEvent(e);
// } else {
// otherEnter();
// }
// } else if (e->type() == QEvent::Leave) {
// if (dynamic_cast<EmojiPan*>(obj)) {
// leaveEvent(e);
// } else {
// otherLeave();
// }
// } else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton && !dynamic_cast<EmojiPan*>(obj)) {
// if (isHidden() || _hiding) {
// otherEnter();
// } else {
// otherLeave();
// }
// }
// return false;
//}
//
//void StickerPan::showAll() {
// _scroll.show();
//}
//
//void StickerPan::hideAll() {
// _scroll.hide();
//}

View File

@ -134,6 +134,8 @@ public:
void showEmojiPack(DBIEmojiTab packIndex); void showEmojiPack(DBIEmojiTab packIndex);
void clearSelection(bool fast = false);
public slots: public slots:
void updateSelected(); void updateSelected();
@ -142,17 +144,20 @@ public slots:
signals: signals:
void emojiSelected(EmojiPtr emoji); void emojiSelected(EmojiPtr emoji);
void stickerSelected(DocumentData *sticker);
private: private:
typedef QMap<int32, uint64> EmojiAnimations; // index - showing, -index - hiding typedef QMap<int32, uint64> EmojiAnimations; // index - showing, -index - hiding
EmojiAnimations _emojiAnimations; EmojiAnimations _emojiAnimations;
StickerPack _stickers;
QVector<bool> _isUserGen;
QVector<EmojiPtr> _emojis; QVector<EmojiPtr> _emojis;
QVector<float64> _hovers; QVector<float64> _hovers;
DBIEmojiTab _tab; DBIEmojiTab _tab;
int32 _selected, _pressedSel; int32 _selected, _xSelected, _pressedSel, _xPressedSel;
QPoint _lastMousePos; QPoint _lastMousePos;
QTimer _saveConfigTimer; QTimer _saveConfigTimer;
@ -174,6 +179,9 @@ public:
void otherLeave(); void otherLeave();
void fastHide(); void fastHide();
bool hiding() const {
return _hiding || _hideTimer.isActive();
}
bool animStep(float64 ms); bool animStep(float64 ms);
@ -191,6 +199,8 @@ public slots:
signals: signals:
void emojiSelected(EmojiPtr emoji); void emojiSelected(EmojiPtr emoji);
void stickerSelected(DocumentData *sticker);
void updateStickers();
private: private:
@ -207,10 +217,104 @@ private:
BoxShadow _shadow; BoxShadow _shadow;
FlatRadiobutton _recent, _people, _nature, _objects, _places, _symbols; FlatRadiobutton _recent, _people, _nature, _objects, _places, _symbols, _stickers;
int32 _emojiPack; int32 _emojiPack;
ScrollArea _scroll; ScrollArea _scroll;
EmojiPanInner _inner; EmojiPanInner _inner;
}; };
//class StickerPanInner : public QWidget, public Animated {
// Q_OBJECT
//
//public:
//
// StickerPanInner(QWidget *parent = 0);
//
// void paintEvent(QPaintEvent *e);
//
// void mousePressEvent(QMouseEvent *e);
// void mouseReleaseEvent(QMouseEvent *e);
// void mouseMoveEvent(QMouseEvent *e);
// void leaveEvent(QEvent *e);
//
// bool animStep(float64 ms);
//
// void showStickerPack(EmojiPtr emoji);
// bool hasContent() const;
//
//public slots:
//
// void updateSelected();
//
//signals:
//
// void stickerSelected(DocumentData *sticker);
//
//private:
//
// typedef QMap<int32, uint64> StickerAnimations; // index - showing, -index - hiding
// StickerAnimations _stickerAnimations;
//
// StickerPack _stickers;
// QVector<float64> _hovers;
//
// EmojiPtr _emoji;
// int32 _selected, _pressedSel;
// QPoint _lastMousePos;
//
//};
//
//class StickerPan : public TWidget, public Animated {
// Q_OBJECT
//
//public:
//
// StickerPan(QWidget *parent);
//
// void setStickerPack(EmojiPtr emoji, bool show);
// void paintEvent(QPaintEvent *e);
//
// void enterEvent(QEvent *e);
// void leaveEvent(QEvent *e);
// void otherEnter();
// void otherLeave();
//
// void fastHide();
//
// bool animStep(float64 ms);
//
// bool eventFilter(QObject *obj, QEvent *e);
//
//public slots:
//
// void hideStart();
// void hideFinish();
//
// void showStart();
//
//signals:
//
// void stickerSelected(DocumentData *sticker);
//
//private:
//
// void showAll();
// void hideAll();
//
// int32 _width, _height;
// bool _hiding;
// QPixmap _cache;
//
// anim::fvalue a_opacity;
//
// QTimer _hideTimer;
//
// BoxShadow _shadow;
//
// EmojiPtr _emoji;
// ScrollArea _scroll;
// StickerPanInner _inner;
//
//};

View File

@ -32,9 +32,9 @@ void FileUploader::uploadMedia(MsgId msgId, const ReadyLocalMedia &media) {
} else if (media.type == ToPrepareDocument) { } else if (media.type == ToPrepareDocument) {
DocumentData *document; DocumentData *document;
if (media.photoThumbs.isEmpty()) { if (media.photoThumbs.isEmpty()) {
document = App::feedDocument(MTP::authedId(), media.document); document = App::feedDocument(media.document);
} else { } else {
document = App::feedDocument(MTP::authedId(), media.document, media.photoThumbs.begin().value()); document = App::feedDocument(media.document, media.photoThumbs.begin().value());
} }
document->status = FileUploading; document->status = FileUploading;
if (!media.file.isEmpty()) { if (!media.file.isEmpty()) {

View File

@ -4512,6 +4512,71 @@ void findEmoji(const QChar *ch, const QChar *e, const QChar *&newEmojiEnd, uint3
break; break;
} }
break; break;
case 'k':
if (ch + 2 != e) switch ((ch + 2)->unicode()) {
case 'i':
if (ch + 3 != e) switch ((ch + 3)->unicode()) {
case 's':
if (ch + 4 != e) switch ((ch + 4)->unicode()) {
case 's':
if (ch + 5 != e) switch ((ch + 5)->unicode()) {
case ':':
newEmojiEnd = ch + 6;
if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') {
emojiCode = 0xD83DDC8BU;
return;
}
break;
}
break;
}
break;
}
break;
}
break;
case 'j':
if (ch + 2 != e) switch ((ch + 2)->unicode()) {
case 'o':
if (ch + 3 != e) switch ((ch + 3)->unicode()) {
case 'y':
if (ch + 4 != e) switch ((ch + 4)->unicode()) {
case ':':
newEmojiEnd = ch + 5;
if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') {
emojiCode = 0xD83DDE02U;
return;
}
break;
}
break;
}
break;
}
break;
case 'g':
if (ch + 2 != e) switch ((ch + 2)->unicode()) {
case 'r':
if (ch + 3 != e) switch ((ch + 3)->unicode()) {
case 'i':
if (ch + 4 != e) switch ((ch + 4)->unicode()) {
case 'n':
if (ch + 5 != e) switch ((ch + 5)->unicode()) {
case ':':
newEmojiEnd = ch + 6;
if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') {
emojiCode = 0xD83DDE01U;
return;
}
break;
}
break;
}
break;
}
break;
}
break;
case 'd': case 'd':
if (ch + 2 != e) switch ((ch + 2)->unicode()) { if (ch + 2 != e) switch ((ch + 2)->unicode()) {
case 'i': case 'i':
@ -4605,7 +4670,7 @@ void findEmoji(const QChar *ch, const QChar *e, const QChar *&newEmojiEnd, uint3
case '(': case '(':
newEmojiEnd = ch + 3; newEmojiEnd = ch + 3;
if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') { if (newEmojiEnd == e || emojiEdge(newEmojiEnd) || newEmojiEnd->unicode() == ' ') {
emojiCode = 0xD83DDE12U; emojiCode = 0xD83DDE1EU;
return; return;
} }
break; break;

View File

@ -166,6 +166,75 @@ QSize FlatTextarea::minimumSizeHint() const {
return geometry().size(); return geometry().size();
} }
EmojiPtr FlatTextarea::getSingleEmoji() const {
QString text;
QTextFragment fragment;
getSingleEmojiFragment(text, fragment);
if (!text.isEmpty()) {
QString imageName = static_cast<const QTextImageFormat*>(&fragment.charFormat())->name();
return getEmoji(imageName.mid(8).toUInt(0, 16));
}
return 0;
}
void FlatTextarea::getSingleEmojiFragment(QString &text, QTextFragment &fragment) const {
int32 end = textCursor().position(), start = end - 1;
if (textCursor().anchor() != end) return;
if (start < 0) start = 0;
QTextDocument *doc(document());
QTextBlock from = doc->findBlock(start), till = doc->findBlock(end);
if (till.isValid()) till = till.next();
for (QTextBlock b = from; b != till; b = b.next()) {
for (QTextBlock::Iterator iter = b.begin(); !iter.atEnd(); ++iter) {
QTextFragment fr(iter.fragment());
if (!fr.isValid()) continue;
int32 p = fr.position(), e = (p + fr.length());
if (p >= end || e <= start) {
continue;
}
QTextCharFormat f = fr.charFormat();
QString t(fr.text());
if (p < start) {
t = t.mid(start - p, end - start);
} else if (e > end) {
t = t.mid(0, end - p);
}
if (f.isImageFormat() && !t.isEmpty() && t.at(0).unicode() == QChar::ObjectReplacementCharacter) {
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
if (imageName.midRef(0, 8) == qsl("emoji://")) {
fragment = fr;
text = t;
return;
}
}
return;
}
}
return;
}
void FlatTextarea::removeSingleEmoji() {
QString text;
QTextFragment fragment;
getSingleEmojiFragment(text, fragment);
if (!text.isEmpty()) {
QTextCursor t(textCursor());
t.setPosition(fragment.position());
t.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
t.removeSelectedText();
setTextCursor(t);
}
}
QString FlatTextarea::getText(int32 start, int32 end) const { QString FlatTextarea::getText(int32 start, int32 end) const {
if (end >= 0 && end <= start) return QString(); if (end >= 0 && end <= start) return QString();

View File

@ -48,6 +48,8 @@ public:
QSize sizeHint() const; QSize sizeHint() const;
QSize minimumSizeHint() const; QSize minimumSizeHint() const;
EmojiPtr getSingleEmoji() const;
void removeSingleEmoji();
QString getText(int32 start = 0, int32 end = -1) const; QString getText(int32 start = 0, int32 end = -1) const;
bool hasText() const; bool hasText() const;
@ -77,6 +79,7 @@ protected:
private: private:
void getSingleEmojiFragment(QString &text, QTextFragment &fragment) const;
void processDocumentContentsChange(int position, int charsAdded); void processDocumentContentsChange(int position, int charsAdded);
QMimeData *createMimeDataFromSelection() const; QMimeData *createMimeDataFromSelection() const;

View File

@ -330,7 +330,7 @@ void Image::invalidateSizeCache() const {
} }
LocalImage::LocalImage(const QString &file, QByteArray fmt) { LocalImage::LocalImage(const QString &file, QByteArray fmt) {
data = QPixmap::fromImage(App::readImage(file, &fmt, false), Qt::ColorOnly); data = QPixmap::fromImage(App::readImage(file, &fmt, false, 0, &saved), Qt::ColorOnly);
format = fmt; format = fmt;
if (!data.isNull()) { if (!data.isNull()) {
globalAquiredSize += int64(data.width()) * data.height() * 4; globalAquiredSize += int64(data.width()) * data.height() * 4;

View File

@ -4212,7 +4212,7 @@ LinkRanges textParseLinks(const QString &text, bool rich) {
} }
} }
if (p > domainEnd) { // check, that domain ended if (p > domainEnd) { // check, that domain ended
if (domainEnd->unicode() != '/') { if (domainEnd->unicode() != '/' && domainEnd->unicode() != '?') {
matchOffset = domainEnd - start; matchOffset = domainEnd - start;
continue; continue;
} }

View File

@ -720,8 +720,8 @@ void DocumentCancelLink::onClick(Qt::MouseButton button) const {
data->cancel(); data->cancel();
} }
DocumentData::DocumentData(int32 user, const DocumentId &id, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) : DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) :
user(user), id(id), type(FileDocument), duration(0), access(access), date(date), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0) { id(id), type(FileDocument), duration(0), access(access), date(date), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
setattributes(attributes); setattributes(attributes);
location = Local::readFileLocation(mediaKey(mtpc_inputDocumentFileLocation, dc, id)); location = Local::readFileLocation(mediaKey(mtpc_inputDocumentFileLocation, dc, id));
} }
@ -1289,27 +1289,14 @@ HistoryItem *History::createItemForwarded(HistoryBlock *block, MsgId id, History
return regItem(result); return regItem(result);
} }
/* HistoryItem *History::createItemDocument(HistoryBlock *block, MsgId id, bool out, bool unread, QDateTime date, int32 from, DocumentData *doc) {
HistoryItem *History::createItem(HistoryBlock *block, const MTPgeoChatMessage &msg, bool newMsg) {
HistoryItem *result = 0; HistoryItem *result = 0;
switch (msg.type()) { result = new HistoryMessage(this, block, id, out, unread, date, from, doc);
case mtpc_geoChatMessageEmpty:
result = new HistoryServiceMsg(this, block, msg.c_geoChatMessageEmpty().vid.v, date(), lang(lng_message_empty));
break;
case mtpc_geoChatMessage:
result = new HistoryMessage(this, block, msg.c_geoChatMessage());
break;
case mtpc_geoChatMessageService:
result = new HistoryServiceMsg(this, block, msg.c_geoChatMessageService());
break;
}
return regItem(result); return regItem(result);
} }
/**/
HistoryItem *History::addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out, bool unread, HistoryMedia *media, bool newMsg) { HistoryItem *History::addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out, bool unread, HistoryMedia *media, bool newMsg) {
HistoryBlock *to = 0; HistoryBlock *to = 0;
bool newBlock = isEmpty(); bool newBlock = isEmpty();
@ -1348,8 +1335,7 @@ HistoryItem *History::addToBackForwarded(MsgId id, HistoryMessage *item) {
return doAddToBack(to, newBlock, createItemForwarded(to, id, item), true); return doAddToBack(to, newBlock, createItemForwarded(to, id, item), true);
} }
/* HistoryItem *History::addToBackDocument(MsgId id, bool out, bool unread, QDateTime date, int32 from, DocumentData *doc) {
HistoryItem *History::addToBack(const MTPgeoChatMessage &msg, bool newMsg) {
HistoryBlock *to = 0; HistoryBlock *to = 0;
bool newBlock = isEmpty(); bool newBlock = isEmpty();
if (newBlock) { if (newBlock) {
@ -1357,10 +1343,8 @@ HistoryItem *History::addToBack(const MTPgeoChatMessage &msg, bool newMsg) {
} else { } else {
to = back(); to = back();
} }
return doAddToBack(to, newBlock, createItemDocument(to, id, out, unread, date, from, doc), true);
return doAddToBack(to, newBlock, createItem(to, msg, newMsg), newMsg);
} }
/**/
void History::createInitialDateBlock(const QDateTime &date) { void History::createInitialDateBlock(const QDateTime &date) {
HistoryBlock *dateBlock = new HistoryBlock(this); // date block HistoryBlock *dateBlock = new HistoryBlock(this); // date block
@ -2988,7 +2972,7 @@ void HistoryDocument::unregItem(HistoryItem *item) {
void HistoryDocument::updateFrom(const MTPMessageMedia &media) { void HistoryDocument::updateFrom(const MTPMessageMedia &media) {
if (media.type() == mtpc_messageMediaDocument) { if (media.type() == mtpc_messageMediaDocument) {
App::feedDocument(data->user, media.c_messageMediaDocument().vdocument, data); App::feedDocument(media.c_messageMediaDocument().vdocument, data);
} }
} }
@ -3096,6 +3080,7 @@ void HistorySticker::initDimensions(const HistoryItem *parent) {
void HistorySticker::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const { void HistorySticker::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
if (width < 0) width = w; if (width < 0) width = w;
if (width < 1) return; if (width < 1) return;
if (width > _maxw) width = _maxw;
bool out = parent->out(), hovered, pressed, already = !data->already().isEmpty(), hasdata = !data->data.isEmpty(); bool out = parent->out(), hovered, pressed, already = !data->already().isEmpty(), hasdata = !data->data.isEmpty();
if (!data->loader && data->status != FileFailed && !already && !hasdata) { if (!data->loader && data->status != FileFailed && !already && !hasdata) {
@ -3158,7 +3143,8 @@ void HistorySticker::unregItem(HistoryItem *item) {
void HistorySticker::updateFrom(const MTPMessageMedia &media) { void HistorySticker::updateFrom(const MTPMessageMedia &media) {
if (media.type() == mtpc_messageMediaDocument) { if (media.type() == mtpc_messageMediaDocument) {
App::feedDocument(data->user, media.c_messageMediaDocument().vdocument, data); App::feedDocument(media.c_messageMediaDocument().vdocument, data);
if (App::main()) App::main()->incrementSticker(data);
} }
} }
@ -3944,12 +3930,22 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgI
, _textHeight(0) , _textHeight(0)
, _media(0) , _media(0)
{ {
QString text(msg);
if (fromMedia) { if (fromMedia) {
_media = fromMedia->clone(); _media = fromMedia->clone();
_media->regItem(this); _media->regItem(this);
} }
initDimensions(text); initDimensions(msg);
}
HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, DocumentData *doc) :
HistoryItem(history, block, msgId, out, unread, date, from)
, _text(st::msgMinWidth)
, _textWidth(0)
, _textHeight(0)
, _media(0)
{
initMediaFromDocument(doc);
initDimensions(QString());
} }
void HistoryMessage::initMedia(const MTPMessageMedia &media, QString &currentText) { void HistoryMessage::initMedia(const MTPMessageMedia &media, QString &currentText) {
@ -3993,12 +3989,8 @@ void HistoryMessage::initMedia(const MTPMessageMedia &media, QString &currentTex
case mtpc_messageMediaDocument: { case mtpc_messageMediaDocument: {
const MTPDocument &document(media.c_messageMediaDocument().vdocument); const MTPDocument &document(media.c_messageMediaDocument().vdocument);
if (document.type() == mtpc_document) { if (document.type() == mtpc_document) {
DocumentData *doc = App::feedDocument(_from->id, document); DocumentData *doc = App::feedDocument(document);
if (doc->type == StickerDocument && doc->dimensions.width() > 0 && doc->dimensions.height() > 0 && doc->size < StickerInMemory) { return initMediaFromDocument(doc);
_media = new HistorySticker(doc);
} else {
_media = new HistoryDocument(doc);
}
} }
} break; } break;
case mtpc_messageMediaUnsupported: case mtpc_messageMediaUnsupported:
@ -4007,6 +3999,15 @@ void HistoryMessage::initMedia(const MTPMessageMedia &media, QString &currentTex
if (_media) _media->regItem(this); if (_media) _media->regItem(this);
} }
void HistoryMessage::initMediaFromDocument(DocumentData *doc) {
if (doc->type == StickerDocument && doc->dimensions.width() > 0 && doc->dimensions.height() > 0 && doc->size < StickerInMemory) {
_media = new HistorySticker(doc);
} else {
_media = new HistoryDocument(doc);
}
_media->regItem(this);
}
void HistoryMessage::initDimensions(const QString &text) { void HistoryMessage::initDimensions(const QString &text) {
_time = date.toString(qsl("hh:mm")); _time = date.toString(qsl("hh:mm"));
_timeWidth = st::msgDateFont->m.width(_time); _timeWidth = st::msgDateFont->m.width(_time);

View File

@ -399,7 +399,7 @@ enum DocumentType {
AnimatedDocument AnimatedDocument
}; };
struct DocumentData { struct DocumentData {
DocumentData(int32 user, const DocumentId &id, const uint64 &access = 0, int32 date = 0, const QVector<MTPDocumentAttribute> &attributes = QVector<MTPDocumentAttribute>(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0); DocumentData(const DocumentId &id, const uint64 &access = 0, int32 date = 0, const QVector<MTPDocumentAttribute> &attributes = QVector<MTPDocumentAttribute>(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
void setattributes(const QVector<MTPDocumentAttribute> &attributes); void setattributes(const QVector<MTPDocumentAttribute> &attributes);
void forget() { void forget() {
@ -435,8 +435,6 @@ struct DocumentData {
QString already(bool check = false); QString already(bool check = false);
int32 user;
DocumentId id; DocumentId id;
DocumentType type; DocumentType type;
QSize dimensions; QSize dimensions;
@ -640,12 +638,14 @@ struct History : public QList<HistoryBlock*> {
HistoryItem *createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg, bool returnExisting = false); HistoryItem *createItem(HistoryBlock *block, const MTPmessage &msg, bool newMsg, bool returnExisting = false);
HistoryItem *createItemForwarded(HistoryBlock *block, MsgId id, HistoryMessage *msg); HistoryItem *createItemForwarded(HistoryBlock *block, MsgId id, HistoryMessage *msg);
// HistoryItem *createItem(HistoryBlock *block, const MTPgeoChatMessage &msg, bool newMsg); HistoryItem *createItemDocument(HistoryBlock *block, MsgId id, bool out, bool unread, QDateTime date, int32 from, DocumentData *doc);
HistoryItem *addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out = false, bool unread = false, HistoryMedia *media = 0, bool newMsg = true); HistoryItem *addToBackService(MsgId msgId, QDateTime date, const QString &text, bool out = false, bool unread = false, HistoryMedia *media = 0, bool newMsg = true);
HistoryItem *addToBack(const MTPmessage &msg, bool newMsg = true); HistoryItem *addToBack(const MTPmessage &msg, bool newMsg = true);
HistoryItem *addToHistory(const MTPmessage &msg); HistoryItem *addToHistory(const MTPmessage &msg);
HistoryItem *addToBackForwarded(MsgId id, HistoryMessage *item); HistoryItem *addToBackForwarded(MsgId id, HistoryMessage *item);
// HistoryItem *addToBack(const MTPgeoChatMessage &msg, bool newMsg = true); HistoryItem *addToBackDocument(MsgId id, bool out, bool unread, QDateTime date, int32 from, DocumentData *doc);
void addToFront(const QVector<MTPMessage> &slice); void addToFront(const QVector<MTPMessage> &slice);
void addToBack(const QVector<MTPMessage> &slice); void addToBack(const QVector<MTPMessage> &slice);
void createInitialDateBlock(const QDateTime &date); void createInitialDateBlock(const QDateTime &date);
@ -1549,8 +1549,10 @@ public:
HistoryMessage(History *history, HistoryBlock *block, const MTPDmessage &msg); HistoryMessage(History *history, HistoryBlock *block, const MTPDmessage &msg);
HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg, const MTPMessageMedia &media); HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg, const MTPMessageMedia &media);
HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg, HistoryMedia *media); HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, const QString &msg, HistoryMedia *media);
HistoryMessage(History *history, HistoryBlock *block, MsgId msgId, bool out, bool unread, QDateTime date, int32 from, DocumentData *doc);
void initMedia(const MTPMessageMedia &media, QString &currentText); void initMedia(const MTPMessageMedia &media, QString &currentText);
void initMediaFromDocument(DocumentData *doc);
void initDimensions(const HistoryItem *parent = 0); void initDimensions(const HistoryItem *parent = 0);
void initDimensions(const QString &text); void initDimensions(const QString &text);
void fromNameUpdated() const; void fromNameUpdated() const;

View File

@ -1233,11 +1233,11 @@ MessageField::MessageField(HistoryWidget *history, const style::flatTextarea &st
} }
void MessageField::onChange() { void MessageField::onChange() {
int newh = ceil(document()->size().height()) + 2 * fakeMargin(); int newh = ceil(document()->size().height()) + 2 * fakeMargin(), minh = st::btnSend.height - 2 * st::sendPadding;
if (newh > st::maxFieldHeight) { if (newh > st::maxFieldHeight) {
newh = st::maxFieldHeight; newh = st::maxFieldHeight;
} else if (newh < st::minFieldHeight) { } else if (newh < minh) {
newh = st::minFieldHeight; newh = minh;
} }
if (height() != newh) { if (height() != newh) {
@ -1533,41 +1533,44 @@ HistoryHider::~HistoryHider() {
} }
HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent) HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
, histRequestsCount(0) , _lastStickersUpdate(0)
, histPeer(0) , _stickersUpdateRequest(0)
, _activeHist(0) , histRequestsCount(0)
, histPreloading(0) , histPeer(0)
, _loadingAroundId(-1) , _activeHist(0)
, _loadingAroundRequest(0) , histPreloading(0)
, _scroll(this, st::historyScroll, false) , _loadingAroundId(-1)
, _list(0) , _loadingAroundRequest(0)
, hist(0) , _scroll(this, st::historyScroll, false)
, _histInited(false) , _list(0)
, _toHistoryEnd(this, st::historyToEnd) , hist(0)
, _send(this, lang(lng_send_button), st::btnSend) , _histInited(false)
, _attachDocument(this, st::btnAttachDocument) , _toHistoryEnd(this, st::historyToEnd)
, _attachPhoto(this, st::btnAttachPhoto) , _send(this, lang(lng_send_button), st::btnSend)
, _attachEmoji(this, st::btnAttachEmoji) , _attachDocument(this, st::btnAttachDocument)
, _field(this, st::taMsgField, lang(lng_message_ph)) , _attachPhoto(this, st::btnAttachPhoto)
, _attachType(this) , _attachEmoji(this, st::btnAttachEmoji)
, _emojiPan(this) , _field(this, st::taMsgField, lang(lng_message_ph))
, _attachDrag(DragStateNone) , _attachType(this)
, _attachDragDocument(this) , _emojiPan(this)
, _attachDragPhoto(this) //, _stickerPan(this)
, imageLoader(this) , _attachDrag(DragStateNone)
, _synthedTextUpdate(false) , _attachDragDocument(this)
, loadingChatId(0) , _attachDragPhoto(this)
, loadingRequestId(0) , imageLoader(this)
, serviceImageCacheSize(0) , _synthedTextUpdate(false)
, confirmImageId(0) , loadingChatId(0)
, confirmWithText(false) , loadingRequestId(0)
, titlePeerTextWidth(0) , serviceImageCacheSize(0)
, bg(st::msgBG) , confirmImageId(0)
, hiderOffered(false) , confirmWithText(false)
, _scrollDelta(0) , titlePeerTextWidth(0)
, _typingRequest(0) , bg(st::msgBG)
, _saveDraftStart(0) , hiderOffered(false)
, _saveDraftText(false) { , _scrollDelta(0)
, _typingRequest(0)
, _saveDraftStart(0)
, _saveDraftText(false) {
_scroll.setFocusPolicy(Qt::NoFocus); _scroll.setFocusPolicy(Qt::NoFocus);
setAcceptDrops(true); setAcceptDrops(true);
@ -1588,6 +1591,9 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
connect(App::wnd()->windowHandle(), SIGNAL(visibleChanged(bool)), this, SLOT(onVisibleChanged())); connect(App::wnd()->windowHandle(), SIGNAL(visibleChanged(bool)), this, SLOT(onVisibleChanged()));
connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer())); connect(&_scrollTimer, SIGNAL(timeout()), this, SLOT(onScrollTimer()));
connect(&_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr))); connect(&_emojiPan, SIGNAL(emojiSelected(EmojiPtr)), &_field, SLOT(onEmojiInsert(EmojiPtr)));
connect(&_emojiPan, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*)));
connect(&_emojiPan, SIGNAL(updateStickers()), this, SLOT(updateStickers()));
// connect(&_stickerPan, SIGNAL(stickerSelected(DocumentData*)), this, SLOT(onStickerSend(DocumentData*)));
connect(&_typingStopTimer, SIGNAL(timeout()), this, SLOT(cancelTyping())); connect(&_typingStopTimer, SIGNAL(timeout()), this, SLOT(cancelTyping()));
_scrollTimer.setSingleShot(false); _scrollTimer.setSingleShot(false);
@ -1618,11 +1624,15 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
_attachDocument.installEventFilter(&_attachType); _attachDocument.installEventFilter(&_attachType);
_attachPhoto.installEventFilter(&_attachType); _attachPhoto.installEventFilter(&_attachType);
_attachEmoji.installEventFilter(&_emojiPan); _attachEmoji.installEventFilter(&_emojiPan);
// _attachEmoji.installEventFilter(&_stickerPan);
// _emojiPan.installEventFilter(&_stickerPan);
// _stickerPan.installEventFilter(&_emojiPan);
connect(_attachType.addButton(new IconedButton(this, st::dropdownAttachDocument, lang(lng_attach_file))), SIGNAL(clicked()), this, SLOT(onDocumentSelect())); connect(_attachType.addButton(new IconedButton(this, st::dropdownAttachDocument, lang(lng_attach_file))), SIGNAL(clicked()), this, SLOT(onDocumentSelect()));
connect(_attachType.addButton(new IconedButton(this, st::dropdownAttachPhoto, lang(lng_attach_photo))), SIGNAL(clicked()), this, SLOT(onPhotoSelect())); connect(_attachType.addButton(new IconedButton(this, st::dropdownAttachPhoto, lang(lng_attach_photo))), SIGNAL(clicked()), this, SLOT(onPhotoSelect()));
_attachType.hide(); _attachType.hide();
_emojiPan.hide(); _emojiPan.hide();
// _stickerPan.hide();
_attachDragDocument.hide(); _attachDragDocument.hide();
_attachDragPhoto.hide(); _attachDragPhoto.hide();
@ -1632,6 +1642,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
void HistoryWidget::onTextChange() { void HistoryWidget::onTextChange() {
updateTyping(); updateTyping();
// updateStickerPan();
if (!hist || _synthedTextUpdate) return; if (!hist || _synthedTextUpdate) return;
_saveDraftText = true; _saveDraftText = true;
@ -1639,6 +1650,8 @@ void HistoryWidget::onTextChange() {
} }
void HistoryWidget::onDraftSaveDelayed() { void HistoryWidget::onDraftSaveDelayed() {
// updateStickerPan();
if (!hist || _synthedTextUpdate) return; if (!hist || _synthedTextUpdate) return;
if (!_field.textCursor().anchor() && !_field.textCursor().position() && !_field.verticalScrollBar()->value()) { if (!_field.textCursor().anchor() && !_field.textCursor().position() && !_field.verticalScrollBar()->value()) {
if (!Local::hasDraftPositions(hist->peer->id)) return; if (!Local::hasDraftPositions(hist->peer->id)) return;
@ -1690,6 +1703,18 @@ void HistoryWidget::updateTyping(bool typing) {
} }
} }
//void HistoryWidget::updateStickerPan() {
// EmojiPtr e = _field.getSingleEmoji();
// if (e) updateStickers();
// _stickerPan.setStickerPack(e, !_emojiPan.isHidden() && !_emojiPan.hiding());
//}
void HistoryWidget::updateRecentStickers() {
if (cEmojiTab() == dbietStickers) {
_emojiPan.onTabChange();
}
}
void HistoryWidget::typingDone(const MTPBool &result, mtpRequestId req) { void HistoryWidget::typingDone(const MTPBool &result, mtpRequestId req) {
if (_typingRequest == req) { if (_typingRequest == req) {
_typingRequest = 0; _typingRequest = 0;
@ -1734,6 +1759,98 @@ void HistoryWidget::chatLoaded(const MTPmessages_ChatFull &res) {
peerUpdated(App::chat(peerId)); peerUpdated(App::chat(peerId));
} }
void HistoryWidget::updateStickers() {
if (_lastStickersUpdate && getms(true) < _lastStickersUpdate + StickersUpdateTimeout) return;
if (_stickersUpdateRequest) return;
_stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_string(cStickersHash())), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed));
}
void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
_lastStickersUpdate = getms(true);
_stickersUpdateRequest = 0;
if (stickers.type() == mtpc_messages_allStickers) {
const MTPDmessages_allStickers &d(stickers.c_messages_allStickers());
AllStickers all;
const QVector<MTPDocument> &docs(d.vdocuments.c_vector().v);
const RecentStickerPack &recent(cRecentStickers());
RecentStickerPack add;
add.reserve(docs.size());
ushort addValue = recent.isEmpty() ? 1 : qAbs(recent.front().second);
for (int32 i = 0, l = docs.size(); i < l; ++i) {
DocumentData *doc = App::feedDocument(docs.at(i));
if (!doc) continue;
int32 j = 0, s = recent.size();
for (; j < s; ++j) {
if (doc == recent.at(j).first) break;
}
if (j < s) continue;
add.push_back(qMakePair(doc, addValue));
}
if (!add.isEmpty()) {
cSetRecentStickers(add + recent);
Local::writeRecentStickers();
_emojiPan.onTabChange();
}
const QVector<MTPStickerPack> &packs(d.vpacks.c_vector().v);
for (int32 i = 0, l = packs.size(); i < l; ++i) {
if (packs.at(i).type() == mtpc_stickerPack) {
const MTPDstickerPack &p(packs.at(i).c_stickerPack());
QString emoticon(qs(p.vemoticon));
EmojiPtr e = 0;
for (const QChar *ch = emoticon.constData(), *end = emoticon.constEnd(); ch != end; ++ch) {
if (ch->isHighSurrogate()) {
if (ch + 1 < end && (ch + 1)->isLowSurrogate()) {
e = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
if (!e) {
++ch;
}
}
} else {
if (ch + 1 < end) {
if (((ch->unicode() >= 48 && ch->unicode() < 58) || ch->unicode() == 35) && (ch + 1)->unicode() == 0x20E3) {
e = getEmoji((ch->unicode() << 16) | (ch + 1)->unicode());
} else if ((ch + 1)->unicode() == 0xFE0F) {
e = getEmoji(ch->unicode());
}
}
}
if (e) break;
}
if (e) {
const QVector<MTPlong> docs(p.vdocuments.c_vector().v);
if (!docs.isEmpty()) {
StickerPack &pack(all[e]);
pack.reserve(pack.size() + docs.size());
for (int32 j = 0, s = docs.size(); j < s; ++j) {
pack.push_back(App::document(docs.at(j).v));
}
}
} else {
LOG(("Sticker Error: Could not find emoji for string: %1").arg(emoticon));
}
}
}
cSetStickers(all);
cSetStickersHash(qba(d.vhash));
// updateStickerPan();
_emojiPan.onTabChange();
}
}
bool HistoryWidget::stickersFailed(const RPCError &error) {
_lastStickersUpdate = getms(true);
_stickersUpdateRequest = 0;
return true;
}
void HistoryWidget::clearLoadingAround() { void HistoryWidget::clearLoadingAround() {
_loadingAroundId = -1; _loadingAroundId = -1;
if (_loadingAroundRequest) { if (_loadingAroundRequest) {
@ -1928,6 +2045,7 @@ void HistoryWidget::updateControlsVisibility() {
_attachEmoji.hide(); _attachEmoji.hide();
_attachType.hide(); _attachType.hide();
_emojiPan.hide(); _emojiPan.hide();
// _stickerPan.hide();
return; return;
} }
@ -1957,6 +2075,7 @@ void HistoryWidget::updateControlsVisibility() {
_attachEmoji.hide(); _attachEmoji.hide();
_attachType.hide(); _attachType.hide();
_emojiPan.hide(); _emojiPan.hide();
// _stickerPan.hide();
if (!_field.isHidden()) { if (!_field.isHidden()) {
_field.hide(); _field.hide();
resizeEvent(0); resizeEvent(0);
@ -1977,6 +2096,7 @@ void HistoryWidget::updateControlsVisibility() {
_attachEmoji.hide(); _attachEmoji.hide();
_attachType.hide(); _attachType.hide();
_emojiPan.hide(); _emojiPan.hide();
// _stickerPan.hide();
_toHistoryEnd.hide(); _toHistoryEnd.hide();
if (!_field.isHidden()) { if (!_field.isHidden()) {
_field.hide(); _field.hide();
@ -2301,6 +2421,7 @@ void HistoryWidget::onSend(bool ctrlShiftEnter) {
if (!_attachType.isHidden()) _attachType.hideStart(); if (!_attachType.isHidden()) _attachType.hideStart();
if (!_emojiPan.isHidden()) _emojiPan.hideStart(); if (!_emojiPan.isHidden()) _emojiPan.hideStart();
// if (!_stickerPan.isHidden()) _stickerPan.hideStart();
} }
_field.setFocus(); _field.setFocus();
@ -2991,13 +3112,17 @@ void HistoryWidget::onDocumentUploaded(MsgId newId, const MTPInputFile &file) {
if (!MTP::authedId()) return; if (!MTP::authedId()) return;
HistoryMessage *item = dynamic_cast<HistoryMessage*>(App::histItemById(newId)); HistoryMessage *item = dynamic_cast<HistoryMessage*>(App::histItemById(newId));
if (item) { if (item) {
HistoryDocument *media = dynamic_cast<HistoryDocument*>(item->getMedia()); DocumentData *document = 0;
if (media) { if (HistoryDocument *media = dynamic_cast<HistoryDocument*>(item->getMedia())) {
document = media->document();
} else if (HistorySticker *media = dynamic_cast<HistorySticker*>(item->getMedia())) {
document = media->document();
}
if (document) {
//App::main()->readServerHistory(item->history(), false); //App::main()->readServerHistory(item->history(), false);
uint64 randomId = MTP::nonce<uint64>(); uint64 randomId = MTP::nonce<uint64>();
App::historyRegRandom(randomId, newId); App::historyRegRandom(randomId, newId);
DocumentData *document = media->document();
History *hist = item->history(); History *hist = item->history();
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedDocument(file, MTP_string(document->mime), _composeDocumentAttributes(document)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId); hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedDocument(file, MTP_string(document->mime), _composeDocumentAttributes(document)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
} }
@ -3008,13 +3133,17 @@ void HistoryWidget::onThumbDocumentUploaded(MsgId newId, const MTPInputFile &fil
if (!MTP::authedId()) return; if (!MTP::authedId()) return;
HistoryMessage *item = dynamic_cast<HistoryMessage*>(App::histItemById(newId)); HistoryMessage *item = dynamic_cast<HistoryMessage*>(App::histItemById(newId));
if (item) { if (item) {
HistoryDocument *media = dynamic_cast<HistoryDocument*>(item->getMedia()); DocumentData *document = 0;
if (media) { if (HistoryDocument *media = dynamic_cast<HistoryDocument*>(item->getMedia())) {
document = media->document();
} else if (HistorySticker *media = dynamic_cast<HistorySticker*>(item->getMedia())) {
document = media->document();
}
if (document) {
//App::main()->readServerHistory(item->history(), false); //App::main()->readServerHistory(item->history(), false);
uint64 randomId = MTP::nonce<uint64>(); uint64 randomId = MTP::nonce<uint64>();
App::historyRegRandom(randomId, newId); App::historyRegRandom(randomId, newId);
DocumentData *document = media->document();
History *hist = item->history(); History *hist = item->history();
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedThumbDocument(file, thumb, MTP_string(document->mime), _composeDocumentAttributes(document)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId); hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedThumbDocument(file, thumb, MTP_string(document->mime), _composeDocumentAttributes(document)), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
} }
@ -3070,6 +3199,7 @@ void HistoryWidget::resizeEvent(QResizeEvent *e) {
_attachType.move(0, _attachDocument.y() - _attachType.height()); _attachType.move(0, _attachDocument.y() - _attachType.height());
_emojiPan.move(width() - _emojiPan.width(), _attachEmoji.y() - _emojiPan.height()); _emojiPan.move(width() - _emojiPan.width(), _attachEmoji.y() - _emojiPan.height());
// _stickerPan.move(width() - _emojiPan.width() - _stickerPan.width() + st::dropdownPadding.left(), _attachEmoji.y() - _stickerPan.height());
switch (_attachDrag) { switch (_attachDrag) {
case DragStateFiles: case DragStateFiles:
@ -3278,6 +3408,35 @@ void HistoryWidget::onFieldTabbed() {
} }
} }
void HistoryWidget::onStickerSend(DocumentData *sticker) {
if (!hist || !sticker) return;
App::main()->readServerHistory(hist, false);
uint64 randomId = MTP::nonce<uint64>();
MsgId newId = clientMsgId();
hist->loadAround(0);
bool out = (histPeer->input.type() != mtpc_inputPeerSelf), unread = (histPeer->input.type() != mtpc_inputPeerSelf);
hist->addToBackDocument(newId, out, unread, date(MTP_int(unixtime())), MTP::authedId(), sticker);
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(histPeer->input, MTP_inputMediaDocument(MTP_inputDocument(MTP_long(sticker->id), MTP_long(sticker->access))), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
App::historyRegRandom(randomId, newId);
App::main()->historyToDown(hist);
App::main()->dialogsToUp();
peerMessagesUpdated(histPeer->id);
if (!_attachType.isHidden()) _attachType.hideStart();
if (!_emojiPan.isHidden()) _emojiPan.hideStart();
// if (!_stickerPan.isHidden()) _stickerPan.hideStart();
// _field.removeSingleEmoji();
_field.setFocus();
}
void HistoryWidget::setFieldText(const QString &text) { void HistoryWidget::setFieldText(const QString &text) {
_synthedTextUpdate = true; _synthedTextUpdate = true;
_field.setPlainText(text); _field.setPlainText(text);

View File

@ -288,6 +288,8 @@ public:
QRect historyRect() const; QRect historyRect() const;
void updateTyping(bool typing = true); void updateTyping(bool typing = true);
// void updateStickerPan();
void updateRecentStickers();
void typingDone(const MTPBool &result, mtpRequestId req); void typingDone(const MTPBool &result, mtpRequestId req);
void destroyData(); void destroyData();
@ -379,6 +381,7 @@ public slots:
void onTextChange(); void onTextChange();
void onFieldTabbed(); void onFieldTabbed();
void onStickerSend(DocumentData *sticker);
void onVisibleChanged(); void onVisibleChanged();
@ -401,6 +404,8 @@ public slots:
void onDraftSaveDelayed(); void onDraftSaveDelayed();
void onDraftSave(bool delayed = false); void onDraftSave(bool delayed = false);
void updateStickers();
private: private:
bool messagesFailed(const RPCError &error, mtpRequestId requestId); bool messagesFailed(const RPCError &error, mtpRequestId requestId);
@ -409,6 +414,12 @@ private:
void addMessagesToBack(const QVector<MTPMessage> &messages); void addMessagesToBack(const QVector<MTPMessage> &messages);
void chatLoaded(const MTPmessages_ChatFull &res); void chatLoaded(const MTPmessages_ChatFull &res);
void stickersGot(const MTPmessages_AllStickers &stickers);
bool stickersFailed(const RPCError &error);
uint64 _lastStickersUpdate;
mtpRequestId _stickersUpdateRequest;
void writeDraft(const QString *text = 0, const MessageCursor *cursor = 0); void writeDraft(const QString *text = 0, const MessageCursor *cursor = 0);
void setFieldText(const QString &text); void setFieldText(const QString &text);
@ -440,6 +451,7 @@ private:
Dropdown _attachType; Dropdown _attachType;
EmojiPan _emojiPan; EmojiPan _emojiPan;
// StickerPan _stickerPan;
DragState _attachDrag; DragState _attachDrag;
DragArea _attachDragDocument, _attachDragPhoto; DragArea _attachDragDocument, _attachDragPhoto;

View File

@ -167,14 +167,20 @@ void LocalImageLoaderPrivate::prepareImages() {
jpeg_id = id; jpeg_id = id;
} else if ((type == ToPrepareVideo || type == ToPrepareDocument) && !img.isNull()) { } else if ((type == ToPrepareVideo || type == ToPrepareDocument) && !img.isNull()) {
int32 w = img.width(), h = img.height(); int32 w = img.width(), h = img.height();
if (animated) attributes.push_back(MTP_documentAttributeAnimated()); QByteArray thumbFormat = "JPG";
if (animated) {
attributes.push_back(MTP_documentAttributeAnimated());
} else if (mime == qsl("image/webp") && w > 0 && h > 0 && filesize < StickerInMemory) {
attributes.push_back(MTP_documentAttributeSticker());
thumbFormat = "webp";
}
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h))); attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(img.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img, Qt::ColorOnly); QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(img.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img, Qt::ColorOnly);
{ {
QBuffer jpegBuffer(&jpeg); QBuffer jpegBuffer(&jpeg);
full.save(&jpegBuffer, "JPG", 87); full.save(&jpegBuffer, thumbFormat, 87);
} }
photoThumbs.insert('0', full); photoThumbs.insert('0', full);

View File

@ -84,7 +84,7 @@ namespace {
result = MTP::nonce<FileKey>(); result = MTP::nonce<FileKey>();
path.resize(_basePath.size()); path.resize(_basePath.size());
path += toFilePart(result); path += toFilePart(result);
} while (keyAlreadyUsed(path)); } while (!result || keyAlreadyUsed(path));
return result; return result;
} }
@ -437,8 +437,11 @@ namespace {
lskUserMap = 0, lskUserMap = 0,
lskDraft, // data: PeerId peer lskDraft, // data: PeerId peer
lskDraftPosition, // data: PeerId peer lskDraftPosition, // data: PeerId peer
lskStorage, // data: StorageKey location lskImages, // data: StorageKey location
lskLocations, // no data lskLocations, // no data
lskStickers, // data: StorageKey location
lskAudios, // data: StorageKey location
lskRecentStickers, // no data
}; };
typedef QMap<PeerId, FileKey> DraftsMap; typedef QMap<PeerId, FileKey> DraftsMap;
@ -446,17 +449,19 @@ namespace {
typedef QMap<PeerId, bool> DraftsNotReadMap; typedef QMap<PeerId, bool> DraftsNotReadMap;
DraftsNotReadMap _draftsNotReadMap; DraftsNotReadMap _draftsNotReadMap;
typedef QPair<FileKey, qint32> FileDesc; // file, size
typedef QMap<StorageKey, FileDesc> StorageMap;
StorageMap _storageMap;
int32 _storageFilesSize = 0;
typedef QMultiMap<MediaKey, FileLocation> FileLocations; typedef QMultiMap<MediaKey, FileLocation> FileLocations;
FileLocations _fileLocations; FileLocations _fileLocations;
typedef QPair<MediaKey, FileLocation> FileLocationPair; typedef QPair<MediaKey, FileLocation> FileLocationPair;
typedef QMap<QString, FileLocationPair> FileLocationPairs; typedef QMap<QString, FileLocationPair> FileLocationPairs;
FileLocationPairs _fileLocationPairs; FileLocationPairs _fileLocationPairs;
FileKey _locationsKey = 0; FileKey _locationsKey = 0;
FileKey _recentStickersKey = 0;
typedef QPair<FileKey, qint32> FileDesc; // file, size
typedef QMap<StorageKey, FileDesc> StorageMap;
StorageMap _imagesMap, _stickersMap, _audiosMap;
int32 _storageImagesSize = 0, _storageStickersSize = 0, _storageAudiosSize = 0;
bool _mapChanged = false; bool _mapChanged = false;
int32 _oldMapVersion = 0; int32 _oldMapVersion = 0;
@ -474,6 +479,8 @@ namespace {
_manager->writeLocations(when == WriteMapFast); _manager->writeLocations(when == WriteMapFast);
return; return;
} }
if (!_working()) return;
_manager->writingLocations(); _manager->writingLocations();
if (_fileLocations.isEmpty()) { if (_fileLocations.isEmpty()) {
if (_locationsKey) { if (_locationsKey) {
@ -484,15 +491,14 @@ namespace {
} }
} else { } else {
if (!_locationsKey) { if (!_locationsKey) {
while (!_locationsKey) { _locationsKey = genKey();
_locationsKey = genKey();
}
_mapChanged = true; _mapChanged = true;
_writeMap(WriteMapFast); _writeMap(WriteMapFast);
} }
quint32 size = 0; quint32 size = 0;
for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) { for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
size += sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + i.value().name.size() * sizeof(ushort) + sizeof(qint64) + sizeof(quint32) + sizeof(qint8) + sizeof(quint32); // location + type + namelen + name + date + size
size += sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + i.value().name.size() * sizeof(ushort) + (sizeof(qint64) + sizeof(quint32) + sizeof(qint8)) + sizeof(quint32);
} }
EncryptedDescriptor data(size); EncryptedDescriptor data(size);
for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) { for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
@ -576,9 +582,9 @@ namespace {
DraftsMap draftsMap, draftsPositionsMap; DraftsMap draftsMap, draftsPositionsMap;
DraftsNotReadMap draftsNotReadMap; DraftsNotReadMap draftsNotReadMap;
StorageMap storageMap; StorageMap imagesMap, stickersMap, audiosMap;
qint64 storageFilesSize = 0; qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0;
quint64 locationsKey = 0; quint64 locationsKey = 0, recentStickersKey = 0;
while (!map.stream.atEnd()) { while (!map.stream.atEnd()) {
quint32 keyType; quint32 keyType;
map.stream >> keyType; map.stream >> keyType;
@ -604,7 +610,7 @@ namespace {
draftsPositionsMap.insert(p, key); draftsPositionsMap.insert(p, key);
} }
} break; } break;
case lskStorage: { case lskImages: {
quint32 count = 0; quint32 count = 0;
map.stream >> count; map.stream >> count;
for (quint32 i = 0; i < count; ++i) { for (quint32 i = 0; i < count; ++i) {
@ -612,13 +618,40 @@ namespace {
quint64 first, second; quint64 first, second;
qint32 size; qint32 size;
map.stream >> key >> first >> second >> size; map.stream >> key >> first >> second >> size;
storageMap.insert(StorageKey(first, second), FileDesc(key, size)); imagesMap.insert(StorageKey(first, second), FileDesc(key, size));
storageFilesSize += size; storageImagesSize += size;
}
} break;
case lskStickers: {
quint32 count = 0;
map.stream >> count;
for (quint32 i = 0; i < count; ++i) {
FileKey key;
quint64 first, second;
qint32 size;
map.stream >> key >> first >> second >> size;
stickersMap.insert(StorageKey(first, second), FileDesc(key, size));
storageStickersSize += size;
}
} break;
case lskAudios: {
quint32 count = 0;
map.stream >> count;
for (quint32 i = 0; i < count; ++i) {
FileKey key;
quint64 first, second;
qint32 size;
map.stream >> key >> first >> second >> size;
audiosMap.insert(StorageKey(first, second), FileDesc(key, size));
storageAudiosSize += size;
} }
} break; } break;
case lskLocations: { case lskLocations: {
map.stream >> locationsKey; map.stream >> locationsKey;
} break; } break;
case lskRecentStickers: {
map.stream >> recentStickersKey;
} break;
default: default:
LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType)); LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType));
return Local::ReadMapFailed; return Local::ReadMapFailed;
@ -632,9 +665,16 @@ namespace {
_draftsMap = draftsMap; _draftsMap = draftsMap;
_draftsPositionsMap = draftsPositionsMap; _draftsPositionsMap = draftsPositionsMap;
_draftsNotReadMap = draftsNotReadMap; _draftsNotReadMap = draftsNotReadMap;
_storageMap = storageMap;
_storageFilesSize = storageFilesSize; _imagesMap = imagesMap;
_storageImagesSize = storageImagesSize;
_stickersMap = stickersMap;
_storageStickersSize = storageStickersSize;
_audiosMap = audiosMap;
_storageAudiosSize = storageAudiosSize;
_locationsKey = locationsKey; _locationsKey = locationsKey;
_recentStickersKey = recentStickersKey;
_oldMapVersion = mapData.version; _oldMapVersion = mapData.version;
if (_oldMapVersion < AppVersion) { if (_oldMapVersion < AppVersion) {
_mapChanged = true; _mapChanged = true;
@ -687,8 +727,11 @@ namespace {
uint32 mapSize = 0; uint32 mapSize = 0;
if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2; if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2;
if (!_draftsPositionsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsPositionsMap.size() * sizeof(quint64) * 2; if (!_draftsPositionsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsPositionsMap.size() * sizeof(quint64) * 2;
if (!_storageMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _storageMap.size() * (sizeof(quint64) * 3 + sizeof(qint32)); if (!_imagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _imagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
if (!_stickersMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _stickersMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
if (!_audiosMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _audiosMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64); if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64);
if (_recentStickersKey) mapSize += sizeof(quint32) + sizeof(quint64);
EncryptedDescriptor mapData(mapSize); EncryptedDescriptor mapData(mapSize);
if (!_draftsMap.isEmpty()) { if (!_draftsMap.isEmpty()) {
mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size()); mapData.stream << quint32(lskDraft) << quint32(_draftsMap.size());
@ -702,15 +745,30 @@ namespace {
mapData.stream << quint64(i.value()) << quint64(i.key()); mapData.stream << quint64(i.value()) << quint64(i.key());
} }
} }
if (!_storageMap.isEmpty()) { if (!_imagesMap.isEmpty()) {
mapData.stream << quint32(lskStorage) << quint32(_storageMap.size()); mapData.stream << quint32(lskImages) << quint32(_imagesMap.size());
for (StorageMap::const_iterator i = _storageMap.cbegin(), e = _storageMap.cend(); i != e; ++i) { for (StorageMap::const_iterator i = _imagesMap.cbegin(), e = _imagesMap.cend(); i != e; ++i) {
mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second);
}
}
if (!_stickersMap.isEmpty()) {
mapData.stream << quint32(lskStickers) << quint32(_stickersMap.size());
for (StorageMap::const_iterator i = _stickersMap.cbegin(), e = _stickersMap.cend(); i != e; ++i) {
mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second);
}
}
if (!_audiosMap.isEmpty()) {
mapData.stream << quint32(lskAudios) << quint32(_audiosMap.size());
for (StorageMap::const_iterator i = _audiosMap.cbegin(), e = _audiosMap.cend(); i != e; ++i) {
mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second); mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second);
} }
} }
if (_locationsKey) { if (_locationsKey) {
mapData.stream << quint32(lskLocations) << quint64(_locationsKey); mapData.stream << quint32(lskLocations) << quint64(_locationsKey);
} }
if (_recentStickersKey) {
mapData.stream << quint32(lskRecentStickers) << quint64(_recentStickersKey);
}
map.writeEncrypted(mapData); map.writeEncrypted(mapData);
map.finish(); map.finish();
@ -958,9 +1016,25 @@ namespace Local {
return result; return result;
} }
qint32 _storageStickerSize(qint32 rawlen) {
// fulllen + storagekey + len + data
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + rawlen;
if (result & 0x0F) result += 0x10 - (result & 0x0F);
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
return result;
}
qint32 _storageAudioSize(qint32 rawlen) {
// fulllen + storagekey + len + data
qint32 result = sizeof(uint32) + sizeof(quint64) * 2 + sizeof(quint32) + rawlen;
if (result & 0x0F) result += 0x10 - (result & 0x0F);
result += tdfMagicLen + sizeof(qint32) + sizeof(quint32) + 0x10 + 0x10; // magic + version + len of encrypted + part of sha1 + md5
return result;
}
void writeImage(const StorageKey &location, const ImagePtr &image) { void writeImage(const StorageKey &location, const ImagePtr &image) {
if (image->isNull() || !image->loaded()) return; if (image->isNull() || !image->loaded()) return;
if (_storageMap.constFind(location) != _storageMap.cend()) return; if (_imagesMap.constFind(location) != _imagesMap.cend()) return;
QByteArray fmt = image->savedFormat(); QByteArray fmt = image->savedFormat();
mtpTypeId format = 0; mtpTypeId format = 0;
@ -981,10 +1055,10 @@ namespace Local {
if (!_working()) return; if (!_working()) return;
qint32 size = _storageImageSize(image.data.size()); qint32 size = _storageImageSize(image.data.size());
StorageMap::const_iterator i = _storageMap.constFind(location); StorageMap::const_iterator i = _imagesMap.constFind(location);
if (i == _storageMap.cend()) { if (i == _imagesMap.cend()) {
i = _storageMap.insert(location, FileDesc(genKey(), size)); i = _imagesMap.insert(location, FileDesc(genKey(), size));
_storageFilesSize += size; _storageImagesSize += size;
_mapChanged = true; _mapChanged = true;
_writeMap(); _writeMap();
} else if (!overwrite) { } else if (!overwrite) {
@ -995,22 +1069,22 @@ namespace Local {
FileWriteDescriptor file(i.value().first, false); FileWriteDescriptor file(i.value().first, false);
file.writeEncrypted(data); file.writeEncrypted(data);
if (i.value().second != size) { if (i.value().second != size) {
_storageFilesSize += size; _storageImagesSize += size;
_storageFilesSize -= i.value().second; _storageImagesSize -= i.value().second;
_storageMap[location].second = size; _imagesMap[location].second = size;
} }
} }
StorageImageSaved readImage(const StorageKey &location) { StorageImageSaved readImage(const StorageKey &location) {
StorageMap::iterator j = _storageMap.find(location); StorageMap::iterator j = _imagesMap.find(location);
if (j == _storageMap.cend()) { if (j == _imagesMap.cend()) {
return StorageImageSaved(); return StorageImageSaved();
} }
FileReadDescriptor draft; FileReadDescriptor draft;
if (!readEncryptedFile(draft, toFilePart(j.value().first), false)) { if (!readEncryptedFile(draft, toFilePart(j.value().first), false)) {
clearKey(j.value().first, false); clearKey(j.value().first, false);
_storageFilesSize -= j.value().second; _storageImagesSize -= j.value().second;
_storageMap.erase(j); _imagesMap.erase(j);
return StorageImageSaved(); return StorageImageSaved();
} }
@ -1023,16 +1097,194 @@ namespace Local {
} }
int32 hasImages() { int32 hasImages() {
return _storageMap.size(); return _imagesMap.size();
} }
qint64 storageFilesSize() { qint64 storageImagesSize() {
return _storageFilesSize; return _storageImagesSize;
}
void writeSticker(const StorageKey &location, const QByteArray &sticker, bool overwrite) {
if (!_working()) return;
qint32 size = _storageStickerSize(sticker.size());
StorageMap::const_iterator i = _stickersMap.constFind(location);
if (i == _stickersMap.cend()) {
i = _stickersMap.insert(location, FileDesc(genKey(), size));
_storageStickersSize += size;
_mapChanged = true;
_writeMap();
} else if (!overwrite) {
return;
}
EncryptedDescriptor data(sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + sticker.size());
data.stream << quint64(location.first) << quint64(location.second) << sticker;
FileWriteDescriptor file(i.value().first, false);
file.writeEncrypted(data);
if (i.value().second != size) {
_storageStickersSize += size;
_storageStickersSize -= i.value().second;
_stickersMap[location].second = size;
}
}
QByteArray readSticker(const StorageKey &location) {
StorageMap::iterator j = _stickersMap.find(location);
if (j == _stickersMap.cend()) {
return QByteArray();
}
FileReadDescriptor draft;
if (!readEncryptedFile(draft, toFilePart(j.value().first), false)) {
clearKey(j.value().first, false);
_storageStickersSize -= j.value().second;
_stickersMap.erase(j);
return QByteArray();
}
QByteArray stickerData;
quint64 locFirst, locSecond;
draft.stream >> locFirst >> locSecond >> stickerData;
return (locFirst == location.first && locSecond == location.second) ? stickerData : QByteArray();
}
int32 hasStickers() {
return _stickersMap.size();
}
qint64 storageStickersSize() {
return _storageStickersSize;
}
void writeAudio(const StorageKey &location, const QByteArray &audio, bool overwrite) {
if (!_working()) return;
qint32 size = _storageAudioSize(audio.size());
StorageMap::const_iterator i = _audiosMap.constFind(location);
if (i == _audiosMap.cend()) {
i = _audiosMap.insert(location, FileDesc(genKey(), size));
_storageAudiosSize += size;
_mapChanged = true;
_writeMap();
} else if (!overwrite) {
return;
}
EncryptedDescriptor data(sizeof(quint64) * 2 + sizeof(quint32) + sizeof(quint32) + audio.size());
data.stream << quint64(location.first) << quint64(location.second) << audio;
FileWriteDescriptor file(i.value().first, false);
file.writeEncrypted(data);
if (i.value().second != size) {
_storageAudiosSize += size;
_storageAudiosSize -= i.value().second;
_audiosMap[location].second = size;
}
}
QByteArray readAudio(const StorageKey &location) {
StorageMap::iterator j = _audiosMap.find(location);
if (j == _audiosMap.cend()) {
return QByteArray();
}
FileReadDescriptor draft;
if (!readEncryptedFile(draft, toFilePart(j.value().first), false)) {
clearKey(j.value().first, false);
_storageAudiosSize -= j.value().second;
_audiosMap.erase(j);
return QByteArray();
}
QByteArray audioData;
quint64 locFirst, locSecond;
draft.stream >> locFirst >> locSecond >> audioData;
return (locFirst == location.first && locSecond == location.second) ? audioData : QByteArray();
}
int32 hasAudios() {
return _audiosMap.size();
}
qint64 storageAudiosSize() {
return _storageAudiosSize;
}
void writeRecentStickers() {
if (!_working()) return;
const RecentStickerPack &recent(cRecentStickers());
if (recent.isEmpty()) {
if (_recentStickersKey) {
clearKey(_recentStickersKey);
_recentStickersKey = 0;
_mapChanged = true;
}
_writeMap();
} else {
if (!_recentStickersKey) {
_recentStickersKey = genKey();
_mapChanged = true;
_writeMap(WriteMapFast);
}
quint32 size = 0;
for (RecentStickerPack::const_iterator i = recent.cbegin(); i != recent.cend(); ++i) {
DocumentData *doc = i->first;
// id + value + access + date + namelen + name + mimelen + mime + dc + size + width + height + type
size += sizeof(quint64) + sizeof(qint16) + sizeof(quint64) + sizeof(qint32) + (sizeof(quint32) + doc->name.size() * sizeof(ushort)) + (sizeof(quint32) + doc->mime.size() * sizeof(ushort)) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32);
}
EncryptedDescriptor data(size);
for (RecentStickerPack::const_iterator i = recent.cbegin(); i != recent.cend(); ++i) {
DocumentData *doc = i->first;
data.stream << quint64(doc->id) << qint16(i->second) << quint64(doc->access) << qint32(doc->date) << doc->name << doc->mime << qint32(doc->dc) << qint32(doc->size) << qint32(doc->dimensions.width()) << qint32(doc->dimensions.height()) << qint32(doc->type);
}
FileWriteDescriptor file(_recentStickersKey);
file.writeEncrypted(data);
}
}
void readRecentStickers() {
if (!_recentStickersKey) return;
FileReadDescriptor stickers;
if (!readEncryptedFile(stickers, toFilePart(_recentStickersKey))) {
clearKey(_recentStickersKey);
_recentStickersKey = 0;
_writeMap();
return;
}
QMap<uint64, bool> read;
RecentStickerPack recent;
while (!stickers.stream.atEnd()) {
quint64 id, access;
QString name, mime;
qint32 date, dc, size, width, height, type;
qint16 value;
stickers.stream >> id >> value >> access >> date >> name >> mime >> dc >> size >> width >> height >> type;
if (read.contains(id)) continue;
read.insert(id, true);
QVector<MTPDocumentAttribute> attributes;
if (!name.isEmpty()) attributes.push_back(MTP_documentAttributeFilename(MTP_string(name)));
if (type == AnimatedDocument) {
attributes.push_back(MTP_documentAttributeAnimated());
} else if (type == StickerDocument) {
attributes.push_back(MTP_documentAttributeSticker());
}
if (width > 0 && height > 0) {
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
}
recent.push_back(qMakePair(App::document(id, 0, access, date, attributes, mime, ImagePtr(), dc, size), value));
}
cSetRecentStickers(recent);
} }
struct ClearManagerData { struct ClearManagerData {
QThread *thread; QThread *thread;
StorageMap images; StorageMap images, stickers, audios;
QMutex mutex; QMutex mutex;
QList<int> tasks; QList<int> tasks;
bool working; bool working;
@ -1050,9 +1302,19 @@ namespace Local {
if (!data->tasks.isEmpty() && (data->tasks.at(0) == ClearManagerAll)) return true; if (!data->tasks.isEmpty() && (data->tasks.at(0) == ClearManagerAll)) return true;
if (task == ClearManagerAll) { if (task == ClearManagerAll) {
data->tasks.clear(); data->tasks.clear();
if (!_storageMap.isEmpty()) { if (!_imagesMap.isEmpty()) {
_storageMap.clear(); _imagesMap.clear();
_storageFilesSize = 0; _storageImagesSize = 0;
_mapChanged = true;
}
if (!_stickersMap.isEmpty()) {
_stickersMap.clear();
_storageStickersSize = 0;
_mapChanged = true;
}
if (!_audiosMap.isEmpty()) {
_audiosMap.clear();
_storageAudiosSize = 0;
_mapChanged = true; _mapChanged = true;
} }
if (!_draftsMap.isEmpty()) { if (!_draftsMap.isEmpty()) {
@ -1067,13 +1329,17 @@ namespace Local {
_locationsKey = 0; _locationsKey = 0;
_mapChanged = true; _mapChanged = true;
} }
if (_recentStickersKey) {
_recentStickersKey = 0;
_mapChanged = true;
}
_writeMap(); _writeMap();
} else { } else {
if (task & ClearManagerImages) { if (task & ClearManagerStorage) {
if (data->images.isEmpty()) { if (data->images.isEmpty()) {
data->images = _storageMap; data->images = _imagesMap;
} else { } else {
for (StorageMap::const_iterator i = _storageMap.cbegin(), e = _storageMap.cend(); i != e; ++i) { for (StorageMap::const_iterator i = _imagesMap.cbegin(), e = _imagesMap.cend(); i != e; ++i) {
StorageKey k = i.key(); StorageKey k = i.key();
while (data->images.constFind(k) != data->images.cend()) { while (data->images.constFind(k) != data->images.cend()) {
++k.second; ++k.second;
@ -1081,12 +1347,44 @@ namespace Local {
data->images.insert(k, i.value()); data->images.insert(k, i.value());
} }
} }
if (!_storageMap.isEmpty()) { if (!_imagesMap.isEmpty()) {
_storageMap.clear(); _imagesMap.clear();
_storageFilesSize = 0; _storageImagesSize = 0;
_mapChanged = true; _mapChanged = true;
_writeMap();
} }
if (data->stickers.isEmpty()) {
data->stickers = _stickersMap;
} else {
for (StorageMap::const_iterator i = _stickersMap.cbegin(), e = _stickersMap.cend(); i != e; ++i) {
StorageKey k = i.key();
while (data->stickers.constFind(k) != data->stickers.cend()) {
++k.second;
}
data->stickers.insert(k, i.value());
}
}
if (!_stickersMap.isEmpty()) {
_stickersMap.clear();
_storageStickersSize = 0;
_mapChanged = true;
}
if (data->audios.isEmpty()) {
data->audios = _audiosMap;
} else {
for (StorageMap::const_iterator i = _audiosMap.cbegin(), e = _audiosMap.cend(); i != e; ++i) {
StorageKey k = i.key();
while (data->audios.constFind(k) != data->audios.cend()) {
++k.second;
}
data->audios.insert(k, i.value());
}
}
if (!_audiosMap.isEmpty()) {
_audiosMap.clear();
_storageAudiosSize = 0;
_mapChanged = true;
}
_writeMap();
} }
for (int32 i = 0, l = data->tasks.size(); i < l; ++i) { for (int32 i = 0, l = data->tasks.size(); i < l; ++i) {
if (data->tasks.at(i) == task) return true; if (data->tasks.at(i) == task) return true;
@ -1121,7 +1419,7 @@ namespace Local {
while (true) { while (true) {
int task = 0; int task = 0;
bool result = false; bool result = false;
StorageMap images; StorageMap images, stickers, audios;
{ {
QMutexLocker lock(&data->mutex); QMutexLocker lock(&data->mutex);
if (data->tasks.isEmpty()) { if (data->tasks.isEmpty()) {
@ -1130,6 +1428,8 @@ namespace Local {
} }
task = data->tasks.at(0); task = data->tasks.at(0);
images = data->images; images = data->images;
stickers = data->stickers;
audios = data->audios;
} }
switch (task) { switch (task) {
case ClearManagerAll: case ClearManagerAll:
@ -1138,10 +1438,16 @@ namespace Local {
case ClearManagerDownloads: case ClearManagerDownloads:
result = QDir(cTempDir()).removeRecursively(); result = QDir(cTempDir()).removeRecursively();
break; break;
case ClearManagerImages: case ClearManagerStorage:
for (StorageMap::const_iterator i = images.cbegin(), e = images.cend(); i != e; ++i) { for (StorageMap::const_iterator i = images.cbegin(), e = images.cend(); i != e; ++i) {
clearKey(i.value().first, false); clearKey(i.value().first, false);
} }
for (StorageMap::const_iterator i = stickers.cbegin(), e = stickers.cend(); i != e; ++i) {
clearKey(i.value().first, false);
}
for (StorageMap::const_iterator i = audios.cbegin(), e = audios.cend(); i != e; ++i) {
clearKey(i.value().first, false);
}
result = true; result = true;
break; break;
} }

View File

@ -59,7 +59,7 @@ namespace Local {
enum ClearManagerTask { enum ClearManagerTask {
ClearManagerAll = 0xFFFF, ClearManagerAll = 0xFFFF,
ClearManagerDownloads = 0x01, ClearManagerDownloads = 0x01,
ClearManagerImages = 0x02, ClearManagerStorage = 0x02,
}; };
struct ClearManagerData; struct ClearManagerData;
@ -106,6 +106,19 @@ namespace Local {
void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true); void writeImage(const StorageKey &location, const StorageImageSaved &jpeg, bool overwrite = true);
StorageImageSaved readImage(const StorageKey &location); StorageImageSaved readImage(const StorageKey &location);
int32 hasImages(); int32 hasImages();
qint64 storageFilesSize(); qint64 storageImagesSize();
void writeSticker(const StorageKey &location, const QByteArray &data, bool overwrite = true);
QByteArray readSticker(const StorageKey &location);
int32 hasStickers();
qint64 storageStickersSize();
void writeAudio(const StorageKey &location, const QByteArray &data, bool overwrite = true);
QByteArray readAudio(const StorageKey &location);
int32 hasAudios();
qint64 storageAudiosSize();
void writeRecentStickers();
void readRecentStickers();
}; };

View File

@ -26,6 +26,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "mainwidget.h" #include "mainwidget.h"
#include "boxes/confirmbox.h" #include "boxes/confirmbox.h"
#include "localstorage.h"
#include "audio.h" #include "audio.h"
TopBarWidget::TopBarWidget(MainWidget *w) : TWidget(w), TopBarWidget::TopBarWidget(MainWidget *w) : TWidget(w),
@ -2121,6 +2123,8 @@ void MainWidget::start(const MTPUser &user) {
} }
_started = true; _started = true;
App::wnd()->sendServiceHistoryRequest(); App::wnd()->sendServiceHistoryRequest();
Local::readRecentStickers();
history.updateRecentStickers();
} }
bool MainWidget::started() { bool MainWidget::started() {
@ -2267,6 +2271,45 @@ void MainWidget::updateNotifySetting(PeerData *peer, bool enabled) {
updateNotifySettingTimer.start(NotifySettingSaveTimeout); updateNotifySettingTimer.start(NotifySettingSaveTimeout);
} }
void MainWidget::incrementSticker(DocumentData *sticker) {
RecentStickerPack recent(cRecentStickers());
RecentStickerPack::iterator i = recent.begin(), e = recent.end();
for (; i != e; ++i) {
if (i->first == sticker) {
if (i->second > 0) {
++i->second;
} else {
--i->second;
}
if (qAbs(i->second) > 0x4000) {
for (RecentStickerPack::iterator j = recent.begin(); j != e; ++j) {
if (qAbs(j->second) > 1) {
j->second /= 2;
} else if (j->second > 0) {
j->second = 1;
} else {
j->second = -1;
}
}
}
for (; i != recent.begin(); --i) {
if (qAbs((i - 1)->second) > qAbs(i->second)) {
break;
}
qSwap(*i, *(i - 1));
}
break;
}
}
if (i == e) {
recent.push_front(qMakePair(sticker, -(recent.isEmpty() ? 1 : qAbs(recent.front().second))));
}
cSetRecentStickers(recent);
Local::writeRecentStickers();
history.updateRecentStickers();
}
void MainWidget::activate() { void MainWidget::activate() {
if (!profile && !overview) { if (!profile && !overview) {
if (hider) { if (hider) {

View File

@ -196,6 +196,8 @@ public:
void updateNotifySetting(PeerData *peer, bool enabled); void updateNotifySetting(PeerData *peer, bool enabled);
void incrementSticker(DocumentData *sticker);
void activate(); void activate();
void createDialogAtTop(History *history, int32 unreadCount); void createDialogAtTop(History *history, int32 unreadCount);

View File

@ -179,7 +179,7 @@ void MediaView::updateControls() {
} else { } else {
_dateText = lng_mediaview_date_time(lt_date, d.date().toString(qsl("dd.MM.yy")), lt_time, d.time().toString(qsl("hh:mm"))); _dateText = lng_mediaview_date_time(lt_date, d.date().toString(qsl("dd.MM.yy")), lt_time, d.time().toString(qsl("hh:mm")));
} }
_fromName.setText(st::medviewNameFont, _from->name); if (_from) _fromName.setText(st::medviewNameFont, _from->name);
updateHeader(); updateHeader();
_leftNavVisible = _photo && (_index > 0 || (_index == 0 && _history && _history->_overview[OverviewPhotos].size() < _history->_overviewCount[OverviewPhotos])); _leftNavVisible = _photo && (_index > 0 || (_index == 0 && _history && _history->_overview[OverviewPhotos].size() < _history->_overviewCount[OverviewPhotos]));
_rightNavVisible = _photo && (_index >= 0 && ( _rightNavVisible = _photo && (_index >= 0 && (
@ -480,7 +480,7 @@ void MediaView::showDocument(DocumentData *doc, QPixmap pix, HistoryItem *contex
} }
_x = (_avail.width() - _w) / 2; _x = (_avail.width() - _w) / 2;
_y = (_avail.height() - st::medviewBottomBar - _h) / 2; _y = (_avail.height() - st::medviewBottomBar - _h) / 2;
_from = App::user(_doc->user); _from = context ? context->from()->asUser() : 0;
_full = 1; _full = 1;
updateControls(); updateControls();
if (isHidden()) { if (isHidden()) {
@ -721,20 +721,26 @@ void MediaView::paintEvent(QPaintEvent *e) {
} else { } else {
p.setPen(st::medviewNameColor->p); p.setPen(st::medviewNameColor->p);
} }
if (_over == OverName) _fromName.replaceFont(st::medviewNameFont->underline()); if (_from) {
if (_nameNav.intersects(r)) _fromName.drawElided(p, _nameNav.left(), _nameNav.top(), _nameNav.width()); if (_nameNav.intersects(r)) {
if (_over == OverName) _fromName.replaceFont(st::medviewNameFont); if (_over == OverName) _fromName.replaceFont(st::medviewNameFont->underline());
_fromName.drawElided(p, _nameNav.left(), _nameNav.top(), _nameNav.width());
if (_over == OverName) _fromName.replaceFont(st::medviewNameFont);
}
}
// date // date
if (_doc) { if (_dateNav.intersects(r)) {
float64 o = overLevel(OverDate); if (_doc) {
p.setOpacity(st::medviewOverview.overOpacity * o + st::medviewOverview.opacity * (1 - o)); float64 o = overLevel(OverDate);
p.setPen(st::white->p); p.setOpacity(st::medviewOverview.overOpacity * o + st::medviewOverview.opacity * (1 - o));
} else { p.setPen(st::white->p);
p.setPen(st::medviewDateColor->p); } else {
p.setPen(st::medviewDateColor->p);
}
p.setFont((_over == OverDate ? st::medviewDateFont->underline() : st::medviewDateFont)->f);
p.drawText(_dateNav.left(), _dateNav.top() + st::medviewDateFont->ascent, _dateText);
} }
p.setFont((_over == OverDate ? st::medviewDateFont->underline() : st::medviewDateFont)->f);
if (_dateNav.intersects(r)) p.drawText(_dateNav.left(), _dateNav.top() + st::medviewDateFont->ascent, _dateText);
} }
void MediaView::keyPressEvent(QKeyEvent *e) { void MediaView::keyPressEvent(QKeyEvent *e) {
@ -1060,7 +1066,7 @@ void MediaView::mouseReleaseEvent(QMouseEvent *e) {
} }
textlnkDown(TextLinkPtr()); textlnkDown(TextLinkPtr());
if (_over == OverName && _down == OverName) { if (_over == OverName && _down == OverName) {
if (App::wnd()) { if (App::wnd() && _from) {
onClose(); onClose();
if (App::main()) App::main()->showPeerProfile(_from); if (App::main()) App::main()->showPeerProfile(_from);
} }
@ -1339,15 +1345,21 @@ void MediaView::updatePolaroid() {
int32 minus1 = width() - _delete.x(), minus2 = _overview.x() + st::medviewHeaderFont->m.width(_header) - st::medviewOverview.width; int32 minus1 = width() - _delete.x(), minus2 = _overview.x() + st::medviewHeaderFont->m.width(_header) - st::medviewOverview.width;
if (minus2 > minus1) minus1 = minus2; if (minus2 > minus1) minus1 = minus2;
int32 nameWidth = _fromName.maxWidth(), maxWidth = width() - 2 * minus1, dateWidth = st::medviewDateFont->m.width(_dateText); int32 dateWidth = st::medviewDateFont->m.width(_dateText), maxWidth = width() - 2 * minus1;
if (maxWidth < dateWidth) { if (_from) {
maxWidth = dateWidth; int32 nameWidth = _fromName.maxWidth();
if (maxWidth < dateWidth) {
maxWidth = dateWidth;
}
if (nameWidth > maxWidth) {
nameWidth = maxWidth;
}
_nameNav = QRect((_avail.width() - nameWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + st::medviewNameTop, nameWidth, st::medviewNameFont->height);
_dateNav = QRect((_avail.width() - dateWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + st::medviewDateTop, dateWidth, st::medviewDateFont->height);
} else {
_nameNav = QRect(_avail.x() - 1, _avail.y() - 1, 0, 0);
_dateNav = QRect((_avail.width() - dateWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + ((st::medviewNameTop + st::medviewDateTop) / 2), dateWidth, st::medviewDateFont->height);
} }
if (nameWidth > maxWidth) {
nameWidth = maxWidth;
}
_nameNav = QRect((_avail.width() - nameWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + st::medviewNameTop, nameWidth, st::medviewNameFont->height);
_dateNav = QRect((_avail.width() - dateWidth) / 2, _avail.y() + _avail.height() - ((st::medviewPolaroid.bottom() + st::medviewBottomBar) / 2) + st::medviewDateTop, dateWidth, st::medviewDateFont->height);
} else { } else {
int32 pminw = qMin(st::medviewPolaroidMin.width(), int(_avail.width() - 2 * st::medviewNavBarWidth)); int32 pminw = qMin(st::medviewPolaroidMin.width(), int(_avail.width() - 2 * st::medviewNavBarWidth));

View File

@ -762,7 +762,12 @@ inline bool operator!=(const MTPstring &a, const MTPstring &b) {
inline QString qs(const MTPstring &v) { inline QString qs(const MTPstring &v) {
const string &d(v.c_string().v); const string &d(v.c_string().v);
return QString::fromUtf8(d.c_str(), d.length()); return QString::fromUtf8(d.data(), d.length());
}
inline QByteArray qba(const MTPstring &v) {
const string &d(v.c_string().v);
return QByteArray(d.data(), d.length());
} }
class MTPbool { class MTPbool {

View File

@ -254,8 +254,17 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
if (!locationType && triedLocal && (fname.isEmpty() || duplicateInData)) { if (!locationType && triedLocal && (fname.isEmpty() || duplicateInData)) {
Local::writeImage(storageKey(dc, volume, local), StorageImageSaved(type, data)); Local::writeImage(storageKey(dc, volume, local), StorageImageSaved(type, data));
} else if (locationType && triedLocal && !fname.isEmpty()) { } else if (locationType && triedLocal) {
Local::writeFileLocation(mediaKey(locationType, dc, id), FileLocation(type, fname)); if (!fname.isEmpty()) {
Local::writeFileLocation(mediaKey(locationType, dc, id), FileLocation(type, fname));
}
if (duplicateInData) {
if (locationType == mtpc_inputDocumentFileLocation) {
Local::writeSticker(mediaKey(locationType, dc, id), data);
} else if (locationType == mtpc_inputAudioFileLocation) {
Local::writeAudio(mediaKey(locationType, dc, id), data);
}
}
} }
} }
emit progress(this); emit progress(this);
@ -297,29 +306,44 @@ void mtpFileLoader::start(bool loadFirst, bool prior) {
StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local)); StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local));
if (cached.type != mtpc_storage_fileUnknown) { if (cached.type != mtpc_storage_fileUnknown) {
data = cached.data; data = cached.data;
if (!fname.isEmpty() && duplicateInData) {
if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
if (!fileIsOpen) {
return finishFail();
}
if (file.write(data) != qint64(data.size())) {
return finishFail();
}
}
type = cached.type; type = cached.type;
complete = true;
if (fileIsOpen) {
file.close();
fileIsOpen = false;
psPostprocessFile(QFileInfo(file).absoluteFilePath());
}
App::wnd()->update();
App::wnd()->notifyUpdateAllPhotos();
emit progress(this);
return loadNext();
} }
} else if (locationType && !fname.isEmpty()) { } else if (locationType) {
triedLocal = true; if (!fname.isEmpty()) {
triedLocal = true;
}
if (duplicateInData) {
if (locationType == mtpc_inputDocumentFileLocation) {
triedLocal = true;
data = Local::readSticker(mediaKey(locationType, dc, id));
if (!data.isEmpty()) type = mtpc_storage_filePartial;
} else if (locationType == mtpc_inputAudioFileLocation) {
triedLocal = true;
data = Local::readAudio(mediaKey(locationType, dc, id));
if (!data.isEmpty()) type = mtpc_storage_filePartial;
}
}
}
if (triedLocal && !data.isEmpty()) {
if (!fname.isEmpty() && duplicateInData) {
if (!fileIsOpen) fileIsOpen = file.open(QIODevice::WriteOnly);
if (!fileIsOpen) {
return finishFail();
}
if (file.write(data) != qint64(data.size())) {
return finishFail();
}
}
complete = true;
if (fileIsOpen) {
file.close();
fileIsOpen = false;
psPostprocessFile(QFileInfo(file).absoluteFilePath());
}
App::wnd()->update();
App::wnd()->notifyUpdateAllPhotos();
emit progress(this);
return loadNext();
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -357,6 +357,9 @@ enum {
mtpc_documentAttributeVideo = 0x5910cccb, mtpc_documentAttributeVideo = 0x5910cccb,
mtpc_documentAttributeAudio = 0x51448e5, mtpc_documentAttributeAudio = 0x51448e5,
mtpc_documentAttributeFilename = 0x15590068, mtpc_documentAttributeFilename = 0x15590068,
mtpc_stickerPack = 0x12b299d4,
mtpc_messages_allStickersNotModified = 0xe86602c3,
mtpc_messages_allStickers = 0xdcef3102,
mtpc_invokeAfterMsg = 0xcb9f372d, mtpc_invokeAfterMsg = 0xcb9f372d,
mtpc_invokeAfterMsgs = 0x3dc4b4f0, mtpc_invokeAfterMsgs = 0x3dc4b4f0,
mtpc_auth_checkPhone = 0x6fe51dfb, mtpc_auth_checkPhone = 0x6fe51dfb,
@ -463,7 +466,8 @@ enum {
mtpc_account_setAccountTTL = 0x2442485e, mtpc_account_setAccountTTL = 0x2442485e,
mtpc_contacts_resolveUsername = 0xbf0131c, mtpc_contacts_resolveUsername = 0xbf0131c,
mtpc_account_sendChangePhoneCode = 0xa407a8f4, mtpc_account_sendChangePhoneCode = 0xa407a8f4,
mtpc_account_changePhone = 0x70c32edb mtpc_account_changePhone = 0x70c32edb,
mtpc_messages_getAllStickers = 0xaa3bc868
}; };
// Type forward declarations // Type forward declarations
@ -962,6 +966,12 @@ class MTPDdocumentAttributeVideo;
class MTPDdocumentAttributeAudio; class MTPDdocumentAttributeAudio;
class MTPDdocumentAttributeFilename; class MTPDdocumentAttributeFilename;
class MTPstickerPack;
class MTPDstickerPack;
class MTPmessages_allStickers;
class MTPDmessages_allStickers;
// Boxed types definitions // Boxed types definitions
typedef MTPBoxed<MTPresPQ> MTPResPQ; typedef MTPBoxed<MTPresPQ> MTPResPQ;
@ -1092,6 +1102,8 @@ typedef MTPBoxed<MTPaccount_privacyRules> MTPaccount_PrivacyRules;
typedef MTPBoxed<MTPaccountDaysTTL> MTPAccountDaysTTL; typedef MTPBoxed<MTPaccountDaysTTL> MTPAccountDaysTTL;
typedef MTPBoxed<MTPaccount_sentChangePhoneCode> MTPaccount_SentChangePhoneCode; typedef MTPBoxed<MTPaccount_sentChangePhoneCode> MTPaccount_SentChangePhoneCode;
typedef MTPBoxed<MTPdocumentAttribute> MTPDocumentAttribute; typedef MTPBoxed<MTPdocumentAttribute> MTPDocumentAttribute;
typedef MTPBoxed<MTPstickerPack> MTPStickerPack;
typedef MTPBoxed<MTPmessages_allStickers> MTPmessages_AllStickers;
// Type classes definitions // Type classes definitions
@ -7133,6 +7145,75 @@ private:
}; };
typedef MTPBoxed<MTPdocumentAttribute> MTPDocumentAttribute; typedef MTPBoxed<MTPdocumentAttribute> MTPDocumentAttribute;
class MTPstickerPack : private mtpDataOwner {
public:
MTPstickerPack();
MTPstickerPack(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_stickerPack) : mtpDataOwner(0) {
read(from, end, cons);
}
MTPDstickerPack &_stickerPack() {
if (!data) throw mtpErrorUninitialized();
split();
return *(MTPDstickerPack*)data;
}
const MTPDstickerPack &c_stickerPack() const {
if (!data) throw mtpErrorUninitialized();
return *(const MTPDstickerPack*)data;
}
uint32 innerLength() const;
mtpTypeId type() const;
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_stickerPack);
void write(mtpBuffer &to) const;
typedef void ResponseType;
private:
explicit MTPstickerPack(MTPDstickerPack *_data);
friend MTPstickerPack MTP_stickerPack(const MTPstring &_emoticon, const MTPVector<MTPlong> &_documents);
};
typedef MTPBoxed<MTPstickerPack> MTPStickerPack;
class MTPmessages_allStickers : private mtpDataOwner {
public:
MTPmessages_allStickers() : mtpDataOwner(0), _type(0) {
}
MTPmessages_allStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) {
read(from, end, cons);
}
MTPDmessages_allStickers &_messages_allStickers() {
if (!data) throw mtpErrorUninitialized();
if (_type != mtpc_messages_allStickers) throw mtpErrorWrongTypeId(_type, mtpc_messages_allStickers);
split();
return *(MTPDmessages_allStickers*)data;
}
const MTPDmessages_allStickers &c_messages_allStickers() const {
if (!data) throw mtpErrorUninitialized();
if (_type != mtpc_messages_allStickers) throw mtpErrorWrongTypeId(_type, mtpc_messages_allStickers);
return *(const MTPDmessages_allStickers*)data;
}
uint32 innerLength() const;
mtpTypeId type() const;
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
void write(mtpBuffer &to) const;
typedef void ResponseType;
private:
explicit MTPmessages_allStickers(mtpTypeId type);
explicit MTPmessages_allStickers(MTPDmessages_allStickers *_data);
friend MTPmessages_allStickers MTP_messages_allStickersNotModified();
friend MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents);
mtpTypeId _type;
};
typedef MTPBoxed<MTPmessages_allStickers> MTPmessages_AllStickers;
// Type constructors with data // Type constructors with data
class MTPDresPQ : public mtpDataImpl<MTPDresPQ> { class MTPDresPQ : public mtpDataImpl<MTPDresPQ> {
@ -9997,6 +10078,29 @@ public:
MTPstring vfile_name; MTPstring vfile_name;
}; };
class MTPDstickerPack : public mtpDataImpl<MTPDstickerPack> {
public:
MTPDstickerPack() {
}
MTPDstickerPack(const MTPstring &_emoticon, const MTPVector<MTPlong> &_documents) : vemoticon(_emoticon), vdocuments(_documents) {
}
MTPstring vemoticon;
MTPVector<MTPlong> vdocuments;
};
class MTPDmessages_allStickers : public mtpDataImpl<MTPDmessages_allStickers> {
public:
MTPDmessages_allStickers() {
}
MTPDmessages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents) : vhash(_hash), vpacks(_packs), vdocuments(_documents) {
}
MTPstring vhash;
MTPVector<MTPStickerPack> vpacks;
MTPVector<MTPDocument> vdocuments;
};
// RPC methods // RPC methods
class MTPreq_pq { // RPC method 'req_pq' class MTPreq_pq { // RPC method 'req_pq'
@ -14855,6 +14959,45 @@ public:
} }
}; };
class MTPmessages_getAllStickers { // RPC method 'messages.getAllStickers'
public:
MTPstring vhash;
MTPmessages_getAllStickers() {
}
MTPmessages_getAllStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getAllStickers) {
read(from, end, cons);
}
MTPmessages_getAllStickers(const MTPstring &_hash) : vhash(_hash) {
}
uint32 innerLength() const {
return vhash.innerLength();
}
mtpTypeId type() const {
return mtpc_messages_getAllStickers;
}
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getAllStickers) {
vhash.read(from, end);
}
void write(mtpBuffer &to) const {
vhash.write(to);
}
typedef MTPmessages_AllStickers ResponseType;
};
class MTPmessages_GetAllStickers : public MTPBoxed<MTPmessages_getAllStickers> {
public:
MTPmessages_GetAllStickers() {
}
MTPmessages_GetAllStickers(const MTPmessages_getAllStickers &v) : MTPBoxed<MTPmessages_getAllStickers>(v) {
}
MTPmessages_GetAllStickers(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_getAllStickers>(from, end, cons) {
}
MTPmessages_GetAllStickers(const MTPstring &_hash) : MTPBoxed<MTPmessages_getAllStickers>(MTPmessages_getAllStickers(_hash)) {
}
};
// Inline methods definition // Inline methods definition
inline MTPresPQ::MTPresPQ() : mtpDataOwner(new MTPDresPQ()) { inline MTPresPQ::MTPresPQ() : mtpDataOwner(new MTPDresPQ()) {
@ -22980,6 +23123,88 @@ inline MTPdocumentAttribute MTP_documentAttributeFilename(const MTPstring &_file
return MTPdocumentAttribute(new MTPDdocumentAttributeFilename(_file_name)); return MTPdocumentAttribute(new MTPDdocumentAttributeFilename(_file_name));
} }
inline MTPstickerPack::MTPstickerPack() : mtpDataOwner(new MTPDstickerPack()) {
}
inline uint32 MTPstickerPack::innerLength() const {
const MTPDstickerPack &v(c_stickerPack());
return v.vemoticon.innerLength() + v.vdocuments.innerLength();
}
inline mtpTypeId MTPstickerPack::type() const {
return mtpc_stickerPack;
}
inline void MTPstickerPack::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
if (cons != mtpc_stickerPack) throw mtpErrorUnexpected(cons, "MTPstickerPack");
if (!data) setData(new MTPDstickerPack());
MTPDstickerPack &v(_stickerPack());
v.vemoticon.read(from, end);
v.vdocuments.read(from, end);
}
inline void MTPstickerPack::write(mtpBuffer &to) const {
const MTPDstickerPack &v(c_stickerPack());
v.vemoticon.write(to);
v.vdocuments.write(to);
}
inline MTPstickerPack::MTPstickerPack(MTPDstickerPack *_data) : mtpDataOwner(_data) {
}
inline MTPstickerPack MTP_stickerPack(const MTPstring &_emoticon, const MTPVector<MTPlong> &_documents) {
return MTPstickerPack(new MTPDstickerPack(_emoticon, _documents));
}
inline uint32 MTPmessages_allStickers::innerLength() const {
switch (_type) {
case mtpc_messages_allStickers: {
const MTPDmessages_allStickers &v(c_messages_allStickers());
return v.vhash.innerLength() + v.vpacks.innerLength() + v.vdocuments.innerLength();
}
}
return 0;
}
inline mtpTypeId MTPmessages_allStickers::type() const {
if (!_type) throw mtpErrorUninitialized();
return _type;
}
inline void MTPmessages_allStickers::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
if (cons != _type) setData(0);
switch (cons) {
case mtpc_messages_allStickersNotModified: _type = cons; break;
case mtpc_messages_allStickers: _type = cons; {
if (!data) setData(new MTPDmessages_allStickers());
MTPDmessages_allStickers &v(_messages_allStickers());
v.vhash.read(from, end);
v.vpacks.read(from, end);
v.vdocuments.read(from, end);
} break;
default: throw mtpErrorUnexpected(cons, "MTPmessages_allStickers");
}
}
inline void MTPmessages_allStickers::write(mtpBuffer &to) const {
switch (_type) {
case mtpc_messages_allStickers: {
const MTPDmessages_allStickers &v(c_messages_allStickers());
v.vhash.write(to);
v.vpacks.write(to);
v.vdocuments.write(to);
} break;
}
}
inline MTPmessages_allStickers::MTPmessages_allStickers(mtpTypeId type) : mtpDataOwner(0), _type(type) {
switch (type) {
case mtpc_messages_allStickersNotModified: break;
case mtpc_messages_allStickers: setData(new MTPDmessages_allStickers()); break;
default: throw mtpErrorBadTypeId(type, "MTPmessages_allStickers");
}
}
inline MTPmessages_allStickers::MTPmessages_allStickers(MTPDmessages_allStickers *_data) : mtpDataOwner(_data), _type(mtpc_messages_allStickers) {
}
inline MTPmessages_allStickers MTP_messages_allStickersNotModified() {
return MTPmessages_allStickers(mtpc_messages_allStickersNotModified);
}
inline MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents) {
return MTPmessages_allStickers(new MTPDmessages_allStickers(_hash, _packs, _documents));
}
// Human-readable text serialization // Human-readable text serialization
#if (defined _DEBUG || defined _WITH_DEBUG) #if (defined _DEBUG || defined _WITH_DEBUG)

View File

@ -549,6 +549,11 @@ documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
documentAttributeAudio#51448e5 duration:int = DocumentAttribute; documentAttributeAudio#51448e5 duration:int = DocumentAttribute;
documentAttributeFilename#15590068 file_name:string = DocumentAttribute; documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
messages.allStickersNotModified#e86602c3 = messages.AllStickers;
messages.allStickers#dcef3102 hash:string packs:Vector<StickerPack> documents:Vector<Document> = messages.AllStickers;
---functions--- ---functions---
invokeAfterMsg#cb9f372d msg_id:long query:!X = X; invokeAfterMsg#cb9f372d msg_id:long query:!X = X;
@ -682,3 +687,5 @@ contacts.resolveUsername#bf0131c username:string = User;
account.sendChangePhoneCode#a407a8f4 phone_number:string = account.SentChangePhoneCode; account.sendChangePhoneCode#a407a8f4 phone_number:string = account.SentChangePhoneCode;
account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User;
messages.getAllStickers#aa3bc868 hash:string = messages.AllStickers;

View File

@ -850,6 +850,8 @@ void OverviewInner::onUpdateSelected() {
textlnkOver(lnk); textlnkOver(lnk);
App::hoveredLinkItem(lnk ? item : 0); App::hoveredLinkItem(lnk ? item : 0);
updateMsg(App::hoveredLinkItem()); updateMsg(App::hoveredLinkItem());
} else {
App::mousedItem(item);
} }
fixItemIndex(_dragItemIndex, _dragItem); fixItemIndex(_dragItemIndex, _dragItem);
@ -1089,6 +1091,23 @@ void OverviewInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
_menu->addAction(lang(lng_context_select_msg), this, SLOT(selectMessage()))->setEnabled(true); _menu->addAction(lang(lng_context_select_msg), this, SLOT(selectMessage()))->setEnabled(true);
} }
App::contextItem(App::hoveredLinkItem()); App::contextItem(App::hoveredLinkItem());
} else if (App::mousedItem() && App::mousedItem()->id == _mousedItem) {
_menu = new ContextMenu(_overview);
_menu->addAction(lang(lng_context_to_msg), this, SLOT(goToMessage()))->setEnabled(true);
if (isUponSelected > 1) {
_menu->addAction(lang(lng_context_forward_selected), _overview, SLOT(onForwardSelected()));
_menu->addAction(lang(lng_context_delete_selected), _overview, SLOT(onDeleteSelected()));
_menu->addAction(lang(lng_context_clear_selection), _overview, SLOT(onClearSelected()));
} else {
if (isUponSelected != -2) {
if (dynamic_cast<HistoryMessage*>(App::mousedItem())) {
_menu->addAction(lang(lng_context_forward_msg), this, SLOT(forwardMessage()))->setEnabled(true);
}
_menu->addAction(lang(lng_context_delete_msg), this, SLOT(deleteMessage()))->setEnabled(true);
}
_menu->addAction(lang(lng_context_select_msg), this, SLOT(selectMessage()))->setEnabled(true);
}
App::contextItem(App::mousedItem());
} }
if (_menu) { if (_menu) {
_menu->deleteOnHide(); _menu->deleteOnHide();

View File

@ -72,6 +72,10 @@ DBIEmojiTab gEmojiTab = dbietRecent;
RecentEmojiPack gRecentEmojis; RecentEmojiPack gRecentEmojis;
RecentEmojiPreload gRecentEmojisPreload; RecentEmojiPreload gRecentEmojisPreload;
AllStickers gStickers;
QByteArray gStickersHash;
RecentStickerPack gRecentStickers;
int32 gLang = -2; // auto int32 gLang = -2; // auto
QString gLangFile; QString gLangFile;
@ -147,7 +151,7 @@ void settingsParseArgs(int argc, char *argv[]) {
const RecentEmojiPack &cGetRecentEmojis() { const RecentEmojiPack &cGetRecentEmojis() {
if (cRecentEmojis().isEmpty()) { if (cRecentEmojis().isEmpty()) {
RecentEmojiPack r; RecentEmojiPack r;
if (!cRecentEmojisPreload().isEmpty()) { if (false && !cRecentEmojisPreload().isEmpty()) {
RecentEmojiPreload p(cRecentEmojisPreload()); RecentEmojiPreload p(cRecentEmojisPreload());
cSetRecentEmojisPreload(RecentEmojiPreload()); cSetRecentEmojisPreload(RecentEmojiPreload());
r.reserve(p.size()); r.reserve(p.size());

View File

@ -145,6 +145,14 @@ DeclareSetting(RecentEmojiPreload, RecentEmojisPreload);
const RecentEmojiPack &cGetRecentEmojis(); const RecentEmojiPack &cGetRecentEmojis();
struct DocumentData;
typedef QVector<DocumentData*> StickerPack;
typedef QMap<EmojiPtr, StickerPack> AllStickers;
DeclareSetting(AllStickers, Stickers);
DeclareSetting(QByteArray, StickersHash);
typedef QList<QPair<DocumentData*, int16> > RecentStickerPack;
DeclareSetting(RecentStickerPack, RecentStickers);
DeclareSetting(int32, Lang); DeclareSetting(int32, Lang);
DeclareSetting(QString, LangFile); DeclareSetting(QString, LangFile);

View File

@ -160,10 +160,11 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
_catsAndDogs(this, lang(lng_settings_cats_and_dogs), cCatsAndDogs()), _catsAndDogs(this, lang(lng_settings_cats_and_dogs), cCatsAndDogs()),
// local storage // local storage
_localImagesClear(this, lang(lng_local_images_clear)), _localStorageClear(this, lang(lng_local_storage_clear)),
_imagesClearingWidth(st::linkFont->m.width(lang(lng_local_images_clearing))), _localStorageHeight(1),
_imagesClearedWidth(st::linkFont->m.width(lang(lng_local_images_cleared))), _storageClearingWidth(st::linkFont->m.width(lang(lng_local_storage_clearing))),
_imagesClearFailedWidth(st::linkFont->m.width(lang(lng_local_images_clear_failed))), _storageClearedWidth(st::linkFont->m.width(lang(lng_local_storage_cleared))),
_storageClearFailedWidth(st::linkFont->m.width(lang(lng_local_storage_clear_failed))),
// advanced // advanced
_connectionType(this, lng_connection_auto(lt_type, QString())), _connectionType(this, lng_connection_auto(lt_type, QString())),
@ -249,11 +250,11 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : QWidget(parent),
connect(&_catsAndDogs, SIGNAL(changed()), this, SLOT(onCatsAndDogs())); connect(&_catsAndDogs, SIGNAL(changed()), this, SLOT(onCatsAndDogs()));
// local storage // local storage
connect(&_localImagesClear, SIGNAL(clicked()), this, SLOT(onLocalImagesClear())); connect(&_localStorageClear, SIGNAL(clicked()), this, SLOT(onLocalStorageClear()));
switch (App::wnd()->localImagesState()) { switch (App::wnd()->localStorageState()) {
case Window::TempDirEmpty: _imagesClearState = TempDirEmpty; break; case Window::TempDirEmpty: _storageClearState = TempDirEmpty; break;
case Window::TempDirExists: _imagesClearState = TempDirExists; break; case Window::TempDirExists: _storageClearState = TempDirExists; break;
case Window::TempDirRemoving: _imagesClearState = TempDirClearing; break; case Window::TempDirRemoving: _storageClearState = TempDirClearing; break;
} }
// advanced // advanced
@ -481,27 +482,45 @@ void SettingsInner::paintEvent(QPaintEvent *e) {
p.setFont(st::setHeaderFont->f); p.setFont(st::setHeaderFont->f);
p.setPen(st::setHeaderColor->p); p.setPen(st::setHeaderColor->p);
p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_cache)); p.drawText(_left + st::setHeaderLeft, top + st::setHeaderTop + st::setHeaderFont->ascent, lang(lng_settings_section_cache));
top += st::setHeaderSkip;
QString localImagesText = lang(lng_settings_no_images_cached);
int32 cnt = Local::hasImages();
if (cnt) {
localImagesText = lng_settings_images_cached(lt_count, cnt, lt_size, formatSizeText(Local::storageFilesSize()));
}
p.setFont(st::linkFont->f); p.setFont(st::linkFont->f);
p.setPen(st::black->p); p.setPen(st::black->p);
p.drawText(_left + st::setHeaderLeft, top + st::linkFont->ascent, localImagesText);
QString clearText; QString clearText;
int32 clearWidth = 0; int32 clearWidth = 0;
switch (_imagesClearState) { switch (_storageClearState) {
case TempDirClearing: clearText = lang(lng_local_images_clearing); clearWidth = _imagesClearingWidth; break; case TempDirClearing: clearText = lang(lng_local_storage_clearing); clearWidth = _storageClearingWidth; break;
case TempDirCleared: clearText = lang(lng_local_images_cleared); clearWidth = _imagesClearedWidth; break; case TempDirCleared: clearText = lang(lng_local_storage_cleared); clearWidth = _storageClearedWidth; break;
case TempDirClearFailed: clearText = lang(lng_local_images_clear_failed); clearWidth = _imagesClearFailedWidth; break; case TempDirClearFailed: clearText = lang(lng_local_storage_clear_failed); clearWidth = _storageClearFailedWidth; break;
} }
if (clearWidth) { if (clearWidth) {
p.drawText(_left + st::setWidth - clearWidth, top + st::linkFont->ascent, clearText); p.drawText(_left + st::setWidth - clearWidth, top + st::setHeaderTop + st::setHeaderFont->ascent, clearText);
} }
top += _localImagesClear.height();
top += st::setHeaderSkip;
int32 cntImages = Local::hasImages() + Local::hasStickers(), cntAudios = Local::hasAudios();
if (cntImages > 0 && cntAudios > 0) {
if (_localStorageHeight != 2) {
cntAudios = 0;
QTimer::singleShot(0, this, SLOT(onUpdateLocalStorage()));
}
} else {
if (_localStorageHeight != 1) {
QTimer::singleShot(0, this, SLOT(onUpdateLocalStorage()));
}
}
if (cntImages > 0) {
QString cnt = lng_settings_images_cached(lt_count, cntImages, lt_size, formatSizeText(Local::storageImagesSize() + Local::storageStickersSize()));
p.drawText(_left + st::setHeaderLeft, top + st::linkFont->ascent, cnt);
}
if (_localStorageHeight == 2) top += _localStorageClear.height() + st::setLittleSkip;
if (cntAudios > 0) {
QString cnt = lng_settings_audios_cached(lt_count, cntAudios, lt_size, formatSizeText(Local::storageAudiosSize()));
p.drawText(_left + st::setHeaderLeft, top + st::linkFont->ascent, cnt);
} else if (cntImages <= 0) {
p.drawText(_left + st::setHeaderLeft, top + st::linkFont->ascent, lang(lng_settings_no_data_cached));
}
top += _localStorageClear.height();
} }
// advanced // advanced
@ -590,8 +609,15 @@ void SettingsInner::resizeEvent(QResizeEvent *e) {
_catsAndDogs.move(_left, top); top += _catsAndDogs.height(); _catsAndDogs.move(_left, top); top += _catsAndDogs.height();
// local storage // local storage
_localStorageClear.move(_left + st::setWidth - _localStorageClear.width(), top + st::setHeaderTop + st::setHeaderFont->ascent - st::linkFont->ascent);
top += st::setHeaderSkip; top += st::setHeaderSkip;
_localImagesClear.move(_left + st::setWidth - _localImagesClear.width(), top); top += _localImagesClear.height(); if ((Local::hasImages() || Local::hasStickers()) && Local::hasAudios()) {
_localStorageHeight = 2;
top += _localStorageClear.height() + st::setLittleSkip;
} else {
_localStorageHeight = 1;
}
top += _localStorageClear.height();
} }
// advanced // advanced
@ -816,14 +842,13 @@ void SettingsInner::showAll() {
_dontAskDownloadPath.hide(); _dontAskDownloadPath.hide();
_downloadPathEdit.hide(); _downloadPathEdit.hide();
_downloadPathClear.hide(); _downloadPathClear.hide();
_localImagesClear.hide();
} }
// local storage // local storage
if (self() && _imagesClearState == TempDirExists) { if (self() && _storageClearState == TempDirExists) {
_localImagesClear.show(); _localStorageClear.show();
} else { } else {
_localImagesClear.hide(); _localStorageClear.hide();
} }
// advanced // advanced
@ -935,6 +960,12 @@ void SettingsInner::onSaveTestLang() {
App::quit(); App::quit();
} }
void SettingsInner::onUpdateLocalStorage() {
resizeEvent(0);
updateSize(width());
update();
}
void SettingsInner::onAutoUpdate() { void SettingsInner::onAutoUpdate() {
cSetAutoUpdate(!cAutoUpdate()); cSetAutoUpdate(!cAutoUpdate());
App::writeConfig(); App::writeConfig();
@ -1210,9 +1241,9 @@ void SettingsInner::onDownloadPathClearSure() {
update(); update();
} }
void SettingsInner::onLocalImagesClear() { void SettingsInner::onLocalStorageClear() {
App::wnd()->tempDirDelete(Local::ClearManagerImages); App::wnd()->tempDirDelete(Local::ClearManagerStorage);
_imagesClearState = TempDirClearing; _storageClearState = TempDirClearing;
showAll(); showAll();
update(); update();
} }
@ -1220,8 +1251,8 @@ void SettingsInner::onLocalImagesClear() {
void SettingsInner::onTempDirCleared(int task) { void SettingsInner::onTempDirCleared(int task) {
if (task & Local::ClearManagerDownloads) { if (task & Local::ClearManagerDownloads) {
_tempDirClearState = TempDirCleared; _tempDirClearState = TempDirCleared;
} else if (task & Local::ClearManagerImages) { } else if (task & Local::ClearManagerStorage) {
_imagesClearState = TempDirCleared; _storageClearState = TempDirCleared;
} }
showAll(); showAll();
update(); update();
@ -1230,8 +1261,8 @@ void SettingsInner::onTempDirCleared(int task) {
void SettingsInner::onTempDirClearFailed(int task) { void SettingsInner::onTempDirClearFailed(int task) {
if (task & Local::ClearManagerDownloads) { if (task & Local::ClearManagerDownloads) {
_tempDirClearState = TempDirClearFailed; _tempDirClearState = TempDirClearFailed;
} else if (task & Local::ClearManagerImages) { } else if (task & Local::ClearManagerStorage) {
_imagesClearState = TempDirClearFailed; _storageClearState = TempDirClearFailed;
} }
showAll(); showAll();
update(); update();

View File

@ -127,7 +127,7 @@ public slots:
void onCatsAndDogs(); void onCatsAndDogs();
void onLocalImagesClear(); void onLocalStorageClear();
void onUpdateChecking(); void onUpdateChecking();
void onUpdateLatest(); void onUpdateLatest();
@ -145,6 +145,8 @@ public slots:
void onChangeLanguage(); void onChangeLanguage();
void onSaveTestLang(); void onSaveTestLang();
void onUpdateLocalStorage();
private: private:
void doneResetSessions(const MTPBool &res); void doneResetSessions(const MTPBool &res);
@ -222,9 +224,10 @@ private:
FlatCheckbox _catsAndDogs; FlatCheckbox _catsAndDogs;
// local storage // local storage
LinkButton _localImagesClear; LinkButton _localStorageClear;
int32 _imagesClearingWidth, _imagesClearedWidth, _imagesClearFailedWidth; int32 _localStorageHeight;
TempDirClearState _imagesClearState; int32 _storageClearingWidth, _storageClearedWidth, _storageClearFailedWidth;
TempDirClearState _storageClearState;
// advanced // advanced
LinkButton _connectionType, _resetSessions; LinkButton _connectionType, _resetSessions;

View File

@ -313,12 +313,13 @@ enum DBIScale {
}; };
enum DBIEmojiTab { enum DBIEmojiTab {
dbietRecent = -1, dbietRecent = -1,
dbietPeople = 0, dbietPeople = 0,
dbietNature = 1, dbietNature = 1,
dbietObjects = 2, dbietObjects = 2,
dbietPlaces = 3, dbietPlaces = 3,
dbietSymbols = 4, dbietSymbols = 4,
dbietStickers = 666,
}; };
enum DBIPlatform { enum DBIPlatform {

View File

@ -1044,11 +1044,11 @@ Window::TempDirState Window::tempDirState() {
return QDir(cTempDir()).exists() ? TempDirExists : TempDirEmpty; return QDir(cTempDir()).exists() ? TempDirExists : TempDirEmpty;
} }
Window::TempDirState Window::localImagesState() { Window::TempDirState Window::localStorageState() {
if (_clearManager && _clearManager->hasTask(Local::ClearManagerImages)) { if (_clearManager && _clearManager->hasTask(Local::ClearManagerStorage)) {
return TempDirRemoving; return TempDirRemoving;
} }
return Local::hasImages() ? TempDirExists : TempDirEmpty; return (Local::hasImages() || Local::hasStickers() || Local::hasAudios()) ? TempDirExists : TempDirEmpty;
} }
void Window::tempDirDelete(int task) { void Window::tempDirDelete(int task) {

View File

@ -201,7 +201,7 @@ public:
TempDirEmpty, TempDirEmpty,
}; };
TempDirState tempDirState(); TempDirState tempDirState();
TempDirState localImagesState(); TempDirState localStorageState();
void tempDirDelete(int task); void tempDirDelete(int task);
void quit(); void quit();