Improve top bars in forums, in narrow column.

This commit is contained in:
John Preston 2022-10-24 15:52:28 +04:00
parent 70e5f752ba
commit 72354f52d4
14 changed files with 171 additions and 51 deletions

View file

@ -744,17 +744,20 @@ void Widget::refreshTopBars() {
_forumReportBar = std::make_unique<HistoryView::ContactStatus>(
controller(),
this,
_openedForum);
_openedForum,
true);
_forumRequestsBar = std::make_unique<Ui::RequestsBar>(
this,
HistoryView::RequestsBarContentByPeer(
_openedForum,
st::historyRequestsUserpics.size));
st::historyRequestsUserpics.size,
true));
_forumGroupCallBar = std::make_unique<Ui::GroupCallBar>(
this,
HistoryView::GroupCallBarContentByPeer(
_openedForum,
st::historyGroupCallUserpics.size),
st::historyGroupCallUserpics.size,
true),
Core::App().appDeactivatedValue());
_forumTopShadow = std::make_unique<Ui::PlainShadow>(this);

View file

@ -2126,7 +2126,8 @@ void HistoryWidget::showHistory(
_contactStatus = std::make_unique<HistoryView::ContactStatus>(
controller(),
this,
_peer);
_peer,
false);
_contactStatus->bar().heightValue() | rpl::start_with_next([=] {
updateControlsGeometry();
}, _contactStatus->bar().lifetime());
@ -6434,7 +6435,8 @@ void HistoryWidget::setupGroupCallBar() {
this,
HistoryView::GroupCallBarContentByPeer(
peer,
st::historyGroupCallUserpics.size),
st::historyGroupCallUserpics.size,
false),
Core::App().appDeactivatedValue());
controller()->adaptive().oneColumnValue(
@ -6486,7 +6488,8 @@ void HistoryWidget::setupRequestsBar() {
this,
HistoryView::RequestsBarContentByPeer(
peer,
st::historyRequestsUserpics.size));
st::historyRequestsUserpics.size,
false));
controller()->adaptive().oneColumnValue(
) | rpl::start_with_next([=](bool one) {

View file

@ -28,6 +28,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_session.h"
#include "data/data_forum_topic.h"
#include "data/data_peer_values.h"
#include "data/stickers/data_custom_emoji.h"
#include "settings/settings_premium.h"
#include "window/window_peer_menu.h"
@ -41,6 +42,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_chat.h"
#include "styles/style_layers.h"
#include "styles/style_info.h"
#include "styles/style_menu_icons.h"
namespace HistoryView {
namespace {
@ -111,6 +113,23 @@ namespace {
}) | rpl::flatten_latest() | rpl::distinct_until_changed();
}
[[nodiscard]] object_ptr<Ui::AbstractButton> MakeIconButton(
QWidget *parent,
const style::icon &icon) {
auto result = object_ptr<Ui::RippleButton>(
parent,
st::historyContactStatusButton.ripple);
const auto raw = result.data();
raw->paintRequest(
) | rpl::start_with_next([=, &icon] {
auto p = QPainter(raw);
p.fillRect(raw->rect(), st::historyContactStatusButton.bgColor);
raw->paintRipple(p, 0, 0);
icon.paintInCenter(p, raw->rect());
}, raw->lifetime());
return result;
}
} // namespace
class ContactStatus::BgButton final : public Ui::RippleButton {
@ -153,15 +172,18 @@ private:
QString _name;
object_ptr<Ui::FlatButton> _add;
object_ptr<Ui::FlatButton> _unarchive;
object_ptr<Ui::AbstractButton> _unarchiveIcon;
object_ptr<Ui::FlatButton> _block;
object_ptr<Ui::FlatButton> _share;
object_ptr<Ui::FlatButton> _report;
object_ptr<Ui::AbstractButton> _reportIcon;
object_ptr<Ui::IconButton> _close;
object_ptr<BgButton> _requestChatBg;
object_ptr<Ui::FlatLabel> _requestChatInfo;
object_ptr<Ui::PaddingWrap<Ui::FlatLabel>> _emojiStatusInfo;
object_ptr<Ui::PlainShadow> _emojiStatusShadow;
bool _emojiStatusRepaintScheduled = false;
bool _narrow = false;
rpl::event_stream<> _emojiStatusClicks;
};
@ -200,6 +222,7 @@ ContactStatus::Bar::Bar(
this,
tr::lng_new_contact_unarchive(tr::now).toUpper(),
st::historyContactStatusButton)
, _unarchiveIcon(MakeIconButton(this, st::menuIconUnarchive))
, _block(
this,
tr::lng_new_contact_block(tr::now).toUpper(),
@ -212,6 +235,7 @@ ContactStatus::Bar::Bar(
this,
QString(),
st::historyContactStatusBlock)
, _reportIcon(MakeIconButton(this, st::menuIconReportAttention))
, _close(this, st::historyReplyCancel)
, _requestChatBg(this, st::historyContactStatusButton)
, _requestChatInfo(
@ -242,14 +266,18 @@ void ContactStatus::Bar::showState(
using Type = State::Type;
const auto type = state.type;
_add->setVisible(type == Type::AddOrBlock || type == Type::Add);
_unarchive->setVisible(type == Type::UnarchiveOrBlock
|| type == Type::UnarchiveOrReport);
const auto unarchive = (type == Type::UnarchiveOrBlock)
|| (type == Type::UnarchiveOrReport);
_unarchive->setVisible(!_narrow && unarchive);
_unarchiveIcon->setVisible(_narrow && unarchive);
_block->setVisible(type == Type::AddOrBlock
|| type == Type::UnarchiveOrBlock);
_share->setVisible(type == Type::SharePhoneNumber);
_close->setVisible(type != Type::RequestChatInfo);
_report->setVisible(type == Type::ReportSpam
|| type == Type::UnarchiveOrReport);
_close->setVisible(!_narrow && type != Type::RequestChatInfo);
const auto report = (type == Type::ReportSpam)
|| (type == Type::UnarchiveOrReport);
_report->setVisible(!_narrow && report);
_reportIcon->setVisible(_narrow && report);
_requestChatInfo->setVisible(type == Type::RequestChatInfo);
_requestChatBg->setVisible(type == Type::RequestChatInfo);
const auto has = !status.empty();
@ -291,7 +319,10 @@ void ContactStatus::Bar::showState(
}
rpl::producer<> ContactStatus::Bar::unarchiveClicks() const {
return _unarchive->clicks() | rpl::to_empty;
return rpl::merge(
_unarchive->clicks(),
_unarchiveIcon->clicks()
) | rpl::to_empty;
}
rpl::producer<> ContactStatus::Bar::addClicks() const {
@ -307,7 +338,10 @@ rpl::producer<> ContactStatus::Bar::shareClicks() const {
}
rpl::producer<> ContactStatus::Bar::reportClicks() const {
return _report->clicks() | rpl::to_empty;
return rpl::merge(
_report->clicks(),
_reportIcon->clicks()
) | rpl::to_empty;
}
rpl::producer<> ContactStatus::Bar::closeClicks() const {
@ -323,7 +357,27 @@ rpl::producer<> ContactStatus::Bar::emojiStatusClicks() const {
}
int ContactStatus::Bar::resizeGetHeight(int newWidth) {
_close->moveToRight(0, 0);
_close->moveToRight(0, 0, newWidth);
const auto narrow = (newWidth < _close->width() * 2);
if (_narrow != narrow) {
_narrow = narrow;
_close->setVisible(_requestChatInfo->isHidden() && !_narrow);
const auto report = !_report->isHidden() || !_reportIcon->isHidden();
_report->setVisible(!_narrow && report);
_reportIcon->setVisible(_narrow && report);
const auto unarchive = !_unarchive->isHidden()
|| !_unarchiveIcon->isHidden();
_unarchive->setVisible(!_narrow && unarchive);
_unarchiveIcon->setVisible(_narrow && unarchive);
}
if (!_unarchiveIcon->isHidden()) {
const auto half = newWidth / 2;
_unarchiveIcon->setGeometry(0, 0, half, _close->height());
_reportIcon->setGeometry(half, 0, newWidth - half, _close->height());
} else if (!_reportIcon->isHidden()) {
_reportIcon->setGeometry(0, 0, newWidth, _close->height());
}
const auto closeWidth = _close->width();
const auto closeHeight = _close->height();
@ -489,11 +543,12 @@ rpl::producer<int> SlidingBar::heightValue() const {
ContactStatus::ContactStatus(
not_null<Window::SessionController*> window,
not_null<Ui::RpWidget*> parent,
not_null<PeerData*> peer)
not_null<PeerData*> peer,
bool showInForum)
: _controller(window)
, _inner(Ui::CreateChild<Bar>(parent.get(), peer->shortName()))
, _bar(parent, object_ptr<Bar>::fromRaw(_inner)) {
setupState(peer);
setupState(peer, showInForum);
setupHandlers(peer);
}
@ -555,7 +610,7 @@ auto ContactStatus::PeerState(not_null<PeerData*> peer)
});
}
void ContactStatus::setupState(not_null<PeerData*> peer) {
void ContactStatus::setupState(not_null<PeerData*> peer, bool showInForum) {
if (!BarCurrentlyHidden(peer)) {
peer->session().api().requestPeerSettings(peer);
}
@ -567,13 +622,21 @@ void ContactStatus::setupState(not_null<PeerData*> peer) {
};
};
_inner->showState({}, {}, _context);
const auto channel = peer->asChannel();
rpl::combine(
PeerState(peer),
PeerCustomStatus(peer)
) | rpl::start_with_next([=](State state, TextWithEntities status) {
PeerCustomStatus(peer),
((channel && !showInForum)
? Data::PeerFlagValue(channel, ChannelData::Flag::Forum)
: rpl::single(false))
) | rpl::start_with_next([=](
State state,
TextWithEntities status,
bool hiddenByForum) {
_state = state;
_status = status;
if (state.type == State::Type::None) {
_hiddenByForum = hiddenByForum;
if (state.type == State::Type::None || hiddenByForum) {
_bar.toggleContent(false);
} else {
_inner->showState(state, std::move(status), _context);
@ -769,7 +832,7 @@ void ContactStatus::setupEmojiStatusHandler(not_null<PeerData*> peer) {
void ContactStatus::show() {
if (!_shown) {
_shown = true;
if (_state.type != State::Type::None) {
if (_state.type != State::Type::None && !_hiddenByForum) {
_inner->showState(_state, _status, _context);
_bar.toggleContent(true);
}

View file

@ -69,7 +69,8 @@ public:
ContactStatus(
not_null<Window::SessionController*> controller,
not_null<Ui::RpWidget*> parent,
not_null<PeerData*> peer);
not_null<PeerData*> peer,
bool showInForum);
void show();
@ -98,7 +99,7 @@ private:
TimeId requestDate = 0;
};
void setupState(not_null<PeerData*> peer);
void setupState(not_null<PeerData*> peer, bool showInForum);
void setupHandlers(not_null<PeerData*> peer);
void setupAddHandler(not_null<UserData*> user);
void setupBlockHandler(not_null<UserData*> user);
@ -117,6 +118,7 @@ private:
Fn<std::any(Fn<void()> customEmojiRepaint)> _context;
QPointer<Bar> _inner;
SlidingBar _bar;
bool _hiddenByForum = false;
bool _shown = false;
};

View file

@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_changes.h"
#include "data/data_group_call.h"
#include "data/data_peer_values.h"
#include "main/main_session.h"
#include "ui/chat/group_call_bar.h"
#include "ui/chat/group_call_userpics.h"
@ -348,15 +349,22 @@ rpl::producer<Ui::GroupCallBarContent> GroupCallBarContentByCall(
rpl::producer<Ui::GroupCallBarContent> GroupCallBarContentByPeer(
not_null<PeerData*> peer,
int userpicSize) {
int userpicSize,
bool showInForum) {
const auto channel = peer->asChannel();
return rpl::combine(
peer->session().changes().peerFlagsValue(
peer,
Data::PeerUpdate::Flag::GroupCall),
Core::App().calls().currentGroupCallValue()
) | rpl::map([=](const auto&, Calls::GroupCall *current) {
Core::App().calls().currentGroupCallValue(),
((showInForum || !channel)
? rpl::single(false)
: Data::PeerFlagValue(channel, ChannelData::Flag::Forum))
) | rpl::map([=](auto, Calls::GroupCall *current, bool hiddenByForum) {
const auto call = peer->groupCall();
return (call && (!current || current->peer() != peer))
return (call
&& !hiddenByForum
&& (!current || current->peer() != peer))
? call
: nullptr;
}) | rpl::distinct_until_changed(

View file

@ -44,7 +44,8 @@ void GenerateUserpicsInRow(
[[nodiscard]] auto GroupCallBarContentByPeer(
not_null<PeerData*> peer,
int userpicSize)
int userpicSize,
bool showInForum)
-> rpl::producer<Ui::GroupCallBarContent>;
} // namespace HistoryView

View file

@ -14,6 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_channel.h"
#include "data/data_changes.h"
#include "data/data_session.h"
#include "data/data_peer_values.h"
#include "main/main_session.h"
#include "ui/chat/requests_bar.h"
#include "ui/chat/group_call_userpics.h"
@ -23,7 +24,8 @@ namespace HistoryView {
rpl::producer<Ui::RequestsBarContent> RequestsBarContentByPeer(
not_null<PeerData*> peer,
int userpicSize) {
int userpicSize,
bool showInForum) {
struct State {
explicit State(not_null<PeerData*> peer)
: peer(peer) {
@ -106,8 +108,9 @@ rpl::producer<Ui::RequestsBarContent> RequestsBarContentByPeer(
auto state = lifetime.make_state<State>(peer);
const auto pushNext = [=](bool now = false) {
if (std::min(state->current.count, kRecentRequestsLimit)
!= state->users.size()) {
if ((!showInForum && peer->isForum())
|| (std::min(state->current.count, kRecentRequestsLimit)
!= state->users.size())) {
return;
} else if (now) {
state->pushScheduled = false;
@ -124,6 +127,21 @@ rpl::producer<Ui::RequestsBarContent> RequestsBarContentByPeer(
});
};
if (!showInForum) {
if (const auto channel = peer->asChannel()) {
Data::PeerFlagValue(
channel,
ChannelData::Flag::Forum
) | rpl::start_with_next([=](bool hiddenByForum) {
if (hiddenByForum) {
consumer.put_next({});
} else {
pushNext();
}
}, lifetime);
}
}
peer->session().downloaderTaskFinished(
) | rpl::filter([=] {
return state->someUserpicsNotLoaded;

View file

@ -19,6 +19,7 @@ inline constexpr auto kRecentRequestsLimit = 3;
[[nodiscard]] rpl::producer<Ui::RequestsBarContent> RequestsBarContentByPeer(
not_null<PeerData*> peer,
int userpicSize);
int userpicSize,
bool showInForum);
} // namespace HistoryView

View file

@ -437,12 +437,8 @@ rpl::producer<int> RestrictionsCountValue(not_null<PeerData*> peer) {
return countOfRestrictions({}, chat->defaultRestrictions());
});
} else if (const auto channel = peer->asChannel()) {
auto forumValue = channel->flagsValue(
) | rpl::filter([](const ChannelData::Flags::Change &change) {
return (change.diff & ChannelData::Flag::Forum);
});
return rpl::combine(
std::move(forumValue),
Data::PeerFlagValue(channel, ChannelData::Flag::Forum),
channel->session().changes().peerFlagsValue(
channel,
UpdateFlag::Rights)

View file

@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_chat.h"
#include "styles/style_calls.h"
#include "styles/style_info.h" // st::topBarArrowPadding, like TopBarWidget.
#include "styles/style_window.h" // st::columnMinimalWidthLeft
#include "styles/palette.h"
#include <QtGui/QtEvents>
@ -242,12 +243,20 @@ void GroupCallBar::setupRightButton(not_null<RoundButton*> button) {
rpl::combine(
_inner->widthValue(),
button->widthValue()
) | rpl::start_with_next([=](int outerWidth, int) {
) | rpl::start_with_next([=](int outerWidth, int buttonWidth) {
// Skip shadow of the bar above.
const auto top = (st::historyReplyHeight
- st::lineWidth
- button->height()) / 2 + st::lineWidth;
button->moveToRight(top, top, outerWidth);
const auto narrow = (outerWidth < st::columnMinimalWidthLeft);
if (narrow) {
button->moveToLeft(
(outerWidth - buttonWidth) / 2,
top,
outerWidth);
} else {
button->moveToRight(top, top, outerWidth);
}
}, button->lifetime());
button->clicks() | rpl::start_to_stream(_joinClicks, button->lifetime());
@ -256,6 +265,14 @@ void GroupCallBar::setupRightButton(not_null<RoundButton*> button) {
void GroupCallBar::paint(Painter &p) {
p.fillRect(_inner->rect(), st::historyComposeAreaBg);
const auto narrow = (_inner->width() < st::columnMinimalWidthLeft);
if (!narrow) {
paintTitleAndStatus(p);
paintUserpics(p);
}
}
void GroupCallBar::paintTitleAndStatus(Painter &p) {
const auto left = st::topBarArrowPadding.right();
const auto titleTop = st::msgReplyPadding.top();
const auto textTop = titleTop + st::msgServiceNameFont->height;
@ -325,7 +342,9 @@ void GroupCallBar::paint(Painter &p) {
lt_count_decimal,
_content.count)
: tr::lng_group_call_no_members(tr::now)));
}
void GroupCallBar::paintUserpics(Painter &p) {
const auto size = st::historyGroupCallUserpics.size;
// Skip shadow of the bar above.
const auto top = (st::historyReplyHeight - st::lineWidth - size) / 2

View file

@ -95,6 +95,8 @@ private:
void setupInner();
void setupRightButton(not_null<RoundButton*> button);
void paint(Painter &p);
void paintTitleAndStatus(Painter &p);
void paintUserpics(Painter &p);
SlideWrap<> _wrap;
not_null<RpWidget*> _inner;

View file

@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_chat.h"
#include "styles/style_calls.h"
#include "styles/style_info.h" // st::topBarArrowPadding, like TopBarWidget.
#include "styles/style_window.h" // st::columnMinimalWidthLeft
#include "styles/palette.h"
#include <QtGui/QtEvents>
@ -150,12 +151,14 @@ void RequestsBar::paint(Painter &p) {
p.setPen(st::defaultMessageBar.titleFg);
p.setFont(font);
const auto textLeft = userpicsLeft + _userpicsWidth + userpicsLeft;
const auto available = width - textLeft - userpicsLeft;
if (_textFull.isEmpty() || available < _textFull.maxWidth()) {
_textShort.drawElided(p, textLeft, textTop, available);
} else {
_textFull.drawElided(p, textLeft, textTop, available);
if (width >= st::columnMinimalWidthLeft) {
const auto textLeft = userpicsLeft + _userpicsWidth + userpicsLeft;
const auto available = width - textLeft - userpicsLeft;
if (_textFull.isEmpty() || available < _textFull.maxWidth()) {
_textShort.drawElided(p, textLeft, textTop, available);
} else {
_textFull.drawElided(p, textLeft, textTop, available);
}
}
// Skip shadow of the bar above.

View file

@ -116,5 +116,6 @@ menuIconStartStreamWith: icon {{ "menu/start_stream_with", menuIconColor }};
menuIconDeleteAttention: icon {{ "menu/delete", menuIconAttentionColor }};
menuIconLeaveAttention: icon {{ "menu/leave", menuIconAttentionColor }};
menuIconDisableAttention: icon {{ "menu/disable", menuIconAttentionColor }};
menuIconReportAttention: icon {{ "menu/report", menuIconAttentionColor }};
menuIconBlockSettings: icon {{ "menu/block", windowBgActive }};

View file

@ -976,12 +976,12 @@ void SessionController::setActiveChatEntry(Dialogs::RowDescriptor row) {
now->setFakeUnreadWhileOpened(true);
if (const auto channel = now->peer->asChannel()
; channel && !channel->isForum()) {
channel->flagsValue(
) | rpl::filter([=](const ChannelData::Flags::Change &update) {
using Flag = ChannelData::Flag;
return (update.diff & Flag::Forum)
&& (update.value & Flag::Forum);
}) | rpl::start_with_next([=] {
Data::PeerFlagValue(
channel,
ChannelData::Flag::Forum
) | rpl::filter(
rpl::mappers::_1
) | rpl::start_with_next([=] {
clearSectionStack(
{ anim::type::normal, anim::activation::background });
openForum(channel,