mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Fix shortcut messages sizing / emoji panel.
This commit is contained in:
parent
aad8e989d8
commit
8545a14763
21 changed files with 253 additions and 82 deletions
|
@ -89,6 +89,9 @@ mtpRequestId EditMessage(
|
|||
: emptyFlag)
|
||||
| (options.scheduled
|
||||
? MTPmessages_EditMessage::Flag::f_schedule_date
|
||||
: emptyFlag)
|
||||
| (item->isBusinessShortcut()
|
||||
? MTPmessages_EditMessage::Flag::f_quick_reply_shortcut_id
|
||||
: emptyFlag);
|
||||
|
||||
const auto id = item->isScheduled()
|
||||
|
@ -105,7 +108,7 @@ mtpRequestId EditMessage(
|
|||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(options.scheduled),
|
||||
MTPint() // quick_reply_shortcut_id
|
||||
MTP_int(item->shortcutId())
|
||||
)).done([=](
|
||||
const MTPUpdates &result,
|
||||
[[maybe_unused]] mtpRequestId requestId) {
|
||||
|
|
|
@ -895,6 +895,7 @@ void EditCaptionBox::save() {
|
|||
|
||||
auto options = Api::SendOptions();
|
||||
options.scheduled = item->isScheduled() ? item->date() : 0;
|
||||
options.shortcutId = item->shortcutId();
|
||||
|
||||
if (!_preparedList.files.empty()) {
|
||||
if ((_albumType != Ui::AlbumType::None)
|
||||
|
|
|
@ -23,6 +23,7 @@ struct ComposeFeatures {
|
|||
bool autocompleteHashtags = true;
|
||||
bool autocompleteMentions = true;
|
||||
bool autocompleteCommands = true;
|
||||
bool commonTabbedPanel = true;
|
||||
};
|
||||
|
||||
} // namespace ChatHelpers
|
||||
|
|
|
@ -60,7 +60,8 @@ constexpr auto kRequestTimeLimit = 60 * crl::time(1000);
|
|||
MTP_int(data.vttl_period().value_or_empty()));
|
||||
}, [&](const MTPDmessage &data) {
|
||||
return MTP_message(
|
||||
MTP_flags(data.vflags().v | MTPDmessage::Flag::f_quick_reply_shortcut_id),
|
||||
MTP_flags(data.vflags().v
|
||||
| MTPDmessage::Flag::f_quick_reply_shortcut_id),
|
||||
data.vid(),
|
||||
data.vfrom_id() ? *data.vfrom_id() : MTPPeer(),
|
||||
MTPint(), // from_boosts_applied
|
||||
|
|
|
@ -96,6 +96,18 @@ public:
|
|||
[[nodiscard]] static constexpr DraftKey ScheduledEdit() {
|
||||
return kScheduledDraftIndex + kEditDraftShift;
|
||||
}
|
||||
[[nodiscard]] static constexpr DraftKey Shortcut(
|
||||
BusinessShortcutId shortcutId) {
|
||||
return (shortcutId < 0 || shortcutId >= ServerMaxMsgId)
|
||||
? None()
|
||||
: (kShortcutDraftShift + shortcutId);
|
||||
}
|
||||
[[nodiscard]] static constexpr DraftKey ShortcutEdit(
|
||||
BusinessShortcutId shortcutId) {
|
||||
return (shortcutId < 0 || shortcutId >= ServerMaxMsgId)
|
||||
? None()
|
||||
: (kShortcutDraftShift + kEditDraftShift + shortcutId);
|
||||
}
|
||||
|
||||
[[nodiscard]] static constexpr DraftKey FromSerialized(qint64 value) {
|
||||
return value;
|
||||
|
@ -156,6 +168,7 @@ private:
|
|||
static constexpr auto kScheduledDraftIndex = -3;
|
||||
static constexpr auto kEditDraftShift = ServerMaxMsgId.bare;
|
||||
static constexpr auto kCloudDraftShift = 2 * ServerMaxMsgId.bare;
|
||||
static constexpr auto kShortcutDraftShift = 3 * ServerMaxMsgId.bare;
|
||||
static constexpr auto kEditDraftShiftOld = 0x3FFF'FFFF;
|
||||
|
||||
int64 _value = 0;
|
||||
|
|
|
@ -108,6 +108,7 @@ struct EntryState {
|
|||
Replies,
|
||||
SavedSublist,
|
||||
ContextMenu,
|
||||
ShortcutMessages,
|
||||
};
|
||||
|
||||
Key key;
|
||||
|
|
|
@ -2108,7 +2108,7 @@ bool HistoryItem::allowsEdit(TimeId now) const {
|
|||
}
|
||||
|
||||
bool HistoryItem::canBeEdited() const {
|
||||
if ((!isRegular() && !isScheduled())
|
||||
if ((!isRegular() && !isScheduled() && !isBusinessShortcut())
|
||||
|| Has<HistoryMessageVia>()
|
||||
|| Has<HistoryMessageForwarded>()) {
|
||||
return false;
|
||||
|
|
|
@ -114,6 +114,9 @@ using ForwardPanel = Controls::ForwardPanel;
|
|||
|
||||
} // namespace
|
||||
|
||||
const ChatHelpers::PauseReason kDefaultPanelsLevel
|
||||
= ChatHelpers::PauseReason::TabbedPanel;
|
||||
|
||||
class FieldHeader final : public Ui::RpWidget {
|
||||
public:
|
||||
FieldHeader(
|
||||
|
@ -760,7 +763,10 @@ MessageToEdit FieldHeader::queryToEdit() {
|
|||
}
|
||||
return {
|
||||
.fullId = item->fullId(),
|
||||
.options = { .scheduled = item->isScheduled() ? item->date() : 0 },
|
||||
.options = {
|
||||
.scheduled = item->isScheduled() ? item->date() : 0,
|
||||
.shortcutId = item->shortcutId(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -788,21 +794,24 @@ ComposeControls::ComposeControls(
|
|||
: st::defaultComposeControls)
|
||||
, _features(descriptor.features)
|
||||
, _parent(parent)
|
||||
, _panelsParent(descriptor.panelsParent
|
||||
? descriptor.panelsParent
|
||||
: _parent.get())
|
||||
, _show(std::move(descriptor.show))
|
||||
, _session(&_show->session())
|
||||
, _regularWindow(descriptor.regularWindow)
|
||||
, _ownedSelector(_regularWindow
|
||||
, _ownedSelector((_regularWindow && _features.commonTabbedPanel)
|
||||
? nullptr
|
||||
: std::make_unique<ChatHelpers::TabbedSelector>(
|
||||
_parent,
|
||||
_panelsParent,
|
||||
ChatHelpers::TabbedSelectorDescriptor{
|
||||
.show = _show,
|
||||
.st = _st.tabbed,
|
||||
.level = Window::GifPauseReason::TabbedPanel,
|
||||
.level = descriptor.panelsLevel,
|
||||
.mode = ChatHelpers::TabbedSelector::Mode::Full,
|
||||
.features = _features,
|
||||
}))
|
||||
, _selector(_regularWindow
|
||||
, _selector((_regularWindow && _features.commonTabbedPanel)
|
||||
? _regularWindow->tabbedSelector()
|
||||
: not_null(_ownedSelector.get()))
|
||||
, _mode(descriptor.mode)
|
||||
|
@ -876,6 +885,12 @@ void ComposeControls::updateTopicRootId(MsgId topicRootId) {
|
|||
_header->updateTopicRootId(_topicRootId);
|
||||
}
|
||||
|
||||
void ComposeControls::updateShortcutId(BusinessShortcutId shortcutId) {
|
||||
unregisterDraftSources();
|
||||
_shortcutId = shortcutId;
|
||||
registerDraftSource();
|
||||
}
|
||||
|
||||
void ComposeControls::setHistory(SetHistoryArgs &&args) {
|
||||
_showSlowmodeError = std::move(args.showSlowmodeError);
|
||||
_sendActionFactory = std::move(args.sendActionFactory);
|
||||
|
@ -1592,7 +1607,7 @@ void ComposeControls::initField() {
|
|||
&& Data::AllowEmojiWithoutPremium(_history->peer, emoji);
|
||||
};
|
||||
const auto suggestions = Ui::Emoji::SuggestionsController::Init(
|
||||
_parent,
|
||||
_panelsParent,
|
||||
_field,
|
||||
_session,
|
||||
{
|
||||
|
@ -1828,6 +1843,10 @@ Data::DraftKey ComposeControls::draftKey(DraftType type) const {
|
|||
return (type == DraftType::Edit)
|
||||
? Key::ScheduledEdit()
|
||||
: Key::Scheduled();
|
||||
case Section::ShortcutMessages:
|
||||
return (type == DraftType::Edit)
|
||||
? Key::ShortcutEdit(_shortcutId)
|
||||
: Key::Shortcut(_shortcutId);
|
||||
}
|
||||
return Key::None();
|
||||
}
|
||||
|
@ -2053,7 +2072,9 @@ rpl::producer<SendActionUpdate> ComposeControls::sendActionUpdates() const {
|
|||
}
|
||||
|
||||
void ComposeControls::initTabbedSelector() {
|
||||
if (!_regularWindow || _regularWindow->hasTabbedSelectorOwnership()) {
|
||||
if (!_regularWindow
|
||||
|| !_features.commonTabbedPanel
|
||||
|| _regularWindow->hasTabbedSelectorOwnership()) {
|
||||
createTabbedPanel();
|
||||
} else {
|
||||
setTabbedPanel(nullptr);
|
||||
|
@ -2686,7 +2707,7 @@ void ComposeControls::updateAttachBotsMenu() {
|
|||
return;
|
||||
}
|
||||
_attachBotsMenu = InlineBots::MakeAttachBotsMenu(
|
||||
_parent,
|
||||
_panelsParent,
|
||||
_regularWindow,
|
||||
_history->peer,
|
||||
_sendActionFactory,
|
||||
|
@ -2729,7 +2750,7 @@ void ComposeControls::escape() {
|
|||
bool ComposeControls::pushTabbedSelectorToThirdSection(
|
||||
not_null<Data::Thread*> thread,
|
||||
const Window::SectionShow ¶ms) {
|
||||
if (!_tabbedPanel || !_regularWindow) {
|
||||
if (!_tabbedPanel || !_regularWindow || !_features.commonTabbedPanel) {
|
||||
return true;
|
||||
//} else if (!_canSendMessages) {
|
||||
// Core::App().settings().setTabbedReplacedWithInfo(true);
|
||||
|
@ -2764,7 +2785,7 @@ void ComposeControls::createTabbedPanel() {
|
|||
.nonOwnedSelector = _ownedSelector ? nullptr : _selector.get(),
|
||||
};
|
||||
setTabbedPanel(std::make_unique<TabbedPanel>(
|
||||
_parent,
|
||||
_panelsParent,
|
||||
std::move(descriptor)));
|
||||
_tabbedPanel->setDesiredHeightValues(
|
||||
st::emojiPanHeightRatio,
|
||||
|
@ -2787,7 +2808,7 @@ void ComposeControls::setTabbedPanel(
|
|||
}
|
||||
|
||||
void ComposeControls::toggleTabbedSelectorMode() {
|
||||
if (!_history || !_regularWindow) {
|
||||
if (!_history || !_regularWindow || !_features.commonTabbedPanel) {
|
||||
return;
|
||||
}
|
||||
if (_tabbedPanel) {
|
||||
|
@ -3248,7 +3269,7 @@ void ComposeControls::applyInlineBotQuery(
|
|||
}
|
||||
if (!_inlineResults) {
|
||||
_inlineResults = std::make_unique<InlineBots::Layout::Widget>(
|
||||
_parent,
|
||||
_panelsParent,
|
||||
_regularWindow);
|
||||
_inlineResults->setResultSelectedCallback([=](
|
||||
InlineBots::ResultSelected result) {
|
||||
|
|
|
@ -37,6 +37,7 @@ class TabbedSelector;
|
|||
struct FileChosen;
|
||||
struct PhotoChosen;
|
||||
class Show;
|
||||
enum class PauseReason;
|
||||
} // namespace ChatHelpers
|
||||
|
||||
namespace Data {
|
||||
|
@ -95,6 +96,8 @@ enum class ComposeControlsMode {
|
|||
Scheduled,
|
||||
};
|
||||
|
||||
extern const ChatHelpers::PauseReason kDefaultPanelsLevel;
|
||||
|
||||
struct ComposeControlsDescriptor {
|
||||
const style::ComposeControls *stOverride = nullptr;
|
||||
std::shared_ptr<ChatHelpers::Show> show;
|
||||
|
@ -104,6 +107,8 @@ struct ComposeControlsDescriptor {
|
|||
Window::SessionController *regularWindow = nullptr;
|
||||
rpl::producer<ChatHelpers::FileChosen> stickerOrEmojiChosen;
|
||||
rpl::producer<QString> customPlaceholder;
|
||||
QWidget *panelsParent = nullptr;
|
||||
ChatHelpers::PauseReason panelsLevel = kDefaultPanelsLevel;
|
||||
QString voiceCustomCancelText;
|
||||
bool voiceLockFromBottom = false;
|
||||
ChatHelpers::ComposeFeatures features;
|
||||
|
@ -137,6 +142,7 @@ public:
|
|||
[[nodiscard]] Main::Session &session() const;
|
||||
void setHistory(SetHistoryArgs &&args);
|
||||
void updateTopicRootId(MsgId topicRootId);
|
||||
void updateShortcutId(BusinessShortcutId shortcutId);
|
||||
void setCurrentDialogsEntryState(Dialogs::EntryState state);
|
||||
[[nodiscard]] PeerData *sendAsPeer() const;
|
||||
|
||||
|
@ -343,6 +349,7 @@ private:
|
|||
const style::ComposeControls &_st;
|
||||
const ChatHelpers::ComposeFeatures _features;
|
||||
const not_null<QWidget*> _parent;
|
||||
const not_null<QWidget*> _panelsParent;
|
||||
const std::shared_ptr<ChatHelpers::Show> _show;
|
||||
const not_null<Main::Session*> _session;
|
||||
|
||||
|
@ -353,6 +360,7 @@ private:
|
|||
|
||||
History *_history = nullptr;
|
||||
MsgId _topicRootId = 0;
|
||||
BusinessShortcutId _shortcutId = 0;
|
||||
Fn<bool()> _showSlowmodeError;
|
||||
Fn<Api::SendAction()> _sendActionFactory;
|
||||
rpl::variable<int> _slowmodeSecondsLeft;
|
||||
|
|
|
@ -551,7 +551,7 @@ void BottomInfo::layoutReactionsText() {
|
|||
|
||||
QSize BottomInfo::countOptimalSize() {
|
||||
if (_data.flags & Data::Flag::Shortcut) {
|
||||
return { st::historySendStateSpace / 2, st::msgDateFont->height };
|
||||
return { st::historyShortcutStateSpace, st::msgDateFont->height };
|
||||
}
|
||||
auto width = 0;
|
||||
if (_data.flags & (Data::Flag::OutLayout | Data::Flag::Sending)) {
|
||||
|
|
|
@ -102,7 +102,9 @@ bool HasEditMessageAction(
|
|||
|| item->hasFailed()
|
||||
|| item->isEditingMedia()
|
||||
|| !request.selectedItems.empty()
|
||||
|| (context != Context::History && context != Context::Replies)) {
|
||||
|| (context != Context::History
|
||||
&& context != Context::Replies
|
||||
&& context != Context::ShortcutMessages)) {
|
||||
return false;
|
||||
}
|
||||
const auto peer = item->history()->peer;
|
||||
|
|
|
@ -2166,6 +2166,21 @@ void ListWidget::paintEvent(QPaintEvent *e) {
|
|||
context.translate(0, top);
|
||||
p.translate(0, -top);
|
||||
|
||||
paintUserpics(p, context, clip);
|
||||
paintDates(p, context, clip);
|
||||
|
||||
_reactionsManager->paint(p, context);
|
||||
_emojiInteractions->paint(p);
|
||||
}
|
||||
|
||||
void ListWidget::paintUserpics(
|
||||
Painter &p,
|
||||
const Ui::ChatPaintContext &context,
|
||||
QRect clip) {
|
||||
if (_context == Context::ShortcutMessages) {
|
||||
return;
|
||||
}
|
||||
const auto session = &controller()->session();
|
||||
enumerateUserpics([&](not_null<Element*> view, int userpicTop) {
|
||||
// stop the enumeration if the userpic is below the painted rect
|
||||
if (userpicTop >= clip.top() + clip.height()) {
|
||||
|
@ -2210,6 +2225,15 @@ void ListWidget::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void ListWidget::paintDates(
|
||||
Painter &p,
|
||||
const Ui::ChatPaintContext &context,
|
||||
QRect clip) {
|
||||
if (_context == Context::ShortcutMessages) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto dateHeight = st::msgServicePadding.bottom() + st::msgServiceFont->height + st::msgServicePadding.top();
|
||||
auto scrollDateOpacity = _scrollDateOpacity.value(_scrollDateShown ? 1. : 0.);
|
||||
|
@ -2256,9 +2280,6 @@ void ListWidget::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
_reactionsManager->paint(p, context);
|
||||
_emojiInteractions->paint(p);
|
||||
}
|
||||
|
||||
void ListWidget::maybeMarkReactionsRead(not_null<HistoryItem*> item) {
|
||||
|
|
|
@ -600,6 +600,15 @@ private:
|
|||
void showPremiumStickerTooltip(
|
||||
not_null<const HistoryView::Element*> view);
|
||||
|
||||
void paintUserpics(
|
||||
Painter &p,
|
||||
const Ui::ChatPaintContext &context,
|
||||
QRect clip);
|
||||
void paintDates(
|
||||
Painter &p,
|
||||
const Ui::ChatPaintContext &context,
|
||||
QRect clip);
|
||||
|
||||
// This function finds all history items that are displayed and calls template method
|
||||
// for each found message (in given direction) in the passed history with passed top offset.
|
||||
//
|
||||
|
|
|
@ -167,7 +167,12 @@ Ui::RpWidget *ContentWidget::doSetInnerWidget(
|
|||
const auto bottom = top + height;
|
||||
_innerDesiredHeight = desired;
|
||||
_innerWrap->setVisibleTopBottom(top, bottom);
|
||||
LOG(("TOP: %1, HEIGHT: %2, DESIRED: %3, TILL: %4").arg(top).arg(height).arg(desired).arg(std::max(desired - bottom, 0)));
|
||||
_scrollTillBottomChanges.fire_copy(std::max(desired - bottom, 0));
|
||||
//const auto bottom = _scroll->scrollTop() + _scroll->height();
|
||||
//_innerDesiredHeight = desired;
|
||||
//_innerWrap->setVisibleTopBottom(_scroll->scrollTop(), bottom);
|
||||
//_scrollTillBottomChanges.fire_copy(std::max(desired - bottom, 0));
|
||||
}, _innerWrap->lifetime());
|
||||
|
||||
return _innerWrap->entity();
|
||||
|
@ -217,7 +222,12 @@ rpl::producer<int> ContentWidget::desiredHeightValue() const {
|
|||
_innerWrap->entity()->desiredHeightValue(),
|
||||
_scrollTopSkip.value(),
|
||||
_scrollBottomSkip.value()
|
||||
) | rpl::map(_1 + _2 + _3);
|
||||
//) | rpl::map(_1 + _2 + _3);
|
||||
) | rpl::map([=](int desired, int, int) {
|
||||
return desired
|
||||
+ _scrollTopSkip.current()
|
||||
+ _scrollBottomSkip.current();
|
||||
});
|
||||
}
|
||||
|
||||
rpl::producer<bool> ContentWidget::desiredShadowVisibility() const {
|
||||
|
|
|
@ -30,7 +30,7 @@ LayerWidget::LayerWidget(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<Memento*> memento)
|
||||
: _controller(controller)
|
||||
, _content(this, controller, Wrap::Layer, memento) {
|
||||
, _contentWrap(this, controller, Wrap::Layer, memento) {
|
||||
setupHeightConsumers();
|
||||
controller->window().replaceFloatPlayerDelegate(floatPlayerDelegate());
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ LayerWidget::LayerWidget(
|
|||
not_null<Window::SessionController*> controller,
|
||||
not_null<MoveMemento*> memento)
|
||||
: _controller(controller)
|
||||
, _content(memento->takeContent(this, Wrap::Layer)) {
|
||||
, _contentWrap(memento->takeContent(this, Wrap::Layer)) {
|
||||
setupHeightConsumers();
|
||||
controller->window().replaceFloatPlayerDelegate(floatPlayerDelegate());
|
||||
}
|
||||
|
@ -64,17 +64,17 @@ void LayerWidget::floatPlayerToggleGifsPaused(bool paused) {
|
|||
|
||||
auto LayerWidget::floatPlayerGetSection(Window::Column column)
|
||||
-> not_null<::Media::Player::FloatSectionDelegate*> {
|
||||
Expects(_content != nullptr);
|
||||
Expects(_contentWrap != nullptr);
|
||||
|
||||
return _content;
|
||||
return _contentWrap;
|
||||
}
|
||||
|
||||
void LayerWidget::floatPlayerEnumerateSections(Fn<void(
|
||||
not_null<::Media::Player::FloatSectionDelegate*> widget,
|
||||
Window::Column widgetColumn)> callback) {
|
||||
Expects(_content != nullptr);
|
||||
Expects(_contentWrap != nullptr);
|
||||
|
||||
callback(_content, Window::Column::Second);
|
||||
callback(_contentWrap, Window::Column::Second);
|
||||
}
|
||||
|
||||
bool LayerWidget::floatPlayerIsVisible(not_null<HistoryItem*> item) {
|
||||
|
@ -87,9 +87,9 @@ void LayerWidget::floatPlayerDoubleClickEvent(
|
|||
}
|
||||
|
||||
void LayerWidget::setupHeightConsumers() {
|
||||
Expects(_content != nullptr);
|
||||
Expects(_contentWrap != nullptr);
|
||||
|
||||
_content->scrollTillBottomChanges(
|
||||
_contentWrap->scrollTillBottomChanges(
|
||||
) | rpl::filter([this] {
|
||||
if (!_inResize) {
|
||||
return true;
|
||||
|
@ -100,10 +100,10 @@ void LayerWidget::setupHeightConsumers() {
|
|||
resizeToWidth(width());
|
||||
}, lifetime());
|
||||
|
||||
_content->grabbingForExpanding(
|
||||
_contentWrap->grabbingForExpanding(
|
||||
) | rpl::start_with_next([=](bool grabbing) {
|
||||
if (grabbing) {
|
||||
_savedHeight = _contentHeight;
|
||||
_savedHeight = _contentWrapHeight;
|
||||
_savedHeightAnimation = base::take(_heightAnimation);
|
||||
setContentHeight(_desiredHeight);
|
||||
} else {
|
||||
|
@ -112,7 +112,7 @@ void LayerWidget::setupHeightConsumers() {
|
|||
}
|
||||
}, lifetime());
|
||||
|
||||
_content->desiredHeightValue(
|
||||
_contentWrap->desiredHeightValue(
|
||||
) | rpl::start_with_next([this](int height) {
|
||||
if (!height) {
|
||||
// New content arrived.
|
||||
|
@ -128,32 +128,32 @@ void LayerWidget::setupHeightConsumers() {
|
|||
_heightAnimated = true;
|
||||
_heightAnimation.start([=] {
|
||||
setContentHeight(_heightAnimation.value(_desiredHeight));
|
||||
}, _contentHeight, _desiredHeight, st::slideDuration);
|
||||
}, _contentWrapHeight, _desiredHeight, st::slideDuration);
|
||||
resizeToWidth(width());
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
void LayerWidget::setContentHeight(int height) {
|
||||
if (_contentHeight == height) {
|
||||
if (_contentWrapHeight == height) {
|
||||
return;
|
||||
}
|
||||
|
||||
_contentHeight = height;
|
||||
LOG(("CONTENT WRAP HEIGHT: %1 -> %2").arg(_contentWrapHeight).arg(height));
|
||||
_contentWrapHeight = height;
|
||||
if (_inResize) {
|
||||
_pendingResize = true;
|
||||
} else if (_content) {
|
||||
} else if (_contentWrap) {
|
||||
resizeToWidth(width());
|
||||
}
|
||||
}
|
||||
|
||||
void LayerWidget::showFinished() {
|
||||
floatPlayerShowVisible();
|
||||
_content->showFast();
|
||||
_contentWrap->showFast();
|
||||
}
|
||||
|
||||
void LayerWidget::parentResized() {
|
||||
if (!_content) {
|
||||
if (!_contentWrap) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ void LayerWidget::parentResized() {
|
|||
Ui::FocusPersister persister(this);
|
||||
restoreFloatPlayerDelegate();
|
||||
|
||||
auto memento = std::make_shared<MoveMemento>(std::move(_content));
|
||||
auto memento = std::make_shared<MoveMemento>(std::move(_contentWrap));
|
||||
|
||||
// We want to call hideSpecialLayer synchronously to avoid glitches,
|
||||
// but we can't destroy LayerStackWidget from its' resizeEvent,
|
||||
|
@ -209,7 +209,7 @@ bool LayerWidget::takeToThirdSection() {
|
|||
//
|
||||
//Ui::FocusPersister persister(this);
|
||||
//auto localCopy = _controller;
|
||||
//auto memento = MoveMemento(std::move(_content));
|
||||
//auto memento = MoveMemento(std::move(_contentWrap));
|
||||
//localCopy->hideSpecialLayer(anim::type::instant);
|
||||
|
||||
//// When creating third section in response to the window
|
||||
|
@ -235,7 +235,7 @@ bool LayerWidget::takeToThirdSection() {
|
|||
bool LayerWidget::showSectionInternal(
|
||||
not_null<Window::SectionMemento*> memento,
|
||||
const Window::SectionShow ¶ms) {
|
||||
if (_content && _content->showInternal(memento, params)) {
|
||||
if (_contentWrap && _contentWrap->showInternal(memento, params)) {
|
||||
if (params.activation != anim::activation::background) {
|
||||
_controller->parentController()->hideLayer();
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ bool LayerWidget::showSectionInternal(
|
|||
}
|
||||
|
||||
bool LayerWidget::closeByOutsideClick() const {
|
||||
return _content ? _content->closeByOutsideClick() : true;
|
||||
return _contentWrap ? _contentWrap->closeByOutsideClick() : true;
|
||||
}
|
||||
|
||||
int LayerWidget::MinimalSupportedWidth() {
|
||||
|
@ -254,19 +254,48 @@ int LayerWidget::MinimalSupportedWidth() {
|
|||
}
|
||||
|
||||
int LayerWidget::resizeGetHeight(int newWidth) {
|
||||
if (!parentWidget() || !_content || !newWidth) {
|
||||
if (!parentWidget() || !_contentWrap || !newWidth) {
|
||||
return 0;
|
||||
}
|
||||
constexpr auto kMaxAttempts = 16;
|
||||
auto attempts = 0;
|
||||
while (true) {
|
||||
_inResize = true;
|
||||
{
|
||||
const auto &parentSize = parentWidget()->size();
|
||||
const auto windowWidth = parentSize.width();
|
||||
const auto windowHeight = parentSize.height();
|
||||
const auto newLeft = (windowWidth - newWidth) / 2;
|
||||
const auto newTop = std::clamp(
|
||||
windowHeight / 24,
|
||||
st::infoLayerTopMinimal,
|
||||
st::infoLayerTopMaximal);
|
||||
const auto newBottom = newTop;
|
||||
|
||||
const auto bottomRadius = st::boxRadius;
|
||||
const auto maxVisibleHeight = windowHeight - newTop;
|
||||
// Top rounding is included in _contentWrapHeight.
|
||||
auto desiredHeight = _contentWrapHeight + bottomRadius;
|
||||
accumulate_min(desiredHeight, maxVisibleHeight - newBottom);
|
||||
|
||||
// First resize content to new width and get the new desired height.
|
||||
const auto contentLeft = 0;
|
||||
const auto contentTop = 0;
|
||||
const auto contentBottom = bottomRadius;
|
||||
const auto contentWidth = newWidth;
|
||||
auto contentHeight = desiredHeight - contentTop - contentBottom;
|
||||
LOG(("ATTEMPT %1: WIDTH %2, WRAP HEIGHT %3, SCROLL TILL BOTTOM: %4"
|
||||
).arg(attempts + 1
|
||||
).arg(newWidth
|
||||
).arg(_contentWrapHeight
|
||||
).arg(_contentWrap->scrollTillBottom(contentHeight)));
|
||||
}
|
||||
const auto newGeometry = countGeometry(newWidth);
|
||||
_inResize = false;
|
||||
if (!_pendingResize) {
|
||||
const auto oldGeometry = geometry();
|
||||
if (newGeometry != oldGeometry) {
|
||||
_content->forceContentRepaint();
|
||||
_contentWrap->forceContentRepaint();
|
||||
}
|
||||
if (newGeometry.topLeft() != oldGeometry.topLeft()) {
|
||||
move(newGeometry.topLeft());
|
||||
|
@ -292,8 +321,8 @@ QRect LayerWidget::countGeometry(int newWidth) {
|
|||
|
||||
const auto bottomRadius = st::boxRadius;
|
||||
const auto maxVisibleHeight = windowHeight - newTop;
|
||||
// Top rounding is included in _contentHeight.
|
||||
auto desiredHeight = _contentHeight + bottomRadius;
|
||||
// Top rounding is included in _contentWrapHeight.
|
||||
auto desiredHeight = _contentWrapHeight + bottomRadius;
|
||||
accumulate_min(desiredHeight, maxVisibleHeight - newBottom);
|
||||
|
||||
// First resize content to new width and get the new desired height.
|
||||
|
@ -302,10 +331,11 @@ QRect LayerWidget::countGeometry(int newWidth) {
|
|||
const auto contentBottom = bottomRadius;
|
||||
const auto contentWidth = newWidth;
|
||||
auto contentHeight = desiredHeight - contentTop - contentBottom;
|
||||
const auto scrollTillBottom = _content->scrollTillBottom(contentHeight);
|
||||
const auto scrollTillBottom = _contentWrap->scrollTillBottom(
|
||||
contentHeight);
|
||||
auto additionalScroll = std::min(scrollTillBottom, newBottom);
|
||||
|
||||
const auto expanding = (_desiredHeight > _contentHeight);
|
||||
const auto expanding = (_desiredHeight > _contentWrapHeight);
|
||||
|
||||
desiredHeight += additionalScroll;
|
||||
contentHeight += additionalScroll;
|
||||
|
@ -313,11 +343,11 @@ QRect LayerWidget::countGeometry(int newWidth) {
|
|||
if (_tillBottom) {
|
||||
additionalScroll += contentBottom;
|
||||
}
|
||||
_contentTillBottom = _tillBottom && !_content->scrollBottomSkip();
|
||||
_contentTillBottom = _tillBottom && !_contentWrap->scrollBottomSkip();
|
||||
if (_contentTillBottom) {
|
||||
contentHeight += contentBottom;
|
||||
}
|
||||
_content->updateGeometry({
|
||||
_contentWrap->updateGeometry({
|
||||
contentLeft,
|
||||
contentTop,
|
||||
contentWidth,
|
||||
|
@ -328,8 +358,8 @@ QRect LayerWidget::countGeometry(int newWidth) {
|
|||
}
|
||||
|
||||
void LayerWidget::doSetInnerFocus() {
|
||||
if (_content) {
|
||||
_content->setInnerFocus();
|
||||
if (_contentWrap) {
|
||||
_contentWrap->setInnerFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -342,7 +372,7 @@ void LayerWidget::paintEvent(QPaintEvent *e) {
|
|||
if (!_tillBottom) {
|
||||
const auto bottom = QRect{ 0, height() - radius, width(), radius };
|
||||
if (clip.intersects(bottom)) {
|
||||
if (const auto rounding = _content->bottomSkipRounding()) {
|
||||
if (const auto rounding = _contentWrap->bottomSkipRounding()) {
|
||||
rounding->paint(p, rect(), RectPart::FullBottom);
|
||||
} else {
|
||||
Ui::FillRoundRect(p, bottom, st::boxBg, {
|
||||
|
@ -351,11 +381,11 @@ void LayerWidget::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
}
|
||||
} else if (!_contentTillBottom) {
|
||||
const auto rounding = _content->bottomSkipRounding();
|
||||
const auto rounding = _contentWrap->bottomSkipRounding();
|
||||
const auto &color = rounding ? rounding->color() : st::boxBg;
|
||||
p.fillRect(0, height() - radius, width(), radius, color);
|
||||
}
|
||||
if (_content->animatingShow()) {
|
||||
if (_contentWrap->animatingShow()) {
|
||||
const auto top = QRect{ 0, 0, width(), radius };
|
||||
if (clip.intersects(top)) {
|
||||
Ui::FillRoundRect(p, top, st::boxBg, {
|
||||
|
|
|
@ -73,10 +73,10 @@ private:
|
|||
[[nodiscard]] QRect countGeometry(int newWidth);
|
||||
|
||||
not_null<Window::SessionController*> _controller;
|
||||
object_ptr<WrapWidget> _content;
|
||||
object_ptr<WrapWidget> _contentWrap;
|
||||
|
||||
int _desiredHeight = 0;
|
||||
int _contentHeight = 0;
|
||||
int _contentWrapHeight = 0;
|
||||
int _savedHeight = 0;
|
||||
Ui::Animations::Simple _heightAnimation;
|
||||
Ui::Animations::Simple _savedHeightAnimation;
|
||||
|
|
|
@ -50,8 +50,8 @@ void SectionWidget::init() {
|
|||
return (_content != nullptr);
|
||||
}) | rpl::start_with_next([=](QSize size, int) {
|
||||
const auto expanding = false;
|
||||
const auto additionalScroll = st::boxRadius;
|
||||
const auto full = !_content->scrollBottomSkip();
|
||||
const auto additionalScroll = (full ? st::boxRadius : 0);
|
||||
const auto height = size.height() - (full ? 0 : st::boxRadius);
|
||||
const auto wrapGeometry = QRect{ 0, 0, size.width(), height };
|
||||
_content->updateGeometry(
|
||||
|
|
|
@ -117,17 +117,17 @@ Widget::Widget(
|
|||
}
|
||||
|
||||
if (_pinnedToBottom) {
|
||||
const auto processHeight = [=](int bottomHeight, int height) {
|
||||
setScrollBottomSkip(bottomHeight);
|
||||
const auto processHeight = [=] {
|
||||
setScrollBottomSkip(_pinnedToBottom->height());
|
||||
_pinnedToBottom->moveToLeft(
|
||||
_pinnedToBottom->x(),
|
||||
height - bottomHeight);
|
||||
height() - _pinnedToBottom->height());
|
||||
};
|
||||
|
||||
_inner->sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &s) {
|
||||
_pinnedToBottom->resizeToWidth(s.width());
|
||||
processHeight(_pinnedToBottom->height(), height());
|
||||
//processHeight();
|
||||
}, _pinnedToBottom->lifetime());
|
||||
|
||||
rpl::combine(
|
||||
|
|
|
@ -98,6 +98,7 @@ public:
|
|||
|
||||
private:
|
||||
void outerResized(QSize outer);
|
||||
void updateComposeControlsPosition();
|
||||
|
||||
// ListDelegate interface.
|
||||
Context listContext() override;
|
||||
|
@ -505,7 +506,7 @@ void ShortcutMessages::outerResized(QSize outer) {
|
|||
? base::make_optional(_scroll->scrollTop())
|
||||
: 0;
|
||||
_skipScrollEvent = true;
|
||||
_inner->resizeToWidth(contentWidth, _scroll->height());
|
||||
_inner->resizeToWidth(contentWidth, st::boxWidth);
|
||||
_skipScrollEvent = false;
|
||||
|
||||
if (!_scroll->isHidden()) {
|
||||
|
@ -514,25 +515,34 @@ void ShortcutMessages::outerResized(QSize outer) {
|
|||
}
|
||||
updateInnerVisibleArea();
|
||||
}
|
||||
_composeControls->setAutocompleteBoundingRect(_scroll->geometry());
|
||||
updateComposeControlsPosition();
|
||||
_cornerButtons.updatePositions();
|
||||
}
|
||||
|
||||
void ShortcutMessages::updateComposeControlsPosition() {
|
||||
const auto bottom = _scroll->parentWidget()->height();
|
||||
const auto controlsHeight = _composeControls->heightCurrent();
|
||||
_composeControls->move(0, bottom - controlsHeight + st::boxRadius);
|
||||
_composeControls->setAutocompleteBoundingRect(_scroll->geometry());
|
||||
}
|
||||
|
||||
void ShortcutMessages::setupComposeControls() {
|
||||
_shortcutId.value() | rpl::start_with_next([=](BusinessShortcutId id) {
|
||||
_composeControls->updateShortcutId(id);
|
||||
}, lifetime());
|
||||
|
||||
const auto state = Dialogs::EntryState{
|
||||
.key = Dialogs::Key{ _history },
|
||||
.section = Dialogs::EntryState::Section::ShortcutMessages,
|
||||
.currentReplyTo = replyTo(),
|
||||
};
|
||||
_composeControls->setCurrentDialogsEntryState(state);
|
||||
|
||||
_composeControls->setHistory({
|
||||
.history = _history.get(),
|
||||
.writeRestriction = rpl::single(Controls::WriteRestriction()),
|
||||
});
|
||||
|
||||
_composeControls->height(
|
||||
) | rpl::start_with_next([=](int height) {
|
||||
const auto wasMax = (_scroll->scrollTopMax() == _scroll->scrollTop());
|
||||
_controlsWrap->resize(width(), height);
|
||||
if (wasMax) {
|
||||
listScrollTo(_scroll->scrollTopMax());
|
||||
}
|
||||
}, lifetime());
|
||||
|
||||
_composeControls->cancelRequests(
|
||||
) | rpl::start_with_next([=] {
|
||||
listCancelRequest();
|
||||
|
@ -637,20 +647,58 @@ void ShortcutMessages::setupComposeControls() {
|
|||
_controlsWrap->widthValue() | rpl::start_with_next([=](int width) {
|
||||
_composeControls->resizeToWidth(width);
|
||||
}, _controlsWrap->lifetime());
|
||||
_composeControls->height() | rpl::start_with_next([=](int height) {
|
||||
_controlsWrap->resize(_controlsWrap->width(), height);
|
||||
}, _controlsWrap->lifetime());
|
||||
|
||||
_composeControls->height(
|
||||
) | rpl::start_with_next([=](int height) {
|
||||
const auto wasMax = (_scroll->scrollTopMax() == _scroll->scrollTop());
|
||||
_controlsWrap->resize(width(), height - st::boxRadius);
|
||||
updateComposeControlsPosition();
|
||||
if (wasMax) {
|
||||
listScrollTo(_scroll->scrollTopMax());
|
||||
}
|
||||
}, lifetime());
|
||||
}
|
||||
|
||||
QPointer<Ui::RpWidget> ShortcutMessages::createPinnedToBottom(
|
||||
not_null<Ui::RpWidget*> parent) {
|
||||
auto placeholder = rpl::deferred([=] {
|
||||
return _shortcutId.value();
|
||||
}) | rpl::map([=](BusinessShortcutId id) {
|
||||
return _session->data().shortcutMessages().lookupShortcut(id).name;
|
||||
}) | rpl::map([=](const QString &shortcut) {
|
||||
return (shortcut == u"away"_q)
|
||||
? tr::lng_away_message_placeholder()
|
||||
: (shortcut == u"hello"_q)
|
||||
? tr::lng_greeting_message_placeholder()
|
||||
: tr::lng_replies_message_placeholder();
|
||||
}) | rpl::flatten_latest();
|
||||
|
||||
_controlsWrap = std::make_unique<Ui::RpWidget>(parent);
|
||||
_composeControls = std::make_unique<ComposeControls>(
|
||||
_controlsWrap.get(),
|
||||
_controller,
|
||||
[=](not_null<DocumentData*> emoji) { listShowPremiumToast(emoji); },
|
||||
ComposeControls::Mode::Normal,
|
||||
SendMenu::Type::Disabled);
|
||||
dynamic_cast<Ui::RpWidget*>(_scroll->parentWidget()),
|
||||
ComposeControlsDescriptor{
|
||||
.show = _controller->uiShow(),
|
||||
.unavailableEmojiPasted = [=](not_null<DocumentData*> emoji) {
|
||||
listShowPremiumToast(emoji);
|
||||
},
|
||||
.mode = HistoryView::ComposeControlsMode::Normal,
|
||||
.sendMenuType = SendMenu::Type::Disabled,
|
||||
.regularWindow = _controller,
|
||||
.stickerOrEmojiChosen = _controller->stickerOrEmojiChosen(),
|
||||
.customPlaceholder = std::move(placeholder),
|
||||
.panelsLevel = Window::GifPauseReason::Layer,
|
||||
.voiceCustomCancelText = tr::lng_record_cancel_stories(tr::now),
|
||||
.voiceLockFromBottom = true,
|
||||
.features = {
|
||||
.sendAs = false,
|
||||
.ttlInfo = false,
|
||||
.botCommandSend = false,
|
||||
.silentBroadcastToggle = false,
|
||||
.attachBotsMenu = false,
|
||||
.megagroupSet = false,
|
||||
.commonTabbedPanel = false,
|
||||
},
|
||||
});
|
||||
|
||||
setupComposeControls();
|
||||
|
||||
|
|
|
@ -517,6 +517,7 @@ FileLoadTask::FileLoadTask(
|
|||
, _caption(caption)
|
||||
, _spoiler(spoiler) {
|
||||
Expects(to.options.scheduled
|
||||
|| to.options.shortcutId
|
||||
|| !to.replaceMediaOf
|
||||
|| IsServerMsgId(to.replaceMediaOf));
|
||||
|
||||
|
|
|
@ -301,6 +301,7 @@ historySentInvertedIcon: icon {{ "history_sent", historyIconFgInverted, point(2p
|
|||
historyReceivedIcon: icon {{ "history_received", historyOutIconFg, point(2px, 4px) }};
|
||||
historyReceivedSelectedIcon: icon {{ "history_received", historyOutIconFgSelected, point(2px, 4px) }};
|
||||
historyReceivedInvertedIcon: icon {{ "history_received", historyIconFgInverted, point(2px, 4px) }};
|
||||
historyShortcutStateSpace: 18px;
|
||||
|
||||
historyViewsSpace: 8px;
|
||||
historyViewsWidth: 20px;
|
||||
|
|
Loading…
Add table
Reference in a new issue