mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 07:33:52 +02:00
Moved PinnedBar to Ui:: in td_ui.
This commit is contained in:
parent
37fb94cbfb
commit
0873db58d0
8 changed files with 316 additions and 240 deletions
|
@ -92,6 +92,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/qthelp_regex.h"
|
#include "base/qthelp_regex.h"
|
||||||
|
#include "ui/chat/pinned_bar.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
#include "ui/item_text_options.h"
|
#include "ui/item_text_options.h"
|
||||||
#include "ui/unread_badge.h"
|
#include "ui/unread_badge.h"
|
||||||
|
@ -5252,10 +5253,9 @@ void HistoryWidget::checkPinnedBarState() {
|
||||||
messageId.type
|
messageId.type
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
_pinnedBar = std::make_unique<HistoryView::PinnedBar>(
|
_pinnedBar = std::make_unique<Ui::PinnedBar>(
|
||||||
this,
|
this,
|
||||||
&session(),
|
HistoryView::PinnedBarContent(&session(), std::move(shown)),
|
||||||
std::move(shown),
|
|
||||||
true);
|
true);
|
||||||
|
|
||||||
_pinnedBar->closeClicks(
|
_pinnedBar->closeClicks(
|
||||||
|
|
|
@ -66,7 +66,7 @@ class SilentToggle;
|
||||||
class FlatButton;
|
class FlatButton;
|
||||||
class LinkButton;
|
class LinkButton;
|
||||||
class RoundButton;
|
class RoundButton;
|
||||||
class MessageBar;
|
class PinnedBar;
|
||||||
namespace Toast {
|
namespace Toast {
|
||||||
class Instance;
|
class Instance;
|
||||||
} // namespace Toast
|
} // namespace Toast
|
||||||
|
@ -95,7 +95,6 @@ class TopBarWidget;
|
||||||
class ContactStatus;
|
class ContactStatus;
|
||||||
class Element;
|
class Element;
|
||||||
class PinnedTracker;
|
class PinnedTracker;
|
||||||
class PinnedBar;
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
||||||
class DragArea;
|
class DragArea;
|
||||||
|
@ -603,7 +602,7 @@ private:
|
||||||
object_ptr<Ui::IconButton> _fieldBarCancel;
|
object_ptr<Ui::IconButton> _fieldBarCancel;
|
||||||
|
|
||||||
std::unique_ptr<HistoryView::PinnedTracker> _pinnedTracker;
|
std::unique_ptr<HistoryView::PinnedTracker> _pinnedTracker;
|
||||||
std::unique_ptr<HistoryView::PinnedBar> _pinnedBar;
|
std::unique_ptr<Ui::PinnedBar> _pinnedBar;
|
||||||
int _pinnedBarHeight = 0;
|
int _pinnedBarHeight = 0;
|
||||||
|
|
||||||
mtpRequestId _saveEditMsgRequestId = 0;
|
mtpRequestId _saveEditMsgRequestId = 0;
|
||||||
|
|
|
@ -12,42 +12,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_changes.h"
|
#include "data/data_changes.h"
|
||||||
#include "data/data_poll.h"
|
#include "data/data_poll.h"
|
||||||
#include "ui/widgets/shadow.h"
|
|
||||||
#include "ui/widgets/buttons.h"
|
|
||||||
#include "history/view/history_view_pinned_tracker.h"
|
#include "history/view/history_view_pinned_tracker.h"
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "styles/style_chat.h"
|
#include "styles/style_history.h"
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
[[nodiscard]] Ui::MessageBarContent ContentWithoutPreview(
|
[[nodiscard]] Ui::MessageBarContent ContentWithoutPreview(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item) {
|
||||||
PinnedIdType type) {
|
|
||||||
const auto media = item->media();
|
const auto media = item->media();
|
||||||
const auto poll = media ? media->poll() : nullptr;
|
const auto poll = media ? media->poll() : nullptr;
|
||||||
return Ui::MessageBarContent{
|
return Ui::MessageBarContent{
|
||||||
.id = item->id,
|
.id = item->id,
|
||||||
.title = ((type == PinnedIdType::First)
|
|
||||||
? tr::lng_pinned_previous(tr::now) // #TODO pinned first?
|
|
||||||
: (type == PinnedIdType::Middle)
|
|
||||||
? tr::lng_pinned_previous(tr::now)
|
|
||||||
: !poll
|
|
||||||
? tr::lng_pinned_message(tr::now)
|
|
||||||
: poll->quiz()
|
|
||||||
? tr::lng_pinned_quiz(tr::now)
|
|
||||||
: tr::lng_pinned_poll(tr::now)),
|
|
||||||
.text = item->inReplyText(),
|
.text = item->inReplyText(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] Ui::MessageBarContent ContentWithPreview(
|
[[nodiscard]] Ui::MessageBarContent ContentWithPreview(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item,
|
||||||
PinnedIdType type,
|
|
||||||
Image *preview) {
|
Image *preview) {
|
||||||
auto result = ContentWithoutPreview(item, type);
|
auto result = ContentWithoutPreview(item);
|
||||||
if (!preview) {
|
if (!preview) {
|
||||||
static const auto kEmpty = [&] {
|
static const auto kEmpty = [&] {
|
||||||
const auto size = st::historyReplyHeight * cIntRetinaFactor();
|
const auto size = st::historyReplyHeight * cIntRetinaFactor();
|
||||||
|
@ -66,15 +53,14 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItem(
|
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItem(
|
||||||
not_null<HistoryItem*> item,
|
not_null<HistoryItem*> item) {
|
||||||
PinnedIdType type) {
|
|
||||||
return item->history()->session().changes().messageFlagsValue(
|
return item->history()->session().changes().messageFlagsValue(
|
||||||
item,
|
item,
|
||||||
Data::MessageUpdate::Flag::Edited
|
Data::MessageUpdate::Flag::Edited
|
||||||
) | rpl::map([=]() -> rpl::producer<Ui::MessageBarContent> {
|
) | rpl::map([=]() -> rpl::producer<Ui::MessageBarContent> {
|
||||||
const auto media = item->media();
|
const auto media = item->media();
|
||||||
if (!media || !media->hasReplyPreview()) {
|
if (!media || !media->hasReplyPreview()) {
|
||||||
return rpl::single(ContentWithoutPreview(item, type));
|
return rpl::single(ContentWithoutPreview(item));
|
||||||
}
|
}
|
||||||
constexpr auto kFullLoaded = 2;
|
constexpr auto kFullLoaded = 2;
|
||||||
constexpr auto kSomeLoaded = 1;
|
constexpr auto kSomeLoaded = 1;
|
||||||
|
@ -98,19 +84,19 @@ namespace {
|
||||||
}) | rpl::then(
|
}) | rpl::then(
|
||||||
rpl::single(kFullLoaded)
|
rpl::single(kFullLoaded)
|
||||||
) | rpl::map([=] {
|
) | rpl::map([=] {
|
||||||
return ContentWithPreview(item, type, media->replyPreview());
|
return ContentWithPreview(item, media->replyPreview());
|
||||||
});
|
});
|
||||||
}) | rpl::flatten_latest();
|
}) | rpl::flatten_latest();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItemId(
|
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItemId(
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
PinnedBarId id,
|
FullMsgId id,
|
||||||
bool alreadyLoaded = false) {
|
bool alreadyLoaded = false) {
|
||||||
if (!id.message) {
|
if (!id) {
|
||||||
return rpl::single(Ui::MessageBarContent());
|
return rpl::single(Ui::MessageBarContent());
|
||||||
} else if (const auto item = session->data().message(id.message)) {
|
} else if (const auto item = session->data().message(id)) {
|
||||||
return ContentByItem(item, id.type);
|
return ContentByItem(item);
|
||||||
} else if (alreadyLoaded) {
|
} else if (alreadyLoaded) {
|
||||||
return rpl::single(Ui::MessageBarContent()); // Deleted message?..
|
return rpl::single(Ui::MessageBarContent()); // Deleted message?..
|
||||||
}
|
}
|
||||||
|
@ -118,13 +104,13 @@ namespace {
|
||||||
consumer.put_next(Ui::MessageBarContent{
|
consumer.put_next(Ui::MessageBarContent{
|
||||||
.text = tr::lng_contacts_loading(tr::now),
|
.text = tr::lng_contacts_loading(tr::now),
|
||||||
});
|
});
|
||||||
const auto channel = id.message.channel
|
const auto channel = id.channel
|
||||||
? session->data().channel(id.message.channel).get()
|
? session->data().channel(id.channel).get()
|
||||||
: nullptr;
|
: nullptr;
|
||||||
const auto callback = [=](ChannelData *channel, MsgId id) {
|
const auto callback = [=](ChannelData *channel, MsgId id) {
|
||||||
consumer.put_done();
|
consumer.put_done();
|
||||||
};
|
};
|
||||||
session->api().requestMessageData(channel, id.message.msg, callback);
|
session->api().requestMessageData(channel, id.msg, callback);
|
||||||
return rpl::lifetime();
|
return rpl::lifetime();
|
||||||
});
|
});
|
||||||
return std::move(
|
return std::move(
|
||||||
|
@ -134,180 +120,47 @@ namespace {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto WithPinnedTitle(not_null<Main::Session*> session, PinnedBarId id) {
|
||||||
|
return [=](Ui::MessageBarContent &&content) {
|
||||||
|
const auto item = session->data().message(id.message);
|
||||||
|
if (!item) {
|
||||||
|
return std::move(content);
|
||||||
|
}
|
||||||
|
const auto media = item->media();
|
||||||
|
const auto poll = media ? media->poll() : nullptr;
|
||||||
|
content.title = (id.type == PinnedIdType::First)
|
||||||
|
? tr::lng_pinned_previous(tr::now) // #TODO pinned first?
|
||||||
|
: (id.type == PinnedIdType::Middle)
|
||||||
|
? tr::lng_pinned_previous(tr::now)
|
||||||
|
: !poll
|
||||||
|
? tr::lng_pinned_message(tr::now)
|
||||||
|
: poll->quiz()
|
||||||
|
? tr::lng_pinned_quiz(tr::now)
|
||||||
|
: tr::lng_pinned_poll(tr::now);
|
||||||
|
return std::move(content);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
PinnedBar::PinnedBar(
|
rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId(
|
||||||
not_null<QWidget*> parent,
|
not_null<Main::Session*> session,
|
||||||
not_null<Main::Session*> session,
|
FullMsgId id) {
|
||||||
rpl::producer<PinnedBarId> itemId,
|
return ContentByItemId(session, id);
|
||||||
bool withClose)
|
}
|
||||||
: _wrap(parent, object_ptr<Ui::RpWidget>(parent))
|
|
||||||
, _close(withClose
|
|
||||||
? std::make_unique<Ui::IconButton>(
|
|
||||||
_wrap.entity(),
|
|
||||||
st::historyReplyCancel)
|
|
||||||
: nullptr)
|
|
||||||
, _shadow(std::make_unique<Ui::PlainShadow>(_wrap.parentWidget())) {
|
|
||||||
_wrap.hide(anim::type::instant);
|
|
||||||
_shadow->hide();
|
|
||||||
|
|
||||||
_wrap.entity()->paintRequest(
|
rpl::producer<Ui::MessageBarContent> PinnedBarContent(
|
||||||
) | rpl::start_with_next([=](QRect clip) {
|
not_null<Main::Session*> session,
|
||||||
QPainter(_wrap.entity()).fillRect(clip, st::historyPinnedBg);
|
rpl::producer<PinnedBarId> id) {
|
||||||
}, lifetime());
|
return std::move(
|
||||||
_wrap.setAttribute(Qt::WA_OpaquePaintEvent);
|
id
|
||||||
|
|
||||||
rpl::duplicate(
|
|
||||||
itemId
|
|
||||||
) | rpl::distinct_until_changed(
|
) | rpl::distinct_until_changed(
|
||||||
) | rpl::map([=](PinnedBarId id) {
|
) | rpl::map([=](PinnedBarId id) {
|
||||||
return ContentByItemId(session, id);
|
return ContentByItemId(
|
||||||
}) | rpl::flatten_latest(
|
session,
|
||||||
) | rpl::filter([=](const Ui::MessageBarContent &content) {
|
id.message
|
||||||
return !content.title.isEmpty() || !content.text.text.isEmpty();
|
) | rpl::map(WithPinnedTitle(session, id));
|
||||||
}) | rpl::start_with_next([=](Ui::MessageBarContent &&content) {
|
}) | rpl::flatten_latest();
|
||||||
const auto creating = !_bar;
|
|
||||||
if (creating) {
|
|
||||||
createControls();
|
|
||||||
}
|
|
||||||
_bar->set(std::move(content));
|
|
||||||
if (creating) {
|
|
||||||
_bar->finishAnimating();
|
|
||||||
}
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
std::move(
|
|
||||||
itemId
|
|
||||||
) | rpl::map([=](PinnedBarId id) {
|
|
||||||
return !id.message;
|
|
||||||
}) | rpl::start_with_next_done([=](bool hidden) {
|
|
||||||
_shouldBeShown = !hidden;
|
|
||||||
if (!_forceHidden) {
|
|
||||||
_wrap.toggle(_shouldBeShown, anim::type::normal);
|
|
||||||
} else if (!_shouldBeShown) {
|
|
||||||
_bar = nullptr;
|
|
||||||
}
|
|
||||||
}, [=] {
|
|
||||||
_forceHidden = true;
|
|
||||||
_wrap.toggle(false, anim::type::normal);
|
|
||||||
}, lifetime());
|
|
||||||
}
|
|
||||||
|
|
||||||
void PinnedBar::createControls() {
|
|
||||||
Expects(!_bar);
|
|
||||||
|
|
||||||
_bar = std::make_unique<Ui::MessageBar>(
|
|
||||||
_wrap.entity(),
|
|
||||||
st::defaultMessageBar);
|
|
||||||
if (_close) {
|
|
||||||
_close->raise();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clicks.
|
|
||||||
_bar->widget()->setCursor(style::cur_pointer);
|
|
||||||
_bar->widget()->events(
|
|
||||||
) | rpl::filter([=](not_null<QEvent*> event) {
|
|
||||||
return (event->type() == QEvent::MouseButtonPress);
|
|
||||||
}) | rpl::map([=] {
|
|
||||||
return _bar->widget()->events(
|
|
||||||
) | rpl::filter([=](not_null<QEvent*> event) {
|
|
||||||
return (event->type() == QEvent::MouseButtonRelease);
|
|
||||||
}) | rpl::take(1) | rpl::filter([=](not_null<QEvent*> event) {
|
|
||||||
return _bar->widget()->rect().contains(
|
|
||||||
static_cast<QMouseEvent*>(event.get())->pos());
|
|
||||||
});
|
|
||||||
}) | rpl::flatten_latest(
|
|
||||||
) | rpl::map([] {
|
|
||||||
return rpl::empty_value();
|
|
||||||
}) | rpl::start_to_stream(_barClicks, _bar->widget()->lifetime());
|
|
||||||
|
|
||||||
_bar->widget()->move(0, 0);
|
|
||||||
_bar->widget()->show();
|
|
||||||
_wrap.entity()->resize(_wrap.entity()->width(), _bar->widget()->height());
|
|
||||||
|
|
||||||
_wrap.geometryValue(
|
|
||||||
) | rpl::start_with_next([=](QRect rect) {
|
|
||||||
_shadow->setGeometry(
|
|
||||||
rect.x(),
|
|
||||||
rect.y() + rect.height(),
|
|
||||||
rect.width(),
|
|
||||||
st::lineWidth);
|
|
||||||
_bar->widget()->resizeToWidth(
|
|
||||||
rect.width() - (_close ? _close->width() : 0));
|
|
||||||
const auto hidden = _wrap.isHidden() || !rect.height();
|
|
||||||
if (_shadow->isHidden() != hidden) {
|
|
||||||
_shadow->setVisible(!hidden);
|
|
||||||
}
|
|
||||||
if (_close) {
|
|
||||||
_close->moveToRight(0, 0);
|
|
||||||
}
|
|
||||||
}, _bar->widget()->lifetime());
|
|
||||||
|
|
||||||
_wrap.shownValue(
|
|
||||||
) | rpl::skip(
|
|
||||||
1
|
|
||||||
) | rpl::filter([=](bool shown) {
|
|
||||||
return !shown && !_forceHidden;
|
|
||||||
}) | rpl::start_with_next([=] {
|
|
||||||
_bar = nullptr;
|
|
||||||
}, _bar->widget()->lifetime());
|
|
||||||
|
|
||||||
Ensures(_bar != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PinnedBar::show() {
|
|
||||||
if (!_forceHidden) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_forceHidden = false;
|
|
||||||
if (_shouldBeShown) {
|
|
||||||
_wrap.show(anim::type::instant);
|
|
||||||
_shadow->show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void PinnedBar::hide() {
|
|
||||||
if (_forceHidden) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_forceHidden = true;
|
|
||||||
_wrap.hide(anim::type::instant);
|
|
||||||
_shadow->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PinnedBar::raise() {
|
|
||||||
_wrap.raise();
|
|
||||||
_shadow->raise();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PinnedBar::move(int x, int y) {
|
|
||||||
_wrap.move(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PinnedBar::resizeToWidth(int width) {
|
|
||||||
_wrap.entity()->resizeToWidth(width);
|
|
||||||
}
|
|
||||||
|
|
||||||
int PinnedBar::height() const {
|
|
||||||
return !_forceHidden
|
|
||||||
? _wrap.height()
|
|
||||||
: _shouldBeShown
|
|
||||||
? st::historyReplyHeight
|
|
||||||
: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<int> PinnedBar::heightValue() const {
|
|
||||||
return _wrap.heightValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<> PinnedBar::closeClicks() const {
|
|
||||||
return !_close
|
|
||||||
? (rpl::never<>() | rpl::type_erased())
|
|
||||||
: (_close->clicks() | rpl::map([] { return rpl::empty_value(); }));
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<> PinnedBar::barClicks() const {
|
|
||||||
return _barClicks.events();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -7,9 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/wrap/slide_wrap.h"
|
|
||||||
#include "ui/chat/message_bar.h"
|
#include "ui/chat/message_bar.h"
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
namespace Main {
|
namespace Main {
|
||||||
class Session;
|
class Session;
|
||||||
} // namespace Main
|
} // namespace Main
|
||||||
|
@ -17,10 +18,15 @@ class Session;
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class IconButton;
|
class IconButton;
|
||||||
class PlainShadow;
|
class PlainShadow;
|
||||||
|
struct MessageBarContent;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace HistoryView {
|
namespace HistoryView {
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
FullMsgId id);
|
||||||
|
|
||||||
enum class PinnedIdType;
|
enum class PinnedIdType;
|
||||||
struct PinnedBarId {
|
struct PinnedBarId {
|
||||||
FullMsgId message;
|
FullMsgId message;
|
||||||
|
@ -33,42 +39,8 @@ struct PinnedBarId {
|
||||||
return std::tie(message, type) == std::tie(other.message, other.type);
|
return std::tie(message, type) == std::tie(other.message, other.type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
[[nodiscard]] rpl::producer<Ui::MessageBarContent> PinnedBarContent(
|
||||||
class PinnedBar final {
|
not_null<Main::Session*> session,
|
||||||
public:
|
rpl::producer<PinnedBarId> id);
|
||||||
PinnedBar(
|
|
||||||
not_null<QWidget*> parent,
|
|
||||||
not_null<Main::Session*> session,
|
|
||||||
rpl::producer<PinnedBarId> itemId,
|
|
||||||
bool withClose = false);
|
|
||||||
|
|
||||||
void show();
|
|
||||||
void hide();
|
|
||||||
void raise();
|
|
||||||
|
|
||||||
void move(int x, int y);
|
|
||||||
void resizeToWidth(int width);
|
|
||||||
[[nodiscard]] int height() const;
|
|
||||||
[[nodiscard]] rpl::producer<int> heightValue() const;
|
|
||||||
[[nodiscard]] rpl::producer<> closeClicks() const;
|
|
||||||
[[nodiscard]] rpl::producer<> barClicks() const;
|
|
||||||
|
|
||||||
[[nodiscard]] rpl::lifetime &lifetime() {
|
|
||||||
return _wrap.lifetime();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void createControls();
|
|
||||||
|
|
||||||
Ui::SlideWrap<> _wrap;
|
|
||||||
std::unique_ptr<Ui::MessageBar> _bar;
|
|
||||||
std::unique_ptr<Ui::IconButton> _close;
|
|
||||||
std::unique_ptr<Ui::PlainShadow> _shadow;
|
|
||||||
rpl::event_stream<Ui::MessageBarContent> _content;
|
|
||||||
rpl::event_stream<> _barClicks;
|
|
||||||
bool _shouldBeShown = false;
|
|
||||||
bool _forceHidden = false;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace HistoryView
|
} // namespace HistoryView
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ui/rp_widget.h"
|
#include "ui/rp_widget.h"
|
||||||
|
#include "ui/effects/animations.h"
|
||||||
|
|
||||||
class Painter;
|
class Painter;
|
||||||
|
|
||||||
|
|
195
Telegram/SourceFiles/ui/chat/pinned_bar.cpp
Normal file
195
Telegram/SourceFiles/ui/chat/pinned_bar.cpp
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "ui/chat/pinned_bar.h"
|
||||||
|
|
||||||
|
#include "ui/chat/message_bar.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
#include "styles/palette.h"
|
||||||
|
|
||||||
|
#include <QtGui/QtEvents>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
PinnedBar::PinnedBar(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
rpl::producer<MessageBarContent> content,
|
||||||
|
bool withClose)
|
||||||
|
: _wrap(parent, object_ptr<RpWidget>(parent))
|
||||||
|
, _close(withClose
|
||||||
|
? std::make_unique<IconButton>(
|
||||||
|
_wrap.entity(),
|
||||||
|
st::historyReplyCancel)
|
||||||
|
: nullptr)
|
||||||
|
, _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget())) {
|
||||||
|
_wrap.hide(anim::type::instant);
|
||||||
|
_shadow->hide();
|
||||||
|
|
||||||
|
_wrap.entity()->paintRequest(
|
||||||
|
) | rpl::start_with_next([=](QRect clip) {
|
||||||
|
QPainter(_wrap.entity()).fillRect(clip, st::historyPinnedBg);
|
||||||
|
}, lifetime());
|
||||||
|
_wrap.setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
|
auto copy = std::move(
|
||||||
|
content
|
||||||
|
) | rpl::start_spawning(_wrap.lifetime());
|
||||||
|
|
||||||
|
rpl::duplicate(
|
||||||
|
copy
|
||||||
|
) | rpl::filter([=](const MessageBarContent &content) {
|
||||||
|
return !content.title.isEmpty() || !content.text.text.isEmpty();
|
||||||
|
}) | rpl::start_with_next([=](MessageBarContent &&content) {
|
||||||
|
const auto creating = !_bar;
|
||||||
|
if (creating) {
|
||||||
|
createControls();
|
||||||
|
}
|
||||||
|
_bar->set(std::move(content));
|
||||||
|
if (creating) {
|
||||||
|
_bar->finishAnimating();
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
std::move(
|
||||||
|
copy
|
||||||
|
) | rpl::map([=](const MessageBarContent &content) {
|
||||||
|
return content.title.isEmpty() || content.text.text.isEmpty();
|
||||||
|
}) | rpl::start_with_next_done([=](bool hidden) {
|
||||||
|
_shouldBeShown = !hidden;
|
||||||
|
if (!_forceHidden) {
|
||||||
|
_wrap.toggle(_shouldBeShown, anim::type::normal);
|
||||||
|
} else if (!_shouldBeShown) {
|
||||||
|
_bar = nullptr;
|
||||||
|
}
|
||||||
|
}, [=] {
|
||||||
|
_forceHidden = true;
|
||||||
|
_wrap.toggle(false, anim::type::normal);
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
PinnedBar::~PinnedBar() = default;
|
||||||
|
|
||||||
|
void PinnedBar::createControls() {
|
||||||
|
Expects(!_bar);
|
||||||
|
|
||||||
|
_bar = std::make_unique<MessageBar>(
|
||||||
|
_wrap.entity(),
|
||||||
|
st::defaultMessageBar);
|
||||||
|
if (_close) {
|
||||||
|
_close->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clicks.
|
||||||
|
_bar->widget()->setCursor(style::cur_pointer);
|
||||||
|
_bar->widget()->events(
|
||||||
|
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||||
|
return (event->type() == QEvent::MouseButtonPress);
|
||||||
|
}) | rpl::map([=] {
|
||||||
|
return _bar->widget()->events(
|
||||||
|
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||||
|
return (event->type() == QEvent::MouseButtonRelease);
|
||||||
|
}) | rpl::take(1) | rpl::filter([=](not_null<QEvent*> event) {
|
||||||
|
return _bar->widget()->rect().contains(
|
||||||
|
static_cast<QMouseEvent*>(event.get())->pos());
|
||||||
|
});
|
||||||
|
}) | rpl::flatten_latest(
|
||||||
|
) | rpl::map([] {
|
||||||
|
return rpl::empty_value();
|
||||||
|
}) | rpl::start_to_stream(_barClicks, _bar->widget()->lifetime());
|
||||||
|
|
||||||
|
_bar->widget()->move(0, 0);
|
||||||
|
_bar->widget()->show();
|
||||||
|
_wrap.entity()->resize(_wrap.entity()->width(), _bar->widget()->height());
|
||||||
|
|
||||||
|
_wrap.geometryValue(
|
||||||
|
) | rpl::start_with_next([=](QRect rect) {
|
||||||
|
_shadow->setGeometry(
|
||||||
|
rect.x(),
|
||||||
|
rect.y() + rect.height(),
|
||||||
|
rect.width(),
|
||||||
|
st::lineWidth);
|
||||||
|
_bar->widget()->resizeToWidth(
|
||||||
|
rect.width() - (_close ? _close->width() : 0));
|
||||||
|
const auto hidden = _wrap.isHidden() || !rect.height();
|
||||||
|
if (_shadow->isHidden() != hidden) {
|
||||||
|
_shadow->setVisible(!hidden);
|
||||||
|
}
|
||||||
|
if (_close) {
|
||||||
|
_close->moveToRight(0, 0);
|
||||||
|
}
|
||||||
|
}, _bar->widget()->lifetime());
|
||||||
|
|
||||||
|
_wrap.shownValue(
|
||||||
|
) | rpl::skip(
|
||||||
|
1
|
||||||
|
) | rpl::filter([=](bool shown) {
|
||||||
|
return !shown && !_forceHidden;
|
||||||
|
}) | rpl::start_with_next([=] {
|
||||||
|
_bar = nullptr;
|
||||||
|
}, _bar->widget()->lifetime());
|
||||||
|
|
||||||
|
Ensures(_bar != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedBar::show() {
|
||||||
|
if (!_forceHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_forceHidden = false;
|
||||||
|
if (_shouldBeShown) {
|
||||||
|
_wrap.show(anim::type::instant);
|
||||||
|
_shadow->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedBar::hide() {
|
||||||
|
if (_forceHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_forceHidden = true;
|
||||||
|
_wrap.hide(anim::type::instant);
|
||||||
|
_shadow->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedBar::raise() {
|
||||||
|
_wrap.raise();
|
||||||
|
_shadow->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedBar::move(int x, int y) {
|
||||||
|
_wrap.move(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PinnedBar::resizeToWidth(int width) {
|
||||||
|
_wrap.entity()->resizeToWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PinnedBar::height() const {
|
||||||
|
return !_forceHidden
|
||||||
|
? _wrap.height()
|
||||||
|
: _shouldBeShown
|
||||||
|
? st::historyReplyHeight
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> PinnedBar::heightValue() const {
|
||||||
|
return _wrap.heightValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> PinnedBar::closeClicks() const {
|
||||||
|
return !_close
|
||||||
|
? (rpl::never<>() | rpl::type_erased())
|
||||||
|
: (_close->clicks() | rpl::map([] { return rpl::empty_value(); }));
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> PinnedBar::barClicks() const {
|
||||||
|
return _barClicks.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
54
Telegram/SourceFiles/ui/chat/pinned_bar.h
Normal file
54
Telegram/SourceFiles/ui/chat/pinned_bar.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
struct MessageBarContent;
|
||||||
|
class MessageBar;
|
||||||
|
class IconButton;
|
||||||
|
class PlainShadow;
|
||||||
|
|
||||||
|
class PinnedBar final {
|
||||||
|
public:
|
||||||
|
PinnedBar(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
rpl::producer<Ui::MessageBarContent> content,
|
||||||
|
bool withClose = false);
|
||||||
|
~PinnedBar();
|
||||||
|
|
||||||
|
void show();
|
||||||
|
void hide();
|
||||||
|
void raise();
|
||||||
|
|
||||||
|
void move(int x, int y);
|
||||||
|
void resizeToWidth(int width);
|
||||||
|
[[nodiscard]] int height() const;
|
||||||
|
[[nodiscard]] rpl::producer<int> heightValue() const;
|
||||||
|
[[nodiscard]] rpl::producer<> closeClicks() const;
|
||||||
|
[[nodiscard]] rpl::producer<> barClicks() const;
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::lifetime &lifetime() {
|
||||||
|
return _wrap.lifetime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createControls();
|
||||||
|
|
||||||
|
Ui::SlideWrap<> _wrap;
|
||||||
|
std::unique_ptr<Ui::MessageBar> _bar;
|
||||||
|
std::unique_ptr<Ui::IconButton> _close;
|
||||||
|
std::unique_ptr<Ui::PlainShadow> _shadow;
|
||||||
|
rpl::event_stream<> _barClicks;
|
||||||
|
bool _shouldBeShown = false;
|
||||||
|
bool _forceHidden = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -34,6 +34,8 @@ PRIVATE
|
||||||
ui/ui_pch.h
|
ui/ui_pch.h
|
||||||
ui/chat/message_bar.cpp
|
ui/chat/message_bar.cpp
|
||||||
ui/chat/message_bar.h
|
ui/chat/message_bar.h
|
||||||
|
ui/chat/pinned_bar.cpp
|
||||||
|
ui/chat/pinned_bar.h
|
||||||
ui/text/format_values.cpp
|
ui/text/format_values.cpp
|
||||||
ui/text/format_values.h
|
ui/text/format_values.h
|
||||||
ui/text/text_options.cpp
|
ui/text/text_options.cpp
|
||||||
|
|
Loading…
Add table
Reference in a new issue