mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-03 21:54:05 +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());
|
||||
|
||||
setupSharingDisallowed();
|
||||
setupSwipeReply();
|
||||
setupSwipeReplyAndBack();
|
||||
}
|
||||
|
||||
void HistoryInner::reactionChosen(const ChosenReaction &reaction) {
|
||||
|
@ -523,12 +523,30 @@ void HistoryInner::setupSharingDisallowed() {
|
|||
}, lifetime());
|
||||
}
|
||||
|
||||
void HistoryInner::setupSwipeReply() {
|
||||
if (_peer && _peer->isChannel() && !_peer->isMegagroup()) {
|
||||
void HistoryInner::setupSwipeReplyAndBack() {
|
||||
if (!_peer) {
|
||||
return;
|
||||
}
|
||||
const auto peer = _peer;
|
||||
HistoryView::SetupSwipeHandler(this, _scroll, [=, history = _history](
|
||||
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)
|
||||
|| (_gestureHorizontal.translation != data.translation)
|
||||
|| (_gestureHorizontal.reachRatio != data.reachRatio);
|
||||
|
@ -541,9 +559,18 @@ void HistoryInner::setupSwipeReply() {
|
|||
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();
|
||||
if (inSelectionMode().inSelectionMode) {
|
||||
if (inSelectionMode().inSelectionMode
|
||||
|| (peer->isChannel() && !peer->isMegagroup())) {
|
||||
return result;
|
||||
}
|
||||
enumerateItems<EnumItemsDirection::BottomToTop>([&](
|
||||
|
|
|
@ -428,7 +428,7 @@ private:
|
|||
void reactionChosen(const ChosenReaction &reaction);
|
||||
|
||||
void setupSharingDisallowed();
|
||||
void setupSwipeReply();
|
||||
void setupSwipeReplyAndBack();
|
||||
[[nodiscard]] bool hasCopyRestriction(HistoryItem *item = nullptr) const;
|
||||
[[nodiscard]] bool hasCopyMediaRestriction(
|
||||
not_null<HistoryItem*> item) const;
|
||||
|
@ -544,6 +544,7 @@ private:
|
|||
base::Timer _touchScrollTimer;
|
||||
|
||||
HistoryView::ChatPaintGestureHorizontalData _gestureHorizontal;
|
||||
HistoryView::SwipeBackResult _swipeBackData;
|
||||
|
||||
// _menu must be destroyed before _whoReactedMenuLifetime.
|
||||
rpl::lifetime _whoReactedMenuLifetime;
|
||||
|
|
|
@ -13,9 +13,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/event_filter.h"
|
||||
#include "history/history_view_swipe_data.h"
|
||||
#include "ui/chat/chat_style.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "ui/ui_utility.h"
|
||||
#include "ui/widgets/elastic_scroll.h"
|
||||
#include "ui/widgets/scroll_area.h"
|
||||
#include "styles/style_chat.h"
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
|
@ -30,7 +33,7 @@ void SetupSwipeHandler(
|
|||
not_null<Ui::RpWidget*> widget,
|
||||
not_null<Ui::ScrollArea*> scroll,
|
||||
Fn<void(ChatPaintGestureHorizontalData)> update,
|
||||
Fn<SwipeHandlerFinishData(int)> generateFinishByTop,
|
||||
Fn<SwipeHandlerFinishData(int, Qt::LayoutDirection)> generateFinish,
|
||||
rpl::producer<bool> dontStart) {
|
||||
constexpr auto kThresholdWidth = 50;
|
||||
constexpr auto kMaxRatio = 1.5;
|
||||
|
@ -145,8 +148,9 @@ void SetupSwipeHandler(
|
|||
state->startAt = args.position;
|
||||
state->delta = QPointF();
|
||||
state->cursorTop = widget->mapFromGlobal(args.globalCursor).y();
|
||||
state->finishByTopData = generateFinishByTop(
|
||||
state->cursorTop);
|
||||
state->finishByTopData = generateFinish(
|
||||
state->cursorTop,
|
||||
state->direction.value_or(Qt::RightToLeft));
|
||||
if (!state->finishByTopData.callback) {
|
||||
setOrientation(Qt::Vertical);
|
||||
}
|
||||
|
@ -279,4 +283,127 @@ void SetupSwipeHandler(
|
|||
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
|
||||
|
|
|
@ -15,6 +15,9 @@ class ScrollArea;
|
|||
namespace HistoryView {
|
||||
|
||||
struct ChatPaintGestureHorizontalData;
|
||||
struct SwipeBackResult;
|
||||
|
||||
constexpr auto kMsgBareIdSwipeBack = std::numeric_limits<int64>::max() - 77;
|
||||
|
||||
struct SwipeHandlerFinishData {
|
||||
Fn<void(void)> callback;
|
||||
|
@ -25,7 +28,11 @@ void SetupSwipeHandler(
|
|||
not_null<Ui::RpWidget*> widget,
|
||||
not_null<Ui::ScrollArea*> scroll,
|
||||
Fn<void(ChatPaintGestureHorizontalData)> update,
|
||||
Fn<SwipeHandlerFinishData(int)> generateFinishByTop,
|
||||
Fn<SwipeHandlerFinishData(int, Qt::LayoutDirection)> generateFinishByTop,
|
||||
rpl::producer<bool> dontStart = nullptr);
|
||||
|
||||
SwipeBackResult SetupSwipeBack(
|
||||
not_null<Ui::RpWidget*> widget,
|
||||
Fn<std::pair<QColor, QColor>()> colors);
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -17,4 +17,9 @@ struct ChatPaintGestureHorizontalData {
|
|||
int cursorTop = 0;
|
||||
};
|
||||
|
||||
struct SwipeBackResult final {
|
||||
rpl::lifetime lifetime;
|
||||
Fn<void(ChatPaintGestureHorizontalData)> callback;
|
||||
};
|
||||
|
||||
} // namespace HistoryView
|
||||
|
|
|
@ -58,6 +58,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "base/qt_signal_producer.h"
|
||||
#include "base/qt/qt_key_modifiers.h"
|
||||
#include "base/unixtime.h"
|
||||
#include "history/history_view_swipe.h"
|
||||
#include "history/history_view_swipe_data.h"
|
||||
#include "base/call_delayed.h"
|
||||
#include "data/business/data_shortcut_messages.h"
|
||||
#include "data/components/credits.h"
|
||||
|
|
|
@ -904,7 +904,9 @@ void RepliesWidget::setupSwipeReply() {
|
|||
_history->owner().requestItemRepaint(item);
|
||||
}
|
||||
}
|
||||
}, [=, show = controller()->uiShow()](int cursorTop) {
|
||||
}, [=, show = controller()->uiShow()](
|
||||
int cursorTop,
|
||||
Qt::LayoutDirection direction) {
|
||||
auto result = HistoryView::SwipeHandlerFinishData();
|
||||
if (_inner->elementInSelectionMode(nullptr).inSelectionMode) {
|
||||
return result;
|
||||
|
|
|
@ -1245,3 +1245,5 @@ newPeerUserpics: GroupCallUserpics {
|
|||
}
|
||||
newPeerUserpicsPadding: margins(0px, 3px, 0px, 0px);
|
||||
newPeerWidth: 320px;
|
||||
|
||||
swipeBackSize: 150px;
|
||||
|
|
Loading…
Add table
Reference in a new issue