Allow disabling fast reply button.

This commit is contained in:
John Preston
2026-03-02 12:55:04 +04:00
parent 9b0b154bd3
commit 06c5b6c2fb
10 changed files with 85 additions and 6 deletions
+1
View File
@@ -670,6 +670,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_send_cmdenter" = "Send with Cmd+Enter"; "lng_settings_send_cmdenter" = "Send with Cmd+Enter";
"lng_settings_chat_quick_action_reply" = "Reply with double click"; "lng_settings_chat_quick_action_reply" = "Reply with double click";
"lng_settings_chat_quick_action_react" = "Send reaction with double click"; "lng_settings_chat_quick_action_react" = "Send reaction with double click";
"lng_settings_chat_corner_reply" = "Reply button on messages";
"lng_settings_chat_corner_reaction" = "Reaction button on messages"; "lng_settings_chat_corner_reaction" = "Reaction button on messages";
"lng_settings_shortcuts" = "Keyboard shortcuts"; "lng_settings_shortcuts" = "Keyboard shortcuts";
+9 -2
View File
@@ -245,7 +245,8 @@ QByteArray Settings::serialize() const {
+ sizeof(qint32) * 8 + sizeof(qint32) * 8
+ sizeof(ushort) + sizeof(ushort)
+ sizeof(qint32) // _notificationsDisplayChecksum + sizeof(qint32) // _notificationsDisplayChecksum
+ Serialize::bytearraySize(callPanelPosition); + Serialize::bytearraySize(callPanelPosition)
+ sizeof(qint32);
auto result = QByteArray(); auto result = QByteArray();
result.reserve(size); result.reserve(size);
@@ -410,7 +411,8 @@ QByteArray Settings::serialize() const {
<< qint32(_quickDialogAction) << qint32(_quickDialogAction)
<< _notificationsVolume << _notificationsVolume
<< _notificationsDisplayChecksum << _notificationsDisplayChecksum
<< callPanelPosition; << callPanelPosition
<< qint32(_cornerReply.current() ? 1 : 0);
} }
Ensures(result.size() == size); Ensures(result.size() == size);
@@ -513,6 +515,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
qint32 hardwareAcceleratedVideo = _hardwareAcceleratedVideo ? 1 : 0; qint32 hardwareAcceleratedVideo = _hardwareAcceleratedVideo ? 1 : 0;
qint32 chatQuickAction = static_cast<qint32>(_chatQuickAction); qint32 chatQuickAction = static_cast<qint32>(_chatQuickAction);
qint32 suggestAnimatedEmoji = _suggestAnimatedEmoji ? 1 : 0; qint32 suggestAnimatedEmoji = _suggestAnimatedEmoji ? 1 : 0;
qint32 cornerReply = _cornerReply.current() ? 1 : 0;
qint32 cornerReaction = _cornerReaction.current() ? 1 : 0; qint32 cornerReaction = _cornerReaction.current() ? 1 : 0;
qint32 legacySkipTranslationForLanguage = _translateButtonEnabled ? 1 : 0; qint32 legacySkipTranslationForLanguage = _translateButtonEnabled ? 1 : 0;
qint32 skipTranslationLanguagesCount = 0; qint32 skipTranslationLanguagesCount = 0;
@@ -883,6 +886,9 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
if (!stream.atEnd()) { if (!stream.atEnd()) {
stream >> callPanelPosition; stream >> callPanelPosition;
} }
if (!stream.atEnd()) {
stream >> cornerReply;
}
if (stream.status() != QDataStream::Ok) { if (stream.status() != QDataStream::Ok) {
LOG(("App Error: " LOG(("App Error: "
"Bad data for Core::Settings::constructFromSerialized()")); "Bad data for Core::Settings::constructFromSerialized()"));
@@ -1057,6 +1063,7 @@ void Settings::addFromSerialized(const QByteArray &serialized) {
} }
} }
_suggestAnimatedEmoji = (suggestAnimatedEmoji == 1); _suggestAnimatedEmoji = (suggestAnimatedEmoji == 1);
_cornerReply = (cornerReply == 1);
_cornerReaction = (cornerReaction == 1); _cornerReaction = (cornerReaction == 1);
{ // Parse the legacy translation setting. { // Parse the legacy translation setting.
if (legacySkipTranslationForLanguage == 0) { if (legacySkipTranslationForLanguage == 0) {
+9 -2
View File
@@ -493,8 +493,14 @@ public:
[[nodiscard]] rpl::producer<bool> cornerReactionValue() const { [[nodiscard]] rpl::producer<bool> cornerReactionValue() const {
return _cornerReaction.value(); return _cornerReaction.value();
} }
[[nodiscard]] rpl::producer<bool> cornerReactionChanges() const { void setCornerReply(bool value) {
return _cornerReaction.changes(); _cornerReply = value;
}
[[nodiscard]] bool cornerReply() const {
return _cornerReply.current();
}
[[nodiscard]] rpl::producer<bool> cornerReplyValue() const {
return _cornerReply.value();
} }
void setSpellcheckerEnabled(bool value) { void setSpellcheckerEnabled(bool value) {
@@ -1034,6 +1040,7 @@ private:
bool _suggestEmoji = true; bool _suggestEmoji = true;
bool _suggestStickersByEmoji = true; bool _suggestStickersByEmoji = true;
bool _suggestAnimatedEmoji = true; bool _suggestAnimatedEmoji = true;
rpl::variable<bool> _cornerReply = true;
rpl::variable<bool> _cornerReaction = true; rpl::variable<bool> _cornerReaction = true;
rpl::variable<bool> _spellcheckerEnabled = true; rpl::variable<bool> _spellcheckerEnabled = true;
PlaybackSpeed _videoPlaybackSpeed; PlaybackSpeed _videoPlaybackSpeed;
@@ -450,6 +450,14 @@ HistoryInner::HistoryInner(
} }
}, lifetime()); }, lifetime());
Core::App().settings().cornerReplyValue(
) | rpl::on_next([=](bool value) {
_useCornerReply = value;
if (!value) {
_replyButtonManager->updateButton({});
}
}, lifetime());
controller->adaptive().chatWideValue( controller->adaptive().chatWideValue(
) | rpl::on_next([=](bool wide) { ) | rpl::on_next([=](bool wide) {
_isChatWide = wide; _isChatWide = wide;
@@ -4324,6 +4332,9 @@ auto HistoryInner::replyButtonParameters(
QPoint position, QPoint position,
const HistoryView::TextState &replyState) const const HistoryView::TextState &replyState) const
-> HistoryView::ReplyButton::ButtonParameters { -> HistoryView::ReplyButton::ButtonParameters {
if (!_useCornerReply) {
return {};
}
const auto top = itemTop(view); const auto top = itemTop(view);
if (top < 0 if (top < 0
|| _mouseAction == MouseAction::Dragging || _mouseAction == MouseAction::Dragging
@@ -537,6 +537,7 @@ private:
bool _dragStateUserpic = false; bool _dragStateUserpic = false;
bool _pressWasInactive = false; bool _pressWasInactive = false;
bool _recountedAfterPendingResizedItems = false; bool _recountedAfterPendingResizedItems = false;
bool _useCornerReply = false;
bool _useCornerReaction = false; bool _useCornerReaction = false;
bool _acceptsHorizontalScroll = false; bool _acceptsHorizontalScroll = false;
bool _horizontalScrollLocked = false; bool _horizontalScrollLocked = false;
@@ -527,6 +527,16 @@ ListWidget::ListWidget(
}, lifetime()); }, lifetime());
} }
if (_replyButtonManager) {
Core::App().settings().cornerReplyValue(
) | rpl::on_next([=](bool value) {
_useCornerReply = value;
if (!value) {
_replyButtonManager->updateButton({});
}
}, lifetime());
}
_delegate->listChatWideValue( _delegate->listChatWideValue(
) | rpl::on_next([=](bool wide) { ) | rpl::on_next([=](bool wide) {
_isChatWide = wide; _isChatWide = wide;
@@ -3626,6 +3636,9 @@ ReplyButton::ButtonParameters ListWidget::replyButtonParameters(
not_null<const Element*> view, not_null<const Element*> view,
QPoint position, QPoint position,
const TextState &replyState) const { const TextState &replyState) const {
if (!_useCornerReply) {
return {};
}
const auto top = itemTop(view); const auto top = itemTop(view);
if (top < 0 if (top < 0
|| _mouseAction == MouseAction::Dragging || _mouseAction == MouseAction::Dragging
@@ -788,6 +788,7 @@ private:
std::unique_ptr<HistoryView::Reactions::Manager> _reactionsManager; std::unique_ptr<HistoryView::Reactions::Manager> _reactionsManager;
rpl::variable<HistoryItem*> _reactionsItem; rpl::variable<HistoryItem*> _reactionsItem;
bool _useCornerReply = false;
bool _useCornerReaction = false; bool _useCornerReaction = false;
std::unique_ptr<ReplyButton::Manager> _replyButtonManager; std::unique_ptr<ReplyButton::Manager> _replyButtonManager;
@@ -16,7 +16,7 @@ namespace HistoryView::ReplyButton {
namespace { namespace {
constexpr auto kToggleDuration = crl::time(120); constexpr auto kToggleDuration = crl::time(120);
constexpr auto kButtonShowDelay = crl::time(300); constexpr auto kButtonShowDelay = crl::time(0);
constexpr auto kButtonHideDelay = crl::time(300); constexpr auto kButtonHideDelay = crl::time(300);
[[nodiscard]] float64 ScaleForState(ButtonState state) { [[nodiscard]] float64 ScaleForState(ButtonState state) {
@@ -344,7 +344,11 @@ void Manager::removeStaleButtons() {
} }
void Manager::clearAppearAnimations() { void Manager::clearAppearAnimations() {
_buttonHiding.clear(); for (const auto &button : base::take(_buttonHiding)) {
if (!button->isHidden()) {
button->repaint();
}
}
} }
} // namespace HistoryView::ReplyButton } // namespace HistoryView::ReplyButton
@@ -68,6 +68,10 @@ public:
[[nodiscard]] float64 currentScale() const; [[nodiscard]] float64 currentScale() const;
[[nodiscard]] float64 currentOpacity() const; [[nodiscard]] float64 currentOpacity() const;
void repaint() const {
_update(_geometry);
}
private: private:
void updateGeometry(Fn<void(QRect)> update); void updateGeometry(Fn<void(QRect)> update);
void applyState(ButtonState state, Fn<void(QRect)> update); void applyState(ButtonState state, Fn<void(QRect)> update);
@@ -1047,6 +1047,17 @@ void BuildMessagesSection(SectionBuilder &builder) {
}; };
}); });
builder.add(nullptr, [] {
return SearchEntry{
.id = u"chat/corner-reply"_q,
.title = tr::lng_settings_chat_corner_reply(tr::now),
.keywords = { u"corner"_q, u"reply"_q },
.checkIcon = Core::App().settings().cornerReply()
? SearchEntryCheckIcon::Checked
: SearchEntryCheckIcon::Unchecked,
};
});
builder.add(nullptr, [] { builder.add(nullptr, [] {
return SearchEntry{ return SearchEntry{
.id = u"chat/corner-reaction"_q, .id = u"chat/corner-reaction"_q,
@@ -1729,6 +1740,25 @@ void SetupMessages(
Ui::AddSkip(inner, st::settingsSendTypeSkip); Ui::AddSkip(inner, st::settingsSendTypeSkip);
const auto cornerReply = inner->add(
object_ptr<Ui::Checkbox>(
inner,
tr::lng_settings_chat_corner_reply(tr::now),
Core::App().settings().cornerReply(),
st::settingsCheckbox),
st::settingsCheckboxPadding);
cornerReply->checkedChanges(
) | rpl::on_next([=](bool checked) {
Core::App().settings().setCornerReply(checked);
Core::App().saveSettingsDelayed();
}, inner->lifetime());
if (highlights) {
highlights->push_back({ u"chat/corner-reply"_q, {
cornerReply,
{ .radius = st::boxRadius },
} });
}
const auto cornerReaction = inner->add( const auto cornerReaction = inner->add(
object_ptr<Ui::Checkbox>( object_ptr<Ui::Checkbox>(
inner, inner,