mirror of
https://github.com/kotatogram/kotatogram-desktop
synced 2025-08-30 06:07:45 +00:00
Merge remote-tracking branch 'tdesktop/dev' into dev
This commit is contained in:
commit
cb69c37664
@ -9,7 +9,7 @@
|
|||||||
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
|
||||||
ProcessorArchitecture="ARCHITECTURE"
|
ProcessorArchitecture="ARCHITECTURE"
|
||||||
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
|
||||||
Version="2.0.0.0" />
|
Version="2.0.1.0" />
|
||||||
<Properties>
|
<Properties>
|
||||||
<DisplayName>Telegram Desktop</DisplayName>
|
<DisplayName>Telegram Desktop</DisplayName>
|
||||||
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>
|
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>
|
||||||
|
@ -200,7 +200,7 @@ void SendExistingPhoto(
|
|||||||
|
|
||||||
bool SendDice(Api::MessageToSend &message) {
|
bool SendDice(Api::MessageToSend &message) {
|
||||||
static const auto kDiceString = QString::fromUtf8("\xF0\x9F\x8E\xB2");
|
static const auto kDiceString = QString::fromUtf8("\xF0\x9F\x8E\xB2");
|
||||||
if (message.textWithTags.text != kDiceString) {
|
if (message.textWithTags.text.midRef(0).trimmed() != kDiceString) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto history = message.action.history;
|
const auto history = message.action.history;
|
||||||
|
@ -54,6 +54,15 @@ std::map<int, const char*> BetaLogs() {
|
|||||||
1009022,
|
1009022,
|
||||||
"\xE2\x80\xA2 Organize chats into Chat Folders "
|
"\xE2\x80\xA2 Organize chats into Chat Folders "
|
||||||
"if you have too many chats.\n"
|
"if you have too many chats.\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
2000001,
|
||||||
|
"\xE2\x80\xA2 Switch between folders using Ctrl+1, ..., Ctrl+8.\n"
|
||||||
|
|
||||||
|
"\xE2\x80\xA2 Fix crash when a pinned in folder chat "
|
||||||
|
"was added to archive.\n"
|
||||||
|
|
||||||
|
"\xE2\x80\xA2 Fix font issues in Linux version."
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -117,7 +117,7 @@ public:
|
|||||||
void fill();
|
void fill();
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
std::optional<Command> lookup(int shortcutId) const;
|
[[nodiscard]] std::vector<Command> lookup(int shortcutId) const;
|
||||||
void toggleMedia(bool toggled);
|
void toggleMedia(bool toggled);
|
||||||
void toggleSupport(bool toggled);
|
void toggleSupport(bool toggled);
|
||||||
|
|
||||||
@ -128,14 +128,14 @@ private:
|
|||||||
void writeDefaultFile();
|
void writeDefaultFile();
|
||||||
bool readCustomFile();
|
bool readCustomFile();
|
||||||
|
|
||||||
void set(const QString &keys, Command command);
|
void set(const QString &keys, Command command, bool replace = false);
|
||||||
void remove(const QString &keys);
|
void remove(const QString &keys);
|
||||||
void unregister(base::unique_qptr<QShortcut> shortcut);
|
void unregister(base::unique_qptr<QShortcut> shortcut);
|
||||||
|
|
||||||
QStringList _errors;
|
QStringList _errors;
|
||||||
|
|
||||||
base::flat_map<QKeySequence, base::unique_qptr<QShortcut>> _shortcuts;
|
base::flat_map<QKeySequence, base::unique_qptr<QShortcut>> _shortcuts;
|
||||||
base::flat_map<int, Command> _commandByShortcutId;
|
base::flat_multi_map<int, Command> _commandByShortcutId;
|
||||||
|
|
||||||
base::flat_set<QShortcut*> _mediaShortcuts;
|
base::flat_set<QShortcut*> _mediaShortcuts;
|
||||||
base::flat_set<QShortcut*> _supportShortcuts;
|
base::flat_set<QShortcut*> _supportShortcuts;
|
||||||
@ -210,11 +210,14 @@ const QStringList &Manager::errors() const {
|
|||||||
return _errors;
|
return _errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<Command> Manager::lookup(int shortcutId) const {
|
std::vector<Command> Manager::lookup(int shortcutId) const {
|
||||||
const auto i = _commandByShortcutId.find(shortcutId);
|
auto result = std::vector<Command>();
|
||||||
return (i != end(_commandByShortcutId))
|
auto i = _commandByShortcutId.findFirst(shortcutId);
|
||||||
? base::make_optional(i->second)
|
const auto end = _commandByShortcutId.end();
|
||||||
: std::nullopt;
|
for (; i != end && (i->first == shortcutId); ++i) {
|
||||||
|
result.push_back(i->second);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::toggleMedia(bool toggled) {
|
void Manager::toggleMedia(bool toggled) {
|
||||||
@ -282,7 +285,7 @@ bool Manager::readCustomFile() {
|
|||||||
const auto name = (*command).toString();
|
const auto name = (*command).toString();
|
||||||
const auto i = CommandByName.find(name);
|
const auto i = CommandByName.find(name);
|
||||||
if (i != end(CommandByName)) {
|
if (i != end(CommandByName)) {
|
||||||
set((*keys).toString(), i->second);
|
set((*keys).toString(), i->second, true);
|
||||||
} else {
|
} else {
|
||||||
LOG(("Shortcut Warning: "
|
LOG(("Shortcut Warning: "
|
||||||
"could not find shortcut command handler '%1'"
|
"could not find shortcut command handler '%1'"
|
||||||
@ -347,7 +350,7 @@ void Manager::fillDefaults() {
|
|||||||
ranges::view::ints(1, ranges::unreachable));
|
ranges::view::ints(1, ranges::unreachable));
|
||||||
|
|
||||||
for (const auto [command, index] : folders) {
|
for (const auto [command, index] : folders) {
|
||||||
set(qsl("%1+shift+%2").arg(ctrl).arg(index > 9 ? 0 : index), command);
|
set(qsl("%1+%2").arg(ctrl).arg(index), command);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(qsl("%1+shift+down").arg(ctrl), Command::FolderNext);
|
set(qsl("%1+shift+down").arg(ctrl), Command::FolderNext);
|
||||||
@ -379,10 +382,12 @@ void Manager::writeDefaultFile() {
|
|||||||
shortcuts.push_back(version);
|
shortcuts.push_back(version);
|
||||||
|
|
||||||
for (const auto &[sequence, shortcut] : _shortcuts) {
|
for (const auto &[sequence, shortcut] : _shortcuts) {
|
||||||
const auto i = _commandByShortcutId.find(shortcut->id());
|
const auto shortcutId = shortcut->id();
|
||||||
if (i != end(_commandByShortcutId)) {
|
auto i = _commandByShortcutId.findFirst(shortcutId);
|
||||||
|
const auto end = _commandByShortcutId.end();
|
||||||
|
for (; i != end && i->first == shortcutId; ++i) {
|
||||||
const auto j = CommandNames.find(i->second);
|
const auto j = CommandNames.find(i->second);
|
||||||
if (j != end(CommandNames)) {
|
if (j != CommandNames.end()) {
|
||||||
QJsonObject entry;
|
QJsonObject entry;
|
||||||
entry.insert(qsl("keys"), sequence.toString().toLower());
|
entry.insert(qsl("keys"), sequence.toString().toLower());
|
||||||
entry.insert(qsl("command"), j->second);
|
entry.insert(qsl("command"), j->second);
|
||||||
@ -396,7 +401,7 @@ void Manager::writeDefaultFile() {
|
|||||||
file.write(document.toJson(QJsonDocument::Indented));
|
file.write(document.toJson(QJsonDocument::Indented));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::set(const QString &keys, Command command) {
|
void Manager::set(const QString &keys, Command command, bool replace) {
|
||||||
if (keys.isEmpty()) {
|
if (keys.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -421,22 +426,25 @@ void Manager::set(const QString &keys, Command command) {
|
|||||||
if (isMediaShortcut || isSupportShortcut) {
|
if (isMediaShortcut || isSupportShortcut) {
|
||||||
shortcut->setEnabled(false);
|
shortcut->setEnabled(false);
|
||||||
}
|
}
|
||||||
const auto id = shortcut->id();
|
auto id = shortcut->id();
|
||||||
|
auto i = _shortcuts.find(result);
|
||||||
|
if (i == end(_shortcuts)) {
|
||||||
|
i = _shortcuts.emplace(result, std::move(shortcut)).first;
|
||||||
|
} else if (replace) {
|
||||||
|
unregister(std::exchange(i->second, std::move(shortcut)));
|
||||||
|
} else {
|
||||||
|
shortcut = nullptr;
|
||||||
|
id = i->second->id();
|
||||||
|
}
|
||||||
if (!id) {
|
if (!id) {
|
||||||
_errors.push_back(qsl("Could not create shortcut '%1'!").arg(keys));
|
_errors.push_back(qsl("Could not create shortcut '%1'!").arg(keys));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto i = _shortcuts.find(result);
|
|
||||||
if (i == end(_shortcuts)) {
|
|
||||||
i = _shortcuts.emplace(result, std::move(shortcut)).first;
|
|
||||||
} else {
|
|
||||||
unregister(std::exchange(i->second, std::move(shortcut)));
|
|
||||||
}
|
|
||||||
_commandByShortcutId.emplace(id, command);
|
_commandByShortcutId.emplace(id, command);
|
||||||
if (isMediaShortcut) {
|
if (shortcut && isMediaShortcut) {
|
||||||
_mediaShortcuts.emplace(i->second.get());
|
_mediaShortcuts.emplace(i->second.get());
|
||||||
}
|
}
|
||||||
if (isSupportShortcut) {
|
if (shortcut && isSupportShortcut) {
|
||||||
_supportShortcuts.emplace(i->second.get());
|
_supportShortcuts.emplace(i->second.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -471,11 +479,13 @@ Manager Data;
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Request::Request(Command command) : _command(command) {
|
Request::Request(std::vector<Command> commands)
|
||||||
|
: _commands(std::move(commands)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Request::check(Command command, int priority) {
|
bool Request::check(Command command, int priority) {
|
||||||
if (_command == command && priority > _handlerPriority) {
|
if (ranges::contains(_commands, command)
|
||||||
|
&& priority > _handlerPriority) {
|
||||||
_handlerPriority = priority;
|
_handlerPriority = priority;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -487,12 +497,16 @@ bool Request::handle(FnMut<bool()> handler) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FnMut<bool()> RequestHandler(Command command) {
|
FnMut<bool()> RequestHandler(std::vector<Command> commands) {
|
||||||
auto request = Request(command);
|
auto request = Request(std::move(commands));
|
||||||
RequestsStream.fire(&request);
|
RequestsStream.fire(&request);
|
||||||
return std::move(request._handler);
|
return std::move(request._handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FnMut<bool()> RequestHandler(Command command) {
|
||||||
|
return RequestHandler(std::vector<Command>{ command });
|
||||||
|
}
|
||||||
|
|
||||||
bool Launch(Command command) {
|
bool Launch(Command command) {
|
||||||
if (auto handler = RequestHandler(command)) {
|
if (auto handler = RequestHandler(command)) {
|
||||||
return handler();
|
return handler();
|
||||||
@ -500,6 +514,13 @@ bool Launch(Command command) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Launch(std::vector<Command> commands) {
|
||||||
|
if (auto handler = RequestHandler(std::move(commands))) {
|
||||||
|
return handler();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
rpl::producer<not_null<Request*>> Requests() {
|
rpl::producer<not_null<Request*>> Requests() {
|
||||||
return RequestsStream.events();
|
return RequestsStream.events();
|
||||||
}
|
}
|
||||||
@ -515,10 +536,7 @@ const QStringList &Errors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool HandleEvent(not_null<QShortcutEvent*> event) {
|
bool HandleEvent(not_null<QShortcutEvent*> event) {
|
||||||
if (const auto command = Data.lookup(event->shortcutId())) {
|
return Launch(Data.lookup(event->shortcutId()));
|
||||||
return Launch(*command);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToggleMediaShortcuts(bool toggled) {
|
void ToggleMediaShortcuts(bool toggled) {
|
||||||
|
@ -35,16 +35,14 @@ enum class Command {
|
|||||||
ChatPinned4,
|
ChatPinned4,
|
||||||
ChatPinned5,
|
ChatPinned5,
|
||||||
|
|
||||||
|
ShowAllChats,
|
||||||
ShowFolder1,
|
ShowFolder1,
|
||||||
ShowFolder2,
|
ShowFolder2,
|
||||||
ShowFolder3,
|
ShowFolder3,
|
||||||
ShowFolder4,
|
ShowFolder4,
|
||||||
ShowFolder5,
|
ShowFolder5,
|
||||||
ShowFolder6,
|
ShowFolder6,
|
||||||
ShowFolder7,
|
ShowFolderLast,
|
||||||
ShowFolder8,
|
|
||||||
ShowFolder9,
|
|
||||||
ShowFolder10,
|
|
||||||
|
|
||||||
FolderNext,
|
FolderNext,
|
||||||
FolderPrevious,
|
FolderPrevious,
|
||||||
@ -65,16 +63,14 @@ enum class Command {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr auto kShowFolder = {
|
constexpr auto kShowFolder = {
|
||||||
|
Command::ShowAllChats,
|
||||||
Command::ShowFolder1,
|
Command::ShowFolder1,
|
||||||
Command::ShowFolder2,
|
Command::ShowFolder2,
|
||||||
Command::ShowFolder3,
|
Command::ShowFolder3,
|
||||||
Command::ShowFolder4,
|
Command::ShowFolder4,
|
||||||
Command::ShowFolder5,
|
Command::ShowFolder5,
|
||||||
Command::ShowFolder6,
|
Command::ShowFolder6,
|
||||||
Command::ShowFolder7,
|
Command::ShowFolderLast,
|
||||||
Command::ShowFolder8,
|
|
||||||
Command::ShowFolder9,
|
|
||||||
Command::ShowFolder10,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] FnMut<bool()> RequestHandler(Command command);
|
[[nodiscard]] FnMut<bool()> RequestHandler(Command command);
|
||||||
@ -85,13 +81,13 @@ public:
|
|||||||
bool handle(FnMut<bool()> handler);
|
bool handle(FnMut<bool()> handler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit Request(Command command);
|
explicit Request(std::vector<Command> commands);
|
||||||
|
|
||||||
Command _command;
|
std::vector<Command> _commands;
|
||||||
int _handlerPriority = -1;
|
int _handlerPriority = -1;
|
||||||
FnMut<bool()> _handler;
|
FnMut<bool()> _handler;
|
||||||
|
|
||||||
friend FnMut<bool()> RequestHandler(Command command);
|
friend FnMut<bool()> RequestHandler(std::vector<Command> commands);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@ constexpr auto AppId = "{C4A4AE8F-B9F7-4CC7-8A6C-BF7EEE87ACA5}"_cs;
|
|||||||
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
constexpr auto AppNameOld = "Telegram Win (Unofficial)"_cs;
|
||||||
constexpr auto AppName = "Kotatogram Desktop"_cs;
|
constexpr auto AppName = "Kotatogram Desktop"_cs;
|
||||||
constexpr auto AppFile = "Kotatogram"_cs;
|
constexpr auto AppFile = "Kotatogram"_cs;
|
||||||
constexpr auto AppVersion = 2000000;
|
constexpr auto AppVersion = 2000001;
|
||||||
constexpr auto AppVersionStr = "2.0";
|
constexpr auto AppVersionStr = "2.0.1";
|
||||||
constexpr auto AppBetaVersion = false;
|
constexpr auto AppBetaVersion = false;
|
||||||
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
constexpr auto AppAlphaVersion = TDESKTOP_ALPHA_VERSION;
|
||||||
constexpr auto AppKotatoVersion = 1002001;
|
constexpr auto AppKotatoVersion = 1002001;
|
||||||
|
@ -87,6 +87,14 @@ dialogsTextPaletteArchiveActive: TextPalette(defaultTextPalette) {
|
|||||||
linkFg: dialogsTextFgActive;
|
linkFg: dialogsTextFgActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialogsEmptyHeight: 160px;
|
||||||
|
dialogsEmptySkip: 2px;
|
||||||
|
dialogsEmptyLabel: FlatLabel(defaultFlatLabel) {
|
||||||
|
minWidth: 32px;
|
||||||
|
align: align(top);
|
||||||
|
textFg: windowSubTextFg;
|
||||||
|
}
|
||||||
|
|
||||||
dialogsMenuToggle: IconButton {
|
dialogsMenuToggle: IconButton {
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
#include "core/shortcuts.h"
|
#include "core/shortcuts.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "ui/widgets/popup_menu.h"
|
#include "ui/widgets/popup_menu.h"
|
||||||
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/text_options.h"
|
#include "ui/text_options.h"
|
||||||
#include "ui/ui_utility.h"
|
#include "ui/ui_utility.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
@ -123,8 +124,6 @@ InnerWidget::InnerWidget(
|
|||||||
, _pinnedShiftAnimation([=](crl::time now) {
|
, _pinnedShiftAnimation([=](crl::time now) {
|
||||||
return pinnedShiftAnimationCallback(now);
|
return pinnedShiftAnimationCallback(now);
|
||||||
})
|
})
|
||||||
, _addContactLnk(this, tr::lng_add_contact_button(tr::now))
|
|
||||||
, _editFilterLnk(this, tr::lng_filters_context_edit(tr::now))
|
|
||||||
, _cancelSearchInChat(this, st::dialogsCancelSearchInPeer)
|
, _cancelSearchInChat(this, st::dialogsCancelSearchInPeer)
|
||||||
, _cancelSearchFromUser(this, st::dialogsCancelSearchInPeer) {
|
, _cancelSearchFromUser(this, st::dialogsCancelSearchInPeer) {
|
||||||
|
|
||||||
@ -132,8 +131,6 @@ InnerWidget::InnerWidget(
|
|||||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||||
#endif // OS_MAC_OLD
|
#endif // OS_MAC_OLD
|
||||||
|
|
||||||
_addContactLnk->addClickHandler([] { App::wnd()->onShowAddContact(); });
|
|
||||||
_editFilterLnk->addClickHandler([=] { editOpenedFilter(); });
|
|
||||||
_cancelSearchInChat->setClickedCallback([=] { cancelSearchInChat(); });
|
_cancelSearchInChat->setClickedCallback([=] { cancelSearchInChat(); });
|
||||||
_cancelSearchInChat->hide();
|
_cancelSearchInChat->hide();
|
||||||
_cancelSearchFromUser->setClickedCallback([=] {
|
_cancelSearchFromUser->setClickedCallback([=] {
|
||||||
@ -154,6 +151,7 @@ InnerWidget::InnerWidget(
|
|||||||
session().data().contactsLoaded().changes(
|
session().data().contactsLoaded().changes(
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
refresh();
|
refresh();
|
||||||
|
refreshEmptyLabel();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
session().data().itemRemoved(
|
session().data().itemRemoved(
|
||||||
@ -196,7 +194,9 @@ InnerWidget::InnerWidget(
|
|||||||
|
|
||||||
setupOnlineStatusCheck();
|
setupOnlineStatusCheck();
|
||||||
|
|
||||||
session().data().chatsListChanges(
|
rpl::merge(
|
||||||
|
session().data().chatsListChanges(),
|
||||||
|
session().data().chatsListLoadedEvents()
|
||||||
) | rpl::filter([=](Data::Folder *folder) {
|
) | rpl::filter([=](Data::Folder *folder) {
|
||||||
return (folder == _openedFolder);
|
return (folder == _openedFolder);
|
||||||
}) | rpl::start_with_next([=] {
|
}) | rpl::start_with_next([=] {
|
||||||
@ -511,19 +511,6 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
|
|||||||
}
|
}
|
||||||
if (!otherStart) {
|
if (!otherStart) {
|
||||||
p.fillRect(dialogsClip, st::dialogsBg);
|
p.fillRect(dialogsClip, st::dialogsBg);
|
||||||
p.setFont(st::noContactsFont);
|
|
||||||
p.setPen(st::noContactsColor);
|
|
||||||
const auto phrase = _filterId
|
|
||||||
? (session().data().chatsList()->loaded()
|
|
||||||
? tr::lng_no_chats_filter(tr::now)
|
|
||||||
: tr::lng_contacts_loading(tr::now))
|
|
||||||
: session().data().contactsLoaded().current()
|
|
||||||
? tr::lng_no_chats(tr::now)
|
|
||||||
: tr::lng_contacts_loading(tr::now);
|
|
||||||
p.drawText(
|
|
||||||
QRect(0, 0, fullWidth, st::noContactsHeight - (session().data().contactsLoaded().current() ? st::noContactsFont->height : 0)),
|
|
||||||
phrase,
|
|
||||||
style::al_center);
|
|
||||||
}
|
}
|
||||||
} else if (_state == WidgetState::Filtered) {
|
} else if (_state == WidgetState::Filtered) {
|
||||||
if (!_hashtagResults.empty()) {
|
if (!_hashtagResults.empty()) {
|
||||||
@ -1441,8 +1428,7 @@ void InnerWidget::setSearchedPressed(int pressed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::resizeEvent(QResizeEvent *e) {
|
void InnerWidget::resizeEvent(QResizeEvent *e) {
|
||||||
_addContactLnk->move((width() - _addContactLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2);
|
resizeEmptyLabel();
|
||||||
_editFilterLnk->move((width() - _editFilterLnk->width()) / 2, (st::noContactsHeight + st::noContactsFont->height) / 2);
|
|
||||||
const auto widthForCancelButton = qMax(width(), st::columnMinimalWidthLeft);
|
const auto widthForCancelButton = qMax(width(), st::columnMinimalWidthLeft);
|
||||||
const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInChat->width();
|
const auto left = widthForCancelButton - st::dialogsSearchInSkip - _cancelSearchInChat->width();
|
||||||
const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2;
|
const auto top = (st::dialogsSearchInHeight - st::dialogsCancelSearchInPeer.height) / 2;
|
||||||
@ -2231,19 +2217,12 @@ void InnerWidget::refresh(bool toTop) {
|
|||||||
if (needCollapsedRowsRefresh()) {
|
if (needCollapsedRowsRefresh()) {
|
||||||
return refreshWithCollapsedRows(toTop);
|
return refreshWithCollapsedRows(toTop);
|
||||||
}
|
}
|
||||||
|
refreshEmptyLabel();
|
||||||
const auto list = shownDialogs();
|
const auto list = shownDialogs();
|
||||||
_addContactLnk->setVisible(!_filterId
|
|
||||||
&& (_state == WidgetState::Default)
|
|
||||||
&& list->empty()
|
|
||||||
&& session().data().contactsLoaded().current());
|
|
||||||
_editFilterLnk->setVisible((_filterId > 0)
|
|
||||||
&& (_state == WidgetState::Default)
|
|
||||||
&& list->empty()
|
|
||||||
&& session().data().chatsList()->loaded());
|
|
||||||
auto h = 0;
|
auto h = 0;
|
||||||
if (_state == WidgetState::Default) {
|
if (_state == WidgetState::Default) {
|
||||||
if (list->empty()) {
|
if (list->empty()) {
|
||||||
h = st::noContactsHeight;
|
h = st::dialogsEmptyHeight;
|
||||||
} else {
|
} else {
|
||||||
h = dialogsOffset() + list->size() * DialogsRowHeight();
|
h = dialogsOffset() + list->size() * DialogsRowHeight();
|
||||||
}
|
}
|
||||||
@ -2266,6 +2245,69 @@ void InnerWidget::refresh(bool toTop) {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InnerWidget::refreshEmptyLabel() {
|
||||||
|
const auto data = &session().data();
|
||||||
|
const auto state = !shownDialogs()->empty()
|
||||||
|
? EmptyState::None
|
||||||
|
: (!_filterId && data->contactsLoaded().current())
|
||||||
|
? EmptyState::NoContacts
|
||||||
|
: (_filterId > 0) && data->chatsList()->loaded()
|
||||||
|
? EmptyState::EmptyFolder
|
||||||
|
: EmptyState::Loading;
|
||||||
|
if (state == EmptyState::None) {
|
||||||
|
_emptyState = state;
|
||||||
|
_empty.destroy();
|
||||||
|
return;
|
||||||
|
} else if (_emptyState == state) {
|
||||||
|
_empty->setVisible(_state == WidgetState::Default);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_emptyState = state;
|
||||||
|
auto phrase = (state == EmptyState::NoContacts)
|
||||||
|
? tr::lng_no_chats()
|
||||||
|
: (state == EmptyState::EmptyFolder)
|
||||||
|
? tr::lng_no_chats_filter()
|
||||||
|
: tr::lng_contacts_loading();
|
||||||
|
auto link = (state == EmptyState::NoContacts)
|
||||||
|
? tr::lng_add_contact_button()
|
||||||
|
: (state == EmptyState::EmptyFolder)
|
||||||
|
? tr::lng_filters_context_edit()
|
||||||
|
: rpl::single(QString());
|
||||||
|
auto full = rpl::combine(
|
||||||
|
std::move(phrase),
|
||||||
|
std::move(link)
|
||||||
|
) | rpl::map([](const QString &phrase, const QString &link) {
|
||||||
|
auto result = Ui::Text::WithEntities(phrase);
|
||||||
|
if (!link.isEmpty()) {
|
||||||
|
result.append("\n\n").append(Ui::Text::Link(link));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
_empty.create(this, std::move(full), st::dialogsEmptyLabel);
|
||||||
|
resizeEmptyLabel();
|
||||||
|
_empty->setClickHandlerFilter([=](const auto &...) {
|
||||||
|
if (_emptyState == EmptyState::NoContacts) {
|
||||||
|
App::wnd()->onShowAddContact();
|
||||||
|
} else if (_emptyState == EmptyState::EmptyFolder) {
|
||||||
|
editOpenedFilter();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
_empty->setVisible(_state == WidgetState::Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InnerWidget::resizeEmptyLabel() {
|
||||||
|
if (!_empty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto useWidth = std::min(
|
||||||
|
_empty->naturalWidth(),
|
||||||
|
width() - 2 * st::dialogsEmptySkip);
|
||||||
|
const auto left = (width() - useWidth) / 2;
|
||||||
|
_empty->resizeToWidth(useWidth);
|
||||||
|
_empty->move(left, (st::dialogsEmptyHeight - _empty->height()) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
void InnerWidget::clearMouseSelection(bool clearSelection) {
|
void InnerWidget::clearMouseSelection(bool clearSelection) {
|
||||||
_mouseSelection = false;
|
_mouseSelection = false;
|
||||||
_lastMousePosition = std::nullopt;
|
_lastMousePosition = std::nullopt;
|
||||||
@ -2611,6 +2653,7 @@ void InnerWidget::switchToFilter(FilterId filterId) {
|
|||||||
_filterId = filterId;
|
_filterId = filterId;
|
||||||
refreshWithCollapsedRows(true);
|
refreshWithCollapsedRows(true);
|
||||||
}
|
}
|
||||||
|
refreshEmptyLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InnerWidget::chooseHashtag() {
|
bool InnerWidget::chooseHashtag() {
|
||||||
@ -3048,6 +3091,27 @@ void InnerWidget::setupShortcuts() {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const auto filters = &session().data().chatsFilters().list();
|
||||||
|
if (const auto filtersCount = int(filters->size())) {
|
||||||
|
auto &&folders = ranges::view::zip(
|
||||||
|
Shortcuts::kShowFolder,
|
||||||
|
ranges::view::ints(0, ranges::unreachable));
|
||||||
|
|
||||||
|
for (const auto [command, index] : folders) {
|
||||||
|
const auto select = (command == Command::ShowFolderLast)
|
||||||
|
? filtersCount
|
||||||
|
: std::clamp(index, 0, filtersCount);
|
||||||
|
request->check(command) && request->handle([=] {
|
||||||
|
if (select <= filtersCount) {
|
||||||
|
_controller->setActiveChatsFilter((select > 0)
|
||||||
|
? (*filters)[select - 1].id()
|
||||||
|
: 0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const auto kPinned = {
|
static const auto kPinned = {
|
||||||
Command::ChatPinned1,
|
Command::ChatPinned1,
|
||||||
Command::ChatPinned2,
|
Command::ChatPinned2,
|
||||||
@ -3076,42 +3140,23 @@ void InnerWidget::setupShortcuts() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &&folders = ranges::view::zip(
|
|
||||||
Shortcuts::kShowFolder,
|
|
||||||
ranges::view::ints(0, ranges::unreachable));
|
|
||||||
|
|
||||||
for (const auto [command, index] : folders) {
|
|
||||||
request->check(command) && request->handle([=, index = index] {
|
|
||||||
const auto list = &session().data().chatsFilters().list();
|
|
||||||
if (index >= list->size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto filterId = list->at(index).id();
|
|
||||||
_controller->setActiveChatsFilter((filterId == _filterId)
|
|
||||||
? 0
|
|
||||||
: filterId);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto nearFolder = [=](bool isNext) {
|
const auto nearFolder = [=](bool isNext) {
|
||||||
const auto id = _controller->activeChatsFilterCurrent();
|
const auto id = _controller->activeChatsFilterCurrent();
|
||||||
const auto list = &session().data().chatsFilters().list();
|
const auto list = &session().data().chatsFilters().list();
|
||||||
const auto it = (id == 0)
|
const auto index = (id != 0)
|
||||||
? begin(*list) - 1
|
? int(ranges::find(*list, id, &Data::ChatFilter::id)
|
||||||
: ranges::find(*list, id, &Data::ChatFilter::id);
|
- begin(*list))
|
||||||
if (it == end(*list) && id != 0) {
|
: -1;
|
||||||
|
if (index == list->size() && id != 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto i = isNext ? 1 : -1;
|
const auto changed = index + (isNext ? 1 : -1);
|
||||||
const auto index = it - begin(*list) + i;
|
if (changed >= int(list->size()) || changed < -1) {
|
||||||
if (index >= (int)list->size() || index < -1) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto filterId = (index == -1)
|
_controller->setActiveChatsFilter((changed >= 0)
|
||||||
? 0
|
? (*list)[changed].id()
|
||||||
: list->at(index).id();
|
: 0);
|
||||||
_controller->setActiveChatsFilter(filterId);
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ class Session;
|
|||||||
namespace Ui {
|
namespace Ui {
|
||||||
class IconButton;
|
class IconButton;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
class LinkButton;
|
class FlatLabel;
|
||||||
} // namespace Ui
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Window {
|
namespace Window {
|
||||||
@ -97,6 +97,8 @@ public:
|
|||||||
|
|
||||||
void clearFilter();
|
void clearFilter();
|
||||||
void refresh(bool toTop = false);
|
void refresh(bool toTop = false);
|
||||||
|
void refreshEmptyLabel();
|
||||||
|
void resizeEmptyLabel();
|
||||||
|
|
||||||
bool chooseRow();
|
bool chooseRow();
|
||||||
|
|
||||||
@ -168,6 +170,13 @@ private:
|
|||||||
NextOrOriginal,
|
NextOrOriginal,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EmptyState : uchar {
|
||||||
|
None,
|
||||||
|
Loading,
|
||||||
|
NoContacts,
|
||||||
|
EmptyFolder,
|
||||||
|
};
|
||||||
|
|
||||||
Main::Session &session() const;
|
Main::Session &session() const;
|
||||||
|
|
||||||
void dialogRowReplaced(Row *oldRow, Row *newRow);
|
void dialogRowReplaced(Row *oldRow, Row *newRow);
|
||||||
@ -357,6 +366,7 @@ private:
|
|||||||
int _filteredPressed = -1;
|
int _filteredPressed = -1;
|
||||||
|
|
||||||
bool _waitingForSearch = false;
|
bool _waitingForSearch = false;
|
||||||
|
EmptyState _emptyState = EmptyState::None;
|
||||||
|
|
||||||
QString _peerSearchQuery;
|
QString _peerSearchQuery;
|
||||||
std::vector<std::unique_ptr<PeerSearchResult>> _peerSearchResults;
|
std::vector<std::unique_ptr<PeerSearchResult>> _peerSearchResults;
|
||||||
@ -376,8 +386,7 @@ private:
|
|||||||
|
|
||||||
WidgetState _state = WidgetState::Default;
|
WidgetState _state = WidgetState::Default;
|
||||||
|
|
||||||
object_ptr<Ui::LinkButton> _addContactLnk;
|
object_ptr<Ui::FlatLabel> _empty = { nullptr };
|
||||||
object_ptr<Ui::LinkButton> _editFilterLnk;
|
|
||||||
object_ptr<Ui::IconButton> _cancelSearchInChat;
|
object_ptr<Ui::IconButton> _cancelSearchInChat;
|
||||||
object_ptr<Ui::IconButton> _cancelSearchFromUser;
|
object_ptr<Ui::IconButton> _cancelSearchFromUser;
|
||||||
|
|
||||||
|
@ -1948,12 +1948,6 @@ void History::setFolderPointer(Data::Folder *folder) {
|
|||||||
const auto wasInList = inChatList();
|
const auto wasInList = inChatList();
|
||||||
if (wasInList) {
|
if (wasInList) {
|
||||||
removeFromChatList(0, owner().chatsList(this->folder()));
|
removeFromChatList(0, owner().chatsList(this->folder()));
|
||||||
for (const auto &filter : filters.list()) {
|
|
||||||
const auto id = filter.id();
|
|
||||||
if (inChatList(id)) {
|
|
||||||
removeFromChatList(id, filters.chatsList(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const auto was = _folder.value_or(nullptr);
|
const auto was = _folder.value_or(nullptr);
|
||||||
_folder = folder;
|
_folder = folder;
|
||||||
@ -1962,12 +1956,10 @@ void History::setFolderPointer(Data::Folder *folder) {
|
|||||||
}
|
}
|
||||||
if (wasInList) {
|
if (wasInList) {
|
||||||
addToChatList(0, owner().chatsList(folder));
|
addToChatList(0, owner().chatsList(folder));
|
||||||
for (const auto &filter : filters.list()) {
|
|
||||||
if (filter.contains(this)) {
|
owner().chatsFilters().refreshHistory(this);
|
||||||
const auto id = filter.id();
|
updateChatListEntry();
|
||||||
addToChatList(id, filters.chatsList(id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
owner().chatsListChanged(was);
|
owner().chatsListChanged(was);
|
||||||
owner().chatsListChanged(folder);
|
owner().chatsListChanged(folder);
|
||||||
} else if (!wasKnown) {
|
} else if (!wasKnown) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
AppVersion 2000000
|
AppVersion 2000001
|
||||||
AppVersionStrMajor 2.0
|
AppVersionStrMajor 2.0
|
||||||
AppVersionStrSmall 2.0
|
AppVersionStrSmall 2.0.1
|
||||||
AppVersionStr 2.0.0
|
AppVersionStr 2.0.1
|
||||||
BetaChannel 0
|
BetaChannel 0
|
||||||
AlphaVersion 0
|
AlphaVersion 0
|
||||||
AppVersionOriginal 2.0
|
AppVersionOriginal 2.0.1
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit d443119c7c5629cb87fd8b062941c25a6bc5abab
|
Subproject commit 4a2a5d0ff1aea9aa860c56a90558463caf82aa55
|
@ -1,3 +1,9 @@
|
|||||||
|
2.0.1 (31.03.20)
|
||||||
|
|
||||||
|
- Switch between folders using Ctrl+1, ..., Ctrl+8.
|
||||||
|
- Fix crash when a pinned in folder chat was added to archive.
|
||||||
|
- Fix font issues in Linux version.
|
||||||
|
|
||||||
2.0 (30.03.20)
|
2.0 (30.03.20)
|
||||||
|
|
||||||
- Organize chats into Chat Folders if you have too many chats.
|
- Organize chats into Chat Folders if you have too many chats.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user