PoC content outside of PopupMenu.
This commit is contained in:
parent
c20ed7c7a8
commit
a0d5456a4d
|
@ -512,9 +512,10 @@ groupCallMenu: Menu(defaultMenu) {
|
|||
itemFgShortcutOver: groupCallMemberNotJoinedStatus;
|
||||
itemFgShortcutDisabled: groupCallMemberNotJoinedStatus;
|
||||
|
||||
separatorFg: groupCallMenuBgOver;
|
||||
separatorPadding: margins(0px, 4px, 0px, 4px);
|
||||
|
||||
separator: MenuSeparator(defaultMenuSeparator) {
|
||||
padding: margins(0px, 4px, 0px, 4px);
|
||||
fg: groupCallMenuBgOver;
|
||||
}
|
||||
arrow: icon {{ "dropdown_submenu_arrow", groupCallMemberNotJoinedStatus }};
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
|
|
|
@ -50,7 +50,7 @@ bool CoverItem::isEnabled() const {
|
|||
}
|
||||
|
||||
int CoverItem::contentHeight() const {
|
||||
return _st.size + st::groupCallMenu.separatorPadding.bottom();
|
||||
return _st.size + st::groupCallMenu.separator.padding.bottom();
|
||||
}
|
||||
|
||||
AboutItem::AboutItem(
|
||||
|
|
|
@ -311,3 +311,6 @@ inlineRadialSize: 44px;
|
|||
inlineFileSize: 44px;
|
||||
|
||||
stickersPremiumLock: icon{{ "emoji/premium_lock", premiumButtonFg }};
|
||||
|
||||
reactStripExtend: margins(21px, 49px, 39px, 0px);
|
||||
reactStripHeight: 40px;
|
||||
|
|
|
@ -533,12 +533,20 @@ ReactionsFilter PeerReactionsFilter(not_null<PeerData*> peer) {
|
|||
});
|
||||
}
|
||||
|
||||
int UniqueReactionsLimit(not_null<Main::AppConfig*> config) {
|
||||
return config->get<int>("reactions_uniq_max", 11);
|
||||
}
|
||||
|
||||
int UniqueReactionsLimit(not_null<PeerData*> peer) {
|
||||
return UniqueReactionsLimit(&peer->session().account().appConfig());
|
||||
}
|
||||
|
||||
rpl::producer<int> UniqueReactionsLimitValue(
|
||||
not_null<Main::Session*> session) {
|
||||
const auto config = &session->account().appConfig();
|
||||
return config->value(
|
||||
) | rpl::map([=] {
|
||||
return config->get<int>("reactions_uniq_max", 11);
|
||||
return UniqueReactionsLimit(config);
|
||||
}) | rpl::distinct_until_changed();
|
||||
}
|
||||
|
||||
|
|
|
@ -138,6 +138,7 @@ inline auto PeerFullFlagValue(
|
|||
[[nodiscard]] rpl::producer<ReactionsFilter> PeerReactionsFilterValue(
|
||||
not_null<PeerData*> peer);
|
||||
|
||||
[[nodiscard]] int UniqueReactionsLimit(not_null<PeerData*> peer);
|
||||
[[nodiscard]] rpl::producer<int> UniqueReactionsLimitValue(
|
||||
not_null<Main::Session*> session);
|
||||
|
||||
|
|
|
@ -2040,11 +2040,7 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
e->accept();
|
||||
return;
|
||||
}
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(
|
||||
this,
|
||||
(hasWhoReactedItem
|
||||
? st::popupMenuExpandedSeparator
|
||||
: st::popupMenuWithIcons));
|
||||
_menu = base::make_unique_q<Ui::PopupMenu>(this, st::popupMenuWithIcons);
|
||||
const auto session = &this->session();
|
||||
const auto controller = _controller;
|
||||
const auto groupLeaderOrSelf = [](HistoryItem *item) -> HistoryItem* {
|
||||
|
@ -2451,10 +2447,25 @@ void HistoryInner::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
|||
|
||||
if (_menu->empty()) {
|
||||
_menu = nullptr;
|
||||
} else {
|
||||
_menu->popup(e->globalPos());
|
||||
e->accept();
|
||||
return;
|
||||
}
|
||||
using namespace HistoryView::Reactions;
|
||||
const auto desiredPosition = e->globalPos();
|
||||
const auto reactItem = Element::Hovered()
|
||||
? Element::Hovered()->data().get()
|
||||
: nullptr;
|
||||
const auto attached = reactItem
|
||||
? AttachSelectorToMenu(_menu.get(), desiredPosition, reactItem)
|
||||
: AttachSelectorResult::Skipped;
|
||||
if (attached == AttachSelectorResult::Failed) {
|
||||
_menu = nullptr;
|
||||
return;
|
||||
} else if (attached == AttachSelectorResult::Attached) {
|
||||
_menu->popupPrepared();
|
||||
} else {
|
||||
_menu->popup(desiredPosition);
|
||||
}
|
||||
e->accept();
|
||||
}
|
||||
|
||||
bool HistoryInner::hasCopyRestriction(HistoryItem *item) const {
|
||||
|
|
|
@ -952,9 +952,7 @@ base::unique_qptr<Ui::PopupMenu> FillContextMenu(
|
|||
|
||||
auto result = base::make_unique_q<Ui::PopupMenu>(
|
||||
list,
|
||||
(hasWhoReactedItem
|
||||
? st::popupMenuExpandedSeparator
|
||||
: st::popupMenuWithIcons));
|
||||
st::popupMenuWithIcons);
|
||||
|
||||
if (request.overSelection && !list->hasCopyRestrictionForSelected()) {
|
||||
const auto text = request.selectedItems.empty()
|
||||
|
@ -1158,7 +1156,7 @@ void AddWhoReactedAction(
|
|||
}
|
||||
};
|
||||
if (!menu->empty()) {
|
||||
menu->addSeparator();
|
||||
menu->addSeparator(&st::expandedMenuSeparator);
|
||||
}
|
||||
menu->addAction(Ui::WhoReactedContextAction(
|
||||
menu.get(),
|
||||
|
|
|
@ -9,10 +9,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "history/view/history_view_react_button.h"
|
||||
#include "data/data_document.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_message_reactions.h"
|
||||
#include "data/data_peer_values.h"
|
||||
#include "chat_helpers/tabbed_panel.h"
|
||||
#include "chat_helpers/tabbed_selector.h"
|
||||
#include "ui/widgets/popup_menu.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "window/window_session_controller.h"
|
||||
#include "window/window_controller.h"
|
||||
#include "main/main_session.h"
|
||||
#include "mainwindow.h"
|
||||
#include "styles/style_chat_helpers.h"
|
||||
|
||||
|
@ -104,4 +111,175 @@ void Selector::hide(anim::type animated) {
|
|||
}
|
||||
}
|
||||
|
||||
PopupSelector::PopupSelector(
|
||||
not_null<QWidget*> parent,
|
||||
PossibleReactions reactions)
|
||||
: RpWidget(parent) {
|
||||
}
|
||||
|
||||
int PopupSelector::countWidth(int desiredWidth, int maxWidth) {
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
QMargins PopupSelector::extentsForShadow() const {
|
||||
return st::defaultPopupMenu.shadow.extend;
|
||||
}
|
||||
|
||||
int PopupSelector::extendTopForCategories() const {
|
||||
return st::emojiFooterHeight;
|
||||
}
|
||||
|
||||
int PopupSelector::desiredHeight() const {
|
||||
return st::emojiPanMaxHeight;
|
||||
}
|
||||
|
||||
void PopupSelector::paintEvent(QPaintEvent *e) {
|
||||
QPainter(this).fillRect(e->rect(), QColor(0, 128, 0, 128));
|
||||
}
|
||||
|
||||
[[nodiscard]] PossibleReactions LookupPossibleReactions(
|
||||
not_null<HistoryItem*> item) {
|
||||
if (!item->canReact()) {
|
||||
return {};
|
||||
}
|
||||
auto result = PossibleReactions();
|
||||
const auto peer = item->history()->peer;
|
||||
const auto session = &peer->session();
|
||||
const auto reactions = &session->data().reactions();
|
||||
const auto &full = reactions->list(Data::Reactions::Type::Active);
|
||||
const auto &all = item->reactions();
|
||||
const auto my = item->chosenReaction();
|
||||
auto myIsUnique = false;
|
||||
for (const auto &[id, count] : all) {
|
||||
if (count == 1 && id == my) {
|
||||
myIsUnique = true;
|
||||
}
|
||||
}
|
||||
const auto notMineCount = int(all.size()) - (myIsUnique ? 1 : 0);
|
||||
const auto limit = Data::UniqueReactionsLimit(peer);
|
||||
if (limit > 0 && notMineCount >= limit) {
|
||||
result.recent.reserve(all.size());
|
||||
for (const auto &reaction : full) {
|
||||
const auto id = reaction.id;
|
||||
if (all.contains(id)) {
|
||||
result.recent.push_back(id);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const auto filter = Data::PeerReactionsFilter(peer);
|
||||
result.recent.reserve(filter.allowed
|
||||
? filter.allowed->size()
|
||||
: full.size());
|
||||
for (const auto &reaction : full) {
|
||||
const auto id = reaction.id;
|
||||
const auto emoji = filter.allowed ? id.emoji() : QString();
|
||||
if (filter.allowed
|
||||
&& (emoji.isEmpty() || !filter.allowed->contains(emoji))) {
|
||||
continue;
|
||||
} else if (reaction.premium
|
||||
&& !session->premium()
|
||||
&& !all.contains(id)) {
|
||||
if (session->premiumPossible()) {
|
||||
result.morePremiumAvailable = true;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
result.recent.push_back(id);
|
||||
}
|
||||
}
|
||||
result.customAllowed = peer->isUser();
|
||||
}
|
||||
const auto i = ranges::find(result.recent, reactions->favorite());
|
||||
if (i != end(result.recent) && i != begin(result.recent)) {
|
||||
std::rotate(begin(result.recent), i, i + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool SetupSelectorInMenuGeometry(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
QPoint desiredPosition,
|
||||
not_null<PopupSelector*> selector) {
|
||||
const auto extend = st::reactStripExtend;
|
||||
const auto added = extend.left() + extend.right();
|
||||
const auto desiredWidth = menu->width() + added;
|
||||
const auto maxWidth = menu->st().menu.widthMax + added;
|
||||
const auto width = selector->countWidth(desiredWidth, maxWidth);
|
||||
const auto extents = selector->extentsForShadow();
|
||||
const auto categoriesTop = selector->extendTopForCategories();
|
||||
menu->setForceWidth(width - added);
|
||||
const auto height = menu->height();
|
||||
const auto fullTop = extents.top() + categoriesTop + extend.top();
|
||||
const auto minimalHeight = extents.top()
|
||||
+ std::min(
|
||||
selector->desiredHeight(),
|
||||
categoriesTop + st::emojiPanMinHeight / 2)
|
||||
+ extents.bottom();
|
||||
const auto willBeHeightWithoutBottomPadding = fullTop
|
||||
+ height
|
||||
- menu->st().shadow.extend.top();
|
||||
const auto additionalPaddingBottom
|
||||
= (willBeHeightWithoutBottomPadding < minimalHeight
|
||||
? (minimalHeight - willBeHeightWithoutBottomPadding)
|
||||
: 0);
|
||||
menu->setAdditionalMenuPadding(QMargins(
|
||||
extents.left() + extend.left(),
|
||||
fullTop,
|
||||
extents.right() + extend.right(),
|
||||
additionalPaddingBottom
|
||||
), QMargins(
|
||||
extents.left(),
|
||||
extents.top(),
|
||||
extents.right(),
|
||||
std::min(additionalPaddingBottom, extents.bottom())
|
||||
));
|
||||
if (!menu->prepareGeometryFor(desiredPosition)) {
|
||||
return false;
|
||||
}
|
||||
const auto origin = menu->preparedOrigin();
|
||||
if (!additionalPaddingBottom
|
||||
|| origin == Ui::PanelAnimation::Origin::TopLeft
|
||||
|| origin == Ui::PanelAnimation::Origin::TopRight) {
|
||||
return true;
|
||||
}
|
||||
menu->setAdditionalMenuPadding(QMargins(
|
||||
extents.left() + extend.left(),
|
||||
fullTop + additionalPaddingBottom,
|
||||
extents.right() + extend.right(),
|
||||
0
|
||||
), QMargins(
|
||||
extents.left(),
|
||||
extents.top(),
|
||||
extents.right(),
|
||||
0
|
||||
));
|
||||
return menu->prepareGeometryFor(desiredPosition);
|
||||
}
|
||||
|
||||
AttachSelectorResult AttachSelectorToMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
QPoint desiredPosition,
|
||||
not_null<HistoryItem*> item) {
|
||||
auto reactions = LookupPossibleReactions(item);
|
||||
if (reactions.recent.empty() && !reactions.morePremiumAvailable) {
|
||||
return AttachSelectorResult::Skipped;
|
||||
}
|
||||
const auto selector = Ui::CreateChild<PopupSelector>(
|
||||
menu.get(),
|
||||
std::move(reactions));
|
||||
if (!SetupSelectorInMenuGeometry(menu, desiredPosition, selector)) {
|
||||
return AttachSelectorResult::Failed;
|
||||
}
|
||||
const auto extents = selector->extentsForShadow();
|
||||
const auto categoriesTop = selector->extendTopForCategories();
|
||||
selector->setGeometry(
|
||||
extents.left(),
|
||||
menu->preparedPadding().top() - st::reactStripExtend.top(),
|
||||
menu->width() - extents.left() - extents.right(),
|
||||
st::reactStripHeight);
|
||||
selector->lower();
|
||||
selector->show();
|
||||
return AttachSelectorResult::Attached;
|
||||
}
|
||||
|
||||
} // namespace HistoryView::Reactions
|
||||
|
|
|
@ -9,6 +9,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "base/unique_qptr.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
#include "ui/rp_widget.h"
|
||||
|
||||
namespace Data {
|
||||
struct ReactionId;
|
||||
} // namespace Data
|
||||
|
||||
namespace ChatHelpers {
|
||||
class TabbedPanel;
|
||||
|
@ -18,6 +23,10 @@ namespace Window {
|
|||
class SessionController;
|
||||
} // namespace Window
|
||||
|
||||
namespace Ui {
|
||||
class PopupMenu;
|
||||
} // namespace Ui
|
||||
|
||||
namespace HistoryView::Reactions {
|
||||
|
||||
struct ChosenReaction;
|
||||
|
@ -44,4 +53,39 @@ private:
|
|||
|
||||
};
|
||||
|
||||
struct PossibleReactions {
|
||||
std::vector<Data::ReactionId> recent;
|
||||
bool morePremiumAvailable = false;
|
||||
bool customAllowed = false;
|
||||
};
|
||||
|
||||
class PopupSelector final : public Ui::RpWidget {
|
||||
public:
|
||||
PopupSelector(
|
||||
not_null<QWidget*> parent,
|
||||
PossibleReactions reactions);
|
||||
|
||||
int countWidth(int desiredWidth, int maxWidth);
|
||||
[[nodiscard]] QMargins extentsForShadow() const;
|
||||
[[nodiscard]] int extendTopForCategories() const;
|
||||
[[nodiscard]] int desiredHeight() const;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
private:
|
||||
int _columns = 0;
|
||||
|
||||
};
|
||||
|
||||
enum class AttachSelectorResult {
|
||||
Skipped,
|
||||
Failed,
|
||||
Attached,
|
||||
};
|
||||
AttachSelectorResult AttachSelectorToMenu(
|
||||
not_null<Ui::PopupMenu*> menu,
|
||||
QPoint desiredPosition,
|
||||
not_null<HistoryItem*> item);
|
||||
|
||||
} // namespace HistoryView::Reactions
|
||||
|
|
|
@ -148,7 +148,9 @@ mediaviewMenu: Menu(menuWithIcons) {
|
|||
itemFgShortcutOver: mediaviewMenuFg;
|
||||
itemFgShortcutDisabled: mediaviewMenuFg;
|
||||
|
||||
separatorFg: mediaviewMenuFg;
|
||||
separator: MenuSeparator(defaultMenuSeparator) {
|
||||
fg: mediaviewMenuFg;
|
||||
}
|
||||
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: mediaviewMenuBgRipple;
|
||||
|
@ -186,7 +188,9 @@ mediaviewControlsMenu: Menu(defaultMenu) {
|
|||
itemFgShortcutOver: mediaviewPlaybackProgressFg;
|
||||
itemFgShortcutDisabled: mediaviewPlaybackProgressFg;
|
||||
|
||||
separatorFg: mediaviewPlaybackIconRipple;
|
||||
separator: MenuSeparator(defaultMenuSeparator) {
|
||||
fg: mediaviewPlaybackIconRipple;
|
||||
}
|
||||
|
||||
arrow: icon {{ "dropdown_submenu_arrow", mediaviewPlaybackProgressFg }};
|
||||
|
||||
|
|
|
@ -857,8 +857,7 @@ void PipPanel::updateDecorations() {
|
|||
}
|
||||
});
|
||||
const auto position = countPosition();
|
||||
const auto center = position.geometry.center();
|
||||
const auto use = Ui::Platform::TranslucentWindowsSupported(center);
|
||||
const auto use = Ui::Platform::TranslucentWindowsSupported();
|
||||
const auto full = use ? st::callShadow.extend : style::margins();
|
||||
const auto padding = style::margins(
|
||||
(position.attached & RectPart::Left) ? 0 : full.left(),
|
||||
|
|
|
@ -936,10 +936,13 @@ ttlDividerLabelPadding: margins(22px, 10px, 22px, 19px);
|
|||
ttlItemPadding: margins(0px, 4px, 0px, 4px);
|
||||
ttlItemTimerFont: font(12px);
|
||||
|
||||
expandedMenuSeparator: MenuSeparator(defaultMenuSeparator) {
|
||||
padding: margins(0px, 4px, 0px, 4px);
|
||||
width: 6px;
|
||||
}
|
||||
popupMenuExpandedSeparator: PopupMenu(popupMenuWithIcons) {
|
||||
menu: Menu(menuWithIcons) {
|
||||
separatorPadding: margins(0px, 4px, 0px, 4px);
|
||||
separatorWidth: 6px;
|
||||
separator: expandedMenuSeparator;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit b2f2b7b6bce60bc1c6429a6b5ec4bc5891baa060
|
||||
Subproject commit 0e386e22cb6ba8a114b569840a635e096dcb645e
|
|
@ -1 +1 @@
|
|||
Subproject commit 1cc74a41c4d1c3fe9824e4bf47c23e3bcd1759e6
|
||||
Subproject commit a76cdf7edffb6e9cbef515a0e599c3c14a8a5b53
|
Loading…
Reference in New Issue
Block a user