Moved PinnedBar to Ui:: in td_ui.

This commit is contained in:
John Preston 2020-10-12 18:05:54 +03:00
parent 37fb94cbfb
commit 0873db58d0
8 changed files with 316 additions and 240 deletions

View file

@ -92,6 +92,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "apiwrap.h"
#include "base/qthelp_regex.h"
#include "ui/chat/pinned_bar.h"
#include "ui/widgets/popup_menu.h"
#include "ui/item_text_options.h"
#include "ui/unread_badge.h"
@ -5252,10 +5253,9 @@ void HistoryWidget::checkPinnedBarState() {
messageId.type
};
});
_pinnedBar = std::make_unique<HistoryView::PinnedBar>(
_pinnedBar = std::make_unique<Ui::PinnedBar>(
this,
&session(),
std::move(shown),
HistoryView::PinnedBarContent(&session(), std::move(shown)),
true);
_pinnedBar->closeClicks(

View file

@ -66,7 +66,7 @@ class SilentToggle;
class FlatButton;
class LinkButton;
class RoundButton;
class MessageBar;
class PinnedBar;
namespace Toast {
class Instance;
} // namespace Toast
@ -95,7 +95,6 @@ class TopBarWidget;
class ContactStatus;
class Element;
class PinnedTracker;
class PinnedBar;
} // namespace HistoryView
class DragArea;
@ -603,7 +602,7 @@ private:
object_ptr<Ui::IconButton> _fieldBarCancel;
std::unique_ptr<HistoryView::PinnedTracker> _pinnedTracker;
std::unique_ptr<HistoryView::PinnedBar> _pinnedBar;
std::unique_ptr<Ui::PinnedBar> _pinnedBar;
int _pinnedBarHeight = 0;
mtpRequestId _saveEditMsgRequestId = 0;

View file

@ -12,42 +12,29 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_changes.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/history_item.h"
#include "history/history.h"
#include "apiwrap.h"
#include "styles/style_chat.h"
#include "styles/style_history.h"
namespace HistoryView {
namespace {
[[nodiscard]] Ui::MessageBarContent ContentWithoutPreview(
not_null<HistoryItem*> item,
PinnedIdType type) {
not_null<HistoryItem*> item) {
const auto media = item->media();
const auto poll = media ? media->poll() : nullptr;
return Ui::MessageBarContent{
.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(),
};
}
[[nodiscard]] Ui::MessageBarContent ContentWithPreview(
not_null<HistoryItem*> item,
PinnedIdType type,
Image *preview) {
auto result = ContentWithoutPreview(item, type);
auto result = ContentWithoutPreview(item);
if (!preview) {
static const auto kEmpty = [&] {
const auto size = st::historyReplyHeight * cIntRetinaFactor();
@ -66,15 +53,14 @@ namespace {
}
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItem(
not_null<HistoryItem*> item,
PinnedIdType type) {
not_null<HistoryItem*> item) {
return item->history()->session().changes().messageFlagsValue(
item,
Data::MessageUpdate::Flag::Edited
) | rpl::map([=]() -> rpl::producer<Ui::MessageBarContent> {
const auto media = item->media();
if (!media || !media->hasReplyPreview()) {
return rpl::single(ContentWithoutPreview(item, type));
return rpl::single(ContentWithoutPreview(item));
}
constexpr auto kFullLoaded = 2;
constexpr auto kSomeLoaded = 1;
@ -98,19 +84,19 @@ namespace {
}) | rpl::then(
rpl::single(kFullLoaded)
) | rpl::map([=] {
return ContentWithPreview(item, type, media->replyPreview());
return ContentWithPreview(item, media->replyPreview());
});
}) | rpl::flatten_latest();
}
[[nodiscard]] rpl::producer<Ui::MessageBarContent> ContentByItemId(
not_null<Main::Session*> session,
PinnedBarId id,
FullMsgId id,
bool alreadyLoaded = false) {
if (!id.message) {
if (!id) {
return rpl::single(Ui::MessageBarContent());
} else if (const auto item = session->data().message(id.message)) {
return ContentByItem(item, id.type);
} else if (const auto item = session->data().message(id)) {
return ContentByItem(item);
} else if (alreadyLoaded) {
return rpl::single(Ui::MessageBarContent()); // Deleted message?..
}
@ -118,13 +104,13 @@ namespace {
consumer.put_next(Ui::MessageBarContent{
.text = tr::lng_contacts_loading(tr::now),
});
const auto channel = id.message.channel
? session->data().channel(id.message.channel).get()
const auto channel = id.channel
? session->data().channel(id.channel).get()
: nullptr;
const auto callback = [=](ChannelData *channel, MsgId id) {
consumer.put_done();
};
session->api().requestMessageData(channel, id.message.msg, callback);
session->api().requestMessageData(channel, id.msg, callback);
return rpl::lifetime();
});
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
PinnedBar::PinnedBar(
not_null<QWidget*> parent,
not_null<Main::Session*> session,
rpl::producer<PinnedBarId> itemId,
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();
rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId(
not_null<Main::Session*> session,
FullMsgId id) {
return ContentByItemId(session, id);
}
_wrap.entity()->paintRequest(
) | rpl::start_with_next([=](QRect clip) {
QPainter(_wrap.entity()).fillRect(clip, st::historyPinnedBg);
}, lifetime());
_wrap.setAttribute(Qt::WA_OpaquePaintEvent);
rpl::duplicate(
itemId
rpl::producer<Ui::MessageBarContent> PinnedBarContent(
not_null<Main::Session*> session,
rpl::producer<PinnedBarId> id) {
return std::move(
id
) | rpl::distinct_until_changed(
) | rpl::map([=](PinnedBarId id) {
return ContentByItemId(session, id);
}) | rpl::flatten_latest(
) | rpl::filter([=](const Ui::MessageBarContent &content) {
return !content.title.isEmpty() || !content.text.text.isEmpty();
}) | rpl::start_with_next([=](Ui::MessageBarContent &&content) {
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();
return ContentByItemId(
session,
id.message
) | rpl::map(WithPinnedTitle(session, id));
}) | rpl::flatten_latest();
}
} // namespace HistoryView

View file

@ -7,9 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include "ui/wrap/slide_wrap.h"
#include "ui/chat/message_bar.h"
#include <tuple>
namespace Main {
class Session;
} // namespace Main
@ -17,10 +18,15 @@ class Session;
namespace Ui {
class IconButton;
class PlainShadow;
struct MessageBarContent;
} // namespace Ui
namespace HistoryView {
[[nodiscard]] rpl::producer<Ui::MessageBarContent> MessageBarContentByItemId(
not_null<Main::Session*> session,
FullMsgId id);
enum class PinnedIdType;
struct PinnedBarId {
FullMsgId message;
@ -33,42 +39,8 @@ struct PinnedBarId {
return std::tie(message, type) == std::tie(other.message, other.type);
}
};
class PinnedBar final {
public:
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;
};
[[nodiscard]] rpl::producer<Ui::MessageBarContent> PinnedBarContent(
not_null<Main::Session*> session,
rpl::producer<PinnedBarId> id);
} // namespace HistoryView

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "ui/rp_widget.h"
#include "ui/effects/animations.h"
class Painter;

View 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

View 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

View file

@ -34,6 +34,8 @@ PRIVATE
ui/ui_pch.h
ui/chat/message_bar.cpp
ui/chat/message_bar.h
ui/chat/pinned_bar.cpp
ui/chat/pinned_bar.h
ui/text/format_values.cpp
ui/text/format_values.h
ui/text/text_options.cpp