From 374bc85dc7cd737aa416777fb38bb4036dc7823f Mon Sep 17 00:00:00 2001 From: RadRussianRus Date: Fri, 26 Aug 2022 22:26:26 +0300 Subject: [PATCH] [Option][GUI] Compact chat list --- Telegram/Resources/langs/rewrites/en.json | 1 + .../dialogs/dialogs_inner_widget.cpp | 273 +++++----- Telegram/SourceFiles/dialogs/dialogs_row.cpp | 40 +- Telegram/SourceFiles/dialogs/dialogs_row.h | 11 + .../SourceFiles/dialogs/dialogs_widget.cpp | 7 +- .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 472 ++++++++++++++---- .../SourceFiles/kotato/kotato_settings.cpp | 4 + .../kotato/kotato_settings_menu.cpp | 14 + .../SourceFiles/window/window_peer_menu.cpp | 19 +- .../window/window_session_controller.cpp | 3 +- 10 files changed, 609 insertions(+), 235 deletions(-) diff --git a/Telegram/Resources/langs/rewrites/en.json b/Telegram/Resources/langs/rewrites/en.json index 772fa5ceb..476d240ad 100644 --- a/Telegram/Resources/langs/rewrites/en.json +++ b/Telegram/Resources/langs/rewrites/en.json @@ -33,6 +33,7 @@ "ktg_settings_sticker_scale_both_about": "When enabled, sticker maximum width will be changed along with sticker height.", "ktg_settings_emoji_outline": "Big emoji outline", "ktg_settings_always_show_scheduled": "Always show scheduled", + "ktg_settings_chat_list_compact": "Compact chat list", "ktg_fonts_title": "Fonts", "ktg_settings_fonts": "Change application fonts", "ktg_fonts_reset": "Reset", diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 166d8db7c..26bdd580a 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "dialogs/dialogs_inner_widget.h" +#include "kotato/kotato_settings.h" #include "dialogs/dialogs_indexed_list.h" #include "dialogs/ui/dialogs_layout.h" #include "dialogs/ui/dialogs_video_userpic.h" @@ -72,6 +73,18 @@ base::options::toggle TabbedPanelShowOnClick({ "(Cmd+Click on macOS).", }); +inline int DialogsRowHeight() { + return (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsImportantBarHeight + : st::dialogsRowHeight); +} + +inline int DialogsPhotoSize() { + return (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsUnreadHeight + : st::dialogsPhotoSize); +} + int FixedOnTopDialogsCount(not_null list) { auto result = 0; for (const auto &row : *list) { @@ -212,6 +225,12 @@ InnerWidget::InnerWidget( refresh(); }, lifetime()); + ::Kotato::JsonSettings::Events( + "chat_list_lines" + ) | rpl::start_with_next([=] { + refresh(); + }, lifetime()); + session().changes().historyUpdates( Data::HistoryUpdate::Flag::IsPinned | Data::HistoryUpdate::Flag::ChatOccupied @@ -313,7 +332,10 @@ void InnerWidget::refreshWithCollapsedRows(bool toTop) { ? (*list->begin())->folder() : nullptr; const auto inMainMenu = session().settings().archiveInMainMenu(); - if (archive && (session().settings().archiveCollapsed() || inMainMenu)) { + if (archive && + (session().settings().archiveCollapsed() + || inMainMenu + || ::Kotato::JsonSettings::GetInt("chat_list_lines") == 1)) { if (_selected && _selected->folder() == archive) { _selected = nullptr; } @@ -342,7 +364,7 @@ void InnerWidget::refreshWithCollapsedRows(bool toTop) { int InnerWidget::dialogsOffset() const { return _collapsedRows.size() * st::dialogsImportantBarHeight - - _skipTopDialogs * st::dialogsRowHeight; + - _skipTopDialogs * DialogsRowHeight(); } int InnerWidget::fixedOnTopCount() const { @@ -358,7 +380,7 @@ int InnerWidget::fixedOnTopCount() const { } int InnerWidget::pinnedOffset() const { - return dialogsOffset() + fixedOnTopCount() * st::dialogsRowHeight; + return dialogsOffset() + fixedOnTopCount() * DialogsRowHeight(); } int InnerWidget::filteredOffset() const { @@ -366,11 +388,11 @@ int InnerWidget::filteredOffset() const { } int InnerWidget::peerSearchOffset() const { - return filteredOffset() + (_filterResults.size() * st::dialogsRowHeight) + st::searchedBarHeight; + return filteredOffset() + (_filterResults.size() * DialogsRowHeight()) + st::searchedBarHeight; } int InnerWidget::searchedOffset() const { - auto result = peerSearchOffset() + (_peerSearchResults.empty() ? 0 : ((_peerSearchResults.size() * st::dialogsRowHeight) + st::searchedBarHeight)); + auto result = peerSearchOffset() + (_peerSearchResults.empty() ? 0 : ((_peerSearchResults.size() * DialogsRowHeight()) + st::searchedBarHeight)); if (_searchInChat) { result += searchInChatSkip(); } @@ -424,7 +446,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { const auto rows = shownDialogs(); const auto &list = rows->all(); - const auto otherStart = std::max(int(rows->size()) - _skipTopDialogs, 0) * st::dialogsRowHeight; + const auto otherStart = std::max(int(rows->size()) - _skipTopDialogs, 0) * DialogsRowHeight(); const auto active = activeEntry.key; const auto selected = _menuRow.key ? _menuRow.key @@ -439,7 +461,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { const auto skip = dialogsOffset(); auto reorderingPinned = (_aboveIndex >= 0 && !_pinnedRows.empty()); if (reorderingPinned) { - dialogsClip = dialogsClip.marginsAdded(QMargins(0, st::dialogsRowHeight, 0, st::dialogsRowHeight)); + dialogsClip = dialogsClip.marginsAdded(QMargins(0, DialogsRowHeight(), 0, DialogsRowHeight())); } const auto promoted = fixedOnTopCount(); @@ -471,7 +493,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { } }; - auto i = list.cfind(dialogsClip.top() - skip, st::dialogsRowHeight); + auto i = list.cfind(dialogsClip.top() - skip, DialogsRowHeight()); while (i != list.cend() && (*i)->pos() < _skipTopDialogs) { ++i; } @@ -480,13 +502,13 @@ void InnerWidget::paintEvent(QPaintEvent *e) { // If we're reordering pinned chats we need to fill this area background first. if (reorderingPinned) { - p.fillRect(0, (promoted - _skipTopDialogs) * st::dialogsRowHeight, fullWidth, st::dialogsRowHeight * _pinnedRows.size(), st::dialogsBg); + p.fillRect(0, (promoted - _skipTopDialogs) * DialogsRowHeight(), fullWidth, DialogsRowHeight() * _pinnedRows.size(), st::dialogsBg); } - p.translate(0, (lastPaintedPos - _skipTopDialogs) * st::dialogsRowHeight); + p.translate(0, (lastPaintedPos - _skipTopDialogs) * DialogsRowHeight()); for (auto e = list.cend(); i != e; ++i) { auto row = (*i); - if ((lastPaintedPos - _skipTopDialogs) * st::dialogsRowHeight >= dialogsClip.top() - skip + dialogsClip.height()) { + if ((lastPaintedPos - _skipTopDialogs) * DialogsRowHeight() >= dialogsClip.top() - skip + dialogsClip.height()) { break; } @@ -496,7 +518,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { paintDialog(row); } - p.translate(0, st::dialogsRowHeight); + p.translate(0, DialogsRowHeight()); ++lastPaintedPos; } @@ -505,9 +527,9 @@ void InnerWidget::paintEvent(QPaintEvent *e) { auto i = list.cfind(promoted + _aboveIndex, 1); auto pos = (i == list.cend()) ? -1 : (*i)->pos(); if (pos == promoted + _aboveIndex) { - p.translate(0, (pos - lastPaintedPos) * st::dialogsRowHeight); + p.translate(0, (pos - lastPaintedPos) * DialogsRowHeight()); paintDialog(*i); - p.translate(0, (lastPaintedPos - pos) * st::dialogsRowHeight); + p.translate(0, (lastPaintedPos - pos) * DialogsRowHeight()); } } } @@ -562,9 +584,9 @@ void InnerWidget::paintEvent(QPaintEvent *e) { } if (!_filterResults.empty()) { auto skip = filteredOffset(); - auto from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _filterResults.size()); - auto to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _filterResults.size()); - p.translate(0, from * st::dialogsRowHeight); + auto from = floorclamp(r.y() - skip, DialogsRowHeight(), 0, _filterResults.size()); + auto to = ceilclamp(r.y() + r.height() - skip, DialogsRowHeight(), 0, _filterResults.size()); + p.translate(0, from * DialogsRowHeight()); if (from < _filterResults.size()) { for (; from < to; ++from) { const auto row = _filterResults[from]; @@ -586,7 +608,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { selected, ms, videoPaused); - p.translate(0, st::dialogsRowHeight); + p.translate(0, DialogsRowHeight()); } } } @@ -599,9 +621,9 @@ void InnerWidget::paintEvent(QPaintEvent *e) { p.translate(0, st::searchedBarHeight); auto skip = peerSearchOffset(); - auto from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _peerSearchResults.size()); - auto to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _peerSearchResults.size()); - p.translate(0, from * st::dialogsRowHeight); + auto from = floorclamp(r.y() - skip, DialogsRowHeight(), 0, _peerSearchResults.size()); + auto to = ceilclamp(r.y() + r.height() - skip, DialogsRowHeight(), 0, _peerSearchResults.size()); + p.translate(0, from * DialogsRowHeight()); if (from < _peerSearchResults.size()) { const auto activePeer = activeEntry.key.peer(); for (; from < to; ++from) { @@ -615,7 +637,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { ? _peerSearchPressed : _peerSearchSelected)); paintPeerSearchResult(p, result.get(), fullWidth, active, selected); - p.translate(0, st::dialogsRowHeight); + p.translate(0, DialogsRowHeight()); } } } @@ -658,9 +680,9 @@ void InnerWidget::paintEvent(QPaintEvent *e) { p.translate(0, st::searchedBarHeight); auto skip = searchedOffset(); - auto from = floorclamp(r.y() - skip, st::dialogsRowHeight, 0, _searchResults.size()); - auto to = ceilclamp(r.y() + r.height() - skip, st::dialogsRowHeight, 0, _searchResults.size()); - p.translate(0, from * st::dialogsRowHeight); + auto from = floorclamp(r.y() - skip, DialogsRowHeight(), 0, _searchResults.size()); + auto to = ceilclamp(r.y() + r.height() - skip, DialogsRowHeight(), 0, _searchResults.size()); + p.translate(0, from * DialogsRowHeight()); if (from < _searchResults.size()) { for (; from < to; ++from) { const auto &result = _searchResults[from]; @@ -678,7 +700,7 @@ void InnerWidget::paintEvent(QPaintEvent *e) { selected, ms, showUnreadInSearchResults); - p.translate(0, st::dialogsRowHeight); + p.translate(0, DialogsRowHeight()); } } } @@ -768,7 +790,7 @@ void InnerWidget::paintPeerSearchResult( int fullWidth, bool active, bool selected) const { - QRect fullRect(0, 0, fullWidth, st::dialogsRowHeight); + QRect fullRect(0, 0, fullWidth, DialogsRowHeight()); p.fillRect(fullRect, active ? st::dialogsBgActive : (selected ? st::dialogsBgOver : st::dialogsBg)); if (!active) { result->row.paintRipple(p, 0, 0, fullWidth); @@ -776,11 +798,17 @@ void InnerWidget::paintPeerSearchResult( auto peer = result->peer; auto userpicPeer = (peer->migrateTo() ? peer->migrateTo() : peer); - userpicPeer->paintUserpicLeft(p, result->row.userpicView(), st::dialogsPadding.x(), st::dialogsPadding.y(), width(), st::dialogsPhotoSize); + userpicPeer->paintUserpicLeft(p, result->row.userpicView(), st::dialogsPadding.x(), st::dialogsPadding.y(), width(), DialogsPhotoSize()); - auto nameleft = st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPhotoPadding; + auto nameleft = st::dialogsPadding.x() + DialogsPhotoSize() + st::dialogsPhotoPadding; auto namewidth = fullWidth - nameleft - st::dialogsPadding.x(); - QRect rectForName(nameleft, st::dialogsPadding.y() + st::dialogsNameTop, namewidth, st::msgNameFont->height); + QRect rectForName( + nameleft, + (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1) + ? st::dialogsPadding.y() + : st::dialogsPadding.y() + st::dialogsNameTop, + namewidth, + st::msgNameFont->height); if (result->name.isEmpty()) { result->name.setText( @@ -819,29 +847,43 @@ void InnerWidget::paintPeerSearchResult( badgeStyle); rectForName.setWidth(rectForName.width() - badgeWidth); - QRect tr(nameleft, st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip, namewidth, st::dialogsTextFont->height); - p.setFont(st::dialogsTextFont); - QString username = peer->userName(); - if (!active && username.startsWith(_peerSearchQuery, Qt::CaseInsensitive)) { - auto first = '@' + username.mid(0, _peerSearchQuery.size()); - auto second = username.mid(_peerSearchQuery.size()); - auto w = st::dialogsTextFont->width(first); - if (w >= tr.width()) { - p.setPen(st::dialogsTextFgService); - p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided(first, tr.width())); - } else { - p.setPen(st::dialogsTextFgService); - p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, first); - p.setPen(st::dialogsTextFg); - p.drawText(tr.left() + w, tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided(second, tr.width() - w)); - } - } else { - p.setPen(active ? st::dialogsTextFgActive : st::dialogsTextFgService); - p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided('@' + username, tr.width())); - } + if (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1) { + QString text = peer->name(); + p.setPen(active + ? st::dialogsNameFgActive + : selected + ? st::dialogsNameFgOver + : st::dialogsNameFg); + p.setFont(st::dialogsTextFont); - p.setPen(active ? st::dialogsTextFgActive : st::dialogsNameFg); - result->name.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + Ui::Text::String textStr; + textStr.setText(st::dialogsTextStyle, text, Ui::NameTextOptions()); + textStr.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + } else { + QRect tr(nameleft, st::dialogsPadding.y() + st::msgNameFont->height + st::dialogsSkip, namewidth, st::dialogsTextFont->height); + p.setFont(st::dialogsTextFont); + QString username = peer->userName(); + if (!active && username.startsWith(_peerSearchQuery, Qt::CaseInsensitive)) { + auto first = '@' + username.mid(0, _peerSearchQuery.size()); + auto second = username.mid(_peerSearchQuery.size()); + auto w = st::dialogsTextFont->width(first); + if (w >= tr.width()) { + p.setPen(st::dialogsTextFgService); + p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided(first, tr.width())); + } else { + p.setPen(st::dialogsTextFgService); + p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, first); + p.setPen(st::dialogsTextFg); + p.drawText(tr.left() + w, tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided(second, tr.width() - w)); + } + } else { + p.setPen(active ? st::dialogsTextFgActive : st::dialogsTextFgService); + p.drawText(tr.left(), tr.top() + st::dialogsTextFont->ascent, st::dialogsTextFont->elided('@' + username, tr.width())); + } + + p.setPen(active ? st::dialogsTextFgActive : st::dialogsNameFg); + result->name.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + } } void InnerWidget::paintSearchInChat(Painter &p) const { @@ -1003,7 +1045,7 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { : (mouseY >= offset) ? shownDialogs()->rowAtY( mouseY - offset, - st::dialogsRowHeight) + DialogsRowHeight()) : nullptr; if (_selected != selected || _collapsedSelected != collapsedSelected) { updateSelectedRow(); @@ -1034,7 +1076,7 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { } if (!_filterResults.empty()) { auto skip = filteredOffset(); - auto filteredSelected = (mouseY >= skip) ? ((mouseY - skip) / st::dialogsRowHeight) : -1; + auto filteredSelected = (mouseY >= skip) ? ((mouseY - skip) / DialogsRowHeight()) : -1; if (filteredSelected < 0 || filteredSelected >= _filterResults.size()) { filteredSelected = -1; } @@ -1046,7 +1088,7 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { } if (!_peerSearchResults.empty()) { auto skip = peerSearchOffset(); - auto peerSearchSelected = (mouseY >= skip) ? ((mouseY - skip) / st::dialogsRowHeight) : -1; + auto peerSearchSelected = (mouseY >= skip) ? ((mouseY - skip) / DialogsRowHeight()) : -1; if (peerSearchSelected < 0 || peerSearchSelected >= _peerSearchResults.size()) { peerSearchSelected = -1; } @@ -1058,7 +1100,7 @@ void InnerWidget::selectByMouse(QPoint globalPosition) { } if (!_waitingForSearch && !_searchResults.empty()) { auto skip = searchedOffset(); - auto searchedSelected = (mouseY >= skip) ? ((mouseY - skip) / st::dialogsRowHeight) : -1; + auto searchedSelected = (mouseY >= skip) ? ((mouseY - skip) / DialogsRowHeight()) : -1; if (searchedSelected < 0 || searchedSelected >= _searchResults.size()) { searchedSelected = -1; } @@ -1092,7 +1134,7 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) { }); } else if (_pressed) { auto row = _pressed; - row->addRipple(e->pos() - QPoint(0, dialogsOffset() + _pressed->pos() * st::dialogsRowHeight), QSize(width(), st::dialogsRowHeight), [this, row] { + row->addRipple(e->pos() - QPoint(0, dialogsOffset() + _pressed->pos() * DialogsRowHeight()), QSize(width(), DialogsRowHeight()), [this, row] { if (!_pinnedShiftAnimation.animating()) { row->entry()->updateChatListEntry(); } @@ -1108,19 +1150,19 @@ void InnerWidget::mousePressEvent(QMouseEvent *e) { const auto filterId = _filterId; row->addRipple( e->pos() - QPoint(0, filteredOffset() + _filteredPressed * st::dialogsRowHeight), - QSize(width(), st::dialogsRowHeight), + QSize(width(), DialogsRowHeight()), [=] { repaintDialogRow(filterId, row); }); } else if (base::in_range(_peerSearchPressed, 0, _peerSearchResults.size())) { auto &result = _peerSearchResults[_peerSearchPressed]; auto row = &result->row; row->addRipple( - e->pos() - QPoint(0, peerSearchOffset() + _peerSearchPressed * st::dialogsRowHeight), - QSize(width(), st::dialogsRowHeight), + e->pos() - QPoint(0, peerSearchOffset() + _peerSearchPressed * DialogsRowHeight()), + QSize(width(), DialogsRowHeight()), [this, peer = result->peer] { updateSearchResult(peer); }); } else if (base::in_range(_searchedPressed, 0, _searchResults.size())) { auto &row = _searchResults[_searchedPressed]; - row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * st::dialogsRowHeight), QSize(width(), st::dialogsRowHeight), [this, index = _searchedPressed] { - rtlupdate(0, searchedOffset() + index * st::dialogsRowHeight, width(), st::dialogsRowHeight); + row->addRipple(e->pos() - QPoint(0, searchedOffset() + _searchedPressed * DialogsRowHeight()), QSize(width(), DialogsRowHeight()), [this, index = _searchedPressed] { + rtlupdate(0, searchedOffset() + index * DialogsRowHeight(), width(), DialogsRowHeight()); }); } if (anim::Disabled() @@ -1248,7 +1290,7 @@ bool InnerWidget::updateReorderPinned(QPoint localPosition) { auto yaddWas = _pinnedRows[_draggingIndex].yadd.current(); auto shift = 0; auto now = crl::now(); - auto rowHeight = st::dialogsRowHeight; + auto rowHeight = DialogsRowHeight(); if (_dragStart.y() > localPosition.y() && _draggingIndex > 0) { shift = -floorclamp(_dragStart.y() - localPosition.y() + (rowHeight / 2), rowHeight, 0, _draggingIndex); @@ -1328,11 +1370,11 @@ bool InnerWidget::pinnedShiftAnimationCallback(crl::time now) { } if (updateMin >= 0) { auto top = pinnedOffset(); - auto updateFrom = top + st::dialogsRowHeight * (updateMin - 1); - auto updateHeight = st::dialogsRowHeight * (updateMax - updateMin + 3); + auto updateFrom = top + DialogsRowHeight() * (updateMin - 1); + auto updateHeight = DialogsRowHeight() * (updateMax - updateMin + 3); if (base::in_range(_aboveIndex, 0, _pinnedRows.size())) { // Always include currently dragged chat in its current and old positions. - auto aboveRowBottom = top + (_aboveIndex + 1) * st::dialogsRowHeight; + auto aboveRowBottom = top + (_aboveIndex + 1) * DialogsRowHeight(); auto aboveTopShift = qCeil(_pinnedRows[_aboveIndex].yadd.current()); accumulate_max(updateHeight, (aboveRowBottom - updateFrom) + _aboveTopShift); accumulate_max(updateHeight, (aboveRowBottom - updateFrom) + aboveTopShift); @@ -1494,7 +1536,7 @@ void InnerWidget::handleChatListEntryRefreshes() { ) | rpl::filter([=](const Event &event) { return (event.filterId == _filterId); }) | rpl::start_with_next([=](const Event &event) { - const auto rowHeight = st::dialogsRowHeight; + const auto rowHeight = DialogsRowHeight(); const auto from = dialogsOffset() + event.moved.from * rowHeight; const auto to = dialogsOffset() + event.moved.to * rowHeight; const auto &key = event.key; @@ -1555,7 +1597,7 @@ int InnerWidget::defaultRowTop(not_null row) const { if (base::in_range(position, 0, _pinnedRows.size())) { top += qRound(_pinnedRows[position].yadd.current()); } - return top + position * st::dialogsRowHeight; + return top + position * DialogsRowHeight(); } void InnerWidget::repaintDialogRow( @@ -1566,7 +1608,7 @@ void InnerWidget::repaintDialogRow( if (const auto folder = row->folder()) { repaintCollapsedFolderRow(folder); } - update(0, defaultRowTop(row), width(), st::dialogsRowHeight); + update(0, defaultRowTop(row), width(), DialogsRowHeight()); } } else if (_state == WidgetState::Filtered) { if (!filterId) { @@ -1574,9 +1616,9 @@ void InnerWidget::repaintDialogRow( if (_filterResults[i]->key() == row->key()) { update( 0, - filteredOffset() + i * st::dialogsRowHeight, + filteredOffset() + i * DialogsRowHeight(), width(), - st::dialogsRowHeight); + DialogsRowHeight()); break; } } @@ -1610,9 +1652,9 @@ void InnerWidget::updateSearchResult(not_null peer) { const auto index = (i - begin(_peerSearchResults)); rtlupdate( 0, - top + index * st::dialogsRowHeight, + top + index * DialogsRowHeight(), width(), - st::dialogsRowHeight); + DialogsRowHeight()); } } } @@ -1622,7 +1664,7 @@ void InnerWidget::updateDialogRow( QRect updateRect, UpdateRowSections sections) { if (updateRect.isEmpty()) { - updateRect = QRect(0, 0, width(), st::dialogsRowHeight); + updateRect = QRect(0, 0, width(), DialogsRowHeight()); } if (IsServerMsgId(-row.fullId.msg)) { if (const auto peer = row.key.peer()) { @@ -1654,7 +1696,7 @@ void InnerWidget::updateDialogRow( if (base::in_range(position, 0, _pinnedRows.size())) { top += qRound(_pinnedRows[position].yadd.current()); } - updateRow(top + position * st::dialogsRowHeight); + updateRow(top + position * DialogsRowHeight()); } } } else if (_state == WidgetState::Filtered) { @@ -1664,7 +1706,7 @@ void InnerWidget::updateDialogRow( auto index = 0; for (const auto result : _filterResults) { if (result->key() == row.key) { - updateRow(add + index * st::dialogsRowHeight); + updateRow(add + index * DialogsRowHeight()); break; } ++index; @@ -1677,7 +1719,7 @@ void InnerWidget::updateDialogRow( auto index = 0; for (const auto &result : _peerSearchResults) { if (result->peer == peer) { - updateRow(add + index * st::dialogsRowHeight); + updateRow(add + index * DialogsRowHeight()); break; } ++index; @@ -1690,7 +1732,7 @@ void InnerWidget::updateDialogRow( auto index = 0; for (const auto &result : _searchResults) { if (isSearchResultActive(result.get(), row)) { - updateRow(add + index * st::dialogsRowHeight); + updateRow(add + index * DialogsRowHeight()); break; } ++index; @@ -1715,9 +1757,9 @@ void InnerWidget::updateSelectedRow(Key key) { if (base::in_range(position, 0, _pinnedRows.size())) { top += qRound(_pinnedRows[position].yadd.current()); } - update(0, top + position * st::dialogsRowHeight, width(), st::dialogsRowHeight); + update(0, top + position * DialogsRowHeight(), width(), DialogsRowHeight()); } else if (_selected) { - update(0, dialogsOffset() + _selected->pos() * st::dialogsRowHeight, width(), st::dialogsRowHeight); + update(0, dialogsOffset() + _selected->pos() * DialogsRowHeight(), width(), DialogsRowHeight()); } else if (_collapsedSelected >= 0) { update(0, _collapsedSelected * st::dialogsImportantBarHeight, width(), st::dialogsImportantBarHeight); } @@ -1725,18 +1767,18 @@ void InnerWidget::updateSelectedRow(Key key) { if (key) { for (auto i = 0, l = int(_filterResults.size()); i != l; ++i) { if (_filterResults[i]->key() == key) { - update(0, filteredOffset() + i * st::dialogsRowHeight, width(), st::dialogsRowHeight); + update(0, filteredOffset() + i * DialogsRowHeight(), width(), DialogsRowHeight()); break; } } } else if (_hashtagSelected >= 0) { update(0, _hashtagSelected * st::mentionHeight, width(), st::mentionHeight); } else if (_filteredSelected >= 0) { - update(0, filteredOffset() + _filteredSelected * st::dialogsRowHeight, width(), st::dialogsRowHeight); + update(0, filteredOffset() + _filteredSelected * DialogsRowHeight(), width(), DialogsRowHeight()); } else if (_peerSearchSelected >= 0) { - update(0, peerSearchOffset() + _peerSearchSelected * st::dialogsRowHeight, width(), st::dialogsRowHeight); + update(0, peerSearchOffset() + _peerSearchSelected * DialogsRowHeight(), width(), DialogsRowHeight()); } else if (_searchedSelected >= 0) { - update(0, searchedOffset() + _searchedSelected * st::dialogsRowHeight, width(), st::dialogsRowHeight); + update(0, searchedOffset() + _searchedSelected * DialogsRowHeight(), width(), DialogsRowHeight()); } } } @@ -2253,7 +2295,8 @@ bool InnerWidget::needCollapsedRowsRefresh() const { const auto collapsedHasArchive = !_collapsedRows.empty() && (_collapsedRows.back()->folder != nullptr); const auto archiveIsCollapsed = (archive != nullptr) - && session().settings().archiveCollapsed(); + && (session().settings().archiveCollapsed() + || ::Kotato::JsonSettings::GetInt("chat_list_lines") == 1); const auto archiveIsInMainMenu = (archive != nullptr) && session().settings().archiveInMainMenu(); return archiveIsInMainMenu @@ -2280,13 +2323,13 @@ void InnerWidget::refresh(bool toTop) { if (list->empty()) { h = st::dialogsEmptyHeight; } else { - h = dialogsOffset() + list->size() * st::dialogsRowHeight; + h = dialogsOffset() + list->size() * DialogsRowHeight(); } } else if (_state == WidgetState::Filtered) { if (_waitingForSearch) { - h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight) + ((_searchResults.empty() && !_searchInChat) ? -st::searchedBarHeight : 0); + h = searchedOffset() + (_searchResults.size() * DialogsRowHeight()) + ((_searchResults.empty() && !_searchInChat) ? -st::searchedBarHeight : 0); } else { - h = searchedOffset() + (_searchResults.size() * st::dialogsRowHeight); + h = searchedOffset() + (_searchResults.size() * DialogsRowHeight()); } } resize(width(), h); @@ -2517,7 +2560,7 @@ void InnerWidget::selectSkip(int32 direction) { const auto fromY = (_collapsedSelected >= 0) ? (_collapsedSelected * st::dialogsImportantBarHeight) : (dialogsOffset() + _selected->pos() * st::dialogsRowHeight); - _mustScrollTo.fire({ fromY, fromY + st::dialogsRowHeight }); + _mustScrollTo.fire({ fromY, fromY + DialogsRowHeight() }); } } else if (_state == WidgetState::Filtered) { if (_hashtagResults.empty() && _filterResults.empty() && _peerSearchResults.empty() && _searchResults.empty()) { @@ -2572,25 +2615,25 @@ void InnerWidget::selectSkip(int32 direction) { }); } else if (base::in_range(_filteredSelected, 0, _filterResults.size())) { _mustScrollTo.fire({ - filteredOffset() + _filteredSelected * st::dialogsRowHeight, + filteredOffset() + _filteredSelected * DialogsRowHeight(), filteredOffset() - + (_filteredSelected + 1) * st::dialogsRowHeight, + + (_filteredSelected + 1) * DialogsRowHeight(), }); } else if (base::in_range(_peerSearchSelected, 0, _peerSearchResults.size())) { _mustScrollTo.fire({ peerSearchOffset() - + _peerSearchSelected * st::dialogsRowHeight + + _peerSearchSelected * DialogsRowHeight() + (_peerSearchSelected ? 0 : -st::searchedBarHeight), peerSearchOffset() - + (_peerSearchSelected + 1) * st::dialogsRowHeight, + + (_peerSearchSelected + 1) * DialogsRowHeight(), }); } else { _mustScrollTo.fire({ searchedOffset() - + _searchedSelected * st::dialogsRowHeight + + _searchedSelected * DialogsRowHeight() + (_searchedSelected ? 0 : -st::searchedBarHeight), searchedOffset() - + (_searchedSelected + 1) * st::dialogsRowHeight, + + (_searchedSelected + 1) * DialogsRowHeight(), }); } } @@ -2601,33 +2644,33 @@ void InnerWidget::scrollToEntry(const RowDescriptor &entry) { int32 fromY = -1; if (_state == WidgetState::Default) { if (auto row = shownDialogs()->getRow(entry.key)) { - fromY = dialogsOffset() + row->pos() * st::dialogsRowHeight; + fromY = dialogsOffset() + row->pos() * DialogsRowHeight(); } } else if (_state == WidgetState::Filtered) { for (int32 i = 0, c = _searchResults.size(); i < c; ++i) { if (isSearchResultActive(_searchResults[i].get(), entry)) { - fromY = searchedOffset() + i * st::dialogsRowHeight; + fromY = searchedOffset() + i * DialogsRowHeight(); break; } } if (fromY < 0) { for (auto i = 0, c = int(_filterResults.size()); i != c; ++i) { if (_filterResults[i]->key() == entry.key) { - fromY = filteredOffset() + (i * st::dialogsRowHeight); + fromY = filteredOffset() + (i * DialogsRowHeight()); break; } } } } if (fromY >= 0) { - _mustScrollTo.fire({ fromY, fromY + st::dialogsRowHeight }); + _mustScrollTo.fire({ fromY, fromY + DialogsRowHeight() }); } } void InnerWidget::selectSkipPage(int32 pixels, int32 direction) { clearMouseSelection(); const auto list = shownDialogs(); - int toSkip = pixels / int(st::dialogsRowHeight); + int toSkip = pixels / int(DialogsRowHeight()); if (_state == WidgetState::Default) { if (!_selected) { if (direction > 0 && list->size() > _skipTopDialogs) { @@ -2653,8 +2696,8 @@ void InnerWidget::selectSkipPage(int32 pixels, int32 direction) { if (_collapsedSelected >= 0 || _selected) { const auto fromY = (_collapsedSelected >= 0) ? (_collapsedSelected * st::dialogsImportantBarHeight) - : (dialogsOffset() + _selected->pos() * st::dialogsRowHeight); - _mustScrollTo.fire({ fromY, fromY + st::dialogsRowHeight }); + : (dialogsOffset() + _selected->pos() * DialogsRowHeight()); + _mustScrollTo.fire({ fromY, fromY + DialogsRowHeight() }); } } else { return selectSkip(direction * toSkip); @@ -2669,10 +2712,10 @@ void InnerWidget::loadPeerPhotos() { auto yFrom = _visibleTop; auto yTo = _visibleTop + (_visibleBottom - _visibleTop) * (PreloadHeightsCount + 1); if (_state == WidgetState::Default) { - auto otherStart = list->size() * st::dialogsRowHeight; + auto otherStart = list->size() * DialogsRowHeight(); if (yFrom < otherStart) { - for (auto i = list->cfind(yFrom, st::dialogsRowHeight), end = list->cend(); i != end; ++i) { - if (((*i)->pos() * st::dialogsRowHeight) >= yTo) { + for (auto i = list->cfind(yFrom, DialogsRowHeight()), end = list->cend(); i != end; ++i) { + if (((*i)->pos() * DialogsRowHeight()) >= yTo) { break; } (*i)->entry()->loadUserpic(); @@ -2683,10 +2726,10 @@ void InnerWidget::loadPeerPhotos() { } yTo -= otherStart; } else if (_state == WidgetState::Filtered) { - int32 from = (yFrom - filteredOffset()) / st::dialogsRowHeight; + int32 from = (yFrom - filteredOffset()) / DialogsRowHeight(); if (from < 0) from = 0; if (from < _filterResults.size()) { - int32 to = (yTo / int32(st::dialogsRowHeight)) + 1; + int32 to = (yTo / int32(DialogsRowHeight())) + 1; if (to > _filterResults.size()) to = _filterResults.size(); for (; from < to; ++from) { @@ -2694,20 +2737,20 @@ void InnerWidget::loadPeerPhotos() { } } - from = (yFrom > filteredOffset() + st::searchedBarHeight ? ((yFrom - filteredOffset() - st::searchedBarHeight) / int32(st::dialogsRowHeight)) : 0) - _filterResults.size(); + from = (yFrom > filteredOffset() + st::searchedBarHeight ? ((yFrom - filteredOffset() - st::searchedBarHeight) / int32(DialogsRowHeight())) : 0) - _filterResults.size(); if (from < 0) from = 0; if (from < _peerSearchResults.size()) { - int32 to = (yTo > filteredOffset() + st::searchedBarHeight ? ((yTo - filteredOffset() - st::searchedBarHeight) / int32(st::dialogsRowHeight)) : 0) - _filterResults.size() + 1; + int32 to = (yTo > filteredOffset() + st::searchedBarHeight ? ((yTo - filteredOffset() - st::searchedBarHeight) / int32(DialogsRowHeight())) : 0) - _filterResults.size() + 1; if (to > _peerSearchResults.size()) to = _peerSearchResults.size(); for (; from < to; ++from) { _peerSearchResults[from]->peer->loadUserpic(); } } - from = (yFrom > filteredOffset() + ((_peerSearchResults.empty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight) ? ((yFrom - filteredOffset() - (_peerSearchResults.empty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(st::dialogsRowHeight)) : 0) - _filterResults.size() - _peerSearchResults.size(); + from = (yFrom > filteredOffset() + ((_peerSearchResults.empty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight) ? ((yFrom - filteredOffset() - (_peerSearchResults.empty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(DialogsRowHeight())) : 0) - _filterResults.size() - _peerSearchResults.size(); if (from < 0) from = 0; if (from < _searchResults.size()) { - int32 to = (yTo > filteredOffset() + (_peerSearchResults.empty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight ? ((yTo - filteredOffset() - (_peerSearchResults.empty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(st::dialogsRowHeight)) : 0) - _filterResults.size() - _peerSearchResults.size() + 1; + int32 to = (yTo > filteredOffset() + (_peerSearchResults.empty() ? 0 : st::searchedBarHeight) + st::searchedBarHeight ? ((yTo - filteredOffset() - (_peerSearchResults.empty() ? 0 : st::searchedBarHeight) - st::searchedBarHeight) / int32(DialogsRowHeight())) : 0) - _filterResults.size() - _peerSearchResults.size() + 1; if (to > _searchResults.size()) to = _searchResults.size(); for (; from < to; ++from) { @@ -3074,8 +3117,8 @@ void InnerWidget::updateDialogRowCornerStatus(not_null history) { ? st::dialogsOnlineBadgeSkip : st::dialogsCallBadgeSkip; const auto updateRect = QRect( - st::dialogsPhotoSize - skip.x() - size, - st::dialogsPhotoSize - skip.y() - size, + DialogsPhotoSize() - skip.x() - size, + DialogsPhotoSize() - skip.y() - size, size, size ).marginsAdded( @@ -3135,11 +3178,11 @@ void InnerWidget::updateRowCornerStatusShown( [](not_null row) { return row->history(); }); const auto index = (i - begin(_filterResults)); const auto row = (i == end(_filterResults)) ? nullptr : i->get(); - return { row, filteredOffset() + index * st::dialogsRowHeight }; + return { row, filteredOffset() + index * DialogsRowHeight() }; }; if (const auto &[row, top] = findRow(history); row != nullptr) { const auto visible = (top < _visibleBottom) - && (top + st::dialogsRowHeight > _visibleTop); + && (top + DialogsRowHeight() > _visibleTop); row->updateCornerBadgeShown( history->peer, visible ? Fn(crl::guard(this, repaint)) : nullptr); diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 164f3ce87..5d8937217 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "dialogs/dialogs_row.h" +#include "kotato/kotato_settings.h" #include "ui/effects/ripple_animation.h" #include "ui/text/text_options.h" #include "ui/text/text_utilities.h" @@ -141,6 +142,28 @@ void BasicRow::paintUserpic( paused); } +void BasicRow::paintUserpic( + Painter &p, + not_null peer, + Ui::VideoUserpic *videoUserpic, + History *historyForCornerBadge, + crl::time now, + bool active, + int fullWidth, + int size, + bool paused) const { + PaintUserpic( + p, + peer, + videoUserpic, + _userpic, + st::dialogsPadding.x(), + st::dialogsPadding.y(), + fullWidth, + size, + paused); +} + Row::Row(Key key, int pos) : _id(key), _pos(pos) { if (const auto history = key.history()) { updateCornerBadgeShown(history->peer); @@ -198,6 +221,9 @@ void Row::updateCornerBadgeShown( not_null peer, Fn updateCallback) const { const auto shown = [&] { + if (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1) { + return false; + } if (const auto user = peer->asUser()) { return Data::IsUserOnline(user); } else if (const auto channel = peer->asChannel()) { @@ -232,7 +258,9 @@ void Row::PaintCornerBadgeFrame( 0, 0, data->frame.width() / data->frame.devicePixelRatio(), - st::dialogsPhotoSize, + (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsUnreadHeight + : st::dialogsPhotoSize), paused); PainterHighQualityEnabler hq(q); @@ -284,6 +312,9 @@ void Row::paintUserpic( now, active, fullWidth, + (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsUnreadHeight + : st::dialogsPhotoSize), paused); if (!historyForCornerBadge || !_cornerBadgeShown) { _cornerBadgeUserpic = nullptr; @@ -292,9 +323,10 @@ void Row::paintUserpic( } ensureCornerBadgeUserpic(); if (_cornerBadgeUserpic->frame.isNull()) { - _cornerBadgeUserpic->frame = QImage( - st::dialogsPhotoSize * cRetinaFactor(), - st::dialogsPhotoSize * cRetinaFactor(), + const auto frameSize = (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsUnreadHeight + : st::dialogsPhotoSize) * cRetinaFactor(); + _cornerBadgeUserpic->frame = QImage(frameSize, frameSize, QImage::Format_ARGB32_Premultiplied); _cornerBadgeUserpic->frame.setDevicePixelRatio(cRetinaFactor()); } diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index 94fec8115..5ce5f2eb4 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -48,6 +48,17 @@ public: int fullWidth, bool paused) const; + virtual void paintUserpic( + Painter &p, + not_null peer, + Ui::VideoUserpic *videoUserpic, + History *historyForCornerBadge, + crl::time now, + bool active, + int fullWidth, + int size, + bool paused) const; + void addRipple(QPoint origin, QSize size, Fn updateCallback); void stopLastRipple(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index a4ffd5ad3..7b6a29c60 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "dialogs/dialogs_widget.h" +#include "kotato/kotato_settings.h" #include "kotato/kotato_lang.h" #include "dialogs/dialogs_inner_widget.h" #include "dialogs/dialogs_search_from_controllers.h" @@ -231,7 +232,9 @@ Widget::Widget( const auto movedTo = data.ymax; const auto st = int32(_scroll->scrollTop()); if (st > movedTo && st < movedFrom) { - _scroll->scrollToY(st + st::dialogsRowHeight); + _scroll->scrollToY(st + (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsImportantBarHeight + : st::dialogsRowHeight)); } }, lifetime()); _inner->searchMessages( @@ -1670,7 +1673,7 @@ void Widget::updateControlsGeometry() { _forwardCancel->moveToLeft(0, filterAreaTop); filterAreaTop += st::dialogsForwardHeight; } - auto smallLayoutWidth = (st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPadding.x()); + auto smallLayoutWidth = (st::dialogsPadding.x() + (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 ? st::dialogsUnreadHeight : st::dialogsPhotoSize) + st::dialogsPadding.x()); auto smallLayoutRatio = (width() < st::columnMinimalWidthLeft) ? (st::columnMinimalWidthLeft - width()) / float64(st::columnMinimalWidthLeft - smallLayoutWidth) : 0.; auto filterLeft = (controller()->filtersWidth() ? st::dialogsFilterSkip : st::dialogsFilterPadding.x() + _mainMenuToggle->width()) + st::dialogsFilterPadding.x(); auto filterRight = (session().domain().local().hasLocalPasscode() ? (st::dialogsFilterPadding.x() + _lockUnlock->width()) : st::dialogsFilterSkip) + st::dialogsFilterPadding.x(); diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 46f79c5d4..9cec95cd4 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "dialogs/ui/dialogs_layout.h" +#include "kotato/kotato_settings.h" #include "data/data_abstract_structure.h" #include "data/data_drafts.h" #include "data/data_session.h" @@ -92,7 +93,8 @@ void PaintNarrowCounter( bool selected, bool active, bool unreadMuted, - bool mentionOrReactionMuted) { + bool mentionOrReactionMuted, + int lines = 2) { auto skipBeforeMention = 0; if (displayUnreadCounter || displayUnreadMark) { const auto counter = (unreadCount > 0) @@ -104,9 +106,11 @@ void PaintNarrowCounter( : 3; const auto unreadRight = st::dialogsPadding.x() + st::dialogsPhotoSize; - const auto unreadTop = st::dialogsPadding.y() - + st::dialogsPhotoSize - - st::dialogsUnreadHeight; + const auto unreadTop = (lines == 1 + ? st::dialogsPadding.y() + : st::dialogsPadding.y() + + st::dialogsPhotoSize + - st::dialogsUnreadHeight); UnreadBadgeStyle st; st.active = active; @@ -124,11 +128,15 @@ void PaintNarrowCounter( if (displayMentionBadge || displayReactionBadge) { const auto counter = QString(); const auto unreadRight = st::dialogsPadding.x() - + st::dialogsPhotoSize + + (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsUnreadHeight + : st::dialogsPhotoSize) - skipBeforeMention; - const auto unreadTop = st::dialogsPadding.y() - + st::dialogsPhotoSize - - st::dialogsUnreadHeight; + const auto unreadTop = (lines == 1 + ? st::dialogsPadding.y() + : st::dialogsPadding.y() + + st::dialogsPhotoSize + - st::dialogsUnreadHeight); UnreadBadgeStyle st; st.sizeId = displayMentionBadge @@ -302,6 +310,195 @@ enum class Flag { }; inline constexpr bool is_flag_type(Flag) { return true; } +template +void paintOneLineRow( + Painter &p, + not_null row, + not_null entry, + Dialogs::Key chat, + VideoUserpic *videoUserpic, + FilterId filterId, + PeerData *from, + const Ui::Text::String &fromName, + const HiddenSenderInfo *hiddenSenderInfo, + HistoryItem *item, + const Data::Draft *draft, + QDateTime date, + int fullWidth, + base::flags flags, + crl::time ms, + PaintItemCallback &&paintItemCallback, + PaintCounterCallback &&paintCounterCallback) { + const auto supportMode = entry->session().supportMode(); + if (supportMode) { + draft = nullptr; + } + + auto active = (flags & Flag::Active); + auto selected = (flags & Flag::Selected); + auto fullRect = QRect(0, 0, fullWidth, st::dialogsImportantBarHeight); + auto bg = active + ? st::dialogsBgActive + : (selected + ? st::dialogsBgOver + : st::dialogsBg); + auto ripple = active + ? st::dialogsRippleBgActive + : st::dialogsRippleBg; + p.fillRect(fullRect, bg); + row->paintRipple(p, 0, 0, fullWidth, &ripple->c); + + const auto history = chat.history(); + + if (flags & Flag::SavedMessages) { + Ui::EmptyUserpic::PaintSavedMessages( + p, + st::dialogsPadding.x(), + st::dialogsPadding.y(), + fullWidth, + st::dialogsUnreadHeight); + } else if (flags & Flag::RepliesMessages) { + Ui::EmptyUserpic::PaintRepliesMessages( + p, + st::dialogsPadding.x(), + st::dialogsPadding.y(), + fullWidth, + st::dialogsUnreadHeight); + } else if (from) { + row->paintUserpic( + p, + from, + videoUserpic, + (flags & Flag::AllowUserOnline) ? history : nullptr, + ms, + active, + fullWidth, + (flags & Flag::VideoPaused)); + } else if (hiddenSenderInfo) { + hiddenSenderInfo->emptyUserpic.paint( + p, + st::dialogsPadding.x(), + st::dialogsPadding.y(), + fullWidth, + st::dialogsUnreadHeight); + } else { + entry->paintUserpicLeft( + p, + row->userpicView(), + st::dialogsPadding.x(), + st::dialogsPadding.y(), + fullWidth, + st::dialogsUnreadHeight); + } + + auto nameleft = st::dialogsPadding.x() * 2 + st::dialogsUnreadHeight; + if (fullWidth <= nameleft) { + if (!draft && item && !item->isEmpty()) { + paintCounterCallback(); + } + return; + } + + auto namewidth = fullWidth - nameleft - st::dialogsPadding.x(); + auto rectForName = QRect( + nameleft, + st::dialogsPadding.y(), + namewidth, + st::dialogsTextFont->height); + + const auto promoted = (history && history->useTopPromotion()) + && !(flags & (Flag::SearchResult/* | Flag::FeedSearchResult*/)); // #feed + if (promoted) { + const auto text = tr::lng_proxy_sponsor(tr::now); + PaintRowTopRight(p, text, rectForName, active, selected); + } else if (from && !(flags & Flag::SearchResult/* | Flag::FeedSearchResult*/)) { // #feed + if (const auto chatTypeIcon = ChatTypeIcon(from, active, selected)) { + chatTypeIcon->paint(p, rectForName.topLeft(), fullWidth); + rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip); + } + //} else if (const auto feed = chat.feed()) { // #feed + // if (const auto feedTypeIcon = FeedTypeIcon(feed, active, selected)) { + // feedTypeIcon->paint(p, rectForName.topLeft(), fullWidth); + // rectForName.setLeft(rectForName.left() + st::dialogsChatTypeSkip); + // } + } + if (!draft + && !(supportMode + && entry->session().supportHelper().isOccupiedBySomeone(history)) + && item + && !item->isEmpty()) { + const auto nameWithoutCounterWidth = paintItemCallback(nameleft, (flags & Flag::SearchResult ? namewidth : rectForName.width())); + rectForName.setWidth(nameWithoutCounterWidth - st::dialogsPadding.x()); + } else if (entry->isPinnedDialog(filterId) && (filterId || !entry->fixedOnTopIndex())) { + auto &icon = (active ? st::dialogsPinnedIconActive : (selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon)); + icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), st::dialogsPadding.y(), fullWidth); + rectForName.setWidth(rectForName.width() - icon.width() - st::dialogsUnreadPadding); + } + + QString text; + + if (flags & (Flag::SavedMessages | Flag::RepliesMessages)) { + text = (flags & Flag::SavedMessages) + ? tr::lng_saved_messages(tr::now) + : tr::lng_replies_messages(tr::now); + p.setPen(active + ? st::dialogsNameFgActive + : selected + ? st::dialogsNameFgOver + : st::dialogsNameFg); + } else if (from) { + if (!(flags & Flag::SearchResult)) { + const auto badgeStyle = PeerBadgeStyle{ + (active + ? &st::dialogsVerifiedIconActive + : selected + ? &st::dialogsVerifiedIconOver + : &st::dialogsVerifiedIcon), + (active + ? &st::dialogsPremiumIconActive + : selected + ? &st::dialogsPremiumIconOver + : &st::dialogsPremiumIcon), + (active + ? &st::dialogsScamFgActive + : selected + ? &st::dialogsScamFgOver + : &st::dialogsScamFg) }; + const auto badgeWidth = Ui::DrawPeerBadgeGetWidth( + from, + p, + rectForName, + fromName.maxWidth(), + fullWidth, + badgeStyle); + rectForName.setWidth(rectForName.width() - badgeWidth); + + text = fromName.toString(); + p.setPen(active + ? st::dialogsNameFgActive + : selected + ? st::dialogsNameFgOver + : st::dialogsNameFg); + p.setFont(st::dialogsTextFont); + } + } else if (hiddenSenderInfo) { + text = hiddenSenderInfo->nameText().toString(); + } else { + text = entry->chatListName(); + const auto nameFg = active + ? st::dialogsNameFgActive + : (selected + ? st::dialogsArchiveFgOver + : st::dialogsArchiveFg); + p.setPen(nameFg); + } + + if (!(from && (flags & Flag::SearchResult))) { + auto textStr = Ui::Text::String{ st::dialogsTextStyle, text, Ui::NameTextOptions() }; + textStr.drawElided(p, rectForName.left(), rectForName.top(), rectForName.width()); + } +} + template void paintRow( Painter &p, @@ -855,6 +1052,11 @@ void RowPainter::paint( const auto mentionOrReactionMuted = (entry->folder() != nullptr) || (!displayMentionBadge && unreadMuted); const auto displayUnreadCounter = [&] { + if (fullWidth < st::columnMinimalWidthLeft + && ::Kotato::JsonSettings::GetInt("chat_list_lines") == 1) { + return false; + } + if (displayMentionBadge && unreadCount == 1 && item @@ -888,9 +1090,12 @@ void RowPainter::paint( | (peer && peer->isRepliesChat() ? Flag::RepliesMessages : Flag(0)) | (paused ? Flag::VideoPaused : Flag(0)); const auto paintItemCallback = [&](int nameleft, int namewidth) { - const auto texttop = st::dialogsPadding.y() - + st::msgNameFont->height - + st::dialogsSkip; + const auto texttop = (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsPadding.y() + : st::dialogsPadding.y() + + st::msgNameFont->height + + st::dialogsSkip); + const auto availableWidth = PaintWideCounter( p, texttop, @@ -906,37 +1111,42 @@ void RowPainter::paint( selected, unreadMuted, mentionOrReactionMuted); - const auto &color = active - ? st::dialogsTextFgServiceActive - : (selected - ? st::dialogsTextFgServiceOver - : st::dialogsTextFgService); - const auto itemRect = QRect( - nameleft, - texttop, - availableWidth, - st::dialogsTextFont->height); - const auto actionWasPainted = ShowSendActionInDialogs(history) - ? history->sendActionPainter()->paint( - p, - itemRect.x(), - itemRect.y(), - itemRect.width(), - fullWidth, - color, - ms) - : false; - if (const auto folder = row->folder()) { - PaintListEntryText(p, itemRect, active, selected, row); - } else if (history && !actionWasPainted) { - history->lastItemDialogsView.paint( - p, - item, - itemRect, - active, - selected, - {}); + if (flags & Flag::SearchResult + || ::Kotato::JsonSettings::GetInt("chat_list_lines") > 1) { + const auto &color = active + ? st::dialogsTextFgServiceActive + : (selected + ? st::dialogsTextFgServiceOver + : st::dialogsTextFgService); + const auto itemRect = QRect( + nameleft, + texttop, + availableWidth, + st::dialogsTextFont->height); + const auto actionWasPainted = ShowSendActionInDialogs(history) + ? history->sendActionPainter()->paint( + p, + itemRect.x(), + itemRect.y(), + itemRect.width(), + fullWidth, + color, + ms) + : false; + if (const auto folder = row->folder()) { + PaintListEntryText(p, itemRect, active, selected, row); + } else if (history && !actionWasPainted) { + history->lastItemDialogsView.paint( + p, + item, + itemRect, + active, + selected, + {}); + } } + + return availableWidth; }; const auto paintCounterCallback = [&] { PaintNarrowCounter( @@ -949,26 +1159,48 @@ void RowPainter::paint( selected, active, unreadMuted, - mentionOrReactionMuted); + mentionOrReactionMuted, + ::Kotato::JsonSettings::GetInt("chat_list_lines")); }; - paintRow( - p, - row, - entry, - row->key(), - videoUserpic, - filterId, - from, - entry->chatListNameText(), - nullptr, - item, - cloudDraft, - displayDate, - fullWidth, - flags, - ms, - paintItemCallback, - paintCounterCallback); + if (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1) { + paintOneLineRow( + p, + row, + entry, + row->key(), + videoUserpic, + filterId, + from, + entry->chatListNameText(), + nullptr, + item, + cloudDraft, + displayDate, + fullWidth, + flags, + ms, + paintItemCallback, + paintCounterCallback); + } else { + paintRow( + p, + row, + entry, + row->key(), + videoUserpic, + filterId, + from, + entry->chatListNameText(), + nullptr, + item, + cloudDraft, + displayDate, + fullWidth, + flags, + ms, + paintItemCallback, + paintCounterCallback); + } } void RowPainter::paint( @@ -1030,11 +1262,21 @@ void RowPainter::paint( && !displayMentionBadge && unreadMark; const auto displayPinnedIcon = false; - + const auto showSavedMessages = history->peer->isSelf() + && !row->searchInChat(); + const auto showRepliesMessages = history->peer->isRepliesChat() + && !row->searchInChat(); + const auto flags = (active ? Flag::Active : Flag(0)) + | (selected ? Flag::Selected : Flag(0)) + | Flag::SearchResult + | (showSavedMessages ? Flag::SavedMessages : Flag(0)) + | (showRepliesMessages ? Flag::RepliesMessages : Flag(0)); const auto paintItemCallback = [&](int nameleft, int namewidth) { - const auto texttop = st::dialogsPadding.y() - + st::msgNameFont->height - + st::dialogsSkip; + const auto texttop = (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsPadding.y() + : st::dialogsPadding.y() + + st::msgNameFont->height + + st::dialogsSkip); const auto availableWidth = PaintWideCounter( p, texttop, @@ -1051,18 +1293,23 @@ void RowPainter::paint( unreadMuted, mentionOrReactionMuted); - const auto itemRect = QRect( - nameleft, - texttop, - availableWidth, - st::dialogsTextFont->height); - row->itemView().paint( - p, - item, - itemRect, - active, - selected, - previewOptions); + if (flags & Flag::SearchResult + || ::Kotato::JsonSettings::GetInt("chat_list_lines") > 1) { + const auto itemRect = QRect( + nameleft, + texttop, + availableWidth, + st::dialogsTextFont->height); + row->itemView().paint( + p, + item, + itemRect, + active, + selected, + previewOptions); + } + + return availableWidth; }; const auto paintCounterCallback = [&] { PaintNarrowCounter( @@ -1075,35 +1322,48 @@ void RowPainter::paint( selected, active, unreadMuted, - mentionOrReactionMuted); + mentionOrReactionMuted, + ::Kotato::JsonSettings::GetInt("chat_list_lines")); }; - const auto showSavedMessages = history->peer->isSelf() - && !row->searchInChat(); - const auto showRepliesMessages = history->peer->isRepliesChat() - && !row->searchInChat(); - const auto flags = (active ? Flag::Active : Flag(0)) - | (selected ? Flag::Selected : Flag(0)) - | Flag::SearchResult - | (showSavedMessages ? Flag::SavedMessages : Flag(0)) - | (showRepliesMessages ? Flag::RepliesMessages : Flag(0)); - paintRow( - p, - row, - history, - history, - nullptr, - FilterId(), - from, - row->name(), - hiddenSenderInfo, - item, - cloudDraft, - ItemDateTime(item), - fullWidth, - flags, - ms, - paintItemCallback, - paintCounterCallback); + if (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1) { + paintOneLineRow( + p, + row, + history, + history, + nullptr, + FilterId(), + from, + row->name(), + hiddenSenderInfo, + item, + cloudDraft, + ItemDateTime(item), + fullWidth, + flags, + ms, + paintItemCallback, + paintCounterCallback); + } else { + paintRow( + p, + row, + history, + history, + nullptr, + FilterId(), + from, + row->name(), + hiddenSenderInfo, + item, + cloudDraft, + ItemDateTime(item), + fullWidth, + flags, + ms, + paintItemCallback, + paintCounterCallback); + } } QRect RowPainter::sendActionAnimationRect( @@ -1113,7 +1373,9 @@ QRect RowPainter::sendActionAnimationRect( int fullWidth, bool textUpdated) { const auto nameleft = st::dialogsPadding.x() - + st::dialogsPhotoSize + + (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 + ? st::dialogsUnreadHeight + : st::dialogsPhotoSize) + st::dialogsPhotoPadding; const auto namewidth = fullWidth - nameleft - st::dialogsPadding.x(); const auto texttop = st::dialogsPadding.y() diff --git a/Telegram/SourceFiles/kotato/kotato_settings.cpp b/Telegram/SourceFiles/kotato/kotato_settings.cpp index a9a2c9752..95aa3ea4a 100644 --- a/Telegram/SourceFiles/kotato/kotato_settings.cpp +++ b/Telegram/SourceFiles/kotato/kotato_settings.cpp @@ -312,6 +312,10 @@ const std::map> DefinitionMap { { "scales", { .type = SettingType::QJsonArraySetting, .limitHandler = ScalesLimit(), }}, + { "chat_list_lines", { + .type = SettingType::IntSetting, + .defaultValue = 2, + .limitHandler = IntLimit(1, 2, 2), }}, }; using OldOptionKey = QString; diff --git a/Telegram/SourceFiles/kotato/kotato_settings_menu.cpp b/Telegram/SourceFiles/kotato/kotato_settings_menu.cpp index 72cfb68e2..4f4867092 100644 --- a/Telegram/SourceFiles/kotato/kotato_settings_menu.cpp +++ b/Telegram/SourceFiles/kotato/kotato_settings_menu.cpp @@ -105,6 +105,20 @@ void SetupKotatoChats( AddSkip(container); AddSubsectionTitle(container, rktr("ktg_settings_chats")); + AddButton( + container, + rktr("ktg_settings_chat_list_compact"), + st::settingsButtonNoIcon + )->toggleOn( + rpl::single(::Kotato::JsonSettings::GetInt("chat_list_lines") == 1) + )->toggledValue( + ) | rpl::filter([](bool enabled) { + return (enabled != (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1)); + }) | rpl::start_with_next([](bool enabled) { + ::Kotato::JsonSettings::Set("chat_list_lines", enabled ? 1 : 2); + ::Kotato::JsonSettings::Write(); + }, container->lifetime()); + AddButton( container, rktr("ktg_settings_always_show_scheduled"), diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index d1fc681fa..6542db290 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "window/window_peer_menu.h" +#include "kotato/kotato_settings.h" #include "api/api_chat_participants.h" #include "lang/lang_keys.h" #include "ui/boxes/confirm_box.h" @@ -911,14 +912,16 @@ void Filler::fillArchiveActions() { return; } const auto controller = _controller; - const auto hidden = controller->session().settings().archiveCollapsed(); - const auto text = hidden - ? tr::lng_context_archive_expand(tr::now) - : tr::lng_context_archive_collapse(tr::now); - _addAction(text, [=] { - controller->session().settings().setArchiveCollapsed(!hidden); - controller->session().saveSettingsDelayed(); - }, hidden ? &st::menuIconExpand : &st::menuIconCollapse); + if (::Kotato::JsonSettings::GetInt("chat_list_lines") != 1) { + const auto hidden = controller->session().settings().archiveCollapsed(); + const auto text = hidden + ? tr::lng_context_archive_expand(tr::now) + : tr::lng_context_archive_collapse(tr::now); + _addAction(text, [=] { + controller->session().settings().setArchiveCollapsed(!hidden); + controller->session().saveSettingsDelayed(); + }, hidden ? &st::menuIconExpand : &st::menuIconCollapse); + } _addAction(tr::lng_context_archive_to_menu(tr::now), [=] { Ui::Toast::Show( diff --git a/Telegram/SourceFiles/window/window_session_controller.cpp b/Telegram/SourceFiles/window/window_session_controller.cpp index b745f3c39..f240c1f7c 100644 --- a/Telegram/SourceFiles/window/window_session_controller.cpp +++ b/Telegram/SourceFiles/window/window_session_controller.cpp @@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "window/window_session_controller.h" +#include "kotato/kotato_settings.h" #include "boxes/add_contact_box.h" #include "boxes/peers/add_bot_to_chat_box.h" #include "boxes/peers/edit_peer_info_box.h" @@ -1035,7 +1036,7 @@ void SessionController::floatPlayerAreaUpdated() { } int SessionController::dialogsSmallColumnWidth() const { - return st::dialogsPadding.x() + st::dialogsPhotoSize + st::dialogsPadding.x(); + return st::dialogsPadding.x() + (::Kotato::JsonSettings::GetInt("chat_list_lines") == 1 ? st::dialogsUnreadHeight : st::dialogsPhotoSize) + st::dialogsPadding.x(); } int SessionController::minimalThreeColumnWidth() const {