diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt index 9a70915d57..155785981b 100644 --- a/Telegram/Resources/style.txt +++ b/Telegram/Resources/style.txt @@ -1307,6 +1307,13 @@ btnAttachEmoji: iconedButton(btnAttachDocument) { width: 33px; } +emojiCircle: size(19px, 19px); +emojiCirclePeriod: 1500; +emojiCircleDuration: 500; +emojiCircleTop: 13px; +emojiCircleLine: 2px; +emojiCircleFg: #b9b9b9; +emojiCirclePart: 3.5; btnBotKbShow: iconedButton(btnAttachEmoji) { icon: sprite(375px, 74px, 21px, 21px); iconPos: point(6px, 12px); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 1e79a4ce8b..421e2b443f 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -548,7 +548,7 @@ void Application::stopUpdate() { void Application::startUpdateCheck(bool forceWait) { updateCheckTimer.stop(); if (updateRequestId || updateThread || updateReply || !cAutoUpdate()) return; - + int32 constDelay = cBetaVersion() ? 600 : UpdateDelayConstPart, randDelay = cBetaVersion() ? 300 : UpdateDelayRandPart; int32 updateInSecs = cLastUpdateCheck() + constDelay + int32(MTP::nonce() % randDelay) - unixtime(); bool sendRequest = (updateInSecs <= 0 || updateInSecs > (constDelay + randDelay)); @@ -684,7 +684,7 @@ void Application::socketError(QLocalSocket::LocalSocketError e) { socket.close(); psCheckLocalSocket(serverName); - + if (!server.listen(serverName)) { DEBUG_LOG(("Application Error: failed to start listening to %1 server, error %2").arg(serverName).arg(int(server.serverError()))); return App::quit(); @@ -769,7 +769,7 @@ void Application::startApp() { } QNetworkProxyFactory::setUseSystemConfiguration(true); - + if (state != Local::ReadMapPassNeeded) { checkMapVersion(); } @@ -912,7 +912,7 @@ Application::~Application() { cSetChatDogImage(0); style::stopManager(); - + delete _translator; } diff --git a/Telegram/SourceFiles/art/sprite_200x.png b/Telegram/SourceFiles/art/sprite_200x.png index 50dfed9c3e..16b454f057 100644 Binary files a/Telegram/SourceFiles/art/sprite_200x.png and b/Telegram/SourceFiles/art/sprite_200x.png differ diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp index 458504bf7d..d483017098 100644 --- a/Telegram/SourceFiles/dropdown.cpp +++ b/Telegram/SourceFiles/dropdown.cpp @@ -3560,10 +3560,13 @@ void EmojiPan::inlineBotChanged() { } _inlineCache.clear(); s_inner.inlineBotChanged(); + + Notify::inlineBotRequesting(false); } void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) { _inlineRequestId = 0; + Notify::inlineBotRequesting(false); InlineCache::iterator it = _inlineCache.find(_inlineQuery); @@ -3659,6 +3662,8 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) { bool EmojiPan::inlineResultsFail(const RPCError &error) { if (mtpIsFlood(error)) return false; + + Notify::inlineBotRequesting(false); _inlineRequestId = 0; return true; } @@ -3674,6 +3679,7 @@ void EmojiPan::queryInlineBot(UserData *bot, QString query) { if (_inlineRequestId) { MTP::cancel(_inlineRequestId); _inlineRequestId = 0; + Notify::inlineBotRequesting(false); } if (_inlineCache.contains(query)) { _inlineRequestTimer.stop(); @@ -3696,6 +3702,7 @@ void EmojiPan::onInlineRequest() { nextOffset = i.value()->nextOffset; if (nextOffset.isEmpty()) return; } + Notify::inlineBotRequesting(true); _inlineRequestId = MTP::send(MTPmessages_GetInlineBotResults(_inlineBot->inputUser, MTP_string(_inlineQuery), MTP_string(nextOffset)), rpcDone(&EmojiPan::inlineResultsDone), rpcFail(&EmojiPan::inlineResultsFail)); } diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 0fb84b15be..2c5db2dfda 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -149,6 +149,10 @@ namespace Notify { if (MainWidget *m = App::main()) m->notify_botCommandsChanged(user); } + void inlineBotRequesting(bool requesting) { + if (MainWidget *m = App::main()) m->notify_inlineBotRequesting(requesting); + } + void migrateUpdated(PeerData *peer) { if (MainWidget *m = App::main()) m->notify_migrateUpdated(peer); } diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index 21db659b63..ed7ee718cf 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -80,6 +80,8 @@ namespace Notify { void userIsContactChanged(UserData *user, bool fromThisApp = false); void botCommandsChanged(UserData *user); + void inlineBotRequesting(bool requesting); + void migrateUpdated(PeerData *peer); void clipStopperHidden(ClipStopperType type); diff --git a/Telegram/SourceFiles/gui/flatbutton.cpp b/Telegram/SourceFiles/gui/flatbutton.cpp index e02c47fa2e..e41f13b355 100644 --- a/Telegram/SourceFiles/gui/flatbutton.cpp +++ b/Telegram/SourceFiles/gui/flatbutton.cpp @@ -289,6 +289,59 @@ void MaskedButton::paintEvent(QPaintEvent *e) { } } +EmojiButton::EmojiButton(QWidget *parent, const style::iconedButton &st) : IconedButton(parent, st) +, _loading(false) +, _a_loading(animation(this, &EmojiButton::step_loading)) { +} + +void EmojiButton::paintEvent(QPaintEvent *e) { + QPainter p(this); + + uint64 ms = getms(); + float64 loading = a_loading.current(ms, _loading ? 1 : 0); + p.setOpacity(_opacity * (1 - loading)); + + p.fillRect(e->rect(), a_bg.current()); + + p.setOpacity(a_opacity.current() * _opacity * (1 - loading)); + + const QRect &i((_state & StateDown) ? _st.downIcon : _st.icon); + if (i.width()) { + const QPoint &t((_state & StateDown) ? _st.downIconPos : _st.iconPos); + p.drawPixmap(t, App::sprite(), i); + } + + QRect inner(QPoint((width() - st::emojiCircle.width()) / 2, st::emojiCircleTop), st::emojiCircle); + int32 full = 5760; + int32 start = qRound(full * float64(ms % uint64(st::emojiCirclePeriod)) / st::emojiCirclePeriod), part = qRound(full / st::emojiCirclePart); + + p.setBrush(Qt::NoBrush); + p.setRenderHint(QPainter::HighQualityAntialiasing); + + p.setPen(QPen(st::emojiCircleFg->c, st::emojiCircleLine)); + p.setOpacity(a_opacity.current() * _opacity); + p.drawEllipse(inner); + + p.setPen(QPen(st::white->c, st::emojiCircleLine)); + p.setOpacity(loading); + p.drawArc(inner, (full - start) % full, part); + + p.setRenderHint(QPainter::HighQualityAntialiasing, false); +} + +void EmojiButton::setLoading(bool loading) { + if (_loading != loading) { + EnsureAnimation(a_loading, _loading ? 1. : 0., func(this, &EmojiButton::update)); + a_loading.start(loading ? 1. : 0., st::emojiCircleDuration); + _loading = loading; + if (_loading) { + _a_loading.start(); + } else { + _a_loading.stop(); + } + } +} + BoxButton::BoxButton(QWidget *parent, const QString &text, const style::BoxButton &st) : Button(parent) , _text(text.toUpper()) , _fullText(text.toUpper()) diff --git a/Telegram/SourceFiles/gui/flatbutton.h b/Telegram/SourceFiles/gui/flatbutton.h index 9f542949e6..f07b0c4a25 100644 --- a/Telegram/SourceFiles/gui/flatbutton.h +++ b/Telegram/SourceFiles/gui/flatbutton.h @@ -106,7 +106,7 @@ public: void setText(const QString &text); QString getText() const; - + public slots: void onStateChange(int oldState, ButtonStateChangeSource source); @@ -136,6 +136,28 @@ public: }; +class EmojiButton : public IconedButton { + Q_OBJECT + +public: + EmojiButton(QWidget *parent, const style::iconedButton &st); + + void paintEvent(QPaintEvent *e); + void setLoading(bool loading); + +private: + bool _loading; + FloatAnimation a_loading; + Animation _a_loading; + + void step_loading(uint64 ms, bool timer) { + if (timer) { + update(); + } + } + +}; + class BoxButton : public Button { Q_OBJECT diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 18da2d243d..e114842162 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -3028,6 +3028,10 @@ void HistoryWidget::notify_botCommandsChanged(UserData *user) { } } +void HistoryWidget::notify_inlineBotRequesting(bool requesting) { + _attachEmoji.setLoading(requesting); +} + void HistoryWidget::notify_userIsBotChanged(UserData *user) { if (_peer && _peer == user) { _list->notifyIsBotChanged(); @@ -4971,6 +4975,7 @@ bool HistoryWidget::hasBroadcastToggle() const { } void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) { + Notify::inlineBotRequesting(false); _inlineBotUsername = QString(); if (result.type() == mtpc_contacts_resolvedPeer) { const MTPDcontacts_resolvedPeer &d(result.c_contacts_resolvedPeer()); @@ -4982,6 +4987,8 @@ void HistoryWidget::inlineBotResolveDone(const MTPcontacts_ResolvedPeer &result) bool HistoryWidget::inlineBotResolveFail(QString name, const RPCError &error) { if (mtpIsFlood(error)) return false; + + Notify::inlineBotRequesting(false); if (name == _inlineBotUsername) { _inlineBot = 0; onCheckMentionDropdown(); @@ -5335,10 +5342,12 @@ void HistoryWidget::onCheckMentionDropdown() { _field.getMentionHashtagBotCommandStart(start, _inlineBot, _inlineBotUsername); if (inlineBotUsername != _inlineBotUsername) { if (_inlineBotResolveRequestId) { + Notify::inlineBotRequesting(false); MTP::cancel(_inlineBotResolveRequestId); _inlineBotResolveRequestId = 0; } if (_inlineBot == InlineBotLookingUpData) { + Notify::inlineBotRequesting(true); _inlineBotResolveRequestId = MTP::send(MTPcontacts_ResolveUsername(MTP_string(_inlineBotUsername)), rpcDone(&HistoryWidget::inlineBotResolveDone), rpcFail(&HistoryWidget::inlineBotResolveFail, _inlineBotUsername)); return; } diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h index f3f7acb31c..a7a3e6d02d 100644 --- a/Telegram/SourceFiles/historywidget.h +++ b/Telegram/SourceFiles/historywidget.h @@ -568,6 +568,7 @@ public: void notify_historyItemLayoutChanged(const HistoryItem *item); void notify_automaticLoadSettingsChangedGif(); void notify_botCommandsChanged(UserData *user); + void notify_inlineBotRequesting(bool requesting); void notify_userIsBotChanged(UserData *user); void notify_migrateUpdated(PeerData *peer); void notify_clipStopperHidden(ClipStopperType type); @@ -784,7 +785,9 @@ private: FlatButton _send, _unblock, _botStart, _joinChannel, _muteUnmute; mtpRequestId _unblockRequest, _reportSpamRequest; - IconedButton _attachDocument, _attachPhoto, _attachEmoji, _kbShow, _kbHide, _cmdStart; + IconedButton _attachDocument, _attachPhoto; + EmojiButton _attachEmoji; + IconedButton _kbShow, _kbHide, _cmdStart; FlatCheckbox _broadcast; bool _cmdStartShown; MessageField _field; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 8624a27d3f..ba51e53d27 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -759,6 +759,10 @@ void MainWidget::notify_botCommandsChanged(UserData *bot) { history.notify_botCommandsChanged(bot); } +void MainWidget::notify_inlineBotRequesting(bool requesting) { + history.notify_inlineBotRequesting(requesting); +} + void MainWidget::notify_userIsBotChanged(UserData *bot) { history.notify_userIsBotChanged(bot); } diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index 03c30ccda0..3d8c6efa39 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -416,6 +416,7 @@ public: void ui_showPeerHistory(quint64 peer, qint32 msgId, bool back); void notify_botCommandsChanged(UserData *bot); + void notify_inlineBotRequesting(bool requesting); void notify_userIsBotChanged(UserData *bot); void notify_userIsContactChanged(UserData *user, bool fromThisApp); void notify_migrateUpdated(PeerData *peer);