mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Add a fast share button in channels and bots.
This commit is contained in:
parent
ac99784bf7
commit
f32af6999b
13 changed files with 443 additions and 237 deletions
BIN
Telegram/Resources/icons/fast_share.png
Normal file
BIN
Telegram/Resources/icons/fast_share.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 330 B |
BIN
Telegram/Resources/icons/fast_share@2x.png
Normal file
BIN
Telegram/Resources/icons/fast_share@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 661 B |
|
@ -34,6 +34,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/toast/toast.h"
|
#include "ui/toast/toast.h"
|
||||||
#include "ui/widgets/multi_select.h"
|
#include "ui/widgets/multi_select.h"
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
|
#include "history/history_message.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
#include "window/themes/window_theme.h"
|
#include "window/themes/window_theme.h"
|
||||||
|
@ -208,7 +209,7 @@ void ShareBox::createButtons() {
|
||||||
clearButtons();
|
clearButtons();
|
||||||
if (_hasSelected) {
|
if (_hasSelected) {
|
||||||
addButton(langFactory(lng_share_confirm), [this] { onSubmit(); });
|
addButton(langFactory(lng_share_confirm), [this] { onSubmit(); });
|
||||||
} else {
|
} else if (_copyCallback) {
|
||||||
addButton(langFactory(lng_share_copy_link), [this] { onCopyLink(); });
|
addButton(langFactory(lng_share_copy_link), [this] { onCopyLink(); });
|
||||||
}
|
}
|
||||||
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
addButton(langFactory(lng_cancel), [this] { closeBox(); });
|
||||||
|
@ -840,103 +841,6 @@ QString AppendShareGameScoreUrl(const QString &url, const FullMsgId &fullId) {
|
||||||
return url + shareComponent;
|
return url + shareComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
void ShareGameScoreFromItem(HistoryItem *item) {
|
|
||||||
struct ShareGameScoreData {
|
|
||||||
ShareGameScoreData(const FullMsgId &msgId) : msgId(msgId) {
|
|
||||||
}
|
|
||||||
FullMsgId msgId;
|
|
||||||
OrderedSet<mtpRequestId> requests;
|
|
||||||
};
|
|
||||||
auto data = MakeShared<ShareGameScoreData>(item->fullId());
|
|
||||||
|
|
||||||
auto copyCallback = [data]() {
|
|
||||||
if (auto main = App::main()) {
|
|
||||||
if (auto item = App::histItemById(data->msgId)) {
|
|
||||||
if (auto bot = item->getMessageBot()) {
|
|
||||||
if (auto media = item->getMedia()) {
|
|
||||||
if (media->type() == MediaTypeGame) {
|
|
||||||
auto shortName = static_cast<HistoryGame*>(media)->game()->shortName;
|
|
||||||
|
|
||||||
QApplication::clipboard()->setText(Messenger::Instance().createInternalLinkFull(bot->username + qsl("?game=") + shortName));
|
|
||||||
|
|
||||||
Ui::Toast::Show(lang(lng_share_game_link_copied));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
auto submitCallback = [data](const QVector<PeerData*> &result) {
|
|
||||||
if (!data->requests.empty()) {
|
|
||||||
return; // Share clicked already.
|
|
||||||
}
|
|
||||||
if (result.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto restrictedEverywhere = true;
|
|
||||||
auto restrictedSomewhere = false;
|
|
||||||
for_const (auto peer, result) {
|
|
||||||
if (auto megagroup = peer->asMegagroup()) {
|
|
||||||
if (megagroup->restrictedRights().is_send_games()) {
|
|
||||||
restrictedSomewhere = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
restrictedEverywhere = false;
|
|
||||||
}
|
|
||||||
if (restrictedEverywhere) {
|
|
||||||
Ui::show(Box<InformBox>(lang(lng_restricted_send_inline)), KeepOtherLayers);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto doneCallback = [data](const MTPUpdates &updates, mtpRequestId requestId) {
|
|
||||||
if (auto main = App::main()) {
|
|
||||||
main->sentUpdatesReceived(updates);
|
|
||||||
}
|
|
||||||
data->requests.remove(requestId);
|
|
||||||
if (data->requests.empty()) {
|
|
||||||
Ui::Toast::Show(lang(lng_share_done));
|
|
||||||
Ui::hideLayer();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
auto sendFlags = MTPmessages_ForwardMessages::Flag::f_with_my_score;
|
|
||||||
MTPVector<MTPint> msgIds = MTP_vector<MTPint>(1, MTP_int(data->msgId.msg));
|
|
||||||
if (auto main = App::main()) {
|
|
||||||
if (auto item = App::histItemById(data->msgId)) {
|
|
||||||
for_const (auto peer, result) {
|
|
||||||
if (auto megagroup = peer->asMegagroup()) {
|
|
||||||
if (megagroup->restrictedRights().is_send_games()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MTPVector<MTPlong> random = MTP_vector<MTPlong>(1, rand_value<MTPlong>());
|
|
||||||
auto request = MTPmessages_ForwardMessages(MTP_flags(sendFlags), item->history()->peer->input, msgIds, random, peer->input);
|
|
||||||
auto callback = doneCallback;
|
|
||||||
auto requestId = MTP::send(request, rpcDone(std::move(callback)));
|
|
||||||
data->requests.insert(requestId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
auto filterCallback = [](PeerData *peer) {
|
|
||||||
if (peer->canWrite()) {
|
|
||||||
if (auto channel = peer->asChannel()) {
|
|
||||||
return !channel->isBroadcast();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
Ui::show(Box<ShareBox>(std::move(copyCallback), std::move(submitCallback), std::move(filterCallback)));
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void ShareGameScoreByHash(const QString &hash) {
|
void ShareGameScoreByHash(const QString &hash) {
|
||||||
auto key128Size = 0x10;
|
auto key128Size = 0x10;
|
||||||
|
|
||||||
|
@ -988,12 +892,12 @@ void ShareGameScoreByHash(const QString &hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto item = App::histItemById(channelId, msgId)) {
|
if (auto item = App::histItemById(channelId, msgId)) {
|
||||||
ShareGameScoreFromItem(item);
|
FastShareMessage(item);
|
||||||
} else if (App::api()) {
|
} else if (App::api()) {
|
||||||
auto resolveMessageAndShareScore = [msgId](ChannelData *channel) {
|
auto resolveMessageAndShareScore = [msgId](ChannelData *channel) {
|
||||||
App::api()->requestMessageData(channel, msgId, [](ChannelData *channel, MsgId msgId) {
|
App::api()->requestMessageData(channel, msgId, [](ChannelData *channel, MsgId msgId) {
|
||||||
if (auto item = App::histItemById(channel, msgId)) {
|
if (auto item = App::histItemById(channel, msgId)) {
|
||||||
ShareGameScoreFromItem(item);
|
FastShareMessage(item);
|
||||||
} else {
|
} else {
|
||||||
Ui::show(Box<InformBox>(lang(lng_edit_deleted)));
|
Ui::show(Box<InformBox>(lang(lng_edit_deleted)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,3 +483,8 @@ historyAdminLogCancelSearch: CrossButton {
|
||||||
}
|
}
|
||||||
historyAdminLogSearchTop: 11px;
|
historyAdminLogSearchTop: 11px;
|
||||||
historyAdminLogSearchSlideDuration: 150;
|
historyAdminLogSearchSlideDuration: 150;
|
||||||
|
|
||||||
|
historyFastShareSize: 31px;
|
||||||
|
historyFastShareLeft: 13px;
|
||||||
|
historyFastShareBottom: 5px;
|
||||||
|
historyFastShareIcon: icon {{ "fast_share", msgServiceFg, point(4px, 3px)}};
|
||||||
|
|
|
@ -692,6 +692,14 @@ public:
|
||||||
|
|
||||||
virtual void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const {
|
virtual void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const {
|
||||||
}
|
}
|
||||||
|
virtual ClickHandlerPtr fastShareLink() const {
|
||||||
|
return ClickHandlerPtr();
|
||||||
|
}
|
||||||
|
virtual bool displayFastShare() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual void drawFastShare(Painter &p, int left, int top, int outerWidth) const {
|
||||||
|
}
|
||||||
virtual void setViewsCount(int32 count) {
|
virtual void setViewsCount(int32 count) {
|
||||||
}
|
}
|
||||||
virtual void setId(MsgId newId);
|
virtual void setId(MsgId newId);
|
||||||
|
|
|
@ -59,6 +59,9 @@ public:
|
||||||
virtual bool hasTextForCopy() const {
|
virtual bool hasTextForCopy() const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
virtual bool allowsFastShare() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
virtual void initDimensions() = 0;
|
virtual void initDimensions() = 0;
|
||||||
virtual void updateMessageId() {
|
virtual void updateMessageId() {
|
||||||
}
|
}
|
||||||
|
|
|
@ -453,14 +453,20 @@ void HistoryPhoto::draw(Painter &p, const QRect &r, TextSelection selection, Tim
|
||||||
}
|
}
|
||||||
|
|
||||||
// date
|
// date
|
||||||
if (_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
if (notChild && (_data->uploading() || App::hoveredItem() == _parent)) {
|
|
||||||
int32 fullRight = skipx + width, fullBottom = skipy + height;
|
|
||||||
_parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
||||||
_caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
|
_caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
|
||||||
|
} else if (notChild) {
|
||||||
|
auto fullRight = skipx + width;
|
||||||
|
auto fullBottom = skipy + height;
|
||||||
|
if (_data->uploading() || App::hoveredItem() == _parent) {
|
||||||
|
_parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage);
|
||||||
|
}
|
||||||
|
if (!bubble && _parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
_parent->drawFastShare(p, fastShareLeft, fastShareTop, 2 * skipx + width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,7 +475,7 @@ HistoryTextState HistoryPhoto::getState(QPoint point, HistoryStateRequest reques
|
||||||
|
|
||||||
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result;
|
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return result;
|
||||||
int skipx = 0, skipy = 0, width = _width, height = _height;
|
int skipx = 0, skipy = 0, width = _width, height = _height;
|
||||||
bool bubble = _parent->hasBubble();
|
auto bubble = _parent->hasBubble();
|
||||||
|
|
||||||
if (bubble) {
|
if (bubble) {
|
||||||
skipx = st::mediaPadding.left();
|
skipx = st::mediaPadding.left();
|
||||||
|
@ -502,14 +508,20 @@ HistoryTextState HistoryPhoto::getState(QPoint point, HistoryStateRequest reques
|
||||||
} else {
|
} else {
|
||||||
result.link = _savel;
|
result.link = _savel;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (_caption.isEmpty() && _parent->getMedia() == this) {
|
if (_caption.isEmpty() && _parent->getMedia() == this) {
|
||||||
auto fullRight = skipx + width;
|
auto fullRight = skipx + width;
|
||||||
auto fullBottom = skipy + height;
|
auto fullBottom = skipy + height;
|
||||||
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) {
|
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) {
|
||||||
result.cursor = HistoryInDateCursorState;
|
result.cursor = HistoryInDateCursorState;
|
||||||
}
|
}
|
||||||
|
if (!bubble && _parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) {
|
||||||
|
result.link = _parent->fastShareLink();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -830,14 +842,17 @@ void HistoryVideo::draw(Painter &p, const QRect &r, TextSelection selection, Tim
|
||||||
p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x());
|
p.drawTextLeft(statusX, statusY, _width, _statusText, statusW - 2 * st::msgDateImgPadding.x());
|
||||||
|
|
||||||
// date
|
// date
|
||||||
if (_caption.isEmpty()) {
|
if (!_caption.isEmpty()) {
|
||||||
if (_parent->getMedia() == this) {
|
|
||||||
int32 fullRight = skipx + width, fullBottom = skipy + height;
|
|
||||||
_parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
||||||
_caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
|
_caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
|
||||||
|
} else if (_parent->getMedia() == this) {
|
||||||
|
auto fullRight = skipx + width, fullBottom = skipy + height;
|
||||||
|
_parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, InfoDisplayOverImage);
|
||||||
|
if (!bubble && _parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
_parent->drawFastShare(p, fastShareLeft, fastShareTop, 2 * skipx + width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -874,14 +889,20 @@ HistoryTextState HistoryVideo::getState(QPoint point, HistoryStateRequest reques
|
||||||
} else {
|
} else {
|
||||||
result.link = loaded ? _openl : (_data->loading() ? _cancell : _savel);
|
result.link = loaded ? _openl : (_data->loading() ? _cancell : _savel);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (_caption.isEmpty() && _parent->getMedia() == this) {
|
if (_caption.isEmpty() && _parent->getMedia() == this) {
|
||||||
auto fullRight = skipx + width;
|
auto fullRight = skipx + width;
|
||||||
auto fullBottom = skipy + height;
|
auto fullBottom = skipy + height;
|
||||||
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) {
|
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) {
|
||||||
result.cursor = HistoryInDateCursorState;
|
result.cursor = HistoryInDateCursorState;
|
||||||
}
|
}
|
||||||
|
if (!bubble && _parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) {
|
||||||
|
result.link = _parent->fastShareLink();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2160,31 +2181,41 @@ void HistoryGif::draw(Painter &p, const QRect &r, TextSelection selection, TimeM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!_caption.isEmpty()) {
|
if (!isRound && !_caption.isEmpty()) {
|
||||||
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
p.setPen(outbg ? (selected ? st::historyTextOutFgSelected : st::historyTextOutFg) : (selected ? st::historyTextInFgSelected : st::historyTextInFg));
|
||||||
_caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
|
_caption.draw(p, st::msgPadding.left(), skipy + height + st::mediaPadding.bottom() + st::mediaCaptionSkip, captionw, style::al_left, 0, -1, selection);
|
||||||
} else if (!isChildMedia && (isRound || _data->uploading() || App::hoveredItem() == _parent)) {
|
} else if (!isChildMedia) {
|
||||||
auto fullRight = skipx + usex + usew;
|
auto fullRight = skipx + usex + usew;
|
||||||
auto fullBottom = skipy + height;
|
auto fullBottom = skipy + height;
|
||||||
if (isRound && !outbg) {
|
|
||||||
auto infoWidth = _parent->infoWidth();
|
|
||||||
|
|
||||||
// This is just some arbitrary point,
|
|
||||||
// the main idea is to make info left aligned here.
|
|
||||||
fullRight += infoWidth - st::normalFont->height;
|
|
||||||
|
|
||||||
auto maxRight = _parent->history()->width - st::msgMargin.left();
|
auto maxRight = _parent->history()->width - st::msgMargin.left();
|
||||||
if (_parent->history()->canHaveFromPhotos()) {
|
if (_parent->history()->canHaveFromPhotos()) {
|
||||||
maxRight -= st::msgMargin.right();
|
maxRight -= st::msgMargin.right();
|
||||||
} else {
|
} else {
|
||||||
maxRight -= st::msgMargin.left();
|
maxRight -= st::msgMargin.left();
|
||||||
}
|
}
|
||||||
|
if (isRound && !outbg) {
|
||||||
|
auto infoWidth = _parent->infoWidth();
|
||||||
|
|
||||||
|
// This is just some arbitrary point,
|
||||||
|
// the main idea is to make info left aligned here.
|
||||||
|
fullRight += infoWidth - st::normalFont->height;
|
||||||
if (fullRight > maxRight) {
|
if (fullRight > maxRight) {
|
||||||
fullRight = maxRight;
|
fullRight = maxRight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (isRound || _data->uploading() || App::hoveredItem() == _parent) {
|
||||||
_parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage);
|
_parent->drawInfo(p, fullRight, fullBottom, 2 * skipx + width, selected, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage);
|
||||||
}
|
}
|
||||||
|
if (!bubble && _parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
if (fastShareLeft + st::historyFastShareSize > maxRight) {
|
||||||
|
fastShareLeft = (fullRight - st::historyFastShareSize - st::msgDateImgDelta);
|
||||||
|
fastShareTop -= (st::msgDateImgDelta + st::msgDateImgPadding.y() + st::msgDateFont->height + st::msgDateImgPadding.y());
|
||||||
|
}
|
||||||
|
_parent->drawFastShare(p, fastShareLeft, fastShareTop, 2 * skipx + width);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request) const {
|
HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request) const {
|
||||||
|
@ -2212,8 +2243,9 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request)
|
||||||
width -= st::mediaPadding.left() + st::mediaPadding.right();
|
width -= st::mediaPadding.left() + st::mediaPadding.right();
|
||||||
height -= skipy + st::mediaPadding.bottom();
|
height -= skipy + st::mediaPadding.bottom();
|
||||||
}
|
}
|
||||||
auto out = _parent->out(), isPost = _parent->isPost();
|
bool out = _parent->out(), isPost = _parent->isPost(), outbg = out && !isPost;
|
||||||
auto isChildMedia = (_parent->getMedia() != this);
|
auto isChildMedia = (_parent->getMedia() != this);
|
||||||
|
auto isRound = _data->isRoundVideo();
|
||||||
auto usew = width, usex = 0;
|
auto usew = width, usex = 0;
|
||||||
auto separateRoundVideo = isSeparateRoundVideo();
|
auto separateRoundVideo = isSeparateRoundVideo();
|
||||||
auto via = separateRoundVideo ? _parent->Get<HistoryMessageVia>() : nullptr;
|
auto via = separateRoundVideo ? _parent->Get<HistoryMessageVia>() : nullptr;
|
||||||
|
@ -2290,14 +2322,42 @@ HistoryTextState HistoryGif::getState(QPoint point, HistoryStateRequest request)
|
||||||
} else {
|
} else {
|
||||||
result.link = _openInMediaviewLink;
|
result.link = _openInMediaviewLink;
|
||||||
}
|
}
|
||||||
if (!isChildMedia) {
|
}
|
||||||
|
if (isRound || _caption.isEmpty()) {
|
||||||
auto fullRight = usex + skipx + usew;
|
auto fullRight = usex + skipx + usew;
|
||||||
auto fullBottom = skipy + height;
|
auto fullBottom = skipy + height;
|
||||||
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) {
|
auto maxRight = _parent->history()->width - st::msgMargin.left();
|
||||||
|
if (_parent->history()->canHaveFromPhotos()) {
|
||||||
|
maxRight -= st::msgMargin.right();
|
||||||
|
} else {
|
||||||
|
maxRight -= st::msgMargin.left();
|
||||||
|
}
|
||||||
|
if (isRound && !outbg) {
|
||||||
|
auto infoWidth = _parent->infoWidth();
|
||||||
|
|
||||||
|
// This is just some arbitrary point,
|
||||||
|
// the main idea is to make info left aligned here.
|
||||||
|
fullRight += infoWidth - st::normalFont->height;
|
||||||
|
if (fullRight > maxRight) {
|
||||||
|
fullRight = maxRight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isChildMedia) {
|
||||||
|
if (_parent->pointInTime(fullRight, fullBottom, point, isRound ? InfoDisplayOverBackground : InfoDisplayOverImage)) {
|
||||||
result.cursor = HistoryInDateCursorState;
|
result.cursor = HistoryInDateCursorState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
if (!bubble && _parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
if (fastShareLeft + st::historyFastShareSize > maxRight) {
|
||||||
|
fastShareLeft = (fullRight - st::historyFastShareSize - st::msgDateImgDelta);
|
||||||
|
fastShareTop -= st::msgDateImgDelta + st::msgDateImgPadding.y() + st::msgDateFont->height + st::msgDateImgPadding.y();
|
||||||
|
}
|
||||||
|
if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) {
|
||||||
|
result.link = _parent->fastShareLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2637,8 +2697,9 @@ void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, T
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!childmedia) {
|
if (!childmedia) {
|
||||||
_parent->drawInfo(p, usex + usew, _height, usex * 2 + usew, selected, InfoDisplayOverBackground);
|
auto fullRight = usex + usew;
|
||||||
|
auto fullBottom = _height;
|
||||||
|
_parent->drawInfo(p, fullRight, fullBottom, usex * 2 + usew, selected, InfoDisplayOverBackground);
|
||||||
if (via || reply) {
|
if (via || reply) {
|
||||||
int rectw = _width - usew - st::msgReplyPadding.left();
|
int rectw = _width - usew - st::msgReplyPadding.left();
|
||||||
int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom();
|
int recth = st::msgReplyPadding.top() + st::msgReplyPadding.bottom();
|
||||||
|
@ -2673,6 +2734,11 @@ void HistorySticker::draw(Painter &p, const QRect &r, TextSelection selection, T
|
||||||
reply->paint(p, _parent, rectx, recty, rectw, flags);
|
reply->paint(p, _parent, rectx, recty, rectw, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
_parent->drawFastShare(p, fastShareLeft, fastShareTop, 2 * usex + usew);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2728,9 +2794,18 @@ HistoryTextState HistorySticker::getState(QPoint point, HistoryStateRequest requ
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (_parent->getMedia() == this) {
|
if (_parent->getMedia() == this) {
|
||||||
if (_parent->pointInTime(usex + usew, _height, point, InfoDisplayOverImage)) {
|
auto fullRight = usex + usew;
|
||||||
|
auto fullBottom = _height;
|
||||||
|
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) {
|
||||||
result.cursor = HistoryInDateCursorState;
|
result.cursor = HistoryInDateCursorState;
|
||||||
}
|
}
|
||||||
|
if (_parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) {
|
||||||
|
result.link = _parent->fastShareLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pixLeft = usex + (usew - _pixw) / 2;
|
auto pixLeft = usex + (usew - _pixw) / 2;
|
||||||
|
@ -4614,8 +4689,14 @@ void HistoryLocation::draw(Painter &p, const QRect &r, TextSelection selection,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_parent->getMedia() == this) {
|
if (_parent->getMedia() == this) {
|
||||||
int32 fullRight = skipx + width, fullBottom = _height - (skipx ? st::mediaPadding.bottom() : 0);
|
auto fullRight = skipx + width;
|
||||||
|
auto fullBottom = _height - (skipx ? st::mediaPadding.bottom() : 0);
|
||||||
_parent->drawInfo(p, fullRight, fullBottom, skipx * 2 + width, selected, InfoDisplayOverImage);
|
_parent->drawInfo(p, fullRight, fullBottom, skipx * 2 + width, selected, InfoDisplayOverImage);
|
||||||
|
if (!bubble && _parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
_parent->drawFastShare(p, fastShareLeft, fastShareTop, 2 * skipx + width);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4666,12 +4747,20 @@ HistoryTextState HistoryLocation::getState(QPoint point, HistoryStateRequest req
|
||||||
}
|
}
|
||||||
if (QRect(skipx, skipy, width, height).contains(point) && _data) {
|
if (QRect(skipx, skipy, width, height).contains(point) && _data) {
|
||||||
result.link = _link;
|
result.link = _link;
|
||||||
|
}
|
||||||
|
if (_parent->getMedia() == this) {
|
||||||
auto fullRight = skipx + width;
|
auto fullRight = skipx + width;
|
||||||
auto fullBottom = _height - (skipx ? st::mediaPadding.bottom() : 0);
|
auto fullBottom = _height - (skipx ? st::mediaPadding.bottom() : 0);
|
||||||
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) {
|
if (_parent->pointInTime(fullRight, fullBottom, point, InfoDisplayOverImage)) {
|
||||||
result.cursor = HistoryInDateCursorState;
|
result.cursor = HistoryInDateCursorState;
|
||||||
}
|
}
|
||||||
|
if (!bubble && _parent->displayFastShare()) {
|
||||||
|
auto fastShareLeft = (fullRight + st::historyFastShareLeft);
|
||||||
|
auto fastShareTop = (fullBottom - st::historyFastShareBottom - st::historyFastShareSize);
|
||||||
|
if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) {
|
||||||
|
result.link = _parent->fastShareLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result.symbol += symbolAdd;
|
result.symbol += symbolAdd;
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -45,6 +45,10 @@ public:
|
||||||
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
void clickHandlerActiveChanged(const ClickHandlerPtr &p, bool active) override;
|
||||||
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
void clickHandlerPressedChanged(const ClickHandlerPtr &p, bool pressed) override;
|
||||||
|
|
||||||
|
bool allowsFastShare() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
~HistoryFileMedia();
|
~HistoryFileMedia();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -835,6 +839,9 @@ public:
|
||||||
bool customInfoLayout() const override {
|
bool customInfoLayout() const override {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool allowsFastShare() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
HistoryMedia *attach() const {
|
HistoryMedia *attach() const {
|
||||||
return _attach.get();
|
return _attach.get();
|
||||||
|
@ -946,6 +953,9 @@ public:
|
||||||
bool customInfoLayout() const override {
|
bool customInfoLayout() const override {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool allowsFastShare() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
HistoryMedia *attach() const {
|
HistoryMedia *attach() const {
|
||||||
return _attach.get();
|
return _attach.get();
|
||||||
|
|
|
@ -29,6 +29,10 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "history/history_media_types.h"
|
#include "history/history_media_types.h"
|
||||||
#include "history/history_service.h"
|
#include "history/history_service.h"
|
||||||
#include "auth_session.h"
|
#include "auth_session.h"
|
||||||
|
#include "boxes/share_box.h"
|
||||||
|
#include "boxes/confirm_box.h"
|
||||||
|
#include "ui/toast/toast.h"
|
||||||
|
#include "messenger.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
#include "styles/style_widgets.h"
|
#include "styles/style_widgets.h"
|
||||||
#include "styles/style_history.h"
|
#include "styles/style_history.h"
|
||||||
|
@ -105,8 +109,178 @@ MTPDmessage::Flags NewForwardedFlags(gsl::not_null<PeerData*> peer, int32 from,
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasMediaItems(const SelectedItemSet &items) {
|
||||||
|
for_const (auto item, items) {
|
||||||
|
if (auto media = item->getMedia()) {
|
||||||
|
switch (media->type()) {
|
||||||
|
case MediaTypePhoto:
|
||||||
|
case MediaTypeVideo:
|
||||||
|
case MediaTypeFile:
|
||||||
|
case MediaTypeMusicFile:
|
||||||
|
case MediaTypeVoiceFile: return true;
|
||||||
|
case MediaTypeGif: return media->getDocument()->isRoundVideo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasStickerItems(const SelectedItemSet &items) {
|
||||||
|
for_const (auto item, items) {
|
||||||
|
if (auto media = item->getMedia()) {
|
||||||
|
switch (media->type()) {
|
||||||
|
case MediaTypeSticker: return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasGifItems(const SelectedItemSet &items) {
|
||||||
|
for_const (auto item, items) {
|
||||||
|
if (auto media = item->getMedia()) {
|
||||||
|
switch (media->type()) {
|
||||||
|
case MediaTypeGif: return !media->getDocument()->isRoundVideo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasGameItems(const SelectedItemSet &items) {
|
||||||
|
for_const (auto item, items) {
|
||||||
|
if (auto media = item->getMedia()) {
|
||||||
|
switch (media->type()) {
|
||||||
|
case MediaTypeGame: return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasInlineItems(const SelectedItemSet &items) {
|
||||||
|
for_const (auto item, items) {
|
||||||
|
if (item->viaBot()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void FastShareMessage(gsl::not_null<HistoryItem*> item) {
|
||||||
|
struct ShareData {
|
||||||
|
ShareData(const FullMsgId &msgId) : msgId(msgId) {
|
||||||
|
}
|
||||||
|
FullMsgId msgId;
|
||||||
|
OrderedSet<mtpRequestId> requests;
|
||||||
|
};
|
||||||
|
auto data = MakeShared<ShareData>(item->fullId());
|
||||||
|
|
||||||
|
auto canCopyLink = item->hasDirectLink();
|
||||||
|
if (!canCopyLink) {
|
||||||
|
if (auto bot = item->getMessageBot()) {
|
||||||
|
if (auto media = item->getMedia()) {
|
||||||
|
canCopyLink = (media->type() == MediaTypeGame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto copyCallback = [data]() {
|
||||||
|
if (auto main = App::main()) {
|
||||||
|
if (auto item = App::histItemById(data->msgId)) {
|
||||||
|
if (item->hasDirectLink()) {
|
||||||
|
QApplication::clipboard()->setText(item->directLink());
|
||||||
|
|
||||||
|
Ui::Toast::Show(lang(lng_channel_public_link_copied));
|
||||||
|
} else if (auto bot = item->getMessageBot()) {
|
||||||
|
if (auto media = item->getMedia()) {
|
||||||
|
if (media->type() == MediaTypeGame) {
|
||||||
|
auto shortName = static_cast<HistoryGame*>(media)->game()->shortName;
|
||||||
|
|
||||||
|
QApplication::clipboard()->setText(Messenger::Instance().createInternalLinkFull(bot->username + qsl("?game=") + shortName));
|
||||||
|
|
||||||
|
Ui::Toast::Show(lang(lng_share_game_link_copied));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto submitCallback = [data](const QVector<PeerData*> &result) {
|
||||||
|
if (!data->requests.empty()) {
|
||||||
|
return; // Share clicked already.
|
||||||
|
}
|
||||||
|
auto item = App::histItemById(data->msgId);
|
||||||
|
if (!item || result.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto items = SelectedItemSet();
|
||||||
|
auto restrictedSomewhere = false;
|
||||||
|
auto restrictedEverywhere = true;
|
||||||
|
auto firstError = QString();
|
||||||
|
items.insert(item->id, item);
|
||||||
|
for_const (auto peer, result) {
|
||||||
|
auto error = GetErrorTextForForward(peer, items);
|
||||||
|
if (!error.isEmpty()) {
|
||||||
|
if (firstError.isEmpty()) {
|
||||||
|
firstError = error;
|
||||||
|
}
|
||||||
|
restrictedSomewhere = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
restrictedEverywhere = false;
|
||||||
|
}
|
||||||
|
if (restrictedEverywhere) {
|
||||||
|
Ui::show(Box<InformBox>(firstError), KeepOtherLayers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto doneCallback = [data](const MTPUpdates &updates, mtpRequestId requestId) {
|
||||||
|
if (auto main = App::main()) {
|
||||||
|
main->sentUpdatesReceived(updates);
|
||||||
|
}
|
||||||
|
data->requests.remove(requestId);
|
||||||
|
if (data->requests.empty()) {
|
||||||
|
Ui::Toast::Show(lang(lng_share_done));
|
||||||
|
Ui::hideLayer();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto sendFlags = MTPmessages_ForwardMessages::Flag::f_with_my_score;
|
||||||
|
MTPVector<MTPint> msgIds = MTP_vector<MTPint>(1, MTP_int(data->msgId.msg));
|
||||||
|
if (auto main = App::main()) {
|
||||||
|
for_const (auto peer, result) {
|
||||||
|
if (!GetErrorTextForForward(peer, items).isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
MTPVector<MTPlong> random = MTP_vector<MTPlong>(1, rand_value<MTPlong>());
|
||||||
|
auto request = MTPmessages_ForwardMessages(MTP_flags(sendFlags), item->history()->peer->input, msgIds, random, peer->input);
|
||||||
|
auto callback = doneCallback;
|
||||||
|
auto requestId = MTP::send(request, rpcDone(std::move(callback)));
|
||||||
|
data->requests.insert(requestId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto filterCallback = [](PeerData *peer) {
|
||||||
|
if (peer->canWrite()) {
|
||||||
|
if (auto channel = peer->asChannel()) {
|
||||||
|
return !channel->isBroadcast();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
auto copyLinkCallback = canCopyLink ? base::lambda<void()>(std::move(copyCallback)) : base::lambda<void()>();
|
||||||
|
Ui::show(Box<ShareBox>(std::move(copyLinkCallback), std::move(submitCallback), std::move(filterCallback)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HistoryInitMessages() {
|
||||||
|
initTextOptions();
|
||||||
|
}
|
||||||
|
|
||||||
base::lambda<void(ChannelData*, MsgId)> HistoryDependentItemCallback(const FullMsgId &msgId) {
|
base::lambda<void(ChannelData*, MsgId)> HistoryDependentItemCallback(const FullMsgId &msgId) {
|
||||||
return [dependent = msgId](ChannelData *channel, MsgId msgId) {
|
return [dependent = msgId](ChannelData *channel, MsgId msgId) {
|
||||||
if (auto item = App::histItemById(dependent)) {
|
if (auto item = App::histItemById(dependent)) {
|
||||||
|
@ -126,8 +300,25 @@ MTPDmessage::Flags NewMessageFlags(gsl::not_null<PeerData*> peer) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInitMessages() {
|
QString GetErrorTextForForward(gsl::not_null<PeerData*> peer, const SelectedItemSet &items) {
|
||||||
initTextOptions();
|
if (!peer->canWrite()) {
|
||||||
|
return lang(lng_forward_cant);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto megagroup = peer->asMegagroup()) {
|
||||||
|
if (megagroup->restrictedRights().is_send_media() && HasMediaItems(items)) {
|
||||||
|
return lang(lng_restricted_send_media);
|
||||||
|
} else if (megagroup->restrictedRights().is_send_stickers() && HasStickerItems(items)) {
|
||||||
|
return lang(lng_restricted_send_stickers);
|
||||||
|
} else if (megagroup->restrictedRights().is_send_gifs() && HasGifItems(items)) {
|
||||||
|
return lang(lng_restricted_send_gifs);
|
||||||
|
} else if (megagroup->restrictedRights().is_send_games() && HasGameItems(items)) {
|
||||||
|
return lang(lng_restricted_send_inline);
|
||||||
|
} else if (megagroup->restrictedRights().is_send_inline() && HasInlineItems(items)) {
|
||||||
|
return lang(lng_restricted_send_inline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryMessageVia::create(int32 userId) {
|
void HistoryMessageVia::create(int32 userId) {
|
||||||
|
@ -609,6 +800,17 @@ bool HistoryMessage::uploading() const {
|
||||||
return _media && _media->uploading();
|
return _media && _media->uploading();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HistoryMessage::displayFastShare() const {
|
||||||
|
if (_history->peer->isChannel()) {
|
||||||
|
return !_history->peer->isMegagroup();
|
||||||
|
} else if (auto user = _history->peer->asUser()) {
|
||||||
|
if (user->botInfo && !out()) {
|
||||||
|
return _media && _media->allowsFastShare();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryMessage::createComponents(const CreateConfig &config) {
|
void HistoryMessage::createComponents(const CreateConfig &config) {
|
||||||
uint64 mask = 0;
|
uint64 mask = 0;
|
||||||
if (config.replyTo) {
|
if (config.replyTo) {
|
||||||
|
@ -1476,6 +1678,11 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||||
if (needDrawInfo) {
|
if (needDrawInfo) {
|
||||||
HistoryMessage::drawInfo(p, g.left() + g.width(), g.top() + g.height(), 2 * g.left() + g.width(), selected, InfoDisplayDefault);
|
HistoryMessage::drawInfo(p, g.left() + g.width(), g.top() + g.height(), 2 * g.left() + g.width(), selected, InfoDisplayDefault);
|
||||||
}
|
}
|
||||||
|
if (displayFastShare()) {
|
||||||
|
auto fastShareLeft = g.left() + g.width() + st::historyFastShareLeft;
|
||||||
|
auto fastShareTop = g.top() + g.height() - st::historyFastShareBottom - st::historyFastShareSize;
|
||||||
|
drawFastShare(p, fastShareLeft, fastShareTop, width());
|
||||||
|
}
|
||||||
} else if (_media) {
|
} else if (_media) {
|
||||||
p.translate(g.topLeft());
|
p.translate(g.topLeft());
|
||||||
_media->draw(p, clip.translated(-g.topLeft()), skipTextSelection(selection), ms);
|
_media->draw(p, clip.translated(-g.topLeft()), skipTextSelection(selection), ms);
|
||||||
|
@ -1490,6 +1697,17 @@ void HistoryMessage::draw(Painter &p, QRect clip, TextSelection selection, TimeM
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HistoryMessage::drawFastShare(Painter &p, int left, int top, int outerWidth) const {
|
||||||
|
{
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(st::msgServiceBg);
|
||||||
|
|
||||||
|
PainterHighQualityEnabler hq(p);
|
||||||
|
p.drawEllipse(rtlrect(left, top, st::historyFastShareSize, st::historyFastShareSize, outerWidth));
|
||||||
|
}
|
||||||
|
st::historyFastShareIcon.paint(p, left, top, outerWidth);
|
||||||
|
}
|
||||||
|
|
||||||
void HistoryMessage::paintFromName(Painter &p, QRect &trect, bool selected) const {
|
void HistoryMessage::paintFromName(Painter &p, QRect &trect, bool selected) const {
|
||||||
if (displayFromName()) {
|
if (displayFromName()) {
|
||||||
p.setFont(st::msgNameFont);
|
p.setFont(st::msgNameFont);
|
||||||
|
@ -1791,6 +2009,13 @@ HistoryTextState HistoryMessage::getState(QPoint point, HistoryStateRequest requ
|
||||||
result.cursor = HistoryInDateCursorState;
|
result.cursor = HistoryInDateCursorState;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (displayFastShare()) {
|
||||||
|
auto fastShareLeft = g.left() + g.width() + st::historyFastShareLeft;
|
||||||
|
auto fastShareTop = g.top() + g.height() - st::historyFastShareBottom - st::historyFastShareSize;
|
||||||
|
if (QRect(fastShareLeft, fastShareTop, st::historyFastShareSize, st::historyFastShareSize).contains(point)) {
|
||||||
|
result.link = fastShareLink();
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (_media) {
|
} else if (_media) {
|
||||||
result = _media->getState(point - g.topLeft(), request);
|
result = _media->getState(point - g.topLeft(), request);
|
||||||
result.symbol += _text.length();
|
result.symbol += _text.length();
|
||||||
|
@ -1807,6 +2032,17 @@ HistoryTextState HistoryMessage::getState(QPoint point, HistoryStateRequest requ
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClickHandlerPtr HistoryMessage::fastShareLink() const {
|
||||||
|
if (!_fastShareLink) {
|
||||||
|
_fastShareLink = MakeShared<LambdaClickHandler>([id = fullId()] {
|
||||||
|
if (auto item = App::histItemById(id)) {
|
||||||
|
FastShareMessage(item->toHistoryMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return _fastShareLink;
|
||||||
|
}
|
||||||
|
|
||||||
// Forward to _media.
|
// Forward to _media.
|
||||||
void HistoryMessage::updatePressed(QPoint point) {
|
void HistoryMessage::updatePressed(QPoint point) {
|
||||||
if (!_media) return;
|
if (!_media) return;
|
||||||
|
|
|
@ -23,6 +23,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
void HistoryInitMessages();
|
void HistoryInitMessages();
|
||||||
base::lambda<void(ChannelData*, MsgId)> HistoryDependentItemCallback(const FullMsgId &msgId);
|
base::lambda<void(ChannelData*, MsgId)> HistoryDependentItemCallback(const FullMsgId &msgId);
|
||||||
MTPDmessage::Flags NewMessageFlags(gsl::not_null<PeerData*> peer);
|
MTPDmessage::Flags NewMessageFlags(gsl::not_null<PeerData*> peer);
|
||||||
|
QString GetErrorTextForForward(gsl::not_null<PeerData*> peer, const SelectedItemSet &items);
|
||||||
|
void FastShareMessage(gsl::not_null<HistoryItem*> item);
|
||||||
|
|
||||||
class HistoryMessage : public HistoryItem, private HistoryItemInstantiated<HistoryMessage> {
|
class HistoryMessage : public HistoryItem, private HistoryItemInstantiated<HistoryMessage> {
|
||||||
public:
|
public:
|
||||||
|
@ -67,11 +69,14 @@ public:
|
||||||
}
|
}
|
||||||
bool displayEditedBadge(bool hasViaBotOrInlineMarkup) const;
|
bool displayEditedBadge(bool hasViaBotOrInlineMarkup) const;
|
||||||
bool uploading() const;
|
bool uploading() const;
|
||||||
|
bool displayFastShare() const override;
|
||||||
|
|
||||||
void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const override;
|
void drawInfo(Painter &p, int32 right, int32 bottom, int32 width, bool selected, InfoDisplayType type) const override;
|
||||||
|
void drawFastShare(Painter &p, int left, int top, int outerWidth) const override;
|
||||||
void setViewsCount(int32 count) override;
|
void setViewsCount(int32 count) override;
|
||||||
void setId(MsgId newId) override;
|
void setId(MsgId newId) override;
|
||||||
void draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms) const override;
|
void draw(Painter &p, QRect clip, TextSelection selection, TimeMs ms) const override;
|
||||||
|
ClickHandlerPtr fastShareLink() const override;
|
||||||
|
|
||||||
void dependencyItemRemoved(HistoryItem *dependency) override;
|
void dependencyItemRemoved(HistoryItem *dependency) override;
|
||||||
|
|
||||||
|
@ -181,6 +186,8 @@ private:
|
||||||
QString _timeText;
|
QString _timeText;
|
||||||
int _timeWidth = 0;
|
int _timeWidth = 0;
|
||||||
|
|
||||||
|
mutable ClickHandlerPtr _fastShareLink;
|
||||||
|
|
||||||
struct CreateConfig {
|
struct CreateConfig {
|
||||||
MsgId replyTo = 0;
|
MsgId replyTo = 0;
|
||||||
UserId viaBotId = 0;
|
UserId viaBotId = 0;
|
||||||
|
|
|
@ -92,64 +92,6 @@ MTPMessagesFilter TypeToMediaFilter(MediaOverviewType &type) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool HasMediaItems(const SelectedItemSet &items) {
|
|
||||||
for_const (auto item, items) {
|
|
||||||
if (auto media = item->getMedia()) {
|
|
||||||
switch (media->type()) {
|
|
||||||
case MediaTypePhoto:
|
|
||||||
case MediaTypeVideo:
|
|
||||||
case MediaTypeFile:
|
|
||||||
case MediaTypeMusicFile:
|
|
||||||
case MediaTypeVoiceFile: return true;
|
|
||||||
case MediaTypeGif: return media->getDocument()->isRoundVideo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasStickerItems(const SelectedItemSet &items) {
|
|
||||||
for_const (auto item, items) {
|
|
||||||
if (auto media = item->getMedia()) {
|
|
||||||
switch (media->type()) {
|
|
||||||
case MediaTypeSticker: return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasGifItems(const SelectedItemSet &items) {
|
|
||||||
for_const (auto item, items) {
|
|
||||||
if (auto media = item->getMedia()) {
|
|
||||||
switch (media->type()) {
|
|
||||||
case MediaTypeGif: return !media->getDocument()->isRoundVideo();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasGameItems(const SelectedItemSet &items) {
|
|
||||||
for_const (auto item, items) {
|
|
||||||
if (auto media = item->getMedia()) {
|
|
||||||
switch (media->type()) {
|
|
||||||
case MediaTypeGame: return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasInlineItems(const SelectedItemSet &items) {
|
|
||||||
for_const (auto item, items) {
|
|
||||||
if (item->viaBot()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
|
StackItemSection::StackItemSection(std::unique_ptr<Window::SectionMemento> &&memento) : StackItem(nullptr)
|
||||||
|
@ -596,26 +538,10 @@ bool MainWidget::setForwardDraft(PeerId peerId, ForwardWhatMessages what) {
|
||||||
bool MainWidget::setForwardDraft(PeerId peerId, const SelectedItemSet &items) {
|
bool MainWidget::setForwardDraft(PeerId peerId, const SelectedItemSet &items) {
|
||||||
Expects(peerId != 0);
|
Expects(peerId != 0);
|
||||||
auto peer = App::peer(peerId);
|
auto peer = App::peer(peerId);
|
||||||
auto finishWithError = [this](const QString &error) {
|
auto error = GetErrorTextForForward(peer, items);
|
||||||
|
if (!error.isEmpty()) {
|
||||||
Ui::show(Box<InformBox>(error));
|
Ui::show(Box<InformBox>(error));
|
||||||
return false;
|
return false;
|
||||||
};
|
|
||||||
if (!peer->canWrite()) {
|
|
||||||
return finishWithError(lang(lng_forward_cant));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto megagroup = peer->asMegagroup()) {
|
|
||||||
if (megagroup->restrictedRights().is_send_media() && HasMediaItems(items)) {
|
|
||||||
return finishWithError(lang(lng_restricted_send_media));
|
|
||||||
} else if (megagroup->restrictedRights().is_send_stickers() && HasStickerItems(items)) {
|
|
||||||
return finishWithError(lang(lng_restricted_send_stickers));
|
|
||||||
} else if (megagroup->restrictedRights().is_send_gifs() && HasGifItems(items)) {
|
|
||||||
return finishWithError(lang(lng_restricted_send_gifs));
|
|
||||||
} else if (megagroup->restrictedRights().is_send_games() && HasGameItems(items)) {
|
|
||||||
return finishWithError(lang(lng_restricted_send_inline));
|
|
||||||
} else if (megagroup->restrictedRights().is_send_inline() && HasInlineItems(items)) {
|
|
||||||
return finishWithError(lang(lng_restricted_send_inline));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
App::history(peer)->setForwardDraft(items);
|
App::history(peer)->setForwardDraft(items);
|
||||||
|
|
|
@ -35,7 +35,17 @@ NeverFreedPointer<QMap<QObject*, Manager*>> _managers;
|
||||||
|
|
||||||
Manager::Manager(QWidget *parent) : QObject(parent) {
|
Manager::Manager(QWidget *parent) : QObject(parent) {
|
||||||
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideTimeout()));
|
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideTimeout()));
|
||||||
connect(parent, SIGNAL(resized()), this, SLOT(onParentResized()));
|
}
|
||||||
|
|
||||||
|
bool Manager::eventFilter(QObject *o, QEvent *e) {
|
||||||
|
if (e->type() == QEvent::Resize) {
|
||||||
|
for (auto i = _toastByWidget.cbegin(), e = _toastByWidget.cend(); i != e; ++i) {
|
||||||
|
if (i.key()->parentWidget() == o) {
|
||||||
|
i.key()->onParentResized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(o, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
Manager *Manager::instance(QWidget *parent) {
|
Manager *Manager::instance(QWidget *parent) {
|
||||||
|
@ -58,7 +68,23 @@ void Manager::addToast(std::unique_ptr<Instance> &&toast) {
|
||||||
|
|
||||||
_toastByWidget.insert(widget, t);
|
_toastByWidget.insert(widget, t);
|
||||||
connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(onToastWidgetDestroyed(QObject*)));
|
connect(widget, SIGNAL(destroyed(QObject*)), this, SLOT(onToastWidgetDestroyed(QObject*)));
|
||||||
connect(widget->parentWidget(), SIGNAL(resized(QSize)), this, SLOT(onToastWidgetParentResized()), Qt::UniqueConnection);
|
if (auto parent = widget->parentWidget()) {
|
||||||
|
auto found = false;
|
||||||
|
for (auto i = _toastParents.begin(); i != _toastParents.cend();) {
|
||||||
|
if (*i == parent) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
} else if (!*i) {
|
||||||
|
i = _toastParents.erase(i);
|
||||||
|
} else {
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
_toastParents.insert(parent);
|
||||||
|
parent->installEventFilter(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto oldHideNearestMs = _toastByHideTime.isEmpty() ? 0LL : _toastByHideTime.firstKey();
|
auto oldHideNearestMs = _toastByHideTime.isEmpty() ? 0LL : _toastByHideTime.firstKey();
|
||||||
_toastByHideTime.insert(t->_hideAtMs, t);
|
_toastByHideTime.insert(t->_hideAtMs, t);
|
||||||
|
@ -96,17 +122,6 @@ void Manager::onToastWidgetDestroyed(QObject *widget) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::onToastWidgetParentResized() {
|
|
||||||
auto resizedWidget = QObject::sender();
|
|
||||||
if (!resizedWidget) return;
|
|
||||||
|
|
||||||
for (auto i = _toastByWidget.cbegin(), e = _toastByWidget.cend(); i != e; ++i) {
|
|
||||||
if (i.key()->parentWidget() == resizedWidget) {
|
|
||||||
i.key()->onParentResized();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Manager::startNextHideTimer() {
|
void Manager::startNextHideTimer() {
|
||||||
if (_toastByHideTime.isEmpty()) return;
|
if (_toastByHideTime.isEmpty()) return;
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,12 @@ public:
|
||||||
|
|
||||||
~Manager();
|
~Manager();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *o, QEvent *e);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onHideTimeout();
|
void onHideTimeout();
|
||||||
void onToastWidgetDestroyed(QObject *widget);
|
void onToastWidgetDestroyed(QObject *widget);
|
||||||
void onToastWidgetParentResized();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Manager(QWidget *parent);
|
Manager(QWidget *parent);
|
||||||
|
@ -56,6 +58,7 @@ private:
|
||||||
QMultiMap<TimeMs, Instance*> _toastByHideTime;
|
QMultiMap<TimeMs, Instance*> _toastByHideTime;
|
||||||
QMap<Widget*, Instance*> _toastByWidget;
|
QMap<Widget*, Instance*> _toastByWidget;
|
||||||
QList<Instance*> _toasts;
|
QList<Instance*> _toasts;
|
||||||
|
OrderedSet<QPointer<QWidget>> _toastParents;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue