media overview almost done

This commit is contained in:
John Preston 2014-08-15 15:19:32 +04:00
parent 7f976fa251
commit a2179c77ba
28 changed files with 1990 additions and 468 deletions

View File

@ -236,6 +236,21 @@ lng_profile_delete_and_exit: "Leave";
lng_profile_kick: "Kick";
lng_profile_sure_kick: "Kick {user} from the group?";
lng_profile_loading: "Loading...";
lng_profile_shared_media: "Shared media";
lng_profile_no_media: "No media in this conversation.";
lng_profile_photo: "{count} photo »";
lng_profile_photos: "{count} photos »";
lng_profile_photos_header: "Photos overview";
lng_profile_video: "{count} videofile »";
lng_profile_videos: "{count} videofiles »";
lng_profile_videos_header: "Videofiles overview";
lng_profile_document: "{count} document »";
lng_profile_documents: "{count} documents »";
lng_profile_documents_header: "Documents overview";
lng_profile_audio: "{count} voice message »";
lng_profile_audios: "{count} voice messages »";
lng_profile_audios_header: "Voice messages overview";
lng_profile_show_all_types: "Show all types";
lng_participant_filter: "Search";
lng_participant_invite: "Invite";
@ -333,6 +348,7 @@ lng_context_save_audio: "Save Audio As...";
lng_context_open_document: "Open File";
lng_context_save_document: "Save File As...";
lng_context_copy_text: "Copy Message Text";
lng_context_to_msg: "Go To Message";
lng_context_forward_msg: "Forward Message";
lng_context_delete_msg: "Delete Message";
lng_context_cancel_upload: "Cancel Upload";

View File

@ -1481,6 +1481,9 @@ medviewButton: flatButton(btnDefFlat) {
overFont: font(16px);
}
overviewPhotoSkip: 10px;
overviewPhotoMinSize: 100px;
// Mac specific
macAccessoryHeight: 90;

View File

@ -667,40 +667,44 @@ namespace App {
}
PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs) {
const QPixmap *thumb = 0, *full = 0;
int32 thumbLevel = -1, fullLevel = -1;
const QPixmap *thumb = 0, *medium = 0, *full = 0;
int32 thumbLevel = -1, mediumLevel = -1, fullLevel = -1;
for (PreparedPhotoThumbs::const_iterator i = thumbs.cbegin(), e = thumbs.cend(); i != e; ++i) {
int32 newThumbLevel = -1, newFullLevel = -1;
int32 newThumbLevel = -1, newMediumLevel = -1, newFullLevel = -1;
switch (i.key()) {
case 's': newThumbLevel = 0; newFullLevel = 4; break; // box 100x100
case 'm': newThumbLevel = 2; newFullLevel = 3; break; // box 320x320
case 'x': newThumbLevel = 5; newFullLevel = 0; break; // box 800x800
case 'y': newThumbLevel = 6; newFullLevel = 1; break; // box 1280x1280
case 'w': newThumbLevel = 8; newFullLevel = 2; break; // box 2560x2560
case 'a': newThumbLevel = 1; newFullLevel = 8; break; // crop 160x160
case 'b': newThumbLevel = 3; newFullLevel = 7; break; // crop 320x320
case 'c': newThumbLevel = 4; newFullLevel = 6; break; // crop 640x640
case 'd': newThumbLevel = 7; newFullLevel = 5; break; // crop 1280x1280
case 's': newThumbLevel = 0; newMediumLevel = 5; newFullLevel = 4; break; // box 100x100
case 'm': newThumbLevel = 2; newMediumLevel = 0; newFullLevel = 3; break; // box 320x320
case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 0; break; // box 800x800
case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 1; break; // box 1280x1280
case 'w': newThumbLevel = 8; newMediumLevel = 8; newFullLevel = 2; break; // box 2560x2560
case 'a': newThumbLevel = 1; newMediumLevel = 4; newFullLevel = 8; break; // crop 160x160
case 'b': newThumbLevel = 3; newMediumLevel = 1; newFullLevel = 7; break; // crop 320x320
case 'c': newThumbLevel = 4; newMediumLevel = 2; newFullLevel = 6; break; // crop 640x640
case 'd': newThumbLevel = 7; newMediumLevel = 7; newFullLevel = 5; break; // crop 1280x1280
}
if (newThumbLevel < 0 || newFullLevel < 0) {
if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) {
continue;
}
if (thumbLevel < 0 || newThumbLevel < thumbLevel) {
thumbLevel = newThumbLevel;
thumb = &i.value();
}
if (mediumLevel < 0 || newMediumLevel < mediumLevel) {
mediumLevel = newMediumLevel;
medium = &i.value();
}
if (fullLevel < 0 || newFullLevel < fullLevel) {
fullLevel = newFullLevel;
full = &i.value();
}
}
if (!thumb || !full) {
if (!thumb || !medium || !full) {
return App::photo(0);
}
switch (photo.type()) {
case mtpc_photo: {
const MTPDphoto &ph(photo.c_photo());
return App::photo(ph.vid.v, 0, ph.vaccess_hash.v, ph.vuser_id.v, ph.vdate.v, ImagePtr(*thumb, "JPG"), ImagePtr(*full, "JPG"));
return App::photo(ph.vid.v, 0, ph.vaccess_hash.v, ph.vuser_id.v, ph.vdate.v, ImagePtr(*thumb, "JPG"), ImagePtr(*medium, "JPG"), ImagePtr(*full, "JPG"));
} break;
case mtpc_photoEmpty: return App::photo(photo.c_photoEmpty().vid.v);
}
@ -709,8 +713,8 @@ namespace App {
PhotoData *feedPhoto(const MTPDphoto &photo, PhotoData *convert) {
const QVector<MTPPhotoSize> &sizes(photo.vsizes.c_vector().v);
const MTPPhotoSize *thumb = 0, *full = 0;
int32 thumbLevel = -1, fullLevel = -1;
const MTPPhotoSize *thumb = 0, *medium = 0, *full = 0;
int32 thumbLevel = -1, mediumLevel = -1, fullLevel = -1;
for (QVector<MTPPhotoSize>::const_iterator i = sizes.cbegin(), e = sizes.cend(); i != e; ++i) {
char size = 0;
switch (i->type()) {
@ -726,32 +730,36 @@ namespace App {
}
if (!size) continue;
int32 newThumbLevel = -1, newFullLevel = -1;
int32 newThumbLevel = -1, newMediumLevel = -1, newFullLevel = -1;
switch (size) {
case 's': newThumbLevel = 0; newFullLevel = 4; break; // box 100x100
case 'm': newThumbLevel = 2; newFullLevel = 3; break; // box 320x320
case 'x': newThumbLevel = 5; newFullLevel = 0; break; // box 800x800
case 'y': newThumbLevel = 6; newFullLevel = 1; break; // box 1280x1280
case 'w': newThumbLevel = 8; newFullLevel = 2; break; // box 2560x2560
case 'a': newThumbLevel = 1; newFullLevel = 8; break; // crop 160x160
case 'b': newThumbLevel = 3; newFullLevel = 7; break; // crop 320x320
case 'c': newThumbLevel = 4; newFullLevel = 6; break; // crop 640x640
case 'd': newThumbLevel = 7; newFullLevel = 5; break; // crop 1280x1280
case 's': newThumbLevel = 0; newMediumLevel = 5; newFullLevel = 4; break; // box 100x100
case 'm': newThumbLevel = 2; newMediumLevel = 0; newFullLevel = 3; break; // box 320x320
case 'x': newThumbLevel = 5; newMediumLevel = 3; newFullLevel = 0; break; // box 800x800
case 'y': newThumbLevel = 6; newMediumLevel = 6; newFullLevel = 1; break; // box 1280x1280
case 'w': newThumbLevel = 8; newMediumLevel = 8; newFullLevel = 2; break; // box 2560x2560
case 'a': newThumbLevel = 1; newMediumLevel = 4; newFullLevel = 8; break; // crop 160x160
case 'b': newThumbLevel = 3; newMediumLevel = 1; newFullLevel = 7; break; // crop 320x320
case 'c': newThumbLevel = 4; newMediumLevel = 2; newFullLevel = 6; break; // crop 640x640
case 'd': newThumbLevel = 7; newMediumLevel = 7; newFullLevel = 5; break; // crop 1280x1280
}
if (newThumbLevel < 0 || newFullLevel < 0) {
if (newThumbLevel < 0 || newMediumLevel < 0 || newFullLevel < 0) {
continue;
}
if (thumbLevel < 0 || newThumbLevel < thumbLevel) {
thumbLevel = newThumbLevel;
thumb = &(*i);
}
if (mediumLevel < 0 || newMediumLevel < mediumLevel) {
mediumLevel = newMediumLevel;
medium = &(*i);
}
if (fullLevel < 0 || newFullLevel < fullLevel) {
fullLevel = newFullLevel;
full = &(*i);
}
}
if (thumb && full) {
return App::photo(photo.vid.v, convert, photo.vaccess_hash.v, photo.vuser_id.v, photo.vdate.v, App::image(*thumb), App::image(*full));
if (thumb && medium && full) {
return App::photo(photo.vid.v, convert, photo.vaccess_hash.v, photo.vuser_id.v, photo.vdate.v, App::image(*thumb), App::image(*medium), App::image(*full));
}
return App::photo(photo.vid.v, convert);
}
@ -850,7 +858,7 @@ namespace App {
return App::peer(App::peerFromChat(chat))->asChat();
}
PhotoData *photo(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 user, int32 date, const ImagePtr &thumb, const ImagePtr &full) {
PhotoData *photo(const PhotoId &photo, PhotoData *convert, const uint64 &access, int32 user, int32 date, const ImagePtr &thumb, const ImagePtr &medium, const ImagePtr &full) {
if (convert) {
if (convert->id != photo) {
PhotosData::iterator i = photosData.find(convert->id);
@ -864,6 +872,7 @@ namespace App {
convert->user = user;
convert->date = date;
convert->thumb = thumb;
convert->medium = medium;
convert->full = full;
}
}
@ -874,7 +883,7 @@ namespace App {
if (convert) {
result = convert;
} else {
result = new PhotoData(photo, access, user, date, thumb, full);
result = new PhotoData(photo, access, user, date, thumb, medium, full);
}
photosData.insert(photo, result);
} else {
@ -884,6 +893,7 @@ namespace App {
result->user = user;
result->date = date;
result->thumb = thumb;
result->medium = medium;
result->full = full;
}
inLastIter = lastPhotosMap.find(result);

View File

@ -101,7 +101,7 @@ namespace App {
ChatData *chat(const PeerId &peer);
ChatData *chat(int32 chat);
QString peerName(const PeerData *peer, bool forDialogs = false);
PhotoData *photo(const PhotoId &photo, PhotoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = 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());
void forgetPhotos();
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);
void forgetVideos();

View File

@ -374,6 +374,10 @@ void Application::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId)
photoThumbs.insert('a', thumb);
photoSizes.push_back(MTP_photoSize(MTP_string("a"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));
QPixmap medium = QPixmap::fromImage(tosend.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation));
photoThumbs.insert('b', medium);
photoSizes.push_back(MTP_photoSize(MTP_string("b"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));
QPixmap full = QPixmap::fromImage(tosend);
photoThumbs.insert('c', full);
photoSizes.push_back(MTP_photoSize(MTP_string("c"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));

View File

@ -66,6 +66,7 @@ enum {
AutoSearchTimeout = 900, // 0.9 secs
SearchPerPage = 50,
SearchManyPerPage = 100,
MediaOverviewStartPerPage = 5,
MediaOverviewPreloadCount = 4,
};

View File

@ -659,8 +659,10 @@ History::History(const PeerId &peerId) : width(0), height(0)
, posInDialogs(0)
, typingText(st::dlgRichMinWidth)
, myTyping(0)
, _photosOverviewCount(-1) // not loaded yet
{
for (int32 i = 0; i < OverviewCount; ++i) {
_overviewCount[i] = -1; // not loaded yet
}
}
void History::updateNameText() {
@ -1085,12 +1087,15 @@ HistoryItem *History::doAddToBack(HistoryBlock *to, bool newBlock, HistoryItem *
newItemAdded(adding);
}
HistoryMedia *media = adding->getMedia(true);
if (media && media->type() == MediaTypePhoto) {
if (_photosOverviewIds.constFind(adding->id) == _photosOverviewIds.cend()) {
_photosOverview.push_back(adding->id);
_photosOverviewIds.insert(adding->id);
if (_photosOverviewCount > 0) ++_photosOverviewCount;
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer);
if (media) {
MediaOverviewType t = mediaToOverviewType(media->type());
if (t != OverviewCount) {
if (_overviewIds[t].constFind(adding->id) == _overviewIds[t].cend()) {
_overview[t].push_back(adding->id);
_overviewIds[t].insert(adding->id, NullType());
if (_overviewCount[t] > 0) ++_overviewCount[t];
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer);
}
}
}
return adding;
@ -1180,10 +1185,13 @@ void History::addToFront(const QVector<MTPMessage> &slice) {
for (int32 i = block->size(); i > 0; --i) {
HistoryItem *item = (*block)[i - 1];
HistoryMedia *media = item->getMedia(true);
if (media && media->type() == MediaTypePhoto) {
if (_photosOverviewIds.constFind(item->id) == _photosOverviewIds.cend()) {
_photosOverview.push_front(item->id);
_photosOverviewIds.insert(item->id);
if (media) {
MediaOverviewType t = mediaToOverviewType(media->type());
if (t != OverviewCount) {
if (_overviewIds[t].constFind(item->id) == _overviewIds[t].cend()) {
_overview[t].push_front(item->id);
_overviewIds[t].insert(item->id, NullType());
}
}
}
}
@ -1262,17 +1270,22 @@ void History::addToBack(const QVector<MTPMessage> &slice) {
delete block;
}
if (!wasLoadedAtBottom && loadedAtBottom()) { // add all loaded photos to overview
_photosOverview.clear();
_photosOverviewIds.clear();
_photosOverviewCount = -1; // full count unknown
for (int32 i = 0; i < OverviewCount; ++i) {
if (_overviewCount[i] == 0) continue; // all loaded
_overview[i].clear();
_overviewIds[i].clear();
}
for (int32 i = 0; i < size(); ++i) {
HistoryBlock *b = (*this)[i];
for (int32 j = 0; j < b->size(); ++j) {
HistoryItem *item = (*b)[j];
HistoryMedia *media = item->getMedia(true);
if (media && media->type() == MediaTypePhoto) {
_photosOverview.push_back(item->id);
_photosOverviewIds.insert(item->id);
if (media) {
MediaOverviewType t = mediaToOverviewType(media->type());
if (t != OverviewCount && _overviewCount[t] != 0) {
_overview[t].push_back(item->id);
_overviewIds[t].insert(item->id, NullType());
}
}
}
}
@ -1513,9 +1526,11 @@ void History::clear(bool leaveItems) {
if (showFrom) {
showFrom = 0;
}
_photosOverview.clear();
_photosOverviewIds.clear();
_photosOverviewCount = -1; // full count unknown
for (int32 i = 0; i < OverviewCount; ++i) {
if (_overviewCount[i] == 0) _overviewCount[i] = _overview[i].size();
_overview[i].clear();
_overviewIds[i].clear();
}
if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer);
for (Parent::const_iterator i = cbegin(), e = cend(); i != e; ++i) {
if (leaveItems) {
@ -1721,17 +1736,18 @@ void HistoryItem::destroy() {
history()->fixLastMessage(wasAtBottom);
}
HistoryMedia *m = getMedia(true);
if (m && m->type() == MediaTypePhoto && !history()->_photosOverviewIds.isEmpty()) {
History::MediaOverviewIds::iterator i = history()->_photosOverviewIds.find(id);
if (i != history()->_photosOverviewIds.cend()) {
history()->_photosOverviewIds.erase(i);
for (History::MediaOverview::iterator i = history()->_photosOverview.begin(), e = history()->_photosOverview.end(); i != e; ++i) {
MediaOverviewType t = m ? mediaToOverviewType(m->type()) : OverviewCount;
if (t != OverviewCount && !history()->_overviewIds[t].isEmpty()) {
History::MediaOverviewIds::iterator i = history()->_overviewIds[t].find(id);
if (i != history()->_overviewIds[t].cend()) {
history()->_overviewIds[t].erase(i);
for (History::MediaOverview::iterator i = history()->_overview[t].begin(), e = history()->_overview[t].end(); i != e; ++i) {
if ((*i) == id) {
history()->_photosOverview.erase(i);
if (history()->_photosOverviewCount > 0) {
--history()->_photosOverviewCount;
if (!history()->_photosOverviewCount) {
history()->_photosOverviewCount = -1;
history()->_overview[t].erase(i);
if (history()->_overviewCount[t] > 0) {
--history()->_overviewCount[t];
if (!history()->_overviewCount[t]) {
history()->_overviewCount[t] = -1;
}
}
break;
@ -1827,12 +1843,14 @@ const QString HistoryPhoto::inDialogsText() const {
return lang(lng_in_dlg_photo);
}
bool HistoryPhoto::hasPoint(int32 x, int32 y) const {
return (x >= 0 && y >= 0 && x < _maxw && y < _height);
bool HistoryPhoto::hasPoint(int32 x, int32 y, int32 width) const {
if (width < 0) width = _maxw;
return (x >= 0 && y >= 0 && x < width && y < _height);
}
TextLinkPtr HistoryPhoto::getLink(int32 x, int32 y, const HistoryItem *parent) const {
if (x >= 0 && y >= 0 && x < _maxw && y < _height) {
TextLinkPtr HistoryPhoto::getLink(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
if (width < 0) width = _maxw;
if (x >= 0 && y >= 0 && x < width && y < _height) {
return openl;
}
return TextLinkPtr();
@ -1852,31 +1870,33 @@ HistoryMedia *HistoryPhoto::clone() const {
return new HistoryPhoto(*this);
}
void HistoryPhoto::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const {
void HistoryPhoto::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
if (width < 0) width = _maxw;
data->full->load(false, false);
bool out = parent->out();
if (parent != App::contextItem() || /*App::wnd()->photoShown() != data*/ true) {
if (data->full->loaded()) {
p.drawPixmap(0, 0, data->full->pix(_maxw, _height));
p.drawPixmap(0, 0, data->full->pix(width, _height));
} else {
p.drawPixmap(0, 0, data->thumb->pixBlurred(_maxw, _height));
p.drawPixmap(0, 0, data->thumb->pixBlurred(width, _height));
}
if (selected) {
p.fillRect(0, 0, _maxw, _height, textstyleCurrent()->selectOverlay->b);
p.fillRect(0, 0, width, _height, textstyleCurrent()->selectOverlay->b);
}
style::color shadow(selected ? st::msgInSelectShadow : st::msgInShadow);
p.fillRect(0, _height, _maxw, st::msgShadow, shadow->b);
p.fillRect(0, _height, width, st::msgShadow, shadow->b);
}
// date
QString time(parent->time());
if (time.isEmpty()) return;
int32 dateX = _maxw - timeWidth - st::msgDateImgDelta - 2 * st::msgDateImgPadding.x();
int32 dateX = width - parent->timeWidth() - st::msgDateImgDelta - 2 * st::msgDateImgPadding.x();
int32 dateY = _height - st::msgDateFont->height - 2 * st::msgDateImgPadding.y() - st::msgDateImgDelta;
if (parent->out()) {
dateX -= st::msgCheckRect.pxWidth() + st::msgDateImgCheckSpace;
}
int32 dateW = _maxw - dateX - st::msgDateImgDelta;
int32 dateW = width - dateX - st::msgDateImgDelta;
int32 dateH = _height - dateY - st::msgDateImgDelta;
p.fillRect(dateX, dateY, dateW, dateH, st::msgDateImgBg->b);
@ -1976,7 +1996,7 @@ void HistoryVideo::reinit() {
_maxw = st::mediaMaxWidth;
}
void HistoryVideo::initDimensions(const HistoryItem *parent, int32 timeWidth) {
void HistoryVideo::initDimensions(const HistoryItem *parent) {
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
if (!parent->out()) { // add Download / Save As button
_maxw += st::mediaSaveDelta + _buttonWidth;
@ -2000,16 +2020,16 @@ const QString HistoryVideo::inDialogsText() const {
return lang(lng_in_dlg_video);
}
bool HistoryVideo::hasPoint(int32 x, int32 y) const {
int32 width = w;
bool HistoryVideo::hasPoint(int32 x, int32 y, int32 width) const {
if (width < 0) width = w;
if (width >= _maxw) {
width = _maxw;
}
return (x >= 0 && y >= 0 && x < width && y < _height);
}
TextLinkPtr HistoryVideo::getLink(int32 x, int32 y, const HistoryItem *parent) const {
int32 width = w;
TextLinkPtr HistoryVideo::getLink(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
if (width < 0) width = w;
if (width < 1) return TextLinkPtr();
bool out = parent->out(), hovered, pressed;
@ -2047,8 +2067,8 @@ HistoryMedia *HistoryVideo::clone() const {
return n;
}
void HistoryVideo::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const {
int32 width = w;
void HistoryVideo::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
if (width < 0) width = w;
if (width < 1) return;
data->thumb->checkload();
@ -2095,7 +2115,7 @@ void HistoryVideo::draw(QPainter &p, const HistoryItem *parent, const QString &t
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
int32 twidth = width - tleft - st::mediaPadding.right();
int32 fullTimeWidth = timeWidth + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 fullTimeWidth = parent->timeWidth() + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 secondwidth = width - tleft - fullTimeWidth;
p.setFont(st::mediaFont->f);
@ -2133,7 +2153,7 @@ void HistoryVideo::draw(QPainter &p, const HistoryItem *parent, const QString &t
style::color date(selected ? (out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out ? st::msgOutDateColor : st::msgInDateColor));
p.setPen(date->p);
p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time);
p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, parent->time());
if (out) {
QPoint iconPos(width + 5 - st::msgPadding.right() - st::msgCheckRect.pxWidth(), _height + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.pxHeight());
const QRect *iconRect;
@ -2176,15 +2196,15 @@ void HistoryAudio::reinit() {
_maxw = st::mediaMaxWidth;
}
void HistoryAudio::initDimensions(const HistoryItem *parent, int32 timeWidth) {
void HistoryAudio::initDimensions(const HistoryItem *parent) {
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
if (!parent->out()) { // add Download / Save As button
_maxw += st::mediaSaveDelta + _buttonWidth;
}
}
void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const {
int32 width = w;
void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
if (width < 0) width = w;
if (width < 1) return;
bool out = parent->out(), hovered, pressed;
@ -2224,7 +2244,7 @@ void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, const QString &t
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
int32 twidth = width - tleft - st::mediaPadding.right();
int32 fullTimeWidth = timeWidth + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 fullTimeWidth = parent->timeWidth() + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 secondwidth = width - tleft - fullTimeWidth;
p.setFont(st::mediaFont->f);
@ -2262,7 +2282,7 @@ void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, const QString &t
style::color date(selected ? (out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out ? st::msgOutDateColor : st::msgInDateColor));
p.setPen(date->p);
p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time);
p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, parent->time());
if (out) {
QPoint iconPos(width + 5 - st::msgPadding.right() - st::msgCheckRect.pxWidth(), _height + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.pxHeight());
const QRect *iconRect;
@ -2296,16 +2316,16 @@ const QString HistoryAudio::inDialogsText() const {
return lang(lng_in_dlg_audio);
}
bool HistoryAudio::hasPoint(int32 x, int32 y) const {
int32 width = w;
bool HistoryAudio::hasPoint(int32 x, int32 y, int32 width) const {
if (width < 0) width = w;
if (width >= _maxw) {
width = _maxw;
}
return (x >= 0 && y >= 0 && x < width && y < _height);
}
TextLinkPtr HistoryAudio::getLink(int32 x, int32 y, const HistoryItem *parent) const {
int32 width = w;
TextLinkPtr HistoryAudio::getLink(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
if (width < 0) width = w;
if (width < 1) return TextLinkPtr();
bool out = parent->out(), hovered, pressed;
@ -2376,7 +2396,7 @@ void HistoryDocument::reinit() {
_maxw = st::mediaMaxWidth;
}
void HistoryDocument::initDimensions(const HistoryItem *parent, int32 timeWidth) {
void HistoryDocument::initDimensions(const HistoryItem *parent) {
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
if (_namew + tleft + st::mediaPadding.right() > _maxw) {
_maxw = _namew + tleft + st::mediaPadding.right();
@ -2386,8 +2406,8 @@ void HistoryDocument::initDimensions(const HistoryItem *parent, int32 timeWidth)
}
}
void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const {
int32 width = w;
void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
if (width < 0) width = w;
if (width < 1) return;
data->thumb->checkload();
@ -2434,7 +2454,7 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, const QString
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
int32 twidth = width - tleft - st::mediaPadding.right();
int32 fullTimeWidth = timeWidth + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 fullTimeWidth = parent->timeWidth() + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 secondwidth = width - tleft - fullTimeWidth;
p.setFont(st::mediaFont->f);
@ -2476,7 +2496,7 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, const QString
style::color date(selected ? (out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out ? st::msgOutDateColor : st::msgInDateColor));
p.setPen(date->p);
p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time);
p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, parent->time());
if (out) {
QPoint iconPos(width + 5 - st::msgPadding.right() - st::msgCheckRect.pxWidth(), _height + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.pxHeight());
const QRect *iconRect;
@ -2516,16 +2536,16 @@ const QString HistoryDocument::inDialogsText() const {
return lang(lng_in_dlg_document);
}
bool HistoryDocument::hasPoint(int32 x, int32 y) const {
int32 width = w;
bool HistoryDocument::hasPoint(int32 x, int32 y, int32 width) const {
if (width < 0) width = w;
if (width >= _maxw) {
width = _maxw;
}
return (x >= 0 && y >= 0 && x < width && y < _height);
}
TextLinkPtr HistoryDocument::getLink(int32 x, int32 y, const HistoryItem *parent) const {
int32 width = w;
TextLinkPtr HistoryDocument::getLink(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
if (width < 0) width = w;
if (width < 1) return TextLinkPtr();
bool out = parent->out(), hovered, pressed;
@ -2575,9 +2595,9 @@ HistoryContact::HistoryContact(int32 userId, const QString &first, const QString
}
}
void HistoryContact::initDimensions(const HistoryItem *parent, int32 timeWidth) {
void HistoryContact::initDimensions(const HistoryItem *parent) {
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
int32 fullTimeWidth = timeWidth + st::msgDateSpace + (parent->out() ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 fullTimeWidth = parent->timeWidth() + st::msgDateSpace + (parent->out() ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
if (name.maxWidth() + tleft + fullTimeWidth > _maxw) {
_maxw = name.maxWidth() + tleft + fullTimeWidth;
}
@ -2595,12 +2615,14 @@ const QString HistoryContact::inDialogsText() const {
return lang(lng_in_dlg_contact);
}
bool HistoryContact::hasPoint(int32 x, int32 y) const {
return (x >= 0 && y <= 0 && x < _maxw && y < _height);
bool HistoryContact::hasPoint(int32 x, int32 y, int32 width) const {
if (width < 0) width = w;
return (x >= 0 && y <= 0 && x < w && y < _height);
}
TextLinkPtr HistoryContact::getLink(int32 x, int32 y, const HistoryItem *parent) const {
if (x >= 0 && y >= 0 && x < _maxw && y < _height && contact) {
TextLinkPtr HistoryContact::getLink(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
if (width < 0) width = w;
if (x >= 0 && y >= 0 && x < w && y < _height && contact) {
return contact->lnk;
}
return TextLinkPtr();
@ -2617,8 +2639,8 @@ HistoryMedia *HistoryContact::clone() const {
return result;
}
void HistoryContact::draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const {
int32 width = w;
void HistoryContact::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
if (width < 0) width = w;
if (width < 1) return;
bool out = parent->out();
@ -2636,7 +2658,7 @@ void HistoryContact::draw(QPainter &p, const HistoryItem *parent, const QString
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
int32 twidth = width - tleft - st::mediaPadding.right();
int32 fullTimeWidth = timeWidth + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 fullTimeWidth = parent->timeWidth() + st::msgDateSpace + (out ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) + st::msgPadding.right() - st::msgDateDelta.x();
int32 secondwidth = width - tleft - fullTimeWidth;
p.setFont(st::mediaFont->f);
@ -2657,7 +2679,7 @@ void HistoryContact::draw(QPainter &p, const HistoryItem *parent, const QString
style::color date(selected ? (out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out ? st::msgOutDateColor : st::msgInDateColor));
p.setPen(date->p);
p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time);
p.drawText(width + st::msgDateDelta.x() - fullTimeWidth + st::msgDateSpace, _height - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, parent->time());
if (out) {
QPoint iconPos(width + 5 - st::msgPadding.right() - st::msgCheckRect.pxWidth(), _height + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.pxHeight());
const QRect *iconRect;
@ -2679,7 +2701,7 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, const MTPD
, _text(st::msgMinWidth)
, _textWidth(0)
, _textHeight(0)
, media(0)
, _media(0)
{
QString text(textClean(qs(msg.vmessage)));
initMedia(msg.vmedia, text);
@ -2703,7 +2725,7 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgI
, _text(st::msgMinWidth)
, _textWidth(0)
, _textHeight(0)
, media(0)
, _media(0)
{
QString text(msg);
initMedia(media, text);
@ -2715,12 +2737,12 @@ HistoryMessage::HistoryMessage(History *history, HistoryBlock *block, MsgId msgI
, _text(st::msgMinWidth)
, _textWidth(0)
, _textHeight(0)
, media(0)
, _media(0)
{
QString text(msg);
if (fromMedia) {
media = fromMedia->clone();
media->regItem(this);
_media = fromMedia->clone();
_media->regItem(this);
}
initDimensions(text);
}
@ -2730,7 +2752,7 @@ void HistoryMessage::initMedia(const MTPMessageMedia &media, QString &currentTex
case mtpc_messageMediaEmpty: break;
case mtpc_messageMediaContact: {
const MTPDmessageMediaContact &d(media.c_messageMediaContact());
this->media = new HistoryContact(d.vuser_id.v, qs(d.vfirst_name), qs(d.vlast_name), qs(d.vphone_number));
_media = new HistoryContact(d.vuser_id.v, qs(d.vfirst_name), qs(d.vlast_name), qs(d.vphone_number));
} break;
case mtpc_messageMediaGeo: {
const MTPGeoPoint &point(media.c_messageMediaGeo().vgeo);
@ -2743,43 +2765,43 @@ void HistoryMessage::initMedia(const MTPMessageMedia &media, QString &currentTex
case mtpc_messageMediaPhoto: {
const MTPPhoto &photo(media.c_messageMediaPhoto().vphoto);
if (photo.type() == mtpc_photo) {
this->media = new HistoryPhoto(photo.c_photo());
_media = new HistoryPhoto(photo.c_photo());
}
} break;
case mtpc_messageMediaVideo: {
const MTPVideo &video(media.c_messageMediaVideo().vvideo);
if (video.type() == mtpc_video) {
this->media = new HistoryVideo(video.c_video());
_media = new HistoryVideo(video.c_video());
}
} break;
case mtpc_messageMediaAudio: {
const MTPAudio &audio(media.c_messageMediaAudio().vaudio);
if (audio.type() == mtpc_audio) {
this->media = new HistoryAudio(audio.c_audio());
_media = new HistoryAudio(audio.c_audio());
}
} break;
case mtpc_messageMediaDocument: {
const MTPDocument &document(media.c_messageMediaDocument().vdocument);
if (document.type() == mtpc_document) {
this->media = new HistoryDocument(document.c_document());
_media = new HistoryDocument(document.c_document());
}
} break;
case mtpc_messageMediaUnsupported:
default: currentText += " (unsupported media)"; break;
};
if (this->media) this->media->regItem(this);
if (_media) _media->regItem(this);
}
void HistoryMessage::initDimensions(const QString &text) {
time = date.toString(qsl("hh:mm"));
timeWidth = st::msgDateFont->m.width(time);
if (media) {
media->initDimensions(this, timeWidth);
_maxw = media->maxWidth();
_minh = media->height();
_time = date.toString(qsl("hh:mm"));
_timeWidth = st::msgDateFont->m.width(_time);
if (_media) {
_media->initDimensions(this);
_maxw = _media->maxWidth();
_minh = _media->height();
} else {
timeWidth += st::msgDateSpace + (out() ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) - st::msgDateDelta.x();
_text.setText(st::msgFont, text + textcmdSkipBlock(timeWidth, st::msgDateFont->height - st::msgDateDelta.y()), _historyTextOptions);
_timeWidth += st::msgDateSpace + (out() ? st::msgDateCheckSpace + st::msgCheckRect.pxWidth() : 0) - st::msgDateDelta.x();
_text.setText(st::msgFont, text + textcmdSkipBlock(_timeWidth, st::msgDateFont->height - st::msgDateDelta.y()), _historyTextOptions);
_maxw = _text.maxWidth();
_minh = _text.minHeight();
_maxw += st::msgPadding.left() + st::msgPadding.right();
@ -2788,18 +2810,18 @@ void HistoryMessage::initDimensions(const QString &text) {
}
void HistoryMessage::fromNameUpdated() const {
if (media) return;
if (_media) return;
int32 _namew = ((!_out && _history->peer->chat) ? _from->nameText.maxWidth() : 0) + st::msgPadding.left() + st::msgPadding.right();
if (_namew > _maxw) _maxw = _namew;
}
bool HistoryMessage::uploading() const {
return media ? media->uploading() : false;
return _media ? _media->uploading() : false;
}
QString HistoryMessage::selectedText(uint32 selection) const {
if (media && selection == FullItemSel) {
return _text.original(0, 0xFFFF) + '[' + media->inDialogsText() + ']';
if (_media && selection == FullItemSel) {
return _text.original(0, 0xFFFF) + '[' + _media->inDialogsText() + ']';
}
uint16 selectedFrom = (selection == FullItemSel) ? 0 : (selection >> 16) & 0xFFFF;
uint16 selectedTo = (selection == FullItemSel) ? 0xFFFF : (selection & 0xFFFF);
@ -2807,7 +2829,7 @@ QString HistoryMessage::selectedText(uint32 selection) const {
}
HistoryMedia *HistoryMessage::getMedia(bool inOverview) const {
return media;
return _media;
}
void HistoryMessage::draw(QPainter &p, uint32 selection) const {
@ -2850,10 +2872,10 @@ void HistoryMessage::draw(QPainter &p, uint32 selection) const {
if (_out) left += width - _maxw;
width = _maxw;
}
if (media) {
if (_media) {
p.save();
p.translate(left, st::msgMargin.top());
media->draw(p, this, time, timeWidth, selected);
_media->draw(p, this, selected);
p.restore();
} else {
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
@ -2878,7 +2900,7 @@ void HistoryMessage::draw(QPainter &p, uint32 selection) const {
style::color date(selected ? (_out ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (_out ? st::msgOutDateColor : st::msgInDateColor));
p.setPen(date->p);
p.drawText(r.right() - st::msgPadding.right() + st::msgDateDelta.x() - timeWidth + st::msgDateSpace, r.bottom() - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, time);
p.drawText(r.right() - st::msgPadding.right() + st::msgDateDelta.x() - _timeWidth + st::msgDateSpace, r.bottom() - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgDateFont->descent, _time);
if (_out) {
QPoint iconPos(r.right() + 5 - st::msgPadding.right() - st::msgCheckRect.pxWidth(), r.bottom() + 1 - st::msgPadding.bottom() + st::msgDateDelta.y() - st::msgCheckRect.pxHeight());
const QRect *iconRect;
@ -2908,8 +2930,8 @@ void HistoryMessage::drawMessageText(QPainter &p, const QRect &trect, uint32 sel
int32 HistoryMessage::resize(int32 width) {
width -= st::msgMargin.left() + st::msgMargin.right();
if (media) {
_height = media->resize(width);
if (_media) {
_height = _media->resize(width);
} else {
if (width < st::msgPadding.left() + st::msgPadding.right() + 1) {
width = st::msgPadding.left() + st::msgPadding.right() + 1;
@ -2951,8 +2973,8 @@ bool HistoryMessage::hasPoint(int32 x, int32 y) const {
if (_out) left += width - _maxw;
width = _maxw;
}
if (media) {
return media->hasPoint(x - left, y - st::msgMargin.top());
if (_media) {
return _media->hasPoint(x - left, y - st::msgMargin.top());
}
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
return r.contains(x, y);
@ -2982,8 +3004,8 @@ void HistoryMessage::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y)
if (_out) left += width - _maxw;
width = _maxw;
}
if (media) {
lnk = media->getLink(x - left, y - st::msgMargin.top(), this);
if (_media) {
lnk = _media->getLink(x - left, y - st::msgMargin.top(), this);
return;
}
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
@ -3019,7 +3041,7 @@ void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x,
if (_out) left += width - _maxw;
width = _maxw;
}
if (media) {
if (_media) {
return;
}
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
@ -3047,8 +3069,8 @@ bool HistoryMessage::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32
if (_out) left += width - _maxw;
width = _maxw;
}
if (media) {
if (media->getPhotoCoords(photo, x, y, w)) {
if (_media) {
if (_media->getPhotoCoords(photo, x, y, w)) {
x += left;
y += st::msgMargin.top();
return true;
@ -3074,8 +3096,8 @@ bool HistoryMessage::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32
if (_out) left += width - _maxw;
width = _maxw;
}
if (media) {
if (media->getVideoCoords(video, x, y, w)) {
if (_media) {
if (_media->getVideoCoords(video, x, y, w)) {
x += left;
y += st::msgMargin.top();
return true;
@ -3087,7 +3109,7 @@ bool HistoryMessage::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32
void HistoryMessage::drawInDialog(QPainter &p, const QRect &r, bool act, const HistoryItem *&cacheFor, Text &cache) const {
if (cacheFor != this) {
cacheFor = this;
QString msg(media ? media->inDialogsText() : _text.original(0, 0xFFFF, false));
QString msg(_media ? _media->inDialogsText() : _text.original(0, 0xFFFF, false));
TextCustomTagsMap custom;
if (_history->peer->chat || out()) {
custom.insert(QChar('c'), qMakePair(textcmdStartLink(1), textcmdStopLink()));
@ -3098,7 +3120,7 @@ void HistoryMessage::drawInDialog(QPainter &p, const QRect &r, bool act, const H
if (r.width()) {
textstyleSet(&(act ? st::dlgActiveTextStyle : st::dlgTextStyle));
p.setFont(st::dlgHistFont->f);
p.setPen((act ? st::dlgActiveColor : (media ? st::dlgSystemColor : st::dlgTextColor))->p);
p.setPen((act ? st::dlgActiveColor : (_media ? st::dlgSystemColor : st::dlgTextColor))->p);
cache.drawElided(p, r.left(), r.top(), r.width(), r.height() / st::dlgHistFont->height);
}
}
@ -3108,7 +3130,7 @@ QString HistoryMessage::notificationHeader() const {
}
QString HistoryMessage::notificationText() const {
QString msg(media ? media->inDialogsText() : _text.original(0, 0xFFFF, false));
QString msg(_media ? _media->inDialogsText() : _text.original(0, 0xFFFF, false));
if (msg.size() > 0xFF) msg = msg.mid(0, 0xFF) + qsl("..");
// subtitle used
// if (_history->peer->chat || out()) {
@ -3118,10 +3140,10 @@ QString HistoryMessage::notificationText() const {
}
HistoryMessage::~HistoryMessage() {
if (media) {
media->unregItem(this);
if (_media) {
_media->unregItem(this);
}
delete media;
delete _media;
}
HistoryForwarded::HistoryForwarded(History *history, HistoryBlock *block, const MTPDmessageForwarded &msg) : HistoryMessage(history, block, msg.vid.v, msg.vout.v, msg.vunread.v, ::date(msg.vdate), msg.vfrom_id.v, textClean(qs(msg.vmessage)), msg.vmedia)
@ -3153,14 +3175,14 @@ QString HistoryForwarded::selectedText(uint32 selection) const {
}
void HistoryForwarded::fwdNameUpdated() const {
if (media) return;
if (_media) return;
fwdFromName.setText(st::msgServiceNameFont, App::peerName(fwdFrom), _textNameOptions);
int32 _namew = fromWidth + fwdFromName.maxWidth() + st::msgPadding.left() + st::msgPadding.right();
if (_namew > _maxw) _maxw = _namew;
}
void HistoryForwarded::draw(QPainter &p, uint32 selection) const {
if (!media && fwdFrom->nameVersion > fwdFromVersion) {
if (!_media && fwdFrom->nameVersion > fwdFromVersion) {
fwdNameUpdated();
fwdFromVersion = fwdFrom->nameVersion;
}
@ -3190,7 +3212,7 @@ void HistoryForwarded::drawMessageText(QPainter &p, const QRect &trect, uint32 s
int32 HistoryForwarded::resize(int32 width) {
HistoryMessage::resize(width);
if (!media) {
if (!_media) {
int32 h1 = 0, h2 = st::msgServiceNameFont->height;
_height += h1 + (h1 > h2 ? h1 : h2);
}
@ -3198,7 +3220,7 @@ int32 HistoryForwarded::resize(int32 width) {
}
bool HistoryForwarded::hasPoint(int32 x, int32 y) const {
if (!media) {
if (!_media) {
int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right();
if (width > st::msgMaxWidth) {
if (_out) left += width - st::msgMaxWidth;
@ -3225,7 +3247,7 @@ void HistoryForwarded::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y
lnk = TextLinkPtr();
inText = false;
if (!media) {
if (!_media) {
int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right();
if (width > st::msgMaxWidth) {
if (_out) left += width - st::msgMaxWidth;
@ -3272,7 +3294,7 @@ void HistoryForwarded::getSymbol(uint16 &symbol, bool &after, bool &upon, int32
after = false;
upon = false;
if (!media) {
if (!_media) {
int32 left = _out ? st::msgMargin.right() : st::msgMargin.left(), width = _history->width - st::msgMargin.left() - st::msgMargin.right();
if (width > st::msgMaxWidth) {
if (_out) left += width - st::msgMaxWidth;
@ -3339,7 +3361,7 @@ QString HistoryServiceMsg::messageByAction(const MTPmessageAction &action, TextL
case mtpc_messageActionChatEditPhoto: {
const MTPDmessageActionChatEditPhoto &d(action.c_messageActionChatEditPhoto());
if (d.vphoto.type() == mtpc_photo) {
media = new HistoryPhoto(history()->peer, d.vphoto.c_photo(), 100);
_media = new HistoryPhoto(history()->peer, d.vphoto.c_photo(), 100);
}
return lang(lng_action_changed_photo);
} break;
@ -3365,7 +3387,7 @@ QString HistoryServiceMsg::messageByAction(const MTPmessageAction &action, TextL
HistoryServiceMsg::HistoryServiceMsg(History *history, HistoryBlock *block, const MTPDmessageService &msg) :
HistoryItem(history, block, msg.vid.v, msg.vout.v, msg.vunread.v, ::date(msg.vdate), msg.vfrom_id.v)
, _text(st::msgMinWidth)
, media(0)
, _media(0)
{
TextLinkPtr second;
@ -3398,7 +3420,7 @@ HistoryServiceMsg::HistoryServiceMsg(History *history, HistoryBlock *block, cons
HistoryServiceMsg::HistoryServiceMsg(History *history, HistoryBlock *block, MsgId msgId, QDateTime date, const QString &msg, bool out, bool unread, HistoryMedia *media) :
HistoryItem(history, block, msgId, out, unread, date, 0)
, _text(st::msgServiceFont, msg, _historySrvOptions, st::dlgMinWidth)
, media(media)
, _media(media)
{
_maxw = _text.maxWidth() + st::msgServicePadding.left() + st::msgServicePadding.right();
_minh = _text.minHeight();
@ -3416,11 +3438,11 @@ void HistoryServiceMsg::draw(QPainter &p, uint32 selection) const {
int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins
if (width < 1) return;
if (media) {
height -= st::msgServiceMargin.top() + media->height();
if (_media) {
height -= st::msgServiceMargin.top() + _media->height();
p.save();
p.translate(st::msgServiceMargin.left() + (width - media->maxWidth()) / 2, st::msgServiceMargin.top() + height + st::msgServiceMargin.top());
media->draw(p, this, QString(), 0, selection == FullItemSel);
p.translate(st::msgServiceMargin.left() + (width - _media->maxWidth()) / 2, st::msgServiceMargin.top() + height + st::msgServiceMargin.top());
_media->draw(p, this, selection == FullItemSel);
p.restore();
}
@ -3464,8 +3486,8 @@ int32 HistoryServiceMsg::resize(int32 width) {
_height = _textHeight;
}
_height += st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom();
if (media) {
_height += st::msgServiceMargin.top() + media->height();
if (_media) {
_height += st::msgServiceMargin.top() + _media->height();
}
return _height;
}
@ -3474,8 +3496,8 @@ bool HistoryServiceMsg::hasPoint(int32 x, int32 y) const {
int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins
if (width < 1) return false;
if (media) {
height -= st::msgServiceMargin.top() + media->height();
if (_media) {
height -= st::msgServiceMargin.top() + _media->height();
}
return QRect(left, st::msgServiceMargin.top(), width, height).contains(x, y);
}
@ -3487,15 +3509,15 @@ void HistoryServiceMsg::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32
int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins
if (width < 1) return;
if (media) {
height -= st::msgServiceMargin.top() + media->height();
if (_media) {
height -= st::msgServiceMargin.top() + _media->height();
}
QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding));
if (trect.contains(x, y)) {
return _text.getState(lnk, inText, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter);
}
if (media) {
lnk = media->getLink(x - st::msgServiceMargin.left() - (width - media->maxWidth()) / 2, y - st::msgServiceMargin.top() - height - st::msgServiceMargin.top(), this);
if (_media) {
lnk = _media->getLink(x - st::msgServiceMargin.left() - (width - _media->maxWidth()) / 2, y - st::msgServiceMargin.top() - height - st::msgServiceMargin.top(), this);
}
}
@ -3507,8 +3529,8 @@ void HistoryServiceMsg::getSymbol(uint16 &symbol, bool &after, bool &upon, int32
int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins
if (width < 1) return;
if (media) {
height -= st::msgServiceMargin.top() + media->height();
if (_media) {
height -= st::msgServiceMargin.top() + _media->height();
}
QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding));
return _text.getSymbol(symbol, after, upon, x - trect.x(), y - trect.y(), trect.width(), Qt::AlignCenter);
@ -3518,12 +3540,12 @@ bool HistoryServiceMsg::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int
int32 left = st::msgServiceMargin.left(), width = _history->width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = _height - st::msgServiceMargin.top() - st::msgServiceMargin.bottom(); // two small margins
if (width < 1) return false;
if (media) {
height -= st::msgServiceMargin.top() + media->height();
if (_media) {
height -= st::msgServiceMargin.top() + _media->height();
}
if (media) {
if (media->getPhotoCoords(photo, x, y, w)) {
x += st::msgServiceMargin.left() + (width - media->maxWidth()) / 2;
if (_media) {
if (_media->getPhotoCoords(photo, x, y, w)) {
x += st::msgServiceMargin.left() + (width - _media->maxWidth()) / 2;
y += st::msgServiceMargin.top() + height + st::msgServicePadding.top();
return true;
}
@ -3548,11 +3570,11 @@ QString HistoryServiceMsg::notificationText() const {
}
HistoryMedia *HistoryServiceMsg::getMedia(bool inOverview) const {
return inOverview ? 0 : media;
return inOverview ? 0 : _media;
}
HistoryServiceMsg::~HistoryServiceMsg() {
delete media;
delete _media;
}
HistoryDateMsg::HistoryDateMsg(History *history, HistoryBlock *block, const QDate &date) : HistoryServiceMsg(history, block, clientMsgId(), QDateTime(date), langDayOfMonth(date)) {

View File

@ -179,11 +179,12 @@ struct ChatData : public PeerData {
typedef QMap<char, QPixmap> PreparedPhotoThumbs;
struct PhotoData {
PhotoData(const PhotoId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &full = ImagePtr()) :
id(id), access(access), user(user), date(date), thumb(thumb), full(full), chat(0) {
PhotoData(const PhotoId &id, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &medium = ImagePtr(), const ImagePtr &full = ImagePtr()) :
id(id), access(access), user(user), date(date), thumb(thumb), medium(medium), full(full), chat(0) {
}
void forget() {
thumb->forget();
medium->forget();
full->forget();
}
PhotoId id;
@ -191,6 +192,7 @@ struct PhotoData {
int32 user;
int32 date;
ImagePtr thumb;
ImagePtr medium;
ImagePtr full;
ChatData *chat; // for chat photos connection
// geo, caption
@ -579,6 +581,57 @@ struct FakeDialogRow {
mutable Text _cache;
};
enum HistoryMediaType {
MediaTypePhoto,
MediaTypeVideo,
MediaTypeGeo,
MediaTypeContact,
MediaTypeAudio,
MediaTypeDocument,
MediaTypeCount
};
enum MediaOverviewType {
OverviewPhotos,
OverviewVideos,
OverviewDocuments,
OverviewAudios,
OverviewCount
};
inline MediaOverviewType mediaToOverviewType(HistoryMediaType t) {
switch (t) {
case MediaTypePhoto: return OverviewPhotos;
case MediaTypeVideo: return OverviewVideos;
case MediaTypeDocument: return OverviewDocuments;
case MediaTypeAudio: return OverviewAudios;
}
return OverviewCount;
}
inline HistoryMediaType overviewToMediaType(MediaOverviewType t) {
switch (t) {
case OverviewPhotos: return MediaTypePhoto;
case OverviewVideos: return MediaTypeVideo;
case OverviewAudios: return MediaTypeAudio;
case OverviewDocuments: return MediaTypeDocument;
}
return MediaTypeCount;
}
inline MTPMessagesFilter typeToMediaFilter(MediaOverviewType &type) {
switch (type) {
case OverviewPhotos: return MTP_inputMessagesFilterPhotos();
case OverviewVideos: return MTP_inputMessagesFilterVideo();
case OverviewDocuments: return MTP_inputMessagesFilterDocument();
case OverviewAudios: return MTP_inputMessagesFilterAudio();
default: type = OverviewCount; break;
}
return MTPMessagesFilter();
}
class HistoryMedia;
class HistoryMessage;
class HistoryUnreadBar;
@ -707,10 +760,11 @@ struct History : public QList<HistoryBlock*> {
uint64 myTyping;
typedef QList<MsgId> MediaOverview;
typedef QSet<MsgId> MediaOverviewIds;
MediaOverview _photosOverview;
MediaOverviewIds _photosOverviewIds;
int32 _photosOverviewCount; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
typedef QMap<MsgId, NullType> MediaOverviewIds;
MediaOverview _overview[OverviewCount];
MediaOverviewIds _overviewIds[OverviewCount];
int32 _overviewCount[OverviewCount]; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded
static const int32 ScrollMax = INT_MAX;
};
@ -1129,6 +1183,12 @@ public:
virtual HistoryMedia *getMedia(bool inOverview = false) const {
return 0;
}
virtual QString time() const {
return QString();
}
virtual int32 timeWidth() const {
return 0;
}
virtual ~HistoryItem();
@ -1144,26 +1204,17 @@ protected:
HistoryItem *regItem(HistoryItem *item, bool returnExisting = false);
enum HistoryMediaType {
MediaTypePhoto,
MediaTypeVideo,
MediaTypeGeo,
MediaTypeContact,
MediaTypeAudio,
MediaTypeDocument,
};
class HistoryMedia : public HistoryElem {
public:
virtual void initDimensions(const HistoryItem *parent, int32 timeWidth) {
virtual void initDimensions(const HistoryItem *parent) {
}
virtual HistoryMediaType type() const = 0;
virtual const QString inDialogsText() const = 0;
virtual bool hasPoint(int32 x, int32 y) const = 0;
virtual TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const = 0;
virtual void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const = 0;
virtual bool hasPoint(int32 x, int32 y, int32 width = -1) const = 0;
virtual TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const = 0;
virtual void draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width = -1) const = 0;
virtual bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
return false;
}
@ -1194,14 +1245,14 @@ public:
void init();
void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const;
void draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width = -1) const;
int32 resize(int32 width);
HistoryMediaType type() const {
return MediaTypePhoto;
}
const QString inDialogsText() const;
bool hasPoint(int32 x, int32 y) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const;
bool hasPoint(int32 x, int32 y, int32 width = -1) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const;
HistoryMedia *clone() const;
@ -1209,6 +1260,10 @@ public:
return data;
}
TextLinkPtr lnk() const {
return openl;
}
private:
PhotoData *data;
TextLinkPtr openl;
@ -1220,16 +1275,16 @@ public:
HistoryVideo(const MTPDvideo &video, int32 width = 0);
void reinit();
void initDimensions(const HistoryItem *parent, int32 timeWidth);
void initDimensions(const HistoryItem *parent);
void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const;
void draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width = -1) const;
int32 resize(int32 width);
HistoryMediaType type() const {
return MediaTypeVideo;
}
const QString inDialogsText() const;
bool hasPoint(int32 x, int32 y) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const;
bool hasPoint(int32 x, int32 y, int32 width = -1) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const;
bool uploading() const {
return (data->status == FileUploading);
@ -1256,16 +1311,16 @@ public:
HistoryAudio(const MTPDaudio &audio, int32 width = 0);
void reinit();
void initDimensions(const HistoryItem *parent, int32 timeWidth);
void initDimensions(const HistoryItem *parent);
void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const;
void draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width = -1) const;
int32 resize(int32 width);
HistoryMediaType type() const {
return MediaTypeAudio;
}
const QString inDialogsText() const;
bool hasPoint(int32 x, int32 y) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const;
bool hasPoint(int32 x, int32 y, int32 width = -1) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
bool uploading() const {
return (data->status == FileUploading);
}
@ -1290,19 +1345,19 @@ public:
HistoryDocument(const MTPDdocument &document, int32 width = 0);
void reinit();
void initDimensions(const HistoryItem *parent, int32 timeWidth);
void initDimensions(const HistoryItem *parent);
void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const;
void draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width = -1) const;
int32 resize(int32 width);
HistoryMediaType type() const {
return MediaTypeDocument;
}
const QString inDialogsText() const;
bool hasPoint(int32 x, int32 y) const;
bool hasPoint(int32 x, int32 y, int32 width = -1) const;
bool uploading() const {
return (data->status == FileUploading);
}
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width = -1) const;
HistoryMedia *clone() const;
DocumentData *document() {
@ -1332,16 +1387,16 @@ class HistoryContact : public HistoryMedia {
public:
HistoryContact(int32 userId, const QString &first, const QString &last, const QString &phone);
void initDimensions(const HistoryItem *parent, int32 timeWidth);
void initDimensions(const HistoryItem *parent);
void draw(QPainter &p, const HistoryItem *parent, const QString &time, int32 timeWidth, bool selected) const;
void draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const;
int32 resize(int32 width);
HistoryMediaType type() const {
return MediaTypeContact;
}
const QString inDialogsText() const;
bool hasPoint(int32 x, int32 y) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent) const;
bool hasPoint(int32 x, int32 y, int32 width) const;
TextLinkPtr getLink(int32 x, int32 y, const HistoryItem *parent, int32 width) const;
HistoryMedia *clone() const;
private:
@ -1385,12 +1440,19 @@ public:
QString notificationText() const;
void updateMedia(const MTPMessageMedia &media) {
if (this->media) this->media->updateFrom(media);
if (_media) _media->updateFrom(media);
}
QString selectedText(uint32 selection) const;
HistoryMedia *getMedia(bool inOverview = false) const;
QString time() const {
return _time;
}
int32 timeWidth() const {
return _timeWidth;
}
~HistoryMessage();
protected:
@ -1399,9 +1461,9 @@ protected:
int32 _textWidth, _textHeight;
HistoryMedia *media;
QString time;
int32 timeWidth;
HistoryMedia *_media;
QString _time;
int32 _timeWidth;
};
@ -1475,7 +1537,7 @@ protected:
QString messageByAction(const MTPmessageAction &action, TextLinkPtr &second);
Text _text;
HistoryMedia *media;
HistoryMedia *_media;
int32 _textWidth, _textHeight;
};

View File

@ -2198,7 +2198,7 @@ void HistoryWidget::onSend() {
}
mtpRequestId HistoryWidget::onForward(const PeerId &peer, bool forwardSelected) {
if (!_list) return 0;
if (forwardSelected && !_list) return 0;
HistoryItemSet toForward;
if (forwardSelected) {
@ -2295,6 +2295,14 @@ MsgId HistoryWidget::activeMsgId() const {
return hist ? hist->activeMsgId : (_activeHist ? _activeHist->activeMsgId : 0);
}
int32 HistoryWidget::lastWidth() const {
return width();
}
int32 HistoryWidget::lastScrollTop() const {
return _scroll.scrollTop();
}
void HistoryWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back) {
_bgAnimCache = bgAnimCache;
_bgAnimTopBarCache = bgAnimTopBarCache;

View File

@ -309,6 +309,8 @@ public:
PeerData *peer() const;
PeerData *activePeer() const;
MsgId activeMsgId() const;
int32 lastWidth() const;
int32 lastScrollTop() const;
void animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false);
bool animStep(float64 ms);

View File

@ -142,6 +142,10 @@ void LocalImageLoaderPrivate::prepareImages() {
photoThumbs.insert('s', thumb);
photoSizes.push_back(MTP_photoSize(MTP_string("s"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(thumb.width()), MTP_int(thumb.height()), MTP_int(0)));
QPixmap medium = (w > 320 || h > 320) ? QPixmap::fromImage(img.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(img);
photoThumbs.insert('m', medium);
photoSizes.push_back(MTP_photoSize(MTP_string("m"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(medium.width()), MTP_int(medium.height()), MTP_int(0)));
QPixmap full = (w > 800 || h > 800) ? QPixmap::fromImage(img.scaled(800, 800, Qt::KeepAspectRatio, Qt::SmoothTransformation)) : QPixmap::fromImage(img);
photoThumbs.insert('x', full);
photoSizes.push_back(MTP_photoSize(MTP_string("x"), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0)));

View File

@ -258,7 +258,7 @@ MainWidget *TopBarWidget::main() {
}
MainWidget::MainWidget(Window *window) : QWidget(window), failedObjId(0), _dialogsWidth(st::dlgMinWidth),
dialogs(this), history(this), profile(0), _topBar(this), hider(0),
dialogs(this), history(this), profile(0), overview(0), _topBar(this), hider(0),
updPts(0), updDate(0), updQts(0), updSeq(0), updInited(false), onlineRequest(0) {
setGeometry(QRect(0, st::titleHeight, App::wnd()->width(), App::wnd()->height() - st::titleHeight));
@ -358,7 +358,7 @@ void MainWidget::dialogsActivate() {
bool MainWidget::leaveChatFailed(PeerData *peer, const RPCError &e) {
if (e.type() == "CHAT_ID_INVALID") { // left this chat already
if ((profile && profile->peer() == peer) || profileStack.indexOf(peer) >= 0 || history.peer() == peer) {
if ((profile && profile->peer() == peer) || (overview && overview->peer() == peer) || _stack.contains(peer) || history.peer() == peer) {
showPeer(0);
}
dialogs.removePeer(peer);
@ -370,7 +370,7 @@ bool MainWidget::leaveChatFailed(PeerData *peer, const RPCError &e) {
void MainWidget::deleteHistory(PeerData *peer, const MTPmessages_StatedMessage &result) {
sentFullDataReceived(0, result);
if ((profile && profile->peer() == peer) || profileStack.indexOf(peer) >= 0 || history.peer() == peer) {
if ((profile && profile->peer() == peer) || (overview && overview->peer() == peer) || _stack.contains(peer) || history.peer() == peer) {
showPeer(0);
}
dialogs.removePeer(peer);
@ -398,7 +398,7 @@ void MainWidget::deleteHistoryAndContact(UserData *user, const MTPcontacts_Link
App::feedUsers(MTP_vector<MTPUser>(QVector<MTPUser>(1, d.vuser)));
App::feedUserLink(MTP_int(user->id & 0xFFFFFFFF), d.vmy_link, d.vforeign_link);
if ((profile && profile->peer() == user) || profileStack.indexOf(user) >= 0 || history.peer() == user) {
if ((profile && profile->peer() == user) || (overview && overview->peer() == user) || _stack.contains(user) || history.peer() == user) {
showPeer(0);
}
dialogs.removePeer(user);
@ -472,7 +472,7 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
if (!v) return;
if (v->isEmpty()) {
if ((profile && profile->peer() == peer) || profileStack.indexOf(peer) >= 0 || history.peer() == peer) {
if ((profile && profile->peer() == peer) || (overview && overview->peer() == peer) || _stack.contains(peer) || history.peer() == peer) {
showPeer(0);
}
dialogs.removePeer(peer);
@ -544,6 +544,170 @@ void MainWidget::searchMessages(const QString &query) {
dialogs.searchMessages(query);
}
void MainWidget::preloadOverviews(PeerData *peer) {
History *h = App::history(peer->id);
bool sending[OverviewCount] = { false };
for (int32 i = 0; i < OverviewCount; ++i) {
if (h->_overviewCount[i] < 0) {
if (_overviewPreload[i].constFind(peer) == _overviewPreload[i].cend()) {
sending[i] = true;
}
}
}
int32 last = OverviewCount;
while (last > 0) {
if (sending[--last]) break;
}
for (int32 i = 0; i < OverviewCount; ++i) {
if (sending[i]) {
MediaOverviewType type = MediaOverviewType(i);
MTPMessagesFilter filter = typeToMediaFilter(type);
if (type == OverviewCount) break;
_overviewPreload[i].insert(peer, MTP::send(MTPmessages_Search(peer->input, MTP_string(""), filter, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(0)), rpcDone(&MainWidget::overviewPreloaded, peer), rpcFail(&MainWidget::overviewFailed, peer), 0, (i == last) ? 0 : 10));
}
}
}
void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &result, mtpRequestId req) {
MediaOverviewType type = OverviewCount;
for (int32 i = 0; i < OverviewCount; ++i) {
OverviewsPreload::iterator j = _overviewPreload[i].find(peer);
if (j != _overviewPreload[i].end() && j.value() == req) {
type = MediaOverviewType(i);
_overviewPreload[i].erase(j);
break;
}
}
if (type == OverviewCount) return;
History *h = App::history(peer->id);
switch (result.type()) {
case mtpc_messages_messages: {
const MTPDmessages_messages &d(result.c_messages_messages());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
h->_overviewCount[type] = 0;
} break;
case mtpc_messages_messagesSlice: {
const MTPDmessages_messagesSlice &d(result.c_messages_messagesSlice());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
h->_overviewCount[type] = d.vcount.v;
} break;
default: return;
}
if (h->_overviewCount[type] > 0) {
for (History::MediaOverviewIds::const_iterator i = h->_overviewIds[type].cbegin(), e = h->_overviewIds[type].cend(); i != e; ++i) {
if (i.key() < 0) {
++h->_overviewCount[type];
} else {
break;
}
}
}
mediaOverviewUpdated(peer);
}
void MainWidget::mediaOverviewUpdated(PeerData *peer) {
if (profile) profile->mediaOverviewUpdated(peer);
if (overview) overview->mediaOverviewUpdated(peer);
}
bool MainWidget::overviewFailed(PeerData *peer, const RPCError &error, mtpRequestId req) {
MediaOverviewType type = OverviewCount;
for (int32 i = 0; i < OverviewCount; ++i) {
OverviewsPreload::iterator j = _overviewPreload[i].find(peer);
if (j != _overviewPreload[i].end() && j.value() == req) {
_overviewPreload[i].erase(j);
break;
}
}
return true;
}
void MainWidget::loadMediaBack(PeerData *peer, MediaOverviewType type, bool many) {
if (_overviewLoad[type].constFind(peer) != _overviewLoad[type].cend()) return;
MsgId minId = 0;
History *hist = App::history(peer->id);
if (hist->_overviewCount[type] == 0) return; // all loaded
for (History::MediaOverviewIds::const_iterator i = hist->_overviewIds[type].cbegin(), e = hist->_overviewIds[type].cend(); i != e; ++i) {
if (i.key() > 0) {
minId = i.key();
break;
}
}
int32 limit = many ? SearchManyPerPage : (hist->_overview[type].size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
MTPMessagesFilter filter = typeToMediaFilter(type);
if (type == OverviewCount) return;
_overviewLoad[type].insert(hist->peer, MTP::send(MTPmessages_Search(hist->peer->input, MTPstring(), filter, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minId), MTP_int(limit)), rpcDone(&MainWidget::photosLoaded, hist)));
}
void MainWidget::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req) {
OverviewsPreload::iterator it;
MediaOverviewType type = OverviewCount;
for (int32 i = 0; i < OverviewCount; ++i) {
it = _overviewLoad[i].find(h->peer);
if (it != _overviewLoad[i].cend()) {
type = MediaOverviewType(i);
_overviewLoad[i].erase(it);
break;
}
}
if (type == OverviewCount) return;
const QVector<MTPMessage> *v = 0;
switch (msgs.type()) {
case mtpc_messages_messages: {
const MTPDmessages_messages &d(msgs.c_messages_messages());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
v = &d.vmessages.c_vector().v;
h->_overviewCount[type] = 0;
} break;
case mtpc_messages_messagesSlice: {
const MTPDmessages_messagesSlice &d(msgs.c_messages_messagesSlice());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
h->_overviewCount[type] = d.vcount.v;
v = &d.vmessages.c_vector().v;
} break;
default: return;
}
if (h->_overviewCount[type] > 0) {
for (History::MediaOverviewIds::const_iterator i = h->_overviewIds[type].cbegin(), e = h->_overviewIds[type].cend(); i != e; ++i) {
if (i.key() < 0) {
++h->_overviewCount[type];
} else {
break;
}
}
}
if (v->isEmpty()) {
h->_overviewCount[type] = 0;
}
for (QVector<MTPMessage>::const_iterator i = v->cbegin(), e = v->cend(); i != e; ++i) {
HistoryItem *item = App::histories().addToBack(*i, -1);
if (item && h->_overviewIds[type].constFind(item->id) == h->_overviewIds[type].cend()) {
h->_overviewIds[type].insert(item->id, NullType());
h->_overview[type].push_front(item->id);
}
}
if (App::wnd()) App::wnd()->mediaOverviewUpdated(h->peer);
}
void MainWidget::partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result) {
const MTPDmessages_affectedHistory &d(result.c_messages_affectedHistory());
App::main()->updUpdated(d.vpts.v, 0, 0, d.vseq.v);
@ -571,7 +735,7 @@ void MainWidget::videoLoadProgress(mtpFileLoader *loader) {
VideoItems::const_iterator i = items.constFind(video);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
history.msgUpdated(j.key()->history()->peer->id, j.key());
msgUpdated(j.key()->history()->peer->id, j.key());
}
}
}
@ -615,7 +779,7 @@ void MainWidget::audioLoadProgress(mtpFileLoader *loader) {
AudioItems::const_iterator i = items.constFind(audio);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
history.msgUpdated(j.key()->history()->peer->id, j.key());
msgUpdated(j.key()->history()->peer->id, j.key());
}
}
}
@ -647,7 +811,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
DocumentItems::const_iterator i = items.constFind(document);
if (i != items.cend()) {
for (HistoryItemsMap::const_iterator j = i->cbegin(), e = i->cend(); j != e; ++j) {
history.msgUpdated(j.key()->history()->peer->id, j.key());
msgUpdated(j.key()->history()->peer->id, j.key());
}
}
}
@ -710,30 +874,8 @@ void MainWidget::createDialogAtTop(History *history, int32 unreadCount) {
dialogs.createDialogAtTop(history, unreadCount);
}
bool MainWidget::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
if (history.getPhotoCoords(photo, x, y, w)) {
x += history.x();
y += history.y();
return true;
} else if (profile && profile->getPhotoCoords(photo, x, y, w)) {
x += profile->x();
y += profile->y();
return true;
}
return false;
}
bool MainWidget::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const {
if (history.getVideoCoords(video, x, y, w)) {
x += history.x();
y += history.y();
return true;
}
return false;
}
void MainWidget::showPeer(const PeerId &peerId, MsgId msgId, bool back, bool force) {
if (!back && profileStack.size() == 1 && profileStack[0]->id == peerId) {
if (!back && _stack.size() == 1 && _stack[0]->type() == HistoryStackItem && _stack[0]->peer->id == peerId) {
back = true;
}
App::wnd()->hideLayer();
@ -743,7 +885,7 @@ void MainWidget::showPeer(const PeerId &peerId, MsgId msgId, bool back, bool for
hider = 0;
}
if (force || !selectingPeer()) {
if (history.isHidden() && profile) {
if (history.isHidden() && (profile || overview)) {
dialogs.enableShadow(false);
if (peerId) {
_topBar.enableShadow(false);
@ -759,13 +901,19 @@ void MainWidget::showPeer(const PeerId &peerId, MsgId msgId, bool back, bool for
}
history.showPeer(peerId, msgId, force);
if (force || !selectingPeer()) {
if (profile) {
if (profile || overview) {
if (profile) {
profile->deleteLater();
profile->rpcInvalidate();
profile = 0;
}
profile = 0;
profileStack.clear();
if (overview) {
overview->clear();
overview->deleteLater();
overview->rpcInvalidate();
overview = 0;
}
_stack.clear();
if (!history.peer() || !history.peer()->id) {
_topBar.hide();
resizeEvent(0);
@ -805,7 +953,52 @@ PeerData *MainWidget::profilePeer() {
return profile ? profile->peer() : 0;
}
void MainWidget::showPeerProfile(const PeerData *peer, bool back) {
void MainWidget::showMediaOverview(const PeerData *peer, MediaOverviewType type, bool back, int32 lastScrollTop) {
App::wnd()->hideSettings();
if (overview && overview->peer() == peer) {
if (overview->type() != type) {
overview->switchType(type);
}
return;
}
dialogs.enableShadow(false);
_topBar.enableShadow(false);
QPixmap animCache = myGrab(this, history.geometry()), animTopBarCache = myGrab(this, QRect(_topBar.x(), _topBar.y(), _topBar.width(), st::topBarHeight));
dialogs.enableShadow();
_topBar.enableShadow();
if (!back) {
if (overview) {
_stack.push_back(new StackItemOverview(overview->peer(), overview->type(), overview->lastWidth(), overview->lastScrollTop()));
} else if (profile) {
_stack.push_back(new StackItemProfile(profile->peer(), profile->lastScrollTop(), profile->allMediaShown()));
} else {
_stack.push_back(new StackItemHistory(history.peer(), history.lastWidth(), history.lastScrollTop()));
}
}
if (overview) {
overview->clear();
overview->deleteLater();
overview->rpcInvalidate();
}
if (profile) {
profile->deleteLater();
profile->rpcInvalidate();
profile = 0;
}
overview = new OverviewWidget(this, peer, type);
_topBar.show();
resizeEvent(0);
overview->animShow(animCache, animTopBarCache, back, lastScrollTop);
history.animStop();
history.showPeer(0, 0, false, true);
history.hide();
_topBar.raise();
dialogs.raise();
if (hider) hider->raise();
}
void MainWidget::showPeerProfile(const PeerData *peer, bool back, int32 lastScrollTop, bool allMediaShown) {
App::wnd()->hideSettings();
if (profile && profile->peer() == peer) return;
@ -815,12 +1008,20 @@ void MainWidget::showPeerProfile(const PeerData *peer, bool back) {
dialogs.enableShadow();
_topBar.enableShadow();
if (!back) {
if (profile) {
profileStack.push_back(profile->peer());
if (overview) {
_stack.push_back(new StackItemOverview(overview->peer(), overview->type(), overview->lastWidth(), overview->lastScrollTop()));
} else if (profile) {
_stack.push_back(new StackItemProfile(profile->peer(), profile->lastScrollTop(), profile->allMediaShown()));
} else {
profileStack.push_back(history.peer());
_stack.push_back(new StackItemHistory(history.peer(), history.lastWidth(), history.lastScrollTop()));
}
}
if (overview) {
overview->clear();
overview->deleteLater();
overview->rpcInvalidate();
overview = 0;
}
if (profile) {
profile->deleteLater();
profile->rpcInvalidate();
@ -828,7 +1029,7 @@ void MainWidget::showPeerProfile(const PeerData *peer, bool back) {
profile = new ProfileWidget(this, peer);
_topBar.show();
resizeEvent(0);
profile->animShow(animCache, animTopBarCache, back);
profile->animShow(animCache, animTopBarCache, back, lastScrollTop, allMediaShown);
history.animStop();
history.showPeer(0, 0, false, true);
history.hide();
@ -837,15 +1038,21 @@ void MainWidget::showPeerProfile(const PeerData *peer, bool back) {
if (hider) hider->raise();
}
void MainWidget::showPeerBack() {
if (profileStack.isEmpty() || selectingPeer()) return;
PeerData *peer = profileStack.back();
profileStack.pop_back();
if (profileStack.isEmpty()) {
showPeer(peer->id, App::main()->activeMsgId(), true);
} else {
showPeerProfile(peer, true);
void MainWidget::showBackFromStack() {
if (_stack.isEmpty() || selectingPeer()) return;
StackItem *item = _stack.back();
_stack.pop_back();
if (item->type() == HistoryStackItem) {
StackItemHistory *histItem = static_cast<StackItemHistory*>(item);
showPeer(histItem->peer->id, App::main()->activeMsgId(), true);
} else if (item->type() == ProfileStackItem) {
StackItemProfile *profItem = static_cast<StackItemProfile*>(item);
showPeerProfile(profItem->peer, true, profItem->lastScrollTop, profItem->allMediaShown);
} else if (item->type() == OverviewStackItem) {
StackItemOverview *overItem = static_cast<StackItemOverview*>(item);
showMediaOverview(overItem->peer, overItem->mediaType, true, overItem->lastScrollTop);
}
delete item;
}
QRect MainWidget::historyRect() const {
@ -1008,10 +1215,10 @@ void MainWidget::forwardDone(PeerId peer, const MTPmessages_StatedMessages &resu
}
void MainWidget::msgUpdated(PeerId peer, HistoryItem *msg) {
if (!msg) return;
history.msgUpdated(peer, msg);
if (!msg->history()->dialogs.isEmpty()) {
dialogs.dlgUpdated(msg->history()->dialogs[0]);
}
if (!msg->history()->dialogs.isEmpty()) dialogs.dlgUpdated(msg->history()->dialogs[0]);
if (overview) overview->msgUpdated(peer, msg);
}
void MainWidget::historyToDown(History *hist) {
@ -1094,17 +1301,22 @@ void MainWidget::hideAll() {
if (profile) {
profile->hide();
}
if (overview) {
overview->hide();
}
_topBar.hide();
}
void MainWidget::showAll() {
dialogs.show();
if (profile) {
if (overview) {
overview->show();
} else if(profile) {
profile->show();
} else {
history.show();
}
if (profile || history.peer()) {
if (profile || overview || history.peer()) {
_topBar.show();
}
App::wnd()->checkHistoryActivation();
@ -1117,6 +1329,7 @@ void MainWidget::resizeEvent(QResizeEvent *e) {
_topBar.setGeometry(_dialogsWidth, 0, width() - _dialogsWidth, st::topBarHeight + st::titleShadow);
history.setGeometry(_dialogsWidth, tbh, width() - _dialogsWidth, height() - tbh);
if (profile) profile->setGeometry(history.geometry());
if (overview) overview->setGeometry(history.geometry());
if (hider) hider->setGeometry(QRect(_dialogsWidth, 0, width() - _dialogsWidth, height()));
}
@ -1126,6 +1339,8 @@ void MainWidget::keyPressEvent(QKeyEvent *e) {
void MainWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) {
if (profile) {
profile->paintTopBar(p, over, decreaseWidth);
} else if (overview) {
overview->paintTopBar(p, over, decreaseWidth);
} else {
history.paintTopBar(p, over, decreaseWidth);
}
@ -1138,13 +1353,15 @@ TopBarWidget *MainWidget::topBar() {
void MainWidget::onTopBarClick() {
if (profile) {
profile->topBarClick();
} else if (overview) {
overview->topBarClick();
} else {
history.topBarClick();
}
}
void MainWidget::onPeerShown(PeerData *peer) {
if (profile || (peer && peer->id)) {
if (profile || overview || (peer && peer->id)) {
_topBar.show();
} else {
_topBar.hide();
@ -1390,7 +1607,7 @@ void MainWidget::updateNotifySetting(PeerData *peer, bool enabled) {
}
void MainWidget::activate() {
if (!profile) {
if (!profile && !overview) {
if (hider) {
if (hider->wasOffered()) {
hider->setFocus();
@ -1433,7 +1650,7 @@ bool MainWidget::isActive() const {
}
bool MainWidget::historyIsActive() const {
return isActive() && !profile && history.isActive();
return isActive() && !profile && !overview && history.isActive();
}
int32 MainWidget::dlgsWidth() const {
@ -1581,15 +1798,17 @@ void MainWidget::feedUpdate(const MTPUpdate &update) {
if (msgRow) {
App::historyUnregItem(msgRow);
History *h = msgRow->history();
History::MediaOverviewIds::iterator i = h->_photosOverviewIds.find(msgRow->id);
if (i != h->_photosOverviewIds.cend()) {
h->_photosOverviewIds.erase(i);
if (h->_photosOverviewIds.constFind(d.vid.v) == h->_photosOverviewIds.cend()) {
h->_photosOverviewIds.insert(d.vid.v);
for (int32 i = 0, l = h->_photosOverview.size(); i != l; ++i) {
if (h->_photosOverview.at(i) == msgRow->id) {
h->_photosOverview[i] = d.vid.v;
break;
for (int32 i = 0; i < OverviewCount; ++i) {
History::MediaOverviewIds::iterator j = h->_overviewIds[i].find(msgRow->id);
if (j != h->_overviewIds[i].cend()) {
h->_overviewIds[i].erase(j);
if (h->_overviewIds[i].constFind(d.vid.v) == h->_overviewIds[i].cend()) {
h->_overviewIds[i].insert(d.vid.v, NullType());
for (int32 k = 0, l = h->_overview[i].size(); k != l; ++k) {
if (h->_overview[i].at(k) == msgRow->id) {
h->_overview[i][k] = d.vid.v;
break;
}
}
}
}

View File

@ -23,6 +23,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
#include "dialogswidget.h"
#include "historywidget.h"
#include "profilewidget.h"
#include "overviewwidget.h"
class Window;
struct DialogRow;
@ -83,6 +84,75 @@ private:
};
enum StackItemType {
HistoryStackItem,
ProfileStackItem,
OverviewStackItem,
};
class StackItem {
public:
StackItem(PeerData *peer) : peer(peer) {
}
virtual StackItemType type() const = 0;
virtual ~StackItem() {
}
PeerData *peer;
};
class StackItemHistory : public StackItem {
public:
StackItemHistory(PeerData *peer, int32 lastWidth, int32 lastScrollTop) : StackItem(peer), lastWidth(lastWidth), lastScrollTop(lastScrollTop) {
}
StackItemType type() const {
return HistoryStackItem;
}
int32 lastWidth, lastScrollTop;
};
class StackItemProfile : public StackItem {
public:
StackItemProfile(PeerData *peer, int32 lastScrollTop, bool allMediaShown) : StackItem(peer), lastScrollTop(lastScrollTop), allMediaShown(allMediaShown) {
}
StackItemType type() const {
return ProfileStackItem;
}
int32 lastScrollTop;
bool allMediaShown;
};
class StackItemOverview : public StackItem {
public:
StackItemOverview(PeerData *peer, MediaOverviewType mediaType, int32 lastWidth, int32 lastScrollTop) : StackItem(peer), mediaType(mediaType), lastWidth(lastWidth), lastScrollTop(lastScrollTop) {
}
StackItemType type() const {
return OverviewStackItem;
}
MediaOverviewType mediaType;
int32 lastWidth, lastScrollTop;
};
class StackItems : public QVector<StackItem*> {
public:
bool contains(PeerData *peer) const {
for (int32 i = 0, l = size(); i < l; ++i) {
if (at(i)->peer == peer) {
return true;
}
}
return false;
}
void clear() {
for (int32 i = 0, l = size(); i < l; ++i) {
delete at(i);
}
QVector<StackItem*>::clear();
}
~StackItems() {
clear();
}
};
class MainWidget : public QWidget, public Animated, public RPCSender {
Q_OBJECT
@ -128,16 +198,15 @@ public:
void updUpdated(int32 pts, int32 date, int32 qts, int32 seq);
void historyWasRead();
bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const;
bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const;
PeerData *peerBefore(const PeerData *peer);
PeerData *peerAfter(const PeerData *peer);
PeerData *peer();
PeerData *activePeer();
MsgId activeMsgId();
PeerData *profilePeer();
void showPeerProfile(const PeerData *peer, bool back = false);
void showPeerBack();
void showPeerProfile(const PeerData *peer, bool back = false, int32 lastScrollTop = -1, bool allMediaShown = false);
void showMediaOverview(const PeerData *peer, MediaOverviewType type, bool back = false, int32 lastScrollTop = -1);
void showBackFromStack();
QRect historyRect() const;
void confirmSendImage(const ReadyLocalMedia &img);
@ -200,6 +269,10 @@ public:
void stopAnimActive();
void searchMessages(const QString &query);
void preloadOverviews(PeerData *peer);
void mediaOverviewUpdated(PeerData *peer);
void loadMediaBack(PeerData *peer, MediaOverviewType type, bool many = false);
~MainWidget();
@ -245,7 +318,8 @@ public slots:
private:
void partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result);
void photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req);
uint64 failedObjId;
QString failedFileName;
void loadFailed(mtpFileLoader *loader, bool started, const char *retrySlot);
@ -266,6 +340,9 @@ private:
void hideAll();
void showAll();
void overviewPreloaded(PeerData *data, const MTPmessages_Messages &result, mtpRequestId req);
bool overviewFailed(PeerData *data, const RPCError &error, mtpRequestId req);
QPixmap _animCache, _bgAnimCache;
anim::ivalue a_coord, a_bgCoord;
anim::fvalue a_alpha, a_bgAlpha;
@ -276,9 +353,10 @@ private:
DialogsWidget dialogs;
HistoryWidget history;
ProfileWidget *profile;
OverviewWidget *overview;
TopBarWidget _topBar;
HistoryHider *hider;
QVector<PeerData*> profileStack;
StackItems _stack;
QPixmap profileAnimCache;
int updPts, updDate, updQts, updSeq;
@ -294,4 +372,7 @@ private:
typedef QMap<PeerData*, mtpRequestId> ReadRequests;
ReadRequests _readRequests;
typedef QMap<PeerData*, mtpRequestId> OverviewsPreload;
OverviewsPreload _overviewPreload[OverviewCount], _overviewLoad[OverviewCount];
};

View File

@ -75,13 +75,14 @@ void MediaView::moveToScreen() {
void MediaView::mediaOverviewUpdated(PeerData *peer) {
if (_history && _history->peer == peer) {
_index = -1;
for (int i = 0, l = _history->_photosOverview.size(); i < l; ++i) {
if (_history->_photosOverview.at(i) == _msgid) {
for (int i = 0, l = _history->_overview[OverviewPhotos].size(); i < l; ++i) {
if (_history->_overview[OverviewPhotos].at(i) == _msgid) {
_index = i;
break;
}
}
updateControls();
preloadPhotos(0);
} else if (_user == peer) {
_index = -1;
for (int i = 0, l = _user->photos.size(); i < l; ++i) {
@ -91,6 +92,7 @@ void MediaView::mediaOverviewUpdated(PeerData *peer) {
}
}
updateControls();
preloadPhotos(0);
}
}
@ -141,9 +143,9 @@ void MediaView::updateControls() {
_nameNav = QRect(_forward.x() + _forward.width() + (maxWidth - nameWidth) / 2, _forward.y() + st::medviewNameTop, nameWidth, st::msgNameFont->height);
_dateNav = QRect(_forward.x() + _forward.width() + (maxWidth - dateWidth) / 2, _forward.y() + st::medviewDateTop, dateWidth, st::medviewDateFont->height);
updateHeader();
_leftNavVisible = (_index > 0 || (_index == 0 && _history && _history->_photosOverview.size() < _history->_photosOverviewCount));
_leftNavVisible = (_index > 0 || (_index == 0 && _history && _history->_overview[OverviewPhotos].size() < _history->_overviewCount[OverviewPhotos]));
_rightNavVisible = (_index >= 0 && (
(_history && _index + 1 < _history->_photosOverview.size()) ||
(_history && _index + 1 < _history->_overview[OverviewPhotos].size()) ||
(_user && (_index + 1 < _user->photos.size() || _index + 1 < _user->photosCount))));
updateOver(mapFromGlobal(QCursor::pos()));
update();
@ -228,7 +230,7 @@ void MediaView::onCopy() {
}
void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) {
_history = context->history();
_history = context ? context->history() : 0;
_peer = 0;
_user = 0;
@ -242,15 +244,15 @@ void MediaView::showPhoto(PhotoData *photo, HistoryItem *context) {
setCursor(style::cur_default);
_index = -1;
_msgid = context->id;
for (int i = 0, l = _history->_photosOverview.size(); i < l; ++i) {
if (_history->_photosOverview.at(i) == _msgid) {
_msgid = context ? context->id : 0;
for (int i = 0, l = _history->_overview[OverviewPhotos].size(); i < l; ++i) {
if (_history->_overview[OverviewPhotos].at(i) == _msgid) {
_index = i;
break;
}
}
if (_history->_photosOverviewCount < 0) {
if (_history->_overviewCount[OverviewPhotos] < 0) {
loadPhotosBack();
}
@ -443,9 +445,9 @@ void MediaView::moveToPhoto(int32 delta) {
int32 newIndex = _index + delta;
if (_history) {
if (newIndex >= 0 && newIndex < _history->_photosOverview.size()) {
if (newIndex >= 0 && newIndex < _history->_overview[OverviewPhotos].size()) {
_index = newIndex;
if (HistoryItem *item = App::histItemById(_history->_photosOverview[_index])) {
if (HistoryItem *item = App::histItemById(_history->_overview[OverviewPhotos][_index])) {
_msgid = item->id;
HistoryPhoto *photo = dynamic_cast<HistoryPhoto*>(item->getMedia());
if (photo) {
@ -472,12 +474,12 @@ void MediaView::moveToPhoto(int32 delta) {
void MediaView::preloadPhotos(int32 delta) {
if (_index < 0) return;
int32 from = _index + (delta ? delta : -1), to = _index + (delta ? delta * MediaOverviewPreloadCount : 1);
int32 from = _index + (delta ? delta : -1), to = _index + (delta ? delta * MediaOverviewPreloadCount : 1), forget = _index - delta * 2;
if (from > to) qSwap(from, to);
if (_history) {
for (int32 i = from; i <= to; ++i) {
if (i >= 0 && i < _history->_photosOverview.size() && i != _index) {
if (HistoryItem *item = App::histItemById(_history->_photosOverview[i])) {
if (i >= 0 && i < _history->_overview[OverviewPhotos].size() && i != _index) {
if (HistoryItem *item = App::histItemById(_history->_overview[OverviewPhotos][i])) {
HistoryPhoto *photo = dynamic_cast<HistoryPhoto*>(item->getMedia());
if (photo) {
photo->photo()->full->load();
@ -485,6 +487,14 @@ void MediaView::preloadPhotos(int32 delta) {
}
}
}
if (forget >= 0 && forget < _history->_overview[OverviewPhotos].size() && forget != _index) {
if (HistoryItem *item = App::histItemById(_history->_overview[OverviewPhotos][forget])) {
HistoryMedia *media = item->getMedia();
if (media && media->type() == MediaTypePhoto) {
static_cast<HistoryPhoto*>(media)->photo()->forget();
}
}
}
} else if (_user) {
for (int32 i = from; i <= to; ++i) {
if (i >= 0 && i < _user->photos.size() && i != _index) {
@ -496,6 +506,9 @@ void MediaView::preloadPhotos(int32 delta) {
_user->photos[i]->full->load();
}
}
if (forget >= 0 && forget < _user->photos.size() && forget != _index) {
_user->photos[forget]->forget();
}
}
}
@ -714,6 +727,14 @@ bool MediaView::event(QEvent *e) {
return QWidget::event(e);
}
void MediaView::hide() {
_close.clearState();
_save.clearState();
_forward.clearState();
_delete.clearState();
QWidget::hide();
}
void MediaView::onMenuDestroy(QObject *obj) {
if (_menu == obj) {
_menu = 0;
@ -742,72 +763,14 @@ void MediaView::onTouchTimer() {
void MediaView::loadPhotosBack() {
if (_loadRequest || _index < 0) return;
if (_history && _history->_photosOverviewCount != 0) {
MsgId minId = 0;
for (History::MediaOverviewIds::const_iterator i = _history->_photosOverviewIds.cbegin(), e = _history->_photosOverviewIds.cend(); i != e; ++i) {
if (*i > 0) {
minId = *i;
break;
}
}
int32 limit = (_index < MediaOverviewStartPerPage && _history->_photosOverview.size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
_loadRequest = MTP::send(MTPmessages_Search(_history->peer->input, MTPstring(), MTP_inputMessagesFilterPhotos(), MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minId), MTP_int(limit)), rpcDone(&MediaView::photosLoaded, _history));
if (_history && _history->_overviewCount[OverviewPhotos] != 0) {
if (App::main()) App::main()->loadMediaBack(_history->peer, OverviewPhotos);
} else if (_user && _user->photosCount != 0) {
int32 limit = (_index < MediaOverviewStartPerPage && _user->photos.size() > MediaOverviewStartPerPage) ? SearchPerPage : MediaOverviewStartPerPage;
_loadRequest = MTP::send(MTPphotos_GetUserPhotos(_user->inputUser, MTP_int(_user->photos.size()), MTP_int(0), MTP_int(limit)), rpcDone(&MediaView::userPhotosLoaded, _user));
}
}
void MediaView::photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req) {
if (req == _loadRequest) {
_loadRequest = 0;
}
const QVector<MTPMessage> *v = 0;
switch (msgs.type()) {
case mtpc_messages_messages: {
const MTPDmessages_messages &d(msgs.c_messages_messages());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
v = &d.vmessages.c_vector().v;
h->_photosOverviewCount = 0;
} break;
case mtpc_messages_messagesSlice: {
const MTPDmessages_messagesSlice &d(msgs.c_messages_messagesSlice());
App::feedUsers(d.vusers);
App::feedChats(d.vchats);
h->_photosOverviewCount = d.vcount.v;
v = &d.vmessages.c_vector().v;
} break;
default: return;
}
if (h->_photosOverviewCount > 0) {
for (History::MediaOverviewIds::const_iterator i = h->_photosOverviewIds.cbegin(), e = h->_photosOverviewIds.cend(); i != e; ++i) {
if (*i < 0) {
++h->_photosOverviewCount;
} else {
break;
}
}
}
if (v->isEmpty()) {
h->_photosOverviewCount = 0;
}
for (QVector<MTPMessage>::const_iterator i = v->cbegin(), e = v->cend(); i != e; ++i) {
HistoryItem *item = App::histories().addToBack(*i, -1);
if (item && h->_photosOverviewIds.constFind(item->id) == h->_photosOverviewIds.cend()) {
h->_photosOverviewIds.insert(item->id);
h->_photosOverview.push_front(item->id);
}
}
if (App::wnd()) App::wnd()->mediaOverviewUpdated(h->peer);
preloadPhotos(0);
}
void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mtpRequestId req) {
if (req == _loadRequest) {
_loadRequest = 0;
@ -842,14 +805,13 @@ void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mt
u->photos.push_back(photo);
}
if (App::wnd()) App::wnd()->mediaOverviewUpdated(u);
preloadPhotos(0);
}
void MediaView::updateHeader() {
int32 index = _index, count = 0;
if (_history) {
count = _history->_photosOverviewCount ? _history->_photosOverviewCount : _history->_photosOverview.size();
if (index >= 0) index += count - _history->_photosOverview.size();
count = _history->_overviewCount[OverviewPhotos] ? _history->_overviewCount[OverviewPhotos] : _history->_overview[OverviewPhotos].size();
if (index >= 0) index += count - _history->_overview[OverviewPhotos].size();
} else if (_user) {
count = _user->photosCount ? _user->photosCount : _user->photos.size();
}

View File

@ -35,6 +35,8 @@ public:
bool event(QEvent *e);
void hide();
void updateOver(const QPoint &mpos);
void showPhoto(PhotoData *photo, HistoryItem *context);

View File

@ -44,6 +44,9 @@ namespace {
typedef QList<DelayedRequest> DelayedRequestsList;
DelayedRequestsList delayedRequests;
typedef QSet<mtpRequestId> BadGuestDCRequests;
BadGuestDCRequests badGuestDCRequests;
typedef QVector<mtpRequestId> DCAuthWaiters;
typedef QMap<int32, DCAuthWaiters> AuthWaiters;
AuthWaiters authWaiters;
@ -131,6 +134,7 @@ namespace {
bool onErrorDefault(mtpRequestId requestId, const RPCError &error) {
const QString &err(error.type());
bool badGuestDC = (error.code() == 400) && (err == qsl("FILE_ID_INVALID"));
QRegularExpressionMatch m;
if ((m = QRegularExpression("^(FILE|PHONE|NETWORK|USER)_MIGRATE_(\\d+)$").match(err)).hasMatch()) {
if (!requestId) return false;
@ -185,7 +189,7 @@ namespace {
if (resender) resender->checkDelayed();
return true;
} else if (error.code() == 401) {
} else if (error.code() == 401 || (badGuestDC && badGuestDCRequests.constFind(requestId) == badGuestDCRequests.cend())) {
int32 dc = 0;
{
QMutexLocker locker(&requestByDCLock);
@ -198,7 +202,7 @@ namespace {
}
int32 newdc = abs(dc) % _mtp_internal::dcShift;
if (!newdc || newdc == mtpMainDC() || !MTP::authedId()) {
if (globalHandler.onFail) (*globalHandler.onFail)(requestId, error); // auth failed in main dc
if (!badGuestDC && globalHandler.onFail) (*globalHandler.onFail)(requestId, error); // auth failed in main dc
return false;
}
@ -208,6 +212,7 @@ namespace {
authExportRequests.insert(MTP::send(MTPauth_ExportAuthorization(MTP_int(newdc)), rpcDone(exportDone), rpcFail(exportFail)), newdc);
}
waiters.push_back(requestId);
if (badGuestDC) badGuestDCRequests.insert(requestId);
return true;
} else if (err == qsl("CONNECTION_NOT_INITED") || err == qsl("CONNECTION_LAYER_INVALID")) {
RequestMap::const_iterator i = requestMap.constFind(requestId);
@ -230,6 +235,7 @@ namespace {
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPreparedWithInit(i.value());
return true;
}
if (badGuestDC) badGuestDCRequests.remove(requestId);
return false;
}
@ -354,6 +360,7 @@ namespace _mtp_internal {
RPCError err(MTPRpcError(from, end));
DEBUG_LOG(("RPC Info: error received, code %1, type %2, description: %3").arg(err.code()).arg(err.type()).arg(err.description()));
if (!rpcErrorOccured(requestId, h, err)) {
parserMap.insert(requestId, h);
return;
}
} else {
@ -361,6 +368,7 @@ namespace _mtp_internal {
}
} catch (Exception &e) {
if (!rpcErrorOccured(requestId, h, rpcClientError("RESPONSE_PARSE_FAILED", QString("exception text: ") + e.what()))) {
parserMap.insert(requestId, h);
return;
}
}

View File

@ -1953,7 +1953,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
} else { // must create new session, because msg_id and msg_seqno are inconsistent
if (badTime) {
if (serverSalt) sessionData->setSalt(serverSalt);
unixtimeSet(serverTime);
unixtimeSet(serverTime, true);
badTime = false;
}
LOG(("Message Info: bad message notification received, msgId %1, error_code %2").arg(data.vbad_msg_id.v).arg(errorCode));
@ -2073,7 +2073,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
return (badTime ? 0 : 1);
}
if (serverSalt) sessionData->setSalt(serverSalt); // requestsFixTimeSalt with no lookup
unixtimeSet(serverTime);
unixtimeSet(serverTime, true);
DEBUG_LOG(("Message Info: unixtime updated from mtpc_msgs_state_info, now %1").arg(serverTime));
@ -2130,9 +2130,9 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
QVector<MTPlong> ids(1, data.vmsg_id);
if (badTime) {
if (requestsFixTimeSalt(ids, serverTime, serverSalt)) {
DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(data.vmsg_id.v));
badTime = false;
} else {
DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(data.vmsg_id.v));
return 0;
}
}
@ -2203,9 +2203,9 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
QVector<MTPlong> ids(1, reqMsgId);
if (badTime) {
if (requestsFixTimeSalt(ids, serverTime, serverSalt)) {
DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(reqMsgId.v));
badTime = false;
} else {
DEBUG_LOG(("Message Info: error, such message was not sent recently %1").arg(reqMsgId.v));
return 0;
}
}
@ -2309,7 +2309,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
if (badTime) {
DEBUG_LOG(("Message Error: bad time in updates cons"));
return 0;
return -1;
}
mtpBuffer update(end - from);
@ -2380,7 +2380,7 @@ bool MTProtoConnectionPrivate::requestsFixTimeSalt(const QVector<MTPlong> &ids,
for (uint32 i = 0; i < idsCount; ++i) {
if (wasSent(ids[i].v)) {// found such msg_id in recent acked requests or in recent sent requests
if (serverSalt) sessionData->setSalt(serverSalt);
unixtimeSet(serverTime);
unixtimeSet(serverTime, true);
return true;
}
}

View File

@ -0,0 +1,789 @@
/*
This file is part of Telegram Desktop,
an unofficial desktop messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014 John Preston, https://tdesktop.com
*/
#include "stdafx.h"
#include "lang.h"
#include "window.h"
#include "mainwidget.h"
#include "overviewwidget.h"
#include "boxes/addcontactbox.h"
#include "boxes/confirmbox.h"
#include "boxes/photocropbox.h"
#include "application.h"
#include "boxes/addparticipantbox.h"
#include "gui/filedialog.h"
OverviewInner::OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const PeerData *peer, MediaOverviewType type) : TWidget(0),
_overview(overview),
_scroll(scroll),
_resizeIndex(-1),
_resizeSkip(0),
_peer(App::peer(peer->id)),
_type(type),
_hist(App::history(peer->id)),
_menu(0),
_width(0),
_height(0),
_minHeight(0) {
App::contextItem(0);
mediaOverviewUpdated();
}
void OverviewInner::clear() {
_cached.clear();
}
bool OverviewInner::event(QEvent *e) {
if (e->type() == QEvent::MouseMove) {
QMouseEvent *ev = dynamic_cast<QMouseEvent*>(e);
if (ev) {
_lastPos = ev->globalPos();
updateSelected();
}
}
return QWidget::event(e);
}
QPixmap OverviewInner::genPix(PhotoData *photo, int32 size) {
size *= cIntRetinaFactor();
QImage img = (photo->full->loaded() ? photo->full : (photo->medium->loaded() ? photo->medium : photo->thumb))->pix().toImage();
if (img.width() > img.height()) {
img = img.scaled(img.width() * size / img.height(), size, Qt::KeepAspectRatioByExpanding, Qt::FastTransformation);
} else {
img = img.scaled(size, img.height() * size / img.width(), Qt::KeepAspectRatioByExpanding, Qt::FastTransformation);
}
img.setDevicePixelRatio(cRetinaFactor());
photo->forget();
return QPixmap::fromImage(img);
}
void OverviewInner::paintEvent(QPaintEvent *e) {
QPainter p(this);
QRect r(e->rect());
p.setClipRect(r);
if (_hist->_overview[_type].isEmpty()) {
QPoint dogPos((width() - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
p.drawPixmap(dogPos, App::sprite(), st::msgDogImg);
return;
}
if (_type == OverviewPhotos) {
int32 rowFrom = int32(r.top() - st::overviewPhotoSkip) / int32(_vsize + st::overviewPhotoSkip);
int32 rowTo = int32(r.bottom() - st::overviewPhotoSkip) / int32(_vsize + st::overviewPhotoSkip) + 1;
History::MediaOverview &overview(_hist->_overview[_type]);
int32 count = overview.size();
float64 w = float64(width() - st::overviewPhotoSkip) / _photosInRow;
for (int32 row = rowFrom; row < rowTo; ++row) {
if (row * _photosInRow >= count) break;
for (int32 i = 0; i < _photosInRow; ++i) {
int32 index = row * _photosInRow + i;
if (index >= count) break;
HistoryItem *item = App::histItemById(overview[count - index - 1]);
HistoryMedia *m = item ? item->getMedia(true) : 0;
if (!m) continue;
switch (m->type()) {
case MediaTypePhoto: {
PhotoData *photo = static_cast<HistoryPhoto*>(m)->photo();
bool quality = photo->full->loaded();
if (!quality) {
if (photo->thumb->loaded()) {
photo->medium->load(false, false);
quality = photo->medium->loaded();
} else {
photo->thumb->load();
}
}
CachedSizes::iterator it = _cached.find(photo);
if (it == _cached.cend()) {
CachedSize size;
size.medium = quality;
size.vsize = _vsize;
size.pix = genPix(photo, _vsize);
it = _cached.insert(photo, size);
} else if (it->medium != quality || it->vsize != _vsize) {
it->medium = quality;
it->vsize = _vsize;
it->pix = genPix(photo, _vsize);
}
QPixmap &pix(it->pix);
QPoint pos(int32(i * w + st::overviewPhotoSkip), row * (_vsize + st::overviewPhotoSkip) + st::overviewPhotoSkip);
int32 w = pix.width(), h = pix.height();
if (w == h) {
p.drawPixmap(pos, pix);
} else if (w > h) {
p.drawPixmap(pos, pix, QRect((w - h) / 2, 0, h, h));
} else {
p.drawPixmap(pos, pix, QRect(0, (h - w) / 2, w, w));
}
} break;
}
}
}
} else {
int32 addToY = (_height < _minHeight ? (_minHeight - _height) : 0);
p.translate(0, st::msgMargin.top() + addToY);
int32 y = 0, w = _width - st::msgMargin.left() - st::msgMargin.right();
for (int32 i = _items.size(); i > 0;) {
--i;
if (!i || (addToY + _height - _items[i - 1].y > r.top())) {
int32 curY = _height - _items[i].y;
if (addToY + curY >= r.bottom()) break;
p.translate(0, curY - y);
if (_items[i].msgid) { // draw item
HistoryItem *item = App::histItemById(_items[i].msgid);
HistoryMedia *media = item ? item->getMedia(true) : 0;
if (media) {
bool out = item->out();
int32 mw = media->maxWidth(), left = (out ? st::msgMargin.right() : st::msgMargin.left()) + (out && mw < w ? (w - mw) : 0);
if (!out && _hist->peer->chat) {
p.drawPixmap(left, media->height() - st::msgPhotoSize, item->from()->photo->pix(st::msgPhotoSize));
left += st::msgPhotoSkip;
}
p.save();
p.translate(left, 0);
media->draw(p, item, false, w);
p.restore();
}
} else {
QString str = langDayOfMonth(_items[i].date);
int32 left = st::msgServiceMargin.left(), width = _width - st::msgServiceMargin.left() - st::msgServiceMargin.left(), height = st::msgServiceFont->height + st::msgServicePadding.top() + st::msgServicePadding.bottom();
if (width < 1) return;
int32 strwidth = st::msgServiceFont->m.width(str) + st::msgServicePadding.left() + st::msgServicePadding.right();
QRect trect(QRect(left, st::msgServiceMargin.top(), width, height).marginsAdded(-st::msgServicePadding));
left += (width - strwidth) / 2;
width = strwidth;
QRect r(left, st::msgServiceMargin.top(), width, height);
p.setBrush(st::msgServiceBG->b);
p.setPen(Qt::NoPen);
p.drawRoundedRect(r, st::msgServiceRadius, st::msgServiceRadius);
p.setBrush(Qt::NoBrush);
p.setPen(st::msgServiceColor->p);
p.setFont(st::msgServiceFont->f);
p.drawText(r.x() + st::msgServicePadding.left(), r.y() + st::msgServicePadding.top() + st::msgServiceFont->ascent, str);
}
y = curY;
}
}
}
}
void OverviewInner::mouseMoveEvent(QMouseEvent *e) {
_lastPos = e->globalPos();
updateSelected();
}
void OverviewInner::updateSelected() {
if (!isVisible()) return;
QPoint p(mapFromGlobal(_lastPos));
HistoryItem *hovered = App::hoveredLinkItem(), *nhovered = 0;
TextLinkPtr lnk = textlnkOver(), nlnk;
if (_type == OverviewPhotos) {
float64 w = (float64(width() - st::overviewPhotoSkip) / _photosInRow);
int32 inRow = int32(p.x() / w), vsize = (_vsize + st::overviewPhotoSkip);
int32 row = int32(p.y() / vsize);
if (inRow < 0) inRow = 0;
if (row < 0) row = 0;
if (p.x() >= inRow * w + st::overviewPhotoSkip && p.x() < inRow * w + st::overviewPhotoSkip + _vsize) {
if (p.y() >= row * vsize + st::overviewPhotoSkip && p.y() < (row + 1) * vsize + st::overviewPhotoSkip) {
int32 index = row * _photosInRow + inRow, count = _hist->_overview[_type].size();
if (index >= 0 && index < count) {
MsgId msgid = _hist->_overview[_type][count - index - 1];
HistoryItem *item = App::histItemById(msgid);
HistoryMedia *media = item ? item->getMedia(true) : 0;
if (media && media->type() == MediaTypePhoto) {
nlnk = static_cast<HistoryPhoto*>(media)->lnk();
nhovered = item;
}
}
}
}
} else {
int32 addToY = (_height < _minHeight ? (_minHeight - _height) : 0);
int32 w = _width - st::msgMargin.left() - st::msgMargin.right();
for (int32 i = _items.size(); i > 0;) {
--i;
if (!i || (addToY + _height - _items[i - 1].y > p.y())) {
int32 y = addToY + _height - _items[i].y;
if (y >= p.y()) break;
if (!_items[i].msgid) break; // day item
HistoryItem *item = App::histItemById(_items[i].msgid);
HistoryMedia *media = item ? item->getMedia(true) : 0;
if (media) {
bool out = item->out();
int32 mw = media->maxWidth(), left = (out ? st::msgMargin.right() : st::msgMargin.left()) + (out && mw < w ? (w - mw) : 0);
if (!out && _hist->peer->chat) {
if (QRect(left, y + st::msgMargin.top() + media->height() - st::msgPhotoSize, st::msgPhotoSize, st::msgPhotoSize).contains(p)) {
nlnk = item->from()->lnk;
nhovered = item;
break;
}
left += st::msgPhotoSkip;
}
TextLinkPtr lnk = media->getLink(p.x() - left, p.y() - y - st::msgMargin.top(), item, w);
if (lnk) {
nlnk = lnk;
nhovered = item;
break;
}
}
}
}
}
textlnkOver(nlnk);
if (hovered != nhovered) {
App::hoveredLinkItem(nhovered);
if (App::main()) {
if (hovered) App::main()->msgUpdated(hovered->history()->peer->id, hovered);
if (nhovered) App::main()->msgUpdated(nhovered->history()->peer->id, nhovered);
}
}
if (lnk && !nlnk) {
setCursor(style::cur_default);
} else if (!lnk && nlnk) {
setCursor(style::cur_pointer);
}
}
void OverviewInner::mousePressEvent(QMouseEvent *e) {
_lastPos = e->globalPos();
updateSelected();
textlnkDown(textlnkOver());
}
void OverviewInner::mouseReleaseEvent(QMouseEvent *e) {
_lastPos = e->globalPos();
updateSelected();
TextLinkPtr over = textlnkOver();
if (over && over == textlnkDown()) {
over->onClick(e->button());
}
textlnkDown(TextLinkPtr());
}
void OverviewInner::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Escape) {
App::main()->showPeer(0, 0, true);
}
}
void OverviewInner::enterEvent(QEvent *e) {
setMouseTracking(true);
_lastPos = QCursor::pos();
updateSelected();
return TWidget::enterEvent(e);
}
void OverviewInner::leaveEvent(QEvent *e) {
setMouseTracking(false);
_lastPos = QCursor::pos();
updateSelected();
return TWidget::leaveEvent(e);
}
void OverviewInner::leaveToChildEvent(QEvent *e) {
_lastPos = QCursor::pos();
updateSelected();
return TWidget::leaveToChildEvent(e);
}
void OverviewInner::resizeEvent(QResizeEvent *e) {
_width = width();
showAll();
update();
}
void OverviewInner::contextMenuEvent(QContextMenuEvent *e) {
if (_menu) {
_menu->deleteLater();
_menu = 0;
}
if (e->reason() == QContextMenuEvent::Mouse) {
_lastPos = e->globalPos();
updateSelected();
}
_contextMenuLnk = textlnkOver();
PhotoLink *lnkPhoto = dynamic_cast<PhotoLink*>(_contextMenuLnk.data());
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkPhoto || lnkVideo || lnkAudio || lnkDocument) {
_menu = new QMenu(_overview);
if (App::hoveredLinkItem()) {
_menu->addAction(lang(lng_context_to_msg), this, SLOT(goToMessage()))->setEnabled(true);
}
if (lnkPhoto) {
_menu->addAction(lang(lng_context_open_image), this, SLOT(openContextUrl()))->setEnabled(true);
} else {
if ((lnkVideo && lnkVideo->video()->loader) || (lnkAudio && lnkAudio->audio()->loader) || (lnkDocument && lnkDocument->document()->loader)) {
_menu->addAction(lang(lng_context_cancel_download), this, SLOT(cancelContextDownload()))->setEnabled(true);
} else {
if ((lnkVideo && !lnkVideo->video()->already(true).isEmpty()) || (lnkAudio && !lnkAudio->audio()->already(true).isEmpty()) || (lnkDocument && !lnkDocument->document()->already(true).isEmpty())) {
_menu->addAction(lang(cPlatform() == dbipMac ? lng_context_show_in_finder : lng_context_show_in_folder), this, SLOT(showContextInFolder()))->setEnabled(true);
}
_menu->addAction(lang(lnkVideo ? lng_context_open_video : (lnkAudio ? lng_context_open_audio : lng_context_open_document)), this, SLOT(openContextFile()))->setEnabled(true);
_menu->addAction(lang(lnkVideo ? lng_context_save_video : (lnkAudio ? lng_context_save_audio : lng_context_save_document)), this, SLOT(saveContextFile()))->setEnabled(true);
}
}
if (App::hoveredLinkItem()) {
if (dynamic_cast<HistoryMessage*>(App::hoveredLinkItem())) {
_menu->addAction(lang(lng_context_forward_msg), this, SLOT(forwardMessage()))->setEnabled(true);
}
_menu->addAction(lang(lng_context_delete_msg), this, SLOT(deleteMessage()))->setEnabled(true);
App::contextItem(App::hoveredLinkItem());
}
}
if (_menu) {
_menu->setAttribute(Qt::WA_DeleteOnClose);
connect(_menu, SIGNAL(destroyed(QObject*)), this, SLOT(onMenuDestroy(QObject*)));
_menu->popup(e->globalPos());
e->accept();
}
}
int32 OverviewInner::resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeight) {
if (width() == nwidth && minHeight == _minHeight) return scrollTop;
_minHeight = minHeight;
if (_resizeIndex < 0) {
_resizeIndex = _photosInRow * (scrollTop / int32(_vsize + st::overviewPhotoSkip));
_resizeSkip = scrollTop - (scrollTop / int32(_vsize + st::overviewPhotoSkip)) * int32(_vsize + st::overviewPhotoSkip);
}
resize(nwidth, height() > _minHeight ? height() : _minHeight);
showAll();
int32 newRow = _resizeIndex / _photosInRow;
return newRow * int32(_vsize + st::overviewPhotoSkip) + _resizeSkip;
}
void OverviewInner::dropResizeIndex() {
_resizeIndex = -1;
}
PeerData *OverviewInner::peer() const {
return _peer;
}
MediaOverviewType OverviewInner::type() const {
return _type;
}
void OverviewInner::switchType(MediaOverviewType type) {
_type = type;
mediaOverviewUpdated();
if (App::wnd()) App::wnd()->update();
}
void OverviewInner::openContextUrl() {
HistoryItem *was = App::hoveredLinkItem();
App::hoveredLinkItem(App::contextItem());
_contextMenuLnk->onClick(Qt::LeftButton);
App::hoveredLinkItem(was);
}
void OverviewInner::goToMessage() {
HistoryItem *item = App::contextItem();
if (!item) return;
App::main()->showPeer(item->history()->peer->id, item->id, true, true);
}
void OverviewInner::forwardMessage() {
HistoryItem *item = App::contextItem();
if (!item || item->itemType() != HistoryItem::MsgType) return;
App::main()->forwardLayer();
}
void OverviewInner::deleteMessage() {
HistoryItem *item = App::contextItem();
if (!item || item->itemType() != HistoryItem::MsgType) return;
HistoryMessage *msg = dynamic_cast<HistoryMessage*>(item);
App::main()->deleteLayer((msg && msg->uploading()) ? -2 : -1);
}
void OverviewInner::cancelContextDownload() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
mtpFileLoader *loader = lnkVideo ? lnkVideo->video()->loader : (lnkAudio ? lnkAudio->audio()->loader : (lnkDocument ? lnkDocument->document()->loader : 0));
if (loader) loader->cancel();
}
void OverviewInner::showContextInFolder() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
QString already = lnkVideo ? lnkVideo->video()->already(true) : (lnkAudio ? lnkAudio->audio()->already(true) : (lnkDocument ? lnkDocument->document()->already(true) : QString()));
if (!already.isEmpty()) psShowInFolder(already);
}
void OverviewInner::saveContextFile() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) VideoSaveLink(lnkVideo->video()).doSave(true);
if (lnkAudio) AudioSaveLink(lnkAudio->audio()).doSave(true);
if (lnkDocument) DocumentSaveLink(lnkDocument->document()).doSave(true);
}
void OverviewInner::openContextFile() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) VideoOpenLink(lnkVideo->video()).onClick(Qt::LeftButton);
if (lnkAudio) AudioOpenLink(lnkAudio->audio()).onClick(Qt::LeftButton);
if (lnkDocument) DocumentOpenLink(lnkDocument->document()).onClick(Qt::LeftButton);
}
void OverviewInner::onMenuDestroy(QObject *obj) {
if (_menu == obj) {
_menu = 0;
}
}
void OverviewInner::mediaOverviewUpdated() {
int32 oldHeight = _height;
if (_type != OverviewPhotos) {
History::MediaOverview &o(_hist->_overview[_type]);
int32 l = o.size();
_items.reserve(2 * l); // day items
int32 y = 0, in = 0;
bool allGood = true;
QDate prevDate;
for (int32 i = 0; i < l; ++i) {
MsgId msgid = o.at(l - i - 1);
if (allGood) {
if (_items.size() > in && _items.at(in).msgid == msgid) {
prevDate = _items.at(in).date;
y = _items.at(in).y;
++in;
continue;
}
if (_items.size() > in + 1 && !_items.at(in).msgid && _items.at(in + 1).msgid == msgid) { // day item
++in;
prevDate = _items.at(in).date;
y = _items.at(in).y;
++in;
continue;
}
allGood = false;
}
HistoryItem *item = App::histItemById(msgid);
HistoryMedia *media = item ? item->getMedia(true) : 0;
if (!media) continue;
QDate date = item->date.date();
if (in > 0) {
if (date != prevDate) { // add day item
y += st::msgServiceFont->height + st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); // day item height
if (_items.size() > in) {
_items[in].msgid = 0;
_items[in].date = prevDate;
_items[in].y = y;
} else {
_items.push_back(CachedItem(0, prevDate, y));
}
++in;
prevDate = date;
}
} else {
prevDate = date;
}
y += media->height() + st::msgMargin.top() + st::msgMargin.bottom(); // item height
if (_items.size() > in) {
_items[in].msgid = msgid;
_items[in].date = date;
_items[in].y = y;
} else {
_items.push_back(CachedItem(msgid, date, y));
}
++in;
}
if (!_items.isEmpty()) {
y += st::msgServiceFont->height + st::msgServicePadding.top() + st::msgServicePadding.bottom() + st::msgServiceMargin.top() + st::msgServiceMargin.bottom(); // day item height
if (_items.size() > in) {
_items[in].msgid = 0;
_items[in].date = prevDate;
_items[in].y = y;
} else {
_items.push_back(CachedItem(0, prevDate, y));
}
_items.resize(++in);
}
if (_height != y) {
_height = y;
resize(width(), _minHeight > _height ? _minHeight : _height);
}
}
resizeEvent(0);
showAll();
if (_height != oldHeight) {
_overview->scrollBy(_height - oldHeight);
}
}
void OverviewInner::msgUpdated(HistoryItem *msg) {
if (!msg || _hist != msg->history()) return;
MsgId msgid = msg->id;
if (_hist->_overviewIds[_type].constFind(msgid) != _hist->_overviewIds[_type].cend()) {
if (_type == OverviewPhotos) {
int32 index = _hist->_overview[_type].indexOf(msgid);
if (index >= 0) {
index = _hist->_overview[_type].size() - index - 1;
float64 w = (float64(width() - st::overviewPhotoSkip) / _photosInRow);
int32 vsize = (_vsize + st::overviewPhotoSkip);
int32 row = index / _photosInRow, col = index % _photosInRow;
update(int32(col * w), int32(row * vsize), qCeil(w), vsize);
}
} else {
int32 addToY = (_height < _minHeight ? (_minHeight - _height) : 0);
for (int32 i = 0, l = _items.size(); i != l; ++i) {
if (_items[i].msgid == msgid) {
HistoryMedia *media = msg->getMedia(true);
if (media) update(0, addToY + _height - _items[i].y, _width, media->height() + st::msgMargin.top() + st::msgMargin.bottom());
break;
}
}
}
}
}
void OverviewInner::showAll() {
int32 newHeight = height();
if (_type == OverviewPhotos) {
_photosInRow = int32(width() - st::overviewPhotoSkip) / int32(st::overviewPhotoMinSize + st::overviewPhotoSkip);
_vsize = (int32(width() - st::overviewPhotoSkip) / _photosInRow) - st::overviewPhotoSkip;
int32 count = _hist->_overview[_type].size();
int32 rows = (count / _photosInRow) + ((count % _photosInRow) ? 1 : 0);
newHeight = (_vsize + st::overviewPhotoSkip) * rows + st::overviewPhotoSkip;
} else {
newHeight = _height;
}
if (newHeight < _minHeight) {
newHeight = _minHeight;
}
if (height() != newHeight) {
resize(width(), newHeight);
}
}
OverviewInner::~OverviewInner() {
}
OverviewWidget::OverviewWidget(QWidget *parent, const PeerData *peer, MediaOverviewType type) : QWidget(parent)
, _scroll(this, st::setScroll)
, _inner(this, &_scroll, peer, type)
, _noDropResizeIndex(false)
, _bg(st::msgBG)
, _showing(false)
{
_scroll.setWidget(&_inner);
_scroll.move(0, 0);
_inner.move(0, 0);
_scroll.show();
connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSelected()));
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
switchType(type);
}
void OverviewWidget::clear() {
_inner.clear();
}
void OverviewWidget::onScroll() {
MTP::clearLoaderPriorities();
bool nearBottom = _scroll.scrollTop() + _scroll.height() * 5 > _scroll.scrollTopMax(), nearTop = _scroll.scrollTop() < _scroll.height() * 5;
if (nearBottom && type() == OverviewPhotos || nearTop && type() != OverviewPhotos) {
if (App::main()) {
App::main()->loadMediaBack(peer(), type(), true);
}
}
if (!_noDropResizeIndex) {
_inner.dropResizeIndex();
}
}
void OverviewWidget::resizeEvent(QResizeEvent *e) {
_scroll.resize(size());
int32 newScrollTop = _inner.resizeToWidth(width(), _scroll.scrollTop(), height());
if (newScrollTop != _scroll.scrollTop()) {
_noDropResizeIndex = true;
_scroll.scrollToY(newScrollTop);
_noDropResizeIndex = false;
}
}
void OverviewWidget::paintEvent(QPaintEvent *e) {
QPainter p(this);
if (animating() && _showing) {
p.setOpacity(a_bgAlpha.current());
p.drawPixmap(a_bgCoord.current(), 0, _bgAnimCache);
p.setOpacity(a_alpha.current());
p.drawPixmap(a_coord.current(), 0, _animCache);
return;
}
QRect r(e->rect());
if (cCatsAndDogs()) {
int32 i_from = r.left() / _bg.width(), i_to = (r.left() + r.width() - 1) / _bg.width() + 1;
int32 j_from = r.top() / _bg.height(), j_to = (r.top() + r.height() - 1) / _bg.height() + 1;
for (int32 i = i_from; i < i_to; ++i) {
for (int32 j = j_from; j < j_to; ++j) {
p.drawPixmap(i * _bg.width(), j * _bg.height(), _bg);
}
}
} else {
p.fillRect(r, st::historyBG->b);
}
}
void OverviewWidget::scrollBy(int32 add) {
_scroll.scrollToY(_scroll.scrollTop() + add);
}
void OverviewWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) {
if (animating() && _showing) {
p.setOpacity(a_bgAlpha.current());
p.drawPixmap(a_bgCoord.current(), 0, _bgAnimTopBarCache);
p.setOpacity(a_alpha.current());
p.drawPixmap(a_coord.current(), 0, _animTopBarCache);
} else {
p.setOpacity(st::topBarBackAlpha + (1 - st::topBarBackAlpha) * over);
p.drawPixmap(QPoint(st::topBarBackPadding.left(), (st::topBarHeight - st::topBarBackImg.pxHeight()) / 2), App::sprite(), st::topBarBackImg);
p.setFont(st::topBarBackFont->f);
p.setPen(st::topBarBackColor->p);
p.drawText(st::topBarBackPadding.left() + st::topBarBackImg.pxWidth() + st::topBarBackPadding.right(), (st::topBarHeight - st::titleFont->height) / 2 + st::titleFont->ascent, _header);
}
}
void OverviewWidget::topBarClick() {
App::main()->showBackFromStack();
}
PeerData *OverviewWidget::peer() const {
return _inner.peer();
}
MediaOverviewType OverviewWidget::type() const {
return _inner.type();
}
void OverviewWidget::switchType(MediaOverviewType type) {
_inner.switchType(type);
switch (type) {
case OverviewPhotos: _header = lang(lng_profile_photos_header); break;
case OverviewVideos: _header = lang(lng_profile_videos_header); break;
case OverviewDocuments: _header = lang(lng_profile_documents_header); break;
case OverviewAudios: _header = lang(lng_profile_audios_header); break;
}
}
int32 OverviewWidget::lastWidth() const {
return width();
}
int32 OverviewWidget::lastScrollTop() const {
return _scroll.scrollTop();
}
void OverviewWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back, int32 lastScrollTop) {
_bgAnimCache = bgAnimCache;
_bgAnimTopBarCache = bgAnimTopBarCache;
_scroll.scrollToY(lastScrollTop < 0 ? (type() == OverviewPhotos ? 0 : _scroll.scrollTopMax()) : lastScrollTop);
_animCache = myGrab(this, rect());
App::main()->topBar()->stopAnim();
_animTopBarCache = myGrab(App::main()->topBar(), QRect(0, 0, width(), st::topBarHeight));
App::main()->topBar()->startAnim();
_scroll.hide();
a_coord = back ? anim::ivalue(-st::introSlideShift, 0) : anim::ivalue(st::introSlideShift, 0);
a_alpha = anim::fvalue(0, 1);
a_bgCoord = back ? anim::ivalue(0, st::introSlideShift) : anim::ivalue(0, -st::introSlideShift);
a_bgAlpha = anim::fvalue(1, 0);
anim::start(this);
_showing = true;
show();
_inner.setFocus();
App::main()->topBar()->update();
}
bool OverviewWidget::animStep(float64 ms) {
float64 fullDuration = st::introSlideDelta + st::introSlideDuration, dt = ms / fullDuration;
float64 dt1 = (ms > st::introSlideDuration) ? 1 : (ms / st::introSlideDuration), dt2 = (ms > st::introSlideDelta) ? (ms - st::introSlideDelta) / (st::introSlideDuration) : 0;
bool res = true;
if (dt2 >= 1) {
res = _showing = false;
a_bgCoord.finish();
a_bgAlpha.finish();
a_coord.finish();
a_alpha.finish();
_bgAnimCache = _animCache = _animTopBarCache = _bgAnimTopBarCache = QPixmap();
App::main()->topBar()->stopAnim();
_scroll.show();
activate();
onScroll();
} else {
a_bgCoord.update(dt1, st::introHideFunc);
a_bgAlpha.update(dt1, st::introAlphaHideFunc);
a_coord.update(dt2, st::introShowFunc);
a_alpha.update(dt2, st::introAlphaShowFunc);
}
update();
App::main()->topBar()->update();
return res;
}
void OverviewWidget::mediaOverviewUpdated(PeerData *p) {
if (peer() == p) {
_inner.mediaOverviewUpdated();
onScroll();
}
}
void OverviewWidget::msgUpdated(PeerId p, HistoryItem *msg) {
if (peer()->id == p) {
_inner.msgUpdated(msg);
}
}
OverviewWidget::~OverviewWidget() {
}
void OverviewWidget::activate() {
_inner.setFocus();
}

View File

@ -0,0 +1,165 @@
/*
This file is part of Telegram Desktop,
an unofficial desktop messaging app, see https://telegram.org
Telegram Desktop is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
It is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
Copyright (c) 2014 John Preston, https://tdesktop.com
*/
#pragma once
class OverviewWidget;
class OverviewInner : public TWidget, public RPCSender {
Q_OBJECT
public:
OverviewInner(OverviewWidget *overview, ScrollArea *scroll, const PeerData *peer, MediaOverviewType type);
void clear();
bool event(QEvent *e);
void paintEvent(QPaintEvent *e);
void mouseMoveEvent(QMouseEvent *e);
void mousePressEvent(QMouseEvent *e);
void mouseReleaseEvent(QMouseEvent *e);
void keyPressEvent(QKeyEvent *e);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void leaveToChildEvent(QEvent *e);
void resizeEvent(QResizeEvent *e);
void contextMenuEvent(QContextMenuEvent *e);
int32 resizeToWidth(int32 nwidth, int32 scrollTop, int32 minHeight); // returns new scroll top
void dropResizeIndex();
PeerData *peer() const;
MediaOverviewType type() const;
void switchType(MediaOverviewType type);
void mediaOverviewUpdated();
void msgUpdated(HistoryItem *msg);
~OverviewInner();
public slots:
void updateSelected();
void openContextUrl();
void cancelContextDownload();
void showContextInFolder();
void saveContextFile();
void openContextFile();
void goToMessage();
void deleteMessage();
void forwardMessage();
void onMenuDestroy(QObject *obj);
private:
QPixmap genPix(PhotoData *photo, int32 size);
void showAll();
OverviewWidget *_overview;
ScrollArea *_scroll;
int32 _resizeIndex, _resizeSkip;
PeerData *_peer;
MediaOverviewType _type;
History *_hist;
QMenu *_menu;
TextLinkPtr _contextMenuLnk;
// photos
int32 _photosInRow, _vsize;
typedef struct {
int32 vsize;
bool medium;
QPixmap pix;
} CachedSize;
typedef QMap<PhotoData*, CachedSize> CachedSizes;
CachedSizes _cached;
// other
typedef struct _CachedItem {
_CachedItem() : msgid(0), y(0) {
}
_CachedItem(MsgId msgid, const QDate &date, int32 y) : msgid(msgid), date(date), y(y) {
}
MsgId msgid;
QDate date;
int32 y;
} CachedItem;
typedef QVector<CachedItem> CachedItems;
CachedItems _items;
int32 _width, _height, _minHeight;
QPoint _lastPos;
};
class OverviewWidget : public QWidget, public RPCSender, public Animated {
Q_OBJECT
public:
OverviewWidget(QWidget *parent, const PeerData *peer, MediaOverviewType type);
void clear();
void resizeEvent(QResizeEvent *e);
void paintEvent(QPaintEvent *e);
void scrollBy(int32 add);
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
void topBarClick();
PeerData *peer() const;
MediaOverviewType type() const;
void switchType(MediaOverviewType type);
int32 lastWidth() const;
int32 lastScrollTop() const;
void animShow(const QPixmap &oldAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false, int32 lastScrollTop = -1);
bool animStep(float64 ms);
void mediaOverviewUpdated(PeerData *peer);
void msgUpdated(PeerId peer, HistoryItem *msg);
~OverviewWidget();
public slots:
void activate();
void onScroll();
private:
ScrollArea _scroll;
OverviewInner _inner;
bool _noDropResizeIndex;
QPixmap _bg;
QString _header;
bool _showing;
QPixmap _animCache, _bgAnimCache, _animTopBarCache, _bgAnimTopBarCache;
anim::ivalue a_coord, a_bgCoord;
anim::fvalue a_alpha, a_bgAlpha;
};

View File

@ -30,7 +30,7 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const PeerData *peer) : TWidget(0),
_profile(profile), _scroll(scroll), _peer(App::peer(peer->id)),
_peerUser(_peer->chat ? 0 : _peer->asUser()), _peerChat(_peer->chat ? _peer->asChat() : 0),
_peerUser(_peer->chat ? 0 : _peer->asUser()), _peerChat(_peer->chat ? _peer->asChat() : 0), _hist(App::history(peer->id)),
_chatAdmin(_peerChat ? (_peerChat->admin == MTP::authedId()) : false),
// profile
@ -48,6 +48,14 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
_enableNotifications(this, lang(lng_profile_enable_notifications)),
_clearHistory(this, lang(lng_profile_clear_history)),
// shared media
_allMediaTypes(false),
_mediaShowAll(this, lang(lng_profile_show_all_types)),
_mediaPhotos(this, QString()),
_mediaVideos(this, QString()),
_mediaDocuments(this, QString()),
_mediaAudios(this, QString()),
// participants
_pHeight(st::profileListPhotoSize + st::profileListPadding.height() * 2),
_kickWidth(st::linkFont->m.width(lang(lng_profile_kick))),
@ -88,6 +96,18 @@ ProfileInner::ProfileInner(ProfileWidget *profile, ScrollArea *scroll, const Pee
connect(&_enableNotifications, SIGNAL(clicked()), this, SLOT(onEnableNotifications()));
connect(&_clearHistory, SIGNAL(clicked()), this, SLOT(onClearHistory()));
// shared media
connect(&_mediaShowAll, SIGNAL(clicked()), this, SLOT(onMediaShowAll()));
connect(&_mediaPhotos, SIGNAL(clicked()), this, SLOT(onMediaPhotos()));
connect(&_mediaVideos, SIGNAL(clicked()), this, SLOT(onMediaVideos()));
connect(&_mediaDocuments, SIGNAL(clicked()), this, SLOT(onMediaDocuments()));
connect(&_mediaAudios, SIGNAL(clicked()), this, SLOT(onMediaAudios()));
_mediaLinks[OverviewPhotos] = &_mediaPhotos;
_mediaLinks[OverviewVideos] = &_mediaVideos;
_mediaLinks[OverviewDocuments] = &_mediaDocuments;
_mediaLinks[OverviewAudios] = &_mediaAudios;
App::main()->preloadOverviews(_peer);
App::contextItem(0);
resizeEvent(0);
@ -119,7 +139,7 @@ void ProfileInner::loadProfilePhotos(int32 yFrom) {
int32 yTo = yFrom + (parentWidget() ? parentWidget()->height() : App::wnd()->height()) * 5;
MTP::clearLoaderPriorities();
int32 partfrom = (_enableNotifications.y() + _enableNotifications.height()) + st::profileHeaderSkip;
int32 partfrom = _mediaAudios.y() + _mediaAudios.height() + st::profileHeaderSkip;
yFrom -= partfrom;
yTo -= partfrom;
@ -206,6 +226,28 @@ void ProfileInner::onPhotoUpdateDone(PeerId peer) {
update();
}
void ProfileInner::onMediaShowAll() {
_allMediaTypes = true;
resizeEvent(0);
showAll();
}
void ProfileInner::onMediaPhotos() {
App::main()->showMediaOverview(_peer, OverviewPhotos);
}
void ProfileInner::onMediaVideos() {
App::main()->showMediaOverview(_peer, OverviewVideos);
}
void ProfileInner::onMediaDocuments() {
App::main()->showMediaOverview(_peer, OverviewDocuments);
}
void ProfileInner::onMediaAudios() {
App::main()->showMediaOverview(_peer, OverviewAudios);
}
void ProfileInner::gotFullUser(const MTPUserFull &user) {
_loadingId = 0;
const MTPDuserFull &d(user.c_userFull());
@ -407,6 +449,45 @@ void ProfileInner::paintEvent(QPaintEvent *e) {
top += _enableNotifications.height();
// shared media
p.setFont(st::profileHeaderFont->f);
p.setPen(st::profileHeaderColor->p);
p.drawText(_left + st::profileHeaderLeft, top + st::profileHeaderTop + st::profileHeaderFont->ascent, lang(lng_profile_shared_media));
top += st::profileHeaderSkip;
p.setFont(st::linkFont->f);
p.setPen(st::black->p);
int oneState = 0; // < 0 - loading, 0 - no media, > 0 - link shown
for (int i = 0; i < OverviewCount; ++i) {
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
if (count < 0) {
if (!oneState) oneState = count;
if (!_allMediaTypes) {
p.drawText(_left, top + st::linkFont->ascent, lang(lng_profile_loading));
break;
}
} else if (count > 0) {
oneState = count;
if (!_allMediaTypes) {
break;
}
top += _mediaLinks[i]->height() + st::setLittleSkip;
}
}
if (_allMediaTypes) {
if (oneState > 0) {
top -= st::setLittleSkip;
} else {
p.drawText(_left, top + st::linkFont->ascent, lang(oneState < 0 ? lng_profile_loading : lng_profile_no_media));
top += _mediaLinks[OverviewPhotos]->height();
}
} else {
if (!oneState) {
p.drawText(_left, top + st::linkFont->ascent, lang(lng_profile_no_media));
}
top += _mediaLinks[OverviewPhotos]->height();
}
// participants
if (_peerChat && (_peerChat->count > 0 || !_participants.isEmpty())) {
QString sectionHeader = lang(_participants.isEmpty() ? lng_profile_loading : lng_profile_participants_section);
@ -486,7 +567,7 @@ void ProfileInner::updateSelected() {
QPoint lp = mapFromGlobal(_lastPos);
int32 partfrom = (_enableNotifications.y() + _enableNotifications.height()) + st::profileHeaderSkip;
int32 partfrom = _mediaAudios.y() + _mediaAudios.height() + st::profileHeaderSkip;
int32 newSelected = (lp.x() >= _left - st::profileListPadding.width() && lp.x() < _left + _width + st::profileListPadding.width() && lp.y() >= partfrom) ? (lp.y() - partfrom) / _pHeight : -1;
UserData *newKickOver = 0;
@ -591,6 +672,25 @@ void ProfileInner::resizeEvent(QResizeEvent *e) {
// settings
top += st::profileHeaderSkip;
_enableNotifications.move(_left, top); top += _enableNotifications.height();
// shared media
top += st::profileHeaderSkip;
_mediaShowAll.move(_left + _width - _mediaShowAll.width(), top);
int wasCount = 0; // < 0 - loading, 0 - no media, > 0 - link shown
for (int i = 0; i < OverviewCount; ++i) {
if (_allMediaTypes) {
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
if (count > 0) {
if (wasCount) top += _mediaLinks[i]->height() + st::setLittleSkip;
wasCount = count;
}
}
_mediaLinks[i]->move(_left, top);
}
top += _mediaLinks[OverviewPhotos]->height();
// participants
if (_peerChat && (_peerChat->count > 0 || !_participants.isEmpty())) {
top += st::profileHeaderSkip;
if (!_participants.isEmpty()) {
@ -618,20 +718,14 @@ bool ProfileInner::animStep(float64 ms) {
return res;
}
bool ProfileInner::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
if ((_peerUser && photo->id == _peerUser->photoId) || (_peerChat && photo->id == _peerChat->photoId)) {
x = _left;
y = st::profilePadding.top();
w = st::setPhotoSize;
return true;
}
return false;
}
PeerData *ProfileInner::peer() const {
return _peer;
}
bool ProfileInner::allMediaShown() const {
return _allMediaTypes;
}
ProfileInner::~ProfileInner() {
for (ParticipantsData::iterator i = _participantsData.begin(), e = _participantsData.end(); i != e; ++i) {
delete *i;
@ -649,6 +743,13 @@ void ProfileInner::updateNotifySettings() {
_enableNotifications.setChecked(_peer->notify == EmptyNotifySettings || _peer->notify == UnknownNotifySettings || _peer->notify->mute < unixtime());
}
void ProfileInner::mediaOverviewUpdated(PeerData *peer) {
if (peer == _peer) {
resizeEvent(0);
showAll();
}
}
void ProfileInner::showAll() {
if (_peerChat) {
_sendMessage.hide();
@ -688,13 +789,47 @@ void ProfileInner::showAll() {
}
updateNotifySettings();
// shared media
bool first = false, wasCount = false, manyCounts = false;
for (int i = 0; i < OverviewCount; ++i) {
int32 count = (_hist->_overviewCount[i] > 0) ? _hist->_overviewCount[i] : (_hist->_overviewCount[i] == 0 ? _hist->_overview[i].size() : -1);
if (count > 0) {
if (wasCount) {
manyCounts = true;
} else {
wasCount = true;
}
}
if (!first || _allMediaTypes) {
if (count > 0 || count < 0) {
first = true;
} else if (!_allMediaTypes) {
_mediaLinks[i]->hide();
continue;
}
if (count > 0) {
_mediaLinks[i]->setText(overviewLinkText(i, count));
_mediaLinks[i]->show();
} else {
_mediaLinks[i]->hide();
}
} else {
_mediaLinks[i]->hide();
}
}
if (_allMediaTypes || !manyCounts) {
_mediaShowAll.hide();
} else {
_mediaShowAll.show();
}
// participants
reorderParticipants();
int32 h;
if (_peerUser) {
h = _clearHistory.y() + _clearHistory.height() + st::profileHeaderSkip;
} else {
h = _enableNotifications.y() + _enableNotifications.height() + st::profileHeaderSkip;
h = _mediaAudios.y() + _mediaAudios.height() + st::profileHeaderSkip;
if (!_participants.isEmpty()) {
h += st::profileHeaderSkip + _participants.size() * _pHeight;
} else if (_peerChat->count > 0) {
@ -704,6 +839,17 @@ void ProfileInner::showAll() {
resize(width(), h);
}
QString ProfileInner::overviewLinkText(int32 type, int32 count) {
LangKey key = lng_keys_cnt;
switch (type) {
case OverviewPhotos: key = (count > 1) ? lng_profile_photos : lng_profile_photo; break;
case OverviewVideos: key = (count > 1) ? lng_profile_videos : lng_profile_video; break;
case OverviewDocuments: key = (count > 1) ? lng_profile_documents : lng_profile_document; break;
case OverviewAudios: key = (count > 1) ? lng_profile_audios : lng_profile_audio; break;
}
return lang(key).replace(qsl("{count}"), QString::number(count));
}
ProfileWidget::ProfileWidget(QWidget *parent, const PeerData *peer) : QWidget(parent)
, _scroll(this, st::setScroll)
, _inner(this, &_scroll, peer)
@ -747,15 +893,6 @@ void ProfileWidget::dragEnterEvent(QDragEnterEvent *e) {
void ProfileWidget::dropEvent(QDropEvent *e) {
}
bool ProfileWidget::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
if (_inner.getPhotoCoords(photo, x, y, w)) {
x += _inner.x();
y += _inner.y();
return true;
}
return false;
}
void ProfileWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth) {
if (animating() && _showing) {
p.setOpacity(a_bgAlpha.current());
@ -772,16 +909,26 @@ void ProfileWidget::paintTopBar(QPainter &p, float64 over, int32 decreaseWidth)
}
void ProfileWidget::topBarClick() {
App::main()->showPeerBack();
App::main()->showBackFromStack();
}
PeerData *ProfileWidget::peer() const {
return _inner.peer();
}
void ProfileWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back) {
int32 ProfileWidget::lastScrollTop() const {
return _scroll.scrollTop();
}
bool ProfileWidget::allMediaShown() const {
return _inner.allMediaShown();
}
void ProfileWidget::animShow(const QPixmap &bgAnimCache, const QPixmap &bgAnimTopBarCache, bool back, int32 lastScrollTop, bool allMediaShown) {
_bgAnimCache = bgAnimCache;
_bgAnimTopBarCache = bgAnimTopBarCache;
if (allMediaShown) _inner.onMediaShowAll();
if (lastScrollTop >= 0) _scroll.scrollToY(lastScrollTop);
_animCache = myGrab(this, rect());
App::main()->topBar()->stopAnim();
_animTopBarCache = myGrab(App::main()->topBar(), QRect(0, 0, width(), st::topBarHeight));
@ -836,6 +983,10 @@ void ProfileWidget::updateNotifySettings() {
_inner.updateNotifySettings();
}
void ProfileWidget::mediaOverviewUpdated(PeerData *peer) {
_inner.mediaOverviewUpdated(peer);
}
ProfileWidget::~ProfileWidget() {
}

View File

@ -39,9 +39,8 @@ public:
bool animStep(float64 ms);
bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const;
PeerData *peer() const;
bool allMediaShown() const;
void gotFullUser(const MTPUserFull &user);
void gotFullChat(const MTPmessages_ChatFull &res);
@ -55,6 +54,7 @@ public:
void loadProfilePhotos(int32 yFrom);
void updateNotifySettings();
void mediaOverviewUpdated(PeerData *peer);
~ProfileInner();
@ -83,6 +83,12 @@ public slots:
void onKickConfirm();
void onMediaShowAll();
void onMediaPhotos();
void onMediaVideos();
void onMediaDocuments();
void onMediaAudios();
private:
void showAll();
@ -93,6 +99,7 @@ private:
PeerData *_peer;
UserData *_peerUser;
ChatData *_peerChat;
History *_hist;
bool _chatAdmin;
int32 _width, _left;
@ -115,6 +122,12 @@ private:
FlatCheckbox _enableNotifications;
LinkButton _clearHistory;
// shared media
bool _allMediaTypes;
LinkButton _mediaShowAll, _mediaPhotos, _mediaVideos, _mediaDocuments, _mediaAudios;
LinkButton *_mediaLinks[OverviewCount];
QString overviewLinkText(int32 type, int32 count);
// participants
int32 _pHeight;
int32 _kickWidth, _selectedRow, _lastPreload;
@ -135,7 +148,7 @@ private:
QPoint _lastPos;
QString _onlineText;
QString _onlineText;
};
@ -152,20 +165,21 @@ public:
void dragEnterEvent(QDragEnterEvent *e);
void dropEvent(QDropEvent *e);
bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const;
void paintTopBar(QPainter &p, float64 over, int32 decreaseWidth);
void topBarClick();
PeerData *peer() const;
int32 lastScrollTop() const;
bool allMediaShown() const;
void animShow(const QPixmap &oldAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false);
void animShow(const QPixmap &oldAnimCache, const QPixmap &bgAnimTopBarCache, bool back = false, int32 lastScrollTop = -1, bool allMediaShown = false);
bool animStep(float64 ms);
void updateOnlineDisplay();
void updateOnlineDisplayTimer();
void updateNotifySettings();
void mediaOverviewUpdated(PeerData *peer);
~ProfileWidget();

View File

@ -578,16 +578,6 @@ void SettingsInner::updateSize(int32 newWidth) {
}
}
bool SettingsInner::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
if (photo->id == _self->photoId) {
x = _left;
y = st::setTop;
w = st::setPhotoSize;
return true;
}
return false;
}
void SettingsInner::updateOnlineDisplay() {
}
@ -1227,15 +1217,6 @@ void SettingsWidget::dragEnterEvent(QDragEnterEvent *e) {
void SettingsWidget::dropEvent(QDropEvent *e) {
}
bool SettingsWidget::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
if (_inner.getPhotoCoords(photo, x, y, w)) {
x += _inner.x();
y += _inner.y();
return true;
}
return false;
}
void SettingsWidget::updateOnlineDisplay() {
_inner.updateOnlineDisplay();
}

View File

@ -71,7 +71,6 @@ public:
bool animStep(float64 ms);
void updateSize(int32 newWidth);
bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const;
void updateOnlineDisplay();
@ -230,8 +229,6 @@ public:
void dragEnterEvent(QDragEnterEvent *e);
void dropEvent(QDropEvent *e);
bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const;
void animShow(const QPixmap &bgAnimCache, bool back = false);
bool animStep(float64 ms);

View File

@ -17,6 +17,9 @@ Copyright (c) 2014 John Preston, https://tdesktop.com
*/
#pragma once
struct NullType {
};
//typedef unsigned char uchar; // Qt has uchar
typedef qint16 int16;
typedef quint16 uint16;

View File

@ -687,28 +687,6 @@ HitTestType Window::hitTest(const QPoint &p) const {
return HitTestNone;
}
bool Window::getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const {
if (main && main->getPhotoCoords(photo, x, y, w)) {
x += main->x();
y += main->y();
return true;
} else if (settings && settings->getPhotoCoords(photo, x, y, w)) {
x += main->x();
y += main->y();
return true;
}
return false;
}
bool Window::getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const {
if (main && main->getVideoCoords(video, x, y, w)) {
x += main->x();
y += main->y();
return true;
}
return false;
}
QRect Window::iconRect() const {
return QRect(st::titleIconPos + title->geometry().topLeft(), st::titleIconRect.pxSize());
}
@ -933,7 +911,7 @@ void Window::notifySchedule(History *history, MsgId msgId) {
}
uint64 ms = getms() + NotifyWaitTimeout;
notifyWhenAlerts[history].insert(ms);
notifyWhenAlerts[history].insert(ms, NullType());
if (cDesktopNotify()) {
NotifyWhenMaps::iterator i = notifyWhenMaps.find(history);
if (i == notifyWhenMaps.end()) {
@ -1027,7 +1005,7 @@ void Window::notifyShowNext(NotifyWindow *remove) {
uint64 ms = getms(), nextAlert = 0;
bool alert = false;
for (NotifyWhenAlerts::iterator i = notifyWhenAlerts.begin(); i != notifyWhenAlerts.end();) {
while (!i.value().isEmpty() && *i.value().begin() <= ms) {
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
i.value().erase(i.value().begin());
NotifySettingsPtr n = i.key()->peer->notify;
if (n == EmptyNotifySettings || (n != UnknownNotifySettings && n->mute <= unixtime())) {
@ -1037,8 +1015,8 @@ void Window::notifyShowNext(NotifyWindow *remove) {
if (i.value().isEmpty()) {
i = notifyWhenAlerts.erase(i);
} else {
if (!nextAlert || nextAlert > *i.value().begin()) {
nextAlert = *i.value().begin();
if (!nextAlert || nextAlert > i.value().begin().key()) {
nextAlert = i.value().begin().key();
}
++i;
}
@ -1230,6 +1208,7 @@ void Window::sendPaths() {
}
void Window::mediaOverviewUpdated(PeerData *peer) {
if (main) main->mediaOverviewUpdated(peer);
if (!_mediaView || _mediaView->isHidden()) return;
_mediaView->mediaOverviewUpdated(peer);
}

View File

@ -184,9 +184,6 @@ public:
bool historyIsActive(int state = -1) const;
bool getPhotoCoords(PhotoData *photo, int32 &x, int32 &y, int32 &w) const;
bool getVideoCoords(VideoData *video, int32 &x, int32 &y, int32 &w) const;
bool minimizeToTray();
void activate();
@ -297,7 +294,7 @@ private:
NotifyWaiters notifySettingWaiters;
QTimer notifyWaitTimer;
typedef QSet<uint64> NotifyWhenAlert;
typedef QMap<uint64, NullType> NotifyWhenAlert;
typedef QMap<History*, NotifyWhenAlert> NotifyWhenAlerts;
NotifyWhenAlerts notifyWhenAlerts;

View File

@ -290,6 +290,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_overviewwidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_phoneinput.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -482,6 +486,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_overviewwidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_phoneinput.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@ -683,6 +691,10 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_overviewwidget.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_phoneinput.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
@ -787,6 +799,7 @@
<ClCompile Include="SourceFiles\mtproto\mtpFileLoader.cpp" />
<ClCompile Include="SourceFiles\mtproto\mtpRPC.cpp" />
<ClCompile Include="SourceFiles\mtproto\mtpSession.cpp" />
<ClCompile Include="SourceFiles\overviewwidget.cpp" />
<ClCompile Include="SourceFiles\profilewidget.cpp" />
<ClCompile Include="SourceFiles\pspecific_wnd.cpp" />
<ClCompile Include="SourceFiles\settings.cpp" />
@ -1502,6 +1515,20 @@
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
</CustomBuild>
<ClInclude Include="SourceFiles\mtproto\mtpSessionImpl.h" />
<CustomBuild Include="SourceFiles\overviewwidget.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing overviewwidget.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/overviewwidget.h" -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing overviewwidget.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/overviewwidget.h" -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui"</Command>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing overviewwidget.h...</Message>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/overviewwidget.h" -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.3.1\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.3.1\QtGui"</Command>
</CustomBuild>
<ClInclude Include="SourceFiles\pspecific.h" />
<ClInclude Include="SourceFiles\settings.h" />
<ClInclude Include="SourceFiles\style.h" />

View File

@ -680,6 +680,18 @@
<ClCompile Include="GeneratedFiles\Release\moc_mediaview.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Deploy\moc_overviewwidget.cpp">
<Filter>Generated Files\Deploy</Filter>
</ClCompile>
<ClCompile Include="SourceFiles\overviewwidget.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Debug\moc_overviewwidget.cpp">
<Filter>Generated Files\Debug</Filter>
</ClCompile>
<ClCompile Include="GeneratedFiles\Release\moc_overviewwidget.cpp">
<Filter>Generated Files\Release</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="SourceFiles\stdafx.h">
@ -921,6 +933,9 @@
<CustomBuild Include="SourceFiles\mediaview.h">
<Filter>Source Files</Filter>
</CustomBuild>
<CustomBuild Include="SourceFiles\overviewwidget.h">
<Filter>Source Files</Filter>
</CustomBuild>
</ItemGroup>
<ItemGroup>
<Image Include="SourceFiles\art\iconround256.ico" />