Show comments bar when no unread bar.

This commit is contained in:
John Preston 2020-09-15 18:30:34 +03:00
parent cf48152853
commit 9abca29f4c
9 changed files with 121 additions and 63 deletions

View file

@ -2104,7 +2104,7 @@ void History::addUnreadBar() {
} }
if (const auto count = chatListUnreadCount()) { if (const auto count = chatListUnreadCount()) {
_unreadBarView = _firstUnreadView; _unreadBarView = _firstUnreadView;
_unreadBarView->createUnreadBar(); _unreadBarView->createUnreadBar(tr::lng_unread_bar_some());
} }
} }

View file

@ -144,8 +144,8 @@ TextSelection ShiftItemSelection(
return ShiftItemSelection(selection, byText.length()); return ShiftItemSelection(selection, byText.length());
} }
void UnreadBar::init() { void UnreadBar::init(const QString &string) {
text = tr::lng_unread_bar_some(tr::now); text = string;
width = st::semiboldFont->width(text); width = st::semiboldFont->width(text);
} }
@ -440,12 +440,18 @@ bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
return false; return false;
} }
void Element::createUnreadBar() { void Element::createUnreadBar(rpl::producer<QString> text) {
if (!AddComponents(UnreadBar::Bit())) { if (!AddComponents(UnreadBar::Bit())) {
return; return;
} }
const auto bar = Get<UnreadBar>(); const auto bar = Get<UnreadBar>();
bar->init(); std::move(
text
) | rpl::start_with_next([=](const QString &text) {
if (const auto bar = Get<UnreadBar>()) {
bar->init(text);
}
}, bar->lifetime);
if (data()->mainView() == this) { if (data()->mainView() == this) {
recountAttachToPreviousInBlocks(); recountAttachToPreviousInBlocks();
} }

View file

@ -118,7 +118,7 @@ TextSelection ShiftItemSelection(
// Any HistoryView::Element can have this Component for // Any HistoryView::Element can have this Component for
// displaying the unread messages bar above the message. // displaying the unread messages bar above the message.
struct UnreadBar : public RuntimeComponent<UnreadBar, Element> { struct UnreadBar : public RuntimeComponent<UnreadBar, Element> {
void init(); void init(const QString &string);
static int height(); static int height();
static int marginTop(); static int marginTop();
@ -127,6 +127,7 @@ struct UnreadBar : public RuntimeComponent<UnreadBar, Element> {
QString text; QString text;
int width = 0; int width = 0;
rpl::lifetime lifetime;
}; };
@ -206,7 +207,7 @@ public:
bool computeIsAttachToPrevious(not_null<Element*> previous); bool computeIsAttachToPrevious(not_null<Element*> previous);
void createUnreadBar(); void createUnreadBar(rpl::producer<QString> text);
void destroyUnreadBar(); void destroyUnreadBar();
int displayedDateHeight() const; int displayedDateHeight() const;

View file

@ -394,13 +394,23 @@ void ListWidget::animatedScrollTo(
_delegate->listScrollTo(scrollTop); _delegate->listScrollTo(scrollTop);
return; return;
} }
const auto transition = (type == AnimatedScroll::Full)
? anim::sineInOut
: anim::easeOutCubic;
if (delta > 0 && scrollTop == height() - (_visibleBottom - _visibleTop)) {
// Animated scroll to bottom.
_scrollToAnimation.start(
[=] { scrollToAnimationCallback(FullMsgId(), 0); },
-delta,
0,
st::slideDuration,
transition);
return;
}
const auto index = findNearestItem(attachPosition); const auto index = findNearestItem(attachPosition);
Assert(index >= 0 && index < int(_items.size())); Assert(index >= 0 && index < int(_items.size()));
const auto attachTo = _items[index]; const auto attachTo = _items[index];
const auto attachToId = attachTo->data()->fullId(); const auto attachToId = attachTo->data()->fullId();
const auto transition = (type == AnimatedScroll::Full)
? anim::sineInOut
: anim::easeOutCubic;
const auto initial = scrollTop - delta; const auto initial = scrollTop - delta;
_delegate->listScrollTo(initial); _delegate->listScrollTo(initial);
@ -422,6 +432,14 @@ bool ListWidget::animatedScrolling() const {
void ListWidget::scrollToAnimationCallback( void ListWidget::scrollToAnimationCallback(
FullMsgId attachToId, FullMsgId attachToId,
int relativeTo) { int relativeTo) {
if (!attachToId) {
// Animated scroll to bottom.
const auto current = int(std::round(_scrollToAnimation.value(0)));
_delegate->listScrollTo(height()
- (_visibleBottom - _visibleTop)
+ current);
return;
}
const auto attachTo = session().data().message(attachToId); const auto attachTo = session().data().message(attachToId);
const auto attachToView = viewForItem(attachTo); const auto attachToView = viewForItem(attachTo);
if (!attachToView) { if (!attachToView) {
@ -483,11 +501,14 @@ void ListWidget::updateHighlightedMessage() {
} }
void ListWidget::checkUnreadBarCreation() { void ListWidget::checkUnreadBarCreation() {
if (!_unreadBarElement) { if (!_bar.element) {
if (const auto index = _delegate->listUnreadBarView(_items)) { if (auto data = _delegate->listMessagesBar(_items); data.bar.element) {
_unreadBarElement = _items[*index].get(); _bar = std::move(data.bar);
_unreadBarElement->createUnreadBar(); _barText = std::move(data.text);
refreshAttachmentsAtIndex(*index); _bar.element->createUnreadBar(_barText.value());
const auto i = ranges::find(_items, not_null{ _bar.element });
Assert(i != end(_items));
refreshAttachmentsAtIndex(i - begin(_items));
} }
} }
} }
@ -507,10 +528,10 @@ void ListWidget::restoreScrollState() {
return; return;
} }
if (!_scrollTopState.item) { if (!_scrollTopState.item) {
if (!_unreadBarElement) { if (!_bar.element || !_bar.focus) {
return; return;
} }
_scrollTopState.item = _unreadBarElement->data()->position(); _scrollTopState.item = _bar.element->data()->position();
_scrollTopState.shift = st::lineWidth + st::historyUnreadBarMargin; _scrollTopState.shift = st::lineWidth + st::historyUnreadBarMargin;
} }
const auto index = findNearestItem(_scrollTopState.item); const auto index = findNearestItem(_scrollTopState.item);
@ -2605,11 +2626,11 @@ void ListWidget::viewReplaced(not_null<const Element*> was, Element *now) {
if (_visibleTopItem == was) _visibleTopItem = now; if (_visibleTopItem == was) _visibleTopItem = now;
if (_scrollDateLastItem == was) _scrollDateLastItem = now; if (_scrollDateLastItem == was) _scrollDateLastItem = now;
if (_overElement == was) _overElement = now; if (_overElement == was) _overElement = now;
if (_unreadBarElement == was) { if (_bar.element == was.get()) {
const auto bar = _unreadBarElement->Get<UnreadBar>(); const auto bar = _bar.element->Get<UnreadBar>();
_unreadBarElement = now; _bar.element = now;
if (now && bar) { if (now && bar) {
_unreadBarElement->createUnreadBar(); _bar.element->createUnreadBar(_barText.value());
} }
} }
} }

View file

@ -48,7 +48,16 @@ struct SelectedItem {
bool canDelete = false; bool canDelete = false;
bool canForward = false; bool canForward = false;
bool canSendNow = false; bool canSendNow = false;
};
struct MessagesBar {
Element *element = nullptr;
bool focus = false;
};
struct MessagesBarData {
MessagesBar bar;
rpl::producer<QString> text;
}; };
using SelectedItems = std::vector<SelectedItem>; using SelectedItems = std::vector<SelectedItem>;
@ -70,7 +79,7 @@ public:
not_null<HistoryItem*> second) = 0; not_null<HistoryItem*> second) = 0;
virtual void listSelectionChanged(SelectedItems &&items) = 0; virtual void listSelectionChanged(SelectedItems &&items) = 0;
virtual void listVisibleItemsChanged(HistoryItemsList &&items) = 0; virtual void listVisibleItemsChanged(HistoryItemsList &&items) = 0;
virtual std::optional<int> listUnreadBarView( virtual MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) = 0; const std::vector<not_null<Element*>> &elements) = 0;
virtual void listContentRefreshed() = 0; virtual void listContentRefreshed() = 0;
virtual ClickHandlerPtr listDateLink(not_null<Element*> view) = 0; virtual ClickHandlerPtr listDateLink(not_null<Element*> view) = 0;
@ -493,7 +502,8 @@ private:
ClickHandlerPtr _scrollDateLink; ClickHandlerPtr _scrollDateLink;
SingleQueuedInvokation _applyUpdatedScrollState; SingleQueuedInvokation _applyUpdatedScrollState;
Element *_unreadBarElement = nullptr; MessagesBar _bar;
rpl::variable<QString> _barText;
MouseAction _mouseAction = MouseAction::None; MouseAction _mouseAction = MouseAction::None;
TextSelectType _mouseSelectType = TextSelectType::Letters; TextSelectType _mouseSelectType = TextSelectType::Letters;

View file

@ -1212,26 +1212,7 @@ void RepliesWidget::saveState(not_null<RepliesMemento*> memento) {
void RepliesWidget::restoreState(not_null<RepliesMemento*> memento) { void RepliesWidget::restoreState(not_null<RepliesMemento*> memento) {
const auto setReplies = [&](std::shared_ptr<Data::RepliesList> replies) { const auto setReplies = [&](std::shared_ptr<Data::RepliesList> replies) {
_replies = std::move(replies); _replies = std::move(replies);
_topBar->setCustomTitle(tr::lng_manage_discussion_group(tr::now));
rpl::single(
tr::lng_contacts_loading()
) | rpl::then(rpl::combine(
_replies->fullCount(),
_areComments.value()
) | rpl::map([=](int count, bool areComments) {
return count
? (areComments
? tr::lng_comments_header
: tr::lng_replies_header)(
lt_count,
rpl::single(count) | tr::to_count())
: (areComments
? tr::lng_comments_header_none
: tr::lng_replies_header_none)();
})) | rpl::flatten_latest(
) | rpl::start_with_next([=](const QString &text) {
_topBar->setCustomTitle(text);
}, lifetime());
}; };
if (auto replies = memento->getReplies()) { if (auto replies = memento->getReplies()) {
setReplies(std::move(replies)); setReplies(std::move(replies));
@ -1447,15 +1428,19 @@ void RepliesWidget::listSelectionChanged(SelectedItems &&items) {
_topBar->showSelected(state); _topBar->showSelected(state);
} }
void RepliesWidget::readTill(MsgId tillId) { void RepliesWidget::readTill(not_null<HistoryItem*> item) {
if (!_commentsRoot) { if (!_commentsRoot) {
return; return;
} }
const auto now = _commentsRoot->commentsReadTill(); const auto was = _commentsRoot->commentsReadTill();
if (now < tillId) { const auto now = item->id;
_commentsRoot->setCommentsReadTill(tillId); const auto fast = item->out();
if (was < now) {
_commentsRoot->setCommentsReadTill(now);
if (!_readRequestTimer.isActive()) { if (!_readRequestTimer.isActive()) {
_readRequestTimer.callOnce(kReadRequestTimeout); _readRequestTimer.callOnce(fast ? 0 : kReadRequestTimeout);
} else if (fast && _readRequestTimer.remainingTime() > 0) {
_readRequestTimer.callOnce(0);
} }
} }
} }
@ -1466,31 +1451,66 @@ void RepliesWidget::listVisibleItemsChanged(HistoryItemsList &&items) {
return IsServerMsgId(item->id); return IsServerMsgId(item->id);
}); });
if (good != end(reversed)) { if (good != end(reversed)) {
readTill((*good)->id); readTill(*good);
} }
} }
std::optional<int> RepliesWidget::listUnreadBarView( MessagesBarData RepliesWidget::listMessagesBar(
const std::vector<not_null<Element*>> &elements) { const std::vector<not_null<Element*>> &elements) {
if (!_commentsRoot) { if (!_commentsRoot || elements.empty()) {
return std::nullopt; return MessagesBarData();
} }
const auto rootBar = [&] {
const auto fromRoot = (elements.front()->data().get() == _root);
if (elements.size() < 2 || !fromRoot) {
return MessagesBarData();
}
auto text = rpl::combine(
_replies->fullCount(),
_areComments.value()
) | rpl::map([=](int count, bool areComments) {
return count
? (areComments
? tr::lng_comments_header
: tr::lng_replies_header)(
lt_count,
rpl::single(count) | tr::to_count())
: (areComments
? tr::lng_comments_header_none
: tr::lng_replies_header_none)();
}) | rpl::flatten_latest();
return MessagesBarData{
// Designated initializers here crash MSVC 16.7.3.
MessagesBar{
.element = elements[1],
.focus = false,
},
std::move(text),
};
};
const auto till = _commentsRoot->commentsReadTill(); const auto till = _commentsRoot->commentsReadTill();
if (till < 2) { if (till < 2) {
return std::nullopt; return rootBar();
} }
for (auto i = 0, count = int(elements.size()); i != count; ++i) { for (auto i = 0, count = int(elements.size()); i != count; ++i) {
const auto item = elements[i]->data(); const auto item = elements[i]->data();
if (item->id > till) { if (IsServerMsgId(item->id) && item->id > till) {
if (item->out()) { if (item->out()) {
_commentsRoot->setCommentsReadTill(item->id); readTill(item);
_readRequestTimer.callOnce(kReadRequestTimeout);
} else { } else {
return i; return MessagesBarData{
// Designated initializers here crash MSVC 16.7.3.
MessagesBar{
.element = elements[i],
.focus = true,
},
tr::lng_unread_bar_some(),
};
} }
} }
} }
return std::nullopt; return rootBar();
} }
void RepliesWidget::listContentRefreshed() { void RepliesWidget::listContentRefreshed() {

View file

@ -116,7 +116,7 @@ public:
not_null<HistoryItem*> second) override; not_null<HistoryItem*> second) override;
void listSelectionChanged(SelectedItems &&items) override; void listSelectionChanged(SelectedItems &&items) override;
void listVisibleItemsChanged(HistoryItemsList &&items) override; void listVisibleItemsChanged(HistoryItemsList &&items) override;
std::optional<int> listUnreadBarView( MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) override; const std::vector<not_null<Element*>> &elements) override;
void listContentRefreshed() override; void listContentRefreshed() override;
ClickHandlerPtr listDateLink(not_null<Element*> view) override; ClickHandlerPtr listDateLink(not_null<Element*> view) override;
@ -155,7 +155,7 @@ private:
void refreshRootView(); void refreshRootView();
void setupDragArea(); void setupDragArea();
void sendReadTillRequest(); void sendReadTillRequest();
void readTill(MsgId id); void readTill(not_null<HistoryItem*> item);
void setupScrollDownButton(); void setupScrollDownButton();
void scrollDownClicked(); void scrollDownClicked();

View file

@ -1134,9 +1134,9 @@ void ScheduledWidget::listSelectionChanged(SelectedItems &&items) {
void ScheduledWidget::listVisibleItemsChanged(HistoryItemsList &&items) { void ScheduledWidget::listVisibleItemsChanged(HistoryItemsList &&items) {
} }
std::optional<int> ScheduledWidget::listUnreadBarView( MessagesBarData ScheduledWidget::listMessagesBar(
const std::vector<not_null<Element*>> &elements) { const std::vector<not_null<Element*>> &elements) {
return std::nullopt; return MessagesBarData();
} }
void ScheduledWidget::listContentRefreshed() { void ScheduledWidget::listContentRefreshed() {

View file

@ -106,7 +106,7 @@ public:
not_null<HistoryItem*> second) override; not_null<HistoryItem*> second) override;
void listSelectionChanged(SelectedItems &&items) override; void listSelectionChanged(SelectedItems &&items) override;
void listVisibleItemsChanged(HistoryItemsList &&items) override; void listVisibleItemsChanged(HistoryItemsList &&items) override;
std::optional<int> listUnreadBarView( MessagesBarData listMessagesBar(
const std::vector<not_null<Element*>> &elements) override; const std::vector<not_null<Element*>> &elements) override;
void listContentRefreshed() override; void listContentRefreshed() override;
ClickHandlerPtr listDateLink(not_null<Element*> view) override; ClickHandlerPtr listDateLink(not_null<Element*> view) override;