Show local sending messages in replies section.

This commit is contained in:
John Preston 2020-09-04 20:11:36 +04:00
parent beb623bee2
commit 78d83a2c69
11 changed files with 207 additions and 27 deletions

View file

@ -20,7 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Data {
namespace {
constexpr auto kMessagesPerPage = 16;
constexpr auto kMessagesPerPage = 50;
} // namespace
@ -45,6 +45,21 @@ rpl::producer<MessagesSlice> RepliesList::source(
MessagePosition aroundId,
int limitBefore,
int limitAfter) {
return rpl::combine(
sourceFromServer(aroundId, limitBefore, limitAfter),
_history->session().changes().historyFlagsValue(
_history,
Data::HistoryUpdate::Flag::LocalMessages)
) | rpl::map([=](MessagesSlice &&server, const auto &) {
appendLocalMessages(server);
return std::move(server);
});
}
rpl::producer<MessagesSlice> RepliesList::sourceFromServer(
MessagePosition aroundId,
int limitBefore,
int limitAfter) {
const auto around = aroundId.fullId.msg;
return [=](auto consumer) {
auto lifetime = rpl::lifetime();
@ -78,6 +93,65 @@ rpl::producer<MessagesSlice> RepliesList::source(
};
}
void RepliesList::appendLocalMessages(MessagesSlice &slice) {
const auto &local = _history->localMessages();
if (local.empty()) {
return;
} else if (slice.ids.empty()) {
if (slice.skippedBefore != 0 || slice.skippedAfter != 0) {
return;
}
slice.ids.reserve(local.size());
for (const auto item : local) {
if (item->replyToTop() != _rootId) {
continue;
}
slice.ids.push_back(item->fullId());
}
ranges::sort(slice.ids);
return;
}
auto &owner = _history->owner();
auto dates = std::vector<TimeId>();
dates.reserve(slice.ids.size());
for (const auto &id : slice.ids) {
const auto message = owner.message(id);
Assert(message != nullptr);
dates.push_back(message->date());
}
for (const auto item : local) {
if (item->replyToTop() != _rootId) {
continue;
}
const auto date = item->date();
if (date < dates.front()) {
if (slice.skippedBefore != 0) {
if (slice.skippedBefore) {
++*slice.skippedBefore;
}
continue;
}
dates.insert(dates.begin(), date);
slice.ids.insert(slice.ids.begin(), item->fullId());
} else {
auto to = dates.size();
for (; to != 0; --to) {
const auto checkId = slice.ids[to - 1].msg;
if (dates[to - 1] > date) {
continue;
} else if (dates[to - 1] < date
|| IsServerMsgId(checkId)
|| checkId < item->id) {
break;
}
}
dates.insert(dates.begin() + to, date);
slice.ids.insert(slice.ids.begin() + to, item->fullId());
}
}
}
rpl::producer<int> RepliesList::fullCount() const {
return _fullCount.value() | rpl::filter_optional();
}

View file

@ -35,6 +35,12 @@ private:
[[nodiscard]] Histories &histories();
[[nodiscard]] rpl::producer<MessagesSlice> sourceFromServer(
MessagePosition aroundId,
int limitBefore,
int limitAfter);
void appendLocalMessages(MessagesSlice &slice);
[[nodiscard]] bool buildFromData(not_null<Viewer*> viewer);
[[nodiscard]] bool applyUpdate(
not_null<Viewer*> viewer,

View file

@ -1338,6 +1338,10 @@ void History::unregisterLocalMessage(not_null<HistoryItem*> item) {
session().changes().historyUpdated(this, UpdateFlag::LocalMessages);
}
const base::flat_set<not_null<HistoryItem*>> &History::localMessages() {
return _localMessages;
}
HistoryItem *History::latestSendingMessage() const {
auto sending = ranges::view::all(
_localMessages

View file

@ -77,6 +77,7 @@ public:
void checkLocalMessages();
void removeJoinedMessage();
bool isEmpty() const;
bool isDisplayedEmpty() const;
Element *findFirstNonEmpty() const;
@ -181,6 +182,8 @@ public:
void registerLocalMessage(not_null<HistoryItem*> item);
void unregisterLocalMessage(not_null<HistoryItem*> item);
[[nodiscard]] auto localMessages()
-> const base::flat_set<not_null<HistoryItem*>> &;
[[nodiscard]] HistoryItem *latestSendingMessage() const;
[[nodiscard]] bool readInboxTillNeedsRequest(MsgId tillId);

View file

@ -552,13 +552,36 @@ not_null<Element*> ListWidget::enforceViewForItem(
}
void ListWidget::updateAroundPositionFromRows() {
_aroundIndex = findNearestItem(_aroundPosition);
if (_aroundIndex >= 0) {
const auto newPosition = _items[_aroundIndex]->data()->position();
if (_aroundPosition != newPosition) {
_aroundPosition = newPosition;
crl::on_main(this, [=] { refreshViewer(); });
const auto nearestIndex = findNearestItem(_aroundPosition);
if (nearestIndex < 0) {
_aroundIndex = -1;
return;
}
const auto isGoodIndex = [&](int index) {
Expects(index >= 0 && index < _items.size());
return _delegate->listIsGoodForAroundPosition(_items[index]);
};
_aroundIndex = [&] {
for (auto index = nearestIndex; index < _items.size(); ++index) {
if (isGoodIndex(index)) {
return index;
}
}
for (auto index = nearestIndex; index != 0;) {
if (isGoodIndex(--index)) {
return index;
}
}
return -1;
}();
if (_aroundIndex < 0) {
return;
}
const auto newPosition = _items[_aroundIndex]->data()->position();
if (_aroundPosition != newPosition) {
_aroundPosition = newPosition;
crl::on_main(this, [=] { refreshViewer(); });
}
}
@ -1055,8 +1078,8 @@ void ListWidget::checkMoveToOtherViewer() {
return;
}
auto topItem = findItemByY(_visibleTop);
auto bottomItem = findItemByY(_visibleBottom);
auto topItemIndex = findItemIndexByY(_visibleTop);
auto bottomItemIndex = findItemIndexByY(_visibleBottom);
auto preloadedHeight = kPreloadedScreensCountFull * visibleHeight;
auto preloadedCount = preloadedHeight / _itemAverageHeight;
auto preloadIdsLimitMin = (preloadedCount / 2) + 1;
@ -1075,32 +1098,64 @@ void ListWidget::checkMoveToOtherViewer() {
- kPreloadIfLessThanScreens;
auto minUniversalIdDelta = (minScreenDelta * visibleHeight)
/ _itemAverageHeight;
auto preloadAroundMessage = [&](not_null<Element*> view) {
const auto preloadAroundMessage = [&](int index) {
Expects(index >= 0 && index < _items.size());
auto preloadRequired = false;
auto itemPosition = view->data()->position();
auto itemIndex = ranges::find(_items, view) - begin(_items);
Assert(itemIndex < _items.size());
auto itemPosition = _items[index]->data()->position();
if (!preloadRequired) {
preloadRequired = (_idsLimit < preloadIdsLimitMin);
}
if (!preloadRequired) {
Assert(_aroundIndex >= 0);
auto delta = std::abs(itemIndex - _aroundIndex);
auto delta = std::abs(index - _aroundIndex);
preloadRequired = (delta >= minUniversalIdDelta);
}
if (preloadRequired) {
_idsLimit = preloadIdsLimit;
_aroundPosition = itemPosition;
_aroundIndex = itemIndex;
_aroundIndex = index;
refreshViewer();
}
};
const auto findGoodAbove = [&](int index) {
Expects(index >= 0 && index < _items.size());
for (; index != _items.size(); ++index) {
if (_delegate->listIsGoodForAroundPosition(_items[index])) {
return index;
}
}
return -1;
};
const auto findGoodBelow = [&](int index) {
Expects(index >= 0 && index < _items.size());
for (++index; index != 0;) {
if (_delegate->listIsGoodForAroundPosition(_items[--index])) {
return index;
}
}
return -1;
};
if (preloadTop && !topLoaded) {
preloadAroundMessage(topItem);
const auto goodAboveIndex = findGoodAbove(topItemIndex);
const auto goodIndex = (goodAboveIndex >= 0)
? goodAboveIndex
: findGoodBelow(topItemIndex);
if (goodIndex >= 0) {
preloadAroundMessage(goodIndex);
}
} else if (preloadBottom && !bottomLoaded) {
preloadAroundMessage(bottomItem);
const auto goodBelowIndex = findGoodBelow(bottomItemIndex);
const auto goodIndex = (goodBelowIndex >= 0)
? goodBelowIndex
: findGoodAbove(bottomItemIndex);
if (goodIndex >= 0) {
preloadAroundMessage(goodIndex);
}
}
}
@ -1553,20 +1608,24 @@ MessageIdsList ListWidget::getSelectedItems() const {
return collectSelectedIds();
}
not_null<Element*> ListWidget::findItemByY(int y) const {
int ListWidget::findItemIndexByY(int y) const {
Expects(!_items.empty());
if (y < _itemsTop) {
return _items.front();
return 0;
}
auto i = std::lower_bound(
begin(_items),
end(_items),
y,
[this](auto &elem, int top) {
return this->itemTop(elem) + elem->height() <= top;
});
return (i != end(_items)) ? i->get() : _items.back().get();
return this->itemTop(elem) + elem->height() <= top;
});
return std::min(int(i - begin(_items)), int(_items.size() - 1));
}
not_null<Element*> ListWidget::findItemByY(int y) const {
return _items[findItemIndexByY(y)];
}
Element *ListWidget::strictFindItemByY(int y) const {

View file

@ -75,6 +75,8 @@ public:
virtual void listContentRefreshed() = 0;
virtual ClickHandlerPtr listDateLink(not_null<Element*> view) = 0;
virtual bool listElementHideReply(not_null<const Element*> view) = 0;
virtual bool listIsGoodForAroundPosition(
not_null<const Element*> view) = 0;
};
@ -322,11 +324,12 @@ private:
void showContextMenu(QContextMenuEvent *e, bool showFromTouch = false);
not_null<Element*> findItemByY(int y) const;
Element *strictFindItemByY(int y) const;
int findNearestItem(Data::MessagePosition position) const;
[[nodiscard]] int findItemIndexByY(int y) const;
[[nodiscard]] not_null<Element*> findItemByY(int y) const;
[[nodiscard]] Element *strictFindItemByY(int y) const;
[[nodiscard]] int findNearestItem(Data::MessagePosition position) const;
void viewReplaced(not_null<const Element*> was, Element *now);
HistoryItemsList collectVisibleItems() const;
[[nodiscard]] HistoryItemsList collectVisibleItems() const;
void checkMoveToOtherViewer();
void updateVisibleTopItem();

View file

@ -135,6 +135,10 @@ RepliesWidget::RepliesWidget(
) | rpl::start_with_next([=] {
confirmDeleteSelected();
}, _topBar->lifetime());
_topBar->forwardSelectionRequest(
) | rpl::start_with_next([=] {
confirmForwardSelected();
}, _topBar->lifetime());
_topBar->clearSelectionRequest(
) | rpl::start_with_next([=] {
clearSelected();
@ -1380,6 +1384,11 @@ bool RepliesWidget::listElementHideReply(not_null<const Element*> view) {
return (view->data()->replyToId() == _rootId);
}
bool RepliesWidget::listIsGoodForAroundPosition(
not_null<const Element*> view) {
return IsServerMsgId(view->data()->id);
}
void RepliesWidget::confirmSendNowSelected() {
auto items = _inner->getSelectedItems();
if (items.empty()) {
@ -1409,6 +1418,19 @@ void RepliesWidget::confirmDeleteSelected() {
});
}
void RepliesWidget::confirmForwardSelected() {
auto items = _inner->getSelectedItems();
if (items.empty()) {
return;
}
const auto weak = Ui::MakeWeak(this);
Window::ShowForwardMessagesBox(controller(), std::move(items), [=] {
if (const auto strong = weak.data()) {
strong->clearSelected();
}
});
}
void RepliesWidget::clearSelected() {
_inner->cancelSelection();
}

View file

@ -120,6 +120,7 @@ public:
void listContentRefreshed() override;
ClickHandlerPtr listDateLink(not_null<Element*> view) override;
bool listElementHideReply(not_null<const Element*> view) override;
bool listIsGoodForAroundPosition(not_null<const Element*> view) override;
protected:
void resizeEvent(QResizeEvent *e) override;
@ -158,6 +159,7 @@ private:
void confirmSendNowSelected();
void confirmDeleteSelected();
void confirmForwardSelected();
void clearSelected();
void send();

View file

@ -1150,6 +1150,11 @@ bool ScheduledWidget::listElementHideReply(not_null<const Element*> view) {
return false;
}
bool ScheduledWidget::listIsGoodForAroundPosition(
not_null<const Element*> view) {
return true;
}
void ScheduledWidget::confirmSendNowSelected() {
auto items = _inner->getSelectedItems();
if (items.empty()) {

View file

@ -111,6 +111,7 @@ public:
void listContentRefreshed() override;
ClickHandlerPtr listDateLink(not_null<Element*> view) override;
bool listElementHideReply(not_null<const Element*> view) override;
bool listIsGoodForAroundPosition(not_null<const Element *> view) override;
protected:
void resizeEvent(QResizeEvent *e) override;

View file

@ -709,8 +709,9 @@ void MainWidget::cancelUploadLayer(not_null<HistoryItem*> item) {
auto &data = session().data();
if (const auto item = data.message(itemId)) {
if (!item->isEditingMedia()) {
const auto history = item->history();
item->destroy();
item->history()->requestChatListMessage();
history->requestChatListMessage();
} else {
item->returnSavedMedia();
session().uploader().cancel(item->fullId());