Show PSA tooltip icon and tooltip.

This commit is contained in:
John Preston 2020-04-29 16:36:51 +04:00
parent 44e71dfa03
commit 8a4c7e3994
15 changed files with 156 additions and 31 deletions

View File

@ -602,6 +602,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_proxy_sponsor_warning" = "This proxy may display a sponsored channel in your chat list. This doesn't reveal any of your Telegram traffic."; "lng_proxy_sponsor_warning" = "This proxy may display a sponsored channel in your chat list. This doesn't reveal any of your Telegram traffic.";
"lng_badge_psa_default" = "PSA"; "lng_badge_psa_default" = "PSA";
"lng_about_psa_default" = "This message provides you with a public service announcement. To remove it from your chats list, right click it and select **Hide**."; "lng_about_psa_default" = "This message provides you with a public service announcement. To remove it from your chats list, right click it and select **Hide**.";
"lng_tooltip_psa_default" = "This message provides you with a public service announcement.";
"lng_settings_blocked_users" = "Blocked users"; "lng_settings_blocked_users" = "Blocked users";
"lng_settings_no_blocked_users" = "None"; "lng_settings_no_blocked_users" = "None";

View File

@ -582,6 +582,9 @@ void InnerWidget::elementShowPollResults(
FullMsgId context) { FullMsgId context) {
} }
void InnerWidget::elementShowTooltip(const TextWithEntities &text) {
}
void InnerWidget::saveState(not_null<SectionMemento*> memento) { void InnerWidget::saveState(not_null<SectionMemento*> memento) {
memento->setFilter(std::move(_filter)); memento->setFilter(std::move(_filter));
memento->setAdmins(std::move(_admins)); memento->setAdmins(std::move(_admins));

View File

@ -104,6 +104,7 @@ public:
void elementShowPollResults( void elementShowPollResults(
not_null<PollData*> poll, not_null<PollData*> poll,
FullMsgId context) override; FullMsgId context) override;
void elementShowTooltip(const TextWithEntities &text) override;
~InnerWidget(); ~InnerWidget();

View File

@ -394,6 +394,15 @@ historyBubbleTailOutRightSelected: icon {{ "bubble_tail-flip_horizontal", msgOut
historyPeerUserpicFont: semiboldFont; historyPeerUserpicFont: semiboldFont;
historyPsaIconIn: icon {{ "message_psa_tooltip", msgFileThumbLinkInFg }};
historyPsaIconInSelected: icon {{ "message_psa_tooltip", msgFileThumbLinkInFgSelected }};
historyPsaIconOut: icon {{ "message_psa_tooltip", msgFileThumbLinkOutFg }};
historyPsaIconOutSelected: icon {{ "message_psa_tooltip", msgFileThumbLinkOutFgSelected }};
historyPsaIconSkip1: 23px;
historyPsaIconSkip2: 23px;
historyPsaIconPosition1: point(-5px, 0px);
historyPsaIconPosition2: point(-5px, 0px);
historyStatusFg: windowSubTextFg; historyStatusFg: windowSubTextFg;
historyStatusFgActive: windowActiveTextFg; historyStatusFgActive: windowActiveTextFg;
historyStatusFgTyping: historyStatusFgActive; historyStatusFgTyping: historyStatusFgActive;

View File

@ -8,7 +8,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/history_inner_widget.h" #include "history/history_inner_widget.h"
#include <rpl/merge.h> #include <rpl/merge.h>
#include "styles/style_history.h"
#include "core/file_utilities.h" #include "core/file_utilities.h"
#include "core/crash_reports.h" #include "core/crash_reports.h"
#include "history/history.h" #include "history/history.h"
@ -57,6 +56,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_histories.h" #include "data/data_histories.h"
#include "facades.h" #include "facades.h"
#include "app.h" #include "app.h"
#include "styles/style_history.h"
#include "styles/style_window.h" // st::windowMinWidth
#include <QtGui/QClipboard> #include <QtGui/QClipboard>
#include <QtWidgets/QApplication> #include <QtWidgets/QApplication>
@ -87,6 +88,13 @@ int BinarySearchBlocksOrItems(const T &list, int edge) {
return start; return start;
} }
[[nodiscard]] crl::time CountToastDuration(const TextWithEntities &text) {
return std::clamp(
crl::time(1000) * text.text.size() / 14,
crl::time(1000) * 5,
crl::time(1000) * 8);
}
} // namespace } // namespace
// flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html
@ -2481,6 +2489,16 @@ void HistoryInner::elementShowPollResults(
_controller->showPollResults(poll, context); _controller->showPollResults(poll, context);
} }
void HistoryInner::elementShowTooltip(const TextWithEntities &text) {
auto config = Ui::Toast::Config();
config.multiline = config.dark = true;
config.minWidth = st::msgMinWidth;
config.maxWidth = st::windowMinWidth;
config.text = text;
config.durationMs = CountToastDuration(config.text);
Ui::Toast::Show(_widget, config);
}
auto HistoryInner::getSelectionState() const auto HistoryInner::getSelectionState() const
-> HistoryView::TopBarWidget::SelectedState { -> HistoryView::TopBarWidget::SelectedState {
auto result = HistoryView::TopBarWidget::SelectedState {}; auto result = HistoryView::TopBarWidget::SelectedState {};
@ -3348,6 +3366,11 @@ not_null<HistoryView::ElementDelegate*> HistoryInner::ElementDelegate() {
Instance->elementShowPollResults(poll, context); Instance->elementShowPollResults(poll, context);
} }
} }
void elementShowTooltip(const TextWithEntities &text) override {
if (Instance) {
Instance->elementShowTooltip(text);
}
}
}; };

