Before Width: | Height: | Size: 107 B |
Before Width: | Height: | Size: 126 B |
Before Width: | Height: | Size: 174 B |
BIN
Telegram/Resources/icons/contacts_alphabet.png
Normal file
After Width: | Height: | Size: 448 B |
BIN
Telegram/Resources/icons/contacts_alphabet@2x.png
Normal file
After Width: | Height: | Size: 784 B |
BIN
Telegram/Resources/icons/contacts_alphabet@3x.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
Telegram/Resources/icons/contacts_online.png
Normal file
After Width: | Height: | Size: 385 B |
BIN
Telegram/Resources/icons/contacts_online@2x.png
Normal file
After Width: | Height: | Size: 649 B |
BIN
Telegram/Resources/icons/contacts_online@3x.png
Normal file
After Width: | Height: | Size: 1,014 B |
|
@ -160,6 +160,21 @@ contactsAboutFg: windowSubTextFgOver;
|
|||
contactsAboutTop: 60px;
|
||||
contactsAboutBottom: 19px;
|
||||
|
||||
contactsSortButton: IconButton(defaultIconButton) {
|
||||
width: 48px;
|
||||
height: 54px;
|
||||
icon: icon{{ "contacts_alphabet", boxTitleCloseFg }};
|
||||
iconOver: icon{{ "contacts_alphabet", boxTitleCloseFgOver }};
|
||||
iconPosition: point(10px, -1px);
|
||||
rippleAreaPosition: point(1px, 6px);
|
||||
rippleAreaSize: 42px;
|
||||
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||
color: windowBgOver;
|
||||
}
|
||||
}
|
||||
contactsSortOnlineIcon: icon{{ "contacts_online", boxTitleCloseFg }};
|
||||
contactsSortOnlineIconOver: icon{{ "contacts_online", boxTitleCloseFgOver }};
|
||||
|
||||
contactsMarginTop: 4px;
|
||||
contactsMarginBottom: 4px;
|
||||
membersMarginTop: 10px;
|
||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_user.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_histories.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "apiwrap.h"
|
||||
#include "mainwidget.h"
|
||||
#include "mainwindow.h"
|
||||
|
@ -26,12 +27,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/history.h"
|
||||
#include "dialogs/dialogs_main_list.h"
|
||||
#include "window/window_session_controller.h" // showAddContact()
|
||||
#include "base/unixtime.h"
|
||||
#include "facades.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_profile.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto kSortByOnlineThrottle = 3 * crl::time(1000);
|
||||
|
||||
void ShareBotGame(not_null<UserData*> bot, not_null<PeerData*> chat) {
|
||||
const auto history = chat->owner().history(chat);
|
||||
auto &histories = history->owner().histories();
|
||||
|
@ -110,17 +114,31 @@ void AddBotToGroup(not_null<UserData*> bot, not_null<PeerData*> chat) {
|
|||
|
||||
object_ptr<Ui::BoxContent> PrepareContactsBox(
|
||||
not_null<Window::SessionController*> sessionController) {
|
||||
const auto controller = sessionController;
|
||||
auto delegate = [=](not_null<PeerListBox*> box) {
|
||||
using Mode = ContactsBoxController::SortMode;
|
||||
auto controller = std::make_unique<ContactsBoxController>(
|
||||
&sessionController->session());
|
||||
const auto raw = controller.get();
|
||||
auto init = [=](not_null<PeerListBox*> box) {
|
||||
struct State {
|
||||
QPointer<Ui::IconButton> toggleSort;
|
||||
Mode mode = ContactsBoxController::SortMode::Online;
|
||||
};
|
||||
const auto state = box->lifetime().make_state<State>();
|
||||
box->addButton(tr::lng_close(), [=] { box->closeBox(); });
|
||||
box->addLeftButton(
|
||||
tr::lng_profile_add_contact(),
|
||||
[=] { controller->showAddContact(); });
|
||||
[=] { sessionController->showAddContact(); });
|
||||
state->toggleSort = box->addTopButton(st::contactsSortButton, [=] {
|
||||
const auto online = (state->mode == Mode::Online);
|
||||
state->mode = online ? Mode::Alphabet : Mode::Online;
|
||||
raw->setSortMode(state->mode);
|
||||
state->toggleSort->setIconOverride(
|
||||
online ? &st::contactsSortOnlineIcon : nullptr,
|
||||
online ? &st::contactsSortOnlineIconOver : nullptr);
|
||||
});
|
||||
raw->setSortMode(Mode::Online);
|
||||
};
|
||||
return Box<PeerListBox>(
|
||||
std::make_unique<ContactsBoxController>(
|
||||
&sessionController->session()),
|
||||
std::move(delegate));
|
||||
return Box<PeerListBox>(std::move(controller), std::move(init));
|
||||
}
|
||||
|
||||
void PeerListRowWithLink::setActionLink(const QString &action) {
|
||||
|
@ -368,7 +386,8 @@ ContactsBoxController::ContactsBoxController(
|
|||
not_null<Main::Session*> session,
|
||||
std::unique_ptr<PeerListSearchController> searchController)
|
||||
: PeerListController(std::move(searchController))
|
||||
, _session(session) {
|
||||
, _session(session)
|
||||
, _sortByOnlineTimer([=] { sort(); }) {
|
||||
}
|
||||
|
||||
Main::Session &ContactsBoxController::session() const {
|
||||
|
@ -404,6 +423,7 @@ void ContactsBoxController::rebuildRows() {
|
|||
};
|
||||
appendList(session().data().contactsList());
|
||||
checkForEmptyRows();
|
||||
sort();
|
||||
delegate()->peerListRefreshRows();
|
||||
}
|
||||
|
||||
|
@ -427,6 +447,66 @@ void ContactsBoxController::rowClicked(not_null<PeerListRow*> row) {
|
|||
Ui::showPeerHistory(row->peer(), ShowAtUnreadMsgId);
|
||||
}
|
||||
|
||||
void ContactsBoxController::setSortMode(SortMode mode) {
|
||||
if (_sortMode == mode) {
|
||||
return;
|
||||
}
|
||||
_sortMode = mode;
|
||||
sort();
|
||||
if (_sortMode == SortMode::Online) {
|
||||
session().changes().peerUpdates(
|
||||
Data::PeerUpdate::Flag::OnlineStatus
|
||||
) | rpl::filter([=](const Data::PeerUpdate &update) {
|
||||
return !_sortByOnlineTimer.isActive()
|
||||
&& delegate()->peerListFindRow(update.peer->id.value);
|
||||
}) | rpl::start_with_next([=] {
|
||||
_sortByOnlineTimer.callOnce(kSortByOnlineThrottle);
|
||||
}, _sortByOnlineLifetime);
|
||||
} else {
|
||||
_sortByOnlineTimer.cancel();
|
||||
_sortByOnlineLifetime.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsBoxController::sort() {
|
||||
switch (_sortMode) {
|
||||
case SortMode::Alphabet: sortByName(); break;
|
||||
case SortMode::Online: sortByOnline(); break;
|
||||
default: Unexpected("SortMode in ContactsBoxController.");
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsBoxController::sortByName() {
|
||||
auto keys = base::flat_map<PeerListRowId, QString>();
|
||||
keys.reserve(delegate()->peerListFullRowsCount());
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto id = row.id();
|
||||
const auto i = keys.find(id);
|
||||
if (i != end(keys)) {
|
||||
return i->second;
|
||||
}
|
||||
const auto peer = row.peer();
|
||||
const auto history = peer->owner().history(peer);
|
||||
return keys.emplace(id, history->chatListNameSortKey()).first->second;
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return (key(a).compare(key(b)) < 0);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
void ContactsBoxController::sortByOnline() {
|
||||
const auto now = base::unixtime::now();
|
||||
const auto key = [&](const PeerListRow &row) {
|
||||
const auto user = row.peer()->asUser();
|
||||
return user ? (std::min(user->onlineTill, now) + 1) : TimeId();
|
||||
};
|
||||
const auto predicate = [&](const PeerListRow &a, const PeerListRow &b) {
|
||||
return key(a) > key(b);
|
||||
};
|
||||
delegate()->peerListSortRows(predicate);
|
||||
}
|
||||
|
||||
bool ContactsBoxController::appendRow(not_null<UserData*> user) {
|
||||
if (auto row = delegate()->peerListFindRow(user->id.value)) {
|
||||
updateRowHook(row);
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "boxes/peer_list_box.h"
|
||||
#include "base/flat_set.h"
|
||||
#include "base/weak_ptr.h"
|
||||
#include "base/timer.h"
|
||||
|
||||
// Not used for now.
|
||||
//
|
||||
|
@ -136,6 +137,12 @@ public:
|
|||
not_null<PeerData*> peer) override final;
|
||||
void rowClicked(not_null<PeerListRow*> row) override;
|
||||
|
||||
enum class SortMode {
|
||||
Alphabet,
|
||||
Online,
|
||||
};
|
||||
void setSortMode(SortMode mode);
|
||||
|
||||
protected:
|
||||
virtual std::unique_ptr<PeerListRow> createRow(not_null<UserData*> user);
|
||||
virtual void prepareViewHook() {
|
||||
|
@ -144,11 +151,17 @@ protected:
|
|||
}
|
||||
|
||||
private:
|
||||
void sort();
|
||||
void sortByName();
|
||||
void sortByOnline();
|
||||
void rebuildRows();
|
||||
void checkForEmptyRows();
|
||||
bool appendRow(not_null<UserData*> user);
|
||||
|
||||
const not_null<Main::Session*> _session;
|
||||
SortMode _sortMode = SortMode::Alphabet;
|
||||
base::Timer _sortByOnlineTimer;
|
||||
rpl::lifetime _sortByOnlineLifetime;
|
||||
|
||||
};
|
||||
|
||||
|
|