Allow collapsing archive in the chats list.

This commit is contained in:
John Preston 2019-05-03 14:55:44 +04:00
parent 6f885fb6cc
commit 4356b1c193
9 changed files with 348 additions and 209 deletions

View File

@ -1285,6 +1285,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_unpin_from_top" = "Unpin from top"; "lng_context_unpin_from_top" = "Unpin from top";
"lng_context_mark_unread" = "Mark as unread"; "lng_context_mark_unread" = "Mark as unread";
"lng_context_mark_read" = "Mark as read"; "lng_context_mark_read" = "Mark as read";
"lng_context_archive_expand" = "Expand";
"lng_context_archive_collapse" = "Collapse";
"lng_context_promote_admin" = "Promote to admin"; "lng_context_promote_admin" = "Promote to admin";
"lng_context_edit_permissions" = "Edit permissions"; "lng_context_edit_permissions" = "Edit permissions";

View File

@ -93,6 +93,7 @@ QByteArray AuthSessionSettings::serialize() const {
stream << qint32(_variables.exeLaunchWarning ? 1 : 0); stream << qint32(_variables.exeLaunchWarning ? 1 : 0);
stream << autoDownload; stream << autoDownload;
stream << qint32(_variables.supportAllSearchResults.current() ? 1 : 0); stream << qint32(_variables.supportAllSearchResults.current() ? 1 : 0);
stream << qint32(_variables.archiveCollapsed.current() ? 1 : 0);
} }
return result; return result;
} }
@ -129,6 +130,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
qint32 exeLaunchWarning = _variables.exeLaunchWarning ? 1 : 0; qint32 exeLaunchWarning = _variables.exeLaunchWarning ? 1 : 0;
QByteArray autoDownload; QByteArray autoDownload;
qint32 supportAllSearchResults = _variables.supportAllSearchResults.current() ? 1 : 0; qint32 supportAllSearchResults = _variables.supportAllSearchResults.current() ? 1 : 0;
qint32 archiveCollapsed = _variables.archiveCollapsed.current() ? 1 : 0;
stream >> selectorTab; stream >> selectorTab;
stream >> lastSeenWarningSeen; stream >> lastSeenWarningSeen;
@ -208,6 +210,9 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
if (!stream.atEnd()) { if (!stream.atEnd()) {
stream >> supportAllSearchResults; stream >> supportAllSearchResults;
} }
if (!stream.atEnd()) {
stream >> archiveCollapsed;
}
if (stream.status() != QDataStream::Ok) { if (stream.status() != QDataStream::Ok) {
LOG(("App Error: " LOG(("App Error: "
"Bad data for AuthSessionSettings::constructFromSerialized()")); "Bad data for AuthSessionSettings::constructFromSerialized()"));
@ -277,6 +282,7 @@ void AuthSessionSettings::constructFromSerialized(const QByteArray &serialized)
_variables.countUnreadMessages = (countUnreadMessages == 1); _variables.countUnreadMessages = (countUnreadMessages == 1);
_variables.exeLaunchWarning = (exeLaunchWarning == 1); _variables.exeLaunchWarning = (exeLaunchWarning == 1);
_variables.supportAllSearchResults = (supportAllSearchResults == 1); _variables.supportAllSearchResults = (supportAllSearchResults == 1);
_variables.archiveCollapsed = (archiveCollapsed == 1);
} }
void AuthSessionSettings::setSupportChatsTimeSlice(int slice) { void AuthSessionSettings::setSupportChatsTimeSlice(int slice) {
@ -371,8 +377,20 @@ rpl::producer<int> AuthSessionSettings::thirdColumnWidthChanges() const {
return _variables.thirdColumnWidth.changes(); return _variables.thirdColumnWidth.changes();
} }
void AuthSessionSettings::setArchiveCollapsed(bool collapsed) {
_variables.archiveCollapsed = collapsed;
}
bool AuthSessionSettings::archiveCollapsed() const {
return _variables.archiveCollapsed.current();
}
rpl::producer<bool> AuthSessionSettings::archiveCollapsedChanges() const {
return _variables.archiveCollapsed.changes();
}
AuthSession &Auth() { AuthSession &Auth() {
auto result = Core::App().authSession(); const auto result = Core::App().authSession();
Assert(result != nullptr); Assert(result != nullptr);
return *result; return *result;
} }

View File

@ -188,6 +188,10 @@ public:
return _variables.autoDownload; return _variables.autoDownload;
} }
void setArchiveCollapsed(bool collapsed);
bool archiveCollapsed() const;
rpl::producer<bool> archiveCollapsedChanges() const;
bool hadLegacyCallsPeerToPeerNobody() const { bool hadLegacyCallsPeerToPeerNobody() const {
return _variables.hadLegacyCallsPeerToPeerNobody; return _variables.hadLegacyCallsPeerToPeerNobody;
} }
@ -240,6 +244,7 @@ private:
bool countUnreadMessages = true; bool countUnreadMessages = true;
bool exeLaunchWarning = true; bool exeLaunchWarning = true;
Data::AutoDownload::Full autoDownload; Data::AutoDownload::Full autoDownload;
rpl::variable<bool> archiveCollapsed = false;
static constexpr auto kDefaultSupportChatsLimitSlice static constexpr auto kDefaultSupportChatsLimitSlice
= 7 * 24 * 60 * 60; = 7 * 24 * 60 * 60;

View File

