mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Remove non-UI calls to App::main.
This commit is contained in:
parent
3c4e959468
commit
f450f81215
36 changed files with 768 additions and 675 deletions
|
@ -16,14 +16,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
|
#include "data/data_changes.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "history/history.h"
|
#include "history/history.h"
|
||||||
#include "history/history_message.h" // NewMessageFlags.
|
#include "history/history_message.h" // NewMessageFlags.
|
||||||
#include "chat_helpers/message_field.h" // ConvertTextTagsToEntities.
|
#include "chat_helpers/message_field.h" // ConvertTextTagsToEntities.
|
||||||
#include "ui/text/text_entity.h" // TextWithEntities.
|
#include "ui/text/text_entity.h" // TextWithEntities.
|
||||||
|
#include "ui/text_options.h" // Ui::ItemTextOptions.
|
||||||
#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"
|
||||||
|
#include "storage/localimageloader.h"
|
||||||
|
#include "storage/file_upload.h"
|
||||||
#include "mainwidget.h"
|
#include "mainwidget.h"
|
||||||
#include "apiwrap.h"
|
#include "apiwrap.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
@ -329,4 +333,203 @@ void FillMessagePostFlags(
|
||||||
InnerFillMessagePostFlags(action.options, peer, flags);
|
InnerFillMessagePostFlags(action.options, peer, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SendConfirmedFile(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const std::shared_ptr<FileLoadResult> &file,
|
||||||
|
const std::optional<FullMsgId> &oldId) {
|
||||||
|
const auto isEditing = oldId.has_value();
|
||||||
|
const auto channelId = peerToChannel(file->to.peer);
|
||||||
|
|
||||||
|
const auto newId = oldId.value_or(
|
||||||
|
FullMsgId(channelId, session->data().nextLocalMessageId()));
|
||||||
|
auto groupId = file->album ? file->album->groupId : uint64(0);
|
||||||
|
if (file->album) {
|
||||||
|
const auto proj = [](const SendingAlbum::Item &item) {
|
||||||
|
return item.taskId;
|
||||||
|
};
|
||||||
|
const auto it = ranges::find(file->album->items, file->taskId, proj);
|
||||||
|
Assert(it != file->album->items.end());
|
||||||
|
|
||||||
|
it->msgId = newId;
|
||||||
|
}
|
||||||
|
file->edit = isEditing;
|
||||||
|
session->uploader().upload(newId, file);
|
||||||
|
|
||||||
|
const auto itemToEdit = isEditing
|
||||||
|
? session->data().message(newId)
|
||||||
|
: nullptr;
|
||||||
|
|
||||||
|
const auto history = session->data().history(file->to.peer);
|
||||||
|
const auto peer = history->peer;
|
||||||
|
|
||||||
|
auto action = Api::SendAction(history);
|
||||||
|
action.options = file->to.options;
|
||||||
|
action.clearDraft = false;
|
||||||
|
action.replyTo = file->to.replyTo;
|
||||||
|
action.generateLocal = true;
|
||||||
|
session->api().sendAction(action);
|
||||||
|
|
||||||
|
auto caption = TextWithEntities{
|
||||||
|
file->caption.text,
|
||||||
|
TextUtilities::ConvertTextTagsToEntities(file->caption.tags)
|
||||||
|
};
|
||||||
|
const auto prepareFlags = Ui::ItemTextOptions(
|
||||||
|
history,
|
||||||
|
session->user()).flags;
|
||||||
|
TextUtilities::PrepareForSending(caption, prepareFlags);
|
||||||
|
TextUtilities::Trim(caption);
|
||||||
|
auto localEntities = Api::EntitiesToMTP(session, caption.entities);
|
||||||
|
|
||||||
|
if (itemToEdit) {
|
||||||
|
if (const auto id = itemToEdit->groupId()) {
|
||||||
|
groupId = id.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto flags = (isEditing ? MTPDmessage::Flags() : NewMessageFlags(peer))
|
||||||
|
| MTPDmessage::Flag::f_entities
|
||||||
|
| MTPDmessage::Flag::f_media;
|
||||||
|
auto clientFlags = NewMessageClientFlags();
|
||||||
|
if (file->to.replyTo) {
|
||||||
|
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
||||||
|
}
|
||||||
|
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
||||||
|
const auto silentPost = file->to.options.silent;
|
||||||
|
Api::FillMessagePostFlags(action, peer, flags);
|
||||||
|
if (silentPost) {
|
||||||
|
flags |= MTPDmessage::Flag::f_silent;
|
||||||
|
}
|
||||||
|
if (groupId) {
|
||||||
|
flags |= MTPDmessage::Flag::f_grouped_id;
|
||||||
|
}
|
||||||
|
if (file->to.options.scheduled) {
|
||||||
|
flags |= MTPDmessage::Flag::f_from_scheduled;
|
||||||
|
} else {
|
||||||
|
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto messageFromId = channelPost ? 0 : session->userId();
|
||||||
|
const auto messagePostAuthor = channelPost
|
||||||
|
? session->user()->name
|
||||||
|
: QString();
|
||||||
|
|
||||||
|
if (file->type == SendMediaType::Photo) {
|
||||||
|
const auto photoFlags = MTPDmessageMediaPhoto::Flag::f_photo | 0;
|
||||||
|
const auto photo = MTP_messageMediaPhoto(
|
||||||
|
MTP_flags(photoFlags),
|
||||||
|
file->photo,
|
||||||
|
MTPint());
|
||||||
|
|
||||||
|
const auto mtpMessage = MTP_message(
|
||||||
|
MTP_flags(flags),
|
||||||
|
MTP_int(newId.msg),
|
||||||
|
MTP_int(messageFromId),
|
||||||
|
peerToMTP(file->to.peer),
|
||||||
|
MTPMessageFwdHeader(),
|
||||||
|
MTPint(),
|
||||||
|
MTP_int(file->to.replyTo),
|
||||||
|
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||||
|
MTP_string(caption.text),
|
||||||
|
photo,
|
||||||
|
MTPReplyMarkup(),
|
||||||
|
localEntities,
|
||||||
|
MTP_int(1),
|
||||||
|
MTPint(),
|
||||||
|
MTP_string(messagePostAuthor),
|
||||||
|
MTP_long(groupId),
|
||||||
|
//MTPMessageReactions(),
|
||||||
|
MTPVector<MTPRestrictionReason>());
|
||||||
|
|
||||||
|
if (itemToEdit) {
|
||||||
|
itemToEdit->savePreviousMedia();
|
||||||
|
itemToEdit->applyEdition(mtpMessage.c_message());
|
||||||
|
} else {
|
||||||
|
history->addNewMessage(
|
||||||
|
mtpMessage,
|
||||||
|
clientFlags,
|
||||||
|
NewMessageType::Unread);
|
||||||
|
}
|
||||||
|
} else if (file->type == SendMediaType::File) {
|
||||||
|
const auto documentFlags = MTPDmessageMediaDocument::Flag::f_document | 0;
|
||||||
|
const auto document = MTP_messageMediaDocument(
|
||||||
|
MTP_flags(documentFlags),
|
||||||
|
file->document,
|
||||||
|
MTPint());
|
||||||
|
|
||||||
|
const auto mtpMessage = MTP_message(
|
||||||
|
MTP_flags(flags),
|
||||||
|
MTP_int(newId.msg),
|
||||||
|
MTP_int(messageFromId),
|
||||||
|
peerToMTP(file->to.peer),
|
||||||
|
MTPMessageFwdHeader(),
|
||||||
|
MTPint(),
|
||||||
|
MTP_int(file->to.replyTo),
|
||||||
|
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||||
|
MTP_string(caption.text),
|
||||||
|
document,
|
||||||
|
MTPReplyMarkup(),
|
||||||
|
localEntities,
|
||||||
|
MTP_int(1),
|
||||||
|
MTPint(),
|
||||||
|
MTP_string(messagePostAuthor),
|
||||||
|
MTP_long(groupId),
|
||||||
|
//MTPMessageReactions(),
|
||||||
|
MTPVector<MTPRestrictionReason>());
|
||||||
|
|
||||||
|
if (itemToEdit) {
|
||||||
|
itemToEdit->savePreviousMedia();
|
||||||
|
itemToEdit->applyEdition(mtpMessage.c_message());
|
||||||
|
} else {
|
||||||
|
history->addNewMessage(
|
||||||
|
mtpMessage,
|
||||||
|
clientFlags,
|
||||||
|
NewMessageType::Unread);
|
||||||
|
}
|
||||||
|
} else if (file->type == SendMediaType::Audio) {
|
||||||
|
if (!peer->isChannel() || peer->isMegagroup()) {
|
||||||
|
flags |= MTPDmessage::Flag::f_media_unread;
|
||||||
|
}
|
||||||
|
const auto documentFlags = MTPDmessageMediaDocument::Flag::f_document | 0;
|
||||||
|
const auto document = MTP_messageMediaDocument(
|
||||||
|
MTP_flags(documentFlags),
|
||||||
|
file->document,
|
||||||
|
MTPint());
|
||||||
|
history->addNewMessage(
|
||||||
|
MTP_message(
|
||||||
|
MTP_flags(flags),
|
||||||
|
MTP_int(newId.msg),
|
||||||
|
MTP_int(messageFromId),
|
||||||
|
peerToMTP(file->to.peer),
|
||||||
|
MTPMessageFwdHeader(),
|
||||||
|
MTPint(),
|
||||||
|
MTP_int(file->to.replyTo),
|
||||||
|
MTP_int(
|
||||||
|
HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
||||||
|
MTP_string(caption.text),
|
||||||
|
document,
|
||||||
|
MTPReplyMarkup(),
|
||||||
|
localEntities,
|
||||||
|
MTP_int(1),
|
||||||
|
MTPint(),
|
||||||
|
MTP_string(messagePostAuthor),
|
||||||
|
MTP_long(groupId),
|
||||||
|
//MTPMessageReactions(),
|
||||||
|
MTPVector<MTPRestrictionReason>()),
|
||||||
|
clientFlags,
|
||||||
|
NewMessageType::Unread);
|
||||||
|
// Voices can't be edited.
|
||||||
|
} else {
|
||||||
|
Unexpected("Type in sendFilesConfirmed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEditing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->data().sendHistoryChangeNotifications();
|
||||||
|
session->changes().historyUpdated(
|
||||||
|
history,
|
||||||
|
Data::HistoryUpdate::Flag::MessageSent);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
class History;
|
class History;
|
||||||
class PhotoData;
|
class PhotoData;
|
||||||
class DocumentData;
|
class DocumentData;
|
||||||
|
struct FileLoadResult;
|
||||||
|
|
||||||
namespace Api {
|
namespace Api {
|
||||||
|
|
||||||
|
@ -30,4 +31,9 @@ void FillMessagePostFlags(
|
||||||
not_null<PeerData*> peer,
|
not_null<PeerData*> peer,
|
||||||
MTPDmessage::Flags &flags);
|
MTPDmessage::Flags &flags);
|
||||||
|
|
||||||
|
void SendConfirmedFile(
|
||||||
|
not_null<Main::Session*> session,
|
||||||
|
const std::shared_ptr<FileLoadResult> &file,
|
||||||
|
const std::optional<FullMsgId> &oldId);
|
||||||
|
|
||||||
} // namespace Api
|
} // namespace Api
|
||||||
|
|
|
@ -4010,7 +4010,9 @@ void ApiWrap::finishForwarding(const SendAction &action) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_session->data().sendHistoryChangeNotifications();
|
_session->data().sendHistoryChangeNotifications();
|
||||||
_session->data().newMessageSent(history);
|
_session->changes().historyUpdated(
|
||||||
|
history,
|
||||||
|
Data::HistoryUpdate::Flag::MessageSent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::forwardMessages(
|
void ApiWrap::forwardMessages(
|
||||||
|
@ -4248,7 +4250,9 @@ void ApiWrap::sendSharedContact(
|
||||||
sendMedia(item, media, options);
|
sendMedia(item, media, options);
|
||||||
|
|
||||||
_session->data().sendHistoryChangeNotifications();
|
_session->data().sendHistoryChangeNotifications();
|
||||||
_session->data().newMessageSent(history);
|
_session->changes().historyUpdated(
|
||||||
|
history,
|
||||||
|
Data::HistoryUpdate::Flag::MessageSent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ApiWrap::sendVoiceMessage(
|
void ApiWrap::sendVoiceMessage(
|
||||||
|
@ -4259,7 +4263,7 @@ void ApiWrap::sendVoiceMessage(
|
||||||
const auto caption = TextWithTags();
|
const auto caption = TextWithTags();
|
||||||
const auto to = fileLoadTaskOptions(action);
|
const auto to = fileLoadTaskOptions(action);
|
||||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||||
instance()->mainDcId(),
|
&session(),
|
||||||
result,
|
result,
|
||||||
duration,
|
duration,
|
||||||
waveform,
|
waveform,
|
||||||
|
@ -4278,7 +4282,7 @@ void ApiWrap::editMedia(
|
||||||
auto &file = list.files.front();
|
auto &file = list.files.front();
|
||||||
const auto to = fileLoadTaskOptions(action);
|
const auto to = fileLoadTaskOptions(action);
|
||||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||||
instance()->mainDcId(),
|
&session(),
|
||||||
file.path,
|
file.path,
|
||||||
file.content,
|
file.content,
|
||||||
std::move(file.information),
|
std::move(file.information),
|
||||||
|
@ -4326,7 +4330,7 @@ void ApiWrap::sendFiles(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tasks.push_back(std::make_unique<FileLoadTask>(
|
tasks.push_back(std::make_unique<FileLoadTask>(
|
||||||
instance()->mainDcId(),
|
&session(),
|
||||||
file.path,
|
file.path,
|
||||||
file.content,
|
file.content,
|
||||||
std::move(file.information),
|
std::move(file.information),
|
||||||
|
@ -4353,7 +4357,7 @@ void ApiWrap::sendFile(
|
||||||
const auto to = fileLoadTaskOptions(action);
|
const auto to = fileLoadTaskOptions(action);
|
||||||
auto caption = TextWithTags();
|
auto caption = TextWithTags();
|
||||||
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
_fileLoader->addTask(std::make_unique<FileLoadTask>(
|
||||||
instance()->mainDcId(),
|
&session(),
|
||||||
QString(),
|
QString(),
|
||||||
fileContent,
|
fileContent,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|
|
@ -296,7 +296,7 @@ auto AddButtonWithLoader(
|
||||||
if (toggled && (state.is<Available>() || state.is<Failed>())) {
|
if (toggled && (state.is<Available>() || state.is<Failed>())) {
|
||||||
const auto weak = Ui::MakeWeak(button);
|
const auto weak = Ui::MakeWeak(button);
|
||||||
setLocalLoader(base::make_unique_q<Loader>(
|
setLocalLoader(base::make_unique_q<Loader>(
|
||||||
controller->content(),
|
QCoreApplication::instance(),
|
||||||
&controller->session(),
|
&controller->session(),
|
||||||
id,
|
id,
|
||||||
Spellchecker::GetDownloadLocation(id),
|
Spellchecker::GetDownloadLocation(id),
|
||||||
|
|
|
@ -162,7 +162,7 @@ void DownloadDictionaryInBackground(
|
||||||
|
|
||||||
auto sharedLoader = std::make_shared<base::unique_qptr<DictLoader>>();
|
auto sharedLoader = std::make_shared<base::unique_qptr<DictLoader>>();
|
||||||
*sharedLoader = base::make_unique_q<DictLoader>(
|
*sharedLoader = base::make_unique_q<DictLoader>(
|
||||||
App::main(),
|
QCoreApplication::instance(),
|
||||||
session,
|
session,
|
||||||
id,
|
id,
|
||||||
GetDownloadLocation(id),
|
GetDownloadLocation(id),
|
||||||
|
|
|
@ -102,7 +102,7 @@ void DicePack::tryGenerateLocalZero() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto task = FileLoadTask(
|
auto task = FileLoadTask(
|
||||||
_session->mainDcId(),
|
_session,
|
||||||
path,
|
path,
|
||||||
QByteArray(),
|
QByteArray(),
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|
|
@ -340,8 +340,8 @@ void Application::showTheme(
|
||||||
PeerData *Application::ui_getPeerForMouseAction() {
|
PeerData *Application::ui_getPeerForMouseAction() {
|
||||||
if (_mediaView && !_mediaView->isHidden()) {
|
if (_mediaView && !_mediaView->isHidden()) {
|
||||||
return _mediaView->ui_getPeerForMouseAction();
|
return _mediaView->ui_getPeerForMouseAction();
|
||||||
} else if (auto main = App::main()) {
|
} else if (const auto m = App::main()) { // multi good
|
||||||
return main->ui_getPeerForMouseAction();
|
return m->ui_getPeerForMouseAction();
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,7 +111,9 @@ QString MentionClickHandler::copyToClipboardContextItemText() const {
|
||||||
void MentionClickHandler::onClick(ClickContext context) const {
|
void MentionClickHandler::onClick(ClickContext context) const {
|
||||||
const auto button = context.button;
|
const auto button = context.button;
|
||||||
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
|
if (button == Qt::LeftButton || button == Qt::MiddleButton) {
|
||||||
App::main()->openPeerByName(_tag.mid(1), ShowAtProfileMsgId);
|
if (const auto m = App::main()) { // multi good
|
||||||
|
m->openPeerByName(_tag.mid(1), ShowAtProfileMsgId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,9 +133,11 @@ bool ShareUrl(
|
||||||
auto url = params.value(qsl("url"));
|
auto url = params.value(qsl("url"));
|
||||||
if (url.isEmpty()) {
|
if (url.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
|
} else if (const auto controller = App::wnd()->sessionController()) {
|
||||||
|
controller->content()->shareUrlLayer(url, params.value("text"));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
App::main()->shareUrlLayer(url, params.value("text"));
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConfirmPhone(
|
bool ConfirmPhone(
|
||||||
|
@ -291,12 +293,15 @@ bool ResolveUsername(
|
||||||
post = ShowAtGameShareMsgId;
|
post = ShowAtGameShareMsgId;
|
||||||
}
|
}
|
||||||
const auto clickFromMessageId = context.value<FullMsgId>();
|
const auto clickFromMessageId = context.value<FullMsgId>();
|
||||||
App::main()->openPeerByName(
|
if (const auto controller = App::wnd()->sessionController()) {
|
||||||
domain,
|
controller->content()->openPeerByName(
|
||||||
post,
|
domain,
|
||||||
startToken,
|
post,
|
||||||
clickFromMessageId);
|
startToken,
|
||||||
return true;
|
clickFromMessageId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResolvePrivatePost(
|
bool ResolvePrivatePost(
|
||||||
|
|
|
@ -14,8 +14,19 @@ namespace Data {
|
||||||
template <typename DataType, typename UpdateType>
|
template <typename DataType, typename UpdateType>
|
||||||
void Changes::Manager<DataType, UpdateType>::updated(
|
void Changes::Manager<DataType, UpdateType>::updated(
|
||||||
not_null<DataType*> data,
|
not_null<DataType*> data,
|
||||||
Flags flags) {
|
Flags flags,
|
||||||
|
bool dropScheduled) {
|
||||||
sendRealtimeNotifications(data, flags);
|
sendRealtimeNotifications(data, flags);
|
||||||
|
if (dropScheduled) {
|
||||||
|
const auto i = _updates.find(data);
|
||||||
|
if (i != _updates.end()) {
|
||||||
|
flags |= i->second;
|
||||||
|
_updates.erase(i);
|
||||||
|
}
|
||||||
|
_stream.fire({ data, flags });
|
||||||
|
} else {
|
||||||
|
_updates[data] |= flags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename DataType, typename UpdateType>
|
template <typename DataType, typename UpdateType>
|
||||||
|
@ -148,6 +159,72 @@ rpl::producer<HistoryUpdate> Changes::historyFlagsValue(
|
||||||
return _historyChanges.flagsValue(history, flags);
|
return _historyChanges.flagsValue(history, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<HistoryUpdate> Changes::realtimeHistoryUpdates(
|
||||||
|
HistoryUpdate::Flag flag) const {
|
||||||
|
return _historyChanges.realtimeUpdates(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Changes::messageUpdated(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
MessageUpdate::Flags flags) {
|
||||||
|
const auto drop = (flags & MessageUpdate::Flag::Destroyed);
|
||||||
|
_messageChanges.updated(item, flags, drop);
|
||||||
|
if (!drop) {
|
||||||
|
scheduleNotifications();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<MessageUpdate> Changes::messageUpdates(
|
||||||
|
MessageUpdate::Flags flags) const {
|
||||||
|
return _messageChanges.updates(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<MessageUpdate> Changes::messageUpdates(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
MessageUpdate::Flags flags) const {
|
||||||
|
return _messageChanges.updates(item, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<MessageUpdate> Changes::messageFlagsValue(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
MessageUpdate::Flags flags) const {
|
||||||
|
return _messageChanges.flagsValue(item, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<MessageUpdate> Changes::realtimeMessageUpdates(
|
||||||
|
MessageUpdate::Flag flag) const {
|
||||||
|
return _messageChanges.realtimeUpdates(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Changes::entryUpdated(
|
||||||
|
not_null<Dialogs::Entry*> entry,
|
||||||
|
EntryUpdate::Flags flags) {
|
||||||
|
_entryChanges.updated(entry, flags);
|
||||||
|
scheduleNotifications();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<EntryUpdate> Changes::entryUpdates(
|
||||||
|
EntryUpdate::Flags flags) const {
|
||||||
|
return _entryChanges.updates(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<EntryUpdate> Changes::entryUpdates(
|
||||||
|
not_null<Dialogs::Entry*> entry,
|
||||||
|
EntryUpdate::Flags flags) const {
|
||||||
|
return _entryChanges.updates(entry, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<EntryUpdate> Changes::entryFlagsValue(
|
||||||
|
not_null<Dialogs::Entry*> entry,
|
||||||
|
EntryUpdate::Flags flags) const {
|
||||||
|
return _entryChanges.flagsValue(entry, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
rpl::producer<EntryUpdate> Changes::realtimeEntryUpdates(
|
||||||
|
EntryUpdate::Flag flag) const {
|
||||||
|
return _entryChanges.realtimeUpdates(flag);
|
||||||
|
}
|
||||||
|
|
||||||
void Changes::scheduleNotifications() {
|
void Changes::scheduleNotifications() {
|
||||||
if (!_notify) {
|
if (!_notify) {
|
||||||
_notify = true;
|
_notify = true;
|
||||||
|
@ -164,6 +241,8 @@ void Changes::sendNotifications() {
|
||||||
_notify = false;
|
_notify = false;
|
||||||
_peerChanges.sendNotifications();
|
_peerChanges.sendNotifications();
|
||||||
_historyChanges.sendNotifications();
|
_historyChanges.sendNotifications();
|
||||||
|
_messageChanges.sendNotifications();
|
||||||
|
_entryChanges.sendNotifications();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|
|
@ -11,6 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
class History;
|
class History;
|
||||||
class PeerData;
|
class PeerData;
|
||||||
|
class HistoryItem;
|
||||||
|
|
||||||
|
namespace Dialogs {
|
||||||
|
class Entry;
|
||||||
|
} // namespace Dialogs
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
|
|
||||||
|
@ -89,8 +94,13 @@ struct HistoryUpdate {
|
||||||
UnreadMentions = (1 << 4),
|
UnreadMentions = (1 << 4),
|
||||||
LocalMessages = (1 << 5),
|
LocalMessages = (1 << 5),
|
||||||
ChatOccupied = (1 << 6),
|
ChatOccupied = (1 << 6),
|
||||||
|
MessageSent = (1 << 7),
|
||||||
|
ForwardDraft = (1 << 8),
|
||||||
|
OutboxRead = (1 << 9),
|
||||||
|
BotKeyboard = (1 << 10),
|
||||||
|
CloudDraft = (1 << 11),
|
||||||
|
|
||||||
LastUsedBit = (1 << 6),
|
LastUsedBit = (1 << 11),
|
||||||
};
|
};
|
||||||
using Flags = base::flags<Flag>;
|
using Flags = base::flags<Flag>;
|
||||||
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||||
|
@ -100,6 +110,41 @@ struct HistoryUpdate {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MessageUpdate {
|
||||||
|
enum class Flag : uint32 {
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
Edited = (1 << 0),
|
||||||
|
Destroyed = (1 << 1),
|
||||||
|
DialogRowRepaint = (1 << 2),
|
||||||
|
DialogRowRefresh = (1 << 3),
|
||||||
|
|
||||||
|
LastUsedBit = (1 << 3),
|
||||||
|
};
|
||||||
|
using Flags = base::flags<Flag>;
|
||||||
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||||
|
|
||||||
|
not_null<HistoryItem*> item;
|
||||||
|
Flags flags = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EntryUpdate {
|
||||||
|
enum class Flag : uint32 {
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
Repaint = (1 << 0),
|
||||||
|
|
||||||
|
LastUsedBit = (1 << 0),
|
||||||
|
};
|
||||||
|
using Flags = base::flags<Flag>;
|
||||||
|
friend inline constexpr auto is_flag_type(Flag) { return true; }
|
||||||
|
|
||||||
|
not_null<Dialogs::Entry*> entry;
|
||||||
|
Flags flags = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class Changes final {
|
class Changes final {
|
||||||
public:
|
public:
|
||||||
explicit Changes(not_null<Main::Session*> session);
|
explicit Changes(not_null<Main::Session*> session);
|
||||||
|
@ -136,6 +181,36 @@ public:
|
||||||
[[nodiscard]] rpl::producer<HistoryUpdate> historyFlagsValue(
|
[[nodiscard]] rpl::producer<HistoryUpdate> historyFlagsValue(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
HistoryUpdate::Flags flags) const;
|
HistoryUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<HistoryUpdate> realtimeHistoryUpdates(
|
||||||
|
HistoryUpdate::Flag flag) const;
|
||||||
|
|
||||||
|
void messageUpdated(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
MessageUpdate::Flags flags);
|
||||||
|
[[nodiscard]] rpl::producer<MessageUpdate> messageUpdates(
|
||||||
|
MessageUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<MessageUpdate> messageUpdates(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
MessageUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<MessageUpdate> messageFlagsValue(
|
||||||
|
not_null<HistoryItem*> item,
|
||||||
|
MessageUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<MessageUpdate> realtimeMessageUpdates(
|
||||||
|
MessageUpdate::Flag flag) const;
|
||||||
|
|
||||||
|
void entryUpdated(
|
||||||
|
not_null<Dialogs::Entry*> entry,
|
||||||
|
EntryUpdate::Flags flags);
|
||||||
|
[[nodiscard]] rpl::producer<EntryUpdate> entryUpdates(
|
||||||
|
EntryUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<EntryUpdate> entryUpdates(
|
||||||
|
not_null<Dialogs::Entry*> entry,
|
||||||
|
EntryUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<EntryUpdate> entryFlagsValue(
|
||||||
|
not_null<Dialogs::Entry*> entry,
|
||||||
|
EntryUpdate::Flags flags) const;
|
||||||
|
[[nodiscard]] rpl::producer<EntryUpdate> realtimeEntryUpdates(
|
||||||
|
EntryUpdate::Flag flag) const;
|
||||||
|
|
||||||
void sendNotifications();
|
void sendNotifications();
|
||||||
|
|
||||||
|
@ -156,7 +231,10 @@ private:
|
||||||
using Flag = typename UpdateType::Flag;
|
using Flag = typename UpdateType::Flag;
|
||||||
using Flags = typename UpdateType::Flags;
|
using Flags = typename UpdateType::Flags;
|
||||||
|
|
||||||
void updated(not_null<DataType*> data, Flags flags);
|
void updated(
|
||||||
|
not_null<DataType*> data,
|
||||||
|
Flags flags,
|
||||||
|
bool dropScheduled = false);
|
||||||
[[nodiscard]] rpl::producer<UpdateType> updates(Flags flags) const;
|
[[nodiscard]] rpl::producer<UpdateType> updates(Flags flags) const;
|
||||||
[[nodiscard]] rpl::producer<UpdateType> updates(
|
[[nodiscard]] rpl::producer<UpdateType> updates(
|
||||||
not_null<DataType*> data,
|
not_null<DataType*> data,
|
||||||
|
@ -189,6 +267,8 @@ private:
|
||||||
rpl::event_stream<NameUpdate> _nameStream;
|
rpl::event_stream<NameUpdate> _nameStream;
|
||||||
Manager<PeerData, PeerUpdate> _peerChanges;
|
Manager<PeerData, PeerUpdate> _peerChanges;
|
||||||
Manager<History, HistoryUpdate> _historyChanges;
|
Manager<History, HistoryUpdate> _historyChanges;
|
||||||
|
Manager<HistoryItem, MessageUpdate> _messageChanges;
|
||||||
|
Manager<Dialogs::Entry, EntryUpdate> _entryChanges;
|
||||||
|
|
||||||
bool _notify = false;
|
bool _notify = false;
|
||||||
|
|
||||||
|
|
|
@ -560,12 +560,9 @@ bool ChatFilters::loadNextExceptions(bool chatsListLoaded) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatFilters::refreshHistory(not_null<History*> history) {
|
void ChatFilters::refreshHistory(not_null<History*> history) {
|
||||||
_refreshHistoryRequests.fire_copy(history);
|
if (history->inChatList() && !list().empty()) {
|
||||||
}
|
_owner->refreshChatListEntry(history);
|
||||||
|
}
|
||||||
auto ChatFilters::refreshHistoryRequests() const
|
|
||||||
-> rpl::producer<not_null<History*>> {
|
|
||||||
return _refreshHistoryRequests.events();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatFilters::requestSuggested() {
|
void ChatFilters::requestSuggested() {
|
||||||
|
|
|
@ -105,8 +105,6 @@ public:
|
||||||
bool loadNextExceptions(bool chatsListLoaded);
|
bool loadNextExceptions(bool chatsListLoaded);
|
||||||
|
|
||||||
void refreshHistory(not_null<History*> history);
|
void refreshHistory(not_null<History*> history);
|
||||||
[[nodiscard]] auto refreshHistoryRequests() const
|
|
||||||
-> rpl::producer<not_null<History*>>;
|
|
||||||
|
|
||||||
[[nodiscard]] not_null<Dialogs::MainList*> chatsList(FilterId filterId);
|
[[nodiscard]] not_null<Dialogs::MainList*> chatsList(FilterId filterId);
|
||||||
|
|
||||||
|
@ -137,7 +135,6 @@ private:
|
||||||
std::vector<ChatFilter> _list;
|
std::vector<ChatFilter> _list;
|
||||||
base::flat_map<FilterId, std::unique_ptr<Dialogs::MainList>> _chatsLists;
|
base::flat_map<FilterId, std::unique_ptr<Dialogs::MainList>> _chatsLists;
|
||||||
rpl::event_stream<> _listChanged;
|
rpl::event_stream<> _listChanged;
|
||||||
rpl::event_stream<not_null<History*>> _refreshHistoryRequests;
|
|
||||||
mtpRequestId _loadRequestId = 0;
|
mtpRequestId _loadRequestId = 0;
|
||||||
mtpRequestId _saveOrderRequestId = 0;
|
mtpRequestId _saveOrderRequestId = 0;
|
||||||
mtpRequestId _saveOrderAfterId = 0;
|
mtpRequestId _saveOrderAfterId = 0;
|
||||||
|
|
|
@ -400,7 +400,11 @@ void DocumentCancelClickHandler::onClickImpl() const {
|
||||||
return;
|
return;
|
||||||
} else if (data->uploading()) {
|
} else if (data->uploading()) {
|
||||||
if (const auto item = data->owner().message(context())) {
|
if (const auto item = data->owner().message(context())) {
|
||||||
App::main()->cancelUploadLayer(item);
|
if (const auto m = App::main()) { // multi good
|
||||||
|
if (&m->session() == &data->session()) {
|
||||||
|
m->cancelUploadLayer(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data->cancel();
|
data->cancel();
|
||||||
|
|
|
@ -55,7 +55,7 @@ rpl::producer<int> PinnedDialogsInFolderMaxValue(
|
||||||
//}
|
//}
|
||||||
|
|
||||||
Folder::Folder(not_null<Data::Session*> owner, FolderId id)
|
Folder::Folder(not_null<Data::Session*> owner, FolderId id)
|
||||||
: Entry(owner, this)
|
: Entry(owner, Type::Folder)
|
||||||
, _id(id)
|
, _id(id)
|
||||||
, _chatsList(
|
, _chatsList(
|
||||||
&owner->session(),
|
&owner->session(),
|
||||||
|
|
|
@ -353,7 +353,11 @@ void PhotoCancelClickHandler::onClickImpl() const {
|
||||||
return;
|
return;
|
||||||
} else if (data->uploading()) {
|
} else if (data->uploading()) {
|
||||||
if (const auto item = data->owner().message(context())) {
|
if (const auto item = data->owner().message(context())) {
|
||||||
App::main()->cancelUploadLayer(item);
|
if (const auto m = App::main()) { // multi good
|
||||||
|
if (&m->session() == &data->session()) {
|
||||||
|
m->cancelUploadLayer(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data->cancel();
|
data->cancel();
|
||||||
|
|
|
@ -237,7 +237,7 @@ Session::Session(not_null<Main::Session*> session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setupContactViewsViewer();
|
setupMigrationViewer();
|
||||||
setupChannelLeavingViewer();
|
setupChannelLeavingViewer();
|
||||||
setupPeerNameViewer();
|
setupPeerNameViewer();
|
||||||
setupUserIsContactViewer();
|
setupUserIsContactViewer();
|
||||||
|
@ -822,7 +822,7 @@ void Session::deleteConversationLocally(not_null<PeerData*> peer) {
|
||||||
if (history->folderKnown()) {
|
if (history->folderKnown()) {
|
||||||
setChatPinned(history, FilterId(), false);
|
setChatPinned(history, FilterId(), false);
|
||||||
}
|
}
|
||||||
App::main()->removeDialog(history);
|
removeChatListEntry(history);
|
||||||
history->clear(peer->isChannel()
|
history->clear(peer->isChannel()
|
||||||
? History::ClearType::Unload
|
? History::ClearType::Unload
|
||||||
: History::ClearType::DeleteChat);
|
: History::ClearType::DeleteChat);
|
||||||
|
@ -836,21 +836,12 @@ void Session::deleteConversationLocally(not_null<PeerData*> peer) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void Session::newMessageSent(not_null<History*> history) {
|
|
||||||
_newMessageSent.fire_copy(history);
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<not_null<History*>> Session::newMessageSent() const {
|
|
||||||
return _newMessageSent.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::cancelForwarding(not_null<History*> history) {
|
void Session::cancelForwarding(not_null<History*> history) {
|
||||||
history->setForwardDraft({});
|
history->setForwardDraft({});
|
||||||
_forwardDraftUpdated.fire_copy(history);
|
session().changes().historyUpdated(
|
||||||
}
|
history,
|
||||||
|
Data::HistoryUpdate::Flag::ForwardDraft);
|
||||||
rpl::producer<not_null<History*>> Session::forwardDraftUpdates() const {
|
|
||||||
return _forwardDraftUpdated.events();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::registerSendAction(
|
void Session::registerSendAction(
|
||||||
|
@ -1044,16 +1035,24 @@ void Session::forgetPassportCredentials() {
|
||||||
_passportCredentials = nullptr;
|
_passportCredentials = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::setupContactViewsViewer() {
|
void Session::setupMigrationViewer() {
|
||||||
session().changes().peerUpdates(
|
session().changes().peerUpdates(
|
||||||
PeerUpdate::Flag::IsContact
|
PeerUpdate::Flag::Migration
|
||||||
) | rpl::map([](const PeerUpdate &update) {
|
) | rpl::map([](const PeerUpdate &update) {
|
||||||
return update.peer->asUser();
|
return update.peer->asChat();
|
||||||
}) | rpl::start_with_next([=](not_null<UserData*> user) {
|
}) | rpl::filter([=](ChatData *chat) {
|
||||||
const auto i = _contactViews.find(peerToUser(user->id));
|
return (chat != nullptr);
|
||||||
if (i != _contactViews.end()) {
|
}) | rpl::start_with_next([=](not_null<ChatData*> chat) {
|
||||||
for (const auto view : i->second) {
|
const auto channel = chat->migrateTo();
|
||||||
requestViewResize(view);
|
if (!channel) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto from = historyLoaded(chat)) {
|
||||||
|
if (const auto to = historyLoaded(channel)) {
|
||||||
|
if (to->inChatList() && from->inChatList()) {
|
||||||
|
removeChatListEntry(from);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, _lifetime);
|
}, _lifetime);
|
||||||
|
@ -1089,21 +1088,27 @@ void Session::setupPeerNameViewer() {
|
||||||
void Session::setupUserIsContactViewer() {
|
void Session::setupUserIsContactViewer() {
|
||||||
session().changes().peerUpdates(
|
session().changes().peerUpdates(
|
||||||
PeerUpdate::Flag::IsContact
|
PeerUpdate::Flag::IsContact
|
||||||
) | rpl::start_with_next([=](const PeerUpdate &update) {
|
) | rpl::map([](const PeerUpdate &update) {
|
||||||
const auto user = update.peer->asUser();
|
return update.peer->asUser();
|
||||||
Assert(user != nullptr);
|
}) | rpl::start_with_next([=](not_null<UserData*> user) {
|
||||||
|
const auto i = _contactViews.find(peerToUser(user->id));
|
||||||
|
if (i != _contactViews.end()) {
|
||||||
|
for (const auto view : i->second) {
|
||||||
|
requestViewResize(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (user->loadedStatus != PeerData::FullLoaded) {
|
if (user->loadedStatus != PeerData::FullLoaded) {
|
||||||
LOG(("API Error: "
|
LOG(("API Error: "
|
||||||
"userIsContactChanged() called for a not loaded user!"));
|
"userIsContactChanged() called for a not loaded user!"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (user->isContact()) {
|
if (user->isContact()) {
|
||||||
const auto history = user->owner().history(user->id);
|
const auto history = this->history(user->id);
|
||||||
_contactsList.addByName(history);
|
_contactsList.addByName(history);
|
||||||
if (!history->inChatList()) {
|
if (!history->inChatList()) {
|
||||||
_contactsNoChatsList.addByName(history);
|
_contactsNoChatsList.addByName(history);
|
||||||
}
|
}
|
||||||
} else if (const auto history = user->owner().historyLoaded(user)) {
|
} else if (const auto history = historyLoaded(user)) {
|
||||||
_contactsNoChatsList.del(history);
|
_contactsNoChatsList.del(history);
|
||||||
_contactsList.del(history);
|
_contactsList.del(history);
|
||||||
}
|
}
|
||||||
|
@ -1619,12 +1624,12 @@ void Session::applyDialog(
|
||||||
setPinnedFromDialog(history, data.is_pinned());
|
setPinnedFromDialog(history, data.is_pinned());
|
||||||
|
|
||||||
if (const auto from = history->peer->migrateFrom()) {
|
if (const auto from = history->peer->migrateFrom()) {
|
||||||
if (const auto historyFrom = from->owner().historyLoaded(from)) {
|
if (const auto historyFrom = historyLoaded(from)) {
|
||||||
App::main()->removeDialog(historyFrom);
|
removeChatListEntry(historyFrom);
|
||||||
}
|
}
|
||||||
} else if (const auto to = history->peer->migrateTo()) {
|
} else if (const auto to = history->peer->migrateTo()) {
|
||||||
if (to->amIn()) {
|
if (to->amIn()) {
|
||||||
App::main()->removeDialog(history);
|
removeChatListEntry(history);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1898,9 +1903,9 @@ void Session::updateDependentMessages(not_null<HistoryItem*> item) {
|
||||||
dependent->updateDependencyItem();
|
dependent->updateDependencyItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (App::main()) {
|
session().changes().messageUpdated(
|
||||||
App::main()->itemEdited(item);
|
item,
|
||||||
}
|
Data::MessageUpdate::Flag::Edited);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::registerDependentMessage(
|
void Session::registerDependentMessage(
|
||||||
|
@ -3312,14 +3317,6 @@ rpl::producer<not_null<ChannelData*>> Session::channelDifferenceTooLong() const
|
||||||
return _channelDifferenceTooLong.events();
|
return _channelDifferenceTooLong.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::historyOutboxRead(not_null<History*> history) {
|
|
||||||
_historyOutboxReads.fire_copy(history);
|
|
||||||
}
|
|
||||||
|
|
||||||
rpl::producer<not_null<History*>> Session::historyOutboxReads() const {
|
|
||||||
return _historyOutboxReads.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Session::registerItemView(not_null<ViewElement*> view) {
|
void Session::registerItemView(not_null<ViewElement*> view) {
|
||||||
_views[view->data()].push_back(view);
|
_views[view->data()].push_back(view);
|
||||||
}
|
}
|
||||||
|
@ -3409,10 +3406,7 @@ not_null<Dialogs::IndexedList*> Session::contactsNoChatsList() {
|
||||||
return &_contactsNoChatsList;
|
return &_contactsNoChatsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Session::refreshChatListEntry(
|
void Session::refreshChatListEntry(Dialogs::Key key) {
|
||||||
Dialogs::Key key,
|
|
||||||
FilterId filterIdForResult)
|
|
||||||
-> RefreshChatListEntryResult {
|
|
||||||
Expects(key.entry()->folderKnown());
|
Expects(key.entry()->folderKnown());
|
||||||
|
|
||||||
using namespace Dialogs;
|
using namespace Dialogs;
|
||||||
|
@ -3420,42 +3414,47 @@ auto Session::refreshChatListEntry(
|
||||||
const auto entry = key.entry();
|
const auto entry = key.entry();
|
||||||
const auto history = key.history();
|
const auto history = key.history();
|
||||||
const auto mainList = chatsList(entry->folder());
|
const auto mainList = chatsList(entry->folder());
|
||||||
auto mainListResult = RefreshChatListEntryResult();
|
auto event = ChatListEntryRefresh{ .key = key };
|
||||||
mainListResult.changed = !entry->inChatList();
|
const auto creating = event.existenceChanged = !entry->inChatList();
|
||||||
if (mainListResult.changed) {
|
if (event.existenceChanged) {
|
||||||
const auto mainRow = entry->addToChatList(0, mainList);
|
const auto mainRow = entry->addToChatList(0, mainList);
|
||||||
_contactsNoChatsList.del(key, mainRow);
|
_contactsNoChatsList.del(key, mainRow);
|
||||||
} else {
|
} else {
|
||||||
mainListResult.moved = entry->adjustByPosInChatList(0, mainList);
|
event.moved = entry->adjustByPosInChatList(0, mainList);
|
||||||
|
}
|
||||||
|
if (event) {
|
||||||
|
_chatListEntryRefreshes.fire(std::move(event));
|
||||||
}
|
}
|
||||||
auto result = filterIdForResult
|
|
||||||
? RefreshChatListEntryResult()
|
|
||||||
: mainListResult;
|
|
||||||
if (!history) {
|
if (!history) {
|
||||||
return result;
|
return;
|
||||||
}
|
}
|
||||||
for (const auto &filter : _chatsFilters->list()) {
|
for (const auto &filter : _chatsFilters->list()) {
|
||||||
const auto id = filter.id();
|
const auto id = filter.id();
|
||||||
const auto filterList = chatsFilters().chatsList(id);
|
const auto filterList = chatsFilters().chatsList(id);
|
||||||
auto filterResult = RefreshChatListEntryResult();
|
auto event = ChatListEntryRefresh{ .key = key, .filterId = id };
|
||||||
if (filter.contains(history)) {
|
if (filter.contains(history)) {
|
||||||
filterResult.changed = !entry->inChatList(id);
|
event.existenceChanged = !entry->inChatList(id);
|
||||||
if (filterResult.changed) {
|
if (event.existenceChanged) {
|
||||||
entry->addToChatList(id, filterList);
|
entry->addToChatList(id, filterList);
|
||||||
} else {
|
} else {
|
||||||
filterResult.moved = entry->adjustByPosInChatList(
|
event.moved = entry->adjustByPosInChatList(id, filterList);
|
||||||
id,
|
|
||||||
filterList);
|
|
||||||
}
|
}
|
||||||
} else if (entry->inChatList(id)) {
|
} else if (entry->inChatList(id)) {
|
||||||
entry->removeFromChatList(id, filterList);
|
entry->removeFromChatList(id, filterList);
|
||||||
filterResult.changed = true;
|
event.existenceChanged = true;
|
||||||
}
|
}
|
||||||
if (id == filterIdForResult) {
|
if (event) {
|
||||||
result = filterResult;
|
_chatListEntryRefreshes.fire(std::move(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (creating) {
|
||||||
|
if (const auto from = history->peer->migrateFrom()) {
|
||||||
|
if (const auto migrated = historyLoaded(from)) {
|
||||||
|
removeChatListEntry(migrated);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::removeChatListEntry(Dialogs::Key key) {
|
void Session::removeChatListEntry(Dialogs::Key key) {
|
||||||
|
@ -3466,21 +3465,39 @@ void Session::removeChatListEntry(Dialogs::Key key) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Assert(entry->folderKnown());
|
Assert(entry->folderKnown());
|
||||||
const auto mainList = chatsList(entry->folder());
|
|
||||||
entry->removeFromChatList(0, mainList);
|
|
||||||
for (const auto &filter : _chatsFilters->list()) {
|
for (const auto &filter : _chatsFilters->list()) {
|
||||||
const auto id = filter.id();
|
const auto id = filter.id();
|
||||||
if (entry->inChatList(id)) {
|
if (entry->inChatList(id)) {
|
||||||
entry->removeFromChatList(id, chatsFilters().chatsList(id));
|
entry->removeFromChatList(id, chatsFilters().chatsList(id));
|
||||||
|
_chatListEntryRefreshes.fire(ChatListEntryRefresh{
|
||||||
|
.key = key,
|
||||||
|
.filterId = id,
|
||||||
|
.existenceChanged = true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const auto mainList = chatsList(entry->folder());
|
||||||
|
entry->removeFromChatList(0, mainList);
|
||||||
|
_chatListEntryRefreshes.fire(ChatListEntryRefresh{
|
||||||
|
.key = key,
|
||||||
|
.existenceChanged = true
|
||||||
|
});
|
||||||
if (_contactsList.contains(key)) {
|
if (_contactsList.contains(key)) {
|
||||||
if (!_contactsNoChatsList.contains(key)) {
|
if (!_contactsNoChatsList.contains(key)) {
|
||||||
_contactsNoChatsList.addByName(key);
|
_contactsNoChatsList.addByName(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (const auto history = key.history()) {
|
||||||
|
session().notifications().clearFromHistory(history);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Session::chatListEntryRefreshes() const
|
||||||
|
-> rpl::producer<ChatListEntryRefresh> {
|
||||||
|
return _chatListEntryRefreshes.events();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Session::dialogsRowReplaced(DialogsRowReplacement replacement) {
|
void Session::dialogsRowReplaced(DialogsRowReplacement replacement) {
|
||||||
_dialogsRowReplacements.fire(std::move(replacement));
|
_dialogsRowReplacements.fire(std::move(replacement));
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,10 +180,7 @@ public:
|
||||||
|
|
||||||
void deleteConversationLocally(not_null<PeerData*> peer);
|
void deleteConversationLocally(not_null<PeerData*> peer);
|
||||||
|
|
||||||
void newMessageSent(not_null<History*> history);
|
|
||||||
[[nodiscard]] rpl::producer<not_null<History*>> newMessageSent() const;
|
|
||||||
void cancelForwarding(not_null<History*> history);
|
void cancelForwarding(not_null<History*> history);
|
||||||
[[nodiscard]] rpl::producer<not_null<History*>> forwardDraftUpdates() const;
|
|
||||||
|
|
||||||
void registerSendAction(
|
void registerSendAction(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
|
@ -561,9 +558,6 @@ public:
|
||||||
void channelDifferenceTooLong(not_null<ChannelData*> channel);
|
void channelDifferenceTooLong(not_null<ChannelData*> channel);
|
||||||
[[nodiscard]] rpl::producer<not_null<ChannelData*>> channelDifferenceTooLong() const;
|
[[nodiscard]] rpl::producer<not_null<ChannelData*>> channelDifferenceTooLong() const;
|
||||||
|
|
||||||
void historyOutboxRead(not_null<History*> history);
|
|
||||||
[[nodiscard]] rpl::producer<not_null<History*>> historyOutboxReads() const;
|
|
||||||
|
|
||||||
void registerItemView(not_null<ViewElement*> view);
|
void registerItemView(not_null<ViewElement*> view);
|
||||||
void unregisterItemView(not_null<ViewElement*> view);
|
void unregisterItemView(not_null<ViewElement*> view);
|
||||||
|
|
||||||
|
@ -582,14 +576,20 @@ public:
|
||||||
[[nodiscard]] not_null<Dialogs::IndexedList*> contactsList();
|
[[nodiscard]] not_null<Dialogs::IndexedList*> contactsList();
|
||||||
[[nodiscard]] not_null<Dialogs::IndexedList*> contactsNoChatsList();
|
[[nodiscard]] not_null<Dialogs::IndexedList*> contactsNoChatsList();
|
||||||
|
|
||||||
struct RefreshChatListEntryResult {
|
struct ChatListEntryRefresh {
|
||||||
bool changed = false;
|
Dialogs::Key key;
|
||||||
Dialogs::PositionChange moved;
|
Dialogs::PositionChange moved;
|
||||||
|
FilterId filterId = 0;
|
||||||
|
bool existenceChanged = false;
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return existenceChanged || (moved.from != moved.to);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
RefreshChatListEntryResult refreshChatListEntry(
|
void refreshChatListEntry(Dialogs::Key key);
|
||||||
Dialogs::Key key,
|
|
||||||
FilterId filterIdForResult);
|
|
||||||
void removeChatListEntry(Dialogs::Key key);
|
void removeChatListEntry(Dialogs::Key key);
|
||||||
|
[[nodiscard]] auto chatListEntryRefreshes() const
|
||||||
|
-> rpl::producer<ChatListEntryRefresh>;
|
||||||
|
|
||||||
struct DialogsRowReplacement {
|
struct DialogsRowReplacement {
|
||||||
not_null<Dialogs::Row*> old;
|
not_null<Dialogs::Row*> old;
|
||||||
|
@ -645,7 +645,7 @@ private:
|
||||||
|
|
||||||
void suggestStartExport();
|
void suggestStartExport();
|
||||||
|
|
||||||
void setupContactViewsViewer();
|
void setupMigrationViewer();
|
||||||
void setupChannelLeavingViewer();
|
void setupChannelLeavingViewer();
|
||||||
void setupPeerNameViewer();
|
void setupPeerNameViewer();
|
||||||
void setupUserIsContactViewer();
|
void setupUserIsContactViewer();
|
||||||
|
@ -808,6 +808,7 @@ private:
|
||||||
rpl::event_stream<MegagroupParticipant> _megagroupParticipantRemoved;
|
rpl::event_stream<MegagroupParticipant> _megagroupParticipantRemoved;
|
||||||
rpl::event_stream<MegagroupParticipant> _megagroupParticipantAdded;
|
rpl::event_stream<MegagroupParticipant> _megagroupParticipantAdded;
|
||||||
rpl::event_stream<DialogsRowReplacement> _dialogsRowReplacements;
|
rpl::event_stream<DialogsRowReplacement> _dialogsRowReplacements;
|
||||||
|
rpl::event_stream<ChatListEntryRefresh> _chatListEntryRefreshes;
|
||||||
|
|
||||||
Dialogs::MainList _chatsList;
|
Dialogs::MainList _chatsList;
|
||||||
Dialogs::IndexedList _contactsList;
|
Dialogs::IndexedList _contactsList;
|
||||||
|
@ -879,9 +880,6 @@ private:
|
||||||
|
|
||||||
rpl::event_stream<not_null<WebPageData*>> _webpageUpdates;
|
rpl::event_stream<not_null<WebPageData*>> _webpageUpdates;
|
||||||
rpl::event_stream<not_null<ChannelData*>> _channelDifferenceTooLong;
|
rpl::event_stream<not_null<ChannelData*>> _channelDifferenceTooLong;
|
||||||
rpl::event_stream<not_null<History*>> _historyOutboxReads;
|
|
||||||
rpl::event_stream<not_null<History*>> _newMessageSent;
|
|
||||||
rpl::event_stream<not_null<History*>> _forwardDraftUpdated;
|
|
||||||
|
|
||||||
base::flat_multi_map<TimeId, not_null<PollData*>> _pollsClosings;
|
base::flat_multi_map<TimeId, not_null<PollData*>> _pollsClosings;
|
||||||
base::Timer _pollsClosingTimer;
|
base::Timer _pollsClosingTimer;
|
||||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
|
||||||
#include "dialogs/dialogs_key.h"
|
#include "dialogs/dialogs_key.h"
|
||||||
#include "dialogs/dialogs_indexed_list.h"
|
#include "dialogs/dialogs_indexed_list.h"
|
||||||
|
#include "data/data_changes.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_chat_filters.h"
|
#include "data/data_chat_filters.h"
|
||||||
|
@ -41,10 +42,10 @@ uint64 PinnedDialogPos(int pinnedIndex) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Entry::Entry(not_null<Data::Session*> owner, const Key &key)
|
Entry::Entry(not_null<Data::Session*> owner, Type type)
|
||||||
: lastItemTextCache(st::dialogsTextWidthMin)
|
: lastItemTextCache(st::dialogsTextWidthMin)
|
||||||
, _owner(owner)
|
, _owner(owner)
|
||||||
, _key(key) {
|
, _isFolder(type == Type::Folder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Data::Session &Entry::owner() const {
|
Data::Session &Entry::owner() const {
|
||||||
|
@ -55,6 +56,14 @@ Main::Session &Entry::session() const {
|
||||||
return _owner->session();
|
return _owner->session();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
History *Entry::asHistory() {
|
||||||
|
return _isFolder ? nullptr : static_cast<History*>(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Data::Folder *Entry::asFolder() {
|
||||||
|
return _isFolder ? static_cast<Data::Folder*>(this) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Entry::pinnedIndexChanged(int was, int now) {
|
void Entry::pinnedIndexChanged(int was, int now) {
|
||||||
if (session().supportMode()) {
|
if (session().supportMode()) {
|
||||||
// Force reorder in support mode.
|
// Force reorder in support mode.
|
||||||
|
@ -159,13 +168,11 @@ void Entry::notifyUnreadStateChange(const UnreadState &wasState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::setChatListExistence(bool exists) {
|
void Entry::setChatListExistence(bool exists) {
|
||||||
if (const auto main = App::main()) {
|
if (exists && _sortKeyInChatList) {
|
||||||
if (exists && _sortKeyInChatList) {
|
owner().refreshChatListEntry(this);
|
||||||
main->refreshDialog(_key);
|
updateChatListEntry();
|
||||||
updateChatListEntry();
|
} else {
|
||||||
} else {
|
owner().removeChatListEntry(this);
|
||||||
main->removeDialog(_key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,7 +235,7 @@ not_null<Row*> Entry::addToChatList(
|
||||||
}
|
}
|
||||||
return _chatListLinks.emplace(
|
return _chatListLinks.emplace(
|
||||||
filterId,
|
filterId,
|
||||||
list->addEntry(_key)
|
list->addEntry(this)
|
||||||
).first->second.main;
|
).first->second.main;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,7 +243,7 @@ void Entry::removeFromChatList(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
not_null<MainList*> list) {
|
not_null<MainList*> list) {
|
||||||
if (isPinnedDialog(filterId)) {
|
if (isPinnedDialog(filterId)) {
|
||||||
owner().setChatPinned(_key, filterId, false);
|
owner().setChatPinned(this, filterId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto i = _chatListLinks.find(filterId);
|
const auto i = _chatListLinks.find(filterId);
|
||||||
|
@ -244,7 +251,7 @@ void Entry::removeFromChatList(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_chatListLinks.erase(i);
|
_chatListLinks.erase(i);
|
||||||
list->removeEntry(_key);
|
list->removeEntry(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::removeChatListEntryByLetter(FilterId filterId, QChar letter) {
|
void Entry::removeChatListEntryByLetter(FilterId filterId, QChar letter) {
|
||||||
|
@ -264,16 +271,8 @@ void Entry::addChatListEntryByLetter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entry::updateChatListEntry() const {
|
void Entry::updateChatListEntry() {
|
||||||
if (const auto main = App::main()) {
|
session().changes().entryUpdated(this, Data::EntryUpdate::Flag::Repaint);
|
||||||
for (const auto &[filterId, links] : _chatListLinks) {
|
|
||||||
main->repaintDialogRow(filterId, links.main);
|
|
||||||
}
|
|
||||||
if (session().supportMode()
|
|
||||||
&& !session().settings().supportAllSearchResults()) {
|
|
||||||
main->repaintDialogRow({ _key, FullMsgId() });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Dialogs
|
} // namespace Dialogs
|
||||||
|
|
|
@ -90,7 +90,11 @@ inline UnreadState operator-(const UnreadState &a, const UnreadState &b) {
|
||||||
|
|
||||||
class Entry {
|
class Entry {
|
||||||
public:
|
public:
|
||||||
Entry(not_null<Data::Session*> owner, const Key &key);
|
enum class Type {
|
||||||
|
History,
|
||||||
|
Folder,
|
||||||
|
};
|
||||||
|
Entry(not_null<Data::Session*> owner, Type type);
|
||||||
Entry(const Entry &other) = delete;
|
Entry(const Entry &other) = delete;
|
||||||
Entry &operator=(const Entry &other) = delete;
|
Entry &operator=(const Entry &other) = delete;
|
||||||
virtual ~Entry() = default;
|
virtual ~Entry() = default;
|
||||||
|
@ -98,12 +102,17 @@ public:
|
||||||
[[nodiscard]] Data::Session &owner() const;
|
[[nodiscard]] Data::Session &owner() const;
|
||||||
[[nodiscard]] Main::Session &session() const;
|
[[nodiscard]] Main::Session &session() const;
|
||||||
|
|
||||||
|
History *asHistory();
|
||||||
|
Data::Folder *asFolder();
|
||||||
|
|
||||||
PositionChange adjustByPosInChatList(
|
PositionChange adjustByPosInChatList(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
not_null<MainList*> list);
|
not_null<MainList*> list);
|
||||||
[[nodiscard]] bool inChatList(FilterId filterId = 0) const {
|
[[nodiscard]] bool inChatList(FilterId filterId = 0) const {
|
||||||
return _chatListLinks.contains(filterId);
|
return _chatListLinks.contains(filterId);
|
||||||
}
|
}
|
||||||
|
RowsByLetter *chatListLinks(FilterId filterId);
|
||||||
|
const RowsByLetter *chatListLinks(FilterId filterId) const;
|
||||||
[[nodiscard]] int posInChatList(FilterId filterId) const;
|
[[nodiscard]] int posInChatList(FilterId filterId) const;
|
||||||
not_null<Row*> addToChatList(
|
not_null<Row*> addToChatList(
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
|
@ -116,7 +125,7 @@ public:
|
||||||
FilterId filterId,
|
FilterId filterId,
|
||||||
QChar letter,
|
QChar letter,
|
||||||
not_null<Row*> row);
|
not_null<Row*> row);
|
||||||
void updateChatListEntry() const;
|
void updateChatListEntry();
|
||||||
[[nodiscard]] bool isPinnedDialog(FilterId filterId) const {
|
[[nodiscard]] bool isPinnedDialog(FilterId filterId) const {
|
||||||
return lookupPinnedIndex(filterId) != 0;
|
return lookupPinnedIndex(filterId) != 0;
|
||||||
}
|
}
|
||||||
|
@ -202,19 +211,17 @@ private:
|
||||||
[[nodiscard]] uint64 computeSortPosition(FilterId filterId) const;
|
[[nodiscard]] uint64 computeSortPosition(FilterId filterId) const;
|
||||||
|
|
||||||
void setChatListExistence(bool exists);
|
void setChatListExistence(bool exists);
|
||||||
RowsByLetter *chatListLinks(FilterId filterId);
|
|
||||||
const RowsByLetter *chatListLinks(FilterId filterId) const;
|
|
||||||
not_null<Row*> mainChatListLink(FilterId filterId) const;
|
not_null<Row*> mainChatListLink(FilterId filterId) const;
|
||||||
Row *maybeMainChatListLink(FilterId filterId) const;
|
Row *maybeMainChatListLink(FilterId filterId) const;
|
||||||
|
|
||||||
not_null<Data::Session*> _owner;
|
const not_null<Data::Session*> _owner;
|
||||||
Dialogs::Key _key;
|
|
||||||
base::flat_map<FilterId, RowsByLetter> _chatListLinks;
|
base::flat_map<FilterId, RowsByLetter> _chatListLinks;
|
||||||
uint64 _sortKeyInChatList = 0;
|
uint64 _sortKeyInChatList = 0;
|
||||||
uint64 _sortKeyByDate = 0;
|
uint64 _sortKeyByDate = 0;
|
||||||
base::flat_map<FilterId, int> _pinnedIndex;
|
base::flat_map<FilterId, int> _pinnedIndex;
|
||||||
TimeId _timeId = 0;
|
TimeId _timeId = 0;
|
||||||
bool _isTopPromoted = false;
|
bool _isTopPromoted = false;
|
||||||
|
const bool _isFolder = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -209,14 +209,6 @@ InnerWidget::InnerWidget(
|
||||||
refresh();
|
refresh();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
session().data().chatsFilters().refreshHistoryRequests(
|
|
||||||
) | rpl::start_with_next([=](not_null<History*> history) {
|
|
||||||
if (history->inChatList()
|
|
||||||
&& !session().data().chatsFilters().list().empty()) {
|
|
||||||
refreshDialog(history);
|
|
||||||
}
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
subscribe(Window::Theme::Background(), [=](const Window::Theme::BackgroundUpdate &data) {
|
subscribe(Window::Theme::Background(), [=](const Window::Theme::BackgroundUpdate &data) {
|
||||||
if (data.paletteChanged()) {
|
if (data.paletteChanged()) {
|
||||||
Layout::clearUnreadBadgesCache();
|
Layout::clearUnreadBadgesCache();
|
||||||
|
@ -241,7 +233,6 @@ InnerWidget::InnerWidget(
|
||||||
UpdateFlag::Name
|
UpdateFlag::Name
|
||||||
| UpdateFlag::Photo
|
| UpdateFlag::Photo
|
||||||
| UpdateFlag::IsContact
|
| UpdateFlag::IsContact
|
||||||
| UpdateFlag::Migration
|
|
||||||
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
||||||
if (update.flags & (UpdateFlag::Name | UpdateFlag::Photo)) {
|
if (update.flags & (UpdateFlag::Name | UpdateFlag::Photo)) {
|
||||||
this->update();
|
this->update();
|
||||||
|
@ -251,10 +242,34 @@ InnerWidget::InnerWidget(
|
||||||
// contactsNoChatsList could've changed.
|
// contactsNoChatsList could've changed.
|
||||||
Ui::PostponeCall(this, [=] { refresh(); });
|
Ui::PostponeCall(this, [=] { refresh(); });
|
||||||
}
|
}
|
||||||
if (update.flags & UpdateFlag::Migration) {
|
}, lifetime());
|
||||||
if (const auto chat = update.peer->asChat()) {
|
|
||||||
handleChatMigration(chat);
|
session().changes().messageUpdates(
|
||||||
}
|
Data::MessageUpdate::Flag::DialogRowRepaint
|
||||||
|
| Data::MessageUpdate::Flag::DialogRowRefresh
|
||||||
|
) | rpl::start_with_next([=](const Data::MessageUpdate &update) {
|
||||||
|
const auto item = update.item;
|
||||||
|
if (update.flags & Data::MessageUpdate::Flag::DialogRowRefresh) {
|
||||||
|
refreshDialogRow({ item->history(), item->fullId() });
|
||||||
|
}
|
||||||
|
if (update.flags & Data::MessageUpdate::Flag::DialogRowRepaint) {
|
||||||
|
repaintDialogRow({ item->history(), item->fullId() });
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
|
|
||||||
|
session().changes().entryUpdates(
|
||||||
|
Data::EntryUpdate::Flag::Repaint
|
||||||
|
) | rpl::start_with_next([=](const Data::EntryUpdate &update) {
|
||||||
|
const auto entry = update.entry;
|
||||||
|
const auto repaintId = (_state == WidgetState::Default)
|
||||||
|
? _filterId
|
||||||
|
: 0;
|
||||||
|
if (const auto links = entry->chatListLinks(repaintId)) {
|
||||||
|
repaintDialogRow(repaintId, links->main);
|
||||||
|
}
|
||||||
|
if (session().supportMode()
|
||||||
|
&& !session().settings().supportAllSearchResults()) {
|
||||||
|
repaintDialogRow({ entry, FullMsgId() });
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
@ -272,6 +287,8 @@ InnerWidget::InnerWidget(
|
||||||
switchToFilter(filterId);
|
switchToFilter(filterId);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
handleChatListEntryRefreshes();
|
||||||
|
|
||||||
refreshWithCollapsedRows(true);
|
refreshWithCollapsedRows(true);
|
||||||
|
|
||||||
setupShortcuts();
|
setupShortcuts();
|
||||||
|
@ -281,21 +298,6 @@ Main::Session &InnerWidget::session() const {
|
||||||
return _controller->session();
|
return _controller->session();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::handleChatMigration(not_null<ChatData*> chat) {
|
|
||||||
const auto channel = chat->migrateTo();
|
|
||||||
if (!channel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto from = chat->owner().historyLoaded(chat)) {
|
|
||||||
if (const auto to = chat->owner().historyLoaded(channel)) {
|
|
||||||
if (to->inChatList() && from->inChatList()) {
|
|
||||||
removeDialog(from);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InnerWidget::refreshWithCollapsedRows(bool toTop) {
|
void InnerWidget::refreshWithCollapsedRows(bool toTop) {
|
||||||
const auto pressed = _collapsedPressed;
|
const auto pressed = _collapsedPressed;
|
||||||
const auto selected = _collapsedSelected;
|
const auto selected = _collapsedSelected;
|
||||||
|
@ -1443,68 +1445,56 @@ void InnerWidget::dialogRowReplaced(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::refreshDialog(Key key) {
|
void InnerWidget::handleChatListEntryRefreshes() {
|
||||||
if (const auto history = key.history()) {
|
using Event = Data::Session::ChatListEntryRefresh;
|
||||||
if (history->peer->loadedStatus
|
session().data().chatListEntryRefreshes(
|
||||||
!= PeerData::LoadedStatus::FullLoaded) {
|
) | rpl::filter([=](const Event &event) {
|
||||||
LOG(("API Error: "
|
return (event.filterId == _filterId);
|
||||||
"InnerWidget::refreshDialog() called for a non loaded peer!"
|
}) | rpl::start_with_next([=](const Event &event) {
|
||||||
));
|
const auto rowHeight = st::dialogsRowHeight;
|
||||||
return;
|
const auto from = dialogsOffset() + event.moved.from * rowHeight;
|
||||||
}
|
const auto to = dialogsOffset() + event.moved.to * rowHeight;
|
||||||
}
|
const auto &key = event.key;
|
||||||
|
const auto entry = key.entry();
|
||||||
|
|
||||||
const auto result = session().data().refreshChatListEntry(
|
|
||||||
key,
|
|
||||||
_filterId);
|
|
||||||
const auto rowHeight = st::dialogsRowHeight;
|
|
||||||
const auto from = dialogsOffset() + result.moved.from * rowHeight;
|
|
||||||
const auto to = dialogsOffset() + result.moved.to * rowHeight;
|
|
||||||
if (!_dragging
|
|
||||||
&& (from != to)
|
|
||||||
&& (key.entry()->folder() == _openedFolder)) {
|
|
||||||
// Don't jump in chats list scroll position while dragging.
|
// Don't jump in chats list scroll position while dragging.
|
||||||
emit dialogMoved(from, to);
|
if (!_dragging
|
||||||
}
|
&& (from != to)
|
||||||
|
&& (entry->folder() == _openedFolder)
|
||||||
if (result.changed) {
|
&& (_state == WidgetState::Default)) {
|
||||||
refresh();
|
emit dialogMoved(from, to);
|
||||||
} else if (_state == WidgetState::Default && from != to) {
|
|
||||||
update(
|
|
||||||
0,
|
|
||||||
std::min(from, to),
|
|
||||||
width(),
|
|
||||||
std::abs(from - to) + rowHeight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void InnerWidget::removeDialog(Key key) {
|
|
||||||
if (key == _menuRow.key && _menu) {
|
|
||||||
InvokeQueued(this, [=] { _menu = nullptr; });
|
|
||||||
}
|
|
||||||
if (_selected && _selected->key() == key) {
|
|
||||||
_selected = nullptr;
|
|
||||||
}
|
|
||||||
if (_pressed && _pressed->key() == key) {
|
|
||||||
setPressed(nullptr);
|
|
||||||
}
|
|
||||||
session().data().removeChatListEntry(key);
|
|
||||||
if (const auto history = key.history()) {
|
|
||||||
session().notifications().clearFromHistory(history);
|
|
||||||
}
|
|
||||||
const auto i = ranges::find(_filterResults, key, &Row::key);
|
|
||||||
if (i != _filterResults.end()) {
|
|
||||||
if (_filteredSelected == (i - _filterResults.begin())
|
|
||||||
&& (i + 1) == _filterResults.end()) {
|
|
||||||
_filteredSelected = -1;
|
|
||||||
}
|
}
|
||||||
_filterResults.erase(i);
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
_updated.fire({});
|
if (event.existenceChanged) {
|
||||||
|
if (!entry->inChatList()) {
|
||||||
refresh();
|
if (key == _menuRow.key && _menu) {
|
||||||
|
InvokeQueued(this, [=] { _menu = nullptr; });
|
||||||
|
}
|
||||||
|
if (_selected && _selected->key() == key) {
|
||||||
|
_selected = nullptr;
|
||||||
|
}
|
||||||
|
if (_pressed && _pressed->key() == key) {
|
||||||
|
setPressed(nullptr);
|
||||||
|
}
|
||||||
|
const auto i = ranges::find(_filterResults, key, &Row::key);
|
||||||
|
if (i != _filterResults.end()) {
|
||||||
|
if (_filteredSelected == (i - _filterResults.begin())
|
||||||
|
&& (i + 1) == _filterResults.end()) {
|
||||||
|
_filteredSelected = -1;
|
||||||
|
}
|
||||||
|
_filterResults.erase(i);
|
||||||
|
}
|
||||||
|
_updated.fire({});
|
||||||
|
}
|
||||||
|
refresh();
|
||||||
|
} else if (_state == WidgetState::Default && from != to) {
|
||||||
|
update(
|
||||||
|
0,
|
||||||
|
std::min(from, to),
|
||||||
|
width(),
|
||||||
|
std::abs(from - to) + rowHeight);
|
||||||
|
}
|
||||||
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
void InnerWidget::repaintCollapsedFolderRow(not_null<Data::Folder*> folder) {
|
void InnerWidget::repaintCollapsedFolderRow(not_null<Data::Folder*> folder) {
|
||||||
|
|
|
@ -86,12 +86,6 @@ public:
|
||||||
void selectSkip(int32 direction);
|
void selectSkip(int32 direction);
|
||||||
void selectSkipPage(int32 pixels, int32 direction);
|
void selectSkipPage(int32 pixels, int32 direction);
|
||||||
|
|
||||||
void refreshDialog(Key key);
|
|
||||||
void removeDialog(Key key);
|
|
||||||
void repaintDialogRow(FilterId filterId, not_null<Row*> row);
|
|
||||||
void repaintDialogRow(RowDescriptor row);
|
|
||||||
void refreshDialogRow(RowDescriptor row);
|
|
||||||
|
|
||||||
void dragLeft();
|
void dragLeft();
|
||||||
|
|
||||||
void clearFilter();
|
void clearFilter();
|
||||||
|
@ -193,6 +187,10 @@ private:
|
||||||
not_null<FakeRow*> result,
|
not_null<FakeRow*> result,
|
||||||
const RowDescriptor &entry) const;
|
const RowDescriptor &entry) const;
|
||||||
|
|
||||||
|
void repaintDialogRow(FilterId filterId, not_null<Row*> row);
|
||||||
|
void repaintDialogRow(RowDescriptor row);
|
||||||
|
void refreshDialogRow(RowDescriptor row);
|
||||||
|
|
||||||
void clearMouseSelection(bool clearSelection = false);
|
void clearMouseSelection(bool clearSelection = false);
|
||||||
void mousePressReleased(QPoint globalPosition, Qt::MouseButton button);
|
void mousePressReleased(QPoint globalPosition, Qt::MouseButton button);
|
||||||
void clearIrrelevantState();
|
void clearIrrelevantState();
|
||||||
|
@ -316,7 +314,7 @@ private:
|
||||||
int countPinnedIndex(Row *ofRow);
|
int countPinnedIndex(Row *ofRow);
|
||||||
void savePinnedOrder();
|
void savePinnedOrder();
|
||||||
bool pinnedShiftAnimationCallback(crl::time now);
|
bool pinnedShiftAnimationCallback(crl::time now);
|
||||||
void handleChatMigration(not_null<ChatData*> chat);
|
void handleChatListEntryRefreshes();
|
||||||
|
|
||||||
not_null<Window::SessionController*> _controller;
|
not_null<Window::SessionController*> _controller;
|
||||||
|
|
||||||
|
|
|
@ -17,32 +17,35 @@ using Folder = Data::Folder;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
Key::Key(History *history) : _value(history) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Key::Key(Data::Folder *folder) : _value(folder) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Key::Key(not_null<History*> history) : _value(history) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Key::Key(not_null<Data::Folder*> folder) : _value(folder) {
|
||||||
|
}
|
||||||
|
|
||||||
not_null<Entry*> Key::entry() const {
|
not_null<Entry*> Key::entry() const {
|
||||||
if (const auto p = base::get_if<not_null<History*>>(&_value)) {
|
Expects(_value != nullptr);
|
||||||
return *p;
|
|
||||||
} else if (const auto p = base::get_if<not_null<Folder*>>(&_value)) {
|
return _value;
|
||||||
return *p;
|
|
||||||
}
|
|
||||||
Unexpected("Empty Dialogs::Key in Key::entry().");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
History *Key::history() const {
|
History *Key::history() const {
|
||||||
if (const auto p = base::get_if<not_null<History*>>(&_value)) {
|
return _value ? _value->asHistory() : nullptr;
|
||||||
return *p;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Folder *Key::folder() const {
|
Folder *Key::folder() const {
|
||||||
if (const auto p = base::get_if<not_null<Folder*>>(&_value)) {
|
return _value ? _value->asFolder() : nullptr;
|
||||||
return *p;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PeerData *Key::peer() const {
|
PeerData *Key::peer() const {
|
||||||
if (const auto p = base::get_if<not_null<History*>>(&_value)) {
|
if (const auto history = this->history()) {
|
||||||
return (*p)->peer;
|
return history->peer;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/value_ordering.h"
|
#include "base/value_ordering.h"
|
||||||
|
|
||||||
class History;
|
class History;
|
||||||
|
class PeerData;
|
||||||
|
|
||||||
namespace Data {
|
namespace Data {
|
||||||
class Folder;
|
class Folder;
|
||||||
|
@ -22,17 +23,17 @@ class Entry;
|
||||||
class Key {
|
class Key {
|
||||||
public:
|
public:
|
||||||
Key() = default;
|
Key() = default;
|
||||||
Key(History *history) : _value(history) {
|
Key(Entry *entry) : _value(entry) {
|
||||||
}
|
}
|
||||||
Key(not_null<History*> history) : _value(history) {
|
Key(History *history);
|
||||||
}
|
Key(Data::Folder *folder);
|
||||||
Key(Data::Folder *folder) : _value(folder) {
|
Key(not_null<Entry*> entry) : _value(entry) {
|
||||||
}
|
|
||||||
Key(not_null<Data::Folder*> folder) : _value(folder) {
|
|
||||||
}
|
}
|
||||||
|
Key(not_null<History*> history);
|
||||||
|
Key(not_null<Data::Folder*> folder);
|
||||||
|
|
||||||
explicit operator bool() const {
|
explicit operator bool() const {
|
||||||
return !!_value;
|
return (_value != nullptr);
|
||||||
}
|
}
|
||||||
not_null<Entry*> entry() const;
|
not_null<Entry*> entry() const;
|
||||||
History *history() const;
|
History *history() const;
|
||||||
|
@ -58,21 +59,13 @@ public:
|
||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
base::optional_variant<
|
|
||||||
not_null<History*>,
|
|
||||||
not_null<Data::Folder*>> raw() const {
|
|
||||||
return _value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not working :(
|
// Not working :(
|
||||||
//friend inline auto value_ordering_helper(const Key &key) {
|
//friend inline auto value_ordering_helper(const Key &key) {
|
||||||
// return key.value;
|
// return key.value;
|
||||||
//}
|
//}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
base::optional_variant<
|
Entry *_value = nullptr;
|
||||||
not_null<History*>,
|
|
||||||
not_null<Data::Folder*>> _value;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
|
#include "data/data_changes.h"
|
||||||
#include "facades.h"
|
#include "facades.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
@ -188,7 +189,8 @@ Widget::Widget(
|
||||||
refreshLoadMoreButton(mayBlock, isBlocked);
|
refreshLoadMoreButton(mayBlock, isBlocked);
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
session().data().newMessageSent(
|
session().changes().historyUpdates(
|
||||||
|
Data::HistoryUpdate::Flag::MessageSent
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
jumpToTop();
|
jumpToTop();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
@ -558,34 +560,6 @@ void Widget::setInnerFocus() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::refreshDialog(Key key) {
|
|
||||||
const auto creating = !key.entry()->inChatList();
|
|
||||||
_inner->refreshDialog(key);
|
|
||||||
const auto history = key.history();
|
|
||||||
if (creating && history && history->peer->migrateFrom()) {
|
|
||||||
if (const auto migrated = history->owner().historyLoaded(
|
|
||||||
history->peer->migrateFrom())) {
|
|
||||||
if (migrated->inChatList()) {
|
|
||||||
_inner->removeDialog(migrated);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::repaintDialogRow(
|
|
||||||
FilterId filterId,
|
|
||||||
not_null<Row*> row) {
|
|
||||||
_inner->repaintDialogRow(filterId, row);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::repaintDialogRow(RowDescriptor row) {
|
|
||||||
_inner->repaintDialogRow(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::refreshDialogRow(RowDescriptor row) {
|
|
||||||
_inner->refreshDialogRow(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::jumpToTop() {
|
void Widget::jumpToTop() {
|
||||||
if (session().supportMode()) {
|
if (session().supportMode()) {
|
||||||
return;
|
return;
|
||||||
|
@ -1743,10 +1717,6 @@ void Widget::scrollToEntry(const RowDescriptor &entry) {
|
||||||
_inner->scrollToEntry(entry);
|
_inner->scrollToEntry(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::removeDialog(Key key) {
|
|
||||||
_inner->removeDialog(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Widget::cancelSearchRequest() {
|
void Widget::cancelSearchRequest() {
|
||||||
session().api().request(base::take(_searchRequest)).cancel();
|
session().api().request(base::take(_searchRequest)).cancel();
|
||||||
if (_searchInHistoryRequest) {
|
if (_searchInHistoryRequest) {
|
||||||
|
|
|
@ -66,12 +66,6 @@ public:
|
||||||
void searchInChat(Key chat);
|
void searchInChat(Key chat);
|
||||||
void setInnerFocus();
|
void setInnerFocus();
|
||||||
|
|
||||||
void refreshDialog(Key key);
|
|
||||||
void removeDialog(Key key);
|
|
||||||
void repaintDialogRow(FilterId filterId, not_null<Row*> row);
|
|
||||||
void repaintDialogRow(RowDescriptor row);
|
|
||||||
void refreshDialogRow(RowDescriptor row);
|
|
||||||
|
|
||||||
void jumpToTop();
|
void jumpToTop();
|
||||||
|
|
||||||
void startWidthAnimation();
|
void startWidthAnimation();
|
||||||
|
@ -212,7 +206,7 @@ private:
|
||||||
object_ptr<Ui::HistoryDownButton> _scrollToTop;
|
object_ptr<Ui::HistoryDownButton> _scrollToTop;
|
||||||
|
|
||||||
Data::Folder *_openedFolder = nullptr;
|
Data::Folder *_openedFolder = nullptr;
|
||||||
Key _searchInChat;
|
Dialogs::Key _searchInChat;
|
||||||
History *_searchInMigrated = nullptr;
|
History *_searchInMigrated = nullptr;
|
||||||
UserData *_searchFromUser = nullptr;
|
UserData *_searchFromUser = nullptr;
|
||||||
QString _lastFilterText;
|
QString _lastFilterText;
|
||||||
|
|
|
@ -70,7 +70,7 @@ using UpdateFlag = Data::HistoryUpdate::Flag;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
History::History(not_null<Data::Session*> owner, PeerId peerId)
|
History::History(not_null<Data::Session*> owner, PeerId peerId)
|
||||||
: Entry(owner, this)
|
: Entry(owner, Type::History)
|
||||||
, peer(owner->peer(peerId))
|
, peer(owner->peer(peerId))
|
||||||
, cloudDraftTextCache(st::dialogsTextWidthMin)
|
, cloudDraftTextCache(st::dialogsTextWidthMin)
|
||||||
, _mute(owner->notifyIsMuted(peer))
|
, _mute(owner->notifyIsMuted(peer))
|
||||||
|
@ -88,9 +88,7 @@ void History::clearLastKeyboard() {
|
||||||
lastKeyboardHiddenId = 0;
|
lastKeyboardHiddenId = 0;
|
||||||
}
|
}
|
||||||
lastKeyboardId = 0;
|
lastKeyboardId = 0;
|
||||||
if (auto main = App::main()) {
|
session().changes().historyUpdated(this, UpdateFlag::BotKeyboard);
|
||||||
main->updateBotKeyboard(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lastKeyboardInited = true;
|
lastKeyboardInited = true;
|
||||||
lastKeyboardFrom = 0;
|
lastKeyboardFrom = 0;
|
||||||
|
@ -327,9 +325,7 @@ void History::applyCloudDraft() {
|
||||||
} else {
|
} else {
|
||||||
createLocalDraftFromCloud();
|
createLocalDraftFromCloud();
|
||||||
updateChatListSortPosition();
|
updateChatListSortPosition();
|
||||||
if (const auto main = App::main()) {
|
session().changes().historyUpdated(this, UpdateFlag::CloudDraft);
|
||||||
main->applyCloudDraft(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1759,13 +1755,13 @@ void History::outboxRead(MsgId upTo) {
|
||||||
setOutboxReadTill(upTo);
|
setOutboxReadTill(upTo);
|
||||||
if (const auto last = chatListMessage()) {
|
if (const auto last = chatListMessage()) {
|
||||||
if (last->out() && IsServerMsgId(last->id) && last->id <= upTo) {
|
if (last->out() && IsServerMsgId(last->id) && last->id <= upTo) {
|
||||||
if (const auto main = App::main()) {
|
session().changes().messageUpdated(
|
||||||
main->repaintDialogRow({ this, last->fullId() });
|
last,
|
||||||
}
|
Data::MessageUpdate::Flag::DialogRowRepaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateChatListEntry();
|
updateChatListEntry();
|
||||||
session().data().historyOutboxRead(this);
|
session().changes().historyUpdated(this, UpdateFlag::OutboxRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
void History::outboxRead(not_null<const HistoryItem*> wasRead) {
|
void History::outboxRead(not_null<const HistoryItem*> wasRead) {
|
||||||
|
|
|
@ -54,6 +54,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
#include "data/data_file_origin.h"
|
#include "data/data_file_origin.h"
|
||||||
#include "data/data_histories.h"
|
#include "data/data_histories.h"
|
||||||
|
#include "data/data_changes.h"
|
||||||
#include "data/stickers/data_stickers.h"
|
#include "data/stickers/data_stickers.h"
|
||||||
#include "facades.h"
|
#include "facades.h"
|
||||||
#include "app.h"
|
#include "app.h"
|
||||||
|
@ -198,10 +199,10 @@ HistoryInner::HistoryInner(
|
||||||
}) | rpl::start_with_next([this](not_null<const Element*> view) {
|
}) | rpl::start_with_next([this](not_null<const Element*> view) {
|
||||||
mouseActionUpdate();
|
mouseActionUpdate();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
session().data().historyOutboxReads(
|
session().changes().historyUpdates(
|
||||||
) | rpl::filter([=](not_null<History*> history) {
|
_history,
|
||||||
return (_history == history);
|
Data::HistoryUpdate::Flag::OutboxRead
|
||||||
}) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
update();
|
update();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,10 +265,9 @@ PeerData *HistoryItem::displayFrom() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryItem::invalidateChatListEntry() {
|
void HistoryItem::invalidateChatListEntry() {
|
||||||
if (const auto main = App::main()) {
|
history()->session().changes().messageUpdated(
|
||||||
// #TODO feeds search results
|
this,
|
||||||
main->refreshDialogRow({ history(), fullId() });
|
Data::MessageUpdate::Flag::DialogRowRefresh);
|
||||||
}
|
|
||||||
|
|
||||||
// invalidate cache for drawInDialog
|
// invalidate cache for drawInDialog
|
||||||
if (history()->textCachedFor == this) {
|
if (history()->textCachedFor == this) {
|
||||||
|
|
|
@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_game.h"
|
#include "data/data_game.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
#include "data/data_user.h"
|
#include "data/data_user.h"
|
||||||
|
#include "data/data_changes.h"
|
||||||
#include "window/notifications_manager.h"
|
#include "window/notifications_manager.h"
|
||||||
#include "window/window_session_controller.h"
|
#include "window/window_session_controller.h"
|
||||||
#include "storage/storage_shared_media.h"
|
#include "storage/storage_shared_media.h"
|
||||||
|
@ -748,10 +749,9 @@ void HistoryService::updateDependentText() {
|
||||||
// feed->updateChatListEntry();
|
// feed->updateChatListEntry();
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
if (const auto main = App::main()) {
|
history()->session().changes().messageUpdated(
|
||||||
// #TODO feeds search results
|
this,
|
||||||
main->repaintDialogRow({ history(), fullId() });
|
Data::MessageUpdate::Flag::DialogRowRepaint);
|
||||||
}
|
|
||||||
history()->owner().updateDependentMessages(this);
|
history()->owner().updateDependentMessages(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -554,18 +554,51 @@ HistoryWidget::HistoryWidget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
session().data().forwardDraftUpdates(
|
session().changes().historyUpdates(
|
||||||
) | rpl::filter([=](not_null<History*> history) {
|
Data::HistoryUpdate::Flag::MessageSent
|
||||||
return (_history == history.get());
|
| Data::HistoryUpdate::Flag::ForwardDraft
|
||||||
}) | rpl::start_with_next([=](not_null<History*> history) {
|
| Data::HistoryUpdate::Flag::BotKeyboard
|
||||||
updateForwarding();
|
| Data::HistoryUpdate::Flag::CloudDraft
|
||||||
|
| Data::HistoryUpdate::Flag::UnreadMentions
|
||||||
|
| Data::HistoryUpdate::Flag::UnreadView
|
||||||
|
| Data::HistoryUpdate::Flag::TopPromoted
|
||||||
|
| Data::HistoryUpdate::Flag::LocalMessages
|
||||||
|
) | rpl::filter([=](const Data::HistoryUpdate &update) {
|
||||||
|
return (_history == update.history.get());
|
||||||
|
}) | rpl::start_with_next([=](const Data::HistoryUpdate &update) {
|
||||||
|
if (update.flags & Data::HistoryUpdate::Flag::MessageSent) {
|
||||||
|
synteticScrollToY(_scroll->scrollTopMax());
|
||||||
|
}
|
||||||
|
if (update.flags & Data::HistoryUpdate::Flag::ForwardDraft) {
|
||||||
|
updateForwarding();
|
||||||
|
}
|
||||||
|
if (update.flags & Data::HistoryUpdate::Flag::BotKeyboard) {
|
||||||
|
updateBotKeyboard(update.history);
|
||||||
|
}
|
||||||
|
if (update.flags & Data::HistoryUpdate::Flag::CloudDraft) {
|
||||||
|
applyCloudDraft(update.history);
|
||||||
|
}
|
||||||
|
if (update.flags & Data::HistoryUpdate::Flag::LocalMessages) {
|
||||||
|
updateSendButtonType();
|
||||||
|
}
|
||||||
|
if (update.flags & Data::HistoryUpdate::Flag::UnreadMentions) {
|
||||||
|
updateUnreadMentionsVisibility();
|
||||||
|
}
|
||||||
|
if (update.flags & Data::HistoryUpdate::Flag::UnreadView) {
|
||||||
|
unreadCountUpdated();
|
||||||
|
}
|
||||||
|
if (update.flags & Data::HistoryUpdate::Flag::TopPromoted) {
|
||||||
|
updateHistoryGeometry();
|
||||||
|
updateControlsVisibility();
|
||||||
|
updateControlsGeometry();
|
||||||
|
this->update();
|
||||||
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
session().data().newMessageSent(
|
session().changes().messageUpdates(
|
||||||
) | rpl::filter([=](not_null<History*> history) {
|
Data::MessageUpdate::Flag::Edited
|
||||||
return (_history == history.get());
|
) | rpl::start_with_next([=](const Data::MessageUpdate &update) {
|
||||||
}) | rpl::start_with_next([=] {
|
itemEdited(update.item);
|
||||||
synteticScrollToY(_scroll->scrollTopMax());
|
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
subscribe(Media::Player::instance()->switchToNextNotifier(), [this](const Media::Player::Instance::Switch &pair) {
|
subscribe(Media::Player::instance()->switchToNextNotifier(), [this](const Media::Player::Instance::Switch &pair) {
|
||||||
|
@ -574,33 +607,6 @@ HistoryWidget::HistoryWidget(
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
session().changes().historyUpdates(
|
|
||||||
Data::HistoryUpdate::Flag::UnreadMentions
|
|
||||||
| Data::HistoryUpdate::Flag::UnreadView
|
|
||||||
| Data::HistoryUpdate::Flag::TopPromoted
|
|
||||||
| Data::HistoryUpdate::Flag::LocalMessages
|
|
||||||
) | rpl::filter([=](const Data::HistoryUpdate &update) {
|
|
||||||
return (update.history->peer.get() == _peer);
|
|
||||||
}) | rpl::map([](const Data::HistoryUpdate &update) {
|
|
||||||
return update.flags;
|
|
||||||
}) | rpl::start_with_next([=](Data::HistoryUpdate::Flags flags) {
|
|
||||||
if (flags & Data::HistoryUpdate::Flag::LocalMessages) {
|
|
||||||
updateSendButtonType();
|
|
||||||
}
|
|
||||||
if (flags & Data::HistoryUpdate::Flag::UnreadMentions) {
|
|
||||||
updateUnreadMentionsVisibility();
|
|
||||||
}
|
|
||||||
if (flags & Data::HistoryUpdate::Flag::UnreadView) {
|
|
||||||
unreadCountUpdated();
|
|
||||||
}
|
|
||||||
if (flags & Data::HistoryUpdate::Flag::TopPromoted) {
|
|
||||||
updateHistoryGeometry();
|
|
||||||
updateControlsVisibility();
|
|
||||||
updateControlsGeometry();
|
|
||||||
this->update();
|
|
||||||
}
|
|
||||||
}, lifetime());
|
|
||||||
|
|
||||||
using UpdateFlag = Data::PeerUpdate::Flag;
|
using UpdateFlag = Data::PeerUpdate::Flag;
|
||||||
session().changes().peerUpdates(
|
session().changes().peerUpdates(
|
||||||
UpdateFlag::Rights
|
UpdateFlag::Rights
|
||||||
|
@ -727,6 +733,7 @@ HistoryWidget::HistoryWidget(
|
||||||
}
|
}
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
|
subscribeToUploader();
|
||||||
setupScheduledToggle();
|
setupScheduledToggle();
|
||||||
orderWidgets();
|
orderWidgets();
|
||||||
setupShortcuts();
|
setupShortcuts();
|
||||||
|
@ -3177,7 +3184,9 @@ void HistoryWidget::send(Api::SendOptions options) {
|
||||||
if (!_keyboard->hasMarkup() && _keyboard->forceReply() && !_kbReplyTo) {
|
if (!_keyboard->hasMarkup() && _keyboard->forceReply() && !_kbReplyTo) {
|
||||||
toggleKeyboard();
|
toggleKeyboard();
|
||||||
}
|
}
|
||||||
session().data().newMessageSent(_history);
|
session().changes().historyUpdated(
|
||||||
|
_history,
|
||||||
|
Data::HistoryUpdate::Flag::MessageSent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::sendWithModifiers(Qt::KeyboardModifiers modifiers) {
|
void HistoryWidget::sendWithModifiers(Qt::KeyboardModifiers modifiers) {
|
||||||
|
@ -4640,26 +4649,35 @@ void HistoryWidget::uploadFile(
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::subscribeToUploader() {
|
void HistoryWidget::subscribeToUploader() {
|
||||||
if (_uploaderSubscriptions) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
using namespace Storage;
|
using namespace Storage;
|
||||||
|
|
||||||
session().uploader().photoReady(
|
session().uploader().photoReady(
|
||||||
) | rpl::start_with_next([=](const UploadedPhoto &data) {
|
) | rpl::start_with_next([=](const UploadedPhoto &data) {
|
||||||
if (data.edit) {
|
if (data.edit) {
|
||||||
photoEdited(data.fullId, data.options, data.file);
|
session().api().editUploadedFile(
|
||||||
|
data.fullId,
|
||||||
|
data.file,
|
||||||
|
std::nullopt,
|
||||||
|
data.options,
|
||||||
|
false);
|
||||||
} else {
|
} else {
|
||||||
photoUploaded(data.fullId, data.options, data.file);
|
session().api().sendUploadedPhoto(
|
||||||
|
data.fullId,
|
||||||
|
data.file,
|
||||||
|
data.options);
|
||||||
}
|
}
|
||||||
}, _uploaderSubscriptions);
|
}, lifetime());
|
||||||
|
|
||||||
session().uploader().photoProgress(
|
session().uploader().photoProgress(
|
||||||
) | rpl::start_with_next([=](const FullMsgId &fullId) {
|
) | rpl::start_with_next([=](const FullMsgId &fullId) {
|
||||||
photoProgress(fullId);
|
photoProgress(fullId);
|
||||||
}, _uploaderSubscriptions);
|
}, lifetime());
|
||||||
|
|
||||||
session().uploader().photoFailed(
|
session().uploader().photoFailed(
|
||||||
) | rpl::start_with_next([=](const FullMsgId &fullId) {
|
) | rpl::start_with_next([=](const FullMsgId &fullId) {
|
||||||
photoFailed(fullId);
|
photoFailed(fullId);
|
||||||
}, _uploaderSubscriptions);
|
}, lifetime());
|
||||||
|
|
||||||
session().uploader().documentReady(
|
session().uploader().documentReady(
|
||||||
) | rpl::start_with_next([=](const UploadedDocument &data) {
|
) | rpl::start_with_next([=](const UploadedDocument &data) {
|
||||||
if (data.edit) {
|
if (data.edit) {
|
||||||
|
@ -4667,7 +4685,8 @@ void HistoryWidget::subscribeToUploader() {
|
||||||
} else {
|
} else {
|
||||||
documentUploaded(data.fullId, data.options, data.file);
|
documentUploaded(data.fullId, data.options, data.file);
|
||||||
}
|
}
|
||||||
}, _uploaderSubscriptions);
|
}, lifetime());
|
||||||
|
|
||||||
session().uploader().thumbDocumentReady(
|
session().uploader().thumbDocumentReady(
|
||||||
) | rpl::start_with_next([=](const UploadedThumbDocument &data) {
|
) | rpl::start_with_next([=](const UploadedThumbDocument &data) {
|
||||||
thumbDocumentUploaded(
|
thumbDocumentUploaded(
|
||||||
|
@ -4676,222 +4695,17 @@ void HistoryWidget::subscribeToUploader() {
|
||||||
data.file,
|
data.file,
|
||||||
data.thumb,
|
data.thumb,
|
||||||
data.edit);
|
data.edit);
|
||||||
}, _uploaderSubscriptions);
|
}, lifetime());
|
||||||
|
|
||||||
session().uploader().documentProgress(
|
session().uploader().documentProgress(
|
||||||
) | rpl::start_with_next([=](const FullMsgId &fullId) {
|
) | rpl::start_with_next([=](const FullMsgId &fullId) {
|
||||||
documentProgress(fullId);
|
documentProgress(fullId);
|
||||||
}, _uploaderSubscriptions);
|
}, lifetime());
|
||||||
|
|
||||||
session().uploader().documentFailed(
|
session().uploader().documentFailed(
|
||||||
) | rpl::start_with_next([=](const FullMsgId &fullId) {
|
) | rpl::start_with_next([=](const FullMsgId &fullId) {
|
||||||
documentFailed(fullId);
|
documentFailed(fullId);
|
||||||
}, _uploaderSubscriptions);
|
}, lifetime());
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::sendFileConfirmed(
|
|
||||||
const std::shared_ptr<FileLoadResult> &file,
|
|
||||||
const std::optional<FullMsgId> &oldId) {
|
|
||||||
const auto isEditing = oldId.has_value();
|
|
||||||
const auto channelId = peerToChannel(file->to.peer);
|
|
||||||
const auto lastKeyboardUsed = lastForceReplyReplied(FullMsgId(
|
|
||||||
channelId,
|
|
||||||
file->to.replyTo));
|
|
||||||
|
|
||||||
const auto newId = oldId.value_or(
|
|
||||||
FullMsgId(channelId, session().data().nextLocalMessageId()));
|
|
||||||
auto groupId = file->album ? file->album->groupId : uint64(0);
|
|
||||||
if (file->album) {
|
|
||||||
const auto proj = [](const SendingAlbum::Item &item) {
|
|
||||||
return item.taskId;
|
|
||||||
};
|
|
||||||
const auto it = ranges::find(file->album->items, file->taskId, proj);
|
|
||||||
Assert(it != file->album->items.end());
|
|
||||||
|
|
||||||
it->msgId = newId;
|
|
||||||
}
|
|
||||||
subscribeToUploader();
|
|
||||||
file->edit = isEditing;
|
|
||||||
session().uploader().upload(newId, file);
|
|
||||||
|
|
||||||
const auto itemToEdit = isEditing
|
|
||||||
? session().data().message(newId)
|
|
||||||
: nullptr;
|
|
||||||
|
|
||||||
const auto history = session().data().history(file->to.peer);
|
|
||||||
const auto peer = history->peer;
|
|
||||||
|
|
||||||
auto action = Api::SendAction(history);
|
|
||||||
action.options = file->to.options;
|
|
||||||
action.clearDraft = false;
|
|
||||||
action.replyTo = file->to.replyTo;
|
|
||||||
action.generateLocal = true;
|
|
||||||
session().api().sendAction(action);
|
|
||||||
|
|
||||||
auto caption = TextWithEntities{
|
|
||||||
file->caption.text,
|
|
||||||
TextUtilities::ConvertTextTagsToEntities(file->caption.tags)
|
|
||||||
};
|
|
||||||
const auto prepareFlags = Ui::ItemTextOptions(
|
|
||||||
history,
|
|
||||||
session().user()).flags;
|
|
||||||
TextUtilities::PrepareForSending(caption, prepareFlags);
|
|
||||||
TextUtilities::Trim(caption);
|
|
||||||
auto localEntities = Api::EntitiesToMTP(&session(), caption.entities);
|
|
||||||
|
|
||||||
if (itemToEdit) {
|
|
||||||
if (const auto id = itemToEdit->groupId()) {
|
|
||||||
groupId = id.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto flags = (isEditing ? MTPDmessage::Flags() : NewMessageFlags(peer))
|
|
||||||
| MTPDmessage::Flag::f_entities
|
|
||||||
| MTPDmessage::Flag::f_media;
|
|
||||||
auto clientFlags = NewMessageClientFlags();
|
|
||||||
if (file->to.replyTo) {
|
|
||||||
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
|
|
||||||
}
|
|
||||||
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
|
|
||||||
const auto silentPost = file->to.options.silent;
|
|
||||||
Api::FillMessagePostFlags(action, peer, flags);
|
|
||||||
if (silentPost) {
|
|
||||||
flags |= MTPDmessage::Flag::f_silent;
|
|
||||||
}
|
|
||||||
if (groupId) {
|
|
||||||
flags |= MTPDmessage::Flag::f_grouped_id;
|
|
||||||
}
|
|
||||||
if (file->to.options.scheduled) {
|
|
||||||
flags |= MTPDmessage::Flag::f_from_scheduled;
|
|
||||||
} else {
|
|
||||||
clientFlags |= MTPDmessage_ClientFlag::f_local_history_entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto messageFromId = channelPost ? 0 : session().userId();
|
|
||||||
const auto messagePostAuthor = channelPost
|
|
||||||
? session().user()->name
|
|
||||||
: QString();
|
|
||||||
|
|
||||||
if (file->type == SendMediaType::Photo) {
|
|
||||||
const auto photoFlags = MTPDmessageMediaPhoto::Flag::f_photo | 0;
|
|
||||||
const auto photo = MTP_messageMediaPhoto(
|
|
||||||
MTP_flags(photoFlags),
|
|
||||||
file->photo,
|
|
||||||
MTPint());
|
|
||||||
|
|
||||||
const auto mtpMessage = MTP_message(
|
|
||||||
MTP_flags(flags),
|
|
||||||
MTP_int(newId.msg),
|
|
||||||
MTP_int(messageFromId),
|
|
||||||
peerToMTP(file->to.peer),
|
|
||||||
MTPMessageFwdHeader(),
|
|
||||||
MTPint(),
|
|
||||||
MTP_int(file->to.replyTo),
|
|
||||||
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
|
||||||
MTP_string(caption.text),
|
|
||||||
photo,
|
|
||||||
MTPReplyMarkup(),
|
|
||||||
localEntities,
|
|
||||||
MTP_int(1),
|
|
||||||
MTPint(),
|
|
||||||
MTP_string(messagePostAuthor),
|
|
||||||
MTP_long(groupId),
|
|
||||||
//MTPMessageReactions(),
|
|
||||||
MTPVector<MTPRestrictionReason>());
|
|
||||||
|
|
||||||
if (itemToEdit) {
|
|
||||||
itemToEdit->savePreviousMedia();
|
|
||||||
itemToEdit->applyEdition(mtpMessage.c_message());
|
|
||||||
} else {
|
|
||||||
history->addNewMessage(
|
|
||||||
mtpMessage,
|
|
||||||
clientFlags,
|
|
||||||
NewMessageType::Unread);
|
|
||||||
}
|
|
||||||
} else if (file->type == SendMediaType::File) {
|
|
||||||
const auto documentFlags = MTPDmessageMediaDocument::Flag::f_document | 0;
|
|
||||||
const auto document = MTP_messageMediaDocument(
|
|
||||||
MTP_flags(documentFlags),
|
|
||||||
file->document,
|
|
||||||
MTPint());
|
|
||||||
|
|
||||||
const auto mtpMessage = MTP_message(
|
|
||||||
MTP_flags(flags),
|
|
||||||
MTP_int(newId.msg),
|
|
||||||
MTP_int(messageFromId),
|
|
||||||
peerToMTP(file->to.peer),
|
|
||||||
MTPMessageFwdHeader(),
|
|
||||||
MTPint(),
|
|
||||||
MTP_int(file->to.replyTo),
|
|
||||||
MTP_int(HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
|
||||||
MTP_string(caption.text),
|
|
||||||
document,
|
|
||||||
MTPReplyMarkup(),
|
|
||||||
localEntities,
|
|
||||||
MTP_int(1),
|
|
||||||
MTPint(),
|
|
||||||
MTP_string(messagePostAuthor),
|
|
||||||
MTP_long(groupId),
|
|
||||||
//MTPMessageReactions(),
|
|
||||||
MTPVector<MTPRestrictionReason>());
|
|
||||||
|
|
||||||
if (itemToEdit) {
|
|
||||||
itemToEdit->savePreviousMedia();
|
|
||||||
itemToEdit->applyEdition(mtpMessage.c_message());
|
|
||||||
} else {
|
|
||||||
history->addNewMessage(
|
|
||||||
mtpMessage,
|
|
||||||
clientFlags,
|
|
||||||
NewMessageType::Unread);
|
|
||||||
}
|
|
||||||
} else if (file->type == SendMediaType::Audio) {
|
|
||||||
if (!peer->isChannel() || peer->isMegagroup()) {
|
|
||||||
flags |= MTPDmessage::Flag::f_media_unread;
|
|
||||||
}
|
|
||||||
const auto documentFlags = MTPDmessageMediaDocument::Flag::f_document | 0;
|
|
||||||
const auto document = MTP_messageMediaDocument(
|
|
||||||
MTP_flags(documentFlags),
|
|
||||||
file->document,
|
|
||||||
MTPint());
|
|
||||||
history->addNewMessage(
|
|
||||||
MTP_message(
|
|
||||||
MTP_flags(flags),
|
|
||||||
MTP_int(newId.msg),
|
|
||||||
MTP_int(messageFromId),
|
|
||||||
peerToMTP(file->to.peer),
|
|
||||||
MTPMessageFwdHeader(),
|
|
||||||
MTPint(),
|
|
||||||
MTP_int(file->to.replyTo),
|
|
||||||
MTP_int(
|
|
||||||
HistoryItem::NewMessageDate(file->to.options.scheduled)),
|
|
||||||
MTP_string(caption.text),
|
|
||||||
document,
|
|
||||||
MTPReplyMarkup(),
|
|
||||||
localEntities,
|
|
||||||
MTP_int(1),
|
|
||||||
MTPint(),
|
|
||||||
MTP_string(messagePostAuthor),
|
|
||||||
MTP_long(groupId),
|
|
||||||
//MTPMessageReactions(),
|
|
||||||
MTPVector<MTPRestrictionReason>()),
|
|
||||||
clientFlags,
|
|
||||||
NewMessageType::Unread);
|
|
||||||
// Voices can't be edited.
|
|
||||||
} else {
|
|
||||||
Unexpected("Type in sendFilesConfirmed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isEditing) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
session().data().sendHistoryChangeNotifications();
|
|
||||||
session().data().newMessageSent(history);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::photoUploaded(
|
|
||||||
const FullMsgId &newId,
|
|
||||||
Api::SendOptions options,
|
|
||||||
const MTPInputFile &file) {
|
|
||||||
session().api().sendUploadedPhoto(newId, file, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::documentUploaded(
|
void HistoryWidget::documentUploaded(
|
||||||
|
@ -4908,13 +4722,6 @@ void HistoryWidget::documentEdited(
|
||||||
session().api().editUploadedFile(newId, file, std::nullopt, options, true);
|
session().api().editUploadedFile(newId, file, std::nullopt, options, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::photoEdited(
|
|
||||||
const FullMsgId &newId,
|
|
||||||
Api::SendOptions options,
|
|
||||||
const MTPInputFile &file) {
|
|
||||||
session().api().editUploadedFile(newId, file, std::nullopt, options, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void HistoryWidget::thumbDocumentUploaded(
|
void HistoryWidget::thumbDocumentUploaded(
|
||||||
const FullMsgId &newId,
|
const FullMsgId &newId,
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
|
@ -5151,8 +4958,8 @@ void HistoryWidget::itemRemoved(not_null<const HistoryItem*> item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HistoryWidget::itemEdited(HistoryItem *item) {
|
void HistoryWidget::itemEdited(not_null<HistoryItem*> item) {
|
||||||
if (item == _replyEditMsg) {
|
if (item.get() == _replyEditMsg) {
|
||||||
updateReplyEditTexts(true);
|
updateReplyEditTexts(true);
|
||||||
}
|
}
|
||||||
if (_pinnedBar && item->id == _pinnedBar->msgId) {
|
if (_pinnedBar && item->id == _pinnedBar->msgId) {
|
||||||
|
|
|
@ -172,7 +172,7 @@ public:
|
||||||
crl::time highlightStartTime(not_null<const HistoryItem*> item) const;
|
crl::time highlightStartTime(not_null<const HistoryItem*> item) const;
|
||||||
|
|
||||||
MessageIdsList getSelectedItems() const;
|
MessageIdsList getSelectedItems() const;
|
||||||
void itemEdited(HistoryItem *item);
|
void itemEdited(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
void updateScrollColors();
|
void updateScrollColors();
|
||||||
|
|
||||||
|
@ -477,10 +477,6 @@ private:
|
||||||
|
|
||||||
void subscribeToUploader();
|
void subscribeToUploader();
|
||||||
|
|
||||||
void photoUploaded(
|
|
||||||
const FullMsgId &msgId,
|
|
||||||
Api::SendOptions options,
|
|
||||||
const MTPInputFile &file);
|
|
||||||
void photoProgress(const FullMsgId &msgId);
|
void photoProgress(const FullMsgId &msgId);
|
||||||
void photoFailed(const FullMsgId &msgId);
|
void photoFailed(const FullMsgId &msgId);
|
||||||
void documentUploaded(
|
void documentUploaded(
|
||||||
|
@ -501,11 +497,6 @@ private:
|
||||||
Api::SendOptions options,
|
Api::SendOptions options,
|
||||||
const MTPInputFile &file);
|
const MTPInputFile &file);
|
||||||
|
|
||||||
void photoEdited(
|
|
||||||
const FullMsgId &msgId,
|
|
||||||
Api::SendOptions options,
|
|
||||||
const MTPInputFile &file);
|
|
||||||
|
|
||||||
void itemRemoved(not_null<const HistoryItem*> item);
|
void itemRemoved(not_null<const HistoryItem*> item);
|
||||||
|
|
||||||
// Updates position of controls around the message field,
|
// Updates position of controls around the message field,
|
||||||
|
@ -767,8 +758,6 @@ private:
|
||||||
int _recordingSamples = 0;
|
int _recordingSamples = 0;
|
||||||
int _recordCancelWidth;
|
int _recordCancelWidth;
|
||||||
|
|
||||||
rpl::lifetime _uploaderSubscriptions;
|
|
||||||
|
|
||||||
// This can animate for a very long time (like in music playing),
|
// This can animate for a very long time (like in music playing),
|
||||||
// so it should be a Basic, not a Simple animation.
|
// so it should be a Basic, not a Simple animation.
|
||||||
Ui::Animations::Basic _recordingAnimation;
|
Ui::Animations::Basic _recordingAnimation;
|
||||||
|
|
|
@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "data/data_peer_values.h"
|
#include "data/data_peer_values.h"
|
||||||
#include "data/data_drafts.h"
|
#include "data/data_drafts.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
|
#include "data/data_changes.h"
|
||||||
#include "data/data_media_types.h"
|
#include "data/data_media_types.h"
|
||||||
#include "data/data_folder.h"
|
#include "data/data_folder.h"
|
||||||
#include "data/data_channel.h"
|
#include "data/data_channel.h"
|
||||||
|
@ -281,8 +282,10 @@ MainWidget::MainWidget(
|
||||||
[this] { updateControlsGeometry(); },
|
[this] { updateControlsGeometry(); },
|
||||||
lifetime());
|
lifetime());
|
||||||
|
|
||||||
session().data().newMessageSent(
|
session().changes().historyUpdates(
|
||||||
) | rpl::start_with_next([=](not_null<History*> history) {
|
Data::HistoryUpdate::Flag::MessageSent
|
||||||
|
) | rpl::start_with_next([=](const Data::HistoryUpdate &update) {
|
||||||
|
const auto history = update.history;
|
||||||
history->forgetScrollState();
|
history->forgetScrollState();
|
||||||
if (const auto from = history->peer->migrateFrom()) {
|
if (const auto from = history->peer->migrateFrom()) {
|
||||||
if (const auto migrated = history->owner().historyLoaded(from)) {
|
if (const auto migrated = history->owner().historyLoaded(from)) {
|
||||||
|
@ -758,10 +761,6 @@ bool MainWidget::selectingPeer() const {
|
||||||
return _hider ? true : false;
|
return _hider ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::removeDialog(Dialogs::Key key) {
|
|
||||||
_dialogs->removeDialog(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::cacheBackground() {
|
void MainWidget::cacheBackground() {
|
||||||
if (Window::Theme::Background()->colorForFill()) {
|
if (Window::Theme::Background()->colorForFill()) {
|
||||||
return;
|
return;
|
||||||
|
@ -850,13 +849,6 @@ void MainWidget::searchMessages(const QString &query, Dialogs::Key inChat) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::itemEdited(not_null<HistoryItem*> item) {
|
|
||||||
if (_history->peer() == item->history()->peer
|
|
||||||
|| (_history->peer() && _history->peer() == item->history()->peer->migrateTo())) {
|
|
||||||
_history->itemEdited(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::handleAudioUpdate(const Media::Player::TrackState &state) {
|
void MainWidget::handleAudioUpdate(const Media::Player::TrackState &state) {
|
||||||
using State = Media::Player::State;
|
using State = Media::Player::State;
|
||||||
const auto document = state.id.audio();
|
const auto document = state.id.audio();
|
||||||
|
@ -1087,12 +1079,6 @@ void MainWidget::inlineResultLoadFailed(FileLoader *loader, bool started) {
|
||||||
//Ui::repaintInlineItem();
|
//Ui::repaintInlineItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::onSendFileConfirm(
|
|
||||||
const std::shared_ptr<FileLoadResult> &file,
|
|
||||||
const std::optional<FullMsgId> &oldId) {
|
|
||||||
_history->sendFileConfirmed(file, oldId);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MainWidget::sendExistingDocument(not_null<DocumentData*> document) {
|
bool MainWidget::sendExistingDocument(not_null<DocumentData*> document) {
|
||||||
return _history->sendExistingDocument(document);
|
return _history->sendExistingDocument(document);
|
||||||
}
|
}
|
||||||
|
@ -1234,10 +1220,6 @@ Image *MainWidget::newBackgroundThumb() {
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::updateBotKeyboard(History *h) {
|
|
||||||
_history->updateBotKeyboard(h);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::pushReplyReturn(not_null<HistoryItem*> item) {
|
void MainWidget::pushReplyReturn(not_null<HistoryItem*> item) {
|
||||||
_history->pushReplyReturn(item);
|
_history->pushReplyReturn(item);
|
||||||
}
|
}
|
||||||
|
@ -1339,10 +1321,6 @@ void MainWidget::viewsIncrementFail(const RPCError &error, mtpRequestId requestI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::refreshDialog(Dialogs::Key key) {
|
|
||||||
_dialogs->refreshDialog(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::choosePeer(PeerId peerId, MsgId showAtMsgId) {
|
void MainWidget::choosePeer(PeerId peerId, MsgId showAtMsgId) {
|
||||||
if (selectingPeer()) {
|
if (selectingPeer()) {
|
||||||
_hider->offerPeer(peerId);
|
_hider->offerPeer(peerId);
|
||||||
|
@ -1956,20 +1934,6 @@ QPixmap MainWidget::grabForShowAnimation(const Window::SectionSlideParams ¶m
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::repaintDialogRow(
|
|
||||||
FilterId filterId,
|
|
||||||
not_null<Dialogs::Row*> row) {
|
|
||||||
_dialogs->repaintDialogRow(filterId, row);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::repaintDialogRow(Dialogs::RowDescriptor row) {
|
|
||||||
_dialogs->repaintDialogRow(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::refreshDialogRow(Dialogs::RowDescriptor row) {
|
|
||||||
_dialogs->refreshDialogRow(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::windowShown() {
|
void MainWidget::windowShown() {
|
||||||
_history->windowShown();
|
_history->windowShown();
|
||||||
}
|
}
|
||||||
|
@ -2801,10 +2765,6 @@ int32 MainWidget::dlgsWidth() const {
|
||||||
return _dialogs->width();
|
return _dialogs->width();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWidget::applyCloudDraft(History *history) {
|
|
||||||
_history->applyCloudDraft(history);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWidget::saveFieldToHistoryLocalDraft() {
|
void MainWidget::saveFieldToHistoryLocalDraft() {
|
||||||
_history->saveFieldToHistoryLocalDraft();
|
_history->saveFieldToHistoryLocalDraft();
|
||||||
}
|
}
|
||||||
|
|
|
@ -129,12 +129,6 @@ public:
|
||||||
bool started();
|
bool started();
|
||||||
void activate();
|
void activate();
|
||||||
|
|
||||||
void refreshDialog(Dialogs::Key key);
|
|
||||||
void removeDialog(Dialogs::Key key);
|
|
||||||
void repaintDialogRow(FilterId filterId, not_null<Dialogs::Row*> row);
|
|
||||||
void repaintDialogRow(Dialogs::RowDescriptor row);
|
|
||||||
void refreshDialogRow(Dialogs::RowDescriptor row);
|
|
||||||
|
|
||||||
void windowShown();
|
void windowShown();
|
||||||
|
|
||||||
void dialogsToUp();
|
void dialogsToUp();
|
||||||
|
@ -155,15 +149,11 @@ public:
|
||||||
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms);
|
QPixmap grabForShowAnimation(const Window::SectionSlideParams ¶ms);
|
||||||
void checkMainSectionToLayer();
|
void checkMainSectionToLayer();
|
||||||
|
|
||||||
void onSendFileConfirm(
|
|
||||||
const std::shared_ptr<FileLoadResult> &file,
|
|
||||||
const std::optional<FullMsgId> &oldId);
|
|
||||||
bool sendExistingDocument(not_null<DocumentData*> sticker);
|
bool sendExistingDocument(not_null<DocumentData*> sticker);
|
||||||
|
|
||||||
bool isActive() const;
|
bool isActive() const;
|
||||||
[[nodiscard]] bool doWeMarkAsRead() const;
|
[[nodiscard]] bool doWeMarkAsRead() const;
|
||||||
|
|
||||||
void applyCloudDraft(History *history);
|
|
||||||
void saveFieldToHistoryLocalDraft();
|
void saveFieldToHistoryLocalDraft();
|
||||||
|
|
||||||
int32 dlgsWidth() const;
|
int32 dlgsWidth() const;
|
||||||
|
@ -201,7 +191,6 @@ public:
|
||||||
bool insertBotCommand(const QString &cmd);
|
bool insertBotCommand(const QString &cmd);
|
||||||
|
|
||||||
void searchMessages(const QString &query, Dialogs::Key inChat);
|
void searchMessages(const QString &query, Dialogs::Key inChat);
|
||||||
void itemEdited(not_null<HistoryItem*> item);
|
|
||||||
|
|
||||||
QPixmap cachedBackground(const QRect &forRect, int &x, int &y);
|
QPixmap cachedBackground(const QRect &forRect, int &x, int &y);
|
||||||
void updateScrollColors();
|
void updateScrollColors();
|
||||||
|
@ -214,8 +203,6 @@ public:
|
||||||
void checkChatBackground();
|
void checkChatBackground();
|
||||||
Image *newBackgroundThumb();
|
Image *newBackgroundThumb();
|
||||||
|
|
||||||
void updateBotKeyboard(History *h);
|
|
||||||
|
|
||||||
void pushReplyReturn(not_null<HistoryItem*> item);
|
void pushReplyReturn(not_null<HistoryItem*> item);
|
||||||
|
|
||||||
// Does offerPeer or showPeerHistory.
|
// Does offerPeer or showPeerHistory.
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "storage/localimageloader.h"
|
#include "storage/localimageloader.h"
|
||||||
|
|
||||||
#include "api/api_text_entities.h"
|
#include "api/api_text_entities.h"
|
||||||
|
#include "api/api_sending.h"
|
||||||
#include "data/data_document.h"
|
#include "data/data_document.h"
|
||||||
#include "data/data_session.h"
|
#include "data/data_session.h"
|
||||||
#include "core/file_utilities.h"
|
#include "core/file_utilities.h"
|
||||||
|
@ -476,7 +477,7 @@ void FileLoadResult::setThumbData(const QByteArray &thumbdata) {
|
||||||
|
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(
|
FileLoadTask::FileLoadTask(
|
||||||
MTP::DcId dcId,
|
not_null<Main::Session*> session,
|
||||||
const QString &filepath,
|
const QString &filepath,
|
||||||
const QByteArray &content,
|
const QByteArray &content,
|
||||||
std::unique_ptr<FileMediaInformation> information,
|
std::unique_ptr<FileMediaInformation> information,
|
||||||
|
@ -486,7 +487,8 @@ FileLoadTask::FileLoadTask(
|
||||||
std::shared_ptr<SendingAlbum> album,
|
std::shared_ptr<SendingAlbum> album,
|
||||||
MsgId msgIdToEdit)
|
MsgId msgIdToEdit)
|
||||||
: _id(rand_value<uint64>())
|
: _id(rand_value<uint64>())
|
||||||
, _dcId(dcId)
|
, _session(session)
|
||||||
|
, _dcId(session->mainDcId())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _album(std::move(album))
|
, _album(std::move(album))
|
||||||
, _filepath(filepath)
|
, _filepath(filepath)
|
||||||
|
@ -499,14 +501,15 @@ FileLoadTask::FileLoadTask(
|
||||||
}
|
}
|
||||||
|
|
||||||
FileLoadTask::FileLoadTask(
|
FileLoadTask::FileLoadTask(
|
||||||
MTP::DcId dcId,
|
not_null<Main::Session*> session,
|
||||||
const QByteArray &voice,
|
const QByteArray &voice,
|
||||||
int32 duration,
|
int32 duration,
|
||||||
const VoiceWaveform &waveform,
|
const VoiceWaveform &waveform,
|
||||||
const FileLoadTo &to,
|
const FileLoadTo &to,
|
||||||
const TextWithTags &caption)
|
const TextWithTags &caption)
|
||||||
: _id(rand_value<uint64>())
|
: _id(rand_value<uint64>())
|
||||||
, _dcId(dcId)
|
, _session(session)
|
||||||
|
, _dcId(session->mainDcId())
|
||||||
, _to(to)
|
, _to(to)
|
||||||
, _content(voice)
|
, _content(voice)
|
||||||
, _duration(duration)
|
, _duration(duration)
|
||||||
|
@ -965,13 +968,13 @@ void FileLoadTask::finish() {
|
||||||
tr::lng_send_image_too_large(tr::now, lt_name, _filepath)),
|
tr::lng_send_image_too_large(tr::now, lt_name, _filepath)),
|
||||||
Ui::LayerOption::KeepOther);
|
Ui::LayerOption::KeepOther);
|
||||||
removeFromAlbum();
|
removeFromAlbum();
|
||||||
} else if (App::main()) {
|
} else if (const auto session = _session.get()) {
|
||||||
const auto fullId = _msgIdToEdit
|
const auto fullId = _msgIdToEdit
|
||||||
? std::make_optional(FullMsgId(
|
? std::make_optional(FullMsgId(
|
||||||
peerToChannel(_to.peer),
|
peerToChannel(_to.peer),
|
||||||
_msgIdToEdit))
|
_msgIdToEdit))
|
||||||
: std::nullopt;
|
: std::nullopt;
|
||||||
App::main()->onSendFileConfirm(_result, fullId);
|
Api::SendConfirmedFile(session, _result, fullId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -270,7 +270,7 @@ public:
|
||||||
std::unique_ptr<FileMediaInformation> &result);
|
std::unique_ptr<FileMediaInformation> &result);
|
||||||
|
|
||||||
FileLoadTask(
|
FileLoadTask(
|
||||||
MTP::DcId dcId,
|
not_null<Main::Session*> session,
|
||||||
const QString &filepath,
|
const QString &filepath,
|
||||||
const QByteArray &content,
|
const QByteArray &content,
|
||||||
std::unique_ptr<FileMediaInformation> information,
|
std::unique_ptr<FileMediaInformation> information,
|
||||||
|
@ -280,7 +280,7 @@ public:
|
||||||
std::shared_ptr<SendingAlbum> album = nullptr,
|
std::shared_ptr<SendingAlbum> album = nullptr,
|
||||||
MsgId msgIdToEdit = 0);
|
MsgId msgIdToEdit = 0);
|
||||||
FileLoadTask(
|
FileLoadTask(
|
||||||
MTP::DcId dcId,
|
not_null<Main::Session*> session,
|
||||||
const QByteArray &voice,
|
const QByteArray &voice,
|
||||||
int32 duration,
|
int32 duration,
|
||||||
const VoiceWaveform &waveform,
|
const VoiceWaveform &waveform,
|
||||||
|
@ -319,6 +319,7 @@ private:
|
||||||
void removeFromAlbum();
|
void removeFromAlbum();
|
||||||
|
|
||||||
uint64 _id = 0;
|
uint64 _id = 0;
|
||||||
|
base::weak_ptr<Main::Session> _session;
|
||||||
MTP::DcId _dcId = 0;
|
MTP::DcId _dcId = 0;
|
||||||
FileLoadTo _to;
|
FileLoadTo _to;
|
||||||
const std::shared_ptr<SendingAlbum> _album;
|
const std::shared_ptr<SendingAlbum> _album;
|
||||||
|
|
Loading…
Add table
Reference in a new issue