mirror of https://github.com/procxx/kepka.git
Add progress animation to GIFs search.
Also display "no results" phrase.
This commit is contained in:
parent
2028116e22
commit
03a59b04be
|
@ -270,6 +270,7 @@ contactsSearchCancel: CrossButton {
|
||||||
crossPosition: point(4px, 4px);
|
crossPosition: point(4px, 4px);
|
||||||
|
|
||||||
duration: 150;
|
duration: 150;
|
||||||
|
loadingPeriod: 1000;
|
||||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
color: windowBgOver;
|
color: windowBgOver;
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,7 @@ dialogsCancelSearch: CrossButton {
|
||||||
crossPosition: point(0px, 0px);
|
crossPosition: point(0px, 0px);
|
||||||
|
|
||||||
duration: 150;
|
duration: 150;
|
||||||
|
loadingPeriod: 1000;
|
||||||
ripple: emptyRippleAnimation;
|
ripple: emptyRippleAnimation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,9 @@ public:
|
||||||
|
|
||||||
void stealFocus();
|
void stealFocus();
|
||||||
void returnFocus();
|
void returnFocus();
|
||||||
|
void setLoading(bool loading) {
|
||||||
|
_cancel->setLoadingAnimation(loading);
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
@ -181,6 +184,7 @@ GifsListWidget::~GifsListWidget() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GifsListWidget::cancelGifsSearch() {
|
void GifsListWidget::cancelGifsSearch() {
|
||||||
|
_footer->setLoading(false);
|
||||||
if (_inlineRequestId) {
|
if (_inlineRequestId) {
|
||||||
request(_inlineRequestId).cancel();
|
request(_inlineRequestId).cancel();
|
||||||
_inlineRequestId = 0;
|
_inlineRequestId = 0;
|
||||||
|
@ -192,6 +196,7 @@ void GifsListWidget::cancelGifsSearch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GifsListWidget::inlineResultsDone(const MTPmessages_BotResults &result) {
|
void GifsListWidget::inlineResultsDone(const MTPmessages_BotResults &result) {
|
||||||
|
_footer->setLoading(false);
|
||||||
_inlineRequestId = 0;
|
_inlineRequestId = 0;
|
||||||
|
|
||||||
auto it = _inlineCache.find(_inlineQuery);
|
auto it = _inlineCache.find(_inlineQuery);
|
||||||
|
@ -754,9 +759,7 @@ bool GifsListWidget::refreshInlineRows(int32 *added) {
|
||||||
auto it = _inlineCache.find(_inlineQuery);
|
auto it = _inlineCache.find(_inlineQuery);
|
||||||
const InlineCacheEntry *entry = nullptr;
|
const InlineCacheEntry *entry = nullptr;
|
||||||
if (it != _inlineCache.cend()) {
|
if (it != _inlineCache.cend()) {
|
||||||
if (!it->second->results.empty()) {
|
|
||||||
entry = it->second.get();
|
entry = it->second.get();
|
||||||
}
|
|
||||||
_inlineNextOffset = it->second->nextOffset;
|
_inlineNextOffset = it->second->nextOffset;
|
||||||
}
|
}
|
||||||
auto result = refreshInlineRows(entry, false);
|
auto result = refreshInlineRows(entry, false);
|
||||||
|
@ -780,6 +783,7 @@ void GifsListWidget::searchForGifs(const QString &query) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_inlineQuery != query) {
|
if (_inlineQuery != query) {
|
||||||
|
_footer->setLoading(false);
|
||||||
if (_inlineRequestId) {
|
if (_inlineRequestId) {
|
||||||
request(_inlineRequestId).cancel();
|
request(_inlineRequestId).cancel();
|
||||||
_inlineRequestId = 0;
|
_inlineRequestId = 0;
|
||||||
|
@ -813,8 +817,10 @@ void GifsListWidget::sendInlineRequest() {
|
||||||
if (_inlineRequestId || !_inlineQueryPeer || _inlineNextQuery.isEmpty()) {
|
if (_inlineRequestId || !_inlineQueryPeer || _inlineNextQuery.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_searchBot) {
|
if (!_searchBot) {
|
||||||
// Wait for the bot being resolved.
|
// Wait for the bot being resolved.
|
||||||
|
_footer->setLoading(true);
|
||||||
_inlineRequestTimer.start(kSearchRequestDelay);
|
_inlineRequestTimer.start(kSearchRequestDelay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -825,13 +831,18 @@ void GifsListWidget::sendInlineRequest() {
|
||||||
auto it = _inlineCache.find(_inlineQuery);
|
auto it = _inlineCache.find(_inlineQuery);
|
||||||
if (it != _inlineCache.cend()) {
|
if (it != _inlineCache.cend()) {
|
||||||
nextOffset = it->second->nextOffset;
|
nextOffset = it->second->nextOffset;
|
||||||
if (nextOffset.isEmpty()) return;
|
if (nextOffset.isEmpty()) {
|
||||||
|
_footer->setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_footer->setLoading(true);
|
||||||
_inlineRequestId = request(MTPmessages_GetInlineBotResults(MTP_flags(0), _searchBot->inputUser, _inlineQueryPeer->input, MTPInputGeoPoint(), MTP_string(_inlineQuery), MTP_string(nextOffset))).done([this](const MTPmessages_BotResults &result, mtpRequestId requestId) {
|
_inlineRequestId = request(MTPmessages_GetInlineBotResults(MTP_flags(0), _searchBot->inputUser, _inlineQueryPeer->input, MTPInputGeoPoint(), MTP_string(_inlineQuery), MTP_string(nextOffset))).done([this](const MTPmessages_BotResults &result, mtpRequestId requestId) {
|
||||||
inlineResultsDone(result);
|
inlineResultsDone(result);
|
||||||
}).fail([this](const RPCError &error) {
|
}).fail([this](const RPCError &error) {
|
||||||
// show error?
|
// show error?
|
||||||
|
_footer->setLoading(false);
|
||||||
_inlineRequestId = 0;
|
_inlineRequestId = 0;
|
||||||
}).handleAllErrors().send();
|
}).handleAllErrors().send();
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,19 +21,100 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org
|
||||||
#include "ui/effects/cross_animation.h"
|
#include "ui/effects/cross_animation.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
|
namespace {
|
||||||
|
|
||||||
void CrossAnimation::paint(Painter &p, const style::CrossAnimation &st, style::color color, int x, int y, int outerWidth, float64 shown) {
|
constexpr auto kPointCount = 12;
|
||||||
|
|
||||||
|
//
|
||||||
|
// 1 3
|
||||||
|
// X X X X
|
||||||
|
// X X X X
|
||||||
|
// 0 X X 4
|
||||||
|
// X X X X
|
||||||
|
// X 2 X
|
||||||
|
// X X
|
||||||
|
// X X
|
||||||
|
// 11 5
|
||||||
|
// X X
|
||||||
|
// X X
|
||||||
|
// X 8 X
|
||||||
|
// X X X X
|
||||||
|
// 10 X X 6
|
||||||
|
// X X X X
|
||||||
|
// X X X X
|
||||||
|
// 9 7
|
||||||
|
//
|
||||||
|
|
||||||
|
void transformLoadingCross(float64 loading, std::array<QPointF, kPointCount> &points, int &paintPointsCount) {
|
||||||
|
auto moveTo = [](QPointF &point, QPointF &to, float64 ratio) {
|
||||||
|
point = point * (1. - ratio) + to * ratio;
|
||||||
|
};
|
||||||
|
auto moveFrom = [](QPointF &point, QPointF &from, float64 ratio) {
|
||||||
|
point = from * (1. - ratio) + point * ratio;
|
||||||
|
};
|
||||||
|
auto paintPoints = [&points, &paintPointsCount](std::initializer_list<int> &&indices) {
|
||||||
|
auto index = 0;
|
||||||
|
for (auto paintIndex : indices) {
|
||||||
|
points[index++] = points[paintIndex];
|
||||||
|
}
|
||||||
|
paintPointsCount = indices.size();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading < 0.125) {
|
||||||
|
auto ratio = loading / 0.125;
|
||||||
|
moveTo(points[6], points[5], ratio);
|
||||||
|
moveTo(points[7], points[8], ratio);
|
||||||
|
} else if (loading < 0.25) {
|
||||||
|
auto ratio = (loading - 0.125) / 0.125;
|
||||||
|
moveTo(points[9], points[8], ratio);
|
||||||
|
moveTo(points[10], points[11], ratio);
|
||||||
|
paintPoints({ 0, 1, 2, 3, 4, 9, 10, 11 });
|
||||||
|
} else if (loading < 0.375) {
|
||||||
|
auto ratio = (loading - 0.25) / 0.125;
|
||||||
|
moveTo(points[0], points[11], ratio);
|
||||||
|
moveTo(points[1], points[2], ratio);
|
||||||
|
paintPoints({ 0, 1, 2, 3, 4, 8 });
|
||||||
|
} else if (loading < 0.5) {
|
||||||
|
auto ratio = (loading - 0.375) / 0.125;
|
||||||
|
moveTo(points[8], points[4], ratio);
|
||||||
|
moveTo(points[11], points[3], ratio);
|
||||||
|
paintPoints({ 3, 4, 8, 11 });
|
||||||
|
} else if (loading < 0.625) {
|
||||||
|
auto ratio = (loading - 0.5) / 0.125;
|
||||||
|
moveFrom(points[8], points[4], ratio);
|
||||||
|
moveFrom(points[11], points[3], ratio);
|
||||||
|
paintPoints({ 3, 4, 8, 11 });
|
||||||
|
} else if (loading < 0.75) {
|
||||||
|
auto ratio = (loading - 0.625) / 0.125;
|
||||||
|
moveFrom(points[6], points[5], ratio);
|
||||||
|
moveFrom(points[7], points[8], ratio);
|
||||||
|
paintPoints({ 3, 4, 5, 6, 7, 11 });
|
||||||
|
} else if (loading < 0.875) {
|
||||||
|
auto ratio = (loading - 0.75) / 0.125;
|
||||||
|
moveFrom(points[9], points[8], ratio);
|
||||||
|
moveFrom(points[10], points[11], ratio);
|
||||||
|
paintPoints({ 3, 4, 5, 6, 7, 8, 9, 10 });
|
||||||
|
} else {
|
||||||
|
auto ratio = (loading - 0.875) / 0.125;
|
||||||
|
moveFrom(points[0], points[11], ratio);
|
||||||
|
moveFrom(points[1], points[2], ratio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void CrossAnimation::paint(Painter &p, const style::CrossAnimation &st, style::color color, int x, int y, int outerWidth, float64 shown, float64 loading) {
|
||||||
PainterHighQualityEnabler hq(p);
|
PainterHighQualityEnabler hq(p);
|
||||||
|
|
||||||
auto deleteScale = shown + st.minScale * (1. - shown);
|
|
||||||
auto deleteSkip = deleteScale * st.skip + (1. - deleteScale) * (st.size / 2);
|
|
||||||
auto sqrt2 = sqrt(2.);
|
auto sqrt2 = sqrt(2.);
|
||||||
|
auto deleteScale = shown + st.minScale * (1. - shown);
|
||||||
|
auto deleteSkip = (deleteScale * st.skip) + (1. - deleteScale) * (st.size / 2);
|
||||||
auto deleteLeft = rtlpoint(x + deleteSkip, 0, outerWidth).x() + 0.;
|
auto deleteLeft = rtlpoint(x + deleteSkip, 0, outerWidth).x() + 0.;
|
||||||
auto deleteTop = y + deleteSkip + 0.;
|
auto deleteTop = y + deleteSkip + 0.;
|
||||||
auto deleteWidth = st.size - 2 * deleteSkip;
|
auto deleteWidth = st.size - 2 * deleteSkip;
|
||||||
auto deleteHeight = st.size - 2 * deleteSkip;
|
auto deleteHeight = st.size - 2 * deleteSkip;
|
||||||
auto deleteStroke = st.stroke / sqrt2;
|
auto deleteStroke = st.stroke / sqrt2;
|
||||||
QPointF pathDelete[] = {
|
std::array<QPointF, kPointCount> pathDelete = { {
|
||||||
{ deleteLeft, deleteTop + deleteStroke },
|
{ deleteLeft, deleteTop + deleteStroke },
|
||||||
{ deleteLeft + deleteStroke, deleteTop },
|
{ deleteLeft + deleteStroke, deleteTop },
|
||||||
{ deleteLeft + (deleteWidth / 2.), deleteTop + (deleteHeight / 2.) - deleteStroke },
|
{ deleteLeft + (deleteWidth / 2.), deleteTop + (deleteHeight / 2.) - deleteStroke },
|
||||||
|
@ -46,7 +127,17 @@ void CrossAnimation::paint(Painter &p, const style::CrossAnimation &st, style::c
|
||||||
{ deleteLeft + deleteStroke, deleteTop + deleteHeight },
|
{ deleteLeft + deleteStroke, deleteTop + deleteHeight },
|
||||||
{ deleteLeft, deleteTop + deleteHeight - deleteStroke },
|
{ deleteLeft, deleteTop + deleteHeight - deleteStroke },
|
||||||
{ deleteLeft + (deleteWidth / 2.) - deleteStroke, deleteTop + (deleteHeight / 2.) },
|
{ deleteLeft + (deleteWidth / 2.) - deleteStroke, deleteTop + (deleteHeight / 2.) },
|
||||||
};
|
} };
|
||||||
|
auto pathDeleteSize = kPointCount;
|
||||||
|
|
||||||
|
auto loadingArcLength = 0;
|
||||||
|
if (loading > 0.) {
|
||||||
|
transformLoadingCross(loading, pathDelete, pathDeleteSize);
|
||||||
|
|
||||||
|
auto loadingArc = (loading >= 0.5) ? (loading - 1.) : loading;
|
||||||
|
loadingArcLength = qRound(-loadingArc * 2 * FullArcLength);
|
||||||
|
}
|
||||||
|
|
||||||
if (shown < 1.) {
|
if (shown < 1.) {
|
||||||
auto alpha = -(shown - 1.) * M_PI_2;
|
auto alpha = -(shown - 1.) * M_PI_2;
|
||||||
auto cosalpha = cos(alpha);
|
auto cosalpha = cos(alpha);
|
||||||
|
@ -62,10 +153,30 @@ void CrossAnimation::paint(Painter &p, const style::CrossAnimation &st, style::c
|
||||||
}
|
}
|
||||||
QPainterPath path;
|
QPainterPath path;
|
||||||
path.moveTo(pathDelete[0]);
|
path.moveTo(pathDelete[0]);
|
||||||
for (int i = 1; i != base::array_size(pathDelete); ++i) {
|
for (int i = 1; i != pathDeleteSize; ++i) {
|
||||||
path.lineTo(pathDelete[i]);
|
path.lineTo(pathDelete[i]);
|
||||||
}
|
}
|
||||||
|
path.lineTo(pathDelete[0]);
|
||||||
p.fillPath(path, color);
|
p.fillPath(path, color);
|
||||||
|
|
||||||
|
if (loadingArcLength != 0) {
|
||||||
|
auto loadingArcStart = FullArcLength / 8;
|
||||||
|
auto roundSkip = (st.size * (1 - sqrt2) + 2 * sqrt2 * deleteSkip + st.stroke) / 2;
|
||||||
|
auto roundPart = QRectF(x + roundSkip, y + roundSkip, st.size - 2 * roundSkip, st.size - 2 * roundSkip);
|
||||||
|
if (shown < 1.) {
|
||||||
|
loadingArcStart -= qRound(-(shown - 1.) * FullArcLength / 4.);
|
||||||
|
}
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
auto pen = color->p;
|
||||||
|
pen.setWidthF(st.stroke);
|
||||||
|
pen.setCapStyle(Qt::RoundCap);
|
||||||
|
p.setPen(pen);
|
||||||
|
if (loadingArcLength < 0) {
|
||||||
|
loadingArcStart += loadingArcLength;
|
||||||
|
loadingArcLength = -loadingArcLength;
|
||||||
|
}
|
||||||
|
p.drawArc(roundPart, loadingArcStart, loadingArcLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -26,7 +26,7 @@ namespace Ui {
|
||||||
|
|
||||||
class CrossAnimation {
|
class CrossAnimation {
|
||||||
public:
|
public:
|
||||||
static void paint(Painter &p, const style::CrossAnimation &st, style::color color, int x, int y, int outerWidth, float64 shown);
|
static void paint(Painter &p, const style::CrossAnimation &st, style::color color, int x, int y, int outerWidth, float64 shown, float64 loading = 0.);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -625,12 +625,22 @@ void LeftOutlineButton::paintEvent(QPaintEvent *e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CrossButton::CrossButton(QWidget *parent, const style::CrossButton &st) : RippleButton(parent, st.ripple)
|
CrossButton::CrossButton(QWidget *parent, const style::CrossButton &st) : RippleButton(parent, st.ripple)
|
||||||
, _st(st) {
|
, _st(st)
|
||||||
|
, _a_loading(animation(this, &CrossButton::step_loading)) {
|
||||||
resize(_st.width, _st.height);
|
resize(_st.width, _st.height);
|
||||||
setCursor(style::cur_pointer);
|
setCursor(style::cur_pointer);
|
||||||
hide();
|
hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CrossButton::step_loading(TimeMs ms, bool timer) {
|
||||||
|
if (stopLoadingAnimation(ms)) {
|
||||||
|
_a_loading.stop();
|
||||||
|
}
|
||||||
|
if (timer) {
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CrossButton::toggleAnimated(bool visible) {
|
void CrossButton::toggleAnimated(bool visible) {
|
||||||
if (_shown == visible) {
|
if (_shown == visible) {
|
||||||
return;
|
return;
|
||||||
|
@ -659,7 +669,43 @@ void CrossButton::paintEvent(QPaintEvent *e) {
|
||||||
|
|
||||||
paintRipple(p, _st.crossPosition.x(), _st.crossPosition.y(), ms);
|
paintRipple(p, _st.crossPosition.x(), _st.crossPosition.y(), ms);
|
||||||
|
|
||||||
CrossAnimation::paint(p, _st.cross, over ? _st.crossFgOver : _st.crossFg, _st.crossPosition.x(), _st.crossPosition.y(), width(), shown);
|
auto loading = 0.;
|
||||||
|
if (_a_loading.animating()) {
|
||||||
|
if (stopLoadingAnimation(ms)) {
|
||||||
|
_a_loading.stop();
|
||||||
|
} else {
|
||||||
|
loading = ((ms - _loadingStartMs) % _st.loadingPeriod) / float64(_st.loadingPeriod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CrossAnimation::paint(p, _st.cross, over ? _st.crossFgOver : _st.crossFg, _st.crossPosition.x(), _st.crossPosition.y(), width(), shown, loading);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CrossButton::stopLoadingAnimation(TimeMs ms) {
|
||||||
|
if (!_loadingStopMs) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto stopPeriod = (_loadingStopMs - _loadingStartMs) / _st.loadingPeriod;
|
||||||
|
auto currentPeriod = (ms - _loadingStartMs) / _st.loadingPeriod;
|
||||||
|
if (currentPeriod != stopPeriod) {
|
||||||
|
t_assert(currentPeriod > stopPeriod);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrossButton::setLoadingAnimation(bool enabled) {
|
||||||
|
if (enabled) {
|
||||||
|
_loadingStopMs = 0;
|
||||||
|
if (!_a_loading.animating()) {
|
||||||
|
_loadingStartMs = getms();
|
||||||
|
_a_loading.start();
|
||||||
|
}
|
||||||
|
} else if (_a_loading.animating()) {
|
||||||
|
_loadingStopMs = getms();
|
||||||
|
if (!((_loadingStopMs - _loadingStartMs) % _st.loadingPeriod)) {
|
||||||
|
_a_loading.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrossButton::onStateChanged(State was, StateChangeSource source) {
|
void CrossButton::onStateChanged(State was, StateChangeSource source) {
|
||||||
|
|
|
@ -233,6 +233,7 @@ public:
|
||||||
bool isShown() const {
|
bool isShown() const {
|
||||||
return _shown;
|
return _shown;
|
||||||
}
|
}
|
||||||
|
void setLoadingAnimation(bool enabled);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
@ -243,6 +244,8 @@ protected:
|
||||||
QPoint prepareRippleStartPosition() const override;
|
QPoint prepareRippleStartPosition() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void step_loading(TimeMs ms, bool timer);
|
||||||
|
bool stopLoadingAnimation(TimeMs ms);
|
||||||
void animationCallback();
|
void animationCallback();
|
||||||
|
|
||||||
const style::CrossButton &_st;
|
const style::CrossButton &_st;
|
||||||
|
@ -250,6 +253,10 @@ private:
|
||||||
bool _shown = false;
|
bool _shown = false;
|
||||||
Animation _a_show;
|
Animation _a_show;
|
||||||
|
|
||||||
|
TimeMs _loadingStartMs = 0;
|
||||||
|
TimeMs _loadingStopMs = 0;
|
||||||
|
BasicAnimation _a_loading;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
|
@ -315,6 +315,7 @@ CrossButton {
|
||||||
crossFgOver:color;
|
crossFgOver:color;
|
||||||
crossPosition: point;
|
crossPosition: point;
|
||||||
duration: int;
|
duration: int;
|
||||||
|
loadingPeriod: int;
|
||||||
|
|
||||||
ripple: RippleAnimation;
|
ripple: RippleAnimation;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue