Hide button near posts in channels

This commit is contained in:
Neurotoxin001 2025-07-04 03:27:40 +03:00
parent 3be793032f
commit ea4bc18d3f
16 changed files with 504 additions and 115 deletions

View file

@ -6891,6 +6891,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"ayu_ContextCopyID" = "Copy ID";
"ayu_IDCopiedToast" = "ID copied to clipboard.";
"ayu_ContextHideMessage" = "Hide";
"ayu_ShowNearPosts" = "Show Near Posts";
"ayu_ContextCopyCallbackData" = "Copy Callback Data";
"ayu_RegisterURLScheme" = "Register URL Scheme";
"ayu_SessionTerminated" = "Session **{item}** was terminated. You may still browse cached messages.";

View file

@ -295,6 +295,8 @@ AyuGramSettings::AyuGramSettings() {
showMessageSeconds = false;
showMessageShot = true;
showHideButtonNearPosts = true;
// ~ Confirmations
stickerConfirmation = false;
gifConfirmation = false;
@ -555,6 +557,10 @@ void set_showMessageShot(bool val) {
settings->showMessageShot = val;
}
void set_showHideButtonNearPosts(bool val) {
settings->showHideButtonNearPosts = val;
}
void set_stickerConfirmation(bool val) {
settings->stickerConfirmation = val;
}

View file

@ -92,6 +92,7 @@ public:
bool showMessageSeconds;
bool showMessageShot;
bool showHideButtonNearPosts;
bool stickerConfirmation;
bool gifConfirmation;
bool voiceConfirmation;
@ -174,72 +175,138 @@ void set_showPeerId(int val);
void set_showMessageSeconds(bool val);
void set_showMessageShot(bool val);
void set_showHideButtonNearPosts(bool val);
void set_stickerConfirmation(bool val);
void set_gifConfirmation(bool val);
void set_voiceConfirmation(bool val);
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(
AyuGramSettings,
sendReadMessages,
sendReadStories,
sendOnlinePackets,
sendUploadProgress,
sendOfflinePacketAfterOnline,
markReadAfterAction,
useScheduledMessages,
sendWithoutSound,
saveDeletedMessages,
saveMessagesHistory,
saveForBots,
hideFromBlocked,
disableAds,
disableStories,
disableCustomBackgrounds,
showOnlyAddedEmojisAndStickers,
collapseSimilarChannels,
hideSimilarChannels,
wideMultiplier,
spoofWebviewAsAndroid,
increaseWebviewHeight,
increaseWebviewWidth,
disableNotificationsDelay,
localPremium,
appIcon,
simpleQuotesAndReplies,
replaceBottomInfoWithIcons,
deletedMark,
editedMark,
recentStickersCount,
showReactionsPanelInContextMenu,
showViewsPanelInContextMenu,
showHideMessageInContextMenu,
showUserMessagesInContextMenu,
showMessageDetailsInContextMenu,
showAttachButtonInMessageField,
showCommandsButtonInMessageField,
showEmojiButtonInMessageField,
showMicrophoneButtonInMessageField,
showAutoDeleteButtonInMessageField,
showAttachPopup,
showEmojiPopup,
showLReadToggleInDrawer,
showSReadToggleInDrawer,
showGhostToggleInDrawer,
showStreamerToggleInDrawer,
showGhostToggleInTray,
showStreamerToggleInTray,
monoFont,
hideNotificationCounters,
hideNotificationBadge,
hideAllChatsFolder,
channelBottomButton,
showPeerId,
showMessageSeconds,
showMessageShot,
stickerConfirmation,
gifConfirmation,
voiceConfirmation
);
inline void to_json(nlohmann::json &nlohmann_json_j, const AyuGramSettings &nlohmann_json_t) {
NLOHMANN_JSON_TO(sendReadMessages)
NLOHMANN_JSON_TO(sendReadStories)
NLOHMANN_JSON_TO(sendOnlinePackets)
NLOHMANN_JSON_TO(sendUploadProgress)
NLOHMANN_JSON_TO(sendOfflinePacketAfterOnline)
NLOHMANN_JSON_TO(markReadAfterAction)
NLOHMANN_JSON_TO(useScheduledMessages)
NLOHMANN_JSON_TO(sendWithoutSound)
NLOHMANN_JSON_TO(saveDeletedMessages)
NLOHMANN_JSON_TO(saveMessagesHistory)
NLOHMANN_JSON_TO(saveForBots)
NLOHMANN_JSON_TO(hideFromBlocked)
NLOHMANN_JSON_TO(disableAds)
NLOHMANN_JSON_TO(disableStories)
NLOHMANN_JSON_TO(disableCustomBackgrounds)
NLOHMANN_JSON_TO(showOnlyAddedEmojisAndStickers)
NLOHMANN_JSON_TO(collapseSimilarChannels)
NLOHMANN_JSON_TO(hideSimilarChannels)
NLOHMANN_JSON_TO(wideMultiplier)
NLOHMANN_JSON_TO(spoofWebviewAsAndroid)
NLOHMANN_JSON_TO(increaseWebviewHeight)
NLOHMANN_JSON_TO(increaseWebviewWidth)
NLOHMANN_JSON_TO(disableNotificationsDelay)
NLOHMANN_JSON_TO(localPremium)
NLOHMANN_JSON_TO(appIcon)
NLOHMANN_JSON_TO(simpleQuotesAndReplies)
NLOHMANN_JSON_TO(replaceBottomInfoWithIcons)
NLOHMANN_JSON_TO(deletedMark)
NLOHMANN_JSON_TO(editedMark)
NLOHMANN_JSON_TO(recentStickersCount)
NLOHMANN_JSON_TO(showReactionsPanelInContextMenu)
NLOHMANN_JSON_TO(showViewsPanelInContextMenu)
NLOHMANN_JSON_TO(showHideMessageInContextMenu)
NLOHMANN_JSON_TO(showUserMessagesInContextMenu)
NLOHMANN_JSON_TO(showMessageDetailsInContextMenu)
NLOHMANN_JSON_TO(showAttachButtonInMessageField)
NLOHMANN_JSON_TO(showCommandsButtonInMessageField)
NLOHMANN_JSON_TO(showEmojiButtonInMessageField)
NLOHMANN_JSON_TO(showMicrophoneButtonInMessageField)
NLOHMANN_JSON_TO(showAutoDeleteButtonInMessageField)
NLOHMANN_JSON_TO(showAttachPopup)
NLOHMANN_JSON_TO(showEmojiPopup)
NLOHMANN_JSON_TO(showLReadToggleInDrawer)
NLOHMANN_JSON_TO(showSReadToggleInDrawer)
NLOHMANN_JSON_TO(showGhostToggleInDrawer)
NLOHMANN_JSON_TO(showStreamerToggleInDrawer)
NLOHMANN_JSON_TO(showGhostToggleInTray)
NLOHMANN_JSON_TO(showStreamerToggleInTray)
NLOHMANN_JSON_TO(monoFont)
NLOHMANN_JSON_TO(hideNotificationCounters)
NLOHMANN_JSON_TO(hideNotificationBadge)
NLOHMANN_JSON_TO(hideAllChatsFolder)
NLOHMANN_JSON_TO(channelBottomButton)
NLOHMANN_JSON_TO(showPeerId)
NLOHMANN_JSON_TO(showMessageSeconds)
NLOHMANN_JSON_TO(showMessageShot)
NLOHMANN_JSON_TO(stickerConfirmation)
NLOHMANN_JSON_TO(showHideButtonNearPosts)
NLOHMANN_JSON_TO(gifConfirmation)
NLOHMANN_JSON_TO(voiceConfirmation)
}
inline void from_json(const nlohmann::json &nlohmann_json_j, AyuGramSettings &nlohmann_json_t) {
const AyuGramSettings nlohmann_json_default_obj{};
NLOHMANN_JSON_FROM_WITH_DEFAULT(sendReadMessages)
NLOHMANN_JSON_FROM_WITH_DEFAULT(sendReadStories)
NLOHMANN_JSON_FROM_WITH_DEFAULT(sendOnlinePackets)
NLOHMANN_JSON_FROM_WITH_DEFAULT(sendUploadProgress)
NLOHMANN_JSON_FROM_WITH_DEFAULT(sendOfflinePacketAfterOnline)
NLOHMANN_JSON_FROM_WITH_DEFAULT(markReadAfterAction)
NLOHMANN_JSON_FROM_WITH_DEFAULT(useScheduledMessages)
NLOHMANN_JSON_FROM_WITH_DEFAULT(sendWithoutSound)
NLOHMANN_JSON_FROM_WITH_DEFAULT(saveDeletedMessages)
NLOHMANN_JSON_FROM_WITH_DEFAULT(saveMessagesHistory)
NLOHMANN_JSON_FROM_WITH_DEFAULT(saveForBots)
NLOHMANN_JSON_FROM_WITH_DEFAULT(hideFromBlocked)
NLOHMANN_JSON_FROM_WITH_DEFAULT(disableAds)
NLOHMANN_JSON_FROM_WITH_DEFAULT(disableStories)
NLOHMANN_JSON_FROM_WITH_DEFAULT(disableCustomBackgrounds)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showOnlyAddedEmojisAndStickers)
NLOHMANN_JSON_FROM_WITH_DEFAULT(collapseSimilarChannels)
NLOHMANN_JSON_FROM_WITH_DEFAULT(hideSimilarChannels)
NLOHMANN_JSON_FROM_WITH_DEFAULT(wideMultiplier)
NLOHMANN_JSON_FROM_WITH_DEFAULT(spoofWebviewAsAndroid)
NLOHMANN_JSON_FROM_WITH_DEFAULT(increaseWebviewHeight)
NLOHMANN_JSON_FROM_WITH_DEFAULT(increaseWebviewWidth)
NLOHMANN_JSON_FROM_WITH_DEFAULT(disableNotificationsDelay)
NLOHMANN_JSON_FROM_WITH_DEFAULT(localPremium)
NLOHMANN_JSON_FROM_WITH_DEFAULT(appIcon)
NLOHMANN_JSON_FROM_WITH_DEFAULT(simpleQuotesAndReplies)
NLOHMANN_JSON_FROM_WITH_DEFAULT(replaceBottomInfoWithIcons)
NLOHMANN_JSON_FROM_WITH_DEFAULT(deletedMark)
NLOHMANN_JSON_FROM_WITH_DEFAULT(editedMark)
NLOHMANN_JSON_FROM_WITH_DEFAULT(recentStickersCount)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showReactionsPanelInContextMenu)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showViewsPanelInContextMenu)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showHideMessageInContextMenu)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showUserMessagesInContextMenu)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showMessageDetailsInContextMenu)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showAttachButtonInMessageField)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showCommandsButtonInMessageField)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showEmojiButtonInMessageField)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showMicrophoneButtonInMessageField)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showAutoDeleteButtonInMessageField)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showAttachPopup)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showEmojiPopup)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showLReadToggleInDrawer)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showSReadToggleInDrawer)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showGhostToggleInDrawer)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showStreamerToggleInDrawer)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showGhostToggleInTray)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showStreamerToggleInTray)
NLOHMANN_JSON_FROM_WITH_DEFAULT(monoFont)
NLOHMANN_JSON_FROM_WITH_DEFAULT(hideNotificationCounters)
NLOHMANN_JSON_FROM_WITH_DEFAULT(hideNotificationBadge)
NLOHMANN_JSON_FROM_WITH_DEFAULT(hideAllChatsFolder)
NLOHMANN_JSON_FROM_WITH_DEFAULT(channelBottomButton)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showPeerId)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showMessageSeconds)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showMessageShot)
NLOHMANN_JSON_FROM_WITH_DEFAULT(stickerConfirmation)
NLOHMANN_JSON_FROM_WITH_DEFAULT(showHideButtonNearPosts)
NLOHMANN_JSON_FROM_WITH_DEFAULT(gifConfirmation)
NLOHMANN_JSON_FROM_WITH_DEFAULT(voiceConfirmation)
}
AyuGramSettings &getInstance();

View file

@ -21,6 +21,7 @@
#include "styles/style_chat_helpers.h"
#include "styles/style_ayu_styles.h"
#include "styles/style_basic.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_info.h"
#include "styles/style_menu_icons.h"
@ -894,18 +895,66 @@ void SetupContextMenuElements(not_null<Ui::VerticalLayout*> container,
AyuSettings::save();
});
AddChooseButtonWithIconAndRightText(
auto hideValue = container->lifetime().make_state<rpl::variable<int>>(settings.showHideMessageInContextMenu);
rpl::producer<QString> hideLabel = hideValue->value() | rpl::map([=](int val) {
return options[val];
});
// добавляем кнопку для пункта "Hide" с изменяемым подпунктом
// 4-й параметр - стиль, 5-й - иконка
Settings::AddButtonWithLabel(
container,
controller,
settings.showHideMessageInContextMenu,
options,
tr::ayu_ContextHideMessage(),
tr::ayu_SettingsContextMenuTitle(),
st::menuIconClear,
[=](int index)
{
hideLabel,
st::settingsButton,
{ &st::menuIconClear }
)->addClickHandler([=] {
controller->show(Box([=](not_null<Ui::GenericBox*> box) {
box->setTitle(tr::ayu_SettingsContextMenuTitle());
box->addButton(tr::lng_box_ok(), [=] { box->closeBox(); });
const auto group = std::make_shared<Ui::RadiobuttonGroup>(hideValue->current());
const auto layout = box->verticalLayout();
layout->add(object_ptr<Ui::FixedHeightWidget>(
layout,
st::boxOptionListPadding.top() + st::autolockButton.margin.top()));
int idx = 0;
for (const auto &text : options) {
layout->add(
object_ptr<Ui::Radiobutton>(
layout,
group,
idx++,
text,
st::defaultBoxCheckbox,
st::defaultRadio),
QMargins(
st::boxPadding.left() + st::boxOptionListPadding.left(),
0,
st::boxPadding.right(),
st::boxOptionListSkip));
}
const auto check = layout->add(
object_ptr<Ui::Checkbox>(
layout,
tr::ayu_ShowNearPosts(),
settings.showHideButtonNearPosts,
st::defaultBoxCheckbox),
QMargins(
st::boxPadding.left() + st::boxOptionListPadding.left(),
0,
st::boxPadding.right(),
st::boxOptionListSkip));
group->setChangedCallback([=](int index) {
AyuSettings::set_showHideMessageInContextMenu(index);
AyuSettings::save();
hideValue->force_assign(index);
box->closeBox();
});
check->checkedValue()
| rpl::start_with_next([=](bool enabled) {
AyuSettings::set_showHideButtonNearPosts(enabled);
AyuSettings::save();
}, check->lifetime());
}));
});
AddChooseButtonWithIconAndRightText(
container,

View file

@ -61,6 +61,9 @@ namespace {
// A new message from the same sender is attached to previous within 15 minutes.
constexpr int kAttachMessageToPreviousSecondsDelta = 900;
// Отступ между правыми кнопками и краем
constexpr auto kRightActionsMargin = 10;
constexpr auto kRightActionsMarginWide = 1;
Element *HoveredElement/* = nullptr*/;
Element *PressedElement/* = nullptr*/;
@ -1590,6 +1593,11 @@ ClickHandlerPtr Element::rightActionLink(
return ClickHandlerPtr();
}
// Заглушка для дополнительной кнопки "глазик"
ClickHandlerPtr Element::viewActionLink(
std::optional<QPoint> pressPoint) const {
return ClickHandlerPtr();
}
TimeId Element::displayedEditDate() const {
return TimeId(0);
}

View file

@ -493,6 +493,9 @@ public:
int outerWidth) const;
[[nodiscard]] virtual ClickHandlerPtr rightActionLink(
std::optional<QPoint> pressPoint) const;
// Возвращает ссылку для дополнительной кнопки "глазик"
[[nodiscard]] virtual ClickHandlerPtr viewActionLink(
std::optional<QPoint> pressPoint) const;
[[nodiscard]] virtual TimeId displayedEditDate() const;
[[nodiscard]] virtual bool hasVisibleText() const;
[[nodiscard]] int textualMaxWidth() const;

View file

@ -51,12 +51,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
// AyuGram includes
#include "ayu/features/messageshot/message_shot.h"
#include "styles/style_ayu_icons.h"
#include "ayu/ayu_state.h"
#include "ayu/ayu_settings.h"
namespace HistoryView {
namespace {
constexpr auto kPlayStatusLimit = 12;
// Минимальный отступ между кнопкой просмотра и правым краем
constexpr auto kRightActionsMargin = 10;
// Отступ для широких окон, чтобы кнопки стояли чуть правее
constexpr auto kRightActionsMarginWide = 1;
const auto kPsaTooltipPrefix = "cloud_lng_tooltip_psa_";
class KeyboardStyle : public ReplyKeyboard::Style {
@ -397,6 +403,10 @@ struct Message::RightAction {
ClickHandlerPtr link;
QPoint lastPoint;
std::unique_ptr<SecondRightAction> second;
// Дополнительные элементы для кнопки с глазиком
std::unique_ptr<Ui::RippleAnimation> viewRipple;
ClickHandlerPtr viewLink;
QPoint viewLastPoint;
};
LogEntryOriginal::LogEntryOriginal() = default;
@ -1506,9 +1516,12 @@ void Message::draw(Painter &p, const PaintContext &context) const {
(g.height() - size->height()) / 2,
0,
st::historyFastShareBottom);
const auto margin = delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
const auto fastShareLeft = hasRightLayout()
? (g.left() - size->width() - st::historyFastShareLeft)
: (g.left() + g.width() + st::historyFastShareLeft);
: (g.left() + g.width() + st::historyFastShareLeft - margin);
const auto fastShareTop = data()->isSponsored()
? g.top() + fastShareSkip
: g.top() + g.height() - fastShareSkip - size->height();
@ -1583,7 +1596,7 @@ void Message::draw(Painter &p, const PaintContext &context) const {
const auto outerWidth = st::historySwipeIconSkip
+ (isLeftSize ? rect::right(g) : width())
+ ((g.height() < size * kMaxHeightRatio)
? rightActionSize().value_or(QSize()).width()
? rightActionSize().value_or(QSize()).width() * 2
: 0);
const auto shift = std::min(
(size * kShiftRatio * context.gestureHorizontal.ratio),
@ -2271,6 +2284,8 @@ void Message::clickHandlerPressedChanged(
return;
} else if (_rightAction && (handler == _rightAction->link)) {
toggleRightActionRipple(pressed);
} else if (_rightAction && (handler == _rightAction->viewLink)) {
toggleViewActionRipple(pressed);
} else if (_rightAction
&& _rightAction->second
&& (handler == _rightAction->second->link)) {
@ -2342,6 +2357,26 @@ void Message::toggleRightActionRipple(bool pressed) {
}
}
// Ripple для дополнительной кнопки
void Message::toggleViewActionRipple(bool pressed) {
Expects(_rightAction != nullptr);
const auto rightSize = rightActionSize();
Assert(rightSize != std::nullopt);
if (pressed) {
if (!_rightAction->viewRipple) {
_rightAction->viewRipple = std::make_unique<Ui::RippleAnimation>(
st::defaultRippleAnimation,
Ui::RippleAnimation::RoundRectMask(*rightSize, rightSize->width() / 2),
[=] { repaint(); });
}
_rightAction->viewRipple->add(_rightAction->viewLastPoint);
} else if (_rightAction->viewRipple) {
_rightAction->viewRipple->lastStop();
}
}
void Message::toggleReplyRipple(bool pressed) {
const auto reply = Get<Reply>();
if (!reply) {
@ -2762,20 +2797,33 @@ TextState Message::textState(
(g.height() - size->height()) / 2,
0,
st::historyFastShareBottom);
const auto margin = delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
const auto fastShareLeft = hasRightLayout()
? (g.left() - size->width() - st::historyFastShareLeft)
: (g.left() + g.width() + st::historyFastShareLeft);
: (g.left() + g.width() + st::historyFastShareLeft - margin);
const auto fastShareTop = data()->isSponsored()
? g.top() + fastShareSkip
: g.top() + g.height() - fastShareSkip - size->height();
if (QRect(
const auto fastShareRect = QRect(
fastShareLeft,
fastShareTop,
size->width(),
size->height()
).contains(point)) {
size->height());
if (fastShareRect.contains(point)) {
result.link = rightActionLink(point
- QPoint(fastShareLeft, fastShareTop));
} else if (AyuSettings::getInstance().showHideButtonNearPosts) {
const auto viewRect = QRect(
fastShareLeft + size->width() + st::historyFastShareLeft,
fastShareTop,
size->width(),
size->height());
if (viewRect.contains(point)) {
result.link = viewActionLink(point
- QPoint(viewRect.x(), fastShareTop));
}
}
}
} else if (media && media->isDisplayed()) {
@ -3626,6 +3674,12 @@ void Message::refreshDataIdHook() {
if (_rightAction && base::take(_rightAction->link)) {
_rightAction->link = rightActionLink(_rightAction->lastPoint);
}
if (AyuSettings::getInstance().showHideButtonNearPosts
&& _rightAction && base::take(_rightAction->viewLink)) {
_rightAction->viewLink = viewActionLink(_rightAction->viewLastPoint);
} else if (_rightAction) {
_rightAction->viewLink = nullptr;
}
if (base::take(_fastReplyLink)) {
_fastReplyLink = fastReplyLink();
}
@ -4021,6 +4075,7 @@ void Message::drawRightAction(
const auto size = rightActionSize();
const auto st = context.st;
const auto showEye = AyuSettings::getInstance().showHideButtonNearPosts;
if (_rightAction->ripple) {
const auto &stm = context.messageStyle();
@ -4035,6 +4090,19 @@ void Message::drawRightAction(
_rightAction->ripple.reset();
}
}
if (showEye && _rightAction->viewRipple) {
const auto &stm = context.messageStyle();
const auto colorOverride = &stm->msgWaveformInactive->c;
_rightAction->viewRipple->paint(
p,
left + size->width() + st::historyFastShareLeft,
top,
size->width(),
colorOverride);
if (_rightAction->viewRipple->empty()) {
_rightAction->viewRipple.reset();
}
}
if (_rightAction->second && _rightAction->second->ripple) {
const auto &stm = context.messageStyle();
const auto colorOverride = &stm->msgWaveformInactive->c;
@ -4066,6 +4134,22 @@ void Message::drawRightAction(
p.drawRoundedRect(rect, usual / 2, usual / 2);
}
}
// Фон для второй кнопки с глазиком
if (showEye) {
PainterHighQualityEnabler hq(p);
const auto rect = style::rtlrect(
left + size->width() + st::historyFastShareLeft,
top,
size->width(),
size->height(),
outerWidth);
const auto usual = st::historyFastShareSize;
if (size->width() == size->height() && size->width() == usual) {
p.drawEllipse(rect);
} else {
p.drawRoundedRect(rect, usual / 2, usual / 2);
}
}
if (displayRightActionComments()) {
const auto &icon = st->historyFastCommentsIcon();
icon.paint(
@ -4101,6 +4185,15 @@ void Message::drawRightAction(
? st->historyFastShareIcon()
: st->historyGoToOriginalIcon();
icon.paintInCenter(p, Rect(left, top, *size));
// Рисуем копию с глазиком правее исходной кнопки
if (showEye) {
const auto &viewIcon = st->historyFastViewIcon();
viewIcon.paintInCenter(
p,
Rect(left + size->width() + st::historyFastShareLeft,
top,
*size));
}
}
}
@ -4123,6 +4216,43 @@ ClickHandlerPtr Message::rightActionLink(
return _rightAction->link;
}
// Возвращает ссылку для кнопки с глазиком
// Теперь она скрывает выбранное сообщение, как пункт "Hide" в контекстном меню
ClickHandlerPtr Message::viewActionLink(
std::optional<QPoint> pressPoint) const {
if (delegate()->elementInSelectionMode(this).progress > 0) {
return nullptr;
}
if (!AyuSettings::getInstance().showHideButtonNearPosts) {
return nullptr;
}
ensureRightAction();
if (!_rightAction->viewLink) {
const auto sessionId = data()->history()->session().uniqueId();
const auto owner = &data()->history()->owner();
const auto ids = owner->itemOrItsGroup(data()); // список всех сообщений в группе
const auto history = data()->history();
_rightAction->viewLink = std::make_shared<LambdaClickHandler>([=](ClickContext context) {
const auto controller = ExtractController(context);
if (!controller || controller->session().uniqueId() != sessionId) {
return;
}
// Для альбомов скрываем каждое сообщение группы
for (const auto &fullId : ids) {
if (const auto item = owner->message(fullId)) {
item->destroy();
AyuState::hide(item);
}
}
history->requestChatListMessage();
});
}
if (pressPoint) {
_rightAction->viewLastPoint = *pressPoint;
}
return _rightAction->viewLink;
}
void Message::ensureRightAction() const {
if (_rightAction) {
return;
@ -4374,9 +4504,16 @@ QRect Message::innerGeometry() const {
const auto w = std::max(
(media() ? media()->resolveCustomInfoRightBottom().x() : 0),
result.width());
result.setWidth(std::min(
w + rightActionSize().value_or(QSize(0, 0)).width() * 2,
width()));
// Учитываем две кнопки и дополнительный отступ от правого края
const auto margin = hasRightLayout() ? 0
: (delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin);
const auto eye = AyuSettings::getInstance().showHideButtonNearPosts ? 2 : 1;
const auto actionsWidth = rightActionSize().value_or(QSize()).width() * eye
+ st::historyFastShareLeft * eye + margin;
const auto extra = std::max(actionsWidth - st::msgMargin.right(), 0);
result.setWidth(std::min(w + extra, width()));
}
if (hasBubble()) {
const auto cut = [&](int amount) {
@ -4429,11 +4566,22 @@ QRect Message::countGeometry() const {
auto contentWidth = availableWidth;
if (hasFromPhoto()) {
contentLeft += st::msgPhotoSkip;
if (const auto size = rightActionSize()) {
contentWidth -= size->width() + (st::msgPhotoSkip - st::historyFastShareSize);
}
//} else if (!Adaptive::Wide() && !out() && !fromChannel() && st::msgPhotoSkip - (hmaxwidth - hwidth) > 0) {
// contentLeft += st::msgPhotoSkip - (hmaxwidth - hwidth);
if (const auto size = rightActionSize()) {
// Ширина двух кнопок и отступ от правого края
const auto margin = hasRightLayout() ? 0
: (delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin);
const auto eye = AyuSettings::getInstance().showHideButtonNearPosts ? 2 : 1;
const auto actionsWidth = size->width() * eye + st::historyFastShareLeft * eye + margin;
// Отнимаем только разницу между необходимым и уже заложенным отступом
const auto extra = std::max(actionsWidth - st::msgMargin.right(), 0);
contentWidth -= extra;
if (hasFromPhoto()) {
// Для сообщений с аватаркой учитываем дополнительное смещение
contentWidth -= (st::msgPhotoSkip - st::historyFastShareSize);
}
}
accumulate_min(contentWidth, maxWidth());
accumulate_min(contentWidth, int(_bubbleWidthLimit));
@ -4553,9 +4701,18 @@ int Message::resizeContentGetHeight(int newWidth) {
auto contentWidth = newWidth
- st::msgMargin.left()
- (centeredView ? st::msgMargin.left() : st::msgMargin.right());
if (hasFromPhoto()) {
if (const auto size = rightActionSize()) {
contentWidth -= size->width() + (st::msgPhotoSkip - st::historyFastShareSize);
const auto margin = hasRightLayout() ? 0
: (delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin);
const auto eye = AyuSettings::getInstance().showHideButtonNearPosts ? 2 : 1;
const auto actionsWidth = size->width() * eye + st::historyFastShareLeft * eye + margin;
const auto extra = std::max(actionsWidth - st::msgMargin.right(), 0);
contentWidth -= extra;
if (hasFromPhoto()) {
// Учёт области под аватарку
contentWidth -= (st::msgPhotoSkip - st::historyFastShareSize);
}
}
accumulate_min(contentWidth, maxWidth());

View file

@ -139,6 +139,8 @@ public:
int outerWidth) const override;
[[nodiscard]] ClickHandlerPtr rightActionLink(
std::optional<QPoint> pressPoint) const override;
[[nodiscard]] ClickHandlerPtr viewActionLink(
std::optional<QPoint> pressPoint) const override;
[[nodiscard]] TimeId displayedEditDate() const override;
[[nodiscard]] bool toggleSelectionByHandlerClick(
const ClickHandlerPtr &handler) const override;
@ -193,6 +195,7 @@ private:
void createTopicButtonRipple();
void toggleRightActionRipple(bool pressed);
void toggleViewActionRipple(bool pressed);
void toggleReplyRipple(bool pressed);

View file

@ -72,6 +72,8 @@ namespace {
constexpr auto kMaxGifForwardedBarLines = 4;
constexpr auto kUseNonBlurredThreshold = 240;
constexpr auto kMaxInlineArea = 1920 * 1080;
constexpr auto kRightActionsMargin = 10;
constexpr auto kRightActionsMarginWide = 1;
[[nodiscard]] int GifMaxStatusWidth(not_null<DocumentData*> document) {
auto result = st::normalFont->width(
@ -851,15 +853,18 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
const auto rightActionWidth = size
? size->width()
: _transcribe->size().width();
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
auto fastShareLeft = rightLayout
? (paintx + usex - size->width() - st::historyFastShareLeft)
: (fullRight + st::historyFastShareLeft);
: (fullRight + st::historyFastShareLeft - margin);
auto fastShareTop = fullBottom
- st::historyFastShareBottom
- (size ? size->height() : 0);
if (fastShareLeft + rightActionWidth > maxRight) {
if (fastShareLeft + rightActionWidth * 2 > maxRight) {
fastShareLeft = fullRight
- rightActionWidth
- rightActionWidth * 2
- st::msgDateImgDelta;
fastShareTop -= st::msgDateImgDelta
+ st::msgDateImgPadding.y()
@ -1335,24 +1340,40 @@ TextState Gif::textState(QPoint point, StateRequest request) const {
}
if (const auto size = bubble ? std::nullopt : _parent->rightActionSize()) {
const auto rightActionWidth = size->width();
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
auto fastShareLeft = _parent->hasRightLayout()
? (paintx + usex - size->width() - st::historyFastShareLeft)
: (fullRight + st::historyFastShareLeft);
: (fullRight + st::historyFastShareLeft - margin);
auto fastShareTop = fullBottom
- st::historyFastShareBottom
- size->height();
if (fastShareLeft + rightActionWidth > maxRight) {
if (fastShareLeft + rightActionWidth * 2 > maxRight) {
fastShareLeft = fullRight
- rightActionWidth
- rightActionWidth * 2
- st::msgDateImgDelta;
fastShareTop -= st::msgDateImgDelta
+ st::msgDateImgPadding.y()
+ st::msgDateFont->height
+ st::msgDateImgPadding.y();
}
if (QRect(QPoint(fastShareLeft, fastShareTop), *size).contains(point)) {
const auto fastShareRect = QRect(
fastShareLeft,
fastShareTop,
size->width(),
size->height());
const auto viewRect = QRect(
fastShareLeft + size->width() + st::historyFastShareLeft,
fastShareTop,
size->width(),
size->height());
if (fastShareRect.contains(point)) {
result.link = _parent->rightActionLink(point
- QPoint(fastShareLeft, fastShareTop));
} else if (viewRect.contains(point)) {
result.link = _parent->viewActionLink(point
- QPoint(viewRect.x(), fastShareTop));
}
}
if (_transcribe && _transcribe->contains(point)) {

View file

@ -28,6 +28,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView {
namespace {
constexpr auto kRightActionsMargin = 10;
constexpr auto kRightActionsMarginWide = 1;
constexpr auto kUntilOffPeriod = std::numeric_limits<TimeId>::max();
constexpr auto kLiveElapsedPartOpacity = 0.2;
@ -464,9 +466,12 @@ void Location::draw(Painter &p, const PaintContext &context) const {
paintx * 2 + paintw,
InfoDisplayType::Image);
if (const auto size = bubble ? std::nullopt : _parent->rightActionSize()) {
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
auto fastShareLeft = _parent->hasRightLayout()
? (paintx - size->width() - st::historyFastShareLeft)
: (fullRight + st::historyFastShareLeft);
: (fullRight + st::historyFastShareLeft - margin);
auto fastShareTop = (fullBottom - st::historyFastShareBottom - size->height());
_parent->drawRightAction(p, context, fastShareLeft, fastShareTop, 2 * paintx + paintw);
}
@ -669,9 +674,12 @@ TextState Location::textState(QPoint point, StateRequest request) const {
return bottomInfoResult;
}
if (const auto size = bubble ? std::nullopt : _parent->rightActionSize()) {
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
auto fastShareLeft = _parent->hasRightLayout()
? (paintx - size->width() - st::historyFastShareLeft)
: (fullRight + st::historyFastShareLeft);
: (fullRight + st::historyFastShareLeft - margin);
auto fastShareTop = (fullBottom - st::historyFastShareBottom - size->height());
if (QRect(fastShareLeft, fastShareTop, size->width(), size->height()).contains(point)) {
result.link = _parent->rightActionLink(point

View file

@ -30,6 +30,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace HistoryView {
namespace {
constexpr auto kRightActionsMargin = 10;
constexpr auto kRightActionsMarginWide = 1;
std::vector<Ui::GroupMediaLayout> LayoutPlaylist(
const std::vector<QSize> &sizes) {
Expects(!sizes.empty());
@ -472,9 +474,12 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
InfoDisplayType::Image);
}
if (const auto size = _parent->hasBubble() ? std::nullopt : _parent->rightActionSize()) {
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
auto fastShareLeft = _parent->hasRightLayout()
? (-size->width() - st::historyFastShareLeft)
: (fullRight + st::historyFastShareLeft);
: (fullRight + st::historyFastShareLeft - margin);
auto fastShareTop = (fullBottom - st::historyFastShareBottom - size->height());
_parent->drawRightAction(p, context, fastShareLeft, fastShareTop, width());
}
@ -539,13 +544,29 @@ TextState GroupedMedia::textState(QPoint point, StateRequest request) const {
return bottomInfoResult;
}
if (const auto size = _parent->hasBubble() ? std::nullopt : _parent->rightActionSize()) {
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
auto fastShareLeft = _parent->hasRightLayout()
? (-size->width() - st::historyFastShareLeft)
: (fullRight + st::historyFastShareLeft);
: (fullRight + st::historyFastShareLeft - margin);
auto fastShareTop = (fullBottom - st::historyFastShareBottom - size->height());
if (QRect(fastShareLeft, fastShareTop, size->width(), size->height()).contains(point)) {
const auto fastShareRect = QRect(
fastShareLeft,
fastShareTop,
size->width(),
size->height());
const auto viewRect = QRect(
fastShareLeft + size->width() + st::historyFastShareLeft,
fastShareTop,
size->width(),
size->height());
if (fastShareRect.contains(point)) {
result.link = _parent->rightActionLink(point
- QPoint(fastShareLeft, fastShareTop));
} else if (viewRect.contains(point)) {
result.link = _parent->viewActionLink(point
- QPoint(viewRect.x(), fastShareTop));
}
}
}

View file

@ -30,6 +30,8 @@ namespace HistoryView {
namespace {
constexpr auto kMaxForwardedBarLines = 4;
constexpr auto kRightActionsMargin = 10;
constexpr auto kRightActionsMarginWide = 1;
} // namespace
@ -520,8 +522,21 @@ TextState UnwrappedMedia::textState(QPoint point, StateRequest request) const {
fullBottom,
fullRight,
*rightActionSize);
if (QRect(position.x(), position.y(), rightActionSize->width(), rightActionSize->height()).contains(point)) {
const auto fastShareRect = QRect(
position.x(),
position.y(),
rightActionSize->width(),
rightActionSize->height());
const auto viewRect = QRect(
position.x() + rightActionSize->width() + st::historyFastShareLeft,
position.y(),
rightActionSize->width(),
rightActionSize->height());
if (fastShareRect.contains(point)) {
result.link = _parent->rightActionLink(point - position);
return result;
} else if (viewRect.contains(point)) {
result.link = _parent->viewActionLink(point - QPoint(viewRect.x(), position.y()));
return result;
}
}
@ -604,8 +619,8 @@ int UnwrappedMedia::calculateFullRight(const QRect &inner) const {
? st::msgMargin.right()
: st::msgPadding.right());
const auto rightActionWidth = rightActionSize
? (st::historyFastShareLeft * 2
+ rightActionSize->width())
? (st::historyFastShareLeft * 3
+ rightActionSize->width() * 2)
: 0;
auto fullRight = inner.x()
+ inner.width()
@ -633,12 +648,15 @@ QPoint UnwrappedMedia::calculateFastActionPosition(
- size.height());
const auto doesRightActionHitReply = replyRight
&& (fastShareTop < replyHeight);
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
const auto fastShareLeft = rightAligned
? ((doesRightActionHitReply ? replyLeft : inner.x())
- size.width()
- st::historyFastShareLeft)
: ((doesRightActionHitReply ? replyRight : fullRight)
+ st::historyFastShareLeft);
+ st::historyFastShareLeft - margin);
return QPoint(fastShareLeft, fastShareTop);
}

View file

@ -54,6 +54,8 @@ namespace {
constexpr auto kStoryWidth = 720;
constexpr auto kStoryHeight = 1280;
constexpr auto kRightActionsMargin = 10;
constexpr auto kRightActionsMarginWide = 1;
using Data::PhotoSize;
@ -418,9 +420,12 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
InfoDisplayType::Image);
}
if (const auto size = bubble ? std::nullopt : _parent->rightActionSize()) {
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
auto fastShareLeft = _parent->hasRightLayout()
? (paintx - size->width() - st::historyFastShareLeft)
: (fullRight + st::historyFastShareLeft);
: (fullRight + st::historyFastShareLeft - margin);
auto fastShareTop = (fullBottom - st::historyFastShareBottom - size->height());
_parent->drawRightAction(p, context, fastShareLeft, fastShareTop, 2 * paintx + paintw);
}
@ -700,13 +705,29 @@ TextState Photo::textState(QPoint point, StateRequest request) const {
return bottomInfoResult;
}
if (const auto size = bubble ? std::nullopt : _parent->rightActionSize()) {
const auto margin = _parent->delegate()->elementIsChatWide()
? kRightActionsMarginWide
: kRightActionsMargin;
auto fastShareLeft = _parent->hasRightLayout()
? (paintx - size->width() - st::historyFastShareLeft)
: (fullRight + st::historyFastShareLeft);
: (fullRight + st::historyFastShareLeft - margin);
auto fastShareTop = (fullBottom - st::historyFastShareBottom - size->height());
if (QRect(fastShareLeft, fastShareTop, size->width(), size->height()).contains(point)) {
const auto fastShareRect = QRect(
fastShareLeft,
fastShareTop,
size->width(),
size->height());
const auto viewRect = QRect(
fastShareLeft + size->width() + st::historyFastShareLeft,
fastShareTop,
size->width(),
size->height());
if (fastShareRect.contains(point)) {
result.link = _parent->rightActionLink(point
- QPoint(fastShareLeft, fastShareTop));
} else if (viewRect.contains(point)) {
result.link = _parent->viewActionLink(point
- QPoint(viewRect.x(), fastShareTop));
}
}
}

View file

@ -569,6 +569,7 @@ historyFastShareSize: 31px;
historyFastShareLeft: 13px;
historyFastShareBottom: 5px;
historyFastShareIcon: icon {{ "fast_share", msgServiceFg }};
historyFastViewIcon: icon {{ "history_views", msgServiceFg }};
historyGoToOriginalIcon: icon {{ "filled_go_to_message", msgServiceFg, point(0px, 0px) }};
historyFastCommentsIcon: icon {{ "fast_comments", msgServiceFg }};
historyFastCloseSize: 30px;

View file

@ -201,6 +201,7 @@ ChatStyle::ChatStyle(rpl::producer<ColorIndicesCompressed> colorIndices) {
make(_msgBotKbCopyIcon, st::msgBotKbCopyIcon);
make(_historyFastCommentsIcon, st::historyFastCommentsIcon);
make(_historyFastShareIcon, st::historyFastShareIcon);
make(_historyFastViewIcon, st::historyFastViewIcon);
make(_historyFastTranscribeIcon, st::historyFastTranscribeIcon);
make(_historyFastTranscribeLock, st::historyFastTranscribeLock);
make(_historyGoToOriginalIcon, st::historyGoToOriginalIcon);

View file

@ -406,6 +406,9 @@ public:
[[nodiscard]] const style::icon &historyFastShareIcon() const {
return _historyFastShareIcon;
}
[[nodiscard]] const style::icon &historyFastViewIcon() const {
return _historyFastViewIcon;
}
[[nodiscard]] const style::icon &historyFastTranscribeIcon() const {
return _historyFastTranscribeIcon;
}
@ -545,6 +548,7 @@ private:
style::icon _msgBotKbCopyIcon = { Qt::Uninitialized };
style::icon _historyFastCommentsIcon = { Qt::Uninitialized };
style::icon _historyFastShareIcon = { Qt::Uninitialized };
style::icon _historyFastViewIcon = { Qt::Uninitialized };
style::icon _historyFastMoreIcon = { Qt::Uninitialized };
style::icon _historyFastTranscribeIcon = { Qt::Uninitialized };
style::icon _historyFastTranscribeLock = { Qt::Uninitialized };