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()) {
_unreadBarView = _firstUnreadView;
_unreadBarView->createUnreadBar();
_unreadBarView->createUnreadBar(tr::lng_unread_bar_some());
}
}

View file

@ -144,8 +144,8 @@ TextSelection ShiftItemSelection(
return ShiftItemSelection(selection, byText.length());
}
void UnreadBar::init() {
text = tr::lng_unread_bar_some(tr::now);
void UnreadBar::init(const QString &string) {
text = string;
width = st::semiboldFont->width(text);
}
@ -440,12 +440,18 @@ bool Element::computeIsAttachToPrevious(not_null<Element*> previous) {
return false;
}
void Element::createUnreadBar() {
void Element::createUnreadBar(rpl::producer<QString> text) {
if (!AddComponents(UnreadBar::Bit())) {
return;
}
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) {
recountAttachToPreviousInBlocks();
}

View file

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

View file

@ -394,13 +394,23 @@ void ListWidget::animatedScrollTo(
_delegate->listScrollTo(scrollTop);
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);
Assert(index >= 0 && index < int(_items.size()));
const auto attachTo = _items[index];
const auto attachToId = attachTo->data()->fullId();
const auto transition = (type == AnimatedScroll::Full)
? anim::sineInOut
: anim::easeOutCubic;
const auto initial = scrollTop - delta;
_delegate->listScrollTo(initial);
@ -422,6 +432,14 @@ bool ListWidget::animatedScrolling() const {
void ListWidget::scrollToAnimationCallback(
FullMsgId attachToId,
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 attachToView = viewForItem(attachTo);
if (!attachToView) {
@ -483,11 +501,14 @@ void ListWidget::updateHighlightedMessage() {
}
void ListWidget::checkUnreadBarCreation() {
if (!_unreadBarElement) {
if (const auto index = _delegate->listUnreadBarView(_items)) {
_unreadBarElement = _items[*index].get();
_unreadBarElement->createUnreadBar();
refreshAttachmentsAtIndex(*index);
if (!_bar.element) {
if (auto data = _delegate->listMessagesBar(_items); data.bar.element) {
_bar = std::move(data.bar);
_barText = std::move(data.text);
_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;
}
if (!_scrollTopState.item) {
if (!_unreadBarElement) {
if (!_bar.element || !_bar.focus) {
return;
}
_scrollTopState.item = _unreadBarElement->data()->position();
_scrollTopState.item = _bar.element->data()->position();
_scrollTopState.shift = st::lineWidth + st::historyUnreadBarMargin;
}
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 (_scrollDateLastItem == was) _scrollDateLastItem = now;
if (_overElement == was) _overElement = now;
if (_unreadBarElement == was) {
const auto bar = _unreadBarElement->Get<UnreadBar>();
_unreadBarElement = now;
if (_bar.element == was.get()) {
const auto bar = _bar.element->Get<UnreadBar>();
_bar.element = now;
if (now && bar) {
_unreadBarElement->createUnreadBar();
_bar.element->createUnreadBar(_barText.value());
}
}
}

View file

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

View file

@ -1212,26 +1212,7 @@ void RepliesWidget::saveState(not_null<RepliesMemento*> memento) {
void RepliesWidget::restoreState(not_null<RepliesMemento*> memento) {
const auto setReplies = [&](std::shared_ptr<Data::RepliesList> replies) {
_replies = std::move(replies);
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());
_topBar->setCustomTitle(tr::lng_manage_discussion_group(tr::now));
};
if (auto replies = memento->getReplies()) {
setReplies(std::move(replies));
@ -1447,15 +1428,19 @@ void RepliesWidget::listSelectionChanged(SelectedItems &&items) {
_topBar->showSelected(state);
}
void RepliesWidget::readTill(MsgId tillId) {
void RepliesWidget::readTill(not_null<HistoryItem*> item) {
if (!_commentsRoot) {
return;
}
const auto now = _commentsRoot->commentsReadTill();
if (now < tillId) {
_commentsRoot->setCommentsReadTill(tillId);
const auto was = _commentsRoot->commentsReadTill();
const auto now = item->id;
const auto fast = item->out();
if (was < now) {
_commentsRoot->setCommentsReadTill(now);
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);
});
if (good != end(reversed)) {
readTill((*good)->id);
readTill(*good);
}
}
std::optional<int> RepliesWidget::listUnreadBarView(
MessagesBarData RepliesWidget::listMessagesBar(
const std::vector<not_null<Element*>> &elements) {
if (!_commentsRoot) {
return std::nullopt;
if (!_commentsRoot || elements.empty()) {
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();
if (till < 2) {
return std::nullopt;
return rootBar();
}
for (auto i = 0, count = int(elements.size()); i != count; ++i) {
const auto item = elements[i]->data();
if (item->id > till) {
if (IsServerMsgId(item->id) && item->id > till) {
if (item->out()) {
_commentsRoot->setCommentsReadTill(item->id);
_readRequestTimer.callOnce(kReadRequestTimeout);
readTill(item);
} 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() {

View file

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

View file

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

View file

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