mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 23:53:58 +02:00
Show comments bar when no unread bar.
This commit is contained in:
parent
cf48152853
commit
9abca29f4c
9 changed files with 121 additions and 63 deletions
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue