mirror of https://github.com/procxx/kepka.git
stickers emoji tab done, local cache for stickers, recent stickers and voice messages
This commit is contained in:
parent
59381b8ad2
commit
091bba0fc5
|
@ -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:";
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 |
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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();
|
||||||
|
//}
|
||||||
|
|
|
@ -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;
|
||||||
|
//
|
||||||
|
//};
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 ¤tText) {
|
void HistoryMessage::initMedia(const MTPMessageMedia &media, QString ¤tText) {
|
||||||
|
@ -3993,12 +3989,8 @@ void HistoryMessage::initMedia(const MTPMessageMedia &media, QString ¤tTex
|
||||||
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 ¤tTex
|
||||||
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);
|
||||||
|
|
|
@ -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 ¤tText);
|
void initMedia(const MTPMessageMedia &media, QString ¤tText);
|
||||||
|
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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
@ -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();
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue