diff --git a/Telegram/Resources/lang.txt b/Telegram/Resources/lang.txt index c4bf91c20..e43b37c7c 100644 --- a/Telegram/Resources/lang.txt +++ b/Telegram/Resources/lang.txt @@ -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"; diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 0e8799d5a..9d6073fe8 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1481,6 +1481,9 @@ medviewButton: flatButton(btnDefFlat) { overFont: font(16px); } +overviewPhotoSkip: 10px; +overviewPhotoMinSize: 100px; + // Mac specific macAccessoryHeight: 90; diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index 5359f24d7..b27456abf 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -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 &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::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); diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index fcccf20b3..00d7ce5fe 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -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(); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 319d4bbbc..197b3f482 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -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))); diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h index 47acced1c..342707909 100644 --- a/Telegram/SourceFiles/config.h +++ b/Telegram/SourceFiles/config.h @@ -66,6 +66,7 @@ enum { AutoSearchTimeout = 900, // 0.9 secs SearchPerPage = 50, + SearchManyPerPage = 100, MediaOverviewStartPerPage = 5, MediaOverviewPreloadCount = 4, }; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 0eeb69afe..b783b2a19 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -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 &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 &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 ¤tTex 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 ¤tTex 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)) { diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index ad7839084..564bd54a4 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -179,11 +179,12 @@ struct ChatData : public PeerData { typedef QMap 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 { uint64 myTyping; typedef QList MediaOverview; - typedef QSet MediaOverviewIds; - MediaOverview _photosOverview; - MediaOverviewIds _photosOverviewIds; - int32 _photosOverviewCount; // -1 - not loaded, 0 - all loaded, > 0 - count, but not all loaded + typedef QMap 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; }; diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 072032e91..9e962bb03 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -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; diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index 3378e1a7e..72ffc1a15 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -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); diff --git a/Telegram/SourceFiles/localimageloader.cpp b/Telegram/SourceFiles/localimageloader.cpp index b07cf7005..cd3c92c12 100644 --- a/Telegram/SourceFiles/localimageloader.cpp +++ b/Telegram/SourceFiles/localimageloader.cpp @@ -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))); diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index a5c0e4869..070ca9a46 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -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(QVector(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 *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::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(item); + showPeer(histItem->peer->id, App::main()->activeMsgId(), true); + } else if (item->type() == ProfileStackItem) { + StackItemProfile *profItem = static_cast(item); + showPeerProfile(profItem->peer, true, profItem->lastScrollTop, profItem->allMediaShown); + } else if (item->type() == OverviewStackItem) { + StackItemOverview *overItem = static_cast(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; + } } } } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 44f8ff984..6dc6fc966 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -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 { +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::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 profileStack; + StackItems _stack; QPixmap profileAnimCache; int updPts, updDate, updQts, updSeq; @@ -294,4 +372,7 @@ private: typedef QMap ReadRequests; ReadRequests _readRequests; + + typedef QMap OverviewsPreload; + OverviewsPreload _overviewPreload[OverviewCount], _overviewLoad[OverviewCount]; }; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index 3a33a1132..520054df2 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -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(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(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(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 *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::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(); } diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index b496e0982..f19efe929 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -35,6 +35,8 @@ public: bool event(QEvent *e); + void hide(); + void updateOver(const QPoint &mpos); void showPhoto(PhotoData *photo, HistoryItem *context); diff --git a/Telegram/SourceFiles/mtproto/mtp.cpp b/Telegram/SourceFiles/mtproto/mtp.cpp index 3b45e3cd1..3eeb3c4af 100644 --- a/Telegram/SourceFiles/mtproto/mtp.cpp +++ b/Telegram/SourceFiles/mtproto/mtp.cpp @@ -44,6 +44,9 @@ namespace { typedef QList DelayedRequestsList; DelayedRequestsList delayedRequests; + typedef QSet BadGuestDCRequests; + BadGuestDCRequests badGuestDCRequests; + typedef QVector DCAuthWaiters; typedef QMap 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; } } diff --git a/Telegram/SourceFiles/mtproto/mtpConnection.cpp b/Telegram/SourceFiles/mtproto/mtpConnection.cpp index 3b4d9e704..87c59f5aa 100644 --- a/Telegram/SourceFiles/mtproto/mtpConnection.cpp +++ b/Telegram/SourceFiles/mtproto/mtpConnection.cpp @@ -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 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 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 &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; } } diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp new file mode 100644 index 000000000..aaa8af8ae --- /dev/null +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -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(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(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(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(_contextMenuLnk.data()); + VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_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(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(item); + App::main()->deleteLayer((msg && msg->uploading()) ? -2 : -1); +} + +void OverviewInner::cancelContextDownload() { + VideoLink *lnkVideo = dynamic_cast(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_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(_contextMenuLnk.data()); + AudioLink *lnkAudio = dynamic_cast(_contextMenuLnk.data()); + DocumentLink *lnkDocument = dynamic_cast(_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(); +} diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h new file mode 100644 index 000000000..6f1f65361 --- /dev/null +++ b/Telegram/SourceFiles/overviewwidget.h @@ -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 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 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; + +}; + diff --git a/Telegram/SourceFiles/profilewidget.cpp b/Telegram/SourceFiles/profilewidget.cpp index 96a4c1759..e52af6a20 100644 --- a/Telegram/SourceFiles/profilewidget.cpp +++ b/Telegram/SourceFiles/profilewidget.cpp @@ -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() { } diff --git a/Telegram/SourceFiles/profilewidget.h b/Telegram/SourceFiles/profilewidget.h index 6e8cffe20..be333a41d 100644 --- a/Telegram/SourceFiles/profilewidget.h +++ b/Telegram/SourceFiles/profilewidget.h @@ -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(); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index 47c9b2d4e..34d120b8c 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -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(); } diff --git a/Telegram/SourceFiles/settingswidget.h b/Telegram/SourceFiles/settingswidget.h index fdf57c957..4931e1b88 100644 --- a/Telegram/SourceFiles/settingswidget.h +++ b/Telegram/SourceFiles/settingswidget.h @@ -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); diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h index c0f7c7a94..460eb034f 100644 --- a/Telegram/SourceFiles/types.h +++ b/Telegram/SourceFiles/types.h @@ -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; diff --git a/Telegram/SourceFiles/window.cpp b/Telegram/SourceFiles/window.cpp index 5eacd6c1f..fc79a3d73 100644 --- a/Telegram/SourceFiles/window.cpp +++ b/Telegram/SourceFiles/window.cpp @@ -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); } diff --git a/Telegram/SourceFiles/window.h b/Telegram/SourceFiles/window.h index 3fa5df141..4cf9e53cf 100644 --- a/Telegram/SourceFiles/window.h +++ b/Telegram/SourceFiles/window.h @@ -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 NotifyWhenAlert; + typedef QMap NotifyWhenAlert; typedef QMap NotifyWhenAlerts; NotifyWhenAlerts notifyWhenAlerts; diff --git a/Telegram/Telegram.vcxproj b/Telegram/Telegram.vcxproj index c0f64e007..39dafbca3 100644 --- a/Telegram/Telegram.vcxproj +++ b/Telegram/Telegram.vcxproj @@ -290,6 +290,10 @@ true true + + true + true + true true @@ -482,6 +486,10 @@ true true + + true + true + true true @@ -683,6 +691,10 @@ true true + + true + true + true true @@ -787,6 +799,7 @@ + @@ -1502,6 +1515,20 @@ $(QTDIR)\bin\moc.exe;%(FullPath) + + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing overviewwidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(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" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing overviewwidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(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" + $(QTDIR)\bin\moc.exe;%(FullPath) + Moc%27ing overviewwidget.h... + .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp + "$(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" + diff --git a/Telegram/Telegram.vcxproj.filters b/Telegram/Telegram.vcxproj.filters index b3a681c53..a0c1c957f 100644 --- a/Telegram/Telegram.vcxproj.filters +++ b/Telegram/Telegram.vcxproj.filters @@ -680,6 +680,18 @@ Generated Files\Release + + Generated Files\Deploy + + + Source Files + + + Generated Files\Debug + + + Generated Files\Release + @@ -921,6 +933,9 @@ Source Files + + Source Files +