@ -75,29 +75,30 @@ FolderId Folder::id() const {
} }
void Folder::indexNameParts() { void Folder::indexNameParts() {
_nameWords.clear(); // We don't want archive to be filtered in the chats list.
_nameFirstLetters.clear(); //_nameWords.clear();
auto toIndexList = QStringList(); //_nameFirstLetters.clear();
auto appendToIndex = [&](const QString &value) { //auto toIndexList = QStringList();
if (!value.isEmpty()) { //auto appendToIndex = [&](const QString &value) {
toIndexList.push_back(TextUtilities::RemoveAccents(value)); // if (!value.isEmpty()) {
} // toIndexList.push_back(TextUtilities::RemoveAccents(value));
}; // }
//};
appendToIndex(_name); //appendToIndex(_name);
const auto appendTranslit = !toIndexList.isEmpty() //const auto appendTranslit = !toIndexList.isEmpty()
&& cRussianLetters().match(toIndexList.front()).hasMatch(); // && cRussianLetters().match(toIndexList.front()).hasMatch();
if (appendTranslit) { //if (appendTranslit) {
appendToIndex(translitRusEng(toIndexList.front())); // appendToIndex(translitRusEng(toIndexList.front()));
} //}
auto toIndex = toIndexList.join(' '); //auto toIndex = toIndexList.join(' ');
toIndex += ' ' + rusKeyboardLayoutSwitch(toIndex); //toIndex += ' ' + rusKeyboardLayoutSwitch(toIndex);
const auto namesList = TextUtilities::PrepareSearchWords(toIndex); //const auto namesList = TextUtilities::PrepareSearchWords(toIndex);
for (const auto &name : namesList) { //for (const auto &name : namesList) {
_nameWords.insert(name); // _nameWords.insert(name);
_nameFirstLetters.insert(name[0]); // _nameFirstLetters.insert(name[0]);
} //}
} }
void Folder::registerOne(not_null<History*> history) { void Folder::registerOne(not_null<History*> history) {

View File

@ -74,7 +74,11 @@ int PinnedDialogsCount(not_null<Dialogs::IndexedList*> list) {
} // namespace } // namespace
struct InnerWidget::ImportantSwitch { struct InnerWidget::CollapsedRow {
explicit CollapsedRow(Data::Folder *folder = nullptr) : folder(folder) {
}
Data::Folder *folder = nullptr;
RippleRow row; RippleRow row;
}; };
@ -108,10 +112,10 @@ InnerWidget::InnerWidget(
setAttribute(Qt::WA_OpaquePaintEvent, true); setAttribute(Qt::WA_OpaquePaintEvent, true);
#endif // OS_MAC_OLD #endif // OS_MAC_OLD
if (Global::DialogsModeEnabled()) { _mode = Global::DialogsModeEnabled()
_importantSwitch = std::make_unique<ImportantSwitch>(); ? Global::DialogsMode()
_mode = Global::DialogsMode(); : Dialogs::Mode::All;
}
connect(_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact())); connect(_addContactLnk, SIGNAL(clicked()), App::wnd(), SLOT(onShowAddContact()));
_cancelSearchInChat->setClickedCallback([=] { cancelSearchInChat(); }); _cancelSearchInChat->setClickedCallback([=] { cancelSearchInChat(); });
_cancelSearchInChat->hide(); _cancelSearchInChat->hide();
@ -180,6 +184,11 @@ InnerWidget::InnerWidget(
refresh(); refresh();
}, lifetime()); }, lifetime());
session().settings().archiveCollapsedChanges(
) | rpl::start_with_next([=] {
refreshWithCollapsedRows();
}, lifetime());
subscribe(Window::Theme::Background(), [=](const Window::Theme::BackgroundUpdate &data) { subscribe(Window::Theme::Background(), [=](const Window::Theme::BackgroundUpdate &data) {
if (data.paletteChanged()) { if (data.paletteChanged()) {
Layout::clearUnreadBadgesCache(); Layout::clearUnreadBadgesCache();
@ -225,7 +234,8 @@ InnerWidget::InnerWidget(
updateDialogRow(previous); updateDialogRow(previous);
updateDialogRow(next); updateDialogRow(next);
}, lifetime()); }, lifetime());
refresh();
refreshWithCollapsedRows(true);
setupShortcuts(); setupShortcuts();
} }
@ -249,17 +259,50 @@ void InnerWidget::handleChatMigration(not_null<ChatData*> chat) {
} }
} }
bool InnerWidget::importantSwitchShown() const { void InnerWidget::refreshWithCollapsedRows(bool toTop) {
return !_openedFolder && _importantSwitch; const auto pressed = _collapsedPressed;
const auto selected = _collapsedSelected;
setCollapsedPressed(-1);
_collapsedSelected = -1;
_collapsedRows.clear();
if (!_openedFolder && Global::DialogsModeEnabled()) {
_collapsedRows.push_back(std::make_unique<CollapsedRow>());
}
const auto list = shownDialogs();
const auto archive = !list->empty()
? (*list->begin())->folder()
: nullptr;
if (archive && session().settings().archiveCollapsed()) {
if (_selected && _selected->folder() == archive) {
_selected = nullptr;
}
if (_pressed && _pressed->folder() == archive) {
setPressed(nullptr);
}
_skipByCollapsedRows = 1;
_collapsedRows.push_back(std::make_unique<CollapsedRow>(archive));
} else {
_skipByCollapsedRows = 0;
}
refresh(toTop);
if (selected >= 0 && selected < _collapsedRows.size()) {
_collapsedSelected = selected;
}
if (pressed >= 0 && pressed < _collapsedRows.size()) {
setCollapsedPressed(pressed);
}
} }
int InnerWidget::dialogsOffset() const { int InnerWidget::dialogsOffset() const {
return importantSwitchShown() return _collapsedRows.size() * st::dialogsImportantBarHeight
? st::dialogsImportantBarHeight - _skipByCollapsedRows * st::dialogsRowHeight;
: 0;
} }
int InnerWidget::proxyPromotedCount() const { int InnerWidget::fixedOnTopCount() const {
auto result = 0; auto result = 0;
for (const auto row : *shownDialogs()) { for (const auto row : *shownDialogs()) {
if (row->entry()->fixedOnTopIndex()) { if (row->entry()->fixedOnTopIndex()) {
@ -272,7 +315,7 @@ int InnerWidget::proxyPromotedCount() const {
} }
int InnerWidget::pinnedOffset() const { int InnerWidget::pinnedOffset() const {
return dialogsOffset() + proxyPromotedCount() * st::dialogsRowHeight; return dialogsOffset() + fixedOnTopCount() * st::dialogsRowHeight;
} }
int InnerWidget::filteredOffset() const { int InnerWidget::filteredOffset() const {
@ -309,7 +352,7 @@ void InnerWidget::changeOpenedFolder(Data::Folder *folder) {
clearSelection(); clearSelection();
_openedFolder = folder; _openedFolder = folder;
_mode = _openedFolder ? Mode::All : Global::DialogsMode(); _mode = _openedFolder ? Mode::All : Global::DialogsMode();
refresh(true); refreshWithCollapsedRows(true);
// This doesn't work, because we clear selection in leaveEvent on hide. // This doesn't work, because we clear selection in leaveEvent on hide.
//if (mouseSelection && lastMousePosition) { //if (mouseSelection && lastMousePosition) {
// selectByMouse(*lastMousePosition); // selectByMouse(*lastMousePosition);
@ -331,14 +374,11 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
auto dialogsClip = r; auto dialogsClip = r;
auto ms = crl::now(); auto ms = crl::now();
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
auto rows = shownDialogs(); paintCollapsedRows(p, r);
if (importantSwitchShown()) {
auto selected = isPressed() ? _importantSwitchPressed : _importantSwitchSelected; const auto rows = shownDialogs();
Layout::paintImportantSwitch(p, _mode, fullWidth, selected); const auto &list = rows->all();
dialogsClip.translate(0, -st::dialogsImportantBarHeight); const auto otherStart = std::max(int(rows->size()) - _skipByCollapsedRows, 0) * st::dialogsRowHeight;
p.translate(0, st::dialogsImportantBarHeight);
}
auto otherStart = rows->size() * st::dialogsRowHeight;
const auto active = activeEntry.key; const auto active = activeEntry.key;
const auto selected = _menuRow.key const auto selected = _menuRow.key
? _menuRow.key ? _menuRow.key
@ -350,13 +390,13 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
? _selected->key() ? _selected->key()
: Key())); : Key()));
if (otherStart) { if (otherStart) {
const auto skip = dialogsOffset();
auto reorderingPinned = (_aboveIndex >= 0 && !_pinnedRows.empty()); auto reorderingPinned = (_aboveIndex >= 0 && !_pinnedRows.empty());
auto &list = rows->all();
if (reorderingPinned) { if (reorderingPinned) {
dialogsClip = dialogsClip.marginsAdded(QMargins(0, st::dialogsRowHeight, 0, st::dialogsRowHeight)); dialogsClip = dialogsClip.marginsAdded(QMargins(0, st::dialogsRowHeight, 0, st::dialogsRowHeight));
} }
const auto promoted = proxyPromotedCount(); const auto promoted = fixedOnTopCount();
const auto paintDialog = [&](not_null<Row*> row) { const auto paintDialog = [&](not_null<Row*> row) {
const auto pinned = row->pos() - promoted; const auto pinned = row->pos() - promoted;
const auto count = _pinnedRows.size(); const auto count = _pinnedRows.size();
@ -381,19 +421,22 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
} }
}; };
auto i = list.cfind(dialogsClip.top(), st::dialogsRowHeight); auto i = list.cfind(dialogsClip.top() - skip, st::dialogsRowHeight);
while (i != list.cend() && (*i)->pos() < _skipByCollapsedRows) {
++i;
}
if (i != list.cend()) { if (i != list.cend()) {
auto lastPaintedPos = (*i)->pos(); auto lastPaintedPos = (*i)->pos();
// If we're reordering pinned chats we need to fill this area background first. // If we're reordering pinned chats we need to fill this area background first.
if (reorderingPinned) { if (reorderingPinned) {
p.fillRect(0, promoted * st::dialogsRowHeight, fullWidth, st::dialogsRowHeight * _pinnedRows.size(), st::dialogsBg); p.fillRect(0, (promoted - _skipByCollapsedRows) * st::dialogsRowHeight, fullWidth, st::dialogsRowHeight * _pinnedRows.size(), st::dialogsBg);
} }
p.translate(0, lastPaintedPos * st::dialogsRowHeight); p.translate(0, (lastPaintedPos - _skipByCollapsedRows) * st::dialogsRowHeight);
for (auto e = list.cend(); i != e; ++i) { for (auto e = list.cend(); i != e; ++i) {
auto row = (*i); auto row = (*i);
if (lastPaintedPos * st::dialogsRowHeight >= dialogsClip.top() + dialogsClip.height()) { if ((lastPaintedPos - _skipByCollapsedRows) * st::dialogsRowHeight >= dialogsClip.top() - skip + dialogsClip.height()) {
break; break;
} }
@ -591,6 +634,42 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
} }
} }
void InnerWidget::paintCollapsedRows(Painter &p, QRect clip) const {
auto index = 0;
const auto rowHeight = st::dialogsImportantBarHeight;
for (const auto &row : _collapsedRows) {
const auto increment = gsl::finally([&] {
p.translate(0, rowHeight);
++index;
});
const auto y = index * rowHeight;
if (!clip.intersects(QRect(0, y, width(), rowHeight))) {
continue;
}
const auto selected = (index == _collapsedSelected)
|| (index == _collapsedPressed);
paintCollapsedRow(p, row.get(), selected);
}
}
void InnerWidget::paintCollapsedRow(
Painter &p,
not_null<const CollapsedRow*> row,
bool selected) const {
const auto text = row->folder
? row->folder->chatListName()
: (_mode == Dialogs::Mode::Important)
? lang(lng_dialogs_show_all_chats)
: lang(lng_dialogs_hide_muted_chats);
const auto unread = row->folder
? row->folder->chatListUnreadCount()
: (_mode == Dialogs::Mode::Important)
? session().data().unreadOnlyMutedBadge()
: 0;
Layout::PaintCollapsedRow(p, row->row, text, unread, width(), selected);
}
bool InnerWidget::isSearchResultActive( bool InnerWidget::isSearchResultActive(
not_null<FakeRow*> result, not_null<FakeRow*> result,
const RowDescriptor &entry) const { const RowDescriptor &entry) const {
@ -791,8 +870,8 @@ void InnerWidget::clearIrrelevantState() {
_searchedSelected = -1; _searchedSelected = -1;
setSearchedPressed(-1); setSearchedPressed(-1);
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
_importantSwitchSelected = false; _collapsedSelected = -1;
setImportantSwitchPressed(false); setCollapsedPressed(-1);
_selected = nullptr; _selected = nullptr;
setPressed(nullptr); setPressed(nullptr);
} }
@ -810,22 +889,26 @@ void InnerWidget::selectByMouse(QPoint globalPosition) {
const auto mouseY = local.y(); const auto mouseY = local.y();
clearIrrelevantState(); clearIrrelevantState();
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
const auto switchTop = 0; const auto offset = dialogsOffset();
const auto switchBottom = dialogsOffset(); const auto collapsedSelected = (mouseY >= 0
const auto importantSwitchSelected = importantSwitchShown() && mouseY < _collapsedRows.size() * st::dialogsImportantBarHeight)
&& (mouseY >= switchTop) ? (mouseY / st::dialogsImportantBarHeight)
&& (mouseY < switchBottom); : -1;
const auto selected = importantSwitchSelected const auto selected = (collapsedSelected >= 0)
? nullptr ? nullptr
: (mouseY >= switchBottom) : (mouseY >= offset)
? shownDialogs()->rowAtY(mouseY - switchBottom, st::dialogsRowHeight) ? shownDialogs()->rowAtY(
mouseY - offset,
st::dialogsRowHeight)
: nullptr; : nullptr;
if (_selected != selected || _importantSwitchSelected != importantSwitchSelected) { if (_selected != selected || _collapsedSelected != collapsedSelected) {
updateSelectedRow(); updateSelectedRow();
_selected = selected; _selected = selected;
_importantSwitchSelected = importantSwitchSelected; _collapsedSelected = collapsedSelected;
updateSelectedRow(); updateSelectedRow();
setCursor((_selected || _importantSwitchSelected) ? style::cur_pointer : style::cur_default); setCursor((_selected || _collapsedSelected)
? style::cur_pointer
: style::cur_default);
} }
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
auto wasSelected = isSelected(); auto wasSelected = isSelected();
@ -892,15 +975,16 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) {
_pressButton = e->button(); _pressButton = e->button();
setPressed(_selected); setPressed(_selected);
setImportantSwitchPressed(_importantSwitchSelected); setCollapsedPressed(_collapsedSelected);
setHashtagPressed(_hashtagSelected); setHashtagPressed(_hashtagSelected);
_hashtagDeletePressed = _hashtagDeleteSelected; _hashtagDeletePressed = _hashtagDeleteSelected;
setFilteredPressed(_filteredSelected); setFilteredPressed(_filteredSelected);
setPeerSearchPressed(_peerSearchSelected); setPeerSearchPressed(_peerSearchSelected);
setSearchedPressed(_searchedSelected); setSearchedPressed(_searchedSelected);
if (_importantSwitchPressed) { if (base::in_range(_collapsedSelected, 0, _collapsedRows.size())) {
_importantSwitch->row.addRipple(e->pos(), QSize(width(), st::dialogsImportantBarHeight), [this] { auto row = &_collapsedRows[_collapsedSelected]->row;
update(0, 0, width(), st::dialogsImportantBarHeight); row->addRipple(e->pos(), QSize(width(), st::dialogsImportantBarHeight), [this, index = _collapsedSelected] {
update(0, (index * st::dialogsImportantBarHeight), width(), st::dialogsImportantBarHeight);
}); });
} else if (_pressed) { } else if (_pressed) {
auto row = _pressed; auto row = _pressed;
@ -1170,8 +1254,8 @@ void InnerWidget::mousePressReleased(
finishReorderPinned(); finishReorderPinned();
} }
auto importantSwitchPressed = _importantSwitchPressed; auto collapsedPressed = _collapsedPressed;
setImportantSwitchPressed(false); setCollapsedPressed(-1);
auto pressed = _pressed; auto pressed = _pressed;
setPressed(nullptr); setPressed(nullptr);
auto hashtagPressed = _hashtagPressed; auto hashtagPressed = _hashtagPressed;
@ -1189,28 +1273,27 @@ void InnerWidget::mousePressReleased(
} }
updateSelectedRow(); updateSelectedRow();
if (!wasDragging && button == Qt::LeftButton) { if (!wasDragging && button == Qt::LeftButton) {
if (importantSwitchPressed && importantSwitchPressed == _importantSwitchSelected) { if ((collapsedPressed >= 0 && collapsedPressed == _collapsedSelected)
chooseRow(); || (pressed && pressed == _selected)
} else if (pressed && pressed == _selected) { || (hashtagPressed >= 0
chooseRow(); && hashtagPressed == _hashtagSelected
} else if (hashtagPressed >= 0 && hashtagPressed == _hashtagSelected && hashtagDeletePressed == _hashtagDeleteSelected) { && hashtagDeletePressed == _hashtagDeleteSelected)
chooseRow(); || (filteredPressed >= 0 && filteredPressed == _filteredSelected)
} else if (filteredPressed >= 0 && filteredPressed == _filteredSelected) { || (peerSearchPressed >= 0
chooseRow(); && peerSearchPressed == _peerSearchSelected)
} else if (peerSearchPressed >= 0 && peerSearchPressed == _peerSearchSelected) { || (searchedPressed >= 0
chooseRow(); && searchedPressed == _searchedSelected)) {
} else if (searchedPressed >= 0 && searchedPressed == _searchedSelected) {
chooseRow(); chooseRow();
} }
} }
} }
void InnerWidget::setImportantSwitchPressed(bool pressed) { void InnerWidget::setCollapsedPressed(int pressed) {
if (_importantSwitchPressed != pressed) { if (_collapsedPressed != pressed) {
if (_importantSwitchPressed) { if (_collapsedPressed >= 0) {
_importantSwitch->row.stopLastRipple(); _collapsedRows[_collapsedPressed]->row.stopLastRipple();
} }
_importantSwitchPressed = pressed; _collapsedPressed = pressed;
} }
} }
@ -1360,11 +1443,23 @@ void InnerWidget::removeDialog(Key key) {
refresh(); refresh();
} }
void InnerWidget::repaintCollapsedFolderRow(not_null<Data::Folder*> folder) {
for (auto i = 0, l = int(_collapsedRows.size()); i != l; ++i) {
if (_collapsedRows[i]->folder == folder) {
update(0, i * st::dialogsImportantBarHeight, width(), st::dialogsImportantBarHeight);
return;
}
}
}
void InnerWidget::repaintDialogRow( void InnerWidget::repaintDialogRow(
Mode list, Mode list,
not_null<Row*> row) { not_null<Row*> row) {
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
if (_mode == list) { if (_mode == list) {
if (const auto folder = row->folder()) {
repaintCollapsedFolderRow(folder);
}
auto position = row->pos(); auto position = row->pos();
auto top = dialogsOffset(); auto top = dialogsOffset();
if (base::in_range(position, 0, _pinnedRows.size())) { if (base::in_range(position, 0, _pinnedRows.size())) {
@ -1435,6 +1530,9 @@ void InnerWidget::updateDialogRow(
}; };
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
if (sections & UpdateRowSection::Default) { if (sections & UpdateRowSection::Default) {
if (const auto folder = row.key.folder()) {
repaintCollapsedFolderRow(folder);
}
if (const auto dialog = shownDialogs()->getRow(row.key)) { if (const auto dialog = shownDialogs()->getRow(row.key)) {
const auto position = dialog->pos(); const auto position = dialog->pos();
auto top = dialogsOffset(); auto top = dialogsOffset();
@ -1505,8 +1603,8 @@ void InnerWidget::updateSelectedRow(Key key) {
update(0, top + position * st::dialogsRowHeight, width(), st::dialogsRowHeight); update(0, top + position * st::dialogsRowHeight, width(), st::dialogsRowHeight);
} else if (_selected) { } else if (_selected) {
update(0, dialogsOffset() + _selected->pos() * st::dialogsRowHeight, width(), st::dialogsRowHeight); update(0, dialogsOffset() + _selected->pos() * st::dialogsRowHeight, width(), st::dialogsRowHeight);
} else if (_importantSwitchSelected) { } else if (_collapsedSelected >= 0) {
update(0, 0, width(), st::dialogsImportantBarHeight); update(0, _collapsedSelected * st::dialogsImportantBarHeight, width(), st::dialogsImportantBarHeight);
} }
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
if (key) { if (key) {
@ -1545,14 +1643,9 @@ void InnerWidget::dragLeft() {
void InnerWidget::clearSelection() { void InnerWidget::clearSelection() {
_mouseSelection = false; _mouseSelection = false;
_lastMousePosition = std::nullopt; _lastMousePosition = std::nullopt;
if (_importantSwitchSelected if (isSelected()) {
|| _selected
|| _filteredSelected >= 0
|| _hashtagSelected >= 0
|| _peerSearchSelected >= 0
|| _searchedSelected >= 0) {
updateSelectedRow(); updateSelectedRow();
_importantSwitchSelected = false; _collapsedSelected = -1;
_selected = nullptr; _selected = nullptr;
_filteredSelected _filteredSelected
= _searchedSelected = _searchedSelected
@ -1583,6 +1676,10 @@ void InnerWidget::contextMenuEvent(QContextMenuEvent *e) {
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
if (_selected) { if (_selected) {
return { _selected->key(), FullMsgId() }; return { _selected->key(), FullMsgId() };
} else if (base::in_range(_collapsedSelected, 0, _collapsedRows.size())) {
if (const auto folder = _collapsedRows[_collapsedSelected]->folder) {
return { folder, FullMsgId() };
}
} }
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
if (base::in_range(_filteredSelected, 0, _filterResults.size())) { if (base::in_range(_filteredSelected, 0, _filterResults.size())) {
@ -1931,7 +2028,7 @@ void InnerWidget::peerSearchReceived(
const auto [i, ok] = _filterResultsGlobal.emplace( const auto [i, ok] = _filterResultsGlobal.emplace(
peer, peer,
std::move(row)); std::move(row));
_filterResults.push_back(i->second.get()); _filterResults.emplace_back(i->second.get());
} else { } else {
LOG(("API Error: " LOG(("API Error: "
"user %1 was not loaded in InnerWidget::peopleReceived()" "user %1 was not loaded in InnerWidget::peopleReceived()"
@ -1957,7 +2054,7 @@ void InnerWidget::peerSearchReceived(
} }
void InnerWidget::notify_historyMuteUpdated(History *history) { void InnerWidget::notify_historyMuteUpdated(History *history) {
if (!_importantSwitch || !history->inChatList()) { if (!Global::DialogsModeEnabled() || !history->inChatList()) {
return; return;
} }
refreshDialog(history); refreshDialog(history);
@ -1967,7 +2064,23 @@ Data::Folder *InnerWidget::shownFolder() const {
return _openedFolder; return _openedFolder;
} }
bool InnerWidget::needCollapsedRowsRefresh() const {
const auto archive = !shownDialogs()->empty()
? (*shownDialogs()->begin())->folder()
: nullptr;
const auto collapsedHasArchive = !_collapsedRows.empty()
&& (_collapsedRows.back()->folder != nullptr);
const auto archiveIsCollapsed = (archive != nullptr)
&& session().settings().archiveCollapsed();
return archiveIsCollapsed
? (!collapsedHasArchive || _skipByCollapsedRows != 1)
: (collapsedHasArchive || _skipByCollapsedRows != 0);
}
void InnerWidget::refresh(bool toTop) { void InnerWidget::refresh(bool toTop) {
if (needCollapsedRowsRefresh()) {
return refreshWithCollapsedRows(toTop);
}
auto h = 0; auto h = 0;
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
if (shownDialogs()->empty()) { if (shownDialogs()->empty()) {
@ -2006,8 +2119,8 @@ void InnerWidget::clearMouseSelection(bool clearSelection) {
_lastMousePosition = std::nullopt; _lastMousePosition = std::nullopt;
if (clearSelection) { if (clearSelection) {
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
_collapsedSelected = -1;
_selected = nullptr; _selected = nullptr;
_importantSwitchSelected = false;
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
_filteredSelected _filteredSelected
= _peerSearchSelected = _peerSearchSelected
@ -2116,41 +2229,40 @@ void InnerWidget::clearFilter() {
void InnerWidget::selectSkip(int32 direction) { void InnerWidget::selectSkip(int32 direction) {
clearMouseSelection(); clearMouseSelection();
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
if (_importantSwitchSelected) { const auto list = shownDialogs();
if (!shownDialogs()->empty() && direction > 0) { if (_collapsedRows.empty() && list->size() <= _skipByCollapsedRows) {
_selected = *shownDialogs()->cbegin(); return;
_importantSwitchSelected = false; }
if (_collapsedSelected < 0 && !_selected) {
if (!_collapsedRows.empty()) {
_collapsedSelected = 0;
} else { } else {
return; _selected = *(list->cbegin() + _skipByCollapsedRows);
}
} else if (!_selected) {
if (importantSwitchShown()) {
_importantSwitchSelected = true;
} else if (!shownDialogs()->empty() && direction > 0) {
_selected = *shownDialogs()->cbegin();
} else {
return;
}
} else if (direction > 0) {
auto next = shownDialogs()->cfind(_selected);
if (++next != shownDialogs()->cend()) {
_selected = *next;
} }
} else { } else {
auto prev = shownDialogs()->cfind(_selected); auto cur = (_collapsedSelected >= 0)
if (prev != shownDialogs()->cbegin()) { ? _collapsedSelected
_selected = *(--prev); : int(_collapsedRows.size()
} else if (importantSwitchShown()) { + (list->cfind(_selected) - list->cbegin() - _skipByCollapsedRows));
_importantSwitchSelected = true; cur = snap(cur + direction, 0, static_cast<int>(_collapsedRows.size() + list->size() - _skipByCollapsedRows - 1));
if (cur < _collapsedRows.size()) {
_collapsedSelected = cur;
_selected = nullptr; _selected = nullptr;
} else {
_collapsedSelected = -1;
_selected = *(list->cbegin() + _skipByCollapsedRows + cur - _collapsedRows.size());
} }
} }
if (_importantSwitchSelected || _selected) { if (_collapsedSelected >= 0 || _selected) {
int fromY = _importantSwitchSelected ? 0 : (dialogsOffset() + _selected->pos() * st::dialogsRowHeight); const auto fromY = (_collapsedSelected >= 0)
? (_collapsedSelected * st::dialogsImportantBarHeight)
: (dialogsOffset() + _selected->pos() * st::dialogsRowHeight);
emit mustScrollTo(fromY, fromY + st::dialogsRowHeight); emit mustScrollTo(fromY, fromY + st::dialogsRowHeight);
} }
} else if (_state == WidgetState::Filtered) { } else if (_state == WidgetState::Filtered) {
if (_hashtagResults.empty() && _filterResults.empty() && _peerSearchResults.empty() && _searchResults.empty()) return; if (_hashtagResults.empty() && _filterResults.empty() && _peerSearchResults.empty() && _searchResults.empty()) {
return;
}
if ((_hashtagSelected < 0 || _hashtagSelected >= _hashtagResults.size()) && if ((_hashtagSelected < 0 || _hashtagSelected >= _hashtagResults.size()) &&
(_filteredSelected < 0 || _filteredSelected >= _filterResults.size()) && (_filteredSelected < 0 || _filteredSelected >= _filterResults.size()) &&
(_peerSearchSelected < 0 || _peerSearchSelected >= _peerSearchResults.size()) && (_peerSearchSelected < 0 || _peerSearchSelected >= _peerSearchResults.size()) &&
@ -2232,9 +2344,9 @@ void InnerWidget::selectSkipPage(int32 pixels, int32 direction) {
int toSkip = pixels / int(st::dialogsRowHeight); int toSkip = pixels / int(st::dialogsRowHeight);
if (_state == WidgetState::Default) { if (_state == WidgetState::Default) {
if (!_selected) { if (!_selected) {
if (direction > 0 && !shownDialogs()->empty()) { if (direction > 0 && shownDialogs()->size() > _skipByCollapsedRows) {
_selected = *shownDialogs()->cbegin(); _selected = *(shownDialogs()->cbegin() + _skipByCollapsedRows);
_importantSwitchSelected = false; _collapsedSelected = -1;
} else { } else {
return; return;
} }
@ -2244,16 +2356,18 @@ void InnerWidget::selectSkipPage(int32 pixels, int32 direction) {
_selected = *i; _selected = *i;
} }
} else { } else {
for (auto i = shownDialogs()->cfind(_selected), b = shownDialogs()->cbegin(); i != b && (toSkip--);) { for (auto i = shownDialogs()->cfind(_selected), b = shownDialogs()->cbegin(); i != b && (*i)->pos() > _skipByCollapsedRows && (toSkip--);) {
_selected = *(--i); _selected = *(--i);
} }
if (toSkip && importantSwitchShown()) { if (toSkip && !_collapsedRows.empty()) {
_importantSwitchSelected = true; _collapsedSelected = std::max(int(_collapsedRows.size()) - toSkip, 0);
_selected = nullptr; _selected = nullptr;
} }
} }
if (_importantSwitchSelected || _selected) { if (_collapsedSelected >= 0 || _selected) {
int fromY = (_importantSwitchSelected ? 0 : (dialogsOffset() + _selected->pos() * st::dialogsRowHeight)); const auto fromY = (_collapsedSelected >= 0)
? (_collapsedSelected * st::dialogsImportantBarHeight)
: (dialogsOffset() + _selected->pos() * st::dialogsRowHeight);
emit mustScrollTo(fromY, fromY + st::dialogsRowHeight); emit mustScrollTo(fromY, fromY + st::dialogsRowHeight);
} }
} else { } else {
@ -2317,12 +2431,23 @@ void InnerWidget::loadPeerPhotos() {
} }
} }
bool InnerWidget::switchImportantChats() { bool InnerWidget::chooseCollapsedRow() {
if (!_importantSwitchSelected if (_state != WidgetState::Default) {
|| !importantSwitchShown() return false;
|| (_state != WidgetState::Default)) { } else if ((_collapsedSelected < 0)
|| (_collapsedSelected >= _collapsedRows.size())) {
return false; return false;
} }
const auto &row = _collapsedRows[_collapsedSelected];
if (row->folder) {
_controller->openFolder(row->folder);
} else {
switchImportantChats();
}
return true;
}
void InnerWidget::switchImportantChats() {
clearSelection(); clearSelection();
if (Global::DialogsMode() == Mode::All) { if (Global::DialogsMode() == Mode::All) {
Global::SetDialogsMode(Mode::Important); Global::SetDialogsMode(Mode::Important);
@ -2331,9 +2456,8 @@ bool InnerWidget::switchImportantChats() {
} }
_mode = Global::DialogsMode(); _mode = Global::DialogsMode();
Local::writeUserSettings(); Local::writeUserSettings();
refresh(); refreshWithCollapsedRows(true);
_importantSwitchSelected = true; _collapsedSelected = 0;
return true;
} }
bool InnerWidget::chooseHashtag() { bool InnerWidget::chooseHashtag() {
@ -2404,7 +2528,7 @@ ChosenRow InnerWidget::computeChosenRow() const {
} }
bool InnerWidget::chooseRow() { bool InnerWidget::chooseRow() {
if (switchImportantChats()) { if (chooseCollapsedRow()) {
return true; return true;
} else if (chooseHashtag()) { } else if (chooseHashtag()) {
return true; return true;

View File

@ -146,7 +146,7 @@ protected:
void contextMenuEvent(QContextMenuEvent *e) override; void contextMenuEvent(QContextMenuEvent *e) override;
private: private:
struct ImportantSwitch; struct CollapsedRow;
struct HashtagResult; struct HashtagResult;
struct PeerSearchResult; struct PeerSearchResult;
@ -161,7 +161,11 @@ private:
void dialogRowReplaced(Row *oldRow, Row *newRow); void dialogRowReplaced(Row *oldRow, Row *newRow);
bool switchImportantChats(); void repaintCollapsedFolderRow(not_null<Data::Folder*> folder);
void refreshWithCollapsedRows(bool toTop = false);
bool needCollapsedRowsRefresh() const;
bool chooseCollapsedRow();
void switchImportantChats();
bool chooseHashtag(); bool chooseHashtag();
ChosenRow computeChosenRow() const; ChosenRow computeChosenRow() const;
bool isSearchResultActive( bool isSearchResultActive(
@ -173,14 +177,14 @@ private:
void clearIrrelevantState(); void clearIrrelevantState();
void selectByMouse(QPoint globalPosition); void selectByMouse(QPoint globalPosition);
void loadPeerPhotos(); void loadPeerPhotos();
void setImportantSwitchPressed(bool pressed); void setCollapsedPressed(int pressed);
void setPressed(Row *pressed); void setPressed(Row *pressed);
void setHashtagPressed(int pressed); void setHashtagPressed(int pressed);
void setFilteredPressed(int pressed); void setFilteredPressed(int pressed);
void setPeerSearchPressed(int pressed); void setPeerSearchPressed(int pressed);
void setSearchedPressed(int pressed); void setSearchedPressed(int pressed);
bool isPressed() const { bool isPressed() const {
return _importantSwitchPressed return (_collapsedPressed >= 0)
|| _pressed || _pressed
|| (_hashtagPressed >= 0) || (_hashtagPressed >= 0)
|| (_filteredPressed >= 0) || (_filteredPressed >= 0)
@ -188,7 +192,7 @@ private:
|| (_searchedPressed >= 0); || (_searchedPressed >= 0);
} }
bool isSelected() const { bool isSelected() const {
return _importantSwitchSelected return (_collapsedSelected >= 0)
|| _selected || _selected
|| (_hashtagSelected >= 0) || (_hashtagSelected >= 0)
|| (_filteredSelected >= 0) || (_filteredSelected >= 0)
@ -227,15 +231,21 @@ private:
UpdateRowSections sections = UpdateRowSection::All); UpdateRowSections sections = UpdateRowSection::All);
void fillSupportSearchMenu(not_null<Ui::PopupMenu*> menu); void fillSupportSearchMenu(not_null<Ui::PopupMenu*> menu);
bool importantSwitchShown() const;
int dialogsOffset() const; int dialogsOffset() const;
int proxyPromotedCount() const; int fixedOnTopCount() const;
int pinnedOffset() const; int pinnedOffset() const;
int filteredOffset() const; int filteredOffset() const;
int peerSearchOffset() const; int peerSearchOffset() const;
int searchedOffset() const; int searchedOffset() const;
int searchInChatSkip() const; int searchInChatSkip() const;
void paintCollapsedRows(
Painter &p,
QRect clip) const;
void paintCollapsedRow(
Painter &p,
not_null<const CollapsedRow*> row,
bool selected) const;
void paintPeerSearchResult( void paintPeerSearchResult(
Painter &p, Painter &p,
not_null<const PeerSearchResult*> result, not_null<const PeerSearchResult*> result,
@ -290,9 +300,10 @@ private:
Data::Folder *_openedFolder = nullptr; Data::Folder *_openedFolder = nullptr;
std::unique_ptr<ImportantSwitch> _importantSwitch; std::vector<std::unique_ptr<CollapsedRow>> _collapsedRows;
bool _importantSwitchSelected = false; int _collapsedSelected = -1;
bool _importantSwitchPressed = false; int _collapsedPressed = -1;
int _skipByCollapsedRows = 0;
Row *_selected = nullptr; Row *_selected = nullptr;
Row *_pressed = nullptr; Row *_pressed = nullptr;

View File

@ -841,26 +841,21 @@ QRect RowPainter::sendActionAnimationRect(int animationWidth, int animationHeigh
return QRect(nameleft, texttop, textUpdated ? namewidth : animationWidth, animationHeight); return QRect(nameleft, texttop, textUpdated ? namewidth : animationWidth, animationHeight);
} }
void paintImportantSwitch(Painter &p, Mode current, int fullWidth, bool selected) { void PaintCollapsedRow(Painter &p, const RippleRow &row, const QString &text, int unread, int fullWidth, bool selected) {
p.fillRect(0, 0, fullWidth, st::dialogsImportantBarHeight, selected ? st::dialogsBgOver : st::dialogsBg); p.fillRect(0, 0, fullWidth, st::dialogsImportantBarHeight, selected ? st::dialogsBgOver : st::dialogsBg);
row.paintRipple(p, 0, 0, fullWidth);
p.setFont(st::semiboldFont); p.setFont(st::semiboldFont);
p.setPen(st::dialogsNameFg); p.setPen(st::dialogsNameFg);
const auto unreadTop = (st::dialogsImportantBarHeight - st::dialogsUnreadHeight) / 2; const auto unreadTop = (st::dialogsImportantBarHeight - st::dialogsUnreadHeight) / 2;
const auto mutedHidden = (current == Dialogs::Mode::Important);
const auto text = lang(mutedHidden
? lng_dialogs_show_all_chats
: lng_dialogs_hide_muted_chats);
const auto textBaseline = unreadTop const auto textBaseline = unreadTop
+ (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2 + (st::dialogsUnreadHeight - st::dialogsUnreadFont->height) / 2
+ st::dialogsUnreadFont->ascent; + st::dialogsUnreadFont->ascent;
p.drawText(st::dialogsPadding.x(), textBaseline, text); p.drawText(st::dialogsPadding.x(), textBaseline, text);
if (!mutedHidden) { if (unread) {
return;
}
if (const auto unread = Auth().data().unreadOnlyMutedBadge()) {
const auto unreadRight = fullWidth - st::dialogsPadding.x(); const auto unreadRight = fullWidth - st::dialogsPadding.x();
UnreadBadgeStyle st; UnreadBadgeStyle st;
st.muted = true; st.muted = true;

View File

@ -11,6 +11,7 @@ namespace Dialogs {
class Row; class Row;
class FakeRow; class FakeRow;
class RippleRow;
namespace Layout { namespace Layout {
@ -48,9 +49,11 @@ public:
}; };
void paintImportantSwitch( void PaintCollapsedRow(
Painter &p, Painter &p,
Mode current, const RippleRow &row,
const QString &text,
int unread,
int fullWidth, int fullWidth,
bool selected); bool selected);

View File

@ -84,6 +84,7 @@ public:
void fill(); void fill();
private: private:
void addToggleCollapse();
//bool showInfo(); //bool showInfo();
//void addTogglePin(); //void addTogglePin();
//void addInfo(); //void addInfo();
@ -91,10 +92,10 @@ private:
//void addNotifications(); //void addNotifications();
//void addUngroup(); //void addUngroup();
//not_null<Controller*> _controller; not_null<Controller*> _controller;
//not_null<Data::Folder*> _folder; not_null<Data::Folder*> _folder;
//const PeerMenuCallback &_addAction; const PeerMenuCallback &_addAction;
//PeerMenuSource _source; PeerMenuSource _source;
}; };
@ -534,54 +535,33 @@ FolderFiller::FolderFiller(
not_null<Controller*> controller, not_null<Controller*> controller,
not_null<Data::Folder*> folder, not_null<Data::Folder*> folder,
const PeerMenuCallback &addAction, const PeerMenuCallback &addAction,
PeerMenuSource source) { PeerMenuSource source)
//: _controller(controller) : _controller(controller)
//, _folder(folder) , _folder(folder)
//, _addAction(addAction) , _addAction(addAction)
//, _source(source) { , _source(source) {
} }
void FolderFiller::fill() { // #TODO archive void FolderFiller::fill() {
//if (_source == PeerMenuSource::ChatsList) { if (_source == PeerMenuSource::ChatsList) {
// addTogglePin(); addToggleCollapse();
//} }
//if (showInfo()) { }
// addInfo();
//} void FolderFiller::addToggleCollapse() {
//addNotifications(); if (_folder->id() != Data::Folder::kId) {
//if (_source == PeerMenuSource::ChatsList) { return;
// addSearch(); }
//} const auto controller = _controller;
//addUngroup(); const auto hidden = controller->session().settings().archiveCollapsed();
const auto text = lang(hidden
? lng_context_archive_expand
: lng_context_archive_collapse);
_addAction(text, [=] {
controller->session().settings().setArchiveCollapsed(!hidden);
controller->session().saveSettingsDelayed();
});
} }
//
//bool FolderFiller::showInfo() {
// if (_source == PeerMenuSource::Profile) {
// return false;
// } else if (_controller->activeChatCurrent().feed() != _feed) {
// return true;
// } else if (!Adaptive::ThreeColumn()) {
// return true;
// } else if (
// !Auth().settings().thirdSectionInfoEnabled() &&
// !Auth().settings().tabbedReplacedWithInfo()) {
// return true;
// }
// return false;
//}
//
//void FolderFiller::addTogglePin() {
// const auto feed = _feed;
// const auto isPinned = feed->isPinnedDialog();
// const auto pinText = [](bool isPinned) {
// return lang(isPinned
// ? lng_context_unpin_from_top
// : lng_context_pin_to_top);
// };
// _addAction(pinText(isPinned), [=] {
// TogglePinnedDialog(feed);
// });
//}
// //
//void FolderFiller::addInfo() { //void FolderFiller::addInfo() {
// auto controller = _controller; // auto controller = _controller;