View File

@ -85,6 +85,7 @@ public:
void elementShowPollResults( void elementShowPollResults(
not_null<PollData*> poll, not_null<PollData*> poll,
FullMsgId context); FullMsgId context);
void elementShowTooltip(const TextWithEntities &text);
void updateBotInfo(bool recount = true); void updateBotInfo(bool recount = true);

View File

@ -78,6 +78,7 @@ struct HistoryMessageForwarded : public RuntimeComponent<HistoryMessageForwarded
std::unique_ptr<HiddenSenderInfo> hiddenSenderInfo; std::unique_ptr<HiddenSenderInfo> hiddenSenderInfo;
QString originalAuthor; QString originalAuthor;
QString psaType; QString psaType;
mutable ClickHandlerPtr psaTooltipLink;
MsgId originalId = 0; MsgId originalId = 0;
mutable Ui::Text::String text = { 1 }; mutable Ui::Text::String text = { 1 };

View File

@ -4202,6 +4202,7 @@ void HistoryWidget::moveFieldControls() {
} }
if (_aboutTopPromotion) { if (_aboutTopPromotion) {
_aboutTopPromotion->resizeToWidth(width());
_aboutTopPromotion->moveToLeft( _aboutTopPromotion->moveToLeft(
0, 0,
fullWidthButtonRect.y() - _aboutTopPromotion->height()); fullWidthButtonRect.y() - _aboutTopPromotion->height());
@ -5224,7 +5225,6 @@ void HistoryWidget::updateHistoryGeometry(
} }
} }
if (_aboutTopPromotion) { if (_aboutTopPromotion) {
_aboutTopPromotion->resizeToWidth(width());
newScrollHeight -= _aboutTopPromotion->height(); newScrollHeight -= _aboutTopPromotion->height();
} }
if (newScrollHeight <= 0) { if (newScrollHeight <= 0) {

View File

@ -99,6 +99,10 @@ void SimpleElementDelegate::elementShowPollResults(
FullMsgId context) { FullMsgId context) {
} }
void SimpleElementDelegate::elementShowTooltip(
const TextWithEntities &text) {
}
TextSelection UnshiftItemSelection( TextSelection UnshiftItemSelection(
TextSelection selection, TextSelection selection,
uint16 byLength) { uint16 byLength) {

View File

@ -54,6 +54,7 @@ public:
virtual void elementShowPollResults( virtual void elementShowPollResults(
not_null<PollData*> poll, not_null<PollData*> poll,
FullMsgId context) = 0; FullMsgId context) = 0;
virtual void elementShowTooltip(const TextWithEntities &text) = 0;
}; };
@ -77,6 +78,7 @@ public:
void elementShowPollResults( void elementShowPollResults(
not_null<PollData*> poll, not_null<PollData*> poll,
FullMsgId context) override; FullMsgId context) override;
void elementShowTooltip(const TextWithEntities &text) override;
}; };

View File

@ -1158,6 +1158,9 @@ void ListWidget::elementShowPollResults(
FullMsgId context) { FullMsgId context) {
} }
void ListWidget::elementShowTooltip(const TextWithEntities &text) {
}
void ListWidget::saveState(not_null<ListMemento*> memento) { void ListWidget::saveState(not_null<ListMemento*> memento) {
memento->setAroundPosition(_aroundPosition); memento->setAroundPosition(_aroundPosition);
auto state = countScrollState(); auto state = countScrollState();

View File

@ -200,6 +200,7 @@ public:
void elementShowPollResults( void elementShowPollResults(
not_null<PollData*> poll, not_null<PollData*> poll,
FullMsgId context) override; FullMsgId context) override;
void elementShowTooltip(const TextWithEntities &text) override;
~ListWidget(); ~ListWidget();

View File

@ -14,6 +14,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/media/history_view_web_page.h" #include "history/view/media/history_view_web_page.h"
#include "history/history.h" #include "history/history.h"
#include "ui/toast/toast.h" #include "ui/toast/toast.h"
#include "ui/text/text_utilities.h"
#include "ui/text/text_entity.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_user.h" #include "data/data_user.h"
#include "data/data_channel.h" #include "data/data_channel.h"
@ -32,6 +34,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView { namespace HistoryView {
namespace { namespace {
const auto kPsaTooltipPrefix = "cloud_lng_tooltip_psa_";
class KeyboardStyle : public ReplyKeyboard::Style { class KeyboardStyle : public ReplyKeyboard::Style {
public: public:
using ReplyKeyboard::Style::Style; using ReplyKeyboard::Style::Style;
@ -311,7 +315,10 @@ QSize Message::performCountOptimalSize() {
accumulate_max(maxWidth, st::msgPadding.left() + via->maxWidth + st::msgPadding.right()); accumulate_max(maxWidth, st::msgPadding.left() + via->maxWidth + st::msgPadding.right());
} }
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
auto namew = st::msgPadding.left() + forwarded->text.maxWidth() + st::msgPadding.right(); const auto skip1 = forwarded->psaType.isEmpty()
? 0
: st::historyPsaIconSkip1;
auto namew = st::msgPadding.left() + forwarded->text.maxWidth() + skip1 + st::msgPadding.right();
if (via) { if (via) {
namew += st::msgServiceFont->spacew + via->maxWidth; namew += st::msgServiceFont->spacew + via->maxWidth;
} }
@ -608,12 +615,21 @@ void Message::paintForwardedInfo(Painter &p, QRect &trect, bool selected) const
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
const auto item = message(); const auto item = message();
const auto outbg = hasOutLayout(); const auto outbg = hasOutLayout();
auto forwarded = item->Get<HistoryMessageForwarded>(); const auto forwarded = item->Get<HistoryMessageForwarded>();
const auto &serviceFont = st::msgServiceFont; const auto &serviceFont = st::msgServiceFont;
const auto &serviceName = st::msgServiceNameFont; const auto &serviceName = st::msgServiceNameFont;
const auto breakEverywhere = (forwarded->text.countHeight(trect.width()) > 2 * serviceFont->height); const auto skip1 = forwarded->psaType.isEmpty()
? 0
: st::historyPsaIconSkip1;
const auto skip2 = forwarded->psaType.isEmpty()
? 0
: st::historyPsaIconSkip2;
const auto fits = (forwarded->text.maxWidth() + skip1 <= trect.width());
const auto skip = fits ? skip1 : skip2;
const auto useWidth = trect.width() - skip;
const auto countedHeight = forwarded->text.countHeight(useWidth);
const auto breakEverywhere = (countedHeight > 2 * serviceFont->height);
p.setPen(!forwarded->psaType.isEmpty() p.setPen(!forwarded->psaType.isEmpty()
? st::boxTextFgGood ? st::boxTextFgGood
: selected : selected
@ -633,10 +649,26 @@ void Message::paintForwardedInfo(Painter &p, QRect &trect, bool selected) const
: (outbg : (outbg
? st::outFwdTextPalette ? st::outFwdTextPalette
: st::inFwdTextPalette)); : st::inFwdTextPalette));
forwarded->text.drawElided(p, trect.x(), trect.y(), trect.width(), 2, style::al_left, 0, -1, 0, breakEverywhere); forwarded->text.drawElided(p, trect.x(), trect.y(), useWidth, 2, style::al_left, 0, -1, 0, breakEverywhere);
p.setTextPalette(selected ? (outbg ? st::outTextPaletteSelected : st::inTextPaletteSelected) : (outbg ? st::outTextPalette : st::inTextPalette)); p.setTextPalette(selected ? (outbg ? st::outTextPaletteSelected : st::inTextPaletteSelected) : (outbg ? st::outTextPalette : st::inTextPalette));
trect.setY(trect.y() + (((forwarded->text.maxWidth() > trect.width()) ? 2 : 1) * serviceFont->height)); if (!forwarded->psaType.isEmpty()) {
const auto &icon = selected
? (outbg
? st::historyPsaIconOutSelected
: st::historyPsaIconInSelected)
: (outbg ? st::historyPsaIconOut : st::historyPsaIconIn);
const auto position = fits
? st::historyPsaIconPosition1
: st::historyPsaIconPosition2;
icon.paint(
p,
trect.x() + trect.width() - position.x() - icon.width(),
trect.y() + position.y(),
trect.width());
}
trect.setY(trect.y() + ((fits ? 1 : 2) * serviceFont->height));
} }
} }
@ -959,17 +991,41 @@ bool Message::getStateForwardedInfo(
StateRequest request) const { StateRequest request) const {
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
const auto item = message(); const auto item = message();
auto forwarded = item->Get<HistoryMessageForwarded>(); const auto forwarded = item->Get<HistoryMessageForwarded>();
auto fwdheight = ((forwarded->text.maxWidth() > trect.width()) ? 2 : 1) * st::semiboldFont->height; const auto skip1 = forwarded->psaType.isEmpty()
? 0
: st::historyPsaIconSkip1;
const auto skip2 = forwarded->psaType.isEmpty()
? 0
: st::historyPsaIconSkip2;
const auto fits = (forwarded->text.maxWidth() <= (trect.width() - skip1));
const auto fwdheight = (fits ? 1 : 2) * st::semiboldFont->height;
if (point.y() >= trect.top() && point.y() < trect.top() + fwdheight) { if (point.y() >= trect.top() && point.y() < trect.top() + fwdheight) {
auto breakEverywhere = (forwarded->text.countHeight(trect.width()) > 2 * st::semiboldFont->height); if (skip1) {
const auto &icon = st::historyPsaIconIn;
const auto position = fits
? st::historyPsaIconPosition1
: st::historyPsaIconPosition2;
const auto iconRect = QRect(
trect.x() + trect.width() - position.x() - icon.width(),
trect.y() + position.y(),
icon.width(),
icon.height());
if (iconRect.contains(point)) {
ensurePsaTooltipLink(forwarded);
outResult->link = forwarded->psaTooltipLink;
return true;
}
}
const auto useWidth = trect.width() - (fits ? skip1 : skip2);
const auto breakEverywhere = (forwarded->text.countHeight(useWidth) > 2 * st::semiboldFont->height);
auto textRequest = request.forText(); auto textRequest = request.forText();
if (breakEverywhere) { if (breakEverywhere) {
textRequest.flags |= Ui::Text::StateRequest::Flag::BreakEverywhere; textRequest.flags |= Ui::Text::StateRequest::Flag::BreakEverywhere;
} }
*outResult = TextState(item, forwarded->text.getState( *outResult = TextState(item, forwarded->text.getState(
point - trect.topLeft(), point - trect.topLeft(),
trect.width(), useWidth,
textRequest)); textRequest));
outResult->symbol = 0; outResult->symbol = 0;
outResult->afterSymbol = false; outResult->afterSymbol = false;
@ -985,6 +1041,29 @@ bool Message::getStateForwardedInfo(
return false; return false;
} }
void Message::ensurePsaTooltipLink(
not_null<const HistoryMessageForwarded*> forwarded) const {
if (forwarded->psaTooltipLink) {
return;
}
const auto type = forwarded->psaType;
const auto handler = [=] {
const auto custom = type.isEmpty()
? QString()
: Lang::Current().getNonDefaultValue(
kPsaTooltipPrefix + type.toUtf8());
auto text = Ui::Text::RichLangValue(
(custom.isEmpty()
? tr::lng_tooltip_psa_default(tr::now)
: custom));
TextUtilities::ParseEntities(text, 0);
delegate()->elementShowTooltip(text);
};
forwarded->psaTooltipLink
= std::make_shared<LambdaClickHandler>(
crl::guard(this, handler));
}
bool Message::getStateReplyInfo( bool Message::getStateReplyInfo(
QPoint point, QPoint point,
QRect &trect, QRect &trect,
@ -1780,8 +1859,14 @@ int Message::resizeContentGetHeight(int newWidth) {
} }
if (displayForwardedFrom()) { if (displayForwardedFrom()) {
auto forwarded = item->Get<HistoryMessageForwarded>(); const auto forwarded = item->Get<HistoryMessageForwarded>();
auto fwdheight = ((forwarded->text.maxWidth() > (contentWidth - st::msgPadding.left() - st::msgPadding.right())) ? 2 : 1) * st::semiboldFont->height; const auto skip1 = forwarded->psaType.isEmpty()
? 0
: st::historyPsaIconSkip1;
const auto skip2 = forwarded->psaType.isEmpty()
? 0
: st::historyPsaIconSkip2;
const auto fwdheight = ((forwarded->text.maxWidth() > (contentWidth - st::msgPadding.left() - st::msgPadding.right() - skip1)) ? 2 : 1) * st::semiboldFont->height;
newHeight += fwdheight; newHeight += fwdheight;
} }

View File

@ -8,9 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once #pragma once
#include "history/view/history_view_element.h" #include "history/view/history_view_element.h"
#include "base/weak_ptr.h"
class HistoryMessage; class HistoryMessage;
struct HistoryMessageEdited; struct HistoryMessageEdited;
struct HistoryMessageForwarded;
namespace HistoryView { namespace HistoryView {
@ -28,7 +30,7 @@ struct LogEntryOriginal
}; };
class Message : public Element { class Message : public Element, public base::has_weak_ptr {
public: public:
Message( Message(
not_null<ElementDelegate*> delegate, not_null<ElementDelegate*> delegate,
@ -152,6 +154,9 @@ private:
WebPage *logEntryOriginal() const; WebPage *logEntryOriginal() const;
void ensurePsaTooltipLink(
not_null<const HistoryMessageForwarded*> forwarded) const;
mutable ClickHandlerPtr _rightActionLink; mutable ClickHandlerPtr _rightActionLink;
mutable ClickHandlerPtr _fastReplyLink; mutable ClickHandlerPtr _fastReplyLink;

View File

@ -122,13 +122,6 @@ void CountNicePercent(
} }
} }
[[nodiscard]] crl::time CountToastDuration(const TextWithEntities &text) {
return std::clamp(
crl::time(1000) * text.text.size() / 14,
crl::time(1000) * 5,
crl::time(1000) * 8);
}
} // namespace } // namespace
struct Poll::AnswerAnimation { struct Poll::AnswerAnimation {
@ -443,16 +436,9 @@ void Poll::checkQuizAnswered() {
} }
void Poll::showSolution() const { void Poll::showSolution() const {
if (_poll->solution.text.isEmpty()) { if (!_poll->solution.text.isEmpty()) {
return; _parent->delegate()->elementShowTooltip(_poll->solution);
} }
auto config = Ui::Toast::Config();
config.multiline = config.dark = true;
config.minWidth = st::msgMinWidth;
config.maxWidth = st::windowMinWidth;
config.text = _poll->solution;
config.durationMs = CountToastDuration(config.text);
Ui::Toast::Show(config);
} }
void Poll::updateRecentVoters() { void Poll::updateRecentVoters() {