mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 22:54:01 +02:00
Added ability to swipe-to-back to history widget.
This commit is contained in:
parent
17a10cf6bb
commit
540fa0e669
8 changed files with 184 additions and 11 deletions
|
@ -440,7 +440,7 @@ HistoryInner::HistoryInner(
|
||||||
}, _scroll->lifetime());
|
}, _scroll->lifetime());
|
||||||
|
|
||||||
setupSharingDisallowed();
|
setupSharingDisallowed();
|
||||||
setupSwipeReply();
|
setupSwipeReplyAndBack();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInner::reactionChosen(const ChosenReaction &reaction) {
|
void HistoryInner::reactionChosen(const ChosenReaction &reaction) {
|
||||||
|
@ -523,12 +523,30 @@ void HistoryInner::setupSharingDisallowed() {
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryInner::setupSwipeReply() {
|
void HistoryInner::setupSwipeReplyAndBack() {
|
||||||
if (_peer && _peer->isChannel() && !_peer->isMegagroup()) {
|
if (!_peer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto peer = _peer;
|
||||||
HistoryView::SetupSwipeHandler(this, _scroll, [=, history = _history](
|
HistoryView::SetupSwipeHandler(this, _scroll, [=, history = _history](
|
||||||
HistoryView::ChatPaintGestureHorizontalData data) {
|
HistoryView::ChatPaintGestureHorizontalData data) {
|
||||||
|
if (data.translation > 0) {
|
||||||
|
if (!_swipeBackData.callback) {
|
||||||
|
_swipeBackData = HistoryView::SetupSwipeBack(
|
||||||
|
_widget,
|
||||||
|
[=]() -> std::pair<QColor, QColor> {
|
||||||
|
auto context = preparePaintContext({});
|
||||||
|
return {
|
||||||
|
context.st->msgServiceBg()->c,
|
||||||
|
context.st->msgServiceFg()->c,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_swipeBackData.callback(data);
|
||||||
|
return;
|
||||||
|
} else if (_swipeBackData.lifetime) {
|
||||||
|
_swipeBackData = {};
|
||||||
|
}
|
||||||
const auto changed = (_gestureHorizontal.msgBareId != data.msgBareId)
|
const auto changed = (_gestureHorizontal.msgBareId != data.msgBareId)
|
||||||
|| (_gestureHorizontal.translation != data.translation)
|
|| (_gestureHorizontal.translation != data.translation)
|
||||||
|| (_gestureHorizontal.reachRatio != data.reachRatio);
|
|| (_gestureHorizontal.reachRatio != data.reachRatio);
|
||||||
|
@ -541,9 +559,18 @@ void HistoryInner::setupSwipeReply() {
|
||||||
repaintItem(item);
|
repaintItem(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [=, show = _controller->uiShow()](int cursorTop) {
|
}, [=, show = _controller->uiShow()](
|
||||||
|
int cursorTop,
|
||||||
|
Qt::LayoutDirection direction) {
|
||||||
|
if (direction == Qt::RightToLeft) {
|
||||||
|
return HistoryView::SwipeHandlerFinishData{
|
||||||
|
.callback = [=] { _controller->showBackFromStack(); },
|
||||||
|
.msgBareId = HistoryView::kMsgBareIdSwipeBack,
|
||||||
|
};
|
||||||
|
}
|
||||||
auto result = HistoryView::SwipeHandlerFinishData();
|
auto result = HistoryView::SwipeHandlerFinishData();
|
||||||
if (inSelectionMode().inSelectionMode) {
|
if (inSelectionMode().inSelectionMode
|
||||||
|
|| (peer->isChannel() && !peer->isMegagroup())) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
enumerateItems<EnumItemsDirection::BottomToTop>([&](
|
enumerateItems<EnumItemsDirection::BottomToTop>([&](
|
||||||
|
|
|
@ -428,7 +428,7 @@ private:
|
||||||
void reactionChosen(const ChosenReaction &reaction);
|
void reactionChosen(const ChosenReaction &reaction);
|
||||||
|
|
||||||
void setupSharingDisallowed();
|
void setupSharingDisallowed();
|
||||||
void setupSwipeReply();
|
void setupSwipeReplyAndBack();
|
||||||
[[nodiscard]] bool hasCopyRestriction(HistoryItem *item = nullptr) const;
|
[[nodiscard]] bool hasCopyRestriction(HistoryItem *item = nullptr) const;
|
||||||
[[nodiscard]] bool hasCopyMediaRestriction(
|
[[nodiscard]] bool hasCopyMediaRestriction(
|
||||||
not_null<HistoryItem*> item) const;
|
not_null<HistoryItem*> item) const;
|
||||||
|
@ -544,6 +544,7 @@ private:
|
||||||
base::Timer _touchScrollTimer;
|
base::Timer _touchScrollTimer;
|
||||||
|
|
||||||
HistoryView::ChatPaintGestureHorizontalData _gestureHorizontal;
|
HistoryView::ChatPaintGestureHorizontalData _gestureHorizontal;
|
||||||
|
HistoryView::SwipeBackResult _swipeBackData;
|
||||||
|
|
||||||
// _menu must be destroyed before _whoReactedMenuLifetime.
|
// _menu must be destroyed before _whoReactedMenuLifetime.
|
||||||
rpl::lifetime _whoReactedMenuLifetime;
|
rpl::lifetime _whoReactedMenuLifetime;
|
||||||
|
|
|
@ -13,9 +13,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/event_filter.h"
|
#include "base/event_filter.h"
|
||||||
#include "history/history_view_swipe_data.h"
|
#include "history/history_view_swipe_data.h"
|
||||||
#include "ui/chat/chat_style.h"
|
#include "ui/chat/chat_style.h"
|
||||||
|
#include "ui/painter.h"
|
||||||
|
#include "ui/rect.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "ui/widgets/elastic_scroll.h"
|
#include "ui/widgets/elastic_scroll.h"
|
||||||
#include "ui/widgets/scroll_area.h"
|
#include "ui/widgets/scroll_area.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
|
||||||
#include <QtWidgets/QApplication>
|
#include <QtWidgets/QApplication>
|
||||||
|
|
||||||
|
@ -30,7 +33,7 @@ void SetupSwipeHandler(
|
||||||
not_null<Ui::RpWidget*> widget,
|
not_null<Ui::RpWidget*> widget,
|
||||||
not_null<Ui::ScrollArea*> scroll,
|
not_null<Ui::ScrollArea*> scroll,
|
||||||
Fn<void(ChatPaintGestureHorizontalData)> update,
|
Fn<void(ChatPaintGestureHorizontalData)> update,
|
||||||
Fn<SwipeHandlerFinishData(int)> generateFinishByTop,
|
Fn<SwipeHandlerFinishData(int, Qt::LayoutDirection)> generateFinish,
|
||||||
rpl::producer<bool> dontStart) {
|
rpl::producer<bool> dontStart) {
|
||||||
constexpr auto kThresholdWidth = 50;
|
constexpr auto kThresholdWidth = 50;
|
||||||
constexpr auto kMaxRatio = 1.5;
|
constexpr auto kMaxRatio = 1.5;
|
||||||
|
@ -145,8 +148,9 @@ void SetupSwipeHandler(
|
||||||
state->startAt = args.position;
|
state->startAt = args.position;
|
||||||
state->delta = QPointF();
|
state->delta = QPointF();
|
||||||
state->cursorTop = widget->mapFromGlobal(args.globalCursor).y();
|
state->cursorTop = widget->mapFromGlobal(args.globalCursor).y();
|
||||||
state->finishByTopData = generateFinishByTop(
|
state->finishByTopData = generateFinish(
|
||||||
state->cursorTop);
|
state->cursorTop,
|
||||||
|
state->direction.value_or(Qt::RightToLeft));
|
||||||
if (!state->finishByTopData.callback) {
|
if (!state->finishByTopData.callback) {
|
||||||
setOrientation(Qt::Vertical);
|
setOrientation(Qt::Vertical);
|
||||||
}
|
}
|
||||||
|
@ -279,4 +283,127 @@ void SetupSwipeHandler(
|
||||||
base::install_event_filter(widget, filter));
|
base::install_event_filter(widget, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SwipeBackResult SetupSwipeBack(
|
||||||
|
not_null<Ui::RpWidget*> widget,
|
||||||
|
Fn<std::pair<QColor, QColor>()> colors) {
|
||||||
|
struct State {
|
||||||
|
base::unique_qptr<Ui::RpWidget> back;
|
||||||
|
ChatPaintGestureHorizontalData data;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr auto kMaxRightOffset = 0.5;
|
||||||
|
constexpr auto kMaxLeftOffset = 0.8;
|
||||||
|
constexpr auto kIdealSize = 100;
|
||||||
|
const auto maxOffset = st::swipeBackSize * kMaxRightOffset;
|
||||||
|
const auto sizeRatio = st::swipeBackSize
|
||||||
|
/ style::ConvertFloatScale(kIdealSize);
|
||||||
|
|
||||||
|
auto lifetime = rpl::lifetime();
|
||||||
|
const auto state = lifetime.make_state<State>();
|
||||||
|
|
||||||
|
const auto paintCallback = [=] {
|
||||||
|
const auto [bg, fg] = colors();
|
||||||
|
const auto arrowPen = QPen(
|
||||||
|
fg,
|
||||||
|
st::lineWidth * 3 * sizeRatio,
|
||||||
|
Qt::SolidLine,
|
||||||
|
Qt::RoundCap);
|
||||||
|
return [=] {
|
||||||
|
auto p = QPainter(state->back);
|
||||||
|
|
||||||
|
constexpr auto kBouncePart = 0.25;
|
||||||
|
constexpr auto kStrokeWidth = 2.;
|
||||||
|
constexpr auto kWaveWidth = 10.;
|
||||||
|
const auto ratio = std::min(state->data.ratio, 1.);
|
||||||
|
const auto reachRatio = state->data.reachRatio;
|
||||||
|
const auto rect = state->back->rect()
|
||||||
|
- Margins(state->back->width() / 4);
|
||||||
|
const auto center = rect::center(rect);
|
||||||
|
const auto strokeWidth = style::ConvertFloatScale(kStrokeWidth)
|
||||||
|
* sizeRatio;
|
||||||
|
|
||||||
|
const auto reachScale = std::clamp(
|
||||||
|
(reachRatio > kBouncePart)
|
||||||
|
? (kBouncePart * 2 - reachRatio)
|
||||||
|
: reachRatio,
|
||||||
|
0.,
|
||||||
|
1.);
|
||||||
|
auto pen = QPen(bg);
|
||||||
|
pen.setWidthF(strokeWidth - (1. * (reachScale / kBouncePart)));
|
||||||
|
const auto arcRect = rect - Margins(strokeWidth);
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
p.setOpacity(ratio);
|
||||||
|
if (reachScale) {
|
||||||
|
const auto scale = (1. + 1. * reachScale);
|
||||||
|
p.translate(center);
|
||||||
|
p.scale(scale, scale);
|
||||||
|
p.translate(-center);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
p.setBrush(bg);
|
||||||
|
p.drawEllipse(rect);
|
||||||
|
p.drawEllipse(rect);
|
||||||
|
p.setPen(arrowPen);
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
const auto halfSize = rect.width() / 2;
|
||||||
|
const auto arrowSize = halfSize / 2;
|
||||||
|
const auto arrowHalf = arrowSize / 2;
|
||||||
|
const auto arrowX = st::swipeBackSize / 8
|
||||||
|
+ rect.x()
|
||||||
|
+ halfSize
|
||||||
|
- arrowHalf;
|
||||||
|
const auto arrowY = rect.y() + halfSize;
|
||||||
|
|
||||||
|
auto arrowPath = QPainterPath();
|
||||||
|
arrowPath.moveTo(arrowX + arrowSize, arrowY);
|
||||||
|
arrowPath.lineTo(arrowX, arrowY);
|
||||||
|
arrowPath.lineTo(arrowX + arrowHalf, arrowY - arrowHalf);
|
||||||
|
arrowPath.moveTo(arrowX, arrowY);
|
||||||
|
arrowPath.lineTo(arrowX + arrowHalf, arrowY + arrowHalf);
|
||||||
|
|
||||||
|
p.drawPath(arrowPath);
|
||||||
|
}
|
||||||
|
if (reachRatio) {
|
||||||
|
p.setPen(pen);
|
||||||
|
p.setBrush(Qt::NoBrush);
|
||||||
|
const auto w = style::ConvertFloatScale(kWaveWidth)
|
||||||
|
* sizeRatio;
|
||||||
|
p.setOpacity(ratio - reachRatio);
|
||||||
|
p.drawArc(
|
||||||
|
arcRect + Margins(reachRatio * reachRatio * w),
|
||||||
|
arc::kQuarterLength,
|
||||||
|
arc::kFullLength);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto callback = ([=](ChatPaintGestureHorizontalData data) {
|
||||||
|
const auto ratio = std::min(1.0, data.ratio);
|
||||||
|
state->data = std::move(data);
|
||||||
|
if (ratio > 0) {
|
||||||
|
if (!state->back) {
|
||||||
|
state->back = base::make_unique_q<Ui::RpWidget>(widget);
|
||||||
|
const auto raw = state->back.get();
|
||||||
|
raw->paintRequest(
|
||||||
|
) | rpl::start_with_next(paintCallback(), raw->lifetime());
|
||||||
|
raw->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
raw->resize(Size(st::swipeBackSize));
|
||||||
|
raw->show();
|
||||||
|
raw->raise();
|
||||||
|
}
|
||||||
|
state->back->moveToLeft(
|
||||||
|
anim::interpolate(
|
||||||
|
-st::swipeBackSize * kMaxLeftOffset,
|
||||||
|
maxOffset - st::swipeBackSize,
|
||||||
|
ratio),
|
||||||
|
(widget->height() - state->back->height()) / 2);
|
||||||
|
state->back->update();
|
||||||
|
} else if (state->back) {
|
||||||
|
state->back = nullptr;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return { std::move(lifetime), std::move(callback) };
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -15,6 +15,9 @@ class ScrollArea;
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
struct ChatPaintGestureHorizontalData;
|
struct ChatPaintGestureHorizontalData;
|
||||||
|
struct SwipeBackResult;
|
||||||
|
|
||||||
|
constexpr auto kMsgBareIdSwipeBack = std::numeric_limits<int64>::max() - 77;
|
||||||
|
|
||||||
struct SwipeHandlerFinishData {
|
struct SwipeHandlerFinishData {
|
||||||
Fn<void(void)> callback;
|
Fn<void(void)> callback;
|
||||||
|
@ -25,7 +28,11 @@ void SetupSwipeHandler(
|
||||||
not_null<Ui::RpWidget*> widget,
|
not_null<Ui::RpWidget*> widget,
|
||||||
not_null<Ui::ScrollArea*> scroll,
|
not_null<Ui::ScrollArea*> scroll,
|
||||||
Fn<void(ChatPaintGestureHorizontalData)> update,
|
Fn<void(ChatPaintGestureHorizontalData)> update,
|
||||||
Fn<SwipeHandlerFinishData(int)> generateFinishByTop,
|
Fn<SwipeHandlerFinishData(int, Qt::LayoutDirection)> generateFinishByTop,
|
||||||
rpl::producer<bool> dontStart = nullptr);
|
rpl::producer<bool> dontStart = nullptr);
|
||||||
|
|
||||||
|
SwipeBackResult SetupSwipeBack(
|
||||||
|
not_null<Ui::RpWidget*> widget,
|
||||||
|
Fn<std::pair<QColor, QColor>()> colors);
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -17,4 +17,9 @@ struct ChatPaintGestureHorizontalData {
|
||||||
int cursorTop = 0;
|
int cursorTop = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SwipeBackResult final {
|
||||||
|
rpl::lifetime lifetime;
|
||||||
|
Fn<void(ChatPaintGestureHorizontalData)> callback;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -58,6 +58,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/qt_signal_producer.h"
|
#include "base/qt_signal_producer.h"
|
||||||
#include "base/qt/qt_key_modifiers.h"
|
#include "base/qt/qt_key_modifiers.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
|
#include "history/history_view_swipe.h"
|
||||||
|
#include "history/history_view_swipe_data.h"
|
||||||
#include "base/call_delayed.h"
|
#include "base/call_delayed.h"
|
||||||
#include "data/business/data_shortcut_messages.h"
|
#include "data/business/data_shortcut_messages.h"
|
||||||
#include "data/components/credits.h"
|
#include "data/components/credits.h"
|
||||||
|
|
|
@ -904,7 +904,9 @@ void RepliesWidget::setupSwipeReply() {
|
||||||
_history->owner().requestItemRepaint(item);
|
_history->owner().requestItemRepaint(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [=, show = controller()->uiShow()](int cursorTop) {
|
}, [=, show = controller()->uiShow()](
|
||||||
|
int cursorTop,
|
||||||
|
Qt::LayoutDirection direction) {
|
||||||
auto result = HistoryView::SwipeHandlerFinishData();
|
auto result = HistoryView::SwipeHandlerFinishData();
|
||||||
if (_inner->elementInSelectionMode(nullptr).inSelectionMode) {
|
if (_inner->elementInSelectionMode(nullptr).inSelectionMode) {
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -1245,3 +1245,5 @@ newPeerUserpics: GroupCallUserpics {
|
||||||
}
|
}
|
||||||
newPeerUserpicsPadding: margins(0px, 3px, 0px, 0px);
|
newPeerUserpicsPadding: margins(0px, 3px, 0px, 0px);
|
||||||
newPeerWidth: 320px;
|
newPeerWidth: 320px;
|
||||||
|
|
||||||
|
swipeBackSize: 150px;
|
||||||
|
|
Loading…
Add table
Reference in a new issue