mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Add more-chats-added bar to cloud folders.
This commit is contained in:
parent
63960c647b
commit
77939ae9bd
13 changed files with 599 additions and 24 deletions
BIN
Telegram/Resources/animations/cloud_filters.tgs
Normal file
BIN
Telegram/Resources/animations/cloud_filters.tgs
Normal file
Binary file not shown.
|
@ -3,6 +3,7 @@
|
||||||
<file alias="change_number.tgs">../../animations/change_number.tgs</file>
|
<file alias="change_number.tgs">../../animations/change_number.tgs</file>
|
||||||
<file alias="blocked_peers_empty.tgs">../../animations/blocked_peers_empty.tgs</file>
|
<file alias="blocked_peers_empty.tgs">../../animations/blocked_peers_empty.tgs</file>
|
||||||
<file alias="filters.tgs">../../animations/filters.tgs</file>
|
<file alias="filters.tgs">../../animations/filters.tgs</file>
|
||||||
|
<file alias="cloud_filters.tgs">../../animations/cloud_filters.tgs</file>
|
||||||
<file alias="local_passcode_enter.tgs">../../animations/local_passcode_enter.tgs</file>
|
<file alias="local_passcode_enter.tgs">../../animations/local_passcode_enter.tgs</file>
|
||||||
<file alias="cloud_password/intro.tgs">../../animations/cloud_password/intro.tgs</file>
|
<file alias="cloud_password/intro.tgs">../../animations/cloud_password/intro.tgs</file>
|
||||||
<file alias="cloud_password/password_input.tgs">../../animations/cloud_password/password_input.tgs</file>
|
<file alias="cloud_password/password_input.tgs">../../animations/cloud_password/password_input.tgs</file>
|
||||||
|
|
|
@ -191,35 +191,39 @@ void InitFilterLinkHeader(
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportInvite(
|
void ImportInvite(
|
||||||
base::weak_ptr<Window::SessionController> weak,
|
|
||||||
const QString &slug,
|
const QString &slug,
|
||||||
|
FilterId filterId,
|
||||||
const base::flat_set<not_null<PeerData*>> &peers,
|
const base::flat_set<not_null<PeerData*>> &peers,
|
||||||
Fn<void()> done,
|
Fn<void()> done,
|
||||||
Fn<void()> fail) {
|
Fn<void(QString)> fail) {
|
||||||
Expects(!peers.empty());
|
Expects(!peers.empty());
|
||||||
|
|
||||||
const auto peer = peers.front();
|
const auto peer = peers.front();
|
||||||
const auto api = &peer->session().api();
|
const auto api = &peer->session().api();
|
||||||
const auto callback = [=](const MTPUpdates &result) {
|
const auto callback = [=](const MTPUpdates &result) {
|
||||||
api->applyUpdates(result);
|
api->applyUpdates(result);
|
||||||
|
if (slug.isEmpty()) {
|
||||||
|
peer->owner().chatsFilters().moreChatsHide(filterId, true);
|
||||||
|
}
|
||||||
done();
|
done();
|
||||||
};
|
};
|
||||||
const auto error = [=](const MTP::Error &error) {
|
const auto error = [=](const MTP::Error &error) {
|
||||||
if (const auto strong = weak.get()) {
|
fail(error.type());
|
||||||
Ui::ShowMultilineToast({
|
|
||||||
.parentOverride = Window::Show(strong).toastParent(),
|
|
||||||
.text = { error.type() },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
};
|
};
|
||||||
auto inputs = peers | ranges::views::transform([](auto peer) {
|
auto inputs = peers | ranges::views::transform([](auto peer) {
|
||||||
return MTPInputPeer(peer->input);
|
return MTPInputPeer(peer->input);
|
||||||
}) | ranges::to<QVector>();
|
}) | ranges::to<QVector>();
|
||||||
api->request(MTPchatlists_JoinChatlistInvite(
|
if (!slug.isEmpty()) {
|
||||||
MTP_string(slug),
|
api->request(MTPchatlists_JoinChatlistInvite(
|
||||||
MTP_vector<MTPInputPeer>(std::move(inputs))
|
MTP_string(slug),
|
||||||
)).done(callback).fail(error).send();
|
MTP_vector<MTPInputPeer>(std::move(inputs))
|
||||||
|
)).done(callback).fail(error).send();
|
||||||
|
} else {
|
||||||
|
api->request(MTPchatlists_JoinChatlistUpdates(
|
||||||
|
MTP_inputChatlistDialogFilter(MTP_int(filterId)),
|
||||||
|
MTP_vector<MTPInputPeer>(std::move(inputs))
|
||||||
|
)).done(callback).fail(error).send();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ToggleChatsController::ToggleChatsController(
|
ToggleChatsController::ToggleChatsController(
|
||||||
|
@ -462,10 +466,17 @@ void ProcessFilterInvite(
|
||||||
// #TODO filters
|
// #TODO filters
|
||||||
} else if (!state->importing) {
|
} else if (!state->importing) {
|
||||||
state->importing = true;
|
state->importing = true;
|
||||||
ImportInvite(weak, slug, peers, crl::guard(box, [=] {
|
ImportInvite(slug, filterId, peers, crl::guard(box, [=] {
|
||||||
ShowImportToast(weak, title, type, peers.size());
|
ShowImportToast(weak, title, type, peers.size());
|
||||||
box->closeBox();
|
box->closeBox();
|
||||||
}), crl::guard(box, [=] {
|
}), crl::guard(box, [=](QString text) {
|
||||||
|
if (const auto strong = weak.get()) {
|
||||||
|
Ui::ShowMultilineToast({
|
||||||
|
.parentOverride = Window::Show(
|
||||||
|
strong).toastParent(),
|
||||||
|
.text = { text },
|
||||||
|
});
|
||||||
|
}
|
||||||
state->importing = false;
|
state->importing = false;
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -604,6 +615,17 @@ void CheckFilterInvite(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProcessFilterUpdate(
|
||||||
|
base::weak_ptr<Window::SessionController> weak,
|
||||||
|
FilterId filterId,
|
||||||
|
std::vector<not_null<PeerData*>> missing) {
|
||||||
|
if (const auto strong = missing.empty() ? weak.get() : nullptr) {
|
||||||
|
strong->session().data().chatsFilters().moreChatsHide(filterId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ProcessFilterInvite(weak, QString(), filterId, std::move(missing), {});
|
||||||
|
}
|
||||||
|
|
||||||
void ProcessFilterRemove(
|
void ProcessFilterRemove(
|
||||||
base::weak_ptr<Window::SessionController> weak,
|
base::weak_ptr<Window::SessionController> weak,
|
||||||
const QString &title,
|
const QString &title,
|
||||||
|
|
|
@ -25,6 +25,11 @@ void CheckFilterInvite(
|
||||||
not_null<Window::SessionController*> controller,
|
not_null<Window::SessionController*> controller,
|
||||||
const QString &slug);
|
const QString &slug);
|
||||||
|
|
||||||
|
void ProcessFilterUpdate(
|
||||||
|
base::weak_ptr<Window::SessionController> weak,
|
||||||
|
FilterId filterId,
|
||||||
|
std::vector<not_null<PeerData*>> missing);
|
||||||
|
|
||||||
void ProcessFilterRemove(
|
void ProcessFilterRemove(
|
||||||
base::weak_ptr<Window::SessionController> weak,
|
base::weak_ptr<Window::SessionController> weak,
|
||||||
const QString &title,
|
const QString &title,
|
||||||
|
|
|
@ -102,13 +102,19 @@ struct Errors {
|
||||||
Unexpected("Peer type in ErrorForSharing.");
|
Unexpected("Peer type in ErrorForSharing.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShowEmptyLinkError(not_null<Window::SessionController*> window) {
|
void ShowSaveError(
|
||||||
|
not_null<Window::SessionController*> window,
|
||||||
|
QString error) {
|
||||||
Ui::ShowMultilineToast({
|
Ui::ShowMultilineToast({
|
||||||
.parentOverride = Window::Show(window).toastParent(),
|
.parentOverride = Window::Show(window).toastParent(),
|
||||||
.text = { tr::lng_filters_empty(tr::now) },
|
.text = { error },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShowEmptyLinkError(not_null<Window::SessionController*> window) {
|
||||||
|
ShowSaveError(window, tr::lng_filters_empty(tr::now));
|
||||||
|
}
|
||||||
|
|
||||||
void ChatFilterLinkBox(
|
void ChatFilterLinkBox(
|
||||||
not_null<Ui::GenericBox*> box,
|
not_null<Ui::GenericBox*> box,
|
||||||
not_null<Main::Session*> session,
|
not_null<Main::Session*> session,
|
||||||
|
@ -545,7 +551,7 @@ void LinkController::addHeader(not_null<Ui::VerticalLayout*> container) {
|
||||||
auto icon = CreateLottieIcon(
|
auto icon = CreateLottieIcon(
|
||||||
verticalLayout,
|
verticalLayout,
|
||||||
{
|
{
|
||||||
.name = u"filters"_q,
|
.name = u"cloud_filters"_q,
|
||||||
.sizeOverride = {
|
.sizeOverride = {
|
||||||
st::settingsFilterIconSize,
|
st::settingsFilterIconSize,
|
||||||
st::settingsFilterIconSize,
|
st::settingsFilterIconSize,
|
||||||
|
@ -1084,7 +1090,8 @@ void ExportFilterLink(
|
||||||
|
|
||||||
void EditLinkChats(
|
void EditLinkChats(
|
||||||
const Data::ChatFilterLink &link,
|
const Data::ChatFilterLink &link,
|
||||||
base::flat_set<not_null<PeerData*>> peers) {
|
base::flat_set<not_null<PeerData*>> peers,
|
||||||
|
Fn<void(QString)> done) {
|
||||||
Expects(!peers.empty());
|
Expects(!peers.empty());
|
||||||
Expects(link.id != 0);
|
Expects(link.id != 0);
|
||||||
Expects(!link.url.isEmpty());
|
Expects(!link.url.isEmpty());
|
||||||
|
@ -1104,9 +1111,9 @@ void EditLinkChats(
|
||||||
)).done([=](const MTPExportedChatlistInvite &result) {
|
)).done([=](const MTPExportedChatlistInvite &result) {
|
||||||
const auto &data = result.data();
|
const auto &data = result.data();
|
||||||
const auto link = session->data().chatsFilters().add(id, result);
|
const auto link = session->data().chatsFilters().add(id, result);
|
||||||
//done(link);
|
done(QString());
|
||||||
}).fail([=](const MTP::Error &error) {
|
}).fail([=](const MTP::Error &error) {
|
||||||
//done({ .id = id });
|
done(error.type());
|
||||||
}).send();
|
}).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1122,6 +1129,7 @@ object_ptr<Ui::BoxContent> ShowLinkBox(
|
||||||
? rpl::single(link.title)
|
? rpl::single(link.title)
|
||||||
: tr::lng_filters_link_title());
|
: tr::lng_filters_link_title());
|
||||||
|
|
||||||
|
const auto saving = std::make_shared<bool>(false);
|
||||||
raw->hasChangesValue(
|
raw->hasChangesValue(
|
||||||
) | rpl::start_with_next([=](bool has) {
|
) | rpl::start_with_next([=](bool has) {
|
||||||
box->setCloseByOutsideClick(!has);
|
box->setCloseByOutsideClick(!has);
|
||||||
|
@ -1129,11 +1137,23 @@ object_ptr<Ui::BoxContent> ShowLinkBox(
|
||||||
box->clearButtons();
|
box->clearButtons();
|
||||||
if (has) {
|
if (has) {
|
||||||
box->addButton(tr::lng_settings_save(), [=] {
|
box->addButton(tr::lng_settings_save(), [=] {
|
||||||
|
if (*saving) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto chosen = raw->selected();
|
const auto chosen = raw->selected();
|
||||||
if (chosen.empty()) {
|
if (chosen.empty()) {
|
||||||
ShowEmptyLinkError(window);
|
ShowEmptyLinkError(window);
|
||||||
} else {
|
} else {
|
||||||
EditLinkChats(link, chosen);
|
*saving = true;
|
||||||
|
EditLinkChats(link, chosen, crl::guard(box, [=](
|
||||||
|
QString error) {
|
||||||
|
*saving = false;
|
||||||
|
if (error.isEmpty()) {
|
||||||
|
box->closeBox();
|
||||||
|
} else {
|
||||||
|
ShowSaveError(window, error);
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
|
||||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_unread_things.h"
|
#include "history/history_unread_things.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
|
#include "ui/chat/more_chats_bar.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_account.h"
|
#include "main/main_account.h"
|
||||||
#include "main/main_app_config.h"
|
#include "main/main_app_config.h"
|
||||||
|
@ -31,6 +32,12 @@ constexpr auto kRefreshSuggestedTimeout = 7200 * crl::time(1000);
|
||||||
constexpr auto kLoadExceptionsAfter = 100;
|
constexpr auto kLoadExceptionsAfter = 100;
|
||||||
constexpr auto kLoadExceptionsPerRequest = 100;
|
constexpr auto kLoadExceptionsPerRequest = 100;
|
||||||
|
|
||||||
|
[[nodiscard]] crl::time RequestUpdatesEach(not_null<Session*> owner) {
|
||||||
|
const auto appConfig = &owner->session().account().appConfig();
|
||||||
|
return appConfig->get<int>(u"chatlist_update_period"_q, 3600)
|
||||||
|
* crl::time(1000);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
ChatFilter::ChatFilter(
|
ChatFilter::ChatFilter(
|
||||||
|
@ -287,7 +294,9 @@ bool ChatFilter::contains(not_null<History*> history) const {
|
||||||
|| _always.contains(history);
|
|| _always.contains(history);
|
||||||
}
|
}
|
||||||
|
|
||||||
ChatFilters::ChatFilters(not_null<Session*> owner) : _owner(owner) {
|
ChatFilters::ChatFilters(not_null<Session*> owner)
|
||||||
|
: _owner(owner)
|
||||||
|
, _moreChatsTimer([=] { checkLoadMoreChatsLists(); }) {
|
||||||
_list.emplace_back();
|
_list.emplace_back();
|
||||||
crl::on_main(&owner->session(), [=] { load(); });
|
crl::on_main(&owner->session(), [=] { load(); });
|
||||||
}
|
}
|
||||||
|
@ -855,4 +864,119 @@ rpl::producer<> ChatFilters::suggestedUpdated() const {
|
||||||
return _suggestedUpdated.events();
|
return _suggestedUpdated.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<Ui::MoreChatsBarContent> ChatFilters::moreChatsContent(
|
||||||
|
FilterId id) {
|
||||||
|
if (!id) {
|
||||||
|
return rpl::single(Ui::MoreChatsBarContent{ .count = 0 });
|
||||||
|
}
|
||||||
|
return [=](auto consumer) {
|
||||||
|
auto result = rpl::lifetime();
|
||||||
|
|
||||||
|
auto &entry = _moreChatsData[id];
|
||||||
|
auto watching = entry.watching.lock();
|
||||||
|
if (!watching) {
|
||||||
|
watching = std::make_shared<bool>(true);
|
||||||
|
entry.watching = watching;
|
||||||
|
}
|
||||||
|
result.add([watching] {});
|
||||||
|
|
||||||
|
_moreChatsUpdated.events_starting_with_copy(
|
||||||
|
id
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
consumer.put_next(Ui::MoreChatsBarContent{
|
||||||
|
.count = int(moreChats(id).size()),
|
||||||
|
});
|
||||||
|
}, result);
|
||||||
|
loadMoreChatsList(id);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<not_null<PeerData*>> &ChatFilters::moreChats(
|
||||||
|
FilterId id) const {
|
||||||
|
static const auto kEmpty = std::vector<not_null<PeerData*>>();
|
||||||
|
if (!id) {
|
||||||
|
return kEmpty;
|
||||||
|
}
|
||||||
|
const auto i = _moreChatsData.find(id);
|
||||||
|
return (i != end(_moreChatsData)) ? i->second.missing : kEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFilters::moreChatsHide(FilterId id, bool localOnly) {
|
||||||
|
if (!localOnly) {
|
||||||
|
const auto api = &_owner->session().api();
|
||||||
|
api->request(MTPchatlists_HideChatlistUpdates(
|
||||||
|
MTP_inputChatlistDialogFilter(MTP_int(id))
|
||||||
|
)).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto i = _moreChatsData.find(id);
|
||||||
|
if (i != end(_moreChatsData)) {
|
||||||
|
if (const auto requestId = base::take(i->second.requestId)) {
|
||||||
|
_owner->session().api().request(requestId).cancel();
|
||||||
|
}
|
||||||
|
i->second.missing = {};
|
||||||
|
i->second.lastUpdate = crl::now();
|
||||||
|
_moreChatsUpdated.fire_copy(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFilters::loadMoreChatsList(FilterId id) {
|
||||||
|
Expects(id != 0);
|
||||||
|
|
||||||
|
const auto i = ranges::find(_list, id, &ChatFilter::id);
|
||||||
|
if (i == end(_list) || !i->chatlist()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &entry = _moreChatsData[id];
|
||||||
|
const auto now = crl::now();
|
||||||
|
if (!entry.watching.lock() || entry.requestId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto last = entry.lastUpdate;
|
||||||
|
const auto next = last ? (last + RequestUpdatesEach(_owner)) : 0;
|
||||||
|
if (next > now) {
|
||||||
|
if (!_moreChatsTimer.isActive()) {
|
||||||
|
_moreChatsTimer.callOnce(next - now);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &api = _owner->session().api();
|
||||||
|
entry.requestId = api.request(MTPchatlists_GetChatlistUpdates(
|
||||||
|
MTP_inputChatlistDialogFilter(MTP_int(id))
|
||||||
|
)).done([=](const MTPchatlists_ChatlistUpdates &result) {
|
||||||
|
const auto &data = result.data();
|
||||||
|
_owner->processUsers(data.vusers());
|
||||||
|
_owner->processChats(data.vchats());
|
||||||
|
auto list = ranges::views::all(
|
||||||
|
data.vmissing_peers().v
|
||||||
|
) | ranges::views::transform([&](const MTPPeer &peer) {
|
||||||
|
return _owner->peer(peerFromMTP(peer));
|
||||||
|
}) | ranges::to_vector;
|
||||||
|
|
||||||
|
auto &entry = _moreChatsData[id];
|
||||||
|
entry.requestId = 0;
|
||||||
|
entry.lastUpdate = crl::now();
|
||||||
|
if (!_moreChatsTimer.isActive()) {
|
||||||
|
_moreChatsTimer.callOnce(RequestUpdatesEach(_owner));
|
||||||
|
}
|
||||||
|
if (entry.missing != list) {
|
||||||
|
entry.missing = std::move(list);
|
||||||
|
_moreChatsUpdated.fire_copy(id);
|
||||||
|
}
|
||||||
|
}).fail([=] {
|
||||||
|
auto &entry = _moreChatsData[id];
|
||||||
|
entry.requestId = 0;
|
||||||
|
entry.lastUpdate = crl::now();
|
||||||
|
}).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatFilters::checkLoadMoreChatsLists() {
|
||||||
|
for (const auto &[id, entry] : _moreChatsData) {
|
||||||
|
loadMoreChatsList(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "base/flags.h"
|
#include "base/flags.h"
|
||||||
|
#include "base/timer.h"
|
||||||
|
|
||||||
class History;
|
class History;
|
||||||
|
|
||||||
|
@ -16,6 +17,10 @@ class MainList;
|
||||||
class Key;
|
class Key;
|
||||||
} // namespace Dialogs
|
} // namespace Dialogs
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
struct MoreChatsBarContent;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
class Session;
|
class Session;
|
||||||
|
@ -159,7 +164,20 @@ public:
|
||||||
FilterId id) const;
|
FilterId id) const;
|
||||||
void reloadChatlistLinks(FilterId id);
|
void reloadChatlistLinks(FilterId id);
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::producer<Ui::MoreChatsBarContent> moreChatsContent(
|
||||||
|
FilterId id);
|
||||||
|
[[nodiscard]] const std::vector<not_null<PeerData*>> &moreChats(
|
||||||
|
FilterId id) const;
|
||||||
|
void moreChatsHide(FilterId id, bool localOnly = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct MoreChatsData {
|
||||||
|
std::vector<not_null<PeerData*>> missing;
|
||||||
|
crl::time lastUpdate = 0;
|
||||||
|
mtpRequestId requestId = 0;
|
||||||
|
std::weak_ptr<bool> watching;
|
||||||
|
};
|
||||||
|
|
||||||
void load(bool force);
|
void load(bool force);
|
||||||
void received(const QVector<MTPDialogFilter> &list);
|
void received(const QVector<MTPDialogFilter> &list);
|
||||||
bool applyOrder(const QVector<MTPint> &order);
|
bool applyOrder(const QVector<MTPint> &order);
|
||||||
|
@ -167,6 +185,9 @@ private:
|
||||||
void applyInsert(ChatFilter filter, int position);
|
void applyInsert(ChatFilter filter, int position);
|
||||||
void applyRemove(int position);
|
void applyRemove(int position);
|
||||||
|
|
||||||
|
void checkLoadMoreChatsLists();
|
||||||
|
void loadMoreChatsList(FilterId id);
|
||||||
|
|
||||||
const not_null<Session*> _owner;
|
const not_null<Session*> _owner;
|
||||||
|
|
||||||
std::vector<ChatFilter> _list;
|
std::vector<ChatFilter> _list;
|
||||||
|
@ -190,6 +211,10 @@ private:
|
||||||
rpl::event_stream<FilterId> _chatlistLinksUpdated;
|
rpl::event_stream<FilterId> _chatlistLinksUpdated;
|
||||||
mtpRequestId _linksRequestId = 0;
|
mtpRequestId _linksRequestId = 0;
|
||||||
|
|
||||||
|
base::flat_map<FilterId, MoreChatsData> _moreChatsData;
|
||||||
|
rpl::event_stream<FilterId> _moreChatsUpdated;
|
||||||
|
base::Timer _moreChatsTimer;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -24,6 +24,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/radial_animation.h"
|
#include "ui/effects/radial_animation.h"
|
||||||
#include "ui/chat/requests_bar.h"
|
#include "ui/chat/requests_bar.h"
|
||||||
#include "ui/chat/group_call_bar.h"
|
#include "ui/chat/group_call_bar.h"
|
||||||
|
#include "ui/chat/more_chats_bar.h"
|
||||||
#include "ui/controls/download_bar.h"
|
#include "ui/controls/download_bar.h"
|
||||||
#include "ui/controls/jump_down_button.h"
|
#include "ui/controls/jump_down_button.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
@ -34,6 +35,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "main/main_domain.h"
|
#include "main/main_domain.h"
|
||||||
#include "main/main_session.h"
|
#include "main/main_session.h"
|
||||||
#include "main/main_session_settings.h"
|
#include "main/main_session_settings.h"
|
||||||
|
#include "api/api_chat_filters.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "base/event_filter.h"
|
#include "base/event_filter.h"
|
||||||
#include "core/application.h"
|
#include "core/application.h"
|
||||||
|
@ -440,6 +442,7 @@ Widget::Widget(
|
||||||
_searchForNarrowFilters->setRippleColorOverride(color);
|
_searchForNarrowFilters->setRippleColorOverride(color);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
setupMoreChatsBar();
|
||||||
setupDownloadBar();
|
setupDownloadBar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -542,6 +545,49 @@ void Widget::setupScrollUpButton() {
|
||||||
updateScrollUpVisibility();
|
updateScrollUpVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Widget::setupMoreChatsBar() {
|
||||||
|
if (_layout == Layout::Child) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
controller()->activeChatsFilter(
|
||||||
|
) | rpl::start_with_next([=](FilterId id) {
|
||||||
|
if (!id) {
|
||||||
|
_moreChatsBar = nullptr;
|
||||||
|
updateControlsGeometry();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto filters = &session().data().chatsFilters();
|
||||||
|
_moreChatsBar = std::make_unique<Ui::MoreChatsBar>(
|
||||||
|
this,
|
||||||
|
filters->moreChatsContent(id));
|
||||||
|
|
||||||
|
_moreChatsBar->barClicks(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
if (const auto missing = filters->moreChats(id)
|
||||||
|
; !missing.empty()) {
|
||||||
|
Api::ProcessFilterUpdate(controller(), id, missing);
|
||||||
|
}
|
||||||
|
}, _moreChatsBar->lifetime());
|
||||||
|
|
||||||
|
_moreChatsBar->closeClicks(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
Api::ProcessFilterUpdate(controller(), id, {});
|
||||||
|
}, _moreChatsBar->lifetime());
|
||||||
|
|
||||||
|
if (_showAnimation) {
|
||||||
|
_moreChatsBar->hide();
|
||||||
|
} else {
|
||||||
|
_moreChatsBar->show();
|
||||||
|
_moreChatsBar->finishAnimating();
|
||||||
|
}
|
||||||
|
|
||||||
|
_moreChatsBar->heightValue(
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
updateControlsGeometry();
|
||||||
|
}, _moreChatsBar->lifetime());
|
||||||
|
}, lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
void Widget::setupDownloadBar() {
|
void Widget::setupDownloadBar() {
|
||||||
if (_layout == Layout::Child) {
|
if (_layout == Layout::Child) {
|
||||||
return;
|
return;
|
||||||
|
@ -735,6 +781,9 @@ void Widget::updateControlsVisibility(bool fast) {
|
||||||
_updateTelegram->show();
|
_updateTelegram->show();
|
||||||
}
|
}
|
||||||
_searchControls->setVisible(!_openedFolder && !_openedForum);
|
_searchControls->setVisible(!_openedFolder && !_openedForum);
|
||||||
|
if (_moreChatsBar) {
|
||||||
|
_moreChatsBar->show();
|
||||||
|
}
|
||||||
if (_openedFolder || _openedForum) {
|
if (_openedFolder || _openedForum) {
|
||||||
_subsectionTopBar->show();
|
_subsectionTopBar->show();
|
||||||
if (_forumTopShadow) {
|
if (_forumTopShadow) {
|
||||||
|
@ -1165,6 +1214,9 @@ void Widget::startSlideAnimation(
|
||||||
if (_subsectionTopBar) {
|
if (_subsectionTopBar) {
|
||||||
_subsectionTopBar->hide();
|
_subsectionTopBar->hide();
|
||||||
}
|
}
|
||||||
|
if (_moreChatsBar) {
|
||||||
|
_moreChatsBar->hide();
|
||||||
|
}
|
||||||
if (_forumTopShadow) {
|
if (_forumTopShadow) {
|
||||||
_forumTopShadow->hide();
|
_forumTopShadow->hide();
|
||||||
}
|
}
|
||||||
|
@ -2417,7 +2469,13 @@ void Widget::updateControlsGeometry() {
|
||||||
barw,
|
barw,
|
||||||
st::lineWidth);
|
st::lineWidth);
|
||||||
}
|
}
|
||||||
const auto forumGroupCallTop = filterAreaTop + filterAreaHeight;
|
const auto moreChatsBarTop = filterAreaTop + filterAreaHeight;
|
||||||
|
if (_moreChatsBar) {
|
||||||
|
_moreChatsBar->move(0, moreChatsBarTop);
|
||||||
|
_moreChatsBar->resizeToWidth(barw);
|
||||||
|
}
|
||||||
|
const auto forumGroupCallTop = moreChatsBarTop
|
||||||
|
+ (_moreChatsBar ? _moreChatsBar->height() : 0);
|
||||||
if (_forumGroupCallBar) {
|
if (_forumGroupCallBar) {
|
||||||
_forumGroupCallBar->move(0, forumGroupCallTop);
|
_forumGroupCallBar->move(0, forumGroupCallTop);
|
||||||
_forumGroupCallBar->resizeToWidth(barw);
|
_forumGroupCallBar->resizeToWidth(barw);
|
||||||
|
|
|
@ -44,6 +44,7 @@ class PlainShadow;
|
||||||
class DownloadBar;
|
class DownloadBar;
|
||||||
class GroupCallBar;
|
class GroupCallBar;
|
||||||
class RequestsBar;
|
class RequestsBar;
|
||||||
|
class MoreChatsBar;
|
||||||
class JumpDownButton;
|
class JumpDownButton;
|
||||||
template <typename Widget>
|
template <typename Widget>
|
||||||
class FadeWrapScaled;
|
class FadeWrapScaled;
|
||||||
|
@ -158,6 +159,7 @@ private:
|
||||||
void setupSupportMode();
|
void setupSupportMode();
|
||||||
void setupConnectingWidget();
|
void setupConnectingWidget();
|
||||||
void setupMainMenuToggle();
|
void setupMainMenuToggle();
|
||||||
|
void setupMoreChatsBar();
|
||||||
void setupDownloadBar();
|
void setupDownloadBar();
|
||||||
void setupShortcuts();
|
void setupShortcuts();
|
||||||
[[nodiscard]] bool searchForPeersRequired(const QString &query) const;
|
[[nodiscard]] bool searchForPeersRequired(const QString &query) const;
|
||||||
|
@ -234,6 +236,8 @@ private:
|
||||||
object_ptr<Ui::CrossButton> _cancelSearch;
|
object_ptr<Ui::CrossButton> _cancelSearch;
|
||||||
object_ptr<Ui::IconButton> _lockUnlock;
|
object_ptr<Ui::IconButton> _lockUnlock;
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::MoreChatsBar> _moreChatsBar;
|
||||||
|
|
||||||
std::unique_ptr<Ui::PlainShadow> _forumTopShadow;
|
std::unique_ptr<Ui::PlainShadow> _forumTopShadow;
|
||||||
std::unique_ptr<Ui::GroupCallBar> _forumGroupCallBar;
|
std::unique_ptr<Ui::GroupCallBar> _forumGroupCallBar;
|
||||||
std::unique_ptr<Ui::RequestsBar> _forumRequestsBar;
|
std::unique_ptr<Ui::RequestsBar> _forumRequestsBar;
|
||||||
|
|
|
@ -1281,3 +1281,21 @@ historySendDisabled: FlatLabel(defaultFlatLabel) {
|
||||||
historySendDisabledIcon: icon {{ "emoji/premium_lock", placeholderFgActive }};
|
historySendDisabledIcon: icon {{ "emoji/premium_lock", placeholderFgActive }};
|
||||||
historySendDisabledIconSkip: 20px;
|
historySendDisabledIconSkip: 20px;
|
||||||
historySendDisabledPosition: point(0px, 0px);
|
historySendDisabledPosition: point(0px, 0px);
|
||||||
|
|
||||||
|
moreChatsBarHeight: 48px;
|
||||||
|
moreChatsBarTextPosition: point(12px, 4px);
|
||||||
|
moreChatsBarStatusPosition: point(12px, 24px);
|
||||||
|
moreChatsBarClose: IconButton(defaultIconButton) {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
|
||||||
|
icon: boxTitleCloseIcon;
|
||||||
|
iconOver: boxTitleCloseIconOver;
|
||||||
|
iconPosition: point(12px, -1px);
|
||||||
|
|
||||||
|
rippleAreaPosition: point(0px, 4px);
|
||||||
|
rippleAreaSize: 40px;
|
||||||
|
ripple: RippleAnimation(defaultRippleAnimation) {
|
||||||
|
color: windowBgOver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
223
Telegram/SourceFiles/ui/chat/more_chats_bar.cpp
Normal file
223
Telegram/SourceFiles/ui/chat/more_chats_bar.cpp
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "ui/chat/more_chats_bar.h"
|
||||||
|
|
||||||
|
#include "ui/widgets/buttons.h"
|
||||||
|
#include "ui/widgets/shadow.h"
|
||||||
|
#include "ui/text/text_options.h"
|
||||||
|
#include "ui/painter.h"
|
||||||
|
#include "lang/lang_keys.h"
|
||||||
|
#include "styles/style_chat.h"
|
||||||
|
#include "styles/style_window.h" // st::columnMinimalWidthLeft
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
MoreChatsBar::MoreChatsBar(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
rpl::producer<MoreChatsBarContent> content)
|
||||||
|
: _wrap(parent, object_ptr<RpWidget>(parent))
|
||||||
|
, _inner(_wrap.entity())
|
||||||
|
, _shadow(std::make_unique<PlainShadow>(_wrap.parentWidget()))
|
||||||
|
, _close(_inner.get(), st::moreChatsBarClose) {
|
||||||
|
_wrap.hide(anim::type::instant);
|
||||||
|
_shadow->hide();
|
||||||
|
|
||||||
|
_wrap.entity()->paintRequest(
|
||||||
|
) | rpl::start_with_next([=](QRect clip) {
|
||||||
|
QPainter(_wrap.entity()).fillRect(clip, st::historyPinnedBg);
|
||||||
|
}, lifetime());
|
||||||
|
_wrap.setAttribute(Qt::WA_OpaquePaintEvent);
|
||||||
|
|
||||||
|
auto copy = std::move(
|
||||||
|
content
|
||||||
|
) | rpl::start_spawning(_wrap.lifetime());
|
||||||
|
|
||||||
|
rpl::duplicate(
|
||||||
|
copy
|
||||||
|
) | rpl::start_with_next([=](MoreChatsBarContent &&content) {
|
||||||
|
_content = content;
|
||||||
|
if (_content.count > 0) {
|
||||||
|
_text.setText(
|
||||||
|
st::defaultMessageBar.title,
|
||||||
|
tr::lng_filters_bar_you_can(
|
||||||
|
tr::now,
|
||||||
|
lt_count,
|
||||||
|
_content.count),
|
||||||
|
Ui::NameTextOptions());
|
||||||
|
_status.setText(
|
||||||
|
st::defaultMessageBar.text,
|
||||||
|
tr::lng_filters_bar_view(
|
||||||
|
tr::now,
|
||||||
|
lt_count,
|
||||||
|
_content.count),
|
||||||
|
Ui::NameTextOptions());
|
||||||
|
}
|
||||||
|
_inner->update();
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
std::move(
|
||||||
|
copy
|
||||||
|
) | rpl::map([=](const MoreChatsBarContent &content) {
|
||||||
|
return !content.count;
|
||||||
|
}) | rpl::start_with_next_done([=](bool hidden) {
|
||||||
|
_shouldBeShown = !hidden;
|
||||||
|
if (!_forceHidden) {
|
||||||
|
_wrap.toggle(_shouldBeShown, anim::type::normal);
|
||||||
|
}
|
||||||
|
}, [=] {
|
||||||
|
_forceHidden = true;
|
||||||
|
_wrap.toggle(false, anim::type::normal);
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
setupInner();
|
||||||
|
}
|
||||||
|
|
||||||
|
MoreChatsBar::~MoreChatsBar() = default;
|
||||||
|
|
||||||
|
void MoreChatsBar::setupInner() {
|
||||||
|
_inner->resize(0, st::moreChatsBarHeight);
|
||||||
|
_inner->paintRequest(
|
||||||
|
) | rpl::start_with_next([=](QRect rect) {
|
||||||
|
auto p = Painter(_inner);
|
||||||
|
paint(p);
|
||||||
|
}, _inner->lifetime());
|
||||||
|
|
||||||
|
// Clicks.
|
||||||
|
_inner->setCursor(style::cur_pointer);
|
||||||
|
_inner->events(
|
||||||
|
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||||
|
return (event->type() == QEvent::MouseButtonPress);
|
||||||
|
}) | rpl::map([=] {
|
||||||
|
return _inner->events(
|
||||||
|
) | rpl::filter([=](not_null<QEvent*> event) {
|
||||||
|
return (event->type() == QEvent::MouseButtonRelease);
|
||||||
|
}) | rpl::take(1) | rpl::filter([=](not_null<QEvent*> event) {
|
||||||
|
return _inner->rect().contains(
|
||||||
|
static_cast<QMouseEvent*>(event.get())->pos());
|
||||||
|
});
|
||||||
|
}) | rpl::flatten_latest(
|
||||||
|
) | rpl::to_empty | rpl::start_to_stream(_barClicks, _inner->lifetime());
|
||||||
|
|
||||||
|
_wrap.geometryValue(
|
||||||
|
) | rpl::start_with_next([=](QRect rect) {
|
||||||
|
updateShadowGeometry(rect);
|
||||||
|
updateControlsGeometry(rect);
|
||||||
|
}, _inner->lifetime());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::paint(Painter &p) {
|
||||||
|
p.fillRect(_inner->rect(), st::historyComposeAreaBg);
|
||||||
|
|
||||||
|
const auto width = std::max(
|
||||||
|
_inner->width(),
|
||||||
|
st::columnMinimalWidthLeft);
|
||||||
|
const auto available = width
|
||||||
|
- st::moreChatsBarTextPosition.x()
|
||||||
|
- st::moreChatsBarClose.width;
|
||||||
|
|
||||||
|
p.setPen(st::defaultMessageBar.titleFg);
|
||||||
|
_text.drawElided(
|
||||||
|
p,
|
||||||
|
st::moreChatsBarTextPosition.x(),
|
||||||
|
st::moreChatsBarTextPosition.y(),
|
||||||
|
available);
|
||||||
|
|
||||||
|
p.setPen(st::defaultMessageBar.textFg);
|
||||||
|
_status.drawElided(
|
||||||
|
p,
|
||||||
|
st::moreChatsBarStatusPosition.x(),
|
||||||
|
st::moreChatsBarStatusPosition.y(),
|
||||||
|
available);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::updateControlsGeometry(QRect wrapGeometry) {
|
||||||
|
const auto hidden = _wrap.isHidden() || !wrapGeometry.height();
|
||||||
|
if (_shadow->isHidden() != hidden) {
|
||||||
|
_shadow->setVisible(!hidden);
|
||||||
|
}
|
||||||
|
const auto width = std::max(
|
||||||
|
wrapGeometry.width(),
|
||||||
|
st::columnMinimalWidthLeft);
|
||||||
|
_close->move(width - _close->width(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::setShadowGeometryPostprocess(Fn<QRect(QRect)> postprocess) {
|
||||||
|
_shadowGeometryPostprocess = std::move(postprocess);
|
||||||
|
updateShadowGeometry(_wrap.geometry());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::updateShadowGeometry(QRect wrapGeometry) {
|
||||||
|
const auto regular = QRect(
|
||||||
|
wrapGeometry.x(),
|
||||||
|
wrapGeometry.y() + wrapGeometry.height(),
|
||||||
|
wrapGeometry.width(),
|
||||||
|
st::lineWidth);
|
||||||
|
_shadow->setGeometry(_shadowGeometryPostprocess
|
||||||
|
? _shadowGeometryPostprocess(regular)
|
||||||
|
: regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::show() {
|
||||||
|
if (!_forceHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_forceHidden = false;
|
||||||
|
if (_shouldBeShown) {
|
||||||
|
_wrap.show(anim::type::instant);
|
||||||
|
_shadow->show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::hide() {
|
||||||
|
if (_forceHidden) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_forceHidden = true;
|
||||||
|
_wrap.hide(anim::type::instant);
|
||||||
|
_shadow->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::raise() {
|
||||||
|
_wrap.raise();
|
||||||
|
_shadow->raise();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::finishAnimating() {
|
||||||
|
_wrap.finishAnimating();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::move(int x, int y) {
|
||||||
|
_wrap.move(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MoreChatsBar::resizeToWidth(int width) {
|
||||||
|
_wrap.entity()->resizeToWidth(width);
|
||||||
|
_inner->resizeToWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
int MoreChatsBar::height() const {
|
||||||
|
return !_forceHidden
|
||||||
|
? _wrap.height()
|
||||||
|
: _shouldBeShown
|
||||||
|
? st::moreChatsBarHeight
|
||||||
|
: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<int> MoreChatsBar::heightValue() const {
|
||||||
|
return _wrap.heightValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> MoreChatsBar::barClicks() const {
|
||||||
|
return _barClicks.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<> MoreChatsBar::closeClicks() const {
|
||||||
|
return _close->clicks() | rpl::to_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Ui
|
73
Telegram/SourceFiles/ui/chat/more_chats_bar.h
Normal file
73
Telegram/SourceFiles/ui/chat/more_chats_bar.h
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/wrap/slide_wrap.h"
|
||||||
|
#include "ui/effects/animations.h"
|
||||||
|
#include "ui/text/text.h"
|
||||||
|
#include "base/object_ptr.h"
|
||||||
|
#include "base/timer.h"
|
||||||
|
|
||||||
|
class Painter;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
|
||||||
|
class PlainShadow;
|
||||||
|
class IconButton;
|
||||||
|
|
||||||
|
struct MoreChatsBarContent {
|
||||||
|
int count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MoreChatsBar final {
|
||||||
|
public:
|
||||||
|
MoreChatsBar(
|
||||||
|
not_null<QWidget*> parent,
|
||||||
|
rpl::producer<MoreChatsBarContent> content);
|
||||||
|
~MoreChatsBar();
|
||||||
|
|
||||||
|
void show();
|
||||||
|
void hide();
|
||||||
|
void raise();
|
||||||
|
void finishAnimating();
|
||||||
|
|
||||||
|
void setShadowGeometryPostprocess(Fn<QRect(QRect)> postprocess);
|
||||||
|
|
||||||
|
void move(int x, int y);
|
||||||
|
void resizeToWidth(int width);
|
||||||
|
[[nodiscard]] int height() const;
|
||||||
|
[[nodiscard]] rpl::producer<int> heightValue() const;
|
||||||
|
[[nodiscard]] rpl::producer<> barClicks() const;
|
||||||
|
[[nodiscard]] rpl::producer<> closeClicks() const;
|
||||||
|
|
||||||
|
[[nodiscard]] rpl::lifetime &lifetime() {
|
||||||
|
return _wrap.lifetime();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void updateShadowGeometry(QRect wrapGeometry);
|
||||||
|
void updateControlsGeometry(QRect wrapGeometry);
|
||||||
|
void setupInner();
|
||||||
|
void paint(Painter &p);
|
||||||
|
|
||||||
|
SlideWrap<> _wrap;
|
||||||
|
not_null<RpWidget*> _inner;
|
||||||
|
std::unique_ptr<PlainShadow> _shadow;
|
||||||
|
object_ptr<IconButton> _close;
|
||||||
|
rpl::event_stream<> _barClicks;
|
||||||
|
Fn<QRect(QRect)> _shadowGeometryPostprocess;
|
||||||
|
bool _shouldBeShown = false;
|
||||||
|
bool _forceHidden = false;
|
||||||
|
|
||||||
|
MoreChatsBarContent _content;
|
||||||
|
Ui::Text::String _text;
|
||||||
|
Ui::Text::String _status;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Ui
|
|
@ -222,6 +222,8 @@ PRIVATE
|
||||||
ui/chat/message_bar.h
|
ui/chat/message_bar.h
|
||||||
ui/chat/message_bubble.cpp
|
ui/chat/message_bubble.cpp
|
||||||
ui/chat/message_bubble.h
|
ui/chat/message_bubble.h
|
||||||
|
ui/chat/more_chats_bar.cpp
|
||||||
|
ui/chat/more_chats_bar.h
|
||||||
ui/chat/pinned_bar.cpp
|
ui/chat/pinned_bar.cpp
|
||||||
ui/chat/pinned_bar.h
|
ui/chat/pinned_bar.h
|
||||||
ui/chat/requests_bar.cpp
|
ui/chat/requests_bar.cpp
|
||||||
|
|
Loading…
Add table
Reference in a new